sctp_usrreq.c revision 164085
1163953Srrs/*-
2163953Srrs * Copyright (c) 2001-2006, Cisco Systems, Inc. All rights reserved.
3163953Srrs *
4163953Srrs * Redistribution and use in source and binary forms, with or without
5163953Srrs * modification, are permitted provided that the following conditions are met:
6163953Srrs *
7163953Srrs * a) Redistributions of source code must retain the above copyright notice,
8163953Srrs *   this list of conditions and the following disclaimer.
9163953Srrs *
10163953Srrs * b) Redistributions in binary form must reproduce the above copyright
11163953Srrs *    notice, this list of conditions and the following disclaimer in
12163953Srrs *   the documentation and/or other materials provided with the distribution.
13163953Srrs *
14163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
15163953Srrs *    contributors may be used to endorse or promote products derived
16163953Srrs *    from this software without specific prior written permission.
17163953Srrs *
18163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
29163953Srrs */
30163953Srrs
31163953Srrs/* $KAME: sctp_usrreq.c,v 1.48 2005/03/07 23:26:08 itojun Exp $	 */
32163953Srrs
33163953Srrs#include <sys/cdefs.h>
34163953Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 164085 2006-11-08 00:21:13Z rrs $");
35163953Srrs
36163953Srrs
37163953Srrs#include "opt_ipsec.h"
38163953Srrs#include "opt_inet6.h"
39163953Srrs#include "opt_inet.h"
40163953Srrs
41163953Srrs#include "opt_sctp.h"
42163953Srrs
43163953Srrs#include <sys/param.h>
44163953Srrs#include <sys/systm.h>
45163953Srrs#include <sys/kernel.h>
46163953Srrs#include <sys/malloc.h>
47163953Srrs#include <sys/mbuf.h>
48163953Srrs#include <sys/domain.h>
49164039Srwatson#include <sys/priv.h>
50163953Srrs#include <sys/proc.h>
51163953Srrs#include <sys/protosw.h>
52163953Srrs#include <sys/socket.h>
53163953Srrs#include <sys/socketvar.h>
54163953Srrs#include <sys/sysctl.h>
55163953Srrs#include <sys/syslog.h>
56163953Srrs#include <net/if.h>
57163953Srrs#include <net/if_types.h>
58163953Srrs#include <net/if_var.h>
59163953Srrs#include <net/route.h>
60163953Srrs#include <netinet/in.h>
61163953Srrs#include <netinet/in_systm.h>
62163953Srrs#include <netinet/ip.h>
63163953Srrs#include <netinet/ip6.h>
64163953Srrs#include <netinet/in_pcb.h>
65163953Srrs#include <netinet/in_var.h>
66163953Srrs#include <netinet/ip_var.h>
67163953Srrs#include <netinet6/ip6_var.h>
68163953Srrs#include <netinet6/in6_var.h>
69163953Srrs#include <netinet6/scope6_var.h>
70163953Srrs#include <netinet/ip_icmp.h>
71163953Srrs#include <netinet/icmp_var.h>
72163953Srrs#include <netinet/sctp_os.h>
73163953Srrs#include <netinet/sctp_pcb.h>
74163953Srrs#include <netinet/sctp_header.h>
75163953Srrs#include <netinet/sctp_var.h>
76163953Srrs#include <netinet/sctp_output.h>
77163953Srrs#include <netinet/sctp_bsd_addr.h>
78163953Srrs#include <netinet/sctp_uio.h>
79163953Srrs#include <netinet/sctp_asconf.h>
80163953Srrs#include <netinet/sctputil.h>
81163953Srrs#include <netinet/sctp_indata.h>
82163953Srrs#include <netinet/sctp_asconf.h>
83163953Srrs#include <netinet/sctp_timer.h>
84163953Srrs#include <netinet/sctp_auth.h>
85164085Srrs
86163953Srrs#ifdef IPSEC
87163953Srrs#include <netinet6/ipsec.h>
88163953Srrs#include <netkey/key.h>
89163953Srrs#endif				/* IPSEC */
90163953Srrs
91163953Srrs
92163953Srrs
93163953Srrs
94163953Srrs#ifndef in6pcb
95163953Srrs#define in6pcb		inpcb
96163953Srrs#endif
97163953Srrs#ifndef sotoin6pcb
98163953Srrs#define sotoin6pcb      sotoinpcb
99163953Srrs#endif
100163953Srrs
101163953Srrs
102163953Srrs
103163953Srrs/*
104163953Srrs * sysctl tunable variables
105163953Srrs */
106163953Srrsint sctp_sendspace = (128 * 1024);
107163953Srrsint sctp_recvspace = 128 * (1024 +
108163953Srrs#ifdef INET6
109163953Srrs    sizeof(struct sockaddr_in6)
110163953Srrs#else
111163953Srrs    sizeof(struct sockaddr_in)
112163953Srrs#endif
113163953Srrs);
114163953Srrsint sctp_mbuf_threshold_count = SCTP_DEFAULT_MBUFS_IN_CHAIN;
115163953Srrsint sctp_auto_asconf = SCTP_DEFAULT_AUTO_ASCONF;
116163953Srrsint sctp_ecn_enable = 1;
117163953Srrsint sctp_ecn_nonce = 0;
118163953Srrsint sctp_strict_sacks = 0;
119163953Srrsint sctp_no_csum_on_loopback = 1;
120163953Srrsint sctp_strict_init = 1;
121163953Srrsint sctp_abort_if_one_2_one_hits_limit = 0;
122163953Srrsint sctp_strict_data_order = 0;
123163953Srrs
124163953Srrsint sctp_peer_chunk_oh = sizeof(struct mbuf);
125163953Srrsint sctp_max_burst_default = SCTP_DEF_MAX_BURST;
126163953Srrsint sctp_use_cwnd_based_maxburst = 1;
127163953Srrsint sctp_do_drain = 1;
128163953Srrsint sctp_warm_the_crc32_table = 0;
129163953Srrs
130163953Srrsunsigned int sctp_max_chunks_on_queue = SCTP_ASOC_MAX_CHUNKS_ON_QUEUE;
131163953Srrsunsigned int sctp_delayed_sack_time_default = SCTP_RECV_MSEC;
132163953Srrsunsigned int sctp_heartbeat_interval_default = SCTP_HB_DEFAULT_MSEC;
133163953Srrsunsigned int sctp_pmtu_raise_time_default = SCTP_DEF_PMTU_RAISE_SEC;
134163953Srrsunsigned int sctp_shutdown_guard_time_default = SCTP_DEF_MAX_SHUTDOWN_SEC;
135163953Srrsunsigned int sctp_secret_lifetime_default = SCTP_DEFAULT_SECRET_LIFE_SEC;
136163953Srrsunsigned int sctp_rto_max_default = SCTP_RTO_UPPER_BOUND;
137163953Srrsunsigned int sctp_rto_min_default = SCTP_RTO_LOWER_BOUND;
138163953Srrsunsigned int sctp_rto_initial_default = SCTP_RTO_INITIAL;
139163953Srrsunsigned int sctp_init_rto_max_default = SCTP_RTO_UPPER_BOUND;
140163953Srrsunsigned int sctp_valid_cookie_life_default = SCTP_DEFAULT_COOKIE_LIFE;
141163953Srrsunsigned int sctp_init_rtx_max_default = SCTP_DEF_MAX_INIT;
142163953Srrsunsigned int sctp_assoc_rtx_max_default = SCTP_DEF_MAX_SEND;
143163953Srrsunsigned int sctp_path_rtx_max_default = SCTP_DEF_MAX_PATH_RTX;
144163953Srrsunsigned int sctp_nr_outgoing_streams_default = SCTP_OSTREAM_INITIAL;
145163953Srrsunsigned int sctp_add_more_threshold = SCTP_DEFAULT_ADD_MORE;
146163953Srrs
147163953Srrsuint32_t sctp_asoc_free_resc_limit = SCTP_DEF_ASOC_RESC_LIMIT;
148163953Srrsuint32_t sctp_system_free_resc_limit = SCTP_DEF_SYSTEM_RESC_LIMIT;
149163953Srrs
150163953Srrsint sctp_min_split_point = SCTP_DEFAULT_SPLIT_POINT_MIN;
151163953Srrsint sctp_pcbtblsize = SCTP_PCBHASHSIZE;
152163953Srrsint sctp_hashtblsize = SCTP_TCBHASHSIZE;
153163953Srrsint sctp_chunkscale = SCTP_CHUNKQUEUE_SCALE;
154163953Srrs
155163953Srrsunsigned int sctp_cmt_on_off = 0;
156163953Srrsunsigned int sctp_cmt_sockopt_on_off = 0;
157163953Srrsunsigned int sctp_cmt_use_dac = 0;
158163953Srrsunsigned int sctp_cmt_sockopt_use_dac = 0;
159163953Srrs
160163953Srrsint sctp_L2_abc_variable = 1;
161163953Srrsunsigned int sctp_early_fr = 0;
162163953Srrsunsigned int sctp_early_fr_msec = SCTP_MINFR_MSEC_TIMER;
163163953Srrsunsigned int sctp_use_rttvar_cc = 0;
164163953Srrsint sctp_says_check_for_deadlock = 0;
165163953Srrsunsigned int sctp_asconf_auth_nochk = 0;
166163953Srrsunsigned int sctp_auth_disable = 0;
167163953Srrsunsigned int sctp_auth_random_len = SCTP_AUTH_RANDOM_SIZE_DEFAULT;
168163953Srrsunsigned int sctp_auth_hmac_id_default = SCTP_AUTH_HMAC_ID_SHA1;
169163953Srrsstruct sctpstat sctpstat;
170163953Srrs
171163953Srrs#ifdef SCTP_DEBUG
172163953Srrsextern uint32_t sctp_debug_on;
173163953Srrs
174163953Srrs#endif				/* SCTP_DEBUG */
175163953Srrs
176163953Srrs
177163953Srrsvoid
178163953Srrssctp_init(void)
179163953Srrs{
180163953Srrs	/* Init the SCTP pcb in sctp_pcb.c */
181163953Srrs	u_long sb_max_adj;
182163953Srrs
183163953Srrs	sctp_pcb_init();
184163953Srrs
185163953Srrs	if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
186163953Srrs		sctp_max_chunks_on_queue = (nmbclusters / 8);
187163953Srrs	/*
188163953Srrs	 * Allow a user to take no more than 1/2 the number of clusters or
189163953Srrs	 * the SB_MAX whichever is smaller for the send window.
190163953Srrs	 */
191163953Srrs	sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
192163953Srrs	sctp_sendspace = min((min(SB_MAX, sb_max_adj)),
193163953Srrs	    ((nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
194163953Srrs	/*
195163953Srrs	 * Now for the recv window, should we take the same amount? or
196163953Srrs	 * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
197163953Srrs	 * now I will just copy.
198163953Srrs	 */
199163953Srrs	sctp_recvspace = sctp_sendspace;
200163953Srrs
201163953Srrs
202163953Srrs}
203163953Srrs
204163953Srrs
205163953Srrs#ifdef INET6
206163953Srrsvoid
207163953Srrsip_2_ip6_hdr(struct ip6_hdr *ip6, struct ip *ip)
208163953Srrs{
209163953Srrs	bzero(ip6, sizeof(*ip6));
210163953Srrs
211163953Srrs	ip6->ip6_vfc = IPV6_VERSION;
212163953Srrs	ip6->ip6_plen = ip->ip_len;
213163953Srrs	ip6->ip6_nxt = ip->ip_p;
214163953Srrs	ip6->ip6_hlim = ip->ip_ttl;
215163953Srrs	ip6->ip6_src.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] =
216163953Srrs	    IPV6_ADDR_INT32_SMP;
217163953Srrs	ip6->ip6_src.s6_addr32[3] = ip->ip_src.s_addr;
218163953Srrs	ip6->ip6_dst.s6_addr32[3] = ip->ip_dst.s_addr;
219163953Srrs}
220163953Srrs
221163953Srrs#endif				/* INET6 */
222163953Srrs
223163953Srrs
224163953Srrsstatic void
225163953Srrssctp_pathmtu_adustment(struct sctp_inpcb *inp,
226163953Srrs    struct sctp_tcb *stcb,
227163953Srrs    struct sctp_nets *net,
228163953Srrs    uint16_t nxtsz)
229163953Srrs{
230163953Srrs	struct sctp_tmit_chunk *chk;
231163953Srrs
232163953Srrs	/* Adjust that too */
233163953Srrs	stcb->asoc.smallest_mtu = nxtsz;
234163953Srrs	/* now off to subtract IP_DF flag if needed */
235163953Srrs
236163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
237163953Srrs		if ((chk->send_size + IP_HDR_SIZE) > nxtsz) {
238163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
239163953Srrs		}
240163953Srrs	}
241163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
242163953Srrs		if ((chk->send_size + IP_HDR_SIZE) > nxtsz) {
243163953Srrs			/*
244163953Srrs			 * For this guy we also mark for immediate resend
245163953Srrs			 * since we sent to big of chunk
246163953Srrs			 */
247163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
248163953Srrs			if (chk->sent != SCTP_DATAGRAM_RESEND) {
249163953Srrs				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
250163953Srrs			}
251163953Srrs			chk->sent = SCTP_DATAGRAM_RESEND;
252163953Srrs			chk->rec.data.doing_fast_retransmit = 0;
253163953Srrs
254163953Srrs			/* Clear any time so NO RTT is being done */
255163953Srrs			chk->do_rtt = 0;
256163953Srrs			if (stcb->asoc.total_flight >= chk->book_size)
257163953Srrs				stcb->asoc.total_flight -= chk->book_size;
258163953Srrs			else
259163953Srrs				stcb->asoc.total_flight = 0;
260163953Srrs			if (stcb->asoc.total_flight_count > 0)
261163953Srrs				stcb->asoc.total_flight_count--;
262163953Srrs			if (net->flight_size >= chk->book_size)
263163953Srrs				net->flight_size -= chk->book_size;
264163953Srrs			else
265163953Srrs				net->flight_size = 0;
266163953Srrs		}
267163953Srrs	}
268163953Srrs}
269163953Srrs
270163953Srrsstatic void
271163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp,
272163953Srrs    struct sctp_tcb *stcb,
273163953Srrs    struct sctp_nets *net,
274163953Srrs    struct ip *ip,
275163953Srrs    struct sctphdr *sh)
276163953Srrs{
277163953Srrs	struct icmp *icmph;
278163953Srrs	int totsz, tmr_stopped = 0;
279163953Srrs	uint16_t nxtsz;
280163953Srrs
281163953Srrs	/* protection */
282163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
283163953Srrs	    (ip == NULL) || (sh == NULL)) {
284163953Srrs		if (stcb != NULL)
285163953Srrs			SCTP_TCB_UNLOCK(stcb);
286163953Srrs		return;
287163953Srrs	}
288163953Srrs	/* First job is to verify the vtag matches what I would send */
289163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
290163953Srrs		SCTP_TCB_UNLOCK(stcb);
291163953Srrs		return;
292163953Srrs	}
293163953Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
294163953Srrs	    sizeof(struct ip)));
295163953Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
296163953Srrs		/* We only care about unreachable */
297163953Srrs		SCTP_TCB_UNLOCK(stcb);
298163953Srrs		return;
299163953Srrs	}
300163953Srrs	if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
301163953Srrs		/* not a unreachable message due to frag. */
302163953Srrs		SCTP_TCB_UNLOCK(stcb);
303163953Srrs		return;
304163953Srrs	}
305163953Srrs	totsz = ip->ip_len;
306163953Srrs
307163953Srrs	nxtsz = ntohs(icmph->icmp_seq);
308163953Srrs	if (nxtsz == 0) {
309163953Srrs		/*
310163953Srrs		 * old type router that does not tell us what the next size
311163953Srrs		 * mtu is. Rats we will have to guess (in a educated fashion
312163953Srrs		 * of course)
313163953Srrs		 */
314163953Srrs		nxtsz = find_next_best_mtu(totsz);
315163953Srrs	}
316163953Srrs	/* Stop any PMTU timer */
317163953Srrs	if (callout_pending(&net->pmtu_timer.timer)) {
318163953Srrs		tmr_stopped = 1;
319163953Srrs		sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
320163953Srrs	}
321163953Srrs	/* Adjust destination size limit */
322163953Srrs	if (net->mtu > nxtsz) {
323163953Srrs		net->mtu = nxtsz;
324163953Srrs	}
325163953Srrs	/* now what about the ep? */
326163953Srrs	if (stcb->asoc.smallest_mtu > nxtsz) {
327163953Srrs		sctp_pathmtu_adustment(inp, stcb, net, nxtsz);
328163953Srrs	}
329163953Srrs	if (tmr_stopped)
330163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
331163953Srrs
332163953Srrs	SCTP_TCB_UNLOCK(stcb);
333163953Srrs}
334163953Srrs
335163953Srrs
336163953Srrsvoid
337163953Srrssctp_notify(struct sctp_inpcb *inp,
338163953Srrs    int errno,
339163953Srrs    struct sctphdr *sh,
340163953Srrs    struct sockaddr *to,
341163953Srrs    struct sctp_tcb *stcb,
342163953Srrs    struct sctp_nets *net)
343163953Srrs{
344163953Srrs	/* protection */
345163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
346163953Srrs	    (sh == NULL) || (to == NULL)) {
347163953Srrs		return;
348163953Srrs	}
349163953Srrs	/* First job is to verify the vtag matches what I would send */
350163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
351163953Srrs		return;
352163953Srrs	}
353163953Srrs	/* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */
354163953Srrs
355163953Srrs	if ((errno == EHOSTUNREACH) ||	/* Host is not reachable */
356163953Srrs	    (errno == EHOSTDOWN) ||	/* Host is down */
357163953Srrs	    (errno == ECONNREFUSED) ||	/* Host refused the connection, (not
358163953Srrs					 * an abort?) */
359163953Srrs	    (errno == ENOPROTOOPT)	/* SCTP is not present on host */
360163953Srrs	    ) {
361163953Srrs		/*
362163953Srrs		 * Hmm reachablity problems we must examine closely. If its
363163953Srrs		 * not reachable, we may have lost a network. Or if there is
364163953Srrs		 * NO protocol at the other end named SCTP. well we consider
365163953Srrs		 * it a OOTB abort.
366163953Srrs		 */
367163953Srrs		if ((errno == EHOSTUNREACH) || (errno == EHOSTDOWN)) {
368163953Srrs			if (net->dest_state & SCTP_ADDR_REACHABLE) {
369163953Srrs				/* Ok that destination is NOT reachable */
370163953Srrs				net->dest_state &= ~SCTP_ADDR_REACHABLE;
371163953Srrs				net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
372163953Srrs				net->error_count = net->failure_threshold + 1;
373163953Srrs				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
374163953Srrs				    stcb, SCTP_FAILED_THRESHOLD,
375163953Srrs				    (void *)net);
376163953Srrs			}
377163953Srrs			if (stcb)
378163953Srrs				SCTP_TCB_UNLOCK(stcb);
379163953Srrs		} else {
380163953Srrs			/*
381163953Srrs			 * Here the peer is either playing tricks on us,
382163953Srrs			 * including an address that belongs to someone who
383163953Srrs			 * does not support SCTP OR was a userland
384163953Srrs			 * implementation that shutdown and now is dead. In
385163953Srrs			 * either case treat it like a OOTB abort with no
386163953Srrs			 * TCB
387163953Srrs			 */
388163953Srrs			sctp_abort_notification(stcb, SCTP_PEER_FAULTY);
389163953Srrs			sctp_free_assoc(inp, stcb, 0);
390163953Srrs			/* no need to unlock here, since the TCB is gone */
391163953Srrs		}
392163953Srrs	} else {
393163953Srrs		/* Send all others to the app */
394163953Srrs		if (stcb)
395163953Srrs			SCTP_TCB_UNLOCK(stcb);
396163953Srrs
397163953Srrs
398163953Srrs		if (inp->sctp_socket) {
399163953Srrs#ifdef SCTP_LOCK_LOGGING
400163953Srrs			sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCK);
401163953Srrs#endif
402163953Srrs			SOCK_LOCK(inp->sctp_socket);
403163953Srrs			inp->sctp_socket->so_error = errno;
404163953Srrs			sctp_sowwakeup(inp, inp->sctp_socket);
405163953Srrs			SOCK_UNLOCK(inp->sctp_socket);
406163953Srrs		}
407163953Srrs	}
408163953Srrs}
409163953Srrs
410163953Srrsvoid
411163953Srrssctp_ctlinput(cmd, sa, vip)
412163953Srrs	int cmd;
413163953Srrs	struct sockaddr *sa;
414163953Srrs	void *vip;
415163953Srrs{
416163953Srrs	struct ip *ip = vip;
417163953Srrs	struct sctphdr *sh;
418163953Srrs	int s;
419163953Srrs
420163953Srrs
421163953Srrs	if (sa->sa_family != AF_INET ||
422163953Srrs	    ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
423163953Srrs		return;
424163953Srrs	}
425163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
426163953Srrs		ip = 0;
427163953Srrs	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
428163953Srrs		return;
429163953Srrs	}
430163953Srrs	if (ip) {
431163953Srrs		struct sctp_inpcb *inp = NULL;
432163953Srrs		struct sctp_tcb *stcb = NULL;
433163953Srrs		struct sctp_nets *net = NULL;
434163953Srrs		struct sockaddr_in to, from;
435163953Srrs
436163953Srrs		sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
437163953Srrs		bzero(&to, sizeof(to));
438163953Srrs		bzero(&from, sizeof(from));
439163953Srrs		from.sin_family = to.sin_family = AF_INET;
440163953Srrs		from.sin_len = to.sin_len = sizeof(to);
441163953Srrs		from.sin_port = sh->src_port;
442163953Srrs		from.sin_addr = ip->ip_src;
443163953Srrs		to.sin_port = sh->dest_port;
444163953Srrs		to.sin_addr = ip->ip_dst;
445163953Srrs
446163953Srrs		/*
447163953Srrs		 * 'to' holds the dest of the packet that failed to be sent.
448163953Srrs		 * 'from' holds our local endpoint address. Thus we reverse
449163953Srrs		 * the to and the from in the lookup.
450163953Srrs		 */
451163953Srrs		s = splnet();
452163953Srrs		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from,
453163953Srrs		    (struct sockaddr *)&to,
454163953Srrs		    &inp, &net, 1);
455163953Srrs		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
456163953Srrs			if (cmd != PRC_MSGSIZE) {
457163953Srrs				int cm;
458163953Srrs
459163953Srrs				if (cmd == PRC_HOSTDEAD) {
460163953Srrs					cm = EHOSTUNREACH;
461163953Srrs				} else {
462163953Srrs					cm = inetctlerrmap[cmd];
463163953Srrs				}
464163953Srrs				sctp_notify(inp, cm, sh,
465163953Srrs				    (struct sockaddr *)&to, stcb,
466163953Srrs				    net);
467163953Srrs			} else {
468163953Srrs				/* handle possible ICMP size messages */
469163953Srrs				sctp_notify_mbuf(inp, stcb, net, ip, sh);
470163953Srrs			}
471163953Srrs		} else {
472163953Srrs			if ((stcb == NULL) && (inp != NULL)) {
473163953Srrs				/* reduce ref-count */
474163953Srrs				SCTP_INP_WLOCK(inp);
475163953Srrs				SCTP_INP_DECR_REF(inp);
476163953Srrs				SCTP_INP_WUNLOCK(inp);
477163953Srrs			}
478163953Srrs		}
479163953Srrs		splx(s);
480163953Srrs	}
481163953Srrs	return;
482163953Srrs}
483163953Srrs
484163953Srrsstatic int
485163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS)
486163953Srrs{
487164085Srrs	struct xucred xuc;
488163953Srrs	struct sockaddr_in addrs[2];
489163953Srrs	struct sctp_inpcb *inp;
490163953Srrs	struct sctp_nets *net;
491163953Srrs	struct sctp_tcb *stcb;
492164085Srrs	int error;
493163953Srrs
494164039Srwatson	/*
495164039Srwatson	 * XXXRW: Other instances of getcred use SUSER_ALLOWJAIL, as socket
496164039Srwatson	 * visibility is scoped using cr_canseesocket(), which it is not
497164039Srwatson	 * here.
498164039Srwatson	 */
499164039Srwatson	error = priv_check_cred(req->td->td_ucred, PRIV_NETINET_GETCRED, 0);
500163953Srrs	if (error)
501163953Srrs		return (error);
502164039Srwatson
503163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
504163953Srrs	if (error)
505163953Srrs		return (error);
506163953Srrs
507163953Srrs	stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]),
508163953Srrs	    sintosa(&addrs[1]),
509163953Srrs	    &inp, &net, 1);
510163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
511163953Srrs		if ((inp != NULL) && (stcb == NULL)) {
512163953Srrs			/* reduce ref-count */
513163953Srrs			SCTP_INP_WLOCK(inp);
514163953Srrs			SCTP_INP_DECR_REF(inp);
515164085Srrs			goto cred_can_cont;
516163953Srrs		}
517163953Srrs		error = ENOENT;
518163953Srrs		goto out;
519163953Srrs	}
520163953Srrs	SCTP_TCB_UNLOCK(stcb);
521164085Srrs	/*
522164085Srrs	 * We use the write lock here, only since in the error leg we need
523164085Srrs	 * it. If we used RLOCK, then we would have to
524164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
525164085Srrs	 * Better to use higher wlock.
526164085Srrs	 */
527164085Srrs	SCTP_INP_WLOCK(inp);
528164085Srrscred_can_cont:
529164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
530164085Srrs	if (error) {
531164085Srrs		SCTP_INP_WUNLOCK(inp);
532164085Srrs		goto out;
533164085Srrs	}
534164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
535164085Srrs	SCTP_INP_WUNLOCK(inp);
536164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
537163953Srrsout:
538163953Srrs	return (error);
539163953Srrs}
540163953Srrs
541163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
542163953Srrs    0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
543163953Srrs
544163953Srrs
545163953Srrs/*
546163953Srrs * sysctl definitions
547163953Srrs */
548163953Srrs
549163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, sendspace, CTLFLAG_RW,
550163953Srrs    &sctp_sendspace, 0, "Maximum outgoing SCTP buffer size");
551163953Srrs
552163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, recvspace, CTLFLAG_RW,
553163953Srrs    &sctp_recvspace, 0, "Maximum incoming SCTP buffer size");
554163953Srrs
555163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, auto_asconf, CTLFLAG_RW,
556163953Srrs    &sctp_auto_asconf, 0, "Enable SCTP Auto-ASCONF");
557163953Srrs
558163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, ecn_enable, CTLFLAG_RW,
559163953Srrs    &sctp_ecn_enable, 0, "Enable SCTP ECN");
560163953Srrs
561163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, ecn_nonce, CTLFLAG_RW,
562163953Srrs    &sctp_ecn_nonce, 0, "Enable SCTP ECN Nonce");
563163953Srrs
564163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_sacks, CTLFLAG_RW,
565163953Srrs    &sctp_strict_sacks, 0, "Enable SCTP Strict SACK checking");
566163953Srrs
567163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, loopback_nocsum, CTLFLAG_RW,
568163953Srrs    &sctp_no_csum_on_loopback, 0,
569163953Srrs    "Enable NO Csum on packets sent on loopback");
570163953Srrs
571163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_init, CTLFLAG_RW,
572163953Srrs    &sctp_strict_init, 0,
573163953Srrs    "Enable strict INIT/INIT-ACK singleton enforcement");
574163953Srrs
575163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, peer_chkoh, CTLFLAG_RW,
576163953Srrs    &sctp_peer_chunk_oh, 0,
577163953Srrs    "Amount to debit peers rwnd per chunk sent");
578163953Srrs
579163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, maxburst, CTLFLAG_RW,
580163953Srrs    &sctp_max_burst_default, 0,
581163953Srrs    "Default max burst for sctp endpoints");
582163953Srrs
583163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, maxchunks, CTLFLAG_RW,
584163953Srrs    &sctp_max_chunks_on_queue, 0,
585163953Srrs    "Default max chunks on queue per asoc");
586163953Srrs
587163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, tcbhashsize, CTLFLAG_RW,
588163953Srrs    &sctp_hashtblsize, 0,
589163953Srrs    "Tuneable for Hash table sizes");
590163953Srrs
591163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, min_split_point, CTLFLAG_RW,
592163953Srrs    &sctp_min_split_point, 0,
593163953Srrs    "Minimum size when splitting a chunk");
594163953Srrs
595163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, pcbhashsize, CTLFLAG_RW,
596163953Srrs    &sctp_pcbtblsize, 0,
597163953Srrs    "Tuneable for PCB Hash table sizes");
598163953Srrs
599163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, sys_resource, CTLFLAG_RW,
600163953Srrs    &sctp_system_free_resc_limit, 0,
601163953Srrs    "Max number of cached resources in the system");
602163953Srrs
603163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, asoc_resource, CTLFLAG_RW,
604163953Srrs    &sctp_asoc_free_resc_limit, 0,
605163953Srrs    "Max number of cached resources in an asoc");
606163953Srrs
607163953Srrs
608163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, chunkscale, CTLFLAG_RW,
609163953Srrs    &sctp_chunkscale, 0,
610163953Srrs    "Tuneable for Scaling of number of chunks and messages");
611163953Srrs
612163953Srrs
613163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLFLAG_RW,
614163953Srrs    &sctp_delayed_sack_time_default, 0,
615163953Srrs    "Default delayed SACK timer in msec");
616163953Srrs
617163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, heartbeat_interval, CTLFLAG_RW,
618163953Srrs    &sctp_heartbeat_interval_default, 0,
619163953Srrs    "Default heartbeat interval in msec");
620163953Srrs
621163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, pmtu_raise_time, CTLFLAG_RW,
622163953Srrs    &sctp_pmtu_raise_time_default, 0,
623163953Srrs    "Default PMTU raise timer in sec");
624163953Srrs
625163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, shutdown_guard_time, CTLFLAG_RW,
626163953Srrs    &sctp_shutdown_guard_time_default, 0,
627163953Srrs    "Default shutdown guard timer in sec");
628163953Srrs
629163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, secret_lifetime, CTLFLAG_RW,
630163953Srrs    &sctp_secret_lifetime_default, 0,
631163953Srrs    "Default secret lifetime in sec");
632163953Srrs
633163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_max, CTLFLAG_RW,
634163953Srrs    &sctp_rto_max_default, 0,
635163953Srrs    "Default maximum retransmission timeout in msec");
636163953Srrs
637163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_min, CTLFLAG_RW,
638163953Srrs    &sctp_rto_min_default, 0,
639163953Srrs    "Default minimum retransmission timeout in msec");
640163953Srrs
641163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_initial, CTLFLAG_RW,
642163953Srrs    &sctp_rto_initial_default, 0,
643163953Srrs    "Default initial retransmission timeout in msec");
644163953Srrs
645163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, init_rto_max, CTLFLAG_RW,
646163953Srrs    &sctp_init_rto_max_default, 0,
647163953Srrs    "Default maximum retransmission timeout during association setup in msec");
648163953Srrs
649163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, valid_cookie_life, CTLFLAG_RW,
650163953Srrs    &sctp_valid_cookie_life_default, 0,
651163953Srrs    "Default cookie lifetime in sec");
652163953Srrs
653163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, init_rtx_max, CTLFLAG_RW,
654163953Srrs    &sctp_init_rtx_max_default, 0,
655163953Srrs    "Default maximum number of retransmission for INIT chunks");
656163953Srrs
657163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, assoc_rtx_max, CTLFLAG_RW,
658163953Srrs    &sctp_assoc_rtx_max_default, 0,
659163953Srrs    "Default maximum number of retransmissions per association");
660163953Srrs
661163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, path_rtx_max, CTLFLAG_RW,
662163953Srrs    &sctp_path_rtx_max_default, 0,
663163953Srrs    "Default maximum of retransmissions per path");
664163953Srrs
665163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLFLAG_RW,
666163953Srrs    &sctp_add_more_threshold, 0,
667163953Srrs    "When space wise is it worthwhile to try to add more to a socket send buffer");
668163953Srrs
669163953Srrs
670163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, nr_outgoing_streams, CTLFLAG_RW,
671163953Srrs    &sctp_nr_outgoing_streams_default, 0,
672163953Srrs    "Default number of outgoing streams");
673163953Srrs
674163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, cmt_on_off, CTLFLAG_RW,
675163953Srrs    &sctp_cmt_on_off, 0,
676163953Srrs    "CMT ON/OFF flag");
677163953Srrs
678163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLFLAG_RW,
679163953Srrs    &sctp_use_cwnd_based_maxburst, 0,
680163953Srrs    "Use a CWND adjusting maxburst");
681163953Srrs
682163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLFLAG_RW,
683163953Srrs    &sctp_early_fr, 0,
684163953Srrs    "Early Fast Retransmit with Timer");
685163953Srrs
686163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, use_rttvar_congctrl, CTLFLAG_RW,
687163953Srrs    &sctp_use_rttvar_cc, 0,
688163953Srrs    "Use congestion control via rtt variation");
689163953Srrs
690163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, deadlock_detect, CTLFLAG_RW,
691163953Srrs    &sctp_says_check_for_deadlock, 0,
692163953Srrs    "SMP Deadlock detection on/off");
693163953Srrs
694163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, early_fast_retran_msec, CTLFLAG_RW,
695163953Srrs    &sctp_early_fr_msec, 0,
696163953Srrs    "Early Fast Retransmit minimum timer value");
697163953Srrs
698163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, asconf_auth_nochk, CTLFLAG_RW,
699163953Srrs    &sctp_asconf_auth_nochk, 0,
700163953Srrs    "Disable SCTP ASCONF AUTH requirement");
701163953Srrs
702163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, auth_disable, CTLFLAG_RW,
703163953Srrs    &sctp_auth_disable, 0,
704163953Srrs    "Disable SCTP AUTH chunk requirement/function");
705163953Srrs
706163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, auth_random_len, CTLFLAG_RW,
707163953Srrs    &sctp_auth_random_len, 0,
708163953Srrs    "Length of AUTH RANDOMs");
709163953Srrs
710163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, auth_hmac_id, CTLFLAG_RW,
711163953Srrs    &sctp_auth_hmac_id_default, 0,
712163953Srrs    "Default HMAC Id for SCTP AUTHenthication");
713163953Srrs
714163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, abc_l_var, CTLFLAG_RW,
715163953Srrs    &sctp_L2_abc_variable, 0,
716163953Srrs    "SCTP ABC max increase per SACK (L)");
717163953Srrs
718163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, max_chained_mbufs, CTLFLAG_RW,
719163953Srrs    &sctp_mbuf_threshold_count, 0,
720163953Srrs    "Default max number of small mbufs on a chain");
721163953Srrs
722163953SrrsSYSCTL_UINT(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLFLAG_RW,
723163953Srrs    &sctp_cmt_use_dac, 0,
724163953Srrs    "CMT DAC ON/OFF flag");
725163953Srrs
726163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, do_sctp_drain, CTLFLAG_RW,
727163953Srrs    &sctp_do_drain, 0,
728163953Srrs    "Should SCTP respond to the drain calls");
729163953Srrs
730163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, warm_crc_table, CTLFLAG_RW,
731163953Srrs    &sctp_warm_the_crc32_table, 0,
732163953Srrs    "Should the CRC32c tables be warmed before checksum?");
733163953Srrs
734163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, abort_at_limit, CTLFLAG_RW,
735163953Srrs    &sctp_abort_if_one_2_one_hits_limit, 0,
736163953Srrs    "When one-2-one hits qlimit abort");
737163953Srrs
738163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_data_order, CTLFLAG_RW,
739163953Srrs    &sctp_strict_data_order, 0,
740163953Srrs    "Enforce strict data ordering, abort if control inside data");
741163953Srrs
742163953SrrsSYSCTL_STRUCT(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_RW,
743163953Srrs    &sctpstat, sctpstat,
744163953Srrs    "SCTP statistics (struct sctps_stat, netinet/sctp.h");
745163953Srrs#ifdef SCTP_DEBUG
746163953SrrsSYSCTL_INT(_net_inet_sctp, OID_AUTO, debug, CTLFLAG_RW,
747163953Srrs    &sctp_debug_on, 0, "Configure debug output");
748163953Srrs#endif				/* SCTP_DEBUG */
749163953Srrs
750163953Srrsstatic void
751163953Srrssctp_abort(struct socket *so)
752163953Srrs{
753163953Srrs	struct sctp_inpcb *inp;
754163953Srrs	int s;
755163953Srrs	uint32_t flags;
756163953Srrs
757163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
758163953Srrs	if (inp == 0)
759163953Srrs		return;
760163953Srrs
761163953Srrs	s = splnet();
762163953Srrssctp_must_try_again:
763163953Srrs	flags = inp->sctp_flags;
764163953Srrs#ifdef SCTP_LOG_CLOSING
765163953Srrs	sctp_log_closing(inp, NULL, 17);
766163953Srrs#endif
767163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
768163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
769163953Srrs#ifdef SCTP_LOG_CLOSING
770163953Srrs		sctp_log_closing(inp, NULL, 16);
771163953Srrs#endif
772163953Srrs		sctp_inpcb_free(inp, 1, 0);
773163953Srrs		SOCK_LOCK(so);
774163953Srrs		so->so_snd.sb_cc = 0;
775163953Srrs		so->so_snd.sb_mb = NULL;
776163953Srrs		so->so_snd.sb_mbcnt = 0;
777163953Srrs
778163953Srrs		/*
779163953Srrs		 * same for the rcv ones, they are only here for the
780163953Srrs		 * accounting/select.
781163953Srrs		 */
782163953Srrs		so->so_rcv.sb_cc = 0;
783163953Srrs		so->so_rcv.sb_mb = NULL;
784163953Srrs		so->so_rcv.sb_mbcnt = 0;
785163953Srrs		/*
786163953Srrs		 * Now null out the reference, we are completely detached.
787163953Srrs		 */
788163953Srrs		so->so_pcb = NULL;
789163953Srrs		SOCK_UNLOCK(so);
790163953Srrs
791163953Srrs	} else {
792163953Srrs		flags = inp->sctp_flags;
793163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
794163953Srrs			goto sctp_must_try_again;
795163953Srrs		}
796163953Srrs	}
797163953Srrs	splx(s);
798163953Srrs	return;
799163953Srrs}
800163953Srrs
801163953Srrsstatic int
802163953Srrssctp_attach(struct socket *so, int proto, struct thread *p)
803163953Srrs{
804163953Srrs	struct sctp_inpcb *inp;
805163953Srrs	struct inpcb *ip_inp;
806163953Srrs	int s, error;
807163953Srrs
808163953Srrs#ifdef IPSEC
809163953Srrs	uint32_t flags;
810163953Srrs
811163953Srrs#endif
812163953Srrs	s = splnet();
813163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
814163953Srrs	if (inp != 0) {
815163953Srrs		splx(s);
816163953Srrs		return EINVAL;
817163953Srrs	}
818163953Srrs	error = soreserve(so, sctp_sendspace, sctp_recvspace);
819163953Srrs	if (error) {
820163953Srrs		splx(s);
821163953Srrs		return error;
822163953Srrs	}
823163953Srrs	error = sctp_inpcb_alloc(so);
824163953Srrs	if (error) {
825163953Srrs		splx(s);
826163953Srrs		return error;
827163953Srrs	}
828163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
829163953Srrs	SCTP_INP_WLOCK(inp);
830163953Srrs
831163953Srrs	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;	/* I'm not v6! */
832163953Srrs	ip_inp = &inp->ip_inp.inp;
833163953Srrs	ip_inp->inp_vflag |= INP_IPV4;
834163953Srrs	ip_inp->inp_ip_ttl = ip_defttl;
835163953Srrs
836163953Srrs#ifdef IPSEC
837163953Srrs	error = ipsec_init_pcbpolicy(so, &ip_inp->inp_sp);
838163953Srrs#ifdef SCTP_LOG_CLOSING
839163953Srrs	sctp_log_closing(inp, NULL, 17);
840163953Srrs#endif
841163953Srrs	if (error != 0) {
842163953Srrs		flags = inp->sctp_flags;
843163953Srrs		if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
844163953Srrs		    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
845163953Srrs#ifdef SCTP_LOG_CLOSING
846163953Srrs			sctp_log_closing(inp, NULL, 15);
847163953Srrs#endif
848163953Srrs			sctp_inpcb_free(inp, 1, 0);
849163953Srrs		}
850163953Srrs		return error;
851163953Srrs	}
852163953Srrs#endif				/* IPSEC */
853163953Srrs	SCTP_INP_WUNLOCK(inp);
854163953Srrs	splx(s);
855163953Srrs	return 0;
856163953Srrs}
857163953Srrs
858163953Srrsstatic int
859163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
860163953Srrs{
861163953Srrs	struct sctp_inpcb *inp;
862163953Srrs	int s, error;
863163953Srrs
864163953Srrs#ifdef INET6
865163953Srrs	if (addr && addr->sa_family != AF_INET)
866163953Srrs		/* must be a v4 address! */
867163953Srrs		return EINVAL;
868163953Srrs#endif				/* INET6 */
869163953Srrs
870163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
871163953Srrs	if (inp == 0)
872163953Srrs		return EINVAL;
873163953Srrs
874163953Srrs	s = splnet();
875163953Srrs	error = sctp_inpcb_bind(so, addr, p);
876163953Srrs	splx(s);
877163953Srrs	return error;
878163953Srrs}
879163953Srrs
880163953Srrsstatic void
881163953Srrssctp_close(struct socket *so)
882163953Srrs{
883163953Srrs	struct sctp_inpcb *inp;
884163953Srrs	uint32_t flags;
885163953Srrs
886163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
887163953Srrs	if (inp == 0)
888163953Srrs		return;
889163953Srrs
890163953Srrs	/*
891163953Srrs	 * Inform all the lower layer assoc that we are done.
892163953Srrs	 */
893163953Srrssctp_must_try_again:
894163953Srrs	flags = inp->sctp_flags;
895163953Srrs#ifdef SCTP_LOG_CLOSING
896163953Srrs	sctp_log_closing(inp, NULL, 17);
897163953Srrs#endif
898163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
899163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
900163953Srrs		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
901163953Srrs		    (so->so_rcv.sb_cc > 0)) {
902163953Srrs#ifdef SCTP_LOG_CLOSING
903163953Srrs			sctp_log_closing(inp, NULL, 13);
904163953Srrs#endif
905163953Srrs			sctp_inpcb_free(inp, 1, 1);
906163953Srrs		} else {
907163953Srrs#ifdef SCTP_LOG_CLOSING
908163953Srrs			sctp_log_closing(inp, NULL, 14);
909163953Srrs#endif
910163953Srrs			sctp_inpcb_free(inp, 0, 1);
911163953Srrs		}
912163953Srrs		/*
913163953Srrs		 * The socket is now detached, no matter what the state of
914163953Srrs		 * the SCTP association.
915163953Srrs		 */
916163953Srrs		SOCK_LOCK(so);
917163953Srrs		so->so_snd.sb_cc = 0;
918163953Srrs		so->so_snd.sb_mb = NULL;
919163953Srrs		so->so_snd.sb_mbcnt = 0;
920163953Srrs
921163953Srrs		/*
922163953Srrs		 * same for the rcv ones, they are only here for the
923163953Srrs		 * accounting/select.
924163953Srrs		 */
925163953Srrs		so->so_rcv.sb_cc = 0;
926163953Srrs		so->so_rcv.sb_mb = NULL;
927163953Srrs		so->so_rcv.sb_mbcnt = 0;
928163953Srrs		/*
929163953Srrs		 * Now null out the reference, we are completely detached.
930163953Srrs		 */
931163953Srrs		so->so_pcb = NULL;
932163953Srrs		SOCK_UNLOCK(so);
933163953Srrs	} else {
934163953Srrs		flags = inp->sctp_flags;
935163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
936163953Srrs			goto sctp_must_try_again;
937163953Srrs		}
938163953Srrs	}
939163953Srrs	return;
940163953Srrs}
941163953Srrs
942163953Srrs
943163953Srrsint
944163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
945163953Srrs    struct mbuf *control, struct thread *p);
946163953Srrs
947163953Srrs
948163953Srrsint
949163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
950163953Srrs    struct mbuf *control, struct thread *p)
951163953Srrs{
952163953Srrs	struct sctp_inpcb *inp;
953163953Srrs	int error;
954163953Srrs
955163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
956163953Srrs	if (inp == 0) {
957163953Srrs		if (control) {
958163953Srrs			sctp_m_freem(control);
959163953Srrs			control = NULL;
960163953Srrs		}
961163953Srrs		sctp_m_freem(m);
962163953Srrs		return EINVAL;
963163953Srrs	}
964163953Srrs	/* Got to have an to address if we are NOT a connected socket */
965163953Srrs	if ((addr == NULL) &&
966163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
967163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))
968163953Srrs	    ) {
969163953Srrs		goto connected_type;
970163953Srrs	} else if (addr == NULL) {
971163953Srrs		error = EDESTADDRREQ;
972163953Srrs		sctp_m_freem(m);
973163953Srrs		if (control) {
974163953Srrs			sctp_m_freem(control);
975163953Srrs			control = NULL;
976163953Srrs		}
977163953Srrs		return (error);
978163953Srrs	}
979163953Srrs#ifdef INET6
980163953Srrs	if (addr->sa_family != AF_INET) {
981163953Srrs		/* must be a v4 address! */
982163953Srrs		sctp_m_freem(m);
983163953Srrs		if (control) {
984163953Srrs			sctp_m_freem(control);
985163953Srrs			control = NULL;
986163953Srrs		}
987163953Srrs		error = EDESTADDRREQ;
988163953Srrs		return EINVAL;
989163953Srrs	}
990163953Srrs#endif				/* INET6 */
991163953Srrsconnected_type:
992163953Srrs	/* now what about control */
993163953Srrs	if (control) {
994163953Srrs		if (inp->control) {
995163953Srrs			printf("huh? control set?\n");
996163953Srrs			sctp_m_freem(inp->control);
997163953Srrs			inp->control = NULL;
998163953Srrs		}
999163953Srrs		inp->control = control;
1000163953Srrs	}
1001163953Srrs	/* add it in possibly */
1002163953Srrs	if ((inp->pkt) && (inp->pkt->m_flags & M_PKTHDR)) {
1003163953Srrs		struct mbuf *x;
1004163953Srrs		int c_len;
1005163953Srrs
1006163953Srrs		c_len = 0;
1007163953Srrs		/* How big is it */
1008163953Srrs		for (x = m; x; x = x->m_next) {
1009163953Srrs			c_len += x->m_len;
1010163953Srrs		}
1011163953Srrs		inp->pkt->m_pkthdr.len += c_len;
1012163953Srrs	}
1013163953Srrs	/* Place the data */
1014163953Srrs	if (inp->pkt) {
1015163953Srrs		inp->pkt_last->m_next = m;
1016163953Srrs		inp->pkt_last = m;
1017163953Srrs	} else {
1018163953Srrs		inp->pkt_last = inp->pkt = m;
1019163953Srrs	}
1020163953Srrs	if (
1021163953Srrs	/* FreeBSD uses a flag passed */
1022163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
1023163953Srrs	    ) {
1024163953Srrs		/*
1025163953Srrs		 * note with the current version this code will only be used
1026163953Srrs		 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
1027163953Srrs		 * re-defining sosend to use the sctp_sosend. One can
1028163953Srrs		 * optionally switch back to this code (by changing back the
1029163953Srrs		 * definitions) but this is not advisable. This code is used
1030163953Srrs		 * by FreeBSD when sending a file with sendfile() though.
1031163953Srrs		 */
1032163953Srrs		int ret;
1033163953Srrs
1034163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
1035163953Srrs		inp->pkt = NULL;
1036163953Srrs		inp->control = NULL;
1037163953Srrs		return (ret);
1038163953Srrs	} else {
1039163953Srrs		return (0);
1040163953Srrs	}
1041163953Srrs}
1042163953Srrs
1043163953Srrsstatic int
1044163953Srrssctp_disconnect(struct socket *so)
1045163953Srrs{
1046163953Srrs	struct sctp_inpcb *inp;
1047163953Srrs	int s;
1048163953Srrs
1049163953Srrs	s = splnet();
1050163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1051163953Srrs	if (inp == NULL) {
1052163953Srrs		splx(s);
1053163953Srrs		return (ENOTCONN);
1054163953Srrs	}
1055163953Srrs	SCTP_INP_RLOCK(inp);
1056163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1057163953Srrs		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
1058163953Srrs			/* No connection */
1059163953Srrs			splx(s);
1060163953Srrs			SCTP_INP_RUNLOCK(inp);
1061163953Srrs			return (0);
1062163953Srrs		} else {
1063163953Srrs			struct sctp_association *asoc;
1064163953Srrs			struct sctp_tcb *stcb;
1065163953Srrs
1066163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
1067163953Srrs			if (stcb == NULL) {
1068163953Srrs				splx(s);
1069163953Srrs				SCTP_INP_RUNLOCK(inp);
1070163953Srrs				return (EINVAL);
1071163953Srrs			}
1072163953Srrs			SCTP_TCB_LOCK(stcb);
1073163953Srrs			asoc = &stcb->asoc;
1074163953Srrs			if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
1075163953Srrs				/* We are about to be freed, out of here */
1076163953Srrs				SCTP_TCB_UNLOCK(stcb);
1077163953Srrs				SCTP_INP_RUNLOCK(inp);
1078163953Srrs				return (0);
1079163953Srrs			}
1080163953Srrs			if (((so->so_options & SO_LINGER) &&
1081163953Srrs			    (so->so_linger == 0)) ||
1082163953Srrs			    (so->so_rcv.sb_cc > 0)) {
1083163953Srrs				if (SCTP_GET_STATE(asoc) !=
1084163953Srrs				    SCTP_STATE_COOKIE_WAIT) {
1085163953Srrs					/* Left with Data unread */
1086163953Srrs					struct mbuf *err;
1087163953Srrs
1088163953Srrs					err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA);
1089163953Srrs					if (err) {
1090163953Srrs						/*
1091163953Srrs						 * Fill in the user
1092163953Srrs						 * initiated abort
1093163953Srrs						 */
1094163953Srrs						struct sctp_paramhdr *ph;
1095163953Srrs
1096163953Srrs						ph = mtod(err, struct sctp_paramhdr *);
1097163953Srrs						err->m_len = sizeof(struct sctp_paramhdr);
1098163953Srrs						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
1099163953Srrs						ph->param_length = htons(err->m_len);
1100163953Srrs					}
1101163953Srrs					sctp_send_abort_tcb(stcb, err);
1102163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
1103163953Srrs				}
1104163953Srrs				SCTP_INP_RUNLOCK(inp);
1105163953Srrs				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
1106163953Srrs				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1107163953Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1108163953Srrs				}
1109163953Srrs				sctp_free_assoc(inp, stcb, 0);
1110163953Srrs				/* No unlock tcb assoc is gone */
1111163953Srrs				splx(s);
1112163953Srrs				return (0);
1113163953Srrs			}
1114163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
1115163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
1116163953Srrs			    (asoc->stream_queue_cnt == 0)) {
1117163953Srrs				/* there is nothing queued to send, so done */
1118163953Srrs				if (asoc->locked_on_sending) {
1119163953Srrs					goto abort_anyway;
1120163953Srrs				}
1121163953Srrs				if ((SCTP_GET_STATE(asoc) !=
1122163953Srrs				    SCTP_STATE_SHUTDOWN_SENT) &&
1123163953Srrs				    (SCTP_GET_STATE(asoc) !=
1124163953Srrs				    SCTP_STATE_SHUTDOWN_ACK_SENT)) {
1125163953Srrs					/* only send SHUTDOWN 1st time thru */
1126163953Srrs					sctp_stop_timers_for_shutdown(stcb);
1127163953Srrs					sctp_send_shutdown(stcb,
1128163953Srrs					    stcb->asoc.primary_destination);
1129163953Srrs					sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3);
1130163953Srrs					asoc->state = SCTP_STATE_SHUTDOWN_SENT;
1131163953Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1132163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1133163953Srrs					    stcb->sctp_ep, stcb,
1134163953Srrs					    asoc->primary_destination);
1135163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1136163953Srrs					    stcb->sctp_ep, stcb,
1137163953Srrs					    asoc->primary_destination);
1138163953Srrs				}
1139163953Srrs			} else {
1140163953Srrs				/*
1141163953Srrs				 * we still got (or just got) data to send,
1142163953Srrs				 * so set SHUTDOWN_PENDING
1143163953Srrs				 */
1144163953Srrs				/*
1145163953Srrs				 * XXX sockets draft says that SCTP_EOF
1146163953Srrs				 * should be sent with no data. currently,
1147163953Srrs				 * we will allow user data to be sent first
1148163953Srrs				 * and move to SHUTDOWN-PENDING
1149163953Srrs				 */
1150163953Srrs				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1151163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
1152163953Srrs				    asoc->primary_destination);
1153163953Srrs				if (asoc->locked_on_sending) {
1154163953Srrs					/* Locked to send out the data */
1155163953Srrs					struct sctp_stream_queue_pending *sp;
1156163953Srrs
1157163953Srrs					sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1158163953Srrs					if (sp == NULL) {
1159163959Srrs						printf("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1160163953Srrs						    asoc->locked_on_sending->stream_no);
1161163953Srrs					} else {
1162163953Srrs						if ((sp->length == 0) && (sp->msg_is_complete == 0))
1163163953Srrs							asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
1164163953Srrs					}
1165163953Srrs				}
1166163953Srrs				if (TAILQ_EMPTY(&asoc->send_queue) &&
1167163953Srrs				    TAILQ_EMPTY(&asoc->sent_queue) &&
1168163953Srrs				    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1169163953Srrs					struct mbuf *op_err;
1170163953Srrs
1171163953Srrs			abort_anyway:
1172163953Srrs					op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
1173163953Srrs					    0, M_DONTWAIT, 1, MT_DATA);
1174163953Srrs					if (op_err) {
1175163953Srrs						/*
1176163953Srrs						 * Fill in the user
1177163953Srrs						 * initiated abort
1178163953Srrs						 */
1179163953Srrs						struct sctp_paramhdr *ph;
1180163953Srrs						uint32_t *ippp;
1181163953Srrs
1182163953Srrs						op_err->m_len =
1183163953Srrs						    (sizeof(struct sctp_paramhdr) + sizeof(uint32_t));
1184163953Srrs						ph = mtod(op_err,
1185163953Srrs						    struct sctp_paramhdr *);
1186163953Srrs						ph->param_type = htons(
1187163953Srrs						    SCTP_CAUSE_USER_INITIATED_ABT);
1188163953Srrs						ph->param_length = htons(op_err->m_len);
1189163953Srrs						ippp = (uint32_t *) (ph + 1);
1190163953Srrs						*ippp = htonl(0x30000007);
1191163953Srrs					}
1192163953Srrs					sctp_send_abort_tcb(stcb, op_err);
1193163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
1194163953Srrs					if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
1195163953Srrs					    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1196163953Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1197163953Srrs					}
1198163953Srrs					SCTP_INP_RUNLOCK(inp);
1199163953Srrs					sctp_free_assoc(inp, stcb, 0);
1200163953Srrs					splx(s);
1201163953Srrs					return (0);
1202163953Srrs				}
1203163953Srrs			}
1204163953Srrs			SCTP_TCB_UNLOCK(stcb);
1205163953Srrs			SCTP_INP_RUNLOCK(inp);
1206163953Srrs			splx(s);
1207163953Srrs			return (0);
1208163953Srrs		}
1209163953Srrs		/* not reached */
1210163953Srrs	} else {
1211163953Srrs		/* UDP model does not support this */
1212163953Srrs		SCTP_INP_RUNLOCK(inp);
1213163953Srrs		splx(s);
1214163953Srrs		return EOPNOTSUPP;
1215163953Srrs	}
1216163953Srrs}
1217163953Srrs
1218163953Srrsint
1219163953Srrssctp_shutdown(struct socket *so)
1220163953Srrs{
1221163953Srrs	struct sctp_inpcb *inp;
1222163953Srrs	int s;
1223163953Srrs
1224163953Srrs	s = splnet();
1225163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1226163953Srrs	if (inp == 0) {
1227163953Srrs		splx(s);
1228163953Srrs		return EINVAL;
1229163953Srrs	}
1230163953Srrs	SCTP_INP_RLOCK(inp);
1231163953Srrs	/* For UDP model this is a invalid call */
1232163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
1233163953Srrs		/* Restore the flags that the soshutdown took away. */
1234163953Srrs		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
1235163953Srrs		/* This proc will wakeup for read and do nothing (I hope) */
1236163953Srrs		splx(s);
1237163953Srrs		SCTP_INP_RUNLOCK(inp);
1238163953Srrs		return (EOPNOTSUPP);
1239163953Srrs	}
1240163953Srrs	/*
1241163953Srrs	 * Ok if we reach here its the TCP model and it is either a SHUT_WR
1242163953Srrs	 * or SHUT_RDWR. This means we put the shutdown flag against it.
1243163953Srrs	 */
1244163953Srrs	{
1245163953Srrs		struct sctp_tcb *stcb;
1246163953Srrs		struct sctp_association *asoc;
1247163953Srrs
1248163953Srrs		socantsendmore(so);
1249163953Srrs
1250163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1251163953Srrs		if (stcb == NULL) {
1252163953Srrs			/*
1253163953Srrs			 * Ok we hit the case that the shutdown call was
1254163953Srrs			 * made after an abort or something. Nothing to do
1255163953Srrs			 * now.
1256163953Srrs			 */
1257163953Srrs			splx(s);
1258163953Srrs			return (0);
1259163953Srrs		}
1260163953Srrs		SCTP_TCB_LOCK(stcb);
1261163953Srrs		asoc = &stcb->asoc;
1262163953Srrs		if (TAILQ_EMPTY(&asoc->send_queue) &&
1263163953Srrs		    TAILQ_EMPTY(&asoc->sent_queue) &&
1264163953Srrs		    (asoc->stream_queue_cnt == 0)) {
1265163953Srrs			if (asoc->locked_on_sending) {
1266163953Srrs				goto abort_anyway;
1267163953Srrs			}
1268163953Srrs			/* there is nothing queued to send, so I'm done... */
1269163953Srrs			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
1270163953Srrs				/* only send SHUTDOWN the first time through */
1271163953Srrs				sctp_stop_timers_for_shutdown(stcb);
1272163953Srrs				sctp_send_shutdown(stcb,
1273163953Srrs				    stcb->asoc.primary_destination);
1274163953Srrs				sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3);
1275163953Srrs				asoc->state = SCTP_STATE_SHUTDOWN_SENT;
1276163953Srrs				SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1277163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1278163953Srrs				    stcb->sctp_ep, stcb,
1279163953Srrs				    asoc->primary_destination);
1280163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1281163953Srrs				    stcb->sctp_ep, stcb,
1282163953Srrs				    asoc->primary_destination);
1283163953Srrs			}
1284163953Srrs		} else {
1285163953Srrs			/*
1286163953Srrs			 * we still got (or just got) data to send, so set
1287163953Srrs			 * SHUTDOWN_PENDING
1288163953Srrs			 */
1289163953Srrs			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1290163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
1291163953Srrs			    asoc->primary_destination);
1292163953Srrs
1293163953Srrs			if (asoc->locked_on_sending) {
1294163953Srrs				/* Locked to send out the data */
1295163953Srrs				struct sctp_stream_queue_pending *sp;
1296163953Srrs
1297163953Srrs				sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1298163953Srrs				if (sp == NULL) {
1299163959Srrs					printf("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1300163953Srrs					    asoc->locked_on_sending->stream_no);
1301163953Srrs				} else {
1302163953Srrs					if ((sp->length == 0) && (sp->msg_is_complete == 0)) {
1303163953Srrs						asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
1304163953Srrs					}
1305163953Srrs				}
1306163953Srrs			}
1307163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
1308163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
1309163953Srrs			    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1310163953Srrs				struct mbuf *op_err;
1311163953Srrs
1312163953Srrs		abort_anyway:
1313163953Srrs				op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
1314163953Srrs				    0, M_DONTWAIT, 1, MT_DATA);
1315163953Srrs				if (op_err) {
1316163953Srrs					/* Fill in the user initiated abort */
1317163953Srrs					struct sctp_paramhdr *ph;
1318163953Srrs					uint32_t *ippp;
1319163953Srrs
1320163953Srrs					op_err->m_len =
1321163953Srrs					    sizeof(struct sctp_paramhdr) + sizeof(uint32_t);
1322163953Srrs					ph = mtod(op_err,
1323163953Srrs					    struct sctp_paramhdr *);
1324163953Srrs					ph->param_type = htons(
1325163953Srrs					    SCTP_CAUSE_USER_INITIATED_ABT);
1326163953Srrs					ph->param_length = htons(op_err->m_len);
1327163953Srrs					ippp = (uint32_t *) (ph + 1);
1328163953Srrs					*ippp = htonl(0x30000008);
1329163953Srrs				}
1330163953Srrs				sctp_abort_an_association(stcb->sctp_ep, stcb,
1331163953Srrs				    SCTP_RESPONSE_TO_USER_REQ,
1332163953Srrs				    op_err);
1333163953Srrs				goto skip_unlock;
1334163953Srrs			}
1335163953Srrs		}
1336163953Srrs		SCTP_TCB_UNLOCK(stcb);
1337163953Srrs	}
1338163953Srrsskip_unlock:
1339163953Srrs	SCTP_INP_RUNLOCK(inp);
1340163953Srrs	splx(s);
1341163953Srrs	return 0;
1342163953Srrs}
1343163953Srrs
1344163953Srrs/*
1345163953Srrs * copies a "user" presentable address and removes embedded scope, etc.
1346163953Srrs * returns 0 on success, 1 on error
1347163953Srrs */
1348163953Srrsstatic uint32_t
1349163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
1350163953Srrs{
1351163953Srrs	struct sockaddr_in6 lsa6;
1352163953Srrs
1353163953Srrs	sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
1354163953Srrs	    &lsa6);
1355163953Srrs	memcpy(ss, sa, sa->sa_len);
1356163953Srrs	return (0);
1357163953Srrs}
1358163953Srrs
1359163953Srrs
1360163953Srrs
1361163953Srrsstatic int
1362163953Srrssctp_fill_up_addresses(struct sctp_inpcb *inp,
1363163953Srrs    struct sctp_tcb *stcb,
1364163953Srrs    int limit,
1365163953Srrs    struct sockaddr_storage *sas)
1366163953Srrs{
1367163953Srrs	struct ifnet *ifn;
1368163953Srrs	struct ifaddr *ifa;
1369163953Srrs	int loopback_scope, ipv4_local_scope, local_scope, site_scope, actual;
1370163953Srrs	int ipv4_addr_legal, ipv6_addr_legal;
1371163953Srrs
1372163953Srrs	actual = 0;
1373163953Srrs	if (limit <= 0)
1374163953Srrs		return (actual);
1375163953Srrs
1376163953Srrs	if (stcb) {
1377163953Srrs		/* Turn on all the appropriate scope */
1378163953Srrs		loopback_scope = stcb->asoc.loopback_scope;
1379163953Srrs		ipv4_local_scope = stcb->asoc.ipv4_local_scope;
1380163953Srrs		local_scope = stcb->asoc.local_scope;
1381163953Srrs		site_scope = stcb->asoc.site_scope;
1382163953Srrs	} else {
1383163953Srrs		/* Turn on ALL scope, since we look at the EP */
1384163953Srrs		loopback_scope = ipv4_local_scope = local_scope =
1385163953Srrs		    site_scope = 1;
1386163953Srrs	}
1387163953Srrs	ipv4_addr_legal = ipv6_addr_legal = 0;
1388163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1389163953Srrs		ipv6_addr_legal = 1;
1390163953Srrs		if (
1391163953Srrs		    (((struct in6pcb *)inp)->inp_flags & IN6P_IPV6_V6ONLY)
1392163953Srrs		    == 0) {
1393163953Srrs			ipv4_addr_legal = 1;
1394163953Srrs		}
1395163953Srrs	} else {
1396163953Srrs		ipv4_addr_legal = 1;
1397163953Srrs	}
1398163953Srrs
1399163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1400163953Srrs		TAILQ_FOREACH(ifn, &ifnet, if_list) {
1401163953Srrs			if ((loopback_scope == 0) &&
1402163953Srrs			    (ifn->if_type == IFT_LOOP)) {
1403163953Srrs				/* Skip loopback if loopback_scope not set */
1404163953Srrs				continue;
1405163953Srrs			}
1406163953Srrs			TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
1407163953Srrs				if (stcb) {
1408163953Srrs					/*
1409163953Srrs					 * For the BOUND-ALL case, the list
1410163953Srrs					 * associated with a TCB is Always
1411163953Srrs					 * considered a reverse list.. i.e.
1412163953Srrs					 * it lists addresses that are NOT
1413163953Srrs					 * part of the association. If this
1414163953Srrs					 * is one of those we must skip it.
1415163953Srrs					 */
1416163953Srrs					if (sctp_is_addr_restricted(stcb,
1417163953Srrs					    ifa->ifa_addr)) {
1418163953Srrs						continue;
1419163953Srrs					}
1420163953Srrs				}
1421163953Srrs				if ((ifa->ifa_addr->sa_family == AF_INET) &&
1422163953Srrs				    (ipv4_addr_legal)) {
1423163953Srrs					struct sockaddr_in *sin;
1424163953Srrs
1425163953Srrs					sin = (struct sockaddr_in *)ifa->ifa_addr;
1426163953Srrs					if (sin->sin_addr.s_addr == 0) {
1427163953Srrs						/*
1428163953Srrs						 * we skip unspecifed
1429163953Srrs						 * addresses
1430163953Srrs						 */
1431163953Srrs						continue;
1432163953Srrs					}
1433163953Srrs					if ((ipv4_local_scope == 0) &&
1434163953Srrs					    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
1435163953Srrs						continue;
1436163953Srrs					}
1437163953Srrs					if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) {
1438163953Srrs						in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
1439163953Srrs						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1440163953Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
1441163953Srrs						actual += sizeof(sizeof(struct sockaddr_in6));
1442163953Srrs					} else {
1443163953Srrs						memcpy(sas, sin, sizeof(*sin));
1444163953Srrs						((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1445163953Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
1446163953Srrs						actual += sizeof(*sin);
1447163953Srrs					}
1448163953Srrs					if (actual >= limit) {
1449163953Srrs						return (actual);
1450163953Srrs					}
1451163953Srrs				} else if ((ifa->ifa_addr->sa_family == AF_INET6) &&
1452163953Srrs				    (ipv6_addr_legal)) {
1453163953Srrs					struct sockaddr_in6 *sin6;
1454163953Srrs
1455163953Srrs					sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
1456163953Srrs					if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1457163953Srrs						/*
1458163953Srrs						 * we skip unspecifed
1459163953Srrs						 * addresses
1460163953Srrs						 */
1461163953Srrs						continue;
1462163953Srrs					}
1463163953Srrs					if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1464163953Srrs						if (local_scope == 0)
1465163953Srrs							continue;
1466163953Srrs						if (sin6->sin6_scope_id == 0) {
1467163953Srrs							if (sa6_recoverscope(sin6) != 0)
1468163953Srrs								/*
1469163953Srrs								 * bad link
1470163953Srrs								 * local
1471163953Srrs								 * address
1472163953Srrs								 */
1473163953Srrs								continue;
1474163953Srrs						}
1475163953Srrs					}
1476163953Srrs					if ((site_scope == 0) &&
1477163953Srrs					    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
1478163953Srrs						continue;
1479163953Srrs					}
1480163953Srrs					memcpy(sas, sin6, sizeof(*sin6));
1481163953Srrs					((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1482163953Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
1483163953Srrs					actual += sizeof(*sin6);
1484163953Srrs					if (actual >= limit) {
1485163953Srrs						return (actual);
1486163953Srrs					}
1487163953Srrs				}
1488163953Srrs			}
1489163953Srrs		}
1490163953Srrs	} else {
1491163953Srrs		struct sctp_laddr *laddr;
1492163953Srrs
1493163953Srrs		/*
1494163953Srrs		 * If we have a TCB and we do NOT support ASCONF (it's
1495163953Srrs		 * turned off or otherwise) then the list is always the true
1496163953Srrs		 * list of addresses (the else case below).  Otherwise the
1497163953Srrs		 * list on the association is a list of addresses that are
1498163953Srrs		 * NOT part of the association.
1499163953Srrs		 */
1500163953Srrs		if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
1501163953Srrs			/* The list is a NEGATIVE list */
1502163953Srrs			LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1503163953Srrs				if (stcb) {
1504163953Srrs					if (sctp_is_addr_restricted(stcb, laddr->ifa->ifa_addr)) {
1505163953Srrs						continue;
1506163953Srrs					}
1507163953Srrs				}
1508163953Srrs				if (sctp_fill_user_address(sas, laddr->ifa->ifa_addr))
1509163953Srrs					continue;
1510163953Srrs
1511163953Srrs				((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1512163953Srrs				sas = (struct sockaddr_storage *)((caddr_t)sas +
1513163953Srrs				    laddr->ifa->ifa_addr->sa_len);
1514163953Srrs				actual += laddr->ifa->ifa_addr->sa_len;
1515163953Srrs				if (actual >= limit) {
1516163953Srrs					return (actual);
1517163953Srrs				}
1518163953Srrs			}
1519163953Srrs		} else {
1520163953Srrs			/* The list is a positive list if present */
1521163953Srrs			if (stcb) {
1522163953Srrs				/* Must use the specific association list */
1523163953Srrs				LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list,
1524163953Srrs				    sctp_nxt_addr) {
1525163953Srrs					if (sctp_fill_user_address(sas,
1526163953Srrs					    laddr->ifa->ifa_addr))
1527163953Srrs						continue;
1528163953Srrs					((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1529163953Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas +
1530163953Srrs					    laddr->ifa->ifa_addr->sa_len);
1531163953Srrs					actual += laddr->ifa->ifa_addr->sa_len;
1532163953Srrs					if (actual >= limit) {
1533163953Srrs						return (actual);
1534163953Srrs					}
1535163953Srrs				}
1536163953Srrs			} else {
1537163953Srrs				/*
1538163953Srrs				 * No endpoint so use the endpoints
1539163953Srrs				 * individual list
1540163953Srrs				 */
1541163953Srrs				LIST_FOREACH(laddr, &inp->sctp_addr_list,
1542163953Srrs				    sctp_nxt_addr) {
1543163953Srrs					if (sctp_fill_user_address(sas,
1544163953Srrs					    laddr->ifa->ifa_addr))
1545163953Srrs						continue;
1546163953Srrs					((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1547163953Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas +
1548163953Srrs					    laddr->ifa->ifa_addr->sa_len);
1549163953Srrs					actual += laddr->ifa->ifa_addr->sa_len;
1550163953Srrs					if (actual >= limit) {
1551163953Srrs						return (actual);
1552163953Srrs					}
1553163953Srrs				}
1554163953Srrs			}
1555163953Srrs		}
1556163953Srrs	}
1557163953Srrs	return (actual);
1558163953Srrs}
1559163953Srrs
1560163953Srrsstatic int
1561163953Srrssctp_count_max_addresses(struct sctp_inpcb *inp)
1562163953Srrs{
1563163953Srrs	int cnt = 0;
1564163953Srrs
1565163953Srrs	/*
1566163953Srrs	 * In both sub-set bound an bound_all cases we return the MAXIMUM
1567163953Srrs	 * number of addresses that you COULD get. In reality the sub-set
1568163953Srrs	 * bound may have an exclusion list for a given TCB OR in the
1569163953Srrs	 * bound-all case a TCB may NOT include the loopback or other
1570163953Srrs	 * addresses as well.
1571163953Srrs	 */
1572163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1573163953Srrs		struct ifnet *ifn;
1574163953Srrs		struct ifaddr *ifa;
1575163953Srrs
1576163953Srrs		TAILQ_FOREACH(ifn, &ifnet, if_list) {
1577163953Srrs			TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list) {
1578163953Srrs				/* Count them if they are the right type */
1579163953Srrs				if (ifa->ifa_addr->sa_family == AF_INET) {
1580163953Srrs					if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)
1581163953Srrs						cnt += sizeof(struct sockaddr_in6);
1582163953Srrs					else
1583163953Srrs						cnt += sizeof(struct sockaddr_in);
1584163953Srrs
1585163953Srrs				} else if (ifa->ifa_addr->sa_family == AF_INET6)
1586163953Srrs					cnt += sizeof(struct sockaddr_in6);
1587163953Srrs			}
1588163953Srrs		}
1589163953Srrs	} else {
1590163953Srrs		struct sctp_laddr *laddr;
1591163953Srrs
1592163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1593163953Srrs			if (laddr->ifa->ifa_addr->sa_family == AF_INET) {
1594163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)
1595163953Srrs					cnt += sizeof(struct sockaddr_in6);
1596163953Srrs				else
1597163953Srrs					cnt += sizeof(struct sockaddr_in);
1598163953Srrs
1599163953Srrs			} else if (laddr->ifa->ifa_addr->sa_family == AF_INET6)
1600163953Srrs				cnt += sizeof(struct sockaddr_in6);
1601163953Srrs		}
1602163953Srrs	}
1603163953Srrs	return (cnt);
1604163953Srrs}
1605163953Srrs
1606163953Srrsstatic int
1607163953Srrssctp_do_connect_x(struct socket *so,
1608163953Srrs    struct sctp_inpcb *inp,
1609163953Srrs    struct mbuf *m,
1610163953Srrs    struct thread *p,
1611163953Srrs    int delay
1612163953Srrs)
1613163953Srrs{
1614163953Srrs	int s = splnet();
1615163953Srrs
1616163953Srrs	int error = 0;
1617163953Srrs	int creat_lock_on = 0;
1618163953Srrs	struct sctp_tcb *stcb = NULL;
1619163953Srrs	struct sockaddr *sa;
1620163953Srrs	int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr, i, incr, at;
1621163953Srrs
1622163953Srrs#ifdef SCTP_DEBUG
1623163953Srrs	if (sctp_debug_on & SCTP_DEBUG_PCB1) {
1624163953Srrs		printf("Connectx called\n");
1625163953Srrs	}
1626163953Srrs#endif				/* SCTP_DEBUG */
1627163953Srrs
1628163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1629163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1630163953Srrs		/* We are already connected AND the TCP model */
1631163953Srrs		splx(s);
1632163953Srrs		return (EADDRINUSE);
1633163953Srrs	}
1634163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) {
1635163953Srrs		splx(s);
1636163953Srrs		return (EINVAL);
1637163953Srrs	}
1638163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1639163953Srrs		SCTP_INP_RLOCK(inp);
1640163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1641163953Srrs		SCTP_INP_RUNLOCK(inp);
1642163953Srrs	}
1643163953Srrs	if (stcb) {
1644163953Srrs		splx(s);
1645163953Srrs		return (EALREADY);
1646163953Srrs
1647163953Srrs	}
1648163953Srrs	SCTP_INP_INCR_REF(inp);
1649163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
1650163953Srrs	creat_lock_on = 1;
1651163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1652163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
1653163953Srrs		error = EFAULT;
1654163953Srrs		goto out_now;
1655163953Srrs	}
1656163953Srrs	totaddrp = mtod(m, int *);
1657163953Srrs	totaddr = *totaddrp;
1658163953Srrs	sa = (struct sockaddr *)(totaddrp + 1);
1659163953Srrs	at = incr = 0;
1660163953Srrs	/* account and validate addresses */
1661163953Srrs	for (i = 0; i < totaddr; i++) {
1662163953Srrs		if (sa->sa_family == AF_INET) {
1663163953Srrs			num_v4++;
1664163953Srrs			incr = sizeof(struct sockaddr_in);
1665163953Srrs		} else if (sa->sa_family == AF_INET6) {
1666163953Srrs			struct sockaddr_in6 *sin6;
1667163953Srrs
1668163953Srrs			sin6 = (struct sockaddr_in6 *)sa;
1669163953Srrs			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1670163953Srrs				/* Must be non-mapped for connectx */
1671163953Srrs				error = EINVAL;
1672163953Srrs				goto out_now;
1673163953Srrs			}
1674163953Srrs			num_v6++;
1675163953Srrs			incr = sizeof(struct sockaddr_in6);
1676163953Srrs		} else {
1677163953Srrs			totaddr = i;
1678163953Srrs			break;
1679163953Srrs		}
1680163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
1681163953Srrs		if (stcb != NULL) {
1682163953Srrs			/* Already have or am bring up an association */
1683163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
1684163953Srrs			creat_lock_on = 0;
1685163953Srrs			SCTP_TCB_UNLOCK(stcb);
1686163953Srrs			error = EALREADY;
1687163953Srrs			goto out_now;
1688163953Srrs		}
1689163953Srrs		if ((at + incr) > m->m_len) {
1690163953Srrs			totaddr = i;
1691163953Srrs			break;
1692163953Srrs		}
1693163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + incr);
1694163953Srrs	}
1695163953Srrs	sa = (struct sockaddr *)(totaddrp + 1);
1696163953Srrs#ifdef INET6
1697163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
1698163953Srrs	    (num_v6 > 0)) {
1699163953Srrs		splx(s);
1700163953Srrs		error = EINVAL;
1701163953Srrs		goto out_now;
1702163953Srrs	}
1703163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1704163953Srrs	    (num_v4 > 0)) {
1705163953Srrs		struct in6pcb *inp6;
1706163953Srrs
1707163953Srrs		inp6 = (struct in6pcb *)inp;
1708163953Srrs		if (
1709163953Srrs		    (inp6->inp_flags & IN6P_IPV6_V6ONLY)
1710163953Srrs		    ) {
1711163953Srrs			/*
1712163953Srrs			 * if IPV6_V6ONLY flag, ignore connections destined
1713163953Srrs			 * to a v4 addr or v4-mapped addr
1714163953Srrs			 */
1715163953Srrs			error = EINVAL;
1716163953Srrs			goto out_now;
1717163953Srrs		}
1718163953Srrs	}
1719163953Srrs#endif				/* INET6 */
1720163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1721163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
1722163953Srrs		/* Bind a ephemeral port */
1723163953Srrs		SCTP_INP_WUNLOCK(inp);
1724163953Srrs		error = sctp_inpcb_bind(so, NULL, p);
1725163953Srrs		if (error) {
1726163953Srrs			goto out_now;
1727163953Srrs		}
1728163953Srrs	} else {
1729163953Srrs		SCTP_INP_WUNLOCK(inp);
1730163953Srrs	}
1731163953Srrs
1732163953Srrs	/* We are GOOD to go */
1733163953Srrs	stcb = sctp_aloc_assoc(inp, sa, 1, &error, 0);
1734163953Srrs	if (stcb == NULL) {
1735163953Srrs		/* Gak! no memory */
1736163953Srrs		error = ENOMEM;
1737163953Srrs		goto out_now;
1738163953Srrs	}
1739163953Srrs	/* move to second address */
1740163953Srrs	if (sa->sa_family == AF_INET)
1741163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
1742163953Srrs	else
1743163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
1744163953Srrs
1745163953Srrs	for (i = 1; i < totaddr; i++) {
1746163953Srrs		if (sa->sa_family == AF_INET) {
1747163953Srrs			incr = sizeof(struct sockaddr_in);
1748163953Srrs			if (sctp_add_remote_addr(stcb, sa, 0, 8)) {
1749163953Srrs				/* assoc gone no un-lock */
1750163953Srrs				sctp_free_assoc(inp, stcb, 0);
1751163953Srrs				error = ENOBUFS;
1752163953Srrs				goto out_now;
1753163953Srrs			}
1754163953Srrs		} else if (sa->sa_family == AF_INET6) {
1755163953Srrs			incr = sizeof(struct sockaddr_in6);
1756163953Srrs			if (sctp_add_remote_addr(stcb, sa, 0, 8)) {
1757163953Srrs				/* assoc gone no un-lock */
1758163953Srrs				sctp_free_assoc(inp, stcb, 0);
1759163953Srrs				error = ENOBUFS;
1760163953Srrs				goto out_now;
1761163953Srrs			}
1762163953Srrs		}
1763163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + incr);
1764163953Srrs	}
1765163953Srrs	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
1766163953Srrs
1767163953Srrs	/* initialize authentication parameters for the assoc */
1768163953Srrs	sctp_initialize_auth_params(inp, stcb);
1769163953Srrs
1770163953Srrs	if (delay) {
1771163953Srrs		/* doing delayed connection */
1772163953Srrs		stcb->asoc.delayed_connection = 1;
1773163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
1774163953Srrs	} else {
1775163953Srrs		SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1776163953Srrs		sctp_send_initiate(inp, stcb);
1777163953Srrs	}
1778163953Srrs	SCTP_TCB_UNLOCK(stcb);
1779163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1780163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1781163953Srrs		/* Set the connected flag so we can queue data */
1782163953Srrs		soisconnecting(so);
1783163953Srrs	}
1784163953Srrsout_now:
1785163953Srrs	if (creat_lock_on)
1786163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1787163953Srrs	SCTP_INP_DECR_REF(inp);
1788163953Srrs	splx(s);
1789163953Srrs	return error;
1790163953Srrs}
1791163953Srrs
1792163953Srrs
1793163953Srrs
1794163953Srrsstatic int
1795163953Srrssctp_optsget(struct socket *so,
1796163953Srrs    int opt,
1797163953Srrs    struct mbuf **mp,
1798163953Srrs    struct thread *p
1799163953Srrs)
1800163953Srrs{
1801163953Srrs	struct sctp_inpcb *inp;
1802163953Srrs	struct mbuf *m;
1803163953Srrs	int error, optval = 0;
1804163953Srrs	struct sctp_tcb *stcb = NULL;
1805163953Srrs
1806163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1807163953Srrs	if (inp == 0)
1808163953Srrs		return EINVAL;
1809163953Srrs	error = 0;
1810163953Srrs
1811163953Srrs	if (mp == NULL) {
1812163953Srrs		return (EINVAL);
1813163953Srrs	}
1814163953Srrs	m = *mp;
1815163953Srrs	if (m == NULL) {
1816163953Srrs		/* Got to have a mbuf */
1817163953Srrs		return (EINVAL);
1818163953Srrs	}
1819163953Srrs	switch (opt) {
1820163953Srrs	case SCTP_NODELAY:
1821163953Srrs	case SCTP_AUTOCLOSE:
1822163953Srrs	case SCTP_EXPLICIT_EOR:
1823163953Srrs	case SCTP_AUTO_ASCONF:
1824163953Srrs	case SCTP_DISABLE_FRAGMENTS:
1825163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
1826163953Srrs	case SCTP_USE_EXT_RCVINFO:
1827163953Srrs		SCTP_INP_RLOCK(inp);
1828163953Srrs		switch (opt) {
1829163953Srrs		case SCTP_DISABLE_FRAGMENTS:
1830163953Srrs			optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
1831163953Srrs			break;
1832163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
1833163953Srrs			optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
1834163953Srrs			break;
1835163953Srrs		case SCTP_AUTO_ASCONF:
1836163953Srrs			optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
1837163953Srrs			break;
1838163953Srrs		case SCTP_EXPLICIT_EOR:
1839163953Srrs			optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
1840163953Srrs			break;
1841163953Srrs		case SCTP_NODELAY:
1842163953Srrs			optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
1843163953Srrs			break;
1844163953Srrs		case SCTP_USE_EXT_RCVINFO:
1845163953Srrs			optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
1846163953Srrs			break;
1847163953Srrs		case SCTP_AUTOCLOSE:
1848163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
1849163953Srrs				optval = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
1850163953Srrs			else
1851163953Srrs				optval = 0;
1852163953Srrs			break;
1853163953Srrs
1854163953Srrs		default:
1855163953Srrs			error = ENOPROTOOPT;
1856163953Srrs		}		/* end switch (sopt->sopt_name) */
1857163953Srrs		if (opt != SCTP_AUTOCLOSE) {
1858163953Srrs			/* make it an "on/off" value */
1859163953Srrs			optval = (optval != 0);
1860163953Srrs		}
1861163953Srrs		if ((size_t)m->m_len < sizeof(int)) {
1862163953Srrs			error = EINVAL;
1863163953Srrs		}
1864163953Srrs		SCTP_INP_RUNLOCK(inp);
1865163953Srrs		if (error == 0) {
1866163953Srrs			/* return the option value */
1867163953Srrs			*mtod(m, int *)= optval;
1868163953Srrs			m->m_len = sizeof(optval);
1869163953Srrs		}
1870163953Srrs		break;
1871163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
1872163953Srrs		{
1873163953Srrs			if ((size_t)m->m_len < sizeof(unsigned int)) {
1874163953Srrs				error = EINVAL;
1875163953Srrs				break;
1876163953Srrs			}
1877163953Srrs			*mtod(m, unsigned int *)= inp->partial_delivery_point;
1878163953Srrs			m->m_len = sizeof(unsigned int);
1879163953Srrs		}
1880163953Srrs		break;
1881163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
1882163953Srrs		{
1883163953Srrs			if ((size_t)m->m_len < sizeof(unsigned int)) {
1884163953Srrs				error = EINVAL;
1885163953Srrs				break;
1886163953Srrs			}
1887163953Srrs			*mtod(m, unsigned int *)= sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
1888163953Srrs			m->m_len = sizeof(unsigned int);
1889163953Srrs		}
1890163953Srrs		break;
1891163953Srrs	case SCTP_CMT_ON_OFF:
1892163953Srrs		{
1893163953Srrs			if ((size_t)m->m_len < sizeof(unsigned int)) {
1894163953Srrs				error = EINVAL;
1895163953Srrs				break;
1896163953Srrs			}
1897163953Srrs			*mtod(m, unsigned int *)= sctp_cmt_sockopt_on_off;
1898163953Srrs			m->m_len = sizeof(unsigned int);
1899163953Srrs		}
1900163953Srrs		break;
1901163953Srrs	case SCTP_CMT_USE_DAC:
1902163953Srrs		{
1903163953Srrs			*mtod(m, unsigned int *)= sctp_cmt_sockopt_use_dac;
1904163953Srrs			m->m_len = sizeof(unsigned int);
1905163953Srrs		}
1906163953Srrs		break;
1907163953Srrs	case SCTP_GET_ADDR_LEN:
1908163953Srrs		{
1909163953Srrs			struct sctp_assoc_value *av;
1910163953Srrs
1911163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assoc_value)) {
1912163953Srrs				error = EINVAL;
1913163953Srrs				break;
1914163953Srrs			}
1915163953Srrs			av = mtod(m, struct sctp_assoc_value *);
1916163953Srrs			error = EINVAL;
1917163953Srrs#ifdef AF_INET
1918163953Srrs			if (av->assoc_value == AF_INET) {
1919163953Srrs				av->assoc_value = sizeof(struct sockaddr_in);
1920163953Srrs				error = 0;
1921163953Srrs			}
1922163953Srrs#endif
1923163953Srrs#ifdef AF_INET6
1924163953Srrs			if (av->assoc_value == AF_INET6) {
1925163953Srrs				av->assoc_value = sizeof(struct sockaddr_in6);
1926163953Srrs				error = 0;
1927163953Srrs			}
1928163953Srrs#endif
1929163953Srrs		}
1930163953Srrs		break;
1931163953Srrs	case SCTP_GET_ASOC_ID_LIST:
1932163953Srrs		{
1933163953Srrs			struct sctp_assoc_ids *ids;
1934163953Srrs			int cnt, at;
1935163953Srrs			uint16_t orig;
1936163953Srrs
1937163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assoc_ids)) {
1938163953Srrs				error = EINVAL;
1939163953Srrs				break;
1940163953Srrs			}
1941163953Srrs			ids = mtod(m, struct sctp_assoc_ids *);
1942163953Srrs			cnt = 0;
1943163953Srrs			SCTP_INP_RLOCK(inp);
1944163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
1945163953Srrs			if (stcb == NULL) {
1946163953Srrs		none_out_now:
1947163953Srrs				ids->asls_numb_present = 0;
1948163953Srrs				ids->asls_more_to_get = 0;
1949163953Srrs				SCTP_INP_RUNLOCK(inp);
1950163953Srrs				break;
1951163953Srrs			}
1952163953Srrs			orig = ids->asls_assoc_start;
1953163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
1954163953Srrs			while (orig) {
1955163953Srrs				stcb = LIST_NEXT(stcb, sctp_tcblist);
1956163953Srrs				orig--;
1957163953Srrs				cnt--;
1958163953Srrs				if (stcb == NULL)
1959163953Srrs					goto none_out_now;
1960163953Srrs			}
1961163953Srrs			if (stcb == NULL)
1962163953Srrs				goto none_out_now;
1963163953Srrs
1964163953Srrs			at = 0;
1965163953Srrs			ids->asls_numb_present = 0;
1966163953Srrs			ids->asls_more_to_get = 1;
1967163953Srrs			while (at < MAX_ASOC_IDS_RET) {
1968163953Srrs				ids->asls_assoc_id[at] = sctp_get_associd(stcb);
1969163953Srrs				at++;
1970163953Srrs				ids->asls_numb_present++;
1971163953Srrs				stcb = LIST_NEXT(stcb, sctp_tcblist);
1972163953Srrs				if (stcb == NULL) {
1973163953Srrs					ids->asls_more_to_get = 0;
1974163953Srrs					break;
1975163953Srrs				}
1976163953Srrs			}
1977163953Srrs			SCTP_INP_RUNLOCK(inp);
1978163953Srrs		}
1979163953Srrs		break;
1980163953Srrs	case SCTP_CONTEXT:
1981163953Srrs		{
1982163953Srrs
1983163953Srrs			struct sctp_assoc_value *av;
1984163953Srrs
1985163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assoc_value)) {
1986163953Srrs				error = EINVAL;
1987163953Srrs				break;
1988163953Srrs			}
1989163953Srrs			av = mtod(m, struct sctp_assoc_value *);
1990163953Srrs			if (av->assoc_id) {
1991163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, av->assoc_id, 1);
1992163953Srrs				if (stcb == NULL) {
1993163953Srrs					error = ENOTCONN;
1994163953Srrs				} else {
1995163953Srrs					av->assoc_value = stcb->asoc.context;
1996163953Srrs					SCTP_TCB_UNLOCK(stcb);
1997163953Srrs				}
1998163953Srrs			} else {
1999163953Srrs				av->assoc_value = inp->sctp_context;
2000163953Srrs			}
2001163953Srrs		}
2002163953Srrs		break;
2003163953Srrs	case SCTP_GET_NONCE_VALUES:
2004163953Srrs		{
2005163953Srrs			struct sctp_get_nonce_values *gnv;
2006163953Srrs
2007163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_get_nonce_values)) {
2008163953Srrs				error = EINVAL;
2009163953Srrs				break;
2010163953Srrs			}
2011163953Srrs			gnv = mtod(m, struct sctp_get_nonce_values *);
2012163953Srrs			stcb = sctp_findassociation_ep_asocid(inp, gnv->gn_assoc_id, 1);
2013163953Srrs			if (stcb == NULL) {
2014163953Srrs				error = ENOTCONN;
2015163953Srrs			} else {
2016163953Srrs				gnv->gn_peers_tag = stcb->asoc.peer_vtag;
2017163953Srrs				gnv->gn_local_tag = stcb->asoc.my_vtag;
2018163953Srrs				SCTP_TCB_UNLOCK(stcb);
2019163953Srrs			}
2020163953Srrs
2021163953Srrs		}
2022163953Srrs		break;
2023163953Srrs	case SCTP_DELAYED_ACK_TIME:
2024163953Srrs		{
2025163953Srrs			struct sctp_assoc_value *tm;
2026163953Srrs
2027163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assoc_value)) {
2028163953Srrs				error = EINVAL;
2029163953Srrs				break;
2030163953Srrs			}
2031163953Srrs			tm = mtod(m, struct sctp_assoc_value *);
2032163953Srrs
2033163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2034163953Srrs				SCTP_INP_RLOCK(inp);
2035163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2036163953Srrs				if (stcb) {
2037163953Srrs					SCTP_TCB_LOCK(stcb);
2038163953Srrs					tm->assoc_value = stcb->asoc.delayed_ack;
2039163953Srrs					SCTP_TCB_UNLOCK(stcb);
2040163953Srrs				} else {
2041163953Srrs					tm->assoc_value = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
2042163953Srrs				}
2043163953Srrs				SCTP_INP_RUNLOCK(inp);
2044163953Srrs			} else {
2045163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, tm->assoc_id, 1);
2046163953Srrs				if (stcb == NULL) {
2047163953Srrs					error = ENOTCONN;
2048163953Srrs					tm->assoc_value = 0;
2049163953Srrs				} else {
2050163953Srrs					stcb->asoc.delayed_ack = tm->assoc_value;
2051163953Srrs					SCTP_TCB_UNLOCK(stcb);
2052163953Srrs				}
2053163953Srrs			}
2054163953Srrs		}
2055163953Srrs		break;
2056163953Srrs
2057163953Srrs	case SCTP_GET_SNDBUF_USE:
2058163953Srrs		if ((size_t)m->m_len < sizeof(struct sctp_sockstat)) {
2059163953Srrs			error = EINVAL;
2060163953Srrs		} else {
2061163953Srrs			struct sctp_sockstat *ss;
2062163953Srrs			struct sctp_tcb *stcb;
2063163953Srrs			struct sctp_association *asoc;
2064163953Srrs
2065163953Srrs			ss = mtod(m, struct sctp_sockstat *);
2066163953Srrs			stcb = sctp_findassociation_ep_asocid(inp, ss->ss_assoc_id, 1);
2067163953Srrs			if (stcb == NULL) {
2068163953Srrs				error = ENOTCONN;
2069163953Srrs			} else {
2070163953Srrs				asoc = &stcb->asoc;
2071163953Srrs				ss->ss_total_sndbuf = (uint32_t) asoc->total_output_queue_size;
2072163953Srrs				ss->ss_total_recv_buf = (uint32_t) (asoc->size_on_reasm_queue +
2073163953Srrs				    asoc->size_on_all_streams);
2074163953Srrs				SCTP_TCB_UNLOCK(stcb);
2075163953Srrs				error = 0;
2076163953Srrs				m->m_len = sizeof(struct sctp_sockstat);
2077163953Srrs			}
2078163953Srrs		}
2079163953Srrs		break;
2080163953Srrs	case SCTP_MAXBURST:
2081163953Srrs		{
2082163953Srrs			uint8_t *burst;
2083163953Srrs
2084163953Srrs			burst = mtod(m, uint8_t *);
2085163953Srrs			SCTP_INP_RLOCK(inp);
2086163953Srrs			*burst = inp->sctp_ep.max_burst;
2087163953Srrs			SCTP_INP_RUNLOCK(inp);
2088163953Srrs			m->m_len = sizeof(uint8_t);
2089163953Srrs		}
2090163953Srrs		break;
2091163953Srrs
2092163953Srrs	case SCTP_MAXSEG:
2093163953Srrs		{
2094163953Srrs			uint32_t *segsize;
2095163953Srrs			sctp_assoc_t *assoc_id;
2096163953Srrs			int ovh;
2097163953Srrs
2098163953Srrs			if ((size_t)m->m_len < sizeof(uint32_t)) {
2099163953Srrs				error = EINVAL;
2100163953Srrs				break;
2101163953Srrs			}
2102163953Srrs			if ((size_t)m->m_len < sizeof(sctp_assoc_t)) {
2103163953Srrs				error = EINVAL;
2104163953Srrs				break;
2105163953Srrs			}
2106163953Srrs			assoc_id = mtod(m, sctp_assoc_t *);
2107163953Srrs			segsize = mtod(m, uint32_t *);
2108163953Srrs			m->m_len = sizeof(uint32_t);
2109163953Srrs
2110163953Srrs			if (((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
2111163953Srrs			    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) ||
2112163953Srrs			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
2113163953Srrs				struct sctp_tcb *stcb;
2114163953Srrs
2115163953Srrs				SCTP_INP_RLOCK(inp);
2116163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2117163953Srrs				if (stcb) {
2118163953Srrs					SCTP_TCB_LOCK(stcb);
2119163953Srrs					SCTP_INP_RUNLOCK(inp);
2120163953Srrs					*segsize = sctp_get_frag_point(stcb, &stcb->asoc);
2121163953Srrs					SCTP_TCB_UNLOCK(stcb);
2122163953Srrs				} else {
2123163953Srrs					SCTP_INP_RUNLOCK(inp);
2124163953Srrs					goto skipit;
2125163953Srrs				}
2126163953Srrs			} else {
2127163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, *assoc_id, 1);
2128163953Srrs				if (stcb) {
2129163953Srrs					*segsize = sctp_get_frag_point(stcb, &stcb->asoc);
2130163953Srrs					SCTP_TCB_UNLOCK(stcb);
2131163953Srrs					break;
2132163953Srrs				}
2133163953Srrs		skipit:
2134163953Srrs				/*
2135163953Srrs				 * default is to get the max, if I can't
2136163953Srrs				 * calculate from an existing association.
2137163953Srrs				 */
2138163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2139163953Srrs					ovh = SCTP_MED_OVERHEAD;
2140163953Srrs				} else {
2141163953Srrs					ovh = SCTP_MED_V4_OVERHEAD;
2142163953Srrs				}
2143163953Srrs				*segsize = inp->sctp_frag_point - ovh;
2144163953Srrs			}
2145163953Srrs		}
2146163953Srrs		break;
2147163953Srrs
2148163953Srrs	case SCTP_SET_DEBUG_LEVEL:
2149163953Srrs#ifdef SCTP_DEBUG
2150163953Srrs		{
2151163953Srrs			uint32_t *level;
2152163953Srrs
2153163953Srrs			if ((size_t)m->m_len < sizeof(uint32_t)) {
2154163953Srrs				error = EINVAL;
2155163953Srrs				break;
2156163953Srrs			}
2157163953Srrs			level = mtod(m, uint32_t *);
2158163953Srrs			error = 0;
2159163953Srrs			*level = sctp_debug_on;
2160163953Srrs			m->m_len = sizeof(uint32_t);
2161163953Srrs			printf("Returning DEBUG LEVEL %x is set\n",
2162163953Srrs			    (uint32_t) sctp_debug_on);
2163163953Srrs		}
2164163953Srrs#else				/* SCTP_DEBUG */
2165163953Srrs		error = EOPNOTSUPP;
2166163953Srrs#endif
2167163953Srrs		break;
2168163953Srrs	case SCTP_GET_STAT_LOG:
2169163953Srrs#ifdef SCTP_STAT_LOGGING
2170163953Srrs		error = sctp_fill_stat_log(m);
2171163953Srrs#else				/* SCTP_DEBUG */
2172163953Srrs		error = EOPNOTSUPP;
2173163953Srrs#endif
2174163953Srrs		break;
2175163953Srrs	case SCTP_EVENTS:
2176163953Srrs		{
2177163953Srrs			struct sctp_event_subscribe *events;
2178163953Srrs
2179163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_event_subscribe)) {
2180163953Srrs				error = EINVAL;
2181163953Srrs				break;
2182163953Srrs			}
2183163953Srrs			events = mtod(m, struct sctp_event_subscribe *);
2184163953Srrs			memset(events, 0, sizeof(*events));
2185163953Srrs			SCTP_INP_RLOCK(inp);
2186163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
2187163953Srrs				events->sctp_data_io_event = 1;
2188163953Srrs
2189163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
2190163953Srrs				events->sctp_association_event = 1;
2191163953Srrs
2192163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
2193163953Srrs				events->sctp_address_event = 1;
2194163953Srrs
2195163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
2196163953Srrs				events->sctp_send_failure_event = 1;
2197163953Srrs
2198163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
2199163953Srrs				events->sctp_peer_error_event = 1;
2200163953Srrs
2201163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
2202163953Srrs				events->sctp_shutdown_event = 1;
2203163953Srrs
2204163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
2205163953Srrs				events->sctp_partial_delivery_event = 1;
2206163953Srrs
2207163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
2208163953Srrs				events->sctp_adaptation_layer_event = 1;
2209163953Srrs
2210163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
2211163953Srrs				events->sctp_authentication_event = 1;
2212163953Srrs
2213163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
2214163953Srrs				events->sctp_stream_reset_events = 1;
2215163953Srrs			SCTP_INP_RUNLOCK(inp);
2216163953Srrs			m->m_len = sizeof(struct sctp_event_subscribe);
2217163953Srrs
2218163953Srrs		}
2219163953Srrs		break;
2220163953Srrs
2221163953Srrs	case SCTP_ADAPTATION_LAYER:
2222163953Srrs		if ((size_t)m->m_len < sizeof(int)) {
2223163953Srrs			error = EINVAL;
2224163953Srrs			break;
2225163953Srrs		}
2226163953Srrs		SCTP_INP_RLOCK(inp);
2227163953Srrs		*mtod(m, int *)= inp->sctp_ep.adaptation_layer_indicator;
2228163953Srrs		SCTP_INP_RUNLOCK(inp);
2229163953Srrs		m->m_len = sizeof(int);
2230163953Srrs		break;
2231163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
2232163953Srrs		if ((size_t)m->m_len < sizeof(int)) {
2233163953Srrs			error = EINVAL;
2234163953Srrs			break;
2235163953Srrs		}
2236163953Srrs		SCTP_INP_RLOCK(inp);
2237163953Srrs		*mtod(m, int *)= inp->sctp_ep.initial_sequence_debug;
2238163953Srrs		SCTP_INP_RUNLOCK(inp);
2239163953Srrs		m->m_len = sizeof(int);
2240163953Srrs		break;
2241163953Srrs	case SCTP_GET_LOCAL_ADDR_SIZE:
2242163953Srrs		if ((size_t)m->m_len < sizeof(int)) {
2243163953Srrs			error = EINVAL;
2244163953Srrs			break;
2245163953Srrs		}
2246163953Srrs		SCTP_INP_RLOCK(inp);
2247163953Srrs		*mtod(m, int *)= sctp_count_max_addresses(inp);
2248163953Srrs		SCTP_INP_RUNLOCK(inp);
2249163953Srrs		m->m_len = sizeof(int);
2250163953Srrs		break;
2251163953Srrs	case SCTP_GET_REMOTE_ADDR_SIZE:
2252163953Srrs		{
2253163953Srrs			sctp_assoc_t *assoc_id;
2254163953Srrs			uint32_t *val, sz;
2255163953Srrs			struct sctp_nets *net;
2256163953Srrs
2257163953Srrs			if ((size_t)m->m_len < sizeof(sctp_assoc_t)) {
2258163953Srrs				error = EINVAL;
2259163953Srrs				break;
2260163953Srrs			}
2261163953Srrs			stcb = NULL;
2262163953Srrs			val = mtod(m, uint32_t *);
2263163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2264163953Srrs				SCTP_INP_RLOCK(inp);
2265163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2266163953Srrs				if (stcb)
2267163953Srrs					SCTP_TCB_LOCK(stcb);
2268163953Srrs				SCTP_INP_RUNLOCK(inp);
2269163953Srrs			}
2270163953Srrs			if (stcb == NULL) {
2271163953Srrs				assoc_id = mtod(m, sctp_assoc_t *);
2272163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, *assoc_id, 1);
2273163953Srrs			}
2274163953Srrs			if (stcb == NULL) {
2275163953Srrs				error = EINVAL;
2276163953Srrs				break;
2277163953Srrs			}
2278163953Srrs			*val = 0;
2279163953Srrs			sz = 0;
2280163953Srrs			/* Count the sizes */
2281163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2282163953Srrs				if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
2283163953Srrs				    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
2284163953Srrs					sz += sizeof(struct sockaddr_in6);
2285163953Srrs				} else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
2286163953Srrs					sz += sizeof(struct sockaddr_in);
2287163953Srrs				} else {
2288163953Srrs					/* huh */
2289163953Srrs					break;
2290163953Srrs				}
2291163953Srrs			}
2292163953Srrs			SCTP_TCB_UNLOCK(stcb);
2293163953Srrs			*val = sz;
2294163953Srrs			m->m_len = sizeof(uint32_t);
2295163953Srrs		}
2296163953Srrs		break;
2297163953Srrs	case SCTP_GET_PEER_ADDRESSES:
2298163953Srrs		/*
2299163953Srrs		 * Get the address information, an array is passed in to
2300163953Srrs		 * fill up we pack it.
2301163953Srrs		 */
2302163953Srrs		{
2303163953Srrs			int cpsz, left;
2304163953Srrs			struct sockaddr_storage *sas;
2305163953Srrs			struct sctp_nets *net;
2306163953Srrs			struct sctp_getaddresses *saddr;
2307163953Srrs
2308163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_getaddresses)) {
2309163953Srrs				error = EINVAL;
2310163953Srrs				break;
2311163953Srrs			}
2312163953Srrs			left = m->m_len - sizeof(struct sctp_getaddresses);
2313163953Srrs			saddr = mtod(m, struct sctp_getaddresses *);
2314163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2315163953Srrs				SCTP_INP_RLOCK(inp);
2316163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2317163953Srrs				if (stcb)
2318163953Srrs					SCTP_TCB_LOCK(stcb);
2319163953Srrs				SCTP_INP_RUNLOCK(inp);
2320163953Srrs			} else
2321163953Srrs				stcb = sctp_findassociation_ep_asocid(inp,
2322163953Srrs				    saddr->sget_assoc_id, 1);
2323163953Srrs			if (stcb == NULL) {
2324163953Srrs				error = ENOENT;
2325163953Srrs				break;
2326163953Srrs			}
2327163953Srrs			m->m_len = sizeof(struct sctp_getaddresses);
2328163953Srrs			sas = (struct sockaddr_storage *)&saddr->addr[0];
2329163953Srrs
2330163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2331163953Srrs				if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
2332163953Srrs				    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
2333163953Srrs					cpsz = sizeof(struct sockaddr_in6);
2334163953Srrs				} else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
2335163953Srrs					cpsz = sizeof(struct sockaddr_in);
2336163953Srrs				} else {
2337163953Srrs					/* huh */
2338163953Srrs					break;
2339163953Srrs				}
2340163953Srrs				if (left < cpsz) {
2341163953Srrs					/* not enough room. */
2342163953Srrs					break;
2343163953Srrs				}
2344163953Srrs				if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
2345163953Srrs				    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
2346163953Srrs					/* Must map the address */
2347163953Srrs					in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
2348163953Srrs					    (struct sockaddr_in6 *)sas);
2349163953Srrs				} else {
2350163953Srrs					memcpy(sas, &net->ro._l_addr, cpsz);
2351163953Srrs				}
2352163953Srrs				((struct sockaddr_in *)sas)->sin_port = stcb->rport;
2353163953Srrs
2354163953Srrs				sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
2355163953Srrs				left -= cpsz;
2356163953Srrs				m->m_len += cpsz;
2357163953Srrs			}
2358163953Srrs			SCTP_TCB_UNLOCK(stcb);
2359163953Srrs		}
2360163953Srrs		break;
2361163953Srrs	case SCTP_GET_LOCAL_ADDRESSES:
2362163953Srrs		{
2363163953Srrs			int limit, actual;
2364163953Srrs			struct sockaddr_storage *sas;
2365163953Srrs			struct sctp_getaddresses *saddr;
2366163953Srrs
2367163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_getaddresses)) {
2368163953Srrs				error = EINVAL;
2369163953Srrs				break;
2370163953Srrs			}
2371163953Srrs			saddr = mtod(m, struct sctp_getaddresses *);
2372163953Srrs
2373163953Srrs			if (saddr->sget_assoc_id) {
2374163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2375163953Srrs					SCTP_INP_RLOCK(inp);
2376163953Srrs					stcb = LIST_FIRST(&inp->sctp_asoc_list);
2377163953Srrs					if (stcb)
2378163953Srrs						SCTP_TCB_LOCK(stcb);
2379163953Srrs					SCTP_INP_RUNLOCK(inp);
2380163953Srrs				} else
2381163953Srrs					stcb = sctp_findassociation_ep_asocid(inp, saddr->sget_assoc_id, 1);
2382163953Srrs
2383163953Srrs			} else {
2384163953Srrs				stcb = NULL;
2385163953Srrs			}
2386163953Srrs			/*
2387163953Srrs			 * assure that the TCP model does not need a assoc
2388163953Srrs			 * id once connected.
2389163953Srrs			 */
2390163953Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
2391163953Srrs			    (stcb == NULL)) {
2392163953Srrs				SCTP_INP_RLOCK(inp);
2393163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2394163953Srrs				if (stcb)
2395163953Srrs					SCTP_TCB_LOCK(stcb);
2396163953Srrs				SCTP_INP_RUNLOCK(inp);
2397163953Srrs			}
2398163953Srrs			sas = (struct sockaddr_storage *)&saddr->addr[0];
2399163953Srrs			limit = m->m_len - sizeof(sctp_assoc_t);
2400163953Srrs			actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
2401163953Srrs			if (stcb)
2402163953Srrs				SCTP_TCB_UNLOCK(stcb);
2403163953Srrs			m->m_len = sizeof(struct sockaddr_storage) + actual;
2404163953Srrs		}
2405163953Srrs		break;
2406163953Srrs	case SCTP_PEER_ADDR_PARAMS:
2407163953Srrs		{
2408163953Srrs			struct sctp_paddrparams *paddrp;
2409163953Srrs			struct sctp_nets *net;
2410163953Srrs
2411163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_paddrparams)) {
2412163953Srrs				error = EINVAL;
2413163953Srrs				break;
2414163953Srrs			}
2415163953Srrs			paddrp = mtod(m, struct sctp_paddrparams *);
2416163953Srrs
2417163953Srrs			net = NULL;
2418163953Srrs			if (paddrp->spp_assoc_id) {
2419163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2420163953Srrs					SCTP_INP_RLOCK(inp);
2421163953Srrs					stcb = LIST_FIRST(&inp->sctp_asoc_list);
2422163953Srrs					if (stcb) {
2423163953Srrs						SCTP_TCB_LOCK(stcb);
2424163953Srrs						net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
2425163953Srrs					}
2426163953Srrs					SCTP_INP_RLOCK(inp);
2427163953Srrs				} else {
2428163953Srrs					stcb = sctp_findassociation_ep_asocid(inp, paddrp->spp_assoc_id, 1);
2429163953Srrs				}
2430163953Srrs				if (stcb == NULL) {
2431163953Srrs					error = ENOENT;
2432163953Srrs					break;
2433163953Srrs				}
2434163953Srrs			}
2435163953Srrs			if ((stcb == NULL) &&
2436163953Srrs			    ((((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET) ||
2437163953Srrs			    (((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET6))) {
2438163953Srrs				/* Lookup via address */
2439163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2440163953Srrs					SCTP_INP_RLOCK(inp);
2441163953Srrs					stcb = LIST_FIRST(&inp->sctp_asoc_list);
2442163953Srrs					if (stcb) {
2443163953Srrs						SCTP_TCB_LOCK(stcb);
2444163953Srrs						net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
2445163953Srrs					}
2446163953Srrs					SCTP_INP_RUNLOCK(inp);
2447163953Srrs				} else {
2448163953Srrs					SCTP_INP_INCR_REF(inp);
2449163953Srrs					stcb = sctp_findassociation_ep_addr(&inp,
2450163953Srrs					    (struct sockaddr *)&paddrp->spp_address,
2451163953Srrs					    &net, NULL, NULL);
2452163953Srrs					if (stcb == NULL) {
2453163953Srrs						SCTP_INP_DECR_REF(inp);
2454163953Srrs					}
2455163953Srrs				}
2456163953Srrs
2457163953Srrs				if (stcb == NULL) {
2458163953Srrs					error = ENOENT;
2459163953Srrs					break;
2460163953Srrs				}
2461163953Srrs			}
2462163953Srrs			if (stcb) {
2463163953Srrs				/* Applys to the specific association */
2464163953Srrs				paddrp->spp_flags = 0;
2465163953Srrs				if (net) {
2466163953Srrs					paddrp->spp_pathmaxrxt = net->failure_threshold;
2467163953Srrs					paddrp->spp_pathmtu = net->mtu;
2468163953Srrs					/* get flags for HB */
2469163953Srrs					if (net->dest_state & SCTP_ADDR_NOHB)
2470163953Srrs						paddrp->spp_flags |= SPP_HB_DISABLE;
2471163953Srrs					else
2472163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2473163953Srrs					/* get flags for PMTU */
2474163953Srrs					if (callout_pending(&net->pmtu_timer.timer)) {
2475163953Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2476163953Srrs					} else {
2477163953Srrs						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2478163953Srrs					}
2479163953Srrs#ifdef AF_INET
2480163953Srrs					if (net->ro._l_addr.sin.sin_family == AF_INET) {
2481163953Srrs						paddrp->spp_ipv4_tos = net->tos_flowlabel & 0x000000fc;
2482163953Srrs						paddrp->spp_flags |= SPP_IPV4_TOS;
2483163953Srrs					}
2484163953Srrs#endif
2485163953Srrs#ifdef AF_INET6
2486163953Srrs					if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
2487163953Srrs						paddrp->spp_ipv6_flowlabel = net->tos_flowlabel;
2488163953Srrs						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2489163953Srrs					}
2490163953Srrs#endif
2491163953Srrs				} else {
2492163953Srrs					/*
2493163953Srrs					 * No destination so return default
2494163953Srrs					 * value
2495163953Srrs					 */
2496163953Srrs					paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
2497163953Srrs					paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
2498163953Srrs#ifdef AF_INET
2499163953Srrs					paddrp->spp_ipv4_tos = stcb->asoc.default_tos & 0x000000fc;
2500163953Srrs					paddrp->spp_flags |= SPP_IPV4_TOS;
2501163953Srrs#endif
2502163953Srrs#ifdef AF_INET6
2503163953Srrs					paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel;
2504163953Srrs					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2505163953Srrs#endif
2506163953Srrs					/* default settings should be these */
2507163953Srrs					if (sctp_is_hb_timer_running(stcb)) {
2508163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2509163953Srrs					}
2510163953Srrs				}
2511163953Srrs				paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
2512163953Srrs				paddrp->spp_sackdelay = stcb->asoc.delayed_ack;
2513163953Srrs				/*
2514163953Srrs				 * Currently we don't support no sack delay
2515163953Srrs				 * aka SPP_SACKDELAY_DISABLE.
2516163953Srrs				 */
2517163953Srrs				paddrp->spp_flags |= SPP_SACKDELAY_ENABLE;
2518163953Srrs				paddrp->spp_assoc_id = sctp_get_associd(stcb);
2519163953Srrs				SCTP_TCB_UNLOCK(stcb);
2520163953Srrs			} else {
2521163953Srrs				/* Use endpoint defaults */
2522163953Srrs				SCTP_INP_RLOCK(inp);
2523163953Srrs				paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
2524163953Srrs				paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
2525163953Srrs				paddrp->spp_sackdelay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
2526163953Srrs				paddrp->spp_assoc_id = (sctp_assoc_t) 0;
2527163953Srrs				/* get inp's default */
2528163953Srrs#ifdef AF_INET
2529163953Srrs				paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos;
2530163953Srrs				paddrp->spp_flags |= SPP_IPV4_TOS;
2531163953Srrs#endif
2532163953Srrs#ifdef AF_INET6
2533163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2534163953Srrs					paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
2535163953Srrs					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2536163953Srrs				}
2537163953Srrs#endif
2538163953Srrs				/* can't return this */
2539163953Srrs				paddrp->spp_pathmaxrxt = 0;
2540163953Srrs				paddrp->spp_pathmtu = 0;
2541163953Srrs				/* default behavior, no stcb */
2542163953Srrs				paddrp->spp_flags = SPP_HB_ENABLE | SPP_SACKDELAY_ENABLE | SPP_PMTUD_ENABLE;
2543163953Srrs
2544163953Srrs				SCTP_INP_RUNLOCK(inp);
2545163953Srrs			}
2546163953Srrs			m->m_len = sizeof(struct sctp_paddrparams);
2547163953Srrs		}
2548163953Srrs		break;
2549163953Srrs	case SCTP_GET_PEER_ADDR_INFO:
2550163953Srrs		{
2551163953Srrs			struct sctp_paddrinfo *paddri;
2552163953Srrs			struct sctp_nets *net;
2553163953Srrs
2554163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_paddrinfo)) {
2555163953Srrs				error = EINVAL;
2556163953Srrs				break;
2557163953Srrs			}
2558163953Srrs			paddri = mtod(m, struct sctp_paddrinfo *);
2559163953Srrs			net = NULL;
2560163953Srrs			if ((((struct sockaddr *)&paddri->spinfo_address)->sa_family == AF_INET) ||
2561163953Srrs			    (((struct sockaddr *)&paddri->spinfo_address)->sa_family == AF_INET6)) {
2562163953Srrs				/* Lookup via address */
2563163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2564163953Srrs					SCTP_INP_RLOCK(inp);
2565163953Srrs					stcb = LIST_FIRST(&inp->sctp_asoc_list);
2566163953Srrs					if (stcb) {
2567163953Srrs						SCTP_TCB_LOCK(stcb);
2568163953Srrs						net = sctp_findnet(stcb,
2569163953Srrs						    (struct sockaddr *)&paddri->spinfo_address);
2570163953Srrs					}
2571163953Srrs					SCTP_INP_RUNLOCK(inp);
2572163953Srrs				} else {
2573163953Srrs					SCTP_INP_INCR_REF(inp);
2574163953Srrs					stcb = sctp_findassociation_ep_addr(&inp,
2575163953Srrs					    (struct sockaddr *)&paddri->spinfo_address,
2576163953Srrs					    &net, NULL, NULL);
2577163953Srrs					if (stcb == NULL) {
2578163953Srrs						SCTP_INP_DECR_REF(inp);
2579163953Srrs					}
2580163953Srrs				}
2581163953Srrs
2582163953Srrs			} else {
2583163953Srrs				stcb = NULL;
2584163953Srrs			}
2585163953Srrs			if ((stcb == NULL) || (net == NULL)) {
2586163953Srrs				if (stcb) {
2587163953Srrs					SCTP_TCB_UNLOCK(stcb);
2588163953Srrs				}
2589163953Srrs				error = ENOENT;
2590163953Srrs				break;
2591163953Srrs			}
2592163953Srrs			m->m_len = sizeof(struct sctp_paddrinfo);
2593163953Srrs			paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK | SCTP_ADDR_NOHB);
2594163953Srrs			paddri->spinfo_cwnd = net->cwnd;
2595163953Srrs			paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
2596163953Srrs			paddri->spinfo_rto = net->RTO;
2597163953Srrs			paddri->spinfo_assoc_id = sctp_get_associd(stcb);
2598163953Srrs			SCTP_TCB_UNLOCK(stcb);
2599163953Srrs		}
2600163953Srrs		break;
2601163953Srrs	case SCTP_PCB_STATUS:
2602163953Srrs		{
2603163953Srrs			struct sctp_pcbinfo *spcb;
2604163953Srrs
2605163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_pcbinfo)) {
2606163953Srrs				error = EINVAL;
2607163953Srrs				break;
2608163953Srrs			}
2609163953Srrs			spcb = mtod(m, struct sctp_pcbinfo *);
2610163953Srrs			sctp_fill_pcbinfo(spcb);
2611163953Srrs			m->m_len = sizeof(struct sctp_pcbinfo);
2612163953Srrs		}
2613163953Srrs		break;
2614163953Srrs	case SCTP_STATUS:
2615163953Srrs		{
2616163953Srrs			struct sctp_nets *net;
2617163953Srrs			struct sctp_status *sstat;
2618163953Srrs
2619163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_status)) {
2620163953Srrs				error = EINVAL;
2621163953Srrs				break;
2622163953Srrs			}
2623163953Srrs			sstat = mtod(m, struct sctp_status *);
2624163953Srrs
2625163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2626163953Srrs				SCTP_INP_RLOCK(inp);
2627163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2628163953Srrs				if (stcb)
2629163953Srrs					SCTP_TCB_LOCK(stcb);
2630163953Srrs				SCTP_INP_RUNLOCK(inp);
2631163953Srrs			} else
2632163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, sstat->sstat_assoc_id, 1);
2633163953Srrs
2634163953Srrs			if (stcb == NULL) {
2635163953Srrs				error = EINVAL;
2636163953Srrs				break;
2637163953Srrs			}
2638163953Srrs			/*
2639163953Srrs			 * I think passing the state is fine since
2640163953Srrs			 * sctp_constants.h will be available to the user
2641163953Srrs			 * land.
2642163953Srrs			 */
2643163953Srrs			sstat->sstat_state = stcb->asoc.state;
2644163953Srrs			sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
2645163953Srrs			sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
2646163953Srrs			/*
2647163953Srrs			 * We can't include chunks that have been passed to
2648163953Srrs			 * the socket layer. Only things in queue.
2649163953Srrs			 */
2650163953Srrs			sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
2651163953Srrs			    stcb->asoc.cnt_on_all_streams);
2652163953Srrs
2653163953Srrs
2654163953Srrs			sstat->sstat_instrms = stcb->asoc.streamincnt;
2655163953Srrs			sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
2656163953Srrs			sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
2657163953Srrs			memcpy(&sstat->sstat_primary.spinfo_address,
2658163953Srrs			    &stcb->asoc.primary_destination->ro._l_addr,
2659163953Srrs			    ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
2660163953Srrs			net = stcb->asoc.primary_destination;
2661163953Srrs			((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
2662163953Srrs			/*
2663163953Srrs			 * Again the user can get info from sctp_constants.h
2664163953Srrs			 * for what the state of the network is.
2665163953Srrs			 */
2666163953Srrs			sstat->sstat_primary.spinfo_state = net->dest_state & SCTP_REACHABLE_MASK;
2667163953Srrs			sstat->sstat_primary.spinfo_cwnd = net->cwnd;
2668163953Srrs			sstat->sstat_primary.spinfo_srtt = net->lastsa;
2669163953Srrs			sstat->sstat_primary.spinfo_rto = net->RTO;
2670163953Srrs			sstat->sstat_primary.spinfo_mtu = net->mtu;
2671163953Srrs			sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
2672163953Srrs			SCTP_TCB_UNLOCK(stcb);
2673163953Srrs			m->m_len = sizeof(*sstat);
2674163953Srrs		}
2675163953Srrs		break;
2676163953Srrs	case SCTP_RTOINFO:
2677163953Srrs		{
2678163953Srrs			struct sctp_rtoinfo *srto;
2679163953Srrs
2680163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_rtoinfo)) {
2681163953Srrs				error = EINVAL;
2682163953Srrs				break;
2683163953Srrs			}
2684163953Srrs			srto = mtod(m, struct sctp_rtoinfo *);
2685163953Srrs			if (srto->srto_assoc_id == 0) {
2686163953Srrs				/* Endpoint only please */
2687163953Srrs				SCTP_INP_RLOCK(inp);
2688163953Srrs				srto->srto_initial = inp->sctp_ep.initial_rto;
2689163953Srrs				srto->srto_max = inp->sctp_ep.sctp_maxrto;
2690163953Srrs				srto->srto_min = inp->sctp_ep.sctp_minrto;
2691163953Srrs				SCTP_INP_RUNLOCK(inp);
2692163953Srrs				break;
2693163953Srrs			}
2694163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2695163953Srrs				SCTP_INP_RLOCK(inp);
2696163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2697163953Srrs				if (stcb)
2698163953Srrs					SCTP_TCB_LOCK(stcb);
2699163953Srrs				SCTP_INP_RUNLOCK(inp);
2700163953Srrs			} else
2701163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, srto->srto_assoc_id, 1);
2702163953Srrs
2703163953Srrs			if (stcb == NULL) {
2704163953Srrs				error = EINVAL;
2705163953Srrs				break;
2706163953Srrs			}
2707163953Srrs			srto->srto_initial = stcb->asoc.initial_rto;
2708163953Srrs			srto->srto_max = stcb->asoc.maxrto;
2709163953Srrs			srto->srto_min = stcb->asoc.minrto;
2710163953Srrs			SCTP_TCB_UNLOCK(stcb);
2711163953Srrs			m->m_len = sizeof(*srto);
2712163953Srrs		}
2713163953Srrs		break;
2714163953Srrs	case SCTP_ASSOCINFO:
2715163953Srrs		{
2716163953Srrs			struct sctp_assocparams *sasoc;
2717163953Srrs
2718163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assocparams)) {
2719163953Srrs				error = EINVAL;
2720163953Srrs				break;
2721163953Srrs			}
2722163953Srrs			sasoc = mtod(m, struct sctp_assocparams *);
2723163953Srrs			stcb = NULL;
2724163953Srrs
2725163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2726163953Srrs				SCTP_INP_RLOCK(inp);
2727163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2728163953Srrs				if (stcb) {
2729163953Srrs
2730163953Srrs					SCTP_TCB_LOCK(stcb);
2731163953Srrs				}
2732163953Srrs				SCTP_INP_RUNLOCK(inp);
2733163953Srrs			} else if (sasoc->sasoc_assoc_id) {
2734163953Srrs				stcb = sctp_findassociation_ep_asocid(inp,
2735163953Srrs				    sasoc->sasoc_assoc_id, 1);
2736163953Srrs				if (stcb == NULL) {
2737163953Srrs					error = ENOENT;
2738163953Srrs					break;
2739163953Srrs				}
2740163953Srrs			} else {
2741163953Srrs				stcb = NULL;
2742163953Srrs			}
2743163953Srrs			if (stcb) {
2744163953Srrs				sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
2745163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
2746163953Srrs				sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
2747163953Srrs				sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
2748163953Srrs				sasoc->sasoc_cookie_life = stcb->asoc.cookie_life;
2749163953Srrs				SCTP_TCB_UNLOCK(stcb);
2750163953Srrs			} else {
2751163953Srrs				SCTP_INP_RLOCK(inp);
2752163953Srrs				sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
2753163953Srrs				sasoc->sasoc_number_peer_destinations = 0;
2754163953Srrs				sasoc->sasoc_peer_rwnd = 0;
2755163953Srrs				sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
2756163953Srrs				sasoc->sasoc_cookie_life = inp->sctp_ep.def_cookie_life;
2757163953Srrs				SCTP_INP_RUNLOCK(inp);
2758163953Srrs			}
2759163953Srrs			m->m_len = sizeof(*sasoc);
2760163953Srrs		}
2761163953Srrs		break;
2762163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
2763163953Srrs		{
2764163953Srrs			struct sctp_sndrcvinfo *s_info;
2765163953Srrs
2766163953Srrs			if (m->m_len != sizeof(struct sctp_sndrcvinfo)) {
2767163953Srrs				error = EINVAL;
2768163953Srrs				break;
2769163953Srrs			}
2770163953Srrs			s_info = mtod(m, struct sctp_sndrcvinfo *);
2771163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2772163953Srrs				SCTP_INP_RLOCK(inp);
2773163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2774163953Srrs				if (stcb)
2775163953Srrs					SCTP_TCB_LOCK(stcb);
2776163953Srrs				SCTP_INP_RUNLOCK(inp);
2777163953Srrs			} else
2778163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, s_info->sinfo_assoc_id, 1);
2779163953Srrs
2780163953Srrs			if (stcb == NULL) {
2781163953Srrs				error = ENOENT;
2782163953Srrs				break;
2783163953Srrs			}
2784163953Srrs			/* Copy it out */
2785163953Srrs			*s_info = stcb->asoc.def_send;
2786163953Srrs			SCTP_TCB_UNLOCK(stcb);
2787163953Srrs			m->m_len = sizeof(*s_info);
2788163953Srrs		}
2789163953Srrs		break;
2790163953Srrs	case SCTP_INITMSG:
2791163953Srrs		{
2792163953Srrs			struct sctp_initmsg *sinit;
2793163953Srrs
2794163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_initmsg)) {
2795163953Srrs				error = EINVAL;
2796163953Srrs				break;
2797163953Srrs			}
2798163953Srrs			sinit = mtod(m, struct sctp_initmsg *);
2799163953Srrs			SCTP_INP_RLOCK(inp);
2800163953Srrs			sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
2801163953Srrs			sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
2802163953Srrs			sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
2803163953Srrs			sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
2804163953Srrs			SCTP_INP_RUNLOCK(inp);
2805163953Srrs			m->m_len = sizeof(*sinit);
2806163953Srrs		}
2807163953Srrs		break;
2808163953Srrs	case SCTP_PRIMARY_ADDR:
2809163953Srrs		/* we allow a "get" operation on this */
2810163953Srrs		{
2811163953Srrs			struct sctp_setprim *ssp;
2812163953Srrs
2813163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_setprim)) {
2814163953Srrs				error = EINVAL;
2815163953Srrs				break;
2816163953Srrs			}
2817163953Srrs			ssp = mtod(m, struct sctp_setprim *);
2818163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2819163953Srrs				SCTP_INP_RLOCK(inp);
2820163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2821163953Srrs				if (stcb)
2822163953Srrs					SCTP_TCB_LOCK(stcb);
2823163953Srrs				SCTP_INP_RUNLOCK(inp);
2824163953Srrs			} else {
2825163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, ssp->ssp_assoc_id, 1);
2826163953Srrs				if (stcb == NULL) {
2827163953Srrs					/*
2828163953Srrs					 * one last shot, try it by the
2829163953Srrs					 * address in
2830163953Srrs					 */
2831163953Srrs					struct sctp_nets *net;
2832163953Srrs
2833163953Srrs					SCTP_INP_INCR_REF(inp);
2834163953Srrs					stcb = sctp_findassociation_ep_addr(&inp,
2835163953Srrs					    (struct sockaddr *)&ssp->ssp_addr,
2836163953Srrs					    &net, NULL, NULL);
2837163953Srrs					if (stcb == NULL) {
2838163953Srrs						SCTP_INP_DECR_REF(inp);
2839163953Srrs					}
2840163953Srrs				}
2841163953Srrs				if (stcb == NULL) {
2842163953Srrs					error = EINVAL;
2843163953Srrs					break;
2844163953Srrs				}
2845163953Srrs			}
2846163953Srrs			/* simply copy out the sockaddr_storage... */
2847163953Srrs			memcpy(&ssp->ssp_addr,
2848163953Srrs			    &stcb->asoc.primary_destination->ro._l_addr,
2849163953Srrs			    ((struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr)->sa_len);
2850163953Srrs			SCTP_TCB_UNLOCK(stcb);
2851163953Srrs			m->m_len = sizeof(*ssp);
2852163953Srrs		}
2853163953Srrs		break;
2854163953Srrs
2855163953Srrs	case SCTP_HMAC_IDENT:
2856163953Srrs		{
2857163953Srrs			struct sctp_hmacalgo *shmac;
2858163953Srrs			sctp_hmaclist_t *hmaclist;
2859163953Srrs			uint32_t size;
2860163953Srrs			int i;
2861163953Srrs
2862163953Srrs			if ((size_t)(m->m_len) < sizeof(*shmac)) {
2863163953Srrs				error = EINVAL;
2864163953Srrs				break;
2865163953Srrs			}
2866163953Srrs			shmac = mtod(m, struct sctp_hmacalgo *);
2867163953Srrs			SCTP_INP_RLOCK(inp);
2868163953Srrs			hmaclist = inp->sctp_ep.local_hmacs;
2869163953Srrs			if (hmaclist == NULL) {
2870163953Srrs				/* no HMACs to return */
2871163953Srrs				m->m_len = sizeof(*shmac);
2872163953Srrs				break;
2873163953Srrs			}
2874163953Srrs			/* is there room for all of the hmac ids? */
2875163953Srrs			size = sizeof(*shmac) + (hmaclist->num_algo *
2876163953Srrs			    sizeof(shmac->shmac_idents[0]));
2877163953Srrs			if ((size_t)(m->m_len) < size) {
2878163953Srrs				error = EINVAL;
2879163953Srrs				SCTP_INP_RUNLOCK(inp);
2880163953Srrs				break;
2881163953Srrs			}
2882163953Srrs			/* copy in the list */
2883163953Srrs			for (i = 0; i < hmaclist->num_algo; i++)
2884163953Srrs				shmac->shmac_idents[i] = hmaclist->hmac[i];
2885163953Srrs			SCTP_INP_RUNLOCK(inp);
2886163953Srrs			m->m_len = size;
2887163953Srrs			break;
2888163953Srrs		}
2889163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
2890163953Srrs		{
2891163953Srrs			struct sctp_authkeyid *scact;
2892163953Srrs
2893163953Srrs			if ((size_t)(m->m_len) < sizeof(*scact)) {
2894163953Srrs				error = EINVAL;
2895163953Srrs				break;
2896163953Srrs			}
2897163953Srrs			scact = mtod(m, struct sctp_authkeyid *);
2898163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2899163953Srrs				/*
2900163953Srrs				 * if one-to-one, get from the connected
2901163953Srrs				 * assoc; else endpoint
2902163953Srrs				 */
2903163953Srrs				SCTP_INP_RLOCK(inp);
2904163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2905163953Srrs				if (stcb)
2906163953Srrs					SCTP_TCB_LOCK(stcb);
2907163953Srrs				SCTP_INP_RUNLOCK(inp);
2908163953Srrs			} else if (scact->scact_assoc_id) {
2909163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, scact->scact_assoc_id, 1);
2910163953Srrs				if (stcb == NULL) {
2911163953Srrs					error = ENOENT;
2912163953Srrs					break;
2913163953Srrs				}
2914163953Srrs			}
2915163953Srrs			if (stcb != NULL) {
2916163953Srrs				/* get the active key on the assoc */
2917163953Srrs				scact->scact_keynumber = stcb->asoc.authinfo.assoc_keyid;
2918163953Srrs				SCTP_TCB_UNLOCK(stcb);
2919163953Srrs			} else {
2920163953Srrs				/* get the endpoint active key */
2921163953Srrs				SCTP_INP_RLOCK(inp);
2922163953Srrs				scact->scact_keynumber = inp->sctp_ep.default_keyid;
2923163953Srrs				SCTP_INP_RUNLOCK(inp);
2924163953Srrs			}
2925163953Srrs			m->m_len = sizeof(*scact);
2926163953Srrs			break;
2927163953Srrs		}
2928163953Srrs	case SCTP_LOCAL_AUTH_CHUNKS:
2929163953Srrs		{
2930163953Srrs			struct sctp_authchunks *sac;
2931163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2932163953Srrs			int size = 0;
2933163953Srrs
2934163953Srrs			if ((size_t)(m->m_len) < sizeof(*sac)) {
2935163953Srrs				error = EINVAL;
2936163953Srrs				break;
2937163953Srrs			}
2938163953Srrs			sac = mtod(m, struct sctp_authchunks *);
2939163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2940163953Srrs				/*
2941163953Srrs				 * if one-to-one, get from the connected
2942163953Srrs				 * assoc; else endpoint
2943163953Srrs				 */
2944163953Srrs				SCTP_INP_RLOCK(inp);
2945163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2946163953Srrs				if (stcb != NULL)
2947163953Srrs					SCTP_TCB_LOCK(stcb);
2948163953Srrs				SCTP_INP_RUNLOCK(inp);
2949163953Srrs			} else if (sac->gauth_assoc_id) {
2950163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, sac->gauth_assoc_id, 1);
2951163953Srrs				if (stcb == NULL) {
2952163953Srrs					error = ENOENT;
2953163953Srrs					break;
2954163953Srrs				}
2955163953Srrs			}
2956163953Srrs			if (stcb != NULL) {
2957163953Srrs				/* get off the assoc */
2958163953Srrs				chklist = stcb->asoc.local_auth_chunks;
2959163953Srrs				if (chklist == NULL) {
2960163953Srrs					error = EINVAL;
2961163953Srrs					SCTP_TCB_UNLOCK(stcb);
2962163953Srrs					break;
2963163953Srrs				}
2964163953Srrs				/* is there enough space? */
2965163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2966163953Srrs				if ((size_t)m->m_len < (sizeof(struct sctp_authchunks) + size)) {
2967163953Srrs					error = EINVAL;
2968163953Srrs					SCTP_TCB_UNLOCK(stcb);
2969163953Srrs					break;
2970163953Srrs				}
2971163953Srrs				/* copy in the chunks */
2972163953Srrs				sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2973163953Srrs				SCTP_TCB_UNLOCK(stcb);
2974163953Srrs			} else {
2975163953Srrs				/* get off the endpoint */
2976163953Srrs				SCTP_INP_RLOCK(inp);
2977163953Srrs				chklist = inp->sctp_ep.local_auth_chunks;
2978163953Srrs				if (chklist == NULL) {
2979163953Srrs					error = EINVAL;
2980163953Srrs					SCTP_INP_RUNLOCK(inp);
2981163953Srrs					break;
2982163953Srrs				}
2983163953Srrs				/* is there enough space? */
2984163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2985163953Srrs				if ((size_t)m->m_len < (sizeof(struct sctp_authchunks) + size)) {
2986163953Srrs					error = EINVAL;
2987163953Srrs					SCTP_INP_RUNLOCK(inp);
2988163953Srrs					break;
2989163953Srrs				}
2990163953Srrs				/* copy in the chunks */
2991163953Srrs				sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2992163953Srrs				SCTP_INP_RUNLOCK(inp);
2993163953Srrs			}
2994163953Srrs			m->m_len = sizeof(struct sctp_authchunks) + size;
2995163953Srrs			break;
2996163953Srrs		}
2997163953Srrs	case SCTP_PEER_AUTH_CHUNKS:
2998163953Srrs		{
2999163953Srrs			struct sctp_authchunks *sac;
3000163953Srrs			sctp_auth_chklist_t *chklist = NULL;
3001163953Srrs			int size = 0;
3002163953Srrs
3003163953Srrs			if ((size_t)(m->m_len) < sizeof(*sac)) {
3004163953Srrs				error = EINVAL;
3005163953Srrs				break;
3006163953Srrs			}
3007163953Srrs			sac = mtod(m, struct sctp_authchunks *);
3008163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3009163953Srrs				/*
3010163953Srrs				 * if one-to-one, get from the connected
3011163953Srrs				 * assoc, else endpoint
3012163953Srrs				 */
3013163953Srrs				SCTP_INP_RLOCK(inp);
3014163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3015163953Srrs				if (stcb != NULL)
3016163953Srrs					SCTP_TCB_LOCK(stcb);
3017163953Srrs				SCTP_INP_RUNLOCK(inp);
3018163953Srrs			} else if (sac->gauth_assoc_id) {
3019163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, sac->gauth_assoc_id, 1);
3020163953Srrs			}
3021163953Srrs			if (stcb == NULL) {
3022163953Srrs				error = ENOENT;
3023163953Srrs				break;
3024163953Srrs			}
3025163953Srrs			/* get off the assoc */
3026163953Srrs			chklist = stcb->asoc.peer_auth_chunks;
3027163953Srrs			if (chklist == NULL) {
3028163953Srrs				error = EINVAL;
3029163953Srrs				SCTP_TCB_UNLOCK(stcb);
3030163953Srrs				break;
3031163953Srrs			}
3032163953Srrs			/* is there enough space? */
3033163953Srrs			size = sctp_auth_get_chklist_size(chklist);
3034163953Srrs			if ((size_t)m->m_len < (sizeof(struct sctp_authchunks) + size)) {
3035163953Srrs				error = EINVAL;
3036163953Srrs				SCTP_TCB_UNLOCK(stcb);
3037163953Srrs				break;
3038163953Srrs			}
3039163953Srrs			/* copy in the chunks */
3040163953Srrs			sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
3041163953Srrs			SCTP_TCB_UNLOCK(stcb);
3042163953Srrs			m->m_len = sizeof(struct sctp_authchunks) + size;
3043163953Srrs			break;
3044163953Srrs		}
3045163953Srrs
3046163953Srrs
3047163953Srrs	default:
3048163953Srrs		error = ENOPROTOOPT;
3049163953Srrs		m->m_len = 0;
3050163953Srrs		break;
3051163953Srrs	}			/* end switch (sopt->sopt_name) */
3052163953Srrs	return (error);
3053163953Srrs}
3054163953Srrs
3055163953Srrs
3056163953Srrsstatic int
3057163953Srrssctp_optsset(struct socket *so,
3058163953Srrs    int opt,
3059163953Srrs    struct mbuf **mp,
3060163953Srrs    struct thread *p
3061163953Srrs)
3062163953Srrs{
3063163953Srrs	int error, *mopt, set_opt, s;
3064163953Srrs	struct mbuf *m;
3065163953Srrs	struct sctp_tcb *stcb = NULL;
3066163953Srrs	struct sctp_inpcb *inp;
3067163953Srrs
3068163953Srrs	if (mp == NULL) {
3069163953Srrs		return (EINVAL);
3070163953Srrs	}
3071163953Srrs	m = *mp;
3072163953Srrs	if (m == NULL)
3073163953Srrs		return (EINVAL);
3074163953Srrs
3075163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3076163953Srrs	if (inp == 0)
3077163953Srrs		return EINVAL;
3078163953Srrs
3079163953Srrs	error = 0;
3080163953Srrs	switch (opt) {
3081163953Srrs	case SCTP_NODELAY:
3082163953Srrs	case SCTP_AUTOCLOSE:
3083163953Srrs	case SCTP_AUTO_ASCONF:
3084163953Srrs	case SCTP_EXPLICIT_EOR:
3085163953Srrs	case SCTP_DISABLE_FRAGMENTS:
3086163953Srrs	case SCTP_USE_EXT_RCVINFO:
3087163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
3088163953Srrs		/* copy in the option value */
3089163953Srrs		if ((size_t)m->m_len < sizeof(int)) {
3090163953Srrs			error = EINVAL;
3091163953Srrs			break;
3092163953Srrs		}
3093163953Srrs		mopt = mtod(m, int *);
3094163953Srrs		set_opt = 0;
3095163953Srrs		if (error)
3096163953Srrs			break;
3097163953Srrs		switch (opt) {
3098163953Srrs		case SCTP_DISABLE_FRAGMENTS:
3099163953Srrs			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
3100163953Srrs			break;
3101163953Srrs		case SCTP_AUTO_ASCONF:
3102163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
3103163953Srrs			break;
3104163953Srrs		case SCTP_EXPLICIT_EOR:
3105163953Srrs			set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
3106163953Srrs			break;
3107163953Srrs		case SCTP_USE_EXT_RCVINFO:
3108163953Srrs			set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
3109163953Srrs			break;
3110163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
3111163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3112163953Srrs				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
3113163953Srrs			} else {
3114163953Srrs				return (EINVAL);
3115163953Srrs			}
3116163953Srrs			break;
3117163953Srrs		case SCTP_NODELAY:
3118163953Srrs			set_opt = SCTP_PCB_FLAGS_NODELAY;
3119163953Srrs			break;
3120163953Srrs		case SCTP_AUTOCLOSE:
3121163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
3122163953Srrs			/*
3123163953Srrs			 * The value is in ticks. Note this does not effect
3124163953Srrs			 * old associations, only new ones.
3125163953Srrs			 */
3126163953Srrs			inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
3127163953Srrs			break;
3128163953Srrs		}
3129163953Srrs		SCTP_INP_WLOCK(inp);
3130163953Srrs		if (*mopt != 0) {
3131163953Srrs			sctp_feature_on(inp, set_opt);
3132163953Srrs		} else {
3133163953Srrs			sctp_feature_off(inp, set_opt);
3134163953Srrs		}
3135163953Srrs		SCTP_INP_WUNLOCK(inp);
3136163953Srrs		break;
3137163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
3138163953Srrs		{
3139163953Srrs			if ((size_t)m->m_len < sizeof(unsigned int)) {
3140163953Srrs				error = EINVAL;
3141163953Srrs				break;
3142163953Srrs			}
3143163953Srrs			inp->partial_delivery_point = *mtod(m, unsigned int *);
3144163953Srrs			m->m_len = sizeof(unsigned int);
3145163953Srrs		}
3146163953Srrs		break;
3147163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
3148163953Srrs		/* not yet until we re-write sctp_recvmsg() */
3149163953Srrs		{
3150163953Srrs			int on_off;
3151163953Srrs
3152163953Srrs			if ((size_t)m->m_len < sizeof(int)) {
3153163953Srrs				error = EINVAL;
3154163953Srrs				break;
3155163953Srrs			}
3156163964Srrs			on_off = *(mtod(m, int *));
3157163953Srrs			if (on_off) {
3158163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3159163953Srrs			} else {
3160163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3161163953Srrs			}
3162163953Srrs		}
3163163953Srrs		break;
3164163953Srrs	case SCTP_CMT_ON_OFF:
3165163953Srrs		{
3166163953Srrs			struct sctp_assoc_value *av;
3167163953Srrs
3168163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assoc_value)) {
3169163953Srrs				error = EINVAL;
3170163953Srrs				break;
3171163953Srrs			}
3172163953Srrs			av = mtod(m, struct sctp_assoc_value *);
3173163953Srrs			stcb = sctp_findassociation_ep_asocid(inp, av->assoc_id, 1);
3174163953Srrs			if (stcb == NULL) {
3175163953Srrs				error = ENOTCONN;
3176163953Srrs			} else {
3177163953Srrs				if (sctp_cmt_on_off) {
3178163953Srrs					stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value;
3179163953Srrs				} else {
3180163953Srrs					if ((stcb->asoc.sctp_cmt_on_off) && (av->assoc_value == 0)) {
3181163953Srrs						stcb->asoc.sctp_cmt_on_off = 0;
3182163953Srrs					} else {
3183163953Srrs						error = EACCES;
3184163953Srrs					}
3185163953Srrs				}
3186163953Srrs				SCTP_TCB_UNLOCK(stcb);
3187163953Srrs			}
3188163953Srrs		}
3189163953Srrs		break;
3190163953Srrs	case SCTP_CMT_USE_DAC:
3191163953Srrs		{
3192163953Srrs			if ((size_t)m->m_len < sizeof(unsigned int)) {
3193163953Srrs				error = EINVAL;
3194163953Srrs				break;
3195163953Srrs			}
3196163953Srrs			sctp_cmt_sockopt_use_dac = *mtod(m, unsigned int *);
3197163953Srrs			if (sctp_cmt_sockopt_use_dac != 0)
3198163953Srrs				sctp_cmt_sockopt_use_dac = 1;
3199163953Srrs		}
3200163953Srrs		break;
3201163953Srrs	case SCTP_CLR_STAT_LOG:
3202163953Srrs#ifdef SCTP_STAT_LOGGING
3203163953Srrs		sctp_clr_stat_log();
3204163953Srrs#else
3205163953Srrs		error = EOPNOTSUPP;
3206163953Srrs#endif
3207163953Srrs		break;
3208163953Srrs	case SCTP_CONTEXT:
3209163953Srrs		{
3210163953Srrs
3211163953Srrs			struct sctp_assoc_value *av;
3212163953Srrs
3213163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assoc_value)) {
3214163953Srrs				error = EINVAL;
3215163953Srrs				break;
3216163953Srrs			}
3217163953Srrs			av = mtod(m, struct sctp_assoc_value *);
3218163953Srrs			if (av->assoc_id) {
3219163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, av->assoc_id, 1);
3220163953Srrs				if (stcb == NULL) {
3221163953Srrs					error = ENOTCONN;
3222163953Srrs				} else {
3223163953Srrs					stcb->asoc.context = av->assoc_value;
3224163953Srrs					SCTP_TCB_UNLOCK(stcb);
3225163953Srrs				}
3226163953Srrs			} else {
3227163953Srrs				inp->sctp_context = av->assoc_value;
3228163953Srrs			}
3229163953Srrs		}
3230163953Srrs		break;
3231163953Srrs	case SCTP_DELAYED_ACK_TIME:
3232163953Srrs		{
3233163953Srrs			struct sctp_assoc_value *tm;
3234163953Srrs
3235163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assoc_value)) {
3236163953Srrs				error = EINVAL;
3237163953Srrs				break;
3238163953Srrs			}
3239163953Srrs			tm = mtod(m, struct sctp_assoc_value *);
3240163953Srrs
3241163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3242163953Srrs				SCTP_INP_WLOCK(inp);
3243163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3244163953Srrs				if (stcb) {
3245163953Srrs					SCTP_TCB_LOCK(stcb);
3246163953Srrs					stcb->asoc.delayed_ack = tm->assoc_value;
3247163953Srrs					SCTP_TCB_UNLOCK(stcb);
3248163953Srrs				} else {
3249163953Srrs					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(tm->assoc_value);
3250163953Srrs				}
3251163953Srrs				SCTP_INP_WUNLOCK(inp);
3252163953Srrs			} else {
3253163953Srrs				if (tm->assoc_id) {
3254163953Srrs					stcb = sctp_findassociation_ep_asocid(inp, tm->assoc_id, 1);
3255163953Srrs					if (stcb == NULL) {
3256163953Srrs						error = ENOTCONN;
3257163953Srrs					} else {
3258163953Srrs						stcb->asoc.delayed_ack = tm->assoc_value;
3259163953Srrs						SCTP_TCB_UNLOCK(stcb);
3260163953Srrs					}
3261163953Srrs				} else {
3262163953Srrs					SCTP_INP_WLOCK(inp);
3263163953Srrs					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(tm->assoc_value);
3264163953Srrs					SCTP_INP_WUNLOCK(inp);
3265163953Srrs				}
3266163953Srrs			}
3267163953Srrs		}
3268163953Srrs		break;
3269163953Srrs
3270163953Srrs	case SCTP_AUTH_CHUNK:
3271163953Srrs		{
3272163953Srrs			struct sctp_authchunk *sauth;
3273163953Srrs
3274163953Srrs			if ((size_t)m->m_len < sizeof(*sauth)) {
3275163953Srrs				error = EINVAL;
3276163953Srrs				break;
3277163953Srrs			}
3278163953Srrs			sauth = mtod(m, struct sctp_authchunk *);
3279163953Srrs			if (sctp_auth_add_chunk(sauth->sauth_chunk,
3280163953Srrs			    inp->sctp_ep.local_auth_chunks))
3281163953Srrs				error = EINVAL;
3282163953Srrs			break;
3283163953Srrs		}
3284163953Srrs	case SCTP_AUTH_KEY:
3285163953Srrs		{
3286163953Srrs			struct sctp_authkey *sca;
3287163953Srrs			struct sctp_keyhead *shared_keys;
3288163953Srrs			sctp_sharedkey_t *shared_key;
3289163953Srrs			sctp_key_t *key = NULL;
3290163953Srrs			int size;
3291163953Srrs
3292163953Srrs			size = m->m_len - sizeof(*sca);
3293163953Srrs			if (size < 0) {
3294163953Srrs				error = EINVAL;
3295163953Srrs				break;
3296163953Srrs			}
3297163953Srrs			sca = mtod(m, struct sctp_authkey *);
3298163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3299163953Srrs				/*
3300163953Srrs				 * if one-to-one, set it on the connected
3301163953Srrs				 * assoc; else endpoint
3302163953Srrs				 */
3303163953Srrs				SCTP_INP_RLOCK(inp);
3304163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3305163953Srrs				if (stcb)
3306163953Srrs					SCTP_TCB_LOCK(stcb);
3307163953Srrs				SCTP_INP_RUNLOCK(inp);
3308163953Srrs			} else if (sca->sca_assoc_id) {
3309163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, sca->sca_assoc_id, 1);
3310163953Srrs				if (stcb == NULL) {
3311163953Srrs					error = ENOENT;
3312163953Srrs					break;
3313163953Srrs				}
3314163953Srrs			}
3315163953Srrs			if (stcb != NULL) {
3316163953Srrs				/* set it on the assoc */
3317163953Srrs				shared_keys = &stcb->asoc.shared_keys;
3318163953Srrs				/* clear the cached keys for this key id */
3319163953Srrs				sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
3320163953Srrs				/*
3321163953Srrs				 * create the new shared key and
3322163953Srrs				 * insert/replace it
3323163953Srrs				 */
3324163953Srrs				if (size > 0) {
3325163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
3326163953Srrs					if (key == NULL) {
3327163953Srrs						error = ENOMEM;
3328163953Srrs						SCTP_TCB_UNLOCK(stcb);
3329163953Srrs						break;
3330163953Srrs					}
3331163953Srrs				}
3332163953Srrs				shared_key = sctp_alloc_sharedkey();
3333163953Srrs				if (shared_key == NULL) {
3334163953Srrs					sctp_free_key(key);
3335163953Srrs					error = ENOMEM;
3336163953Srrs					SCTP_TCB_UNLOCK(stcb);
3337163953Srrs					break;
3338163953Srrs				}
3339163953Srrs				shared_key->key = key;
3340163953Srrs				shared_key->keyid = sca->sca_keynumber;
3341163953Srrs				sctp_insert_sharedkey(shared_keys, shared_key);
3342163953Srrs				SCTP_TCB_UNLOCK(stcb);
3343163953Srrs			} else {
3344163953Srrs				/* ste it on the endpoint */
3345163953Srrs				SCTP_INP_WLOCK(inp);
3346163953Srrs				shared_keys = &inp->sctp_ep.shared_keys;
3347163953Srrs				/*
3348163953Srrs				 * clear the cached keys on all assocs for
3349163953Srrs				 * this key id
3350163953Srrs				 */
3351163953Srrs				sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
3352163953Srrs				/*
3353163953Srrs				 * create the new shared key and
3354163953Srrs				 * insert/replace it
3355163953Srrs				 */
3356163953Srrs				if (size > 0) {
3357163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
3358163953Srrs					if (key == NULL) {
3359163953Srrs						error = ENOMEM;
3360163953Srrs						SCTP_INP_WUNLOCK(inp);
3361163953Srrs						break;
3362163953Srrs					}
3363163953Srrs				}
3364163953Srrs				shared_key = sctp_alloc_sharedkey();
3365163953Srrs				if (shared_key == NULL) {
3366163953Srrs					sctp_free_key(key);
3367163953Srrs					error = ENOMEM;
3368163953Srrs					SCTP_INP_WUNLOCK(inp);
3369163953Srrs					break;
3370163953Srrs				}
3371163953Srrs				shared_key->key = key;
3372163953Srrs				shared_key->keyid = sca->sca_keynumber;
3373163953Srrs				sctp_insert_sharedkey(shared_keys, shared_key);
3374163953Srrs				SCTP_INP_WUNLOCK(inp);
3375163953Srrs			}
3376163953Srrs			break;
3377163953Srrs		}
3378163953Srrs	case SCTP_HMAC_IDENT:
3379163953Srrs		{
3380163953Srrs			struct sctp_hmacalgo *shmac;
3381163953Srrs			sctp_hmaclist_t *hmaclist;
3382163953Srrs			uint32_t hmacid;
3383163953Srrs			int size, i;
3384163953Srrs
3385163953Srrs			size = m->m_len - sizeof(*shmac);
3386163953Srrs			if (size < 0) {
3387163953Srrs				error = EINVAL;
3388163953Srrs				break;
3389163953Srrs			}
3390163953Srrs			shmac = mtod(m, struct sctp_hmacalgo *);
3391163953Srrs			size = size / sizeof(shmac->shmac_idents[0]);
3392163953Srrs			hmaclist = sctp_alloc_hmaclist(size);
3393163953Srrs			if (hmaclist == NULL) {
3394163953Srrs				error = ENOMEM;
3395163953Srrs				break;
3396163953Srrs			}
3397163953Srrs			for (i = 0; i < size; i++) {
3398163953Srrs				hmacid = shmac->shmac_idents[i];
3399163953Srrs				if (sctp_auth_add_hmacid(hmaclist, (uint16_t) hmacid)) {
3400163953Srrs					 /* invalid HMACs were found */ ;
3401163953Srrs					error = EINVAL;
3402164085Srrs					sctp_free_hmaclist(hmaclist);
3403163953Srrs					goto sctp_set_hmac_done;
3404163953Srrs				}
3405163953Srrs			}
3406163953Srrs			/* set it on the endpoint */
3407163953Srrs			SCTP_INP_WLOCK(inp);
3408163953Srrs			if (inp->sctp_ep.local_hmacs)
3409163953Srrs				sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
3410163953Srrs			inp->sctp_ep.local_hmacs = hmaclist;
3411163953Srrs			SCTP_INP_WUNLOCK(inp);
3412163953Srrs	sctp_set_hmac_done:
3413163953Srrs			break;
3414163953Srrs		}
3415163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
3416163953Srrs		{
3417163953Srrs			struct sctp_authkeyid *scact;
3418163953Srrs
3419163953Srrs			if ((size_t)m->m_len < sizeof(*scact)) {
3420163953Srrs				error = EINVAL;
3421163953Srrs				break;
3422163953Srrs			}
3423163953Srrs			scact = mtod(m, struct sctp_authkeyid *);
3424163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3425163953Srrs				/*
3426163953Srrs				 * if one-to-one, set it on the connected
3427163953Srrs				 * assoc; else endpoint
3428163953Srrs				 */
3429163953Srrs				SCTP_INP_RLOCK(inp);
3430163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3431163953Srrs				if (stcb)
3432163953Srrs					SCTP_TCB_LOCK(stcb);
3433163953Srrs				SCTP_INP_RUNLOCK(inp);
3434163953Srrs			} else if (scact->scact_assoc_id) {
3435163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, scact->scact_assoc_id, 1);
3436163953Srrs				if (stcb == NULL) {
3437163953Srrs					error = ENOENT;
3438163953Srrs					break;
3439163953Srrs				}
3440163953Srrs			}
3441163953Srrs			/* set the active key on the right place */
3442163953Srrs			if (stcb != NULL) {
3443163953Srrs				/* set the active key on the assoc */
3444163953Srrs				if (sctp_auth_setactivekey(stcb, scact->scact_keynumber))
3445163953Srrs					error = EINVAL;
3446163953Srrs				SCTP_TCB_UNLOCK(stcb);
3447163953Srrs			} else {
3448163953Srrs				/* set the active key on the endpoint */
3449163953Srrs				SCTP_INP_WLOCK(inp);
3450163953Srrs				if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber))
3451163953Srrs					error = EINVAL;
3452163953Srrs				SCTP_INP_WUNLOCK(inp);
3453163953Srrs			}
3454163953Srrs			break;
3455163953Srrs		}
3456163953Srrs	case SCTP_AUTH_DELETE_KEY:
3457163953Srrs		{
3458163953Srrs			struct sctp_authkeyid *scdel;
3459163953Srrs
3460163953Srrs			if ((size_t)m->m_len < sizeof(*scdel)) {
3461163953Srrs				error = EINVAL;
3462163953Srrs				break;
3463163953Srrs			}
3464163953Srrs			scdel = mtod(m, struct sctp_authkeyid *);
3465163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3466163953Srrs				/*
3467163953Srrs				 * if one-to-one, delete from the connected
3468163953Srrs				 * assoc; else endpoint
3469163953Srrs				 */
3470163953Srrs				SCTP_INP_RLOCK(inp);
3471163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3472163953Srrs				if (stcb)
3473163953Srrs					SCTP_TCB_LOCK(stcb);
3474163953Srrs				SCTP_INP_RUNLOCK(inp);
3475163953Srrs			} else if (scdel->scact_assoc_id) {
3476163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, scdel->scact_assoc_id, 1);
3477163953Srrs				if (stcb == NULL) {
3478163953Srrs					error = ENOENT;
3479163953Srrs					break;
3480163953Srrs				}
3481163953Srrs			}
3482163953Srrs			/* delete the key from the right place */
3483163953Srrs			if (stcb != NULL) {
3484163953Srrs				if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber))
3485163953Srrs					error = EINVAL;
3486163953Srrs				SCTP_TCB_UNLOCK(stcb);
3487163953Srrs			} else {
3488163953Srrs				SCTP_INP_WLOCK(inp);
3489163953Srrs				if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber))
3490163953Srrs					error = EINVAL;
3491163953Srrs				SCTP_INP_WUNLOCK(inp);
3492163953Srrs			}
3493163953Srrs			break;
3494163953Srrs		}
3495163953Srrs
3496163953Srrs	case SCTP_RESET_STREAMS:
3497163953Srrs		{
3498163953Srrs			struct sctp_stream_reset *strrst;
3499163953Srrs			uint8_t send_in = 0, send_tsn = 0, send_out = 0;
3500163953Srrs			int i;
3501163953Srrs
3502163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_stream_reset)) {
3503163953Srrs				error = EINVAL;
3504163953Srrs				break;
3505163953Srrs			}
3506163953Srrs			strrst = mtod(m, struct sctp_stream_reset *);
3507163953Srrs
3508163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3509163953Srrs				SCTP_INP_RLOCK(inp);
3510163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3511163953Srrs				if (stcb)
3512163953Srrs					SCTP_TCB_LOCK(stcb);
3513163953Srrs				SCTP_INP_RUNLOCK(inp);
3514163953Srrs			} else
3515163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, strrst->strrst_assoc_id, 1);
3516163953Srrs			if (stcb == NULL) {
3517163953Srrs				error = ENOENT;
3518163953Srrs				break;
3519163953Srrs			}
3520163953Srrs			if (stcb->asoc.peer_supports_strreset == 0) {
3521163953Srrs				/*
3522163953Srrs				 * Peer does not support it, we return
3523163953Srrs				 * protocol not supported since this is true
3524163953Srrs				 * for this feature and this peer, not the
3525163953Srrs				 * socket request in general.
3526163953Srrs				 */
3527163953Srrs				error = EPROTONOSUPPORT;
3528163953Srrs				SCTP_TCB_UNLOCK(stcb);
3529163953Srrs				break;
3530163953Srrs			}
3531163953Srrs			if (stcb->asoc.stream_reset_outstanding) {
3532163953Srrs				error = EALREADY;
3533163953Srrs				SCTP_TCB_UNLOCK(stcb);
3534163953Srrs				break;
3535163953Srrs			}
3536163953Srrs			if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) {
3537163953Srrs				send_in = 1;
3538163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) {
3539163953Srrs				send_out = 1;
3540163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_BOTH) {
3541163953Srrs				send_in = 1;
3542163953Srrs				send_out = 1;
3543163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_TSN) {
3544163953Srrs				send_tsn = 1;
3545163953Srrs			} else {
3546163953Srrs				error = EINVAL;
3547163953Srrs				SCTP_TCB_UNLOCK(stcb);
3548163953Srrs				break;
3549163953Srrs			}
3550163953Srrs			for (i = 0; i < strrst->strrst_num_streams; i++) {
3551163953Srrs				if ((send_in) &&
3552163953Srrs
3553163953Srrs				    (strrst->strrst_list[i] > stcb->asoc.streamincnt)) {
3554163953Srrs					error = EINVAL;
3555163953Srrs					goto get_out;
3556163953Srrs				}
3557163953Srrs				if ((send_out) &&
3558163953Srrs				    (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) {
3559163953Srrs					error = EINVAL;
3560163953Srrs					goto get_out;
3561163953Srrs				}
3562163953Srrs			}
3563163953Srrs			if (error) {
3564163953Srrs		get_out:
3565163953Srrs				SCTP_TCB_UNLOCK(stcb);
3566163953Srrs				break;
3567163953Srrs			}
3568163953Srrs			error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams,
3569163953Srrs			    strrst->strrst_list,
3570163953Srrs			    send_out, (stcb->asoc.str_reset_seq_in - 3),
3571163953Srrs			    send_in, send_tsn);
3572163953Srrs
3573163953Srrs			s = splnet();
3574163953Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ);
3575163953Srrs			SCTP_TCB_UNLOCK(stcb);
3576163953Srrs			splx(s);
3577163953Srrs
3578163953Srrs		}
3579163953Srrs		break;
3580163953Srrs	case SCTP_CONNECT_X:
3581163953Srrs		if ((size_t)m->m_len < (sizeof(int) + sizeof(struct sockaddr_in))) {
3582163953Srrs			error = EINVAL;
3583163953Srrs			break;
3584163953Srrs		}
3585163953Srrs		error = sctp_do_connect_x(so, inp, m, p, 0);
3586163953Srrs		break;
3587163953Srrs
3588163953Srrs	case SCTP_CONNECT_X_DELAYED:
3589163953Srrs		if ((size_t)m->m_len < (sizeof(int) + sizeof(struct sockaddr_in))) {
3590163953Srrs			error = EINVAL;
3591163953Srrs			break;
3592163953Srrs		}
3593163953Srrs		error = sctp_do_connect_x(so, inp, m, p, 1);
3594163953Srrs		break;
3595163953Srrs
3596163953Srrs	case SCTP_CONNECT_X_COMPLETE:
3597163953Srrs		{
3598163953Srrs			struct sockaddr *sa;
3599163953Srrs			struct sctp_nets *net;
3600163953Srrs
3601163953Srrs			if ((size_t)m->m_len < sizeof(struct sockaddr_in)) {
3602163953Srrs				error = EINVAL;
3603163953Srrs				break;
3604163953Srrs			}
3605163953Srrs			sa = mtod(m, struct sockaddr *);
3606163953Srrs			/* find tcb */
3607163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3608163953Srrs				SCTP_INP_RLOCK(inp);
3609163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3610163953Srrs				if (stcb) {
3611163953Srrs					SCTP_TCB_LOCK(stcb);
3612163953Srrs					net = sctp_findnet(stcb, sa);
3613163953Srrs				}
3614163953Srrs				SCTP_INP_RUNLOCK(inp);
3615163953Srrs			} else {
3616163953Srrs				SCTP_INP_INCR_REF(inp);
3617163953Srrs				stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL);
3618163953Srrs				if (stcb == NULL) {
3619163953Srrs					SCTP_INP_DECR_REF(inp);
3620163953Srrs				}
3621163953Srrs			}
3622163953Srrs
3623163953Srrs			if (stcb == NULL) {
3624163953Srrs				error = ENOENT;
3625163953Srrs				break;
3626163953Srrs			}
3627163953Srrs			if (stcb->asoc.delayed_connection == 1) {
3628163953Srrs				stcb->asoc.delayed_connection = 0;
3629163953Srrs				SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
3630163953Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
3631163953Srrs				sctp_send_initiate(inp, stcb);
3632163953Srrs			} else {
3633163953Srrs				/*
3634163953Srrs				 * already expired or did not use delayed
3635163953Srrs				 * connectx
3636163953Srrs				 */
3637163953Srrs				error = EALREADY;
3638163953Srrs			}
3639163953Srrs			SCTP_TCB_UNLOCK(stcb);
3640163953Srrs		}
3641163953Srrs		break;
3642163953Srrs	case SCTP_MAXBURST:
3643163953Srrs		{
3644163953Srrs			uint8_t *burst;
3645163953Srrs
3646163953Srrs			SCTP_INP_WLOCK(inp);
3647163953Srrs			burst = mtod(m, uint8_t *);
3648163953Srrs			if (*burst) {
3649163953Srrs				inp->sctp_ep.max_burst = *burst;
3650163953Srrs			}
3651163953Srrs			SCTP_INP_WUNLOCK(inp);
3652163953Srrs		}
3653163953Srrs		break;
3654163953Srrs	case SCTP_MAXSEG:
3655163953Srrs		{
3656163953Srrs			uint32_t *segsize;
3657163953Srrs			int ovh;
3658163953Srrs
3659163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3660163953Srrs				ovh = SCTP_MED_OVERHEAD;
3661163953Srrs			} else {
3662163953Srrs				ovh = SCTP_MED_V4_OVERHEAD;
3663163953Srrs			}
3664163953Srrs			segsize = mtod(m, uint32_t *);
3665163953Srrs			if (*segsize < 1) {
3666163953Srrs				error = EINVAL;
3667163953Srrs				break;
3668163953Srrs			}
3669163953Srrs			SCTP_INP_WLOCK(inp);
3670163953Srrs			inp->sctp_frag_point = (*segsize + ovh);
3671163953Srrs			if (inp->sctp_frag_point < MHLEN) {
3672163953Srrs				inp->sctp_frag_point = MHLEN;
3673163953Srrs			}
3674163953Srrs			SCTP_INP_WUNLOCK(inp);
3675163953Srrs		}
3676163953Srrs		break;
3677163953Srrs	case SCTP_SET_DEBUG_LEVEL:
3678163953Srrs#ifdef SCTP_DEBUG
3679163953Srrs		{
3680163953Srrs			uint32_t *level;
3681163953Srrs
3682163953Srrs			if ((size_t)m->m_len < sizeof(uint32_t)) {
3683163953Srrs				error = EINVAL;
3684163953Srrs				break;
3685163953Srrs			}
3686163953Srrs			level = mtod(m, uint32_t *);
3687163953Srrs			error = 0;
3688163953Srrs			sctp_debug_on = (*level & (SCTP_DEBUG_ALL |
3689163953Srrs			    SCTP_DEBUG_NOISY));
3690163953Srrs			printf("SETTING DEBUG LEVEL to %x\n",
3691163953Srrs			    (uint32_t) sctp_debug_on);
3692163953Srrs
3693163953Srrs		}
3694163953Srrs#else
3695163953Srrs		error = EOPNOTSUPP;
3696163953Srrs#endif				/* SCTP_DEBUG */
3697163953Srrs		break;
3698163953Srrs	case SCTP_EVENTS:
3699163953Srrs		{
3700163953Srrs			struct sctp_event_subscribe *events;
3701163953Srrs
3702163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_event_subscribe)) {
3703163953Srrs				error = EINVAL;
3704163953Srrs				break;
3705163953Srrs			}
3706163953Srrs			SCTP_INP_WLOCK(inp);
3707163953Srrs			events = mtod(m, struct sctp_event_subscribe *);
3708163953Srrs			if (events->sctp_data_io_event) {
3709163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
3710163953Srrs			} else {
3711163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
3712163953Srrs			}
3713163953Srrs
3714163953Srrs			if (events->sctp_association_event) {
3715163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
3716163953Srrs			} else {
3717163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
3718163953Srrs			}
3719163953Srrs
3720163953Srrs			if (events->sctp_address_event) {
3721163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
3722163953Srrs			} else {
3723163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
3724163953Srrs			}
3725163953Srrs
3726163953Srrs			if (events->sctp_send_failure_event) {
3727163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
3728163953Srrs			} else {
3729163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
3730163953Srrs			}
3731163953Srrs
3732163953Srrs			if (events->sctp_peer_error_event) {
3733163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
3734163953Srrs			} else {
3735163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
3736163953Srrs			}
3737163953Srrs
3738163953Srrs			if (events->sctp_shutdown_event) {
3739163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
3740163953Srrs			} else {
3741163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
3742163953Srrs			}
3743163953Srrs
3744163953Srrs			if (events->sctp_partial_delivery_event) {
3745163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
3746163953Srrs			} else {
3747163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
3748163953Srrs			}
3749163953Srrs
3750163953Srrs			if (events->sctp_adaptation_layer_event) {
3751163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
3752163953Srrs			} else {
3753163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
3754163953Srrs			}
3755163953Srrs
3756163953Srrs			if (events->sctp_authentication_event) {
3757163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
3758163953Srrs			} else {
3759163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
3760163953Srrs			}
3761163953Srrs
3762163953Srrs			if (events->sctp_stream_reset_events) {
3763163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
3764163953Srrs			} else {
3765163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
3766163953Srrs			}
3767163953Srrs			SCTP_INP_WUNLOCK(inp);
3768163953Srrs		}
3769163953Srrs		break;
3770163953Srrs
3771163953Srrs	case SCTP_ADAPTATION_LAYER:
3772163953Srrs		{
3773163953Srrs			struct sctp_setadaptation *adap_bits;
3774163953Srrs
3775163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_setadaptation)) {
3776163953Srrs				error = EINVAL;
3777163953Srrs				break;
3778163953Srrs			}
3779163953Srrs			SCTP_INP_WLOCK(inp);
3780163953Srrs			adap_bits = mtod(m, struct sctp_setadaptation *);
3781163953Srrs			inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
3782163953Srrs			SCTP_INP_WUNLOCK(inp);
3783163953Srrs		}
3784163953Srrs		break;
3785163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
3786163953Srrs		{
3787163953Srrs			uint32_t *vvv;
3788163953Srrs
3789163953Srrs			if ((size_t)m->m_len < sizeof(uint32_t)) {
3790163953Srrs				error = EINVAL;
3791163953Srrs				break;
3792163953Srrs			}
3793163953Srrs			SCTP_INP_WLOCK(inp);
3794163953Srrs			vvv = mtod(m, uint32_t *);
3795163953Srrs			inp->sctp_ep.initial_sequence_debug = *vvv;
3796163953Srrs			SCTP_INP_WUNLOCK(inp);
3797163953Srrs		}
3798163953Srrs		break;
3799163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
3800163953Srrs		{
3801163953Srrs			struct sctp_sndrcvinfo *s_info;
3802163953Srrs
3803163953Srrs			if (m->m_len != sizeof(struct sctp_sndrcvinfo)) {
3804163953Srrs				error = EINVAL;
3805163953Srrs				break;
3806163953Srrs			}
3807163953Srrs			s_info = mtod(m, struct sctp_sndrcvinfo *);
3808163953Srrs
3809163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3810163953Srrs				SCTP_INP_RLOCK(inp);
3811163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3812163953Srrs				if (stcb)
3813163953Srrs					SCTP_TCB_LOCK(stcb);
3814163953Srrs				SCTP_INP_RUNLOCK(inp);
3815163953Srrs			} else {
3816163953Srrs				if (s_info->sinfo_assoc_id) {
3817163953Srrs					stcb = sctp_findassociation_ep_asocid(inp, s_info->sinfo_assoc_id, 1);
3818163953Srrs				} else {
3819163953Srrs					stcb = NULL;
3820163953Srrs				}
3821163953Srrs			}
3822163953Srrs			if ((s_info->sinfo_assoc_id == 0) &&
3823163953Srrs			    (stcb == NULL)) {
3824163953Srrs				inp->def_send = *s_info;
3825163953Srrs			} else if (stcb == NULL) {
3826163953Srrs				error = ENOENT;
3827163953Srrs				break;
3828163953Srrs			}
3829163953Srrs			/* Validate things */
3830163953Srrs			if (s_info->sinfo_stream > stcb->asoc.streamoutcnt) {
3831163953Srrs				SCTP_TCB_UNLOCK(stcb);
3832163953Srrs				error = EINVAL;
3833163953Srrs				break;
3834163953Srrs			}
3835163953Srrs			/* Copy it in */
3836163953Srrs			stcb->asoc.def_send = *s_info;
3837163953Srrs			SCTP_TCB_UNLOCK(stcb);
3838163953Srrs		}
3839163953Srrs		break;
3840163953Srrs	case SCTP_PEER_ADDR_PARAMS:
3841163953Srrs		/* Applys to the specific association */
3842163953Srrs		{
3843163953Srrs			struct sctp_paddrparams *paddrp;
3844163953Srrs			struct sctp_nets *net;
3845163953Srrs
3846163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_paddrparams)) {
3847163953Srrs				error = EINVAL;
3848163953Srrs				break;
3849163953Srrs			}
3850163953Srrs			paddrp = mtod(m, struct sctp_paddrparams *);
3851163953Srrs			net = NULL;
3852163953Srrs			if (paddrp->spp_assoc_id) {
3853163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3854163953Srrs					SCTP_INP_RLOCK(inp);
3855163953Srrs					stcb = LIST_FIRST(&inp->sctp_asoc_list);
3856163953Srrs					if (stcb) {
3857163953Srrs						SCTP_TCB_LOCK(stcb);
3858163953Srrs						net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
3859163953Srrs					}
3860163953Srrs					SCTP_INP_RUNLOCK(inp);
3861163953Srrs				} else {
3862163953Srrs					stcb = sctp_findassociation_ep_asocid(inp, paddrp->spp_assoc_id, 1);
3863163953Srrs				}
3864163953Srrs				if (stcb == NULL) {
3865163953Srrs					error = ENOENT;
3866163953Srrs					break;
3867163953Srrs				}
3868163953Srrs			}
3869163953Srrs			if ((stcb == NULL) &&
3870163953Srrs			    ((((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET) ||
3871163953Srrs			    (((struct sockaddr *)&paddrp->spp_address)->sa_family == AF_INET6))) {
3872163953Srrs				/* Lookup via address */
3873163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3874163953Srrs					SCTP_INP_RLOCK(inp);
3875163953Srrs					stcb = LIST_FIRST(&inp->sctp_asoc_list);
3876163953Srrs					if (stcb) {
3877163953Srrs						SCTP_TCB_LOCK(stcb);
3878163953Srrs						net = sctp_findnet(stcb,
3879163953Srrs						    (struct sockaddr *)&paddrp->spp_address);
3880163953Srrs					}
3881163953Srrs					SCTP_INP_RUNLOCK(inp);
3882163953Srrs				} else {
3883163953Srrs					SCTP_INP_INCR_REF(inp);
3884163953Srrs					stcb = sctp_findassociation_ep_addr(&inp,
3885163953Srrs					    (struct sockaddr *)&paddrp->spp_address,
3886163953Srrs					    &net, NULL, NULL);
3887163953Srrs					if (stcb == NULL) {
3888163953Srrs						SCTP_INP_DECR_REF(inp);
3889163953Srrs					}
3890163953Srrs				}
3891163953Srrs			}
3892163953Srrs			if (stcb) {
3893163953Srrs				/************************TCB SPECIFIC SET ******************/
3894163953Srrs				/* sack delay first */
3895163953Srrs				if (paddrp->spp_flags & SPP_SACKDELAY_ENABLE) {
3896163953Srrs					/*
3897163953Srrs					 * we do NOT support turning it off
3898163953Srrs					 * (yet). only setting the delay.
3899163953Srrs					 */
3900163953Srrs					if (paddrp->spp_sackdelay >= SCTP_CLOCK_GRANULARITY)
3901163953Srrs						stcb->asoc.delayed_ack = paddrp->spp_sackdelay;
3902163953Srrs					else
3903163953Srrs						stcb->asoc.delayed_ack = SCTP_CLOCK_GRANULARITY;
3904163953Srrs
3905163953Srrs				} else if (paddrp->spp_flags & SPP_SACKDELAY_DISABLE) {
3906163953Srrs					stcb->asoc.delayed_ack = 0;
3907163953Srrs				}
3908163953Srrs				/*
3909163953Srrs				 * do we change the timer for HB, we run
3910163953Srrs				 * only one?
3911163953Srrs				 */
3912163953Srrs				if (paddrp->spp_hbinterval)
3913163953Srrs					stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
3914163953Srrs				else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
3915163953Srrs					stcb->asoc.heart_beat_delay = 0;
3916163953Srrs
3917163953Srrs				/* network sets ? */
3918163953Srrs				if (net) {
3919163953Srrs					/************************NET SPECIFIC SET ******************/
3920163953Srrs					if (paddrp->spp_flags & SPP_HB_DEMAND) {
3921163953Srrs						/* on demand HB */
3922163953Srrs						sctp_send_hb(stcb, 1, net);
3923163953Srrs					}
3924163953Srrs					if (paddrp->spp_flags & SPP_HB_DISABLE) {
3925163953Srrs						net->dest_state |= SCTP_ADDR_NOHB;
3926163953Srrs					}
3927163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
3928163953Srrs						net->dest_state &= ~SCTP_ADDR_NOHB;
3929163953Srrs					}
3930163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
3931163953Srrs						if (callout_pending(&net->pmtu_timer.timer)) {
3932163953Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
3933163953Srrs						}
3934163953Srrs						if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
3935163953Srrs							net->mtu = paddrp->spp_pathmtu;
3936163953Srrs							if (net->mtu < stcb->asoc.smallest_mtu)
3937163953Srrs								sctp_pathmtu_adustment(inp, stcb, net, net->mtu);
3938163953Srrs						}
3939163953Srrs					}
3940163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
3941163953Srrs						if (callout_pending(&net->pmtu_timer.timer)) {
3942163953Srrs							sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
3943163953Srrs						}
3944163953Srrs					}
3945163953Srrs					if (paddrp->spp_pathmaxrxt)
3946163953Srrs						net->failure_threshold = paddrp->spp_pathmaxrxt;
3947163953Srrs#ifdef AF_INET
3948163953Srrs					if (paddrp->spp_flags & SPP_IPV4_TOS) {
3949163953Srrs						if (net->ro._l_addr.sin.sin_family == AF_INET) {
3950163953Srrs							net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc;
3951163953Srrs						}
3952163953Srrs					}
3953163953Srrs#endif
3954163953Srrs#ifdef AF_INET6
3955163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
3956163953Srrs						if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
3957163953Srrs							net->tos_flowlabel = paddrp->spp_ipv6_flowlabel;
3958163953Srrs						}
3959163953Srrs					}
3960163953Srrs#endif
3961163953Srrs				} else {
3962163953Srrs					/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
3963163953Srrs					if (paddrp->spp_pathmaxrxt)
3964163953Srrs						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
3965163953Srrs
3966163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
3967163953Srrs						/* Turn back on the timer */
3968163953Srrs						stcb->asoc.hb_is_disabled = 0;
3969163953Srrs						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
3970163953Srrs					}
3971163953Srrs					if (paddrp->spp_flags & SPP_HB_DISABLE) {
3972163953Srrs						int cnt_of_unconf = 0;
3973163953Srrs						struct sctp_nets *lnet;
3974163953Srrs
3975163953Srrs						stcb->asoc.hb_is_disabled = 1;
3976163953Srrs						TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
3977163953Srrs							if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
3978163953Srrs								cnt_of_unconf++;
3979163953Srrs							}
3980163953Srrs						}
3981163953Srrs						/*
3982163953Srrs						 * stop the timer ONLY if we
3983163953Srrs						 * have no unconfirmed
3984163953Srrs						 * addresses
3985163953Srrs						 */
3986163953Srrs						if (cnt_of_unconf == 0) {
3987163953Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
3988163953Srrs						}
3989163953Srrs					}
3990163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
3991163953Srrs						/* start up the timer. */
3992163953Srrs						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
3993163953Srrs					}
3994163953Srrs#ifdef AF_INET
3995163953Srrs					if (paddrp->spp_flags & SPP_IPV4_TOS)
3996163953Srrs						stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc;
3997163953Srrs#endif
3998163953Srrs#ifdef AF_INET6
3999163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL)
4000163953Srrs						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel;
4001163953Srrs#endif
4002163953Srrs
4003163953Srrs				}
4004163953Srrs				SCTP_TCB_UNLOCK(stcb);
4005163953Srrs			} else {
4006163953Srrs				/************************NO TCB, SET TO default stuff ******************/
4007163953Srrs				SCTP_INP_WLOCK(inp);
4008163953Srrs				/*
4009163953Srrs				 * For the TOS/FLOWLABEL stuff you set it
4010163953Srrs				 * with the options on the socket
4011163953Srrs				 */
4012163953Srrs				if (paddrp->spp_pathmaxrxt) {
4013163953Srrs					inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
4014163953Srrs				}
4015163953Srrs				if (paddrp->spp_flags & SPP_HB_ENABLE) {
4016163953Srrs					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
4017163953Srrs					sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
4018163953Srrs				} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
4019163953Srrs					sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
4020163953Srrs				}
4021163953Srrs				if (paddrp->spp_flags & SPP_SACKDELAY_ENABLE) {
4022163953Srrs					if (paddrp->spp_sackdelay > SCTP_CLOCK_GRANULARITY)
4023163953Srrs						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(paddrp->spp_sackdelay);
4024163953Srrs					else
4025163953Srrs						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(SCTP_CLOCK_GRANULARITY);
4026163953Srrs
4027163953Srrs				} else if (paddrp->spp_flags & SPP_SACKDELAY_DISABLE) {
4028163953Srrs					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = 0;
4029163953Srrs				}
4030163953Srrs				SCTP_INP_WUNLOCK(inp);
4031163953Srrs			}
4032163953Srrs		}
4033163953Srrs		break;
4034163953Srrs	case SCTP_RTOINFO:
4035163953Srrs		{
4036163953Srrs			struct sctp_rtoinfo *srto;
4037163953Srrs
4038163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_rtoinfo)) {
4039163953Srrs				error = EINVAL;
4040163953Srrs				break;
4041163953Srrs			}
4042163953Srrs			srto = mtod(m, struct sctp_rtoinfo *);
4043163953Srrs			if (srto->srto_assoc_id == 0) {
4044163953Srrs				SCTP_INP_WLOCK(inp);
4045163953Srrs				/*
4046163953Srrs				 * If we have a null asoc, its default for
4047163953Srrs				 * the endpoint
4048163953Srrs				 */
4049163953Srrs				if (srto->srto_initial > 10)
4050163953Srrs					inp->sctp_ep.initial_rto = srto->srto_initial;
4051163953Srrs				if (srto->srto_max > 10)
4052163953Srrs					inp->sctp_ep.sctp_maxrto = srto->srto_max;
4053163953Srrs				if (srto->srto_min > 10)
4054163953Srrs					inp->sctp_ep.sctp_minrto = srto->srto_min;
4055163953Srrs				SCTP_INP_WUNLOCK(inp);
4056163953Srrs				break;
4057163953Srrs			}
4058163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4059163953Srrs				SCTP_INP_RLOCK(inp);
4060163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
4061163953Srrs				if (stcb)
4062163953Srrs					SCTP_TCB_LOCK(stcb);
4063163953Srrs				SCTP_INP_RUNLOCK(inp);
4064163953Srrs			} else
4065163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, srto->srto_assoc_id, 1);
4066163953Srrs			if (stcb == NULL) {
4067163953Srrs				error = EINVAL;
4068163953Srrs				break;
4069163953Srrs			}
4070163953Srrs			/* Set in ms we hope :-) */
4071163953Srrs			if (srto->srto_initial > 10)
4072163953Srrs				stcb->asoc.initial_rto = srto->srto_initial;
4073163953Srrs			if (srto->srto_max > 10)
4074163953Srrs				stcb->asoc.maxrto = srto->srto_max;
4075163953Srrs			if (srto->srto_min > 10)
4076163953Srrs				stcb->asoc.minrto = srto->srto_min;
4077163953Srrs			SCTP_TCB_UNLOCK(stcb);
4078163953Srrs		}
4079163953Srrs		break;
4080163953Srrs	case SCTP_ASSOCINFO:
4081163953Srrs		{
4082163953Srrs			struct sctp_assocparams *sasoc;
4083163953Srrs
4084163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_assocparams)) {
4085163953Srrs				error = EINVAL;
4086163953Srrs				break;
4087163953Srrs			}
4088163953Srrs			sasoc = mtod(m, struct sctp_assocparams *);
4089163953Srrs			if (sasoc->sasoc_assoc_id) {
4090163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4091163953Srrs					SCTP_INP_RLOCK(inp);
4092163953Srrs					stcb = LIST_FIRST(&inp->sctp_asoc_list);
4093163953Srrs					if (stcb)
4094163953Srrs						SCTP_TCB_LOCK(stcb);
4095163953Srrs					SCTP_INP_RUNLOCK(inp);
4096163953Srrs				} else
4097163953Srrs					stcb = sctp_findassociation_ep_asocid(inp,
4098163953Srrs					    sasoc->sasoc_assoc_id, 1);
4099163953Srrs				if (stcb == NULL) {
4100163953Srrs					error = ENOENT;
4101163953Srrs					break;
4102163953Srrs				}
4103163953Srrs			} else {
4104163953Srrs				stcb = NULL;
4105163953Srrs			}
4106163953Srrs			if (stcb) {
4107163953Srrs				if (sasoc->sasoc_asocmaxrxt)
4108163953Srrs					stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
4109163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
4110163953Srrs				sasoc->sasoc_peer_rwnd = 0;
4111163953Srrs				sasoc->sasoc_local_rwnd = 0;
4112163953Srrs				if (stcb->asoc.cookie_life)
4113163953Srrs					stcb->asoc.cookie_life = sasoc->sasoc_cookie_life;
4114163953Srrs				SCTP_TCB_UNLOCK(stcb);
4115163953Srrs			} else {
4116163953Srrs				SCTP_INP_WLOCK(inp);
4117163953Srrs				if (sasoc->sasoc_asocmaxrxt)
4118163953Srrs					inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
4119163953Srrs				sasoc->sasoc_number_peer_destinations = 0;
4120163953Srrs				sasoc->sasoc_peer_rwnd = 0;
4121163953Srrs				sasoc->sasoc_local_rwnd = 0;
4122163953Srrs				if (sasoc->sasoc_cookie_life)
4123163953Srrs					inp->sctp_ep.def_cookie_life = sasoc->sasoc_cookie_life;
4124163953Srrs				SCTP_INP_WUNLOCK(inp);
4125163953Srrs			}
4126163953Srrs		}
4127163953Srrs		break;
4128163953Srrs	case SCTP_INITMSG:
4129163953Srrs		{
4130163953Srrs			struct sctp_initmsg *sinit;
4131163953Srrs
4132163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_initmsg)) {
4133163953Srrs				error = EINVAL;
4134163953Srrs				break;
4135163953Srrs			}
4136163953Srrs			sinit = mtod(m, struct sctp_initmsg *);
4137163953Srrs			SCTP_INP_WLOCK(inp);
4138163953Srrs			if (sinit->sinit_num_ostreams)
4139163953Srrs				inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
4140163953Srrs
4141163953Srrs			if (sinit->sinit_max_instreams)
4142163953Srrs				inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
4143163953Srrs
4144163953Srrs			if (sinit->sinit_max_attempts)
4145163953Srrs				inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
4146163953Srrs
4147163953Srrs			if (sinit->sinit_max_init_timeo > 10)
4148163953Srrs				/*
4149163953Srrs				 * We must be at least a 100ms (we set in
4150163953Srrs				 * ticks)
4151163953Srrs				 */
4152163953Srrs				inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
4153163953Srrs			SCTP_INP_WUNLOCK(inp);
4154163953Srrs		}
4155163953Srrs		break;
4156163953Srrs	case SCTP_PRIMARY_ADDR:
4157163953Srrs		{
4158163953Srrs			struct sctp_setprim *spa;
4159163953Srrs			struct sctp_nets *net, *lnet;
4160163953Srrs
4161163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_setprim)) {
4162163953Srrs				error = EINVAL;
4163163953Srrs				break;
4164163953Srrs			}
4165163953Srrs			spa = mtod(m, struct sctp_setprim *);
4166163953Srrs
4167163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4168163953Srrs				SCTP_INP_RLOCK(inp);
4169163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
4170163953Srrs				if (stcb) {
4171163953Srrs					SCTP_TCB_LOCK(stcb);
4172163953Srrs				} else {
4173163953Srrs					error = EINVAL;
4174163953Srrs					break;
4175163953Srrs				}
4176163953Srrs				SCTP_INP_RUNLOCK(inp);
4177163953Srrs			} else
4178163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, spa->ssp_assoc_id, 1);
4179163953Srrs			if (stcb == NULL) {
4180163953Srrs				/* One last shot */
4181163953Srrs				SCTP_INP_INCR_REF(inp);
4182163953Srrs				stcb = sctp_findassociation_ep_addr(&inp,
4183163953Srrs				    (struct sockaddr *)&spa->ssp_addr,
4184163953Srrs				    &net, NULL, NULL);
4185163953Srrs				if (stcb == NULL) {
4186163953Srrs					SCTP_INP_DECR_REF(inp);
4187163953Srrs					error = EINVAL;
4188163953Srrs					break;
4189163953Srrs				}
4190163953Srrs			} else {
4191163953Srrs				/*
4192163953Srrs				 * find the net, associd or connected lookup
4193163953Srrs				 * type
4194163953Srrs				 */
4195163953Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
4196163953Srrs				if (net == NULL) {
4197163953Srrs					SCTP_TCB_UNLOCK(stcb);
4198163953Srrs					error = EINVAL;
4199163953Srrs					break;
4200163953Srrs				}
4201163953Srrs			}
4202163953Srrs			if ((net != stcb->asoc.primary_destination) &&
4203163953Srrs			    (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
4204163953Srrs				/* Ok we need to set it */
4205163953Srrs				lnet = stcb->asoc.primary_destination;
4206163953Srrs				if (sctp_set_primary_addr(stcb,
4207163953Srrs				    (struct sockaddr *)NULL,
4208163953Srrs				    net) == 0) {
4209163953Srrs					if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
4210163953Srrs						net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
4211163953Srrs					}
4212163953Srrs					net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY;
4213163953Srrs				}
4214163953Srrs			}
4215163953Srrs			SCTP_TCB_UNLOCK(stcb);
4216163953Srrs		}
4217163953Srrs		break;
4218163953Srrs
4219163953Srrs	case SCTP_SET_PEER_PRIMARY_ADDR:
4220163953Srrs		{
4221163953Srrs			struct sctp_setpeerprim *sspp;
4222163953Srrs
4223163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_setpeerprim)) {
4224163953Srrs				error = EINVAL;
4225163953Srrs				break;
4226163953Srrs			}
4227163953Srrs			sspp = mtod(m, struct sctp_setpeerprim *);
4228163953Srrs
4229163953Srrs
4230163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4231163953Srrs				SCTP_INP_RLOCK(inp);
4232163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
4233163953Srrs				if (stcb)
4234163953Srrs					SCTP_TCB_UNLOCK(stcb);
4235163953Srrs				SCTP_INP_RUNLOCK(inp);
4236163953Srrs			} else
4237163953Srrs				stcb = sctp_findassociation_ep_asocid(inp, sspp->sspp_assoc_id, 1);
4238163953Srrs			if (stcb == NULL) {
4239163953Srrs				error = EINVAL;
4240163953Srrs				break;
4241163953Srrs			}
4242163953Srrs			if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) {
4243163953Srrs				error = EINVAL;
4244163953Srrs			}
4245163953Srrs			SCTP_TCB_UNLOCK(stcb);
4246163953Srrs		}
4247163953Srrs		break;
4248163953Srrs	case SCTP_BINDX_ADD_ADDR:
4249163953Srrs		{
4250163953Srrs			struct sctp_getaddresses *addrs;
4251163953Srrs			struct sockaddr *addr_touse;
4252163953Srrs			struct sockaddr_in sin;
4253163953Srrs
4254163953Srrs			/* see if we're bound all already! */
4255163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
4256163953Srrs				error = EINVAL;
4257163953Srrs				break;
4258163953Srrs			}
4259163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_getaddresses)) {
4260163953Srrs				error = EINVAL;
4261163953Srrs				break;
4262163953Srrs			}
4263163953Srrs			addrs = mtod(m, struct sctp_getaddresses *);
4264163953Srrs			addr_touse = addrs->addr;
4265163953Srrs			if (addrs->addr->sa_family == AF_INET6) {
4266163953Srrs				struct sockaddr_in6 *sin6;
4267163953Srrs
4268163953Srrs				sin6 = (struct sockaddr_in6 *)addr_touse;
4269163953Srrs				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
4270163953Srrs					in6_sin6_2_sin(&sin, sin6);
4271163953Srrs					addr_touse = (struct sockaddr *)&sin;
4272163953Srrs				}
4273163953Srrs			}
4274163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
4275163953Srrs				if (p == NULL) {
4276163953Srrs					/* Can't get proc for Net/Open BSD */
4277163953Srrs					error = EINVAL;
4278163953Srrs					break;
4279163953Srrs				}
4280163953Srrs				error = sctp_inpcb_bind(so, addr_touse, p);
4281163953Srrs				break;
4282163953Srrs			}
4283163953Srrs			/*
4284163953Srrs			 * No locks required here since bind and mgmt_ep_sa
4285163953Srrs			 * all do their own locking. If we do something for
4286163953Srrs			 * the FIX: below we may need to lock in that case.
4287163953Srrs			 */
4288163953Srrs			if (addrs->sget_assoc_id == 0) {
4289163953Srrs				/* add the address */
4290163953Srrs				struct sctp_inpcb *lep;
4291163953Srrs
4292163953Srrs				((struct sockaddr_in *)addr_touse)->sin_port = inp->sctp_lport;
4293163953Srrs				lep = sctp_pcb_findep(addr_touse, 1, 0);
4294163953Srrs				if (lep != NULL) {
4295163953Srrs					/*
4296163953Srrs					 * We must decrement the refcount
4297163953Srrs					 * since we have the ep already and
4298163953Srrs					 * are binding. No remove going on
4299163953Srrs					 * here.
4300163953Srrs					 */
4301163953Srrs					SCTP_INP_DECR_REF(inp);
4302163953Srrs				}
4303163953Srrs				if (lep == inp) {
4304163953Srrs					/* already bound to it.. ok */
4305163953Srrs					break;
4306163953Srrs				} else if (lep == NULL) {
4307163953Srrs					((struct sockaddr_in *)addr_touse)->sin_port = 0;
4308163953Srrs					error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
4309163953Srrs					    SCTP_ADD_IP_ADDRESS);
4310163953Srrs				} else {
4311163953Srrs					error = EADDRNOTAVAIL;
4312163953Srrs				}
4313163953Srrs				if (error)
4314163953Srrs					break;
4315163953Srrs
4316163953Srrs			} else {
4317163953Srrs				/*
4318163953Srrs				 * FIX: decide whether we allow assoc based
4319163953Srrs				 * bindx
4320163953Srrs				 */
4321163953Srrs			}
4322163953Srrs		}
4323163953Srrs		break;
4324163953Srrs	case SCTP_BINDX_REM_ADDR:
4325163953Srrs		{
4326163953Srrs			struct sctp_getaddresses *addrs;
4327163953Srrs			struct sockaddr *addr_touse;
4328163953Srrs			struct sockaddr_in sin;
4329163953Srrs
4330163953Srrs			/* see if we're bound all already! */
4331163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
4332163953Srrs				error = EINVAL;
4333163953Srrs				break;
4334163953Srrs			}
4335163953Srrs			if ((size_t)m->m_len < sizeof(struct sctp_getaddresses)) {
4336163953Srrs				error = EINVAL;
4337163953Srrs				break;
4338163953Srrs			}
4339163953Srrs			addrs = mtod(m, struct sctp_getaddresses *);
4340163953Srrs			addr_touse = addrs->addr;
4341163953Srrs			if (addrs->addr->sa_family == AF_INET6) {
4342163953Srrs				struct sockaddr_in6 *sin6;
4343163953Srrs
4344163953Srrs				sin6 = (struct sockaddr_in6 *)addr_touse;
4345163953Srrs				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
4346163953Srrs					in6_sin6_2_sin(&sin, sin6);
4347163953Srrs					addr_touse = (struct sockaddr *)&sin;
4348163953Srrs				}
4349163953Srrs			}
4350163953Srrs			/*
4351163953Srrs			 * No lock required mgmt_ep_sa does its own locking.
4352163953Srrs			 * If the FIX: below is ever changed we may need to
4353163953Srrs			 * lock before calling association level binding.
4354163953Srrs			 */
4355163953Srrs			if (addrs->sget_assoc_id == 0) {
4356163953Srrs				/* delete the address */
4357163953Srrs				sctp_addr_mgmt_ep_sa(inp, addr_touse,
4358163953Srrs				    SCTP_DEL_IP_ADDRESS);
4359163953Srrs			} else {
4360163953Srrs				/*
4361163953Srrs				 * FIX: decide whether we allow assoc based
4362163953Srrs				 * bindx
4363163953Srrs				 */
4364163953Srrs			}
4365163953Srrs		}
4366163953Srrs		break;
4367163953Srrs	default:
4368163953Srrs		error = ENOPROTOOPT;
4369163953Srrs		break;
4370163953Srrs	}			/* end switch (opt) */
4371163953Srrs	return (error);
4372163953Srrs}
4373163953Srrs
4374163953Srrs
4375163953Srrs
4376163953Srrsextern int sctp_chatty_mbuf;
4377163953Srrs
4378163953Srrsint
4379163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt)
4380163953Srrs{
4381163953Srrs	struct mbuf *m = NULL;
4382163953Srrs	struct sctp_inpcb *inp;
4383163953Srrs	int s, error;
4384163953Srrs
4385163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4386163953Srrs	s = splnet();
4387163953Srrs	if (inp == 0) {
4388163953Srrs		splx(s);
4389163953Srrs		/* I made the same as TCP since we are not setup? */
4390163953Srrs		return (ECONNRESET);
4391163953Srrs	}
4392163953Srrs	if (sopt->sopt_level != IPPROTO_SCTP) {
4393163953Srrs		/* wrong proto level... send back up to IP */
4394163953Srrs#ifdef INET6
4395163953Srrs		if (INP_CHECK_SOCKAF(so, AF_INET6))
4396163953Srrs			error = ip6_ctloutput(so, sopt);
4397163953Srrs		else
4398163953Srrs#endif				/* INET6 */
4399163953Srrs			error = ip_ctloutput(so, sopt);
4400163953Srrs		splx(s);
4401163953Srrs		return (error);
4402163953Srrs	}
4403163953Srrs	if (sopt->sopt_valsize) {
4404163953Srrs		if (sopt->sopt_valsize < MLEN) {
4405163953Srrs			m = sctp_get_mbuf_for_msg(1, 0, M_WAIT, 1, MT_DATA);
4406163953Srrs		} else {
4407163953Srrs			m = sctp_get_mbuf_for_msg(sopt->sopt_valsize, 0, M_WAIT, 1, MT_DATA);
4408163953Srrs		}
4409163953Srrs		if (m == NULL) {
4410163953Srrs			sctp_m_freem(m);
4411163953Srrs			splx(s);
4412163953Srrs			return (ENOBUFS);
4413163953Srrs		}
4414163953Srrs		if (sopt->sopt_valsize > M_TRAILINGSPACE(m)) {
4415163953Srrs			/* Limit to actual size gotten */
4416163953Srrs			sopt->sopt_valsize = M_TRAILINGSPACE(m);
4417163953Srrs		}
4418163953Srrs		error = sooptcopyin(sopt, mtod(m, caddr_t), sopt->sopt_valsize,
4419163953Srrs		    sopt->sopt_valsize);
4420163953Srrs		if (error) {
4421163953Srrs			(void)sctp_m_free(m);
4422163953Srrs			goto out;
4423163953Srrs		}
4424163953Srrs		m->m_len = sopt->sopt_valsize;
4425163953Srrs	}
4426163953Srrs	if (sopt->sopt_dir == SOPT_SET) {
4427163953Srrs		error = sctp_optsset(so, sopt->sopt_name, &m, sopt->sopt_td);
4428163953Srrs	} else if (sopt->sopt_dir == SOPT_GET) {
4429163953Srrs		error = sctp_optsget(so, sopt->sopt_name, &m, sopt->sopt_td);
4430163953Srrs	} else {
4431163953Srrs		error = EINVAL;
4432163953Srrs	}
4433163953Srrs	if ((error == 0) && (m != NULL)) {
4434163953Srrs		error = sooptcopyout(sopt, mtod(m, caddr_t), m->m_len);
4435163953Srrs		sctp_m_freem(m);
4436163953Srrs	} else if (m != NULL) {
4437163953Srrs		sctp_m_freem(m);
4438163953Srrs	}
4439163953Srrsout:
4440163953Srrs	splx(s);
4441163953Srrs	return (error);
4442163953Srrs}
4443163953Srrs
4444163953Srrs
4445163953Srrsstatic int
4446163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
4447163953Srrs{
4448163953Srrs	int s = splnet();
4449163953Srrs
4450163953Srrs	int error = 0;
4451163953Srrs	int create_lock_on = 0;
4452163953Srrs	struct sctp_inpcb *inp;
4453163953Srrs	struct sctp_tcb *stcb = NULL;
4454163953Srrs
4455163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4456163953Srrs	if (inp == 0) {
4457163953Srrs		splx(s);
4458163953Srrs		/* I made the same as TCP since we are not setup? */
4459163953Srrs		return (ECONNRESET);
4460163953Srrs	}
4461163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
4462163953Srrs	create_lock_on = 1;
4463163953Srrs
4464163953Srrs	SCTP_INP_INCR_REF(inp);
4465163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
4466163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
4467163953Srrs		/* Should I really unlock ? */
4468163953Srrs		error = EFAULT;
4469163953Srrs		goto out_now;
4470163953Srrs	}
4471163953Srrs#ifdef INET6
4472163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
4473163953Srrs	    (addr->sa_family == AF_INET6)) {
4474163953Srrs		error = EINVAL;
4475163953Srrs		goto out_now;
4476163953Srrs	}
4477163953Srrs#endif				/* INET6 */
4478163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
4479163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
4480163953Srrs		/* Bind a ephemeral port */
4481163953Srrs		error = sctp_inpcb_bind(so, NULL, p);
4482163953Srrs		if (error) {
4483163953Srrs			goto out_now;
4484163953Srrs		}
4485163953Srrs	}
4486163953Srrs	/* Now do we connect? */
4487163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) {
4488163953Srrs		error = EINVAL;
4489163953Srrs		goto out_now;
4490163953Srrs	}
4491163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
4492163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
4493163953Srrs		/* We are already connected AND the TCP model */
4494163953Srrs		error = EADDRINUSE;
4495163953Srrs		goto out_now;
4496163953Srrs	}
4497163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4498163953Srrs		SCTP_INP_RLOCK(inp);
4499163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
4500163953Srrs		if (stcb)
4501163953Srrs			SCTP_TCB_UNLOCK(stcb);
4502163953Srrs		SCTP_INP_RUNLOCK(inp);
4503163953Srrs	} else {
4504163953Srrs		/*
4505163953Srrs		 * Raise the count a second time, since on sucess
4506163953Srrs		 * f-a-ep_addr will decrement it.
4507163953Srrs		 */
4508163953Srrs		SCTP_INP_INCR_REF(inp);
4509163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
4510163953Srrs		if (stcb == NULL) {
4511163953Srrs			SCTP_INP_DECR_REF(inp);
4512163953Srrs		}
4513163953Srrs	}
4514163953Srrs	if (stcb != NULL) {
4515163953Srrs		/* Already have or am bring up an association */
4516163953Srrs		error = EALREADY;
4517163953Srrs		goto out_now;
4518163953Srrs	}
4519163953Srrs	/* We are GOOD to go */
4520163953Srrs	stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0);
4521163953Srrs	if (stcb == NULL) {
4522163953Srrs		/* Gak! no memory */
4523163953Srrs		splx(s);
4524163953Srrs		return (error);
4525163953Srrs	}
4526163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
4527163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
4528163953Srrs		/* Set the connected flag so we can queue data */
4529163953Srrs		soisconnecting(so);
4530163953Srrs	}
4531163953Srrs	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
4532163953Srrs	SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
4533163953Srrs
4534163953Srrs	/* initialize authentication parameters for the assoc */
4535163953Srrs	sctp_initialize_auth_params(inp, stcb);
4536163953Srrs
4537163953Srrs	sctp_send_initiate(inp, stcb);
4538163953Srrsout_now:
4539163953Srrs	if (create_lock_on)
4540163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
4541163953Srrs
4542163953Srrs	if (stcb)
4543163953Srrs		SCTP_TCB_UNLOCK(stcb);
4544163953Srrs	SCTP_INP_DECR_REF(inp);
4545163953Srrs	splx(s);
4546163953Srrs	return error;
4547163953Srrs}
4548163953Srrs
4549163953Srrsint
4550163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p)
4551163953Srrs{
4552163953Srrs	/*
4553163953Srrs	 * Note this module depends on the protocol processing being called
4554163953Srrs	 * AFTER any socket level flags and backlog are applied to the
4555163953Srrs	 * socket. The traditional way that the socket flags are applied is
4556163953Srrs	 * AFTER protocol processing. We have made a change to the
4557163953Srrs	 * sys/kern/uipc_socket.c module to reverse this but this MUST be in
4558163953Srrs	 * place if the socket API for SCTP is to work properly.
4559163953Srrs	 */
4560163953Srrs	int s = splnet();
4561163953Srrs
4562163953Srrs	int error = 0;
4563163953Srrs	struct sctp_inpcb *inp;
4564163953Srrs
4565163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4566163953Srrs	if (inp == 0) {
4567163953Srrs		splx(s);
4568163953Srrs		/* I made the same as TCP since we are not setup? */
4569163953Srrs		return (ECONNRESET);
4570163953Srrs	}
4571163953Srrs	SCTP_INP_RLOCK(inp);
4572163953Srrs#ifdef SCTP_LOCK_LOGGING
4573163953Srrs	sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
4574163953Srrs#endif
4575163953Srrs	SOCK_LOCK(so);
4576163953Srrs	error = solisten_proto_check(so);
4577163953Srrs	if (error) {
4578163953Srrs		SOCK_UNLOCK(so);
4579163953Srrs		return (error);
4580163953Srrs	}
4581163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
4582163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
4583163953Srrs		/* We are already connected AND the TCP model */
4584163953Srrs		splx(s);
4585163953Srrs		SCTP_INP_RUNLOCK(inp);
4586163953Srrs		SOCK_UNLOCK(so);
4587163953Srrs		return (EADDRINUSE);
4588163953Srrs	}
4589163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
4590163953Srrs		/* We must do a bind. */
4591163953Srrs		SCTP_INP_RUNLOCK(inp);
4592163953Srrs		if ((error = sctp_inpcb_bind(so, NULL, p))) {
4593163953Srrs			/* bind error, probably perm */
4594163953Srrs			SOCK_UNLOCK(so);
4595163953Srrs			splx(s);
4596163953Srrs			return (error);
4597163953Srrs		}
4598163953Srrs	} else {
4599163953Srrs		SCTP_INP_RUNLOCK(inp);
4600163953Srrs	}
4601163953Srrs	/* It appears for 7.0 and on, we must always call this. */
4602163953Srrs	solisten_proto(so, backlog);
4603163953Srrs
4604163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
4605163953Srrs		/* remove the ACCEPTCONN flag for one-to-many sockets */
4606163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
4607163953Srrs	}
4608163953Srrs	if (backlog == 0) {
4609163953Srrs		/* turning off listen */
4610163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
4611163953Srrs	}
4612163953Srrs	SOCK_UNLOCK(so);
4613163953Srrs	splx(s);
4614163953Srrs	return (error);
4615163953Srrs}
4616163953Srrs
4617163953Srrsstatic int sctp_defered_wakeup_cnt = 0;
4618163953Srrs
4619163953Srrsint
4620163953Srrssctp_accept(struct socket *so, struct sockaddr **addr)
4621163953Srrs{
4622163953Srrs	int s = splnet();
4623163953Srrs
4624163953Srrs	struct sctp_tcb *stcb;
4625163953Srrs	struct sctp_inpcb *inp;
4626163953Srrs	union sctp_sockstore store;
4627163953Srrs
4628163953Srrs	int error;
4629163953Srrs
4630163953Srrs
4631163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4632163953Srrs
4633163953Srrs	if (inp == 0) {
4634163953Srrs		splx(s);
4635163953Srrs		return (ECONNRESET);
4636163953Srrs	}
4637163953Srrs	SCTP_INP_RLOCK(inp);
4638163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
4639163953Srrs		return (ENOTSUP);
4640163953Srrs	}
4641163953Srrs	if (so->so_state & SS_ISDISCONNECTED) {
4642163953Srrs		splx(s);
4643163953Srrs		SCTP_INP_RUNLOCK(inp);
4644163953Srrs		return (ECONNABORTED);
4645163953Srrs	}
4646163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
4647163953Srrs	if (stcb == NULL) {
4648163953Srrs		splx(s);
4649163953Srrs		SCTP_INP_RUNLOCK(inp);
4650163953Srrs		return (ECONNRESET);
4651163953Srrs	}
4652163953Srrs	SCTP_TCB_LOCK(stcb);
4653163953Srrs	SCTP_INP_RUNLOCK(inp);
4654163953Srrs	store = stcb->asoc.primary_destination->ro._l_addr;
4655163953Srrs	SCTP_TCB_UNLOCK(stcb);
4656163953Srrs	if (store.sa.sa_family == AF_INET) {
4657163953Srrs		struct sockaddr_in *sin;
4658163953Srrs
4659163953Srrs		SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
4660163953Srrs		sin->sin_family = AF_INET;
4661163953Srrs		sin->sin_len = sizeof(*sin);
4662163953Srrs		sin->sin_port = ((struct sockaddr_in *)&store)->sin_port;
4663163953Srrs		sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr;
4664163953Srrs		*addr = (struct sockaddr *)sin;
4665163953Srrs	} else {
4666163953Srrs		struct sockaddr_in6 *sin6;
4667163953Srrs
4668163953Srrs		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
4669163953Srrs		sin6->sin6_family = AF_INET6;
4670163953Srrs		sin6->sin6_len = sizeof(*sin6);
4671163953Srrs		sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port;
4672163953Srrs
4673163953Srrs		sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr;
4674164085Srrs		if ((error = sa6_recoverscope(sin6)) != 0) {
4675164085Srrs			SCTP_FREE_SONAME(sin6);
4676163953Srrs			return (error);
4677164085Srrs		}
4678163953Srrs		*addr = (struct sockaddr *)sin6;
4679163953Srrs	}
4680163953Srrs	/* Wake any delayed sleep action */
4681163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
4682163953Srrs		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
4683163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
4684163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
4685163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
4686163953Srrs			if (sowriteable(inp->sctp_socket)) {
4687163953Srrs				sowwakeup_locked(inp->sctp_socket);
4688163953Srrs			} else {
4689163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
4690163953Srrs			}
4691163953Srrs		}
4692163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
4693163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
4694163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
4695163953Srrs			if (soreadable(inp->sctp_socket)) {
4696163953Srrs				sctp_defered_wakeup_cnt++;
4697163953Srrs				sorwakeup_locked(inp->sctp_socket);
4698163953Srrs			} else {
4699163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
4700163953Srrs			}
4701163953Srrs		}
4702163953Srrs	}
4703163953Srrs	splx(s);
4704163953Srrs	return (0);
4705163953Srrs}
4706163953Srrs
4707163953Srrsint
4708163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr)
4709163953Srrs{
4710163953Srrs	struct sockaddr_in *sin;
4711163953Srrs
4712163953Srrs	int s;
4713163953Srrs	struct sctp_inpcb *inp;
4714163953Srrs
4715163953Srrs	/*
4716163953Srrs	 * Do the malloc first in case it blocks.
4717163953Srrs	 */
4718163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
4719163953Srrs	sin->sin_family = AF_INET;
4720163953Srrs	sin->sin_len = sizeof(*sin);
4721163953Srrs	s = splnet();
4722163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4723163953Srrs	if (!inp) {
4724163953Srrs		splx(s);
4725163953Srrs		SCTP_FREE_SONAME(sin);
4726163953Srrs		return ECONNRESET;
4727163953Srrs	}
4728163953Srrs	SCTP_INP_RLOCK(inp);
4729163953Srrs	sin->sin_port = inp->sctp_lport;
4730163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
4731163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4732163953Srrs			struct sctp_tcb *stcb;
4733163953Srrs			struct sockaddr_in *sin_a;
4734163953Srrs			struct sctp_nets *net;
4735163953Srrs			int fnd;
4736163953Srrs
4737163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
4738163953Srrs			if (stcb == NULL) {
4739163953Srrs				goto notConn;
4740163953Srrs			}
4741163953Srrs			fnd = 0;
4742163953Srrs			sin_a = NULL;
4743163953Srrs			SCTP_TCB_LOCK(stcb);
4744163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4745163953Srrs				sin_a = (struct sockaddr_in *)&net->ro._l_addr;
4746164085Srrs				if (sin_a == NULL)
4747164085Srrs					/* this will make coverity happy */
4748164085Srrs					continue;
4749164085Srrs
4750163953Srrs				if (sin_a->sin_family == AF_INET) {
4751163953Srrs					fnd = 1;
4752163953Srrs					break;
4753163953Srrs				}
4754163953Srrs			}
4755163953Srrs			if ((!fnd) || (sin_a == NULL)) {
4756163953Srrs				/* punt */
4757163953Srrs				SCTP_TCB_UNLOCK(stcb);
4758163953Srrs				goto notConn;
4759163953Srrs			}
4760163953Srrs			sin->sin_addr = sctp_ipv4_source_address_selection(inp,
4761163953Srrs			    stcb, (struct route *)&net->ro, net, 0);
4762163953Srrs			SCTP_TCB_UNLOCK(stcb);
4763163953Srrs		} else {
4764163953Srrs			/* For the bound all case you get back 0 */
4765163953Srrs	notConn:
4766163953Srrs			sin->sin_addr.s_addr = 0;
4767163953Srrs		}
4768163953Srrs
4769163953Srrs	} else {
4770163953Srrs		/* Take the first IPv4 address in the list */
4771163953Srrs		struct sctp_laddr *laddr;
4772163953Srrs		int fnd = 0;
4773163953Srrs
4774163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
4775163953Srrs			if (laddr->ifa->ifa_addr->sa_family == AF_INET) {
4776163953Srrs				struct sockaddr_in *sin_a;
4777163953Srrs
4778163953Srrs				sin_a = (struct sockaddr_in *)laddr->ifa->ifa_addr;
4779163953Srrs				sin->sin_addr = sin_a->sin_addr;
4780163953Srrs				fnd = 1;
4781163953Srrs				break;
4782163953Srrs			}
4783163953Srrs		}
4784163953Srrs		if (!fnd) {
4785163953Srrs			splx(s);
4786163953Srrs			SCTP_FREE_SONAME(sin);
4787163953Srrs			SCTP_INP_RUNLOCK(inp);
4788163953Srrs			return ENOENT;
4789163953Srrs		}
4790163953Srrs	}
4791163953Srrs	SCTP_INP_RUNLOCK(inp);
4792163953Srrs	splx(s);
4793163953Srrs	(*addr) = (struct sockaddr *)sin;
4794163953Srrs	return (0);
4795163953Srrs}
4796163953Srrs
4797163953Srrsint
4798163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr)
4799163953Srrs{
4800163953Srrs	struct sockaddr_in *sin = (struct sockaddr_in *)*addr;
4801163953Srrs
4802163953Srrs	int s, fnd;
4803163953Srrs	struct sockaddr_in *sin_a;
4804163953Srrs	struct sctp_inpcb *inp;
4805163953Srrs	struct sctp_tcb *stcb;
4806163953Srrs	struct sctp_nets *net;
4807163953Srrs
4808163953Srrs
4809163953Srrs	/* Do the malloc first in case it blocks. */
4810163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4811163953Srrs	if ((inp == NULL) ||
4812163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
4813163953Srrs		/* UDP type and listeners will drop out here */
4814163953Srrs		return (ENOTCONN);
4815163953Srrs	}
4816163953Srrs	s = splnet();
4817163953Srrs
4818163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
4819163953Srrs	sin->sin_family = AF_INET;
4820163953Srrs	sin->sin_len = sizeof(*sin);
4821163953Srrs
4822163953Srrs	/* We must recapture incase we blocked */
4823163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4824163953Srrs	if (!inp) {
4825163953Srrs		splx(s);
4826163953Srrs		SCTP_FREE_SONAME(sin);
4827163953Srrs		return ECONNRESET;
4828163953Srrs	}
4829163953Srrs	SCTP_INP_RLOCK(inp);
4830163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
4831163953Srrs	if (stcb)
4832163953Srrs		SCTP_TCB_LOCK(stcb);
4833163953Srrs	SCTP_INP_RUNLOCK(inp);
4834163953Srrs	if (stcb == NULL) {
4835163953Srrs		splx(s);
4836163953Srrs		SCTP_FREE_SONAME(sin);
4837163953Srrs		return ECONNRESET;
4838163953Srrs	}
4839163953Srrs	fnd = 0;
4840163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4841163953Srrs		sin_a = (struct sockaddr_in *)&net->ro._l_addr;
4842163953Srrs		if (sin_a->sin_family == AF_INET) {
4843163953Srrs			fnd = 1;
4844163953Srrs			sin->sin_port = stcb->rport;
4845163953Srrs			sin->sin_addr = sin_a->sin_addr;
4846163953Srrs			break;
4847163953Srrs		}
4848163953Srrs	}
4849163953Srrs	SCTP_TCB_UNLOCK(stcb);
4850163953Srrs	if (!fnd) {
4851163953Srrs		/* No IPv4 address */
4852163953Srrs		splx(s);
4853163953Srrs		SCTP_FREE_SONAME(sin);
4854163953Srrs		return ENOENT;
4855163953Srrs	}
4856163953Srrs	splx(s);
4857163953Srrs	(*addr) = (struct sockaddr *)sin;
4858163953Srrs	return (0);
4859163953Srrs}
4860163953Srrs
4861163953Srrsstruct pr_usrreqs sctp_usrreqs = {
4862163953Srrs	.pru_abort = sctp_abort,
4863163953Srrs	.pru_accept = sctp_accept,
4864163953Srrs	.pru_attach = sctp_attach,
4865163953Srrs	.pru_bind = sctp_bind,
4866163953Srrs	.pru_connect = sctp_connect,
4867163953Srrs	.pru_control = in_control,
4868163953Srrs	.pru_close = sctp_close,
4869163953Srrs	.pru_detach = sctp_close,
4870163953Srrs	.pru_sopoll = sopoll_generic,
4871163953Srrs	.pru_disconnect = sctp_disconnect,
4872163953Srrs	.pru_listen = sctp_listen,
4873163953Srrs	.pru_peeraddr = sctp_peeraddr,
4874163953Srrs	.pru_send = sctp_sendm,
4875163953Srrs	.pru_shutdown = sctp_shutdown,
4876163953Srrs	.pru_sockaddr = sctp_ingetaddr,
4877163953Srrs	.pru_sosend = sctp_sosend,
4878163953Srrs	.pru_soreceive = sctp_soreceive
4879163953Srrs};
4880