sctp_usrreq.c revision 277807
1163953Srrs/*-
2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5163953Srrs *
6163953Srrs * Redistribution and use in source and binary forms, with or without
7163953Srrs * modification, are permitted provided that the following conditions are met:
8163953Srrs *
9163953Srrs * a) Redistributions of source code must retain the above copyright notice,
10228653Stuexen *    this list of conditions and the following disclaimer.
11163953Srrs *
12163953Srrs * b) Redistributions in binary form must reproduce the above copyright
13163953Srrs *    notice, this list of conditions and the following disclaimer in
14228653Stuexen *    the documentation and/or other materials provided with the distribution.
15163953Srrs *
16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
17163953Srrs *    contributors may be used to endorse or promote products derived
18163953Srrs *    from this software without specific prior written permission.
19163953Srrs *
20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
31163953Srrs */
32163953Srrs
33163953Srrs#include <sys/cdefs.h>
34163953Srrs__FBSDID("$FreeBSD: stable/10/sys/netinet/sctp_usrreq.c 277807 2015-01-27 19:36:08Z delphij $");
35235828Stuexen
36166086Srrs#include <netinet/sctp_os.h>
37163953Srrs#include <sys/proc.h>
38163953Srrs#include <netinet/sctp_pcb.h>
39163953Srrs#include <netinet/sctp_header.h>
40163953Srrs#include <netinet/sctp_var.h>
41238475Stuexen#ifdef INET6
42167695Srrs#endif
43167598Srrs#include <netinet/sctp_sysctl.h>
44163953Srrs#include <netinet/sctp_output.h>
45163953Srrs#include <netinet/sctp_uio.h>
46163953Srrs#include <netinet/sctp_asconf.h>
47163953Srrs#include <netinet/sctputil.h>
48163953Srrs#include <netinet/sctp_indata.h>
49163953Srrs#include <netinet/sctp_timer.h>
50163953Srrs#include <netinet/sctp_auth.h>
51170091Srrs#include <netinet/sctp_bsd_addr.h>
52185694Srrs#include <netinet/udp.h>
53164085Srrs
54163953Srrs
55163953Srrs
56217611Stuexenextern struct sctp_cc_functions sctp_cc_functions[];
57217760Stuexenextern struct sctp_ss_functions sctp_ss_functions[];
58170091Srrs
59163953Srrsvoid
60163953Srrssctp_init(void)
61163953Srrs{
62163953Srrs	u_long sb_max_adj;
63163953Srrs
64179783Srrs	/* Initialize and modify the sysctled variables */
65179783Srrs	sctp_init_sysctls();
66163953Srrs	if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
67179783Srrs		SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8);
68163953Srrs	/*
69163953Srrs	 * Allow a user to take no more than 1/2 the number of clusters or
70163953Srrs	 * the SB_MAX whichever is smaller for the send window.
71163953Srrs	 */
72163953Srrs	sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
73179783Srrs	SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj,
74170056Srrs	    (((uint32_t) nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
75163953Srrs	/*
76163953Srrs	 * Now for the recv window, should we take the same amount? or
77163953Srrs	 * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
78163953Srrs	 * now I will just copy.
79163953Srrs	 */
80179783Srrs	SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace);
81179783Srrs	SCTP_BASE_VAR(first_time) = 0;
82179783Srrs	SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
83179783Srrs	sctp_pcb_init();
84179783Srrs#if defined(SCTP_PACKET_LOGGING)
85179783Srrs	SCTP_BASE_VAR(packet_log_writers) = 0;
86179783Srrs	SCTP_BASE_VAR(packet_log_end) = 0;
87179783Srrs	bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE);
88179783Srrs#endif
89163953Srrs}
90163953Srrs
91179783Srrsvoid
92179783Srrssctp_finish(void)
93179783Srrs{
94179783Srrs	sctp_pcb_finish();
95179783Srrs}
96163953Srrs
97166023Srrs
98163953Srrs
99179157Srrsvoid
100228653Stuexensctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
101163953Srrs{
102163953Srrs	struct sctp_tmit_chunk *chk;
103197257Stuexen	uint16_t overhead;
104163953Srrs
105163953Srrs	/* Adjust that too */
106163953Srrs	stcb->asoc.smallest_mtu = nxtsz;
107163953Srrs	/* now off to subtract IP_DF flag if needed */
108197257Stuexen	overhead = IP_HDR_SIZE;
109197257Stuexen	if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
110197257Stuexen		overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id);
111197257Stuexen	}
112163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
113197257Stuexen		if ((chk->send_size + overhead) > nxtsz) {
114163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
115163953Srrs		}
116163953Srrs	}
117163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
118197257Stuexen		if ((chk->send_size + overhead) > nxtsz) {
119163953Srrs			/*
120163953Srrs			 * For this guy we also mark for immediate resend
121163953Srrs			 * since we sent to big of chunk
122163953Srrs			 */
123163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
124190689Srrs			if (chk->sent < SCTP_DATAGRAM_RESEND) {
125190689Srrs				sctp_flight_size_decrease(chk);
126190689Srrs				sctp_total_flight_decrease(stcb, chk);
127190689Srrs			}
128163953Srrs			if (chk->sent != SCTP_DATAGRAM_RESEND) {
129163953Srrs				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
130163953Srrs			}
131163953Srrs			chk->sent = SCTP_DATAGRAM_RESEND;
132163953Srrs			chk->rec.data.doing_fast_retransmit = 0;
133179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
134170744Srrs				sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
135170744Srrs				    chk->whoTo->flight_size,
136170744Srrs				    chk->book_size,
137170744Srrs				    (uintptr_t) chk->whoTo,
138170744Srrs				    chk->rec.data.TSN_seq);
139170744Srrs			}
140163953Srrs			/* Clear any time so NO RTT is being done */
141163953Srrs			chk->do_rtt = 0;
142163953Srrs		}
143163953Srrs	}
144163953Srrs}
145163953Srrs
146221249Stuexen#ifdef INET
147163953Srrsstatic void
148163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp,
149163953Srrs    struct sctp_tcb *stcb,
150163953Srrs    struct sctp_nets *net,
151163953Srrs    struct ip *ip,
152163953Srrs    struct sctphdr *sh)
153163953Srrs{
154163953Srrs	struct icmp *icmph;
155163953Srrs	int totsz, tmr_stopped = 0;
156163953Srrs	uint16_t nxtsz;
157163953Srrs
158163953Srrs	/* protection */
159163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
160163953Srrs	    (ip == NULL) || (sh == NULL)) {
161169420Srrs		if (stcb != NULL) {
162163953Srrs			SCTP_TCB_UNLOCK(stcb);
163169420Srrs		}
164163953Srrs		return;
165163953Srrs	}
166163953Srrs	/* First job is to verify the vtag matches what I would send */
167163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
168163953Srrs		SCTP_TCB_UNLOCK(stcb);
169163953Srrs		return;
170163953Srrs	}
171163953Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
172163953Srrs	    sizeof(struct ip)));
173163953Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
174163953Srrs		/* We only care about unreachable */
175163953Srrs		SCTP_TCB_UNLOCK(stcb);
176163953Srrs		return;
177163953Srrs	}
178163953Srrs	if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
179163953Srrs		/* not a unreachable message due to frag. */
180163953Srrs		SCTP_TCB_UNLOCK(stcb);
181163953Srrs		return;
182163953Srrs	}
183241913Sglebius	totsz = ntohs(ip->ip_len);
184163953Srrs
185171943Srrs	nxtsz = ntohs(icmph->icmp_nextmtu);
186163953Srrs	if (nxtsz == 0) {
187163953Srrs		/*
188163953Srrs		 * old type router that does not tell us what the next size
189163953Srrs		 * mtu is. Rats we will have to guess (in a educated fashion
190163953Srrs		 * of course)
191163953Srrs		 */
192214939Stuexen		nxtsz = sctp_get_prev_mtu(totsz);
193163953Srrs	}
194163953Srrs	/* Stop any PMTU timer */
195165647Srrs	if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
196163953Srrs		tmr_stopped = 1;
197165220Srrs		sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
198165220Srrs		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
199163953Srrs	}
200163953Srrs	/* Adjust destination size limit */
201163953Srrs	if (net->mtu > nxtsz) {
202163953Srrs		net->mtu = nxtsz;
203185694Srrs		if (net->port) {
204185694Srrs			net->mtu -= sizeof(struct udphdr);
205185694Srrs		}
206163953Srrs	}
207163953Srrs	/* now what about the ep? */
208163953Srrs	if (stcb->asoc.smallest_mtu > nxtsz) {
209228653Stuexen		sctp_pathmtu_adjustment(stcb, nxtsz);
210163953Srrs	}
211163953Srrs	if (tmr_stopped)
212163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
213163953Srrs
214163953Srrs	SCTP_TCB_UNLOCK(stcb);
215163953Srrs}
216163953Srrs
217163953Srrsvoid
218163953Srrssctp_notify(struct sctp_inpcb *inp,
219172091Srrs    struct ip *ip,
220163953Srrs    struct sctphdr *sh,
221163953Srrs    struct sockaddr *to,
222163953Srrs    struct sctp_tcb *stcb,
223163953Srrs    struct sctp_nets *net)
224163953Srrs{
225237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
226172090Srrs	struct socket *so;
227172090Srrs
228172090Srrs#endif
229172091Srrs	struct icmp *icmph;
230172091Srrs
231235360Stuexen	/* protection */
232163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
233163953Srrs	    (sh == NULL) || (to == NULL)) {
234172091Srrs		if (stcb)
235172091Srrs			SCTP_TCB_UNLOCK(stcb);
236163953Srrs		return;
237163953Srrs	}
238163953Srrs	/* First job is to verify the vtag matches what I would send */
239163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
240172091Srrs		SCTP_TCB_UNLOCK(stcb);
241163953Srrs		return;
242163953Srrs	}
243172091Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
244172091Srrs	    sizeof(struct ip)));
245172091Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
246172091Srrs		/* We only care about unreachable */
247172091Srrs		SCTP_TCB_UNLOCK(stcb);
248172091Srrs		return;
249172091Srrs	}
250172091Srrs	if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
251172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST) ||
252172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
253172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
254172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
255172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
256172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
257172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
258163953Srrs
259163953Srrs		/*
260163953Srrs		 * Hmm reachablity problems we must examine closely. If its
261163953Srrs		 * not reachable, we may have lost a network. Or if there is
262163953Srrs		 * NO protocol at the other end named SCTP. well we consider
263163953Srrs		 * it a OOTB abort.
264163953Srrs		 */
265172091Srrs		if (net->dest_state & SCTP_ADDR_REACHABLE) {
266172091Srrs			/* Ok that destination is NOT reachable */
267172091Srrs			net->dest_state &= ~SCTP_ADDR_REACHABLE;
268224641Stuexen			net->dest_state &= ~SCTP_ADDR_PF;
269172091Srrs			sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
270235414Stuexen			    stcb, 0,
271172091Srrs			    (void *)net, SCTP_SO_NOT_LOCKED);
272172091Srrs		}
273172091Srrs		SCTP_TCB_UNLOCK(stcb);
274172091Srrs	} else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
275172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_PORT)) {
276172091Srrs		/*
277172091Srrs		 * Here the peer is either playing tricks on us, including
278172091Srrs		 * an address that belongs to someone who does not support
279172091Srrs		 * SCTP OR was a userland implementation that shutdown and
280172091Srrs		 * now is dead. In either case treat it like a OOTB abort
281172091Srrs		 * with no TCB
282172091Srrs		 */
283235403Stuexen		sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
284237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
285172091Srrs		so = SCTP_INP_SO(inp);
286172091Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
287172091Srrs		SCTP_TCB_UNLOCK(stcb);
288172091Srrs		SCTP_SOCKET_LOCK(so, 1);
289172091Srrs		SCTP_TCB_LOCK(stcb);
290172091Srrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
291172090Srrs#endif
292172091Srrs		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
293237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
294172091Srrs		SCTP_SOCKET_UNLOCK(so, 1);
295172091Srrs		/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
296172090Srrs#endif
297172091Srrs		/* no need to unlock here, since the TCB is gone */
298163953Srrs	} else {
299172091Srrs		SCTP_TCB_UNLOCK(stcb);
300163953Srrs	}
301163953Srrs}
302163953Srrs
303270350Stuexen#endif
304270350Stuexen
305221249Stuexen#ifdef INET
306163953Srrsvoid
307163953Srrssctp_ctlinput(cmd, sa, vip)
308163953Srrs	int cmd;
309163953Srrs	struct sockaddr *sa;
310163953Srrs	void *vip;
311163953Srrs{
312163953Srrs	struct ip *ip = vip;
313163953Srrs	struct sctphdr *sh;
314167598Srrs	uint32_t vrf_id;
315163953Srrs
316168299Srrs	/* FIX, for non-bsd is this right? */
317167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
318163953Srrs	if (sa->sa_family != AF_INET ||
319163953Srrs	    ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
320163953Srrs		return;
321163953Srrs	}
322163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
323163953Srrs		ip = 0;
324163953Srrs	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
325163953Srrs		return;
326163953Srrs	}
327163953Srrs	if (ip) {
328163953Srrs		struct sctp_inpcb *inp = NULL;
329163953Srrs		struct sctp_tcb *stcb = NULL;
330163953Srrs		struct sctp_nets *net = NULL;
331163953Srrs		struct sockaddr_in to, from;
332163953Srrs
333163953Srrs		sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
334163953Srrs		bzero(&to, sizeof(to));
335163953Srrs		bzero(&from, sizeof(from));
336163953Srrs		from.sin_family = to.sin_family = AF_INET;
337163953Srrs		from.sin_len = to.sin_len = sizeof(to);
338163953Srrs		from.sin_port = sh->src_port;
339163953Srrs		from.sin_addr = ip->ip_src;
340163953Srrs		to.sin_port = sh->dest_port;
341163953Srrs		to.sin_addr = ip->ip_dst;
342163953Srrs
343163953Srrs		/*
344163953Srrs		 * 'to' holds the dest of the packet that failed to be sent.
345163953Srrs		 * 'from' holds our local endpoint address. Thus we reverse
346163953Srrs		 * the to and the from in the lookup.
347163953Srrs		 */
348237715Stuexen		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to,
349237715Stuexen		    (struct sockaddr *)&from,
350167598Srrs		    &inp, &net, 1, vrf_id);
351163953Srrs		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
352163953Srrs			if (cmd != PRC_MSGSIZE) {
353172091Srrs				sctp_notify(inp, ip, sh,
354163953Srrs				    (struct sockaddr *)&to, stcb,
355163953Srrs				    net);
356163953Srrs			} else {
357163953Srrs				/* handle possible ICMP size messages */
358163953Srrs				sctp_notify_mbuf(inp, stcb, net, ip, sh);
359163953Srrs			}
360163953Srrs		} else {
361163953Srrs			if ((stcb == NULL) && (inp != NULL)) {
362163953Srrs				/* reduce ref-count */
363163953Srrs				SCTP_INP_WLOCK(inp);
364163953Srrs				SCTP_INP_DECR_REF(inp);
365163953Srrs				SCTP_INP_WUNLOCK(inp);
366163953Srrs			}
367209029Srrs			if (stcb) {
368209029Srrs				SCTP_TCB_UNLOCK(stcb);
369209029Srrs			}
370163953Srrs		}
371163953Srrs	}
372163953Srrs	return;
373163953Srrs}
374163953Srrs
375221249Stuexen#endif
376221249Stuexen
377163953Srrsstatic int
378163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS)
379163953Srrs{
380164085Srrs	struct xucred xuc;
381163953Srrs	struct sockaddr_in addrs[2];
382163953Srrs	struct sctp_inpcb *inp;
383163953Srrs	struct sctp_nets *net;
384163953Srrs	struct sctp_tcb *stcb;
385164085Srrs	int error;
386167598Srrs	uint32_t vrf_id;
387163953Srrs
388168299Srrs	/* FIX, for non-bsd is this right? */
389167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
390168299Srrs
391170587Srwatson	error = priv_check(req->td, PRIV_NETINET_GETCRED);
392170587Srwatson
393163953Srrs	if (error)
394163953Srrs		return (error);
395164039Srwatson
396163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
397163953Srrs	if (error)
398163953Srrs		return (error);
399163953Srrs
400237715Stuexen	stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]),
401237715Stuexen	    sintosa(&addrs[0]),
402167598Srrs	    &inp, &net, 1, vrf_id);
403163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
404163953Srrs		if ((inp != NULL) && (stcb == NULL)) {
405163953Srrs			/* reduce ref-count */
406163953Srrs			SCTP_INP_WLOCK(inp);
407163953Srrs			SCTP_INP_DECR_REF(inp);
408164085Srrs			goto cred_can_cont;
409163953Srrs		}
410171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
411163953Srrs		error = ENOENT;
412163953Srrs		goto out;
413163953Srrs	}
414163953Srrs	SCTP_TCB_UNLOCK(stcb);
415164085Srrs	/*
416164085Srrs	 * We use the write lock here, only since in the error leg we need
417164085Srrs	 * it. If we used RLOCK, then we would have to
418164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
419164085Srrs	 * Better to use higher wlock.
420164085Srrs	 */
421164085Srrs	SCTP_INP_WLOCK(inp);
422164085Srrscred_can_cont:
423164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
424164085Srrs	if (error) {
425164085Srrs		SCTP_INP_WUNLOCK(inp);
426164085Srrs		goto out;
427164085Srrs	}
428164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
429164085Srrs	SCTP_INP_WUNLOCK(inp);
430164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
431163953Srrsout:
432163953Srrs	return (error);
433163953Srrs}
434163953Srrs
435163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
436163953Srrs    0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
437163953Srrs
438163953Srrs
439221249Stuexen#ifdef INET
440163953Srrsstatic void
441163953Srrssctp_abort(struct socket *so)
442163953Srrs{
443163953Srrs	struct sctp_inpcb *inp;
444163953Srrs	uint32_t flags;
445163953Srrs
446163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
447233005Stuexen	if (inp == NULL) {
448163953Srrs		return;
449171943Srrs	}
450163953Srrssctp_must_try_again:
451163953Srrs	flags = inp->sctp_flags;
452163953Srrs#ifdef SCTP_LOG_CLOSING
453163953Srrs	sctp_log_closing(inp, NULL, 17);
454163953Srrs#endif
455163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
456163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
457163953Srrs#ifdef SCTP_LOG_CLOSING
458163953Srrs		sctp_log_closing(inp, NULL, 16);
459163953Srrs#endif
460169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
461169380Srrs		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
462163953Srrs		SOCK_LOCK(so);
463167695Srrs		SCTP_SB_CLEAR(so->so_snd);
464163953Srrs		/*
465163953Srrs		 * same for the rcv ones, they are only here for the
466163953Srrs		 * accounting/select.
467163953Srrs		 */
468167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
469167695Srrs
470167695Srrs		/* Now null out the reference, we are completely detached. */
471163953Srrs		so->so_pcb = NULL;
472163953Srrs		SOCK_UNLOCK(so);
473163953Srrs	} else {
474163953Srrs		flags = inp->sctp_flags;
475163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
476163953Srrs			goto sctp_must_try_again;
477163953Srrs		}
478163953Srrs	}
479163953Srrs	return;
480163953Srrs}
481163953Srrs
482163953Srrsstatic int
483228653Stuexensctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
484163953Srrs{
485163953Srrs	struct sctp_inpcb *inp;
486163953Srrs	struct inpcb *ip_inp;
487166086Srrs	int error;
488170205Srrs	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
489185694Srrs
490171167Sgnn#ifdef IPSEC
491163953Srrs	uint32_t flags;
492185694Srrs
493185435Sbz#endif
494171440Srrs
495163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
496163953Srrs	if (inp != 0) {
497171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
498228907Stuexen		return (EINVAL);
499163953Srrs	}
500184030Srrs	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
501184030Srrs		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
502184030Srrs		if (error) {
503228907Stuexen			return (error);
504184030Srrs		}
505163953Srrs	}
506170205Srrs	error = sctp_inpcb_alloc(so, vrf_id);
507163953Srrs	if (error) {
508228907Stuexen		return (error);
509163953Srrs	}
510163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
511163953Srrs	SCTP_INP_WLOCK(inp);
512163953Srrs	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;	/* I'm not v6! */
513163953Srrs	ip_inp = &inp->ip_inp.inp;
514163953Srrs	ip_inp->inp_vflag |= INP_IPV4;
515197288Srrs	ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
516171167Sgnn#ifdef IPSEC
517171133Sgnn	error = ipsec_init_policy(so, &ip_inp->inp_sp);
518163953Srrs#ifdef SCTP_LOG_CLOSING
519163953Srrs	sctp_log_closing(inp, NULL, 17);
520163953Srrs#endif
521163953Srrs	if (error != 0) {
522202523Srrstry_again:
523163953Srrs		flags = inp->sctp_flags;
524163953Srrs		if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
525163953Srrs		    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
526163953Srrs#ifdef SCTP_LOG_CLOSING
527163953Srrs			sctp_log_closing(inp, NULL, 15);
528163953Srrs#endif
529169352Srrs			SCTP_INP_WUNLOCK(inp);
530169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
531169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
532169254Srrs		} else {
533202523Srrs			flags = inp->sctp_flags;
534202523Srrs			if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
535202523Srrs				goto try_again;
536202523Srrs			} else {
537202523Srrs				SCTP_INP_WUNLOCK(inp);
538202523Srrs			}
539163953Srrs		}
540228907Stuexen		return (error);
541163953Srrs	}
542171167Sgnn#endif				/* IPSEC */
543163953Srrs	SCTP_INP_WUNLOCK(inp);
544228907Stuexen	return (0);
545163953Srrs}
546163953Srrs
547163953Srrsstatic int
548163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
549163953Srrs{
550244730Stuexen	struct sctp_inpcb *inp;
551163953Srrs
552163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
553233005Stuexen	if (inp == NULL) {
554171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
555228907Stuexen		return (EINVAL);
556171943Srrs	}
557244730Stuexen	if (addr != NULL) {
558244730Stuexen		if ((addr->sa_family != AF_INET) ||
559244730Stuexen		    (addr->sa_len != sizeof(struct sockaddr_in))) {
560244730Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
561244730Stuexen			return (EINVAL);
562244730Stuexen		}
563244730Stuexen	}
564244730Stuexen	return (sctp_inpcb_bind(so, addr, NULL, p));
565163953Srrs}
566163953Srrs
567221249Stuexen#endif
568171990Srrsvoid
569163953Srrssctp_close(struct socket *so)
570163953Srrs{
571163953Srrs	struct sctp_inpcb *inp;
572163953Srrs	uint32_t flags;
573163953Srrs
574163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
575233005Stuexen	if (inp == NULL)
576163953Srrs		return;
577163953Srrs
578163953Srrs	/*
579163953Srrs	 * Inform all the lower layer assoc that we are done.
580163953Srrs	 */
581163953Srrssctp_must_try_again:
582163953Srrs	flags = inp->sctp_flags;
583163953Srrs#ifdef SCTP_LOG_CLOSING
584163953Srrs	sctp_log_closing(inp, NULL, 17);
585163953Srrs#endif
586163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
587163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
588163953Srrs		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
589163953Srrs		    (so->so_rcv.sb_cc > 0)) {
590163953Srrs#ifdef SCTP_LOG_CLOSING
591163953Srrs			sctp_log_closing(inp, NULL, 13);
592163953Srrs#endif
593169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
594169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
595163953Srrs		} else {
596163953Srrs#ifdef SCTP_LOG_CLOSING
597163953Srrs			sctp_log_closing(inp, NULL, 14);
598163953Srrs#endif
599169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
600169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
601163953Srrs		}
602163953Srrs		/*
603163953Srrs		 * The socket is now detached, no matter what the state of
604163953Srrs		 * the SCTP association.
605163953Srrs		 */
606163953Srrs		SOCK_LOCK(so);
607167695Srrs		SCTP_SB_CLEAR(so->so_snd);
608163953Srrs		/*
609163953Srrs		 * same for the rcv ones, they are only here for the
610163953Srrs		 * accounting/select.
611163953Srrs		 */
612167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
613167695Srrs
614167695Srrs		/* Now null out the reference, we are completely detached. */
615163953Srrs		so->so_pcb = NULL;
616163953Srrs		SOCK_UNLOCK(so);
617163953Srrs	} else {
618163953Srrs		flags = inp->sctp_flags;
619163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
620163953Srrs			goto sctp_must_try_again;
621163953Srrs		}
622163953Srrs	}
623163953Srrs	return;
624163953Srrs}
625163953Srrs
626163953Srrs
627163953Srrsint
628163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
629163953Srrs    struct mbuf *control, struct thread *p);
630163953Srrs
631163953Srrs
632163953Srrsint
633163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
634163953Srrs    struct mbuf *control, struct thread *p)
635163953Srrs{
636163953Srrs	struct sctp_inpcb *inp;
637163953Srrs	int error;
638163953Srrs
639163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
640233005Stuexen	if (inp == NULL) {
641163953Srrs		if (control) {
642163953Srrs			sctp_m_freem(control);
643163953Srrs			control = NULL;
644163953Srrs		}
645171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
646163953Srrs		sctp_m_freem(m);
647228907Stuexen		return (EINVAL);
648163953Srrs	}
649163953Srrs	/* Got to have an to address if we are NOT a connected socket */
650163953Srrs	if ((addr == NULL) &&
651163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
652228907Stuexen	    (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) {
653163953Srrs		goto connected_type;
654163953Srrs	} else if (addr == NULL) {
655171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
656163953Srrs		error = EDESTADDRREQ;
657163953Srrs		sctp_m_freem(m);
658163953Srrs		if (control) {
659163953Srrs			sctp_m_freem(control);
660163953Srrs			control = NULL;
661163953Srrs		}
662163953Srrs		return (error);
663163953Srrs	}
664163953Srrs#ifdef INET6
665163953Srrs	if (addr->sa_family != AF_INET) {
666163953Srrs		/* must be a v4 address! */
667171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
668163953Srrs		sctp_m_freem(m);
669163953Srrs		if (control) {
670163953Srrs			sctp_m_freem(control);
671163953Srrs			control = NULL;
672163953Srrs		}
673163953Srrs		error = EDESTADDRREQ;
674223132Stuexen		return (error);
675163953Srrs	}
676163953Srrs#endif				/* INET6 */
677163953Srrsconnected_type:
678163953Srrs	/* now what about control */
679163953Srrs	if (control) {
680163953Srrs		if (inp->control) {
681169420Srrs			SCTP_PRINTF("huh? control set?\n");
682163953Srrs			sctp_m_freem(inp->control);
683163953Srrs			inp->control = NULL;
684163953Srrs		}
685163953Srrs		inp->control = control;
686163953Srrs	}
687163953Srrs	/* Place the data */
688163953Srrs	if (inp->pkt) {
689165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
690163953Srrs		inp->pkt_last = m;
691163953Srrs	} else {
692163953Srrs		inp->pkt_last = inp->pkt = m;
693163953Srrs	}
694163953Srrs	if (
695163953Srrs	/* FreeBSD uses a flag passed */
696163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
697163953Srrs	    ) {
698163953Srrs		/*
699163953Srrs		 * note with the current version this code will only be used
700163953Srrs		 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
701163953Srrs		 * re-defining sosend to use the sctp_sosend. One can
702163953Srrs		 * optionally switch back to this code (by changing back the
703163953Srrs		 * definitions) but this is not advisable. This code is used
704163953Srrs		 * by FreeBSD when sending a file with sendfile() though.
705163953Srrs		 */
706163953Srrs		int ret;
707163953Srrs
708163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
709163953Srrs		inp->pkt = NULL;
710163953Srrs		inp->control = NULL;
711163953Srrs		return (ret);
712163953Srrs	} else {
713163953Srrs		return (0);
714163953Srrs	}
715163953Srrs}
716163953Srrs
717171990Srrsint
718163953Srrssctp_disconnect(struct socket *so)
719163953Srrs{
720163953Srrs	struct sctp_inpcb *inp;
721163953Srrs
722163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
723163953Srrs	if (inp == NULL) {
724171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
725163953Srrs		return (ENOTCONN);
726163953Srrs	}
727163953Srrs	SCTP_INP_RLOCK(inp);
728171745Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
729171745Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
730199437Stuexen		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
731163953Srrs			/* No connection */
732163953Srrs			SCTP_INP_RUNLOCK(inp);
733163953Srrs			return (0);
734163953Srrs		} else {
735163953Srrs			struct sctp_association *asoc;
736163953Srrs			struct sctp_tcb *stcb;
737163953Srrs
738163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
739163953Srrs			if (stcb == NULL) {
740163953Srrs				SCTP_INP_RUNLOCK(inp);
741171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
742163953Srrs				return (EINVAL);
743163953Srrs			}
744163953Srrs			SCTP_TCB_LOCK(stcb);
745163953Srrs			asoc = &stcb->asoc;
746163953Srrs			if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
747163953Srrs				/* We are about to be freed, out of here */
748163953Srrs				SCTP_TCB_UNLOCK(stcb);
749163953Srrs				SCTP_INP_RUNLOCK(inp);
750163953Srrs				return (0);
751163953Srrs			}
752163953Srrs			if (((so->so_options & SO_LINGER) &&
753163953Srrs			    (so->so_linger == 0)) ||
754163953Srrs			    (so->so_rcv.sb_cc > 0)) {
755163953Srrs				if (SCTP_GET_STATE(asoc) !=
756163953Srrs				    SCTP_STATE_COOKIE_WAIT) {
757163953Srrs					/* Left with Data unread */
758163953Srrs					struct mbuf *err;
759163953Srrs
760243882Sglebius					err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
761163953Srrs					if (err) {
762163953Srrs						/*
763163953Srrs						 * Fill in the user
764163953Srrs						 * initiated abort
765163953Srrs						 */
766163953Srrs						struct sctp_paramhdr *ph;
767163953Srrs
768163953Srrs						ph = mtod(err, struct sctp_paramhdr *);
769165647Srrs						SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr);
770163953Srrs						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
771165647Srrs						ph->param_length = htons(SCTP_BUF_LEN(err));
772163953Srrs					}
773172090Srrs					sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
774163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
775163953Srrs				}
776163953Srrs				SCTP_INP_RUNLOCK(inp);
777163953Srrs				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
778163953Srrs				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
779163953Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
780163953Srrs				}
781171943Srrs				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
782163953Srrs				/* No unlock tcb assoc is gone */
783163953Srrs				return (0);
784163953Srrs			}
785163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
786163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
787163953Srrs			    (asoc->stream_queue_cnt == 0)) {
788163953Srrs				/* there is nothing queued to send, so done */
789163953Srrs				if (asoc->locked_on_sending) {
790163953Srrs					goto abort_anyway;
791163953Srrs				}
792166675Srrs				if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
793166675Srrs				    (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
794163953Srrs					/* only send SHUTDOWN 1st time thru */
795224641Stuexen					struct sctp_nets *netp;
796224641Stuexen
797246588Stuexen					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
798246588Stuexen					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
799246588Stuexen						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
800246588Stuexen					}
801246588Stuexen					SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
802246588Stuexen					SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
803246588Stuexen					sctp_stop_timers_for_shutdown(stcb);
804224641Stuexen					if (stcb->asoc.alternate) {
805224641Stuexen						netp = stcb->asoc.alternate;
806224641Stuexen					} else {
807224641Stuexen						netp = stcb->asoc.primary_destination;
808224641Stuexen					}
809224641Stuexen					sctp_send_shutdown(stcb, netp);
810163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
811224641Stuexen					    stcb->sctp_ep, stcb, netp);
812163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
813224641Stuexen					    stcb->sctp_ep, stcb, netp);
814246588Stuexen					sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
815163953Srrs				}
816163953Srrs			} else {
817163953Srrs				/*
818163953Srrs				 * we still got (or just got) data to send,
819163953Srrs				 * so set SHUTDOWN_PENDING
820163953Srrs				 */
821163953Srrs				/*
822163953Srrs				 * XXX sockets draft says that SCTP_EOF
823163953Srrs				 * should be sent with no data. currently,
824163953Srrs				 * we will allow user data to be sent first
825163953Srrs				 * and move to SHUTDOWN-PENDING
826163953Srrs				 */
827224641Stuexen				struct sctp_nets *netp;
828224641Stuexen
829224641Stuexen				if (stcb->asoc.alternate) {
830224641Stuexen					netp = stcb->asoc.alternate;
831224641Stuexen				} else {
832224641Stuexen					netp = stcb->asoc.primary_destination;
833224641Stuexen				}
834224641Stuexen
835163953Srrs				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
836163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
837224641Stuexen				    netp);
838163953Srrs				if (asoc->locked_on_sending) {
839163953Srrs					/* Locked to send out the data */
840163953Srrs					struct sctp_stream_queue_pending *sp;
841163953Srrs
842163953Srrs					sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
843163953Srrs					if (sp == NULL) {
844169420Srrs						SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
845163953Srrs						    asoc->locked_on_sending->stream_no);
846163953Srrs					} else {
847163953Srrs						if ((sp->length == 0) && (sp->msg_is_complete == 0))
848163953Srrs							asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
849163953Srrs					}
850163953Srrs				}
851163953Srrs				if (TAILQ_EMPTY(&asoc->send_queue) &&
852163953Srrs				    TAILQ_EMPTY(&asoc->sent_queue) &&
853163953Srrs				    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
854163953Srrs					struct mbuf *op_err;
855163953Srrs
856163953Srrs			abort_anyway:
857267723Stuexen					op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
858165220Srrs					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
859172090Srrs					sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
860163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
861163953Srrs					if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
862163953Srrs					    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
863163953Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
864163953Srrs					}
865163953Srrs					SCTP_INP_RUNLOCK(inp);
866171943Srrs					(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
867163953Srrs					return (0);
868171990Srrs				} else {
869172090Srrs					sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
870163953Srrs				}
871163953Srrs			}
872188067Srrs			soisdisconnecting(so);
873163953Srrs			SCTP_TCB_UNLOCK(stcb);
874163953Srrs			SCTP_INP_RUNLOCK(inp);
875163953Srrs			return (0);
876163953Srrs		}
877163953Srrs		/* not reached */
878163953Srrs	} else {
879163953Srrs		/* UDP model does not support this */
880163953Srrs		SCTP_INP_RUNLOCK(inp);
881171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
882228907Stuexen		return (EOPNOTSUPP);
883163953Srrs	}
884163953Srrs}
885163953Srrs
886163953Srrsint
887178202Srrssctp_flush(struct socket *so, int how)
888178202Srrs{
889178202Srrs	/*
890178202Srrs	 * We will just clear out the values and let subsequent close clear
891178202Srrs	 * out the data, if any. Note if the user did a shutdown(SHUT_RD)
892178202Srrs	 * they will not be able to read the data, the socket will block
893178202Srrs	 * that from happening.
894178202Srrs	 */
895209289Stuexen	struct sctp_inpcb *inp;
896209289Stuexen
897209289Stuexen	inp = (struct sctp_inpcb *)so->so_pcb;
898209289Stuexen	if (inp == NULL) {
899209289Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
900228907Stuexen		return (EINVAL);
901209289Stuexen	}
902209289Stuexen	SCTP_INP_RLOCK(inp);
903209289Stuexen	/* For the 1 to many model this does nothing */
904209289Stuexen	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
905209289Stuexen		SCTP_INP_RUNLOCK(inp);
906209289Stuexen		return (0);
907209289Stuexen	}
908209289Stuexen	SCTP_INP_RUNLOCK(inp);
909178202Srrs	if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
910178202Srrs		/*
911178202Srrs		 * First make sure the sb will be happy, we don't use these
912178202Srrs		 * except maybe the count
913178202Srrs		 */
914209289Stuexen		SCTP_INP_WLOCK(inp);
915209289Stuexen		SCTP_INP_READ_LOCK(inp);
916209289Stuexen		inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
917209289Stuexen		SCTP_INP_READ_UNLOCK(inp);
918209289Stuexen		SCTP_INP_WUNLOCK(inp);
919178202Srrs		so->so_rcv.sb_cc = 0;
920178202Srrs		so->so_rcv.sb_mbcnt = 0;
921178202Srrs		so->so_rcv.sb_mb = NULL;
922178202Srrs	}
923178202Srrs	if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
924178202Srrs		/*
925178202Srrs		 * First make sure the sb will be happy, we don't use these
926178202Srrs		 * except maybe the count
927178202Srrs		 */
928178202Srrs		so->so_snd.sb_cc = 0;
929178202Srrs		so->so_snd.sb_mbcnt = 0;
930178202Srrs		so->so_snd.sb_mb = NULL;
931178202Srrs
932178202Srrs	}
933178202Srrs	return (0);
934178202Srrs}
935178202Srrs
936178202Srrsint
937163953Srrssctp_shutdown(struct socket *so)
938163953Srrs{
939163953Srrs	struct sctp_inpcb *inp;
940163953Srrs
941163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
942233005Stuexen	if (inp == NULL) {
943171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
944228907Stuexen		return (EINVAL);
945163953Srrs	}
946163953Srrs	SCTP_INP_RLOCK(inp);
947163953Srrs	/* For UDP model this is a invalid call */
948243558Stuexen	if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
949243558Stuexen	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
950163953Srrs		/* Restore the flags that the soshutdown took away. */
951204096Stuexen		SOCKBUF_LOCK(&so->so_rcv);
952163953Srrs		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
953204096Stuexen		SOCKBUF_UNLOCK(&so->so_rcv);
954163953Srrs		/* This proc will wakeup for read and do nothing (I hope) */
955163953Srrs		SCTP_INP_RUNLOCK(inp);
956171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
957163953Srrs		return (EOPNOTSUPP);
958163953Srrs	}
959163953Srrs	/*
960163953Srrs	 * Ok if we reach here its the TCP model and it is either a SHUT_WR
961163953Srrs	 * or SHUT_RDWR. This means we put the shutdown flag against it.
962163953Srrs	 */
963163953Srrs	{
964163953Srrs		struct sctp_tcb *stcb;
965163953Srrs		struct sctp_association *asoc;
966163953Srrs
967188067Srrs		if ((so->so_state &
968188067Srrs		    (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
969188067Srrs			SCTP_INP_RUNLOCK(inp);
970188067Srrs			return (ENOTCONN);
971188067Srrs		}
972163953Srrs		socantsendmore(so);
973163953Srrs
974163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
975163953Srrs		if (stcb == NULL) {
976163953Srrs			/*
977163953Srrs			 * Ok we hit the case that the shutdown call was
978163953Srrs			 * made after an abort or something. Nothing to do
979163953Srrs			 * now.
980163953Srrs			 */
981168299Srrs			SCTP_INP_RUNLOCK(inp);
982163953Srrs			return (0);
983163953Srrs		}
984163953Srrs		SCTP_TCB_LOCK(stcb);
985163953Srrs		asoc = &stcb->asoc;
986163953Srrs		if (TAILQ_EMPTY(&asoc->send_queue) &&
987163953Srrs		    TAILQ_EMPTY(&asoc->sent_queue) &&
988163953Srrs		    (asoc->stream_queue_cnt == 0)) {
989163953Srrs			if (asoc->locked_on_sending) {
990163953Srrs				goto abort_anyway;
991163953Srrs			}
992163953Srrs			/* there is nothing queued to send, so I'm done... */
993163953Srrs			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
994163953Srrs				/* only send SHUTDOWN the first time through */
995224641Stuexen				struct sctp_nets *netp;
996224641Stuexen
997246588Stuexen				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
998246588Stuexen				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
999246588Stuexen					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1000246588Stuexen				}
1001246588Stuexen				SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
1002246588Stuexen				SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
1003246588Stuexen				sctp_stop_timers_for_shutdown(stcb);
1004224641Stuexen				if (stcb->asoc.alternate) {
1005224641Stuexen					netp = stcb->asoc.alternate;
1006224641Stuexen				} else {
1007224641Stuexen					netp = stcb->asoc.primary_destination;
1008224641Stuexen				}
1009224641Stuexen				sctp_send_shutdown(stcb, netp);
1010163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1011224641Stuexen				    stcb->sctp_ep, stcb, netp);
1012163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1013224641Stuexen				    stcb->sctp_ep, stcb, netp);
1014246588Stuexen				sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
1015163953Srrs			}
1016163953Srrs		} else {
1017163953Srrs			/*
1018163953Srrs			 * we still got (or just got) data to send, so set
1019163953Srrs			 * SHUTDOWN_PENDING
1020163953Srrs			 */
1021224641Stuexen			struct sctp_nets *netp;
1022224641Stuexen
1023224641Stuexen			if (stcb->asoc.alternate) {
1024224641Stuexen				netp = stcb->asoc.alternate;
1025224641Stuexen			} else {
1026224641Stuexen				netp = stcb->asoc.primary_destination;
1027224641Stuexen			}
1028224641Stuexen
1029163953Srrs			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1030163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
1031224641Stuexen			    netp);
1032163953Srrs
1033163953Srrs			if (asoc->locked_on_sending) {
1034163953Srrs				/* Locked to send out the data */
1035163953Srrs				struct sctp_stream_queue_pending *sp;
1036163953Srrs
1037163953Srrs				sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1038163953Srrs				if (sp == NULL) {
1039169420Srrs					SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1040163953Srrs					    asoc->locked_on_sending->stream_no);
1041163953Srrs				} else {
1042163953Srrs					if ((sp->length == 0) && (sp->msg_is_complete == 0)) {
1043163953Srrs						asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
1044163953Srrs					}
1045163953Srrs				}
1046163953Srrs			}
1047163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
1048163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
1049163953Srrs			    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1050163953Srrs				struct mbuf *op_err;
1051163953Srrs
1052163953Srrs		abort_anyway:
1053267723Stuexen				op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
1054165220Srrs				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
1055163953Srrs				sctp_abort_an_association(stcb->sctp_ep, stcb,
1056172090Srrs				    op_err, SCTP_SO_LOCKED);
1057163953Srrs				goto skip_unlock;
1058171990Srrs			} else {
1059172090Srrs				sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
1060163953Srrs			}
1061163953Srrs		}
1062163953Srrs		SCTP_TCB_UNLOCK(stcb);
1063163953Srrs	}
1064163953Srrsskip_unlock:
1065163953Srrs	SCTP_INP_RUNLOCK(inp);
1066228907Stuexen	return (0);
1067163953Srrs}
1068163953Srrs
1069163953Srrs/*
1070163953Srrs * copies a "user" presentable address and removes embedded scope, etc.
1071163953Srrs * returns 0 on success, 1 on error
1072163953Srrs */
1073163953Srrsstatic uint32_t
1074163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
1075163953Srrs{
1076178251Srrs#ifdef INET6
1077163953Srrs	struct sockaddr_in6 lsa6;
1078163953Srrs
1079163953Srrs	sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
1080163953Srrs	    &lsa6);
1081178251Srrs#endif
1082163953Srrs	memcpy(ss, sa, sa->sa_len);
1083163953Srrs	return (0);
1084163953Srrs}
1085163953Srrs
1086163953Srrs
1087163953Srrs
1088172091Srrs/*
1089172091Srrs * NOTE: assumes addr lock is held
1090172091Srrs */
1091166675Srrsstatic size_t
1092168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
1093163953Srrs    struct sctp_tcb *stcb,
1094166675Srrs    size_t limit,
1095167598Srrs    struct sockaddr_storage *sas,
1096167598Srrs    uint32_t vrf_id)
1097163953Srrs{
1098167598Srrs	struct sctp_ifn *sctp_ifn;
1099167598Srrs	struct sctp_ifa *sctp_ifa;
1100166675Srrs	size_t actual;
1101258454Stuexen	int loopback_scope;
1102258454Stuexen
1103258454Stuexen#if defined(INET)
1104258454Stuexen	int ipv4_local_scope, ipv4_addr_legal;
1105258454Stuexen
1106258454Stuexen#endif
1107258454Stuexen#if defined(INET6)
1108258454Stuexen	int local_scope, site_scope, ipv6_addr_legal;
1109258454Stuexen
1110258454Stuexen#endif
1111167598Srrs	struct sctp_vrf *vrf;
1112163953Srrs
1113163953Srrs	actual = 0;
1114163953Srrs	if (limit <= 0)
1115163953Srrs		return (actual);
1116163953Srrs
1117163953Srrs	if (stcb) {
1118163953Srrs		/* Turn on all the appropriate scope */
1119246595Stuexen		loopback_scope = stcb->asoc.scope.loopback_scope;
1120258454Stuexen#if defined(INET)
1121246595Stuexen		ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
1122258454Stuexen		ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
1123258454Stuexen#endif
1124258454Stuexen#if defined(INET6)
1125246595Stuexen		local_scope = stcb->asoc.scope.local_scope;
1126246595Stuexen		site_scope = stcb->asoc.scope.site_scope;
1127246595Stuexen		ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
1128258454Stuexen#endif
1129163953Srrs	} else {
1130246595Stuexen		/* Use generic values for endpoints. */
1131246595Stuexen		loopback_scope = 1;
1132258454Stuexen#if defined(INET)
1133246595Stuexen		ipv4_local_scope = 1;
1134258454Stuexen#endif
1135258454Stuexen#if defined(INET6)
1136246595Stuexen		local_scope = 1;
1137246595Stuexen		site_scope = 1;
1138258454Stuexen#endif
1139246595Stuexen		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1140258454Stuexen#if defined(INET6)
1141246595Stuexen			ipv6_addr_legal = 1;
1142258454Stuexen#endif
1143258454Stuexen#if defined(INET)
1144246595Stuexen			if (SCTP_IPV6_V6ONLY(inp)) {
1145246595Stuexen				ipv4_addr_legal = 0;
1146246595Stuexen			} else {
1147246595Stuexen				ipv4_addr_legal = 1;
1148246595Stuexen			}
1149258454Stuexen#endif
1150246595Stuexen		} else {
1151258454Stuexen#if defined(INET6)
1152246595Stuexen			ipv6_addr_legal = 0;
1153258454Stuexen#endif
1154258454Stuexen#if defined(INET)
1155163953Srrs			ipv4_addr_legal = 1;
1156258454Stuexen#endif
1157163953Srrs		}
1158163953Srrs	}
1159167598Srrs	vrf = sctp_find_vrf(vrf_id);
1160167598Srrs	if (vrf == NULL) {
1161167598Srrs		return (0);
1162167598Srrs	}
1163163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1164167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1165163953Srrs			if ((loopback_scope == 0) &&
1166167598Srrs			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
1167163953Srrs				/* Skip loopback if loopback_scope not set */
1168163953Srrs				continue;
1169163953Srrs			}
1170167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1171163953Srrs				if (stcb) {
1172163953Srrs					/*
1173163953Srrs					 * For the BOUND-ALL case, the list
1174163953Srrs					 * associated with a TCB is Always
1175163953Srrs					 * considered a reverse list.. i.e.
1176163953Srrs					 * it lists addresses that are NOT
1177163953Srrs					 * part of the association. If this
1178163953Srrs					 * is one of those we must skip it.
1179163953Srrs					 */
1180163953Srrs					if (sctp_is_addr_restricted(stcb,
1181167598Srrs					    sctp_ifa)) {
1182163953Srrs						continue;
1183163953Srrs					}
1184163953Srrs				}
1185178251Srrs				switch (sctp_ifa->address.sa.sa_family) {
1186221249Stuexen#ifdef INET
1187178251Srrs				case AF_INET:
1188178251Srrs					if (ipv4_addr_legal) {
1189178251Srrs						struct sockaddr_in *sin;
1190163953Srrs
1191271746Stuexen						sin = &sctp_ifa->address.sin;
1192178251Srrs						if (sin->sin_addr.s_addr == 0) {
1193178251Srrs							/*
1194178251Srrs							 * we skip
1195178251Srrs							 * unspecifed
1196178251Srrs							 * addresses
1197178251Srrs							 */
1198178251Srrs							continue;
1199178251Srrs						}
1200267769Stuexen						if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
1201267769Stuexen						    &sin->sin_addr) != 0) {
1202267769Stuexen							continue;
1203267769Stuexen						}
1204178251Srrs						if ((ipv4_local_scope == 0) &&
1205178251Srrs						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
1206178251Srrs							continue;
1207178251Srrs						}
1208178251Srrs#ifdef INET6
1209178251Srrs						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
1210178251Srrs							in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
1211178251Srrs							((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1212178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
1213178251Srrs							actual += sizeof(struct sockaddr_in6);
1214178251Srrs						} else {
1215178251Srrs#endif
1216178251Srrs							memcpy(sas, sin, sizeof(*sin));
1217178251Srrs							((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1218178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
1219178251Srrs							actual += sizeof(*sin);
1220178251Srrs#ifdef INET6
1221178251Srrs						}
1222178251Srrs#endif
1223178251Srrs						if (actual >= limit) {
1224178251Srrs							return (actual);
1225178251Srrs						}
1226178251Srrs					} else {
1227163953Srrs						continue;
1228163953Srrs					}
1229178251Srrs					break;
1230221249Stuexen#endif
1231178251Srrs#ifdef INET6
1232178251Srrs				case AF_INET6:
1233178251Srrs					if (ipv6_addr_legal) {
1234178251Srrs						struct sockaddr_in6 *sin6;
1235163953Srrs
1236271746Stuexen						sin6 = &sctp_ifa->address.sin6;
1237178251Srrs						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1238178251Srrs							/*
1239178251Srrs							 * we skip
1240178251Srrs							 * unspecifed
1241178251Srrs							 * addresses
1242178251Srrs							 */
1243163953Srrs							continue;
1244178251Srrs						}
1245267769Stuexen						if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
1246267769Stuexen						    &sin6->sin6_addr) != 0) {
1247267769Stuexen							continue;
1248267769Stuexen						}
1249178251Srrs						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1250178251Srrs							if (local_scope == 0)
1251163953Srrs								continue;
1252178251Srrs							if (sin6->sin6_scope_id == 0) {
1253178251Srrs								if (sa6_recoverscope(sin6) != 0)
1254178251Srrs									/*
1255178251Srrs									 *
1256178251Srrs									 * bad
1257178251Srrs									 *
1258178251Srrs									 * li
1259178251Srrs									 * nk
1260178251Srrs									 *
1261178251Srrs									 * loc
1262178251Srrs									 * al
1263178251Srrs									 *
1264178251Srrs									 * add
1265178251Srrs									 * re
1266178251Srrs									 * ss
1267178251Srrs									 * */
1268178251Srrs									continue;
1269178251Srrs							}
1270163953Srrs						}
1271178251Srrs						if ((site_scope == 0) &&
1272178251Srrs						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
1273178251Srrs							continue;
1274178251Srrs						}
1275178251Srrs						memcpy(sas, sin6, sizeof(*sin6));
1276178251Srrs						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1277178251Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
1278178251Srrs						actual += sizeof(*sin6);
1279178251Srrs						if (actual >= limit) {
1280178251Srrs							return (actual);
1281178251Srrs						}
1282178251Srrs					} else {
1283163953Srrs						continue;
1284163953Srrs					}
1285178251Srrs					break;
1286178251Srrs#endif
1287178251Srrs				default:
1288178251Srrs					/* TSNH */
1289178251Srrs					break;
1290163953Srrs				}
1291163953Srrs			}
1292163953Srrs		}
1293163953Srrs	} else {
1294163953Srrs		struct sctp_laddr *laddr;
1295163953Srrs
1296167598Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1297167598Srrs			if (stcb) {
1298167598Srrs				if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
1299163953Srrs					continue;
1300163953Srrs				}
1301163953Srrs			}
1302167598Srrs			if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
1303167598Srrs				continue;
1304246595Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1305246595Stuexen#ifdef INET
1306246595Stuexen			case AF_INET:
1307246595Stuexen				((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1308246595Stuexen				break;
1309246595Stuexen#endif
1310246595Stuexen#ifdef INET6
1311246595Stuexen			case AF_INET6:
1312246595Stuexen				((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1313246595Stuexen				break;
1314246595Stuexen#endif
1315246595Stuexen			default:
1316246595Stuexen				/* TSNH */
1317246595Stuexen				break;
1318246595Stuexen			}
1319167598Srrs			sas = (struct sockaddr_storage *)((caddr_t)sas +
1320167598Srrs			    laddr->ifa->address.sa.sa_len);
1321167598Srrs			actual += laddr->ifa->address.sa.sa_len;
1322167598Srrs			if (actual >= limit) {
1323167598Srrs				return (actual);
1324163953Srrs			}
1325163953Srrs		}
1326163953Srrs	}
1327163953Srrs	return (actual);
1328163953Srrs}
1329163953Srrs
1330168124Srrsstatic size_t
1331168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp,
1332168124Srrs    struct sctp_tcb *stcb,
1333168124Srrs    size_t limit,
1334168124Srrs    struct sockaddr_storage *sas)
1335168124Srrs{
1336168124Srrs	size_t size = 0;
1337168124Srrs
1338172218Srrs	SCTP_IPI_ADDR_RLOCK();
1339168124Srrs	/* fill up addresses for the endpoint's default vrf */
1340168124Srrs	size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
1341168124Srrs	    inp->def_vrf_id);
1342172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1343168124Srrs	return (size);
1344168124Srrs}
1345168124Srrs
1346172091Srrs/*
1347172091Srrs * NOTE: assumes addr lock is held
1348172091Srrs */
1349163953Srrsstatic int
1350168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
1351163953Srrs{
1352163953Srrs	int cnt = 0;
1353167598Srrs	struct sctp_vrf *vrf = NULL;
1354163953Srrs
1355163953Srrs	/*
1356163953Srrs	 * In both sub-set bound an bound_all cases we return the MAXIMUM
1357163953Srrs	 * number of addresses that you COULD get. In reality the sub-set
1358163953Srrs	 * bound may have an exclusion list for a given TCB OR in the
1359163953Srrs	 * bound-all case a TCB may NOT include the loopback or other
1360163953Srrs	 * addresses as well.
1361163953Srrs	 */
1362167598Srrs	vrf = sctp_find_vrf(vrf_id);
1363167598Srrs	if (vrf == NULL) {
1364167598Srrs		return (0);
1365167598Srrs	}
1366163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1367167598Srrs		struct sctp_ifn *sctp_ifn;
1368167598Srrs		struct sctp_ifa *sctp_ifa;
1369163953Srrs
1370167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1371167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1372163953Srrs				/* Count them if they are the right type */
1373221249Stuexen				switch (sctp_ifa->address.sa.sa_family) {
1374221249Stuexen#ifdef INET
1375221249Stuexen				case AF_INET:
1376178251Srrs					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1377163953Srrs						cnt += sizeof(struct sockaddr_in6);
1378163953Srrs					else
1379163953Srrs						cnt += sizeof(struct sockaddr_in);
1380221249Stuexen					break;
1381221249Stuexen#endif
1382221249Stuexen#ifdef INET6
1383221249Stuexen				case AF_INET6:
1384163953Srrs					cnt += sizeof(struct sockaddr_in6);
1385221249Stuexen					break;
1386221249Stuexen#endif
1387221249Stuexen				default:
1388221249Stuexen					break;
1389221249Stuexen				}
1390163953Srrs			}
1391163953Srrs		}
1392163953Srrs	} else {
1393163953Srrs		struct sctp_laddr *laddr;
1394163953Srrs
1395163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1396221249Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1397221249Stuexen#ifdef INET
1398221249Stuexen			case AF_INET:
1399178251Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1400163953Srrs					cnt += sizeof(struct sockaddr_in6);
1401163953Srrs				else
1402163953Srrs					cnt += sizeof(struct sockaddr_in);
1403221249Stuexen				break;
1404221249Stuexen#endif
1405221249Stuexen#ifdef INET6
1406221249Stuexen			case AF_INET6:
1407163953Srrs				cnt += sizeof(struct sockaddr_in6);
1408221249Stuexen				break;
1409221249Stuexen#endif
1410221249Stuexen			default:
1411221249Stuexen				break;
1412221249Stuexen			}
1413163953Srrs		}
1414163953Srrs	}
1415163953Srrs	return (cnt);
1416163953Srrs}
1417163953Srrs
1418168124Srrsstatic int
1419168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp)
1420168124Srrs{
1421168124Srrs	int cnt = 0;
1422166675Srrs
1423172218Srrs	SCTP_IPI_ADDR_RLOCK();
1424168124Srrs	/* count addresses for the endpoint's default VRF */
1425168124Srrs	cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
1426172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1427168124Srrs	return (cnt);
1428168124Srrs}
1429168124Srrs
1430163953Srrsstatic int
1431166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
1432166675Srrs    size_t optsize, void *p, int delay)
1433163953Srrs{
1434163953Srrs	int error = 0;
1435163953Srrs	int creat_lock_on = 0;
1436163953Srrs	struct sctp_tcb *stcb = NULL;
1437163953Srrs	struct sockaddr *sa;
1438169352Srrs	int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
1439167598Srrs	uint32_t vrf_id;
1440170056Srrs	int bad_addresses = 0;
1441167598Srrs	sctp_assoc_t *a_id;
1442163953Srrs
1443169420Srrs	SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
1444163953Srrs
1445163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1446163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1447163953Srrs		/* We are already connected AND the TCP model */
1448171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
1449163953Srrs		return (EADDRINUSE);
1450163953Srrs	}
1451181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
1452181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
1453171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1454163953Srrs		return (EINVAL);
1455163953Srrs	}
1456163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1457163953Srrs		SCTP_INP_RLOCK(inp);
1458163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1459163953Srrs		SCTP_INP_RUNLOCK(inp);
1460163953Srrs	}
1461163953Srrs	if (stcb) {
1462171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1463163953Srrs		return (EALREADY);
1464163953Srrs	}
1465163953Srrs	SCTP_INP_INCR_REF(inp);
1466163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
1467163953Srrs	creat_lock_on = 1;
1468163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1469163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
1470171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
1471163953Srrs		error = EFAULT;
1472163953Srrs		goto out_now;
1473163953Srrs	}
1474166675Srrs	totaddrp = (int *)optval;
1475163953Srrs	totaddr = *totaddrp;
1476163953Srrs	sa = (struct sockaddr *)(totaddrp + 1);
1477170056Srrs	stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
1478170056Srrs	if ((stcb != NULL) || bad_addresses) {
1479169352Srrs		/* Already have or am bring up an association */
1480169352Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1481169352Srrs		creat_lock_on = 0;
1482170931Srrs		if (stcb)
1483170931Srrs			SCTP_TCB_UNLOCK(stcb);
1484171943Srrs		if (bad_addresses == 0) {
1485171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1486170056Srrs			error = EALREADY;
1487171943Srrs		}
1488169352Srrs		goto out_now;
1489163953Srrs	}
1490163953Srrs#ifdef INET6
1491163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
1492163953Srrs	    (num_v6 > 0)) {
1493163953Srrs		error = EINVAL;
1494163953Srrs		goto out_now;
1495163953Srrs	}
1496163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1497163953Srrs	    (num_v4 > 0)) {
1498163953Srrs		struct in6pcb *inp6;
1499163953Srrs
1500163953Srrs		inp6 = (struct in6pcb *)inp;
1501166023Srrs		if (SCTP_IPV6_V6ONLY(inp6)) {
1502163953Srrs			/*
1503163953Srrs			 * if IPV6_V6ONLY flag, ignore connections destined
1504163953Srrs			 * to a v4 addr or v4-mapped addr
1505163953Srrs			 */
1506171943Srrs			SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1507163953Srrs			error = EINVAL;
1508163953Srrs			goto out_now;
1509163953Srrs		}
1510163953Srrs	}
1511163953Srrs#endif				/* INET6 */
1512163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1513163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
1514163953Srrs		/* Bind a ephemeral port */
1515171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
1516163953Srrs		if (error) {
1517163953Srrs			goto out_now;
1518163953Srrs		}
1519163953Srrs	}
1520167695Srrs	/* FIX ME: do we want to pass in a vrf on the connect call? */
1521167695Srrs	vrf_id = inp->def_vrf_id;
1522167695Srrs
1523181054Srrs
1524163953Srrs	/* We are GOOD to go */
1525206137Stuexen	stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id,
1526171531Srrs	    (struct thread *)p
1527171531Srrs	    );
1528163953Srrs	if (stcb == NULL) {
1529163953Srrs		/* Gak! no memory */
1530163953Srrs		goto out_now;
1531163953Srrs	}
1532225559Stuexen	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1533225559Stuexen		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1534225559Stuexen		/* Set the connected flag so we can queue data */
1535225559Stuexen		soisconnecting(so);
1536225559Stuexen	}
1537171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
1538163953Srrs	/* move to second address */
1539221249Stuexen	switch (sa->sa_family) {
1540221249Stuexen#ifdef INET
1541221249Stuexen	case AF_INET:
1542163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
1543221249Stuexen		break;
1544221249Stuexen#endif
1545221249Stuexen#ifdef INET6
1546221249Stuexen	case AF_INET6:
1547163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
1548221249Stuexen		break;
1549221249Stuexen#endif
1550221249Stuexen	default:
1551221249Stuexen		break;
1552221249Stuexen	}
1553163953Srrs
1554170056Srrs	error = 0;
1555223132Stuexen	sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
1556167598Srrs	/* Fill in the return id */
1557170056Srrs	if (error) {
1558207924Srrs		(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
1559170056Srrs		goto out_now;
1560170056Srrs	}
1561167598Srrs	a_id = (sctp_assoc_t *) optval;
1562167598Srrs	*a_id = sctp_get_associd(stcb);
1563163953Srrs
1564163953Srrs	/* initialize authentication parameters for the assoc */
1565163953Srrs	sctp_initialize_auth_params(inp, stcb);
1566163953Srrs
1567163953Srrs	if (delay) {
1568163953Srrs		/* doing delayed connection */
1569163953Srrs		stcb->asoc.delayed_connection = 1;
1570163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
1571163953Srrs	} else {
1572169378Srrs		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1573172090Srrs		sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
1574163953Srrs	}
1575163953Srrs	SCTP_TCB_UNLOCK(stcb);
1576163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1577163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1578163953Srrs		/* Set the connected flag so we can queue data */
1579163953Srrs		soisconnecting(so);
1580163953Srrs	}
1581163953Srrsout_now:
1582169655Srrs	if (creat_lock_on) {
1583163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1584169655Srrs	}
1585163953Srrs	SCTP_INP_DECR_REF(inp);
1586228907Stuexen	return (error);
1587163953Srrs}
1588163953Srrs
1589169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
1590169655Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\
1591169655Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \
1592166675Srrs		SCTP_INP_RLOCK(inp); \
1593166675Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list); \
1594169655Srrs		if (stcb) { \
1595166675Srrs			SCTP_TCB_LOCK(stcb); \
1596169655Srrs                } \
1597166675Srrs		SCTP_INP_RUNLOCK(inp); \
1598223132Stuexen	} else if (assoc_id > SCTP_ALL_ASSOC) { \
1599166675Srrs		stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
1600166675Srrs		if (stcb == NULL) { \
1601171943Srrs		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
1602166675Srrs			error = ENOENT; \
1603166675Srrs			break; \
1604166675Srrs		} \
1605166675Srrs	} else { \
1606166675Srrs		stcb = NULL; \
1607169420Srrs        } \
1608169420Srrs  }
1609163953Srrs
1610169420Srrs
1611234464Stuexen#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
1612166675Srrs	if (size < sizeof(type)) { \
1613171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
1614166675Srrs		error = EINVAL; \
1615166675Srrs		break; \
1616166675Srrs	} else { \
1617166675Srrs		destp = (type *)srcp; \
1618169420Srrs	} \
1619169420Srrs      }
1620163953Srrs
1621163953Srrsstatic int
1622166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
1623166675Srrs    void *p)
1624163953Srrs{
1625171943Srrs	struct sctp_inpcb *inp = NULL;
1626166675Srrs	int error, val = 0;
1627163953Srrs	struct sctp_tcb *stcb = NULL;
1628163953Srrs
1629166675Srrs	if (optval == NULL) {
1630171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1631166675Srrs		return (EINVAL);
1632166675Srrs	}
1633163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1634233005Stuexen	if (inp == NULL) {
1635171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1636163953Srrs		return EINVAL;
1637171943Srrs	}
1638163953Srrs	error = 0;
1639163953Srrs
1640166675Srrs	switch (optname) {
1641163953Srrs	case SCTP_NODELAY:
1642163953Srrs	case SCTP_AUTOCLOSE:
1643163953Srrs	case SCTP_EXPLICIT_EOR:
1644163953Srrs	case SCTP_AUTO_ASCONF:
1645163953Srrs	case SCTP_DISABLE_FRAGMENTS:
1646163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
1647163953Srrs	case SCTP_USE_EXT_RCVINFO:
1648163953Srrs		SCTP_INP_RLOCK(inp);
1649166675Srrs		switch (optname) {
1650163953Srrs		case SCTP_DISABLE_FRAGMENTS:
1651166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
1652163953Srrs			break;
1653163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
1654166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
1655163953Srrs			break;
1656163953Srrs		case SCTP_AUTO_ASCONF:
1657171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1658171943Srrs				/* only valid for bound all sockets */
1659171943Srrs				val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
1660171943Srrs			} else {
1661171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1662171943Srrs				error = EINVAL;
1663171943Srrs				goto flags_out;
1664171943Srrs			}
1665163953Srrs			break;
1666163953Srrs		case SCTP_EXPLICIT_EOR:
1667166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
1668163953Srrs			break;
1669163953Srrs		case SCTP_NODELAY:
1670166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
1671163953Srrs			break;
1672163953Srrs		case SCTP_USE_EXT_RCVINFO:
1673166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
1674163953Srrs			break;
1675163953Srrs		case SCTP_AUTOCLOSE:
1676163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
1677166675Srrs				val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
1678163953Srrs			else
1679166675Srrs				val = 0;
1680163953Srrs			break;
1681163953Srrs
1682163953Srrs		default:
1683171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
1684163953Srrs			error = ENOPROTOOPT;
1685163953Srrs		}		/* end switch (sopt->sopt_name) */
1686166675Srrs		if (*optsize < sizeof(val)) {
1687171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1688163953Srrs			error = EINVAL;
1689163953Srrs		}
1690171943Srrsflags_out:
1691163953Srrs		SCTP_INP_RUNLOCK(inp);
1692163953Srrs		if (error == 0) {
1693163953Srrs			/* return the option value */
1694166675Srrs			*(int *)optval = val;
1695166675Srrs			*optsize = sizeof(val);
1696163953Srrs		}
1697163953Srrs		break;
1698170091Srrs	case SCTP_GET_PACKET_LOG:
1699170091Srrs		{
1700170091Srrs#ifdef  SCTP_PACKET_LOGGING
1701170091Srrs			uint8_t *target;
1702170091Srrs			int ret;
1703167598Srrs
1704170091Srrs			SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize);
1705170091Srrs			ret = sctp_copy_out_packet_log(target, (int)*optsize);
1706170091Srrs			*optsize = ret;
1707170091Srrs#else
1708171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1709170091Srrs			error = EOPNOTSUPP;
1710170091Srrs#endif
1711170091Srrs			break;
1712170091Srrs		}
1713181054Srrs	case SCTP_REUSE_PORT:
1714181054Srrs		{
1715181054Srrs			uint32_t *value;
1716181054Srrs
1717181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
1718181054Srrs				/* Can't do this for a 1-m socket */
1719181054Srrs				error = EINVAL;
1720181054Srrs				break;
1721181054Srrs			}
1722181054Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1723181054Srrs			*value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
1724181054Srrs			*optsize = sizeof(uint32_t);
1725223132Stuexen			break;
1726181054Srrs		}
1727163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
1728163953Srrs		{
1729166675Srrs			uint32_t *value;
1730166675Srrs
1731166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1732166675Srrs			*value = inp->partial_delivery_point;
1733166675Srrs			*optsize = sizeof(uint32_t);
1734223132Stuexen			break;
1735163953Srrs		}
1736163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
1737163953Srrs		{
1738166675Srrs			uint32_t *value;
1739166675Srrs
1740166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1741168943Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
1742168943Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
1743168943Srrs					*value = SCTP_FRAG_LEVEL_2;
1744168943Srrs				} else {
1745168943Srrs					*value = SCTP_FRAG_LEVEL_1;
1746168943Srrs				}
1747168943Srrs			} else {
1748168943Srrs				*value = SCTP_FRAG_LEVEL_0;
1749168943Srrs			}
1750166675Srrs			*optsize = sizeof(uint32_t);
1751223132Stuexen			break;
1752163953Srrs		}
1753163953Srrs	case SCTP_CMT_ON_OFF:
1754163953Srrs		{
1755166675Srrs			struct sctp_assoc_value *av;
1756166675Srrs
1757166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1758211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1759211944Stuexen			if (stcb) {
1760211944Stuexen				av->assoc_value = stcb->asoc.sctp_cmt_on_off;
1761211944Stuexen				SCTP_TCB_UNLOCK(stcb);
1762166675Srrs			} else {
1763224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1764224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1765224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1766223132Stuexen					SCTP_INP_RLOCK(inp);
1767223132Stuexen					av->assoc_value = inp->sctp_cmt_on_off;
1768223132Stuexen					SCTP_INP_RUNLOCK(inp);
1769223132Stuexen				} else {
1770223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1771223132Stuexen					error = EINVAL;
1772223132Stuexen				}
1773163953Srrs			}
1774223132Stuexen			if (error == 0) {
1775223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1776223132Stuexen			}
1777223132Stuexen			break;
1778163953Srrs		}
1779171440Srrs	case SCTP_PLUGGABLE_CC:
1780171440Srrs		{
1781171440Srrs			struct sctp_assoc_value *av;
1782171440Srrs
1783171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1784171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1785171440Srrs			if (stcb) {
1786171440Srrs				av->assoc_value = stcb->asoc.congestion_control_module;
1787171440Srrs				SCTP_TCB_UNLOCK(stcb);
1788171440Srrs			} else {
1789224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1790224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1791224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1792223132Stuexen					SCTP_INP_RLOCK(inp);
1793223132Stuexen					av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
1794223132Stuexen					SCTP_INP_RUNLOCK(inp);
1795223132Stuexen				} else {
1796223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1797223132Stuexen					error = EINVAL;
1798223132Stuexen				}
1799171440Srrs			}
1800223132Stuexen			if (error == 0) {
1801223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1802223132Stuexen			}
1803223132Stuexen			break;
1804171440Srrs		}
1805219057Srrs	case SCTP_CC_OPTION:
1806219057Srrs		{
1807219057Srrs			struct sctp_cc_option *cc_opt;
1808219057Srrs
1809219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize);
1810219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
1811219057Srrs			if (stcb == NULL) {
1812219057Srrs				error = EINVAL;
1813219057Srrs			} else {
1814219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
1815219057Srrs					error = ENOTSUP;
1816219057Srrs				} else {
1817223132Stuexen					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt);
1818223132Stuexen					*optsize = sizeof(struct sctp_cc_option);
1819219057Srrs				}
1820219057Srrs				SCTP_TCB_UNLOCK(stcb);
1821219057Srrs			}
1822223132Stuexen			break;
1823219057Srrs		}
1824217760Stuexen	case SCTP_PLUGGABLE_SS:
1825217760Stuexen		{
1826217760Stuexen			struct sctp_assoc_value *av;
1827217760Stuexen
1828217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1829217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1830217760Stuexen			if (stcb) {
1831217760Stuexen				av->assoc_value = stcb->asoc.stream_scheduling_module;
1832217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1833217760Stuexen			} else {
1834224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1835224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1836224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1837223132Stuexen					SCTP_INP_RLOCK(inp);
1838223132Stuexen					av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
1839223132Stuexen					SCTP_INP_RUNLOCK(inp);
1840223132Stuexen				} else {
1841223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1842223132Stuexen					error = EINVAL;
1843223132Stuexen				}
1844217760Stuexen			}
1845223132Stuexen			if (error == 0) {
1846223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1847223132Stuexen			}
1848223132Stuexen			break;
1849217760Stuexen		}
1850217760Stuexen	case SCTP_SS_VALUE:
1851217760Stuexen		{
1852217760Stuexen			struct sctp_stream_value *av;
1853217760Stuexen
1854217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
1855217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1856217760Stuexen			if (stcb) {
1857277807Sdelphij				if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
1858277807Sdelphij				    (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
1859277807Sdelphij				    &av->stream_value) < 0)) {
1860217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1861217760Stuexen					error = EINVAL;
1862217760Stuexen				} else {
1863223132Stuexen					*optsize = sizeof(struct sctp_stream_value);
1864217760Stuexen				}
1865217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1866217760Stuexen			} else {
1867217760Stuexen				/*
1868217760Stuexen				 * Can't get stream value without
1869217760Stuexen				 * association
1870217760Stuexen				 */
1871217760Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1872217760Stuexen				error = EINVAL;
1873217760Stuexen			}
1874223132Stuexen			break;
1875217760Stuexen		}
1876163953Srrs	case SCTP_GET_ADDR_LEN:
1877163953Srrs		{
1878163953Srrs			struct sctp_assoc_value *av;
1879163953Srrs
1880166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1881163953Srrs			error = EINVAL;
1882167598Srrs#ifdef INET
1883163953Srrs			if (av->assoc_value == AF_INET) {
1884163953Srrs				av->assoc_value = sizeof(struct sockaddr_in);
1885163953Srrs				error = 0;
1886163953Srrs			}
1887163953Srrs#endif
1888167598Srrs#ifdef INET6
1889163953Srrs			if (av->assoc_value == AF_INET6) {
1890163953Srrs				av->assoc_value = sizeof(struct sockaddr_in6);
1891163953Srrs				error = 0;
1892163953Srrs			}
1893163953Srrs#endif
1894172091Srrs			if (error) {
1895171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1896223132Stuexen			} else {
1897223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1898172091Srrs			}
1899223132Stuexen			break;
1900163953Srrs		}
1901169655Srrs	case SCTP_GET_ASSOC_NUMBER:
1902163953Srrs		{
1903169655Srrs			uint32_t *value, cnt;
1904163953Srrs
1905169655Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1906163953Srrs			cnt = 0;
1907163953Srrs			SCTP_INP_RLOCK(inp);
1908169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1909169655Srrs				cnt++;
1910163953Srrs			}
1911169655Srrs			SCTP_INP_RUNLOCK(inp);
1912169655Srrs			*value = cnt;
1913169655Srrs			*optsize = sizeof(uint32_t);
1914223132Stuexen			break;
1915169655Srrs		}
1916169655Srrs	case SCTP_GET_ASSOC_ID_LIST:
1917169655Srrs		{
1918169655Srrs			struct sctp_assoc_ids *ids;
1919169655Srrs			unsigned int at, limit;
1920169655Srrs
1921169655Srrs			SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
1922163953Srrs			at = 0;
1923185694Srrs			limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t);
1924169655Srrs			SCTP_INP_RLOCK(inp);
1925169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1926169655Srrs				if (at < limit) {
1927169655Srrs					ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
1928169655Srrs				} else {
1929169655Srrs					error = EINVAL;
1930171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1931163953Srrs					break;
1932163953Srrs				}
1933163953Srrs			}
1934163953Srrs			SCTP_INP_RUNLOCK(inp);
1935223132Stuexen			if (error == 0) {
1936223132Stuexen				ids->gaids_number_of_ids = at;
1937223132Stuexen				*optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
1938223132Stuexen			}
1939223132Stuexen			break;
1940163953Srrs		}
1941163953Srrs	case SCTP_CONTEXT:
1942163953Srrs		{
1943163953Srrs			struct sctp_assoc_value *av;
1944163953Srrs
1945166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1946166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1947166675Srrs
1948166675Srrs			if (stcb) {
1949166675Srrs				av->assoc_value = stcb->asoc.context;
1950166675Srrs				SCTP_TCB_UNLOCK(stcb);
1951163953Srrs			} else {
1952224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1953224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1954224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1955223132Stuexen					SCTP_INP_RLOCK(inp);
1956223132Stuexen					av->assoc_value = inp->sctp_context;
1957223132Stuexen					SCTP_INP_RUNLOCK(inp);
1958223132Stuexen				} else {
1959223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1960223132Stuexen					error = EINVAL;
1961223132Stuexen				}
1962163953Srrs			}
1963223132Stuexen			if (error == 0) {
1964223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1965223132Stuexen			}
1966223132Stuexen			break;
1967163953Srrs		}
1968167598Srrs	case SCTP_VRF_ID:
1969167598Srrs		{
1970170056Srrs			uint32_t *default_vrfid;
1971167598Srrs
1972170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
1973170056Srrs			*default_vrfid = inp->def_vrf_id;
1974223132Stuexen			*optsize = sizeof(uint32_t);
1975167598Srrs			break;
1976167598Srrs		}
1977167598Srrs	case SCTP_GET_ASOC_VRF:
1978167598Srrs		{
1979167598Srrs			struct sctp_assoc_value *id;
1980167598Srrs
1981167598Srrs			SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
1982167598Srrs			SCTP_FIND_STCB(inp, stcb, id->assoc_id);
1983167598Srrs			if (stcb == NULL) {
1984167598Srrs				error = EINVAL;
1985171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1986223132Stuexen			} else {
1987223132Stuexen				id->assoc_value = stcb->asoc.vrf_id;
1988223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1989167598Srrs			}
1990167598Srrs			break;
1991167598Srrs		}
1992167598Srrs	case SCTP_GET_VRF_IDS:
1993167598Srrs		{
1994171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1995167598Srrs			error = EOPNOTSUPP;
1996167598Srrs			break;
1997167598Srrs		}
1998163953Srrs	case SCTP_GET_NONCE_VALUES:
1999163953Srrs		{
2000163953Srrs			struct sctp_get_nonce_values *gnv;
2001163953Srrs
2002166675Srrs			SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
2003166675Srrs			SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
2004166675Srrs
2005166675Srrs			if (stcb) {
2006163953Srrs				gnv->gn_peers_tag = stcb->asoc.peer_vtag;
2007163953Srrs				gnv->gn_local_tag = stcb->asoc.my_vtag;
2008163953Srrs				SCTP_TCB_UNLOCK(stcb);
2009223132Stuexen				*optsize = sizeof(struct sctp_get_nonce_values);
2010166675Srrs			} else {
2011171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2012166675Srrs				error = ENOTCONN;
2013163953Srrs			}
2014223132Stuexen			break;
2015163953Srrs		}
2016170056Srrs	case SCTP_DELAYED_SACK:
2017163953Srrs		{
2018170056Srrs			struct sctp_sack_info *sack;
2019163953Srrs
2020170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
2021170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
2022166675Srrs			if (stcb) {
2023170056Srrs				sack->sack_delay = stcb->asoc.delayed_ack;
2024170056Srrs				sack->sack_freq = stcb->asoc.sack_freq;
2025166675Srrs				SCTP_TCB_UNLOCK(stcb);
2026166675Srrs			} else {
2027224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2028224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2029224918Stuexen				    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) {
2030223132Stuexen					SCTP_INP_RLOCK(inp);
2031223132Stuexen					sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
2032223132Stuexen					sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
2033223132Stuexen					SCTP_INP_RUNLOCK(inp);
2034223132Stuexen				} else {
2035223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2036223132Stuexen					error = EINVAL;
2037223132Stuexen				}
2038163953Srrs			}
2039223132Stuexen			if (error == 0) {
2040223132Stuexen				*optsize = sizeof(struct sctp_sack_info);
2041223132Stuexen			}
2042223132Stuexen			break;
2043163953Srrs		}
2044163953Srrs	case SCTP_GET_SNDBUF_USE:
2045166675Srrs		{
2046163953Srrs			struct sctp_sockstat *ss;
2047163953Srrs
2048166675Srrs			SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
2049166675Srrs			SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
2050166675Srrs
2051166675Srrs			if (stcb) {
2052166675Srrs				ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
2053166675Srrs				ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
2054166675Srrs				    stcb->asoc.size_on_all_streams);
2055166675Srrs				SCTP_TCB_UNLOCK(stcb);
2056223132Stuexen				*optsize = sizeof(struct sctp_sockstat);
2057166675Srrs			} else {
2058171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2059163953Srrs				error = ENOTCONN;
2060163953Srrs			}
2061223132Stuexen			break;
2062163953Srrs		}
2063170056Srrs	case SCTP_MAX_BURST:
2064163953Srrs		{
2065217895Stuexen			struct sctp_assoc_value *av;
2066163953Srrs
2067217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2068217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2069166675Srrs
2070217895Stuexen			if (stcb) {
2071217895Stuexen				av->assoc_value = stcb->asoc.max_burst;
2072217895Stuexen				SCTP_TCB_UNLOCK(stcb);
2073217894Stuexen			} else {
2074224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2075224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2076224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2077223132Stuexen					SCTP_INP_RLOCK(inp);
2078223132Stuexen					av->assoc_value = inp->sctp_ep.max_burst;
2079223132Stuexen					SCTP_INP_RUNLOCK(inp);
2080223132Stuexen				} else {
2081223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2082223132Stuexen					error = EINVAL;
2083223132Stuexen				}
2084217894Stuexen			}
2085223132Stuexen			if (error == 0) {
2086223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2087223132Stuexen			}
2088223132Stuexen			break;
2089163953Srrs		}
2090163953Srrs	case SCTP_MAXSEG:
2091163953Srrs		{
2092167598Srrs			struct sctp_assoc_value *av;
2093163953Srrs			int ovh;
2094163953Srrs
2095167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2096170056Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2097163953Srrs
2098167598Srrs			if (stcb) {
2099167598Srrs				av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
2100167598Srrs				SCTP_TCB_UNLOCK(stcb);
2101163953Srrs			} else {
2102224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2103224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2104224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2105223132Stuexen					SCTP_INP_RLOCK(inp);
2106223132Stuexen					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2107223132Stuexen						ovh = SCTP_MED_OVERHEAD;
2108223132Stuexen					} else {
2109223132Stuexen						ovh = SCTP_MED_V4_OVERHEAD;
2110223132Stuexen					}
2111223132Stuexen					if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
2112223132Stuexen						av->assoc_value = 0;
2113223132Stuexen					else
2114223132Stuexen						av->assoc_value = inp->sctp_frag_point - ovh;
2115223132Stuexen					SCTP_INP_RUNLOCK(inp);
2116167598Srrs				} else {
2117223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2118223132Stuexen					error = EINVAL;
2119167598Srrs				}
2120163953Srrs			}
2121223132Stuexen			if (error == 0) {
2122223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2123223132Stuexen			}
2124223132Stuexen			break;
2125163953Srrs		}
2126163953Srrs	case SCTP_GET_STAT_LOG:
2127167598Srrs		error = sctp_fill_stat_log(optval, optsize);
2128163953Srrs		break;
2129163953Srrs	case SCTP_EVENTS:
2130163953Srrs		{
2131163953Srrs			struct sctp_event_subscribe *events;
2132163953Srrs
2133166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
2134223132Stuexen			memset(events, 0, sizeof(struct sctp_event_subscribe));
2135163953Srrs			SCTP_INP_RLOCK(inp);
2136163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
2137163953Srrs				events->sctp_data_io_event = 1;
2138163953Srrs
2139163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
2140163953Srrs				events->sctp_association_event = 1;
2141163953Srrs
2142163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
2143163953Srrs				events->sctp_address_event = 1;
2144163953Srrs
2145163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
2146163953Srrs				events->sctp_send_failure_event = 1;
2147163953Srrs
2148163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
2149163953Srrs				events->sctp_peer_error_event = 1;
2150163953Srrs
2151163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
2152163953Srrs				events->sctp_shutdown_event = 1;
2153163953Srrs
2154163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
2155163953Srrs				events->sctp_partial_delivery_event = 1;
2156163953Srrs
2157163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
2158163953Srrs				events->sctp_adaptation_layer_event = 1;
2159163953Srrs
2160163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
2161163953Srrs				events->sctp_authentication_event = 1;
2162163953Srrs
2163185694Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
2164185694Srrs				events->sctp_sender_dry_event = 1;
2165185694Srrs
2166163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
2167202520Srrs				events->sctp_stream_reset_event = 1;
2168163953Srrs			SCTP_INP_RUNLOCK(inp);
2169166675Srrs			*optsize = sizeof(struct sctp_event_subscribe);
2170223132Stuexen			break;
2171163953Srrs		}
2172163953Srrs	case SCTP_ADAPTATION_LAYER:
2173166675Srrs		{
2174166675Srrs			uint32_t *value;
2175166675Srrs
2176166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2177166675Srrs
2178166675Srrs			SCTP_INP_RLOCK(inp);
2179166675Srrs			*value = inp->sctp_ep.adaptation_layer_indicator;
2180166675Srrs			SCTP_INP_RUNLOCK(inp);
2181166675Srrs			*optsize = sizeof(uint32_t);
2182223132Stuexen			break;
2183163953Srrs		}
2184163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
2185166675Srrs		{
2186166675Srrs			uint32_t *value;
2187166675Srrs
2188166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2189166675Srrs			SCTP_INP_RLOCK(inp);
2190166675Srrs			*value = inp->sctp_ep.initial_sequence_debug;
2191166675Srrs			SCTP_INP_RUNLOCK(inp);
2192166675Srrs			*optsize = sizeof(uint32_t);
2193223132Stuexen			break;
2194163953Srrs		}
2195163953Srrs	case SCTP_GET_LOCAL_ADDR_SIZE:
2196166675Srrs		{
2197166675Srrs			uint32_t *value;
2198166675Srrs
2199166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2200166675Srrs			SCTP_INP_RLOCK(inp);
2201168124Srrs			*value = sctp_count_max_addresses(inp);
2202166675Srrs			SCTP_INP_RUNLOCK(inp);
2203166675Srrs			*optsize = sizeof(uint32_t);
2204223132Stuexen			break;
2205163953Srrs		}
2206163953Srrs	case SCTP_GET_REMOTE_ADDR_SIZE:
2207163953Srrs		{
2208166675Srrs			uint32_t *value;
2209166675Srrs			size_t size;
2210163953Srrs			struct sctp_nets *net;
2211163953Srrs
2212166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2213166675Srrs			/* FIXME MT: change to sctp_assoc_value? */
2214166675Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
2215166675Srrs
2216166675Srrs			if (stcb) {
2217166675Srrs				size = 0;
2218166675Srrs				/* Count the sizes */
2219166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2220221249Stuexen					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2221166675Srrs						size += sizeof(struct sockaddr_in6);
2222166675Srrs					} else {
2223221249Stuexen						switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
2224221249Stuexen#ifdef INET
2225221249Stuexen						case AF_INET:
2226221249Stuexen							size += sizeof(struct sockaddr_in);
2227221249Stuexen							break;
2228221249Stuexen#endif
2229221249Stuexen#ifdef INET6
2230221249Stuexen						case AF_INET6:
2231221249Stuexen							size += sizeof(struct sockaddr_in6);
2232221249Stuexen							break;
2233221249Stuexen#endif
2234221249Stuexen						default:
2235221249Stuexen							break;
2236221249Stuexen						}
2237166675Srrs					}
2238163953Srrs				}
2239166675Srrs				SCTP_TCB_UNLOCK(stcb);
2240166675Srrs				*value = (uint32_t) size;
2241223132Stuexen				*optsize = sizeof(uint32_t);
2242166675Srrs			} else {
2243171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2244166675Srrs				error = ENOTCONN;
2245163953Srrs			}
2246223132Stuexen			break;
2247163953Srrs		}
2248163953Srrs	case SCTP_GET_PEER_ADDRESSES:
2249163953Srrs		/*
2250163953Srrs		 * Get the address information, an array is passed in to
2251163953Srrs		 * fill up we pack it.
2252163953Srrs		 */
2253163953Srrs		{
2254166675Srrs			size_t cpsz, left;
2255163953Srrs			struct sockaddr_storage *sas;
2256163953Srrs			struct sctp_nets *net;
2257163953Srrs			struct sctp_getaddresses *saddr;
2258163953Srrs
2259166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2260166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2261163953Srrs
2262166675Srrs			if (stcb) {
2263166675Srrs				left = (*optsize) - sizeof(struct sctp_getaddresses);
2264166675Srrs				*optsize = sizeof(struct sctp_getaddresses);
2265166675Srrs				sas = (struct sockaddr_storage *)&saddr->addr[0];
2266166675Srrs
2267166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2268221249Stuexen					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2269166675Srrs						cpsz = sizeof(struct sockaddr_in6);
2270166675Srrs					} else {
2271221249Stuexen						switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
2272221249Stuexen#ifdef INET
2273221249Stuexen						case AF_INET:
2274221249Stuexen							cpsz = sizeof(struct sockaddr_in);
2275221249Stuexen							break;
2276221249Stuexen#endif
2277221249Stuexen#ifdef INET6
2278221249Stuexen						case AF_INET6:
2279221249Stuexen							cpsz = sizeof(struct sockaddr_in6);
2280221249Stuexen							break;
2281221249Stuexen#endif
2282221249Stuexen						default:
2283221249Stuexen							cpsz = 0;
2284221249Stuexen							break;
2285221249Stuexen						}
2286221249Stuexen					}
2287221249Stuexen					if (cpsz == 0) {
2288166675Srrs						break;
2289166675Srrs					}
2290166675Srrs					if (left < cpsz) {
2291166675Srrs						/* not enough room. */
2292166675Srrs						break;
2293166675Srrs					}
2294221249Stuexen#if defined(INET) && defined(INET6)
2295178251Srrs					if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
2296166675Srrs					    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
2297166675Srrs						/* Must map the address */
2298166675Srrs						in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
2299166675Srrs						    (struct sockaddr_in6 *)sas);
2300166675Srrs					} else {
2301178251Srrs#endif
2302166675Srrs						memcpy(sas, &net->ro._l_addr, cpsz);
2303221249Stuexen#if defined(INET) && defined(INET6)
2304166675Srrs					}
2305178251Srrs#endif
2306166675Srrs					((struct sockaddr_in *)sas)->sin_port = stcb->rport;
2307166675Srrs
2308166675Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
2309166675Srrs					left -= cpsz;
2310166675Srrs					*optsize += cpsz;
2311163953Srrs				}
2312166675Srrs				SCTP_TCB_UNLOCK(stcb);
2313166675Srrs			} else {
2314171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2315166675Srrs				error = ENOENT;
2316163953Srrs			}
2317223132Stuexen			break;
2318163953Srrs		}
2319163953Srrs	case SCTP_GET_LOCAL_ADDRESSES:
2320163953Srrs		{
2321166675Srrs			size_t limit, actual;
2322163953Srrs			struct sockaddr_storage *sas;
2323163953Srrs			struct sctp_getaddresses *saddr;
2324163953Srrs
2325166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2326166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2327163953Srrs
2328163953Srrs			sas = (struct sockaddr_storage *)&saddr->addr[0];
2329166675Srrs			limit = *optsize - sizeof(sctp_assoc_t);
2330168124Srrs			actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
2331169655Srrs			if (stcb) {
2332163953Srrs				SCTP_TCB_UNLOCK(stcb);
2333169655Srrs			}
2334166675Srrs			*optsize = sizeof(struct sockaddr_storage) + actual;
2335223132Stuexen			break;
2336163953Srrs		}
2337163953Srrs	case SCTP_PEER_ADDR_PARAMS:
2338163953Srrs		{
2339163953Srrs			struct sctp_paddrparams *paddrp;
2340163953Srrs			struct sctp_nets *net;
2341163953Srrs
2342166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
2343166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
2344163953Srrs
2345163953Srrs			net = NULL;
2346166675Srrs			if (stcb) {
2347166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
2348166675Srrs			} else {
2349166675Srrs				/*
2350166675Srrs				 * We increment here since
2351166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2352166675Srrs				 * decrement if it finds the stcb as long as
2353166675Srrs				 * the locked tcb (last argument) is NOT a
2354166675Srrs				 * TCB.. aka NULL.
2355166675Srrs				 */
2356166675Srrs				SCTP_INP_INCR_REF(inp);
2357166675Srrs				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL);
2358163953Srrs				if (stcb == NULL) {
2359166675Srrs					SCTP_INP_DECR_REF(inp);
2360163953Srrs				}
2361163953Srrs			}
2362171943Srrs			if (stcb && (net == NULL)) {
2363171943Srrs				struct sockaddr *sa;
2364163953Srrs
2365171943Srrs				sa = (struct sockaddr *)&paddrp->spp_address;
2366221249Stuexen#ifdef INET
2367171943Srrs				if (sa->sa_family == AF_INET) {
2368171943Srrs					struct sockaddr_in *sin;
2369171943Srrs
2370171943Srrs					sin = (struct sockaddr_in *)sa;
2371171943Srrs					if (sin->sin_addr.s_addr) {
2372171943Srrs						error = EINVAL;
2373171943Srrs						SCTP_TCB_UNLOCK(stcb);
2374171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2375171943Srrs						break;
2376171943Srrs					}
2377221249Stuexen				} else
2378221249Stuexen#endif
2379221249Stuexen#ifdef INET6
2380221249Stuexen				if (sa->sa_family == AF_INET6) {
2381171943Srrs					struct sockaddr_in6 *sin6;
2382171943Srrs
2383171943Srrs					sin6 = (struct sockaddr_in6 *)sa;
2384171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
2385171943Srrs						error = EINVAL;
2386171943Srrs						SCTP_TCB_UNLOCK(stcb);
2387171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2388171943Srrs						break;
2389171943Srrs					}
2390221249Stuexen				} else
2391221249Stuexen#endif
2392221249Stuexen				{
2393171943Srrs					error = EAFNOSUPPORT;
2394171943Srrs					SCTP_TCB_UNLOCK(stcb);
2395171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2396171943Srrs					break;
2397171943Srrs				}
2398171943Srrs			}
2399163953Srrs			if (stcb) {
2400224641Stuexen				/* Applies to the specific association */
2401163953Srrs				paddrp->spp_flags = 0;
2402163953Srrs				if (net) {
2403170056Srrs					int ovh;
2404170056Srrs
2405170056Srrs					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2406170056Srrs						ovh = SCTP_MED_OVERHEAD;
2407170056Srrs					} else {
2408170056Srrs						ovh = SCTP_MED_V4_OVERHEAD;
2409170056Srrs					}
2410170056Srrs
2411224641Stuexen					paddrp->spp_hbinterval = net->heart_beat_delay;
2412163953Srrs					paddrp->spp_pathmaxrxt = net->failure_threshold;
2413170056Srrs					paddrp->spp_pathmtu = net->mtu - ovh;
2414163953Srrs					/* get flags for HB */
2415225635Stuexen					if (net->dest_state & SCTP_ADDR_NOHB) {
2416163953Srrs						paddrp->spp_flags |= SPP_HB_DISABLE;
2417225635Stuexen					} else {
2418163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2419225635Stuexen					}
2420163953Srrs					/* get flags for PMTU */
2421225635Stuexen					if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
2422163953Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2423163953Srrs					} else {
2424163953Srrs						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2425163953Srrs					}
2426225549Stuexen					if (net->dscp & 0x01) {
2427226252Stuexen						paddrp->spp_dscp = net->dscp & 0xfc;
2428224870Stuexen						paddrp->spp_flags |= SPP_DSCP;
2429163953Srrs					}
2430167598Srrs#ifdef INET6
2431225549Stuexen					if ((net->ro._l_addr.sa.sa_family == AF_INET6) &&
2432225549Stuexen					    (net->flowlabel & 0x80000000)) {
2433225549Stuexen						paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff;
2434163953Srrs						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2435163953Srrs					}
2436163953Srrs#endif
2437163953Srrs				} else {
2438163953Srrs					/*
2439163953Srrs					 * No destination so return default
2440163953Srrs					 * value
2441163953Srrs					 */
2442163953Srrs					paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
2443163953Srrs					paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
2444225549Stuexen					if (stcb->asoc.default_dscp & 0x01) {
2445226252Stuexen						paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
2446225549Stuexen						paddrp->spp_flags |= SPP_DSCP;
2447225549Stuexen					}
2448167598Srrs#ifdef INET6
2449225549Stuexen					if (stcb->asoc.default_flowlabel & 0x80000000) {
2450225549Stuexen						paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff;
2451225549Stuexen						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2452225549Stuexen					}
2453163953Srrs#endif
2454163953Srrs					/* default settings should be these */
2455225635Stuexen					if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2456224641Stuexen						paddrp->spp_flags |= SPP_HB_DISABLE;
2457224641Stuexen					} else {
2458163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2459163953Srrs					}
2460225635Stuexen					if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
2461225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2462225635Stuexen					} else {
2463170056Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2464170056Srrs					}
2465225635Stuexen					paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
2466163953Srrs				}
2467163953Srrs				paddrp->spp_assoc_id = sctp_get_associd(stcb);
2468163953Srrs				SCTP_TCB_UNLOCK(stcb);
2469163953Srrs			} else {
2470224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2471224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2472224918Stuexen				    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
2473223132Stuexen					/* Use endpoint defaults */
2474223132Stuexen					SCTP_INP_RLOCK(inp);
2475223132Stuexen					paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
2476223132Stuexen					paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
2477223132Stuexen					paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
2478223132Stuexen					/* get inp's default */
2479225549Stuexen					if (inp->sctp_ep.default_dscp & 0x01) {
2480226252Stuexen						paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc;
2481225549Stuexen						paddrp->spp_flags |= SPP_DSCP;
2482225549Stuexen					}
2483167598Srrs#ifdef INET6
2484225549Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
2485225549Stuexen					    (inp->sctp_ep.default_flowlabel & 0x80000000)) {
2486225549Stuexen						paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff;
2487223132Stuexen						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2488223132Stuexen					}
2489163953Srrs#endif
2490223132Stuexen					/* can't return this */
2491223132Stuexen					paddrp->spp_pathmtu = 0;
2492170056Srrs
2493223132Stuexen					if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2494223132Stuexen						paddrp->spp_flags |= SPP_HB_ENABLE;
2495223132Stuexen					} else {
2496223132Stuexen						paddrp->spp_flags |= SPP_HB_DISABLE;
2497223132Stuexen					}
2498225635Stuexen					if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
2499225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2500225635Stuexen					} else {
2501225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2502225635Stuexen					}
2503223132Stuexen					SCTP_INP_RUNLOCK(inp);
2504170056Srrs				} else {
2505223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2506223132Stuexen					error = EINVAL;
2507170056Srrs				}
2508163953Srrs			}
2509223132Stuexen			if (error == 0) {
2510223132Stuexen				*optsize = sizeof(struct sctp_paddrparams);
2511223132Stuexen			}
2512223132Stuexen			break;
2513163953Srrs		}
2514163953Srrs	case SCTP_GET_PEER_ADDR_INFO:
2515163953Srrs		{
2516163953Srrs			struct sctp_paddrinfo *paddri;
2517163953Srrs			struct sctp_nets *net;
2518163953Srrs
2519166675Srrs			SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
2520166675Srrs			SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
2521166675Srrs
2522163953Srrs			net = NULL;
2523166675Srrs			if (stcb) {
2524166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address);
2525166675Srrs			} else {
2526166675Srrs				/*
2527166675Srrs				 * We increment here since
2528166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2529166675Srrs				 * decrement if it finds the stcb as long as
2530166675Srrs				 * the locked tcb (last argument) is NOT a
2531166675Srrs				 * TCB.. aka NULL.
2532166675Srrs				 */
2533166675Srrs				SCTP_INP_INCR_REF(inp);
2534166675Srrs				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL);
2535166675Srrs				if (stcb == NULL) {
2536166675Srrs					SCTP_INP_DECR_REF(inp);
2537163953Srrs				}
2538166675Srrs			}
2539163953Srrs
2540166675Srrs			if ((stcb) && (net)) {
2541217635Srrs				if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2542217638Stuexen					/* It's unconfirmed */
2543217635Srrs					paddri->spinfo_state = SCTP_UNCONFIRMED;
2544217635Srrs				} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2545217638Stuexen					/* It's active */
2546217635Srrs					paddri->spinfo_state = SCTP_ACTIVE;
2547217635Srrs				} else {
2548217638Stuexen					/* It's inactive */
2549217635Srrs					paddri->spinfo_state = SCTP_INACTIVE;
2550217635Srrs				}
2551166675Srrs				paddri->spinfo_cwnd = net->cwnd;
2552219014Stuexen				paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2553166675Srrs				paddri->spinfo_rto = net->RTO;
2554166675Srrs				paddri->spinfo_assoc_id = sctp_get_associd(stcb);
2555222029Stuexen				paddri->spinfo_mtu = net->mtu;
2556166675Srrs				SCTP_TCB_UNLOCK(stcb);
2557223132Stuexen				*optsize = sizeof(struct sctp_paddrinfo);
2558163953Srrs			} else {
2559163953Srrs				if (stcb) {
2560163953Srrs					SCTP_TCB_UNLOCK(stcb);
2561163953Srrs				}
2562171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2563163953Srrs				error = ENOENT;
2564163953Srrs			}
2565223132Stuexen			break;
2566163953Srrs		}
2567163953Srrs	case SCTP_PCB_STATUS:
2568163953Srrs		{
2569163953Srrs			struct sctp_pcbinfo *spcb;
2570163953Srrs
2571166675Srrs			SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
2572163953Srrs			sctp_fill_pcbinfo(spcb);
2573166675Srrs			*optsize = sizeof(struct sctp_pcbinfo);
2574223132Stuexen			break;
2575163953Srrs		}
2576163953Srrs	case SCTP_STATUS:
2577163953Srrs		{
2578163953Srrs			struct sctp_nets *net;
2579163953Srrs			struct sctp_status *sstat;
2580163953Srrs
2581166675Srrs			SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
2582166675Srrs			SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
2583163953Srrs
2584163953Srrs			if (stcb == NULL) {
2585223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2586163953Srrs				error = EINVAL;
2587163953Srrs				break;
2588163953Srrs			}
2589163953Srrs			/*
2590163953Srrs			 * I think passing the state is fine since
2591163953Srrs			 * sctp_constants.h will be available to the user
2592163953Srrs			 * land.
2593163953Srrs			 */
2594163953Srrs			sstat->sstat_state = stcb->asoc.state;
2595173179Srrs			sstat->sstat_assoc_id = sctp_get_associd(stcb);
2596163953Srrs			sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
2597163953Srrs			sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
2598163953Srrs			/*
2599163953Srrs			 * We can't include chunks that have been passed to
2600163953Srrs			 * the socket layer. Only things in queue.
2601163953Srrs			 */
2602163953Srrs			sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
2603163953Srrs			    stcb->asoc.cnt_on_all_streams);
2604163953Srrs
2605163953Srrs
2606163953Srrs			sstat->sstat_instrms = stcb->asoc.streamincnt;
2607163953Srrs			sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
2608163953Srrs			sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
2609163953Srrs			memcpy(&sstat->sstat_primary.spinfo_address,
2610163953Srrs			    &stcb->asoc.primary_destination->ro._l_addr,
2611163953Srrs			    ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
2612163953Srrs			net = stcb->asoc.primary_destination;
2613163953Srrs			((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
2614163953Srrs			/*
2615163953Srrs			 * Again the user can get info from sctp_constants.h
2616163953Srrs			 * for what the state of the network is.
2617163953Srrs			 */
2618217635Srrs			if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2619217635Srrs				/* It's unconfirmed */
2620217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
2621217635Srrs			} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2622217638Stuexen				/* It's active */
2623217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
2624217635Srrs			} else {
2625217638Stuexen				/* It's inactive */
2626217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
2627217635Srrs			}
2628163953Srrs			sstat->sstat_primary.spinfo_cwnd = net->cwnd;
2629219014Stuexen			sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2630163953Srrs			sstat->sstat_primary.spinfo_rto = net->RTO;
2631163953Srrs			sstat->sstat_primary.spinfo_mtu = net->mtu;
2632163953Srrs			sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
2633163953Srrs			SCTP_TCB_UNLOCK(stcb);
2634223132Stuexen			*optsize = sizeof(struct sctp_status);
2635223132Stuexen			break;
2636163953Srrs		}
2637163953Srrs	case SCTP_RTOINFO:
2638163953Srrs		{
2639163953Srrs			struct sctp_rtoinfo *srto;
2640163953Srrs
2641166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
2642166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
2643166675Srrs
2644166675Srrs			if (stcb) {
2645166675Srrs				srto->srto_initial = stcb->asoc.initial_rto;
2646166675Srrs				srto->srto_max = stcb->asoc.maxrto;
2647166675Srrs				srto->srto_min = stcb->asoc.minrto;
2648166675Srrs				SCTP_TCB_UNLOCK(stcb);
2649166675Srrs			} else {
2650224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2651224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2652224918Stuexen				    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
2653223132Stuexen					SCTP_INP_RLOCK(inp);
2654223132Stuexen					srto->srto_initial = inp->sctp_ep.initial_rto;
2655223132Stuexen					srto->srto_max = inp->sctp_ep.sctp_maxrto;
2656223132Stuexen					srto->srto_min = inp->sctp_ep.sctp_minrto;
2657223132Stuexen					SCTP_INP_RUNLOCK(inp);
2658223132Stuexen				} else {
2659223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2660223132Stuexen					error = EINVAL;
2661223132Stuexen				}
2662163953Srrs			}
2663223132Stuexen			if (error == 0) {
2664223132Stuexen				*optsize = sizeof(struct sctp_rtoinfo);
2665223132Stuexen			}
2666223132Stuexen			break;
2667163953Srrs		}
2668215410Stuexen	case SCTP_TIMEOUTS:
2669215410Stuexen		{
2670215410Stuexen			struct sctp_timeouts *stimo;
2671215410Stuexen
2672215410Stuexen			SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize);
2673215410Stuexen			SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id);
2674215410Stuexen
2675215410Stuexen			if (stcb) {
2676215410Stuexen				stimo->stimo_init = stcb->asoc.timoinit;
2677215410Stuexen				stimo->stimo_data = stcb->asoc.timodata;
2678215410Stuexen				stimo->stimo_sack = stcb->asoc.timosack;
2679215410Stuexen				stimo->stimo_shutdown = stcb->asoc.timoshutdown;
2680215410Stuexen				stimo->stimo_heartbeat = stcb->asoc.timoheartbeat;
2681215410Stuexen				stimo->stimo_cookie = stcb->asoc.timocookie;
2682215410Stuexen				stimo->stimo_shutdownack = stcb->asoc.timoshutdownack;
2683215410Stuexen				SCTP_TCB_UNLOCK(stcb);
2684223132Stuexen				*optsize = sizeof(struct sctp_timeouts);
2685215410Stuexen			} else {
2686223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2687215410Stuexen				error = EINVAL;
2688215410Stuexen			}
2689223132Stuexen			break;
2690215410Stuexen		}
2691163953Srrs	case SCTP_ASSOCINFO:
2692163953Srrs		{
2693163953Srrs			struct sctp_assocparams *sasoc;
2694163953Srrs
2695166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
2696166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
2697163953Srrs
2698163953Srrs			if (stcb) {
2699171477Srrs				sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
2700163953Srrs				sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
2701163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
2702163953Srrs				sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
2703163953Srrs				sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
2704163953Srrs				SCTP_TCB_UNLOCK(stcb);
2705163953Srrs			} else {
2706224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2707224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2708224918Stuexen				    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
2709223132Stuexen					SCTP_INP_RLOCK(inp);
2710223132Stuexen					sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
2711223132Stuexen					sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
2712223132Stuexen					sasoc->sasoc_number_peer_destinations = 0;
2713223132Stuexen					sasoc->sasoc_peer_rwnd = 0;
2714223132Stuexen					sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
2715223132Stuexen					SCTP_INP_RUNLOCK(inp);
2716223132Stuexen				} else {
2717223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2718223132Stuexen					error = EINVAL;
2719223132Stuexen				}
2720163953Srrs			}
2721223132Stuexen			if (error == 0) {
2722223132Stuexen				*optsize = sizeof(struct sctp_assocparams);
2723223132Stuexen			}
2724223132Stuexen			break;
2725163953Srrs		}
2726163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
2727163953Srrs		{
2728163953Srrs			struct sctp_sndrcvinfo *s_info;
2729163953Srrs
2730166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
2731166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
2732166675Srrs
2733166675Srrs			if (stcb) {
2734170056Srrs				memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
2735166675Srrs				SCTP_TCB_UNLOCK(stcb);
2736166675Srrs			} else {
2737224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2738224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2739224918Stuexen				    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) {
2740223132Stuexen					SCTP_INP_RLOCK(inp);
2741223132Stuexen					memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
2742223132Stuexen					SCTP_INP_RUNLOCK(inp);
2743223132Stuexen				} else {
2744223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2745223132Stuexen					error = EINVAL;
2746223132Stuexen				}
2747163953Srrs			}
2748223132Stuexen			if (error == 0) {
2749223132Stuexen				*optsize = sizeof(struct sctp_sndrcvinfo);
2750223132Stuexen			}
2751223132Stuexen			break;
2752163953Srrs		}
2753163953Srrs	case SCTP_INITMSG:
2754163953Srrs		{
2755163953Srrs			struct sctp_initmsg *sinit;
2756163953Srrs
2757166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
2758163953Srrs			SCTP_INP_RLOCK(inp);
2759163953Srrs			sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
2760163953Srrs			sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
2761163953Srrs			sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
2762163953Srrs			sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
2763163953Srrs			SCTP_INP_RUNLOCK(inp);
2764223132Stuexen			*optsize = sizeof(struct sctp_initmsg);
2765223132Stuexen			break;
2766163953Srrs		}
2767163953Srrs	case SCTP_PRIMARY_ADDR:
2768163953Srrs		/* we allow a "get" operation on this */
2769163953Srrs		{
2770163953Srrs			struct sctp_setprim *ssp;
2771163953Srrs
2772166675Srrs			SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
2773166675Srrs			SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
2774166675Srrs
2775166675Srrs			if (stcb) {
2776166675Srrs				/* simply copy out the sockaddr_storage... */
2777260426Stuexen				size_t len;
2778170056Srrs
2779170056Srrs				len = *optsize;
2780170056Srrs				if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len)
2781170056Srrs					len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len;
2782170056Srrs
2783170056Srrs				memcpy(&ssp->ssp_addr,
2784170056Srrs				    &stcb->asoc.primary_destination->ro._l_addr,
2785170056Srrs				    len);
2786166675Srrs				SCTP_TCB_UNLOCK(stcb);
2787223132Stuexen				*optsize = sizeof(struct sctp_setprim);
2788166675Srrs			} else {
2789223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2790163953Srrs				error = EINVAL;
2791163953Srrs			}
2792223132Stuexen			break;
2793163953Srrs		}
2794163953Srrs	case SCTP_HMAC_IDENT:
2795163953Srrs		{
2796163953Srrs			struct sctp_hmacalgo *shmac;
2797163953Srrs			sctp_hmaclist_t *hmaclist;
2798163953Srrs			uint32_t size;
2799163953Srrs			int i;
2800163953Srrs
2801166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
2802166675Srrs
2803163953Srrs			SCTP_INP_RLOCK(inp);
2804163953Srrs			hmaclist = inp->sctp_ep.local_hmacs;
2805163953Srrs			if (hmaclist == NULL) {
2806163953Srrs				/* no HMACs to return */
2807166675Srrs				*optsize = sizeof(*shmac);
2808168299Srrs				SCTP_INP_RUNLOCK(inp);
2809163953Srrs				break;
2810163953Srrs			}
2811163953Srrs			/* is there room for all of the hmac ids? */
2812163953Srrs			size = sizeof(*shmac) + (hmaclist->num_algo *
2813163953Srrs			    sizeof(shmac->shmac_idents[0]));
2814166675Srrs			if ((size_t)(*optsize) < size) {
2815223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2816163953Srrs				error = EINVAL;
2817163953Srrs				SCTP_INP_RUNLOCK(inp);
2818163953Srrs				break;
2819163953Srrs			}
2820163953Srrs			/* copy in the list */
2821181054Srrs			shmac->shmac_number_of_idents = hmaclist->num_algo;
2822181054Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
2823163953Srrs				shmac->shmac_idents[i] = hmaclist->hmac[i];
2824181054Srrs			}
2825163953Srrs			SCTP_INP_RUNLOCK(inp);
2826166675Srrs			*optsize = size;
2827163953Srrs			break;
2828163953Srrs		}
2829163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
2830163953Srrs		{
2831163953Srrs			struct sctp_authkeyid *scact;
2832163953Srrs
2833166675Srrs			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
2834166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
2835166675Srrs
2836166675Srrs			if (stcb) {
2837163953Srrs				/* get the active key on the assoc */
2838185694Srrs				scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
2839163953Srrs				SCTP_TCB_UNLOCK(stcb);
2840163953Srrs			} else {
2841224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2842224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2843224918Stuexen				    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) {
2844223132Stuexen					/* get the endpoint active key */
2845223132Stuexen					SCTP_INP_RLOCK(inp);
2846223132Stuexen					scact->scact_keynumber = inp->sctp_ep.default_keyid;
2847223132Stuexen					SCTP_INP_RUNLOCK(inp);
2848223132Stuexen				} else {
2849223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2850223132Stuexen					error = EINVAL;
2851223132Stuexen				}
2852163953Srrs			}
2853223132Stuexen			if (error == 0) {
2854223132Stuexen				*optsize = sizeof(struct sctp_authkeyid);
2855223132Stuexen			}
2856163953Srrs			break;
2857163953Srrs		}
2858163953Srrs	case SCTP_LOCAL_AUTH_CHUNKS:
2859163953Srrs		{
2860163953Srrs			struct sctp_authchunks *sac;
2861163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2862166675Srrs			size_t size = 0;
2863163953Srrs
2864166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2865166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2866166675Srrs
2867166675Srrs			if (stcb) {
2868163953Srrs				/* get off the assoc */
2869163953Srrs				chklist = stcb->asoc.local_auth_chunks;
2870163953Srrs				/* is there enough space? */
2871163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2872166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2873163953Srrs					error = EINVAL;
2874171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2875166675Srrs				} else {
2876166675Srrs					/* copy in the chunks */
2877169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2878234832Stuexen					sac->gauth_number_of_chunks = (uint32_t) size;
2879223132Stuexen					*optsize = sizeof(struct sctp_authchunks) + size;
2880163953Srrs				}
2881163953Srrs				SCTP_TCB_UNLOCK(stcb);
2882163953Srrs			} else {
2883224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2884224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2885224918Stuexen				    (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) {
2886223132Stuexen					/* get off the endpoint */
2887223132Stuexen					SCTP_INP_RLOCK(inp);
2888223132Stuexen					chklist = inp->sctp_ep.local_auth_chunks;
2889223132Stuexen					/* is there enough space? */
2890223132Stuexen					size = sctp_auth_get_chklist_size(chklist);
2891223132Stuexen					if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2892223132Stuexen						error = EINVAL;
2893223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2894223132Stuexen					} else {
2895223132Stuexen						/* copy in the chunks */
2896223132Stuexen						(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2897234832Stuexen						sac->gauth_number_of_chunks = (uint32_t) size;
2898223132Stuexen						*optsize = sizeof(struct sctp_authchunks) + size;
2899223132Stuexen					}
2900223132Stuexen					SCTP_INP_RUNLOCK(inp);
2901223132Stuexen				} else {
2902223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2903163953Srrs					error = EINVAL;
2904163953Srrs				}
2905163953Srrs			}
2906163953Srrs			break;
2907163953Srrs		}
2908163953Srrs	case SCTP_PEER_AUTH_CHUNKS:
2909163953Srrs		{
2910163953Srrs			struct sctp_authchunks *sac;
2911163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2912166675Srrs			size_t size = 0;
2913163953Srrs
2914166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2915166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2916166675Srrs
2917166675Srrs			if (stcb) {
2918166675Srrs				/* get off the assoc */
2919166675Srrs				chklist = stcb->asoc.peer_auth_chunks;
2920166675Srrs				/* is there enough space? */
2921166675Srrs				size = sctp_auth_get_chklist_size(chklist);
2922166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2923166675Srrs					error = EINVAL;
2924171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2925166675Srrs				} else {
2926166675Srrs					/* copy in the chunks */
2927169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2928234832Stuexen					sac->gauth_number_of_chunks = (uint32_t) size;
2929223132Stuexen					*optsize = sizeof(struct sctp_authchunks) + size;
2930166675Srrs				}
2931166675Srrs				SCTP_TCB_UNLOCK(stcb);
2932166675Srrs			} else {
2933171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2934163953Srrs				error = ENOENT;
2935163953Srrs			}
2936163953Srrs			break;
2937163953Srrs		}
2938223132Stuexen	case SCTP_EVENT:
2939223132Stuexen		{
2940223132Stuexen			struct sctp_event *event;
2941223132Stuexen			uint32_t event_type;
2942163953Srrs
2943223132Stuexen			SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize);
2944223132Stuexen			SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
2945163953Srrs
2946223132Stuexen			switch (event->se_type) {
2947223132Stuexen			case SCTP_ASSOC_CHANGE:
2948223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
2949223132Stuexen				break;
2950223132Stuexen			case SCTP_PEER_ADDR_CHANGE:
2951223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
2952223132Stuexen				break;
2953223132Stuexen			case SCTP_REMOTE_ERROR:
2954223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPEERERR;
2955223132Stuexen				break;
2956223132Stuexen			case SCTP_SEND_FAILED:
2957223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
2958223132Stuexen				break;
2959223132Stuexen			case SCTP_SHUTDOWN_EVENT:
2960223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
2961223132Stuexen				break;
2962223132Stuexen			case SCTP_ADAPTATION_INDICATION:
2963223132Stuexen				event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
2964223132Stuexen				break;
2965223132Stuexen			case SCTP_PARTIAL_DELIVERY_EVENT:
2966223132Stuexen				event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
2967223132Stuexen				break;
2968223132Stuexen			case SCTP_AUTHENTICATION_EVENT:
2969223132Stuexen				event_type = SCTP_PCB_FLAGS_AUTHEVNT;
2970223132Stuexen				break;
2971223132Stuexen			case SCTP_STREAM_RESET_EVENT:
2972223132Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
2973223132Stuexen				break;
2974223132Stuexen			case SCTP_SENDER_DRY_EVENT:
2975223132Stuexen				event_type = SCTP_PCB_FLAGS_DRYEVNT;
2976223132Stuexen				break;
2977223132Stuexen			case SCTP_NOTIFICATIONS_STOPPED_EVENT:
2978223132Stuexen				event_type = 0;
2979223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
2980223132Stuexen				error = ENOTSUP;
2981223132Stuexen				break;
2982235009Stuexen			case SCTP_ASSOC_RESET_EVENT:
2983235009Stuexen				event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
2984235009Stuexen				break;
2985235009Stuexen			case SCTP_STREAM_CHANGE_EVENT:
2986235009Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
2987235009Stuexen				break;
2988235075Stuexen			case SCTP_SEND_FAILED_EVENT:
2989235075Stuexen				event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
2990235075Stuexen				break;
2991223132Stuexen			default:
2992223132Stuexen				event_type = 0;
2993223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2994223132Stuexen				error = EINVAL;
2995223132Stuexen				break;
2996223132Stuexen			}
2997223132Stuexen			if (event_type > 0) {
2998223132Stuexen				if (stcb) {
2999223132Stuexen					event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
3000223132Stuexen					SCTP_TCB_UNLOCK(stcb);
3001223132Stuexen				} else {
3002224918Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3003224918Stuexen					    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3004224918Stuexen					    (event->se_assoc_id == SCTP_FUTURE_ASSOC)) {
3005223132Stuexen						SCTP_INP_RLOCK(inp);
3006223132Stuexen						event->se_on = sctp_is_feature_on(inp, event_type);
3007223132Stuexen						SCTP_INP_RUNLOCK(inp);
3008223132Stuexen					} else {
3009223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3010223132Stuexen						error = EINVAL;
3011223132Stuexen					}
3012223132Stuexen				}
3013223132Stuexen			}
3014223132Stuexen			if (error == 0) {
3015223132Stuexen				*optsize = sizeof(struct sctp_event);
3016223132Stuexen			}
3017223132Stuexen			break;
3018223132Stuexen		}
3019223132Stuexen	case SCTP_RECVRCVINFO:
3020223132Stuexen		{
3021223132Stuexen			int onoff;
3022223132Stuexen
3023223132Stuexen			if (*optsize < sizeof(int)) {
3024223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3025223132Stuexen				error = EINVAL;
3026223132Stuexen			} else {
3027230104Stuexen				SCTP_INP_RLOCK(inp);
3028223132Stuexen				onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
3029223132Stuexen				SCTP_INP_RUNLOCK(inp);
3030223132Stuexen			}
3031223132Stuexen			if (error == 0) {
3032223132Stuexen				/* return the option value */
3033223132Stuexen				*(int *)optval = onoff;
3034223132Stuexen				*optsize = sizeof(int);
3035223132Stuexen			}
3036223132Stuexen			break;
3037223132Stuexen		}
3038223132Stuexen	case SCTP_RECVNXTINFO:
3039223132Stuexen		{
3040223132Stuexen			int onoff;
3041223132Stuexen
3042223132Stuexen			if (*optsize < sizeof(int)) {
3043223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3044223132Stuexen				error = EINVAL;
3045223132Stuexen			} else {
3046230104Stuexen				SCTP_INP_RLOCK(inp);
3047223132Stuexen				onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
3048223132Stuexen				SCTP_INP_RUNLOCK(inp);
3049223132Stuexen			}
3050223132Stuexen			if (error == 0) {
3051223132Stuexen				/* return the option value */
3052223132Stuexen				*(int *)optval = onoff;
3053223132Stuexen				*optsize = sizeof(int);
3054223132Stuexen			}
3055223132Stuexen			break;
3056223132Stuexen		}
3057223132Stuexen	case SCTP_DEFAULT_SNDINFO:
3058223132Stuexen		{
3059223132Stuexen			struct sctp_sndinfo *info;
3060223132Stuexen
3061223132Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize);
3062223132Stuexen			SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
3063223132Stuexen
3064223132Stuexen			if (stcb) {
3065223132Stuexen				info->snd_sid = stcb->asoc.def_send.sinfo_stream;
3066223132Stuexen				info->snd_flags = stcb->asoc.def_send.sinfo_flags;
3067223162Stuexen				info->snd_flags &= 0xfff0;
3068223132Stuexen				info->snd_ppid = stcb->asoc.def_send.sinfo_ppid;
3069223132Stuexen				info->snd_context = stcb->asoc.def_send.sinfo_context;
3070223132Stuexen				SCTP_TCB_UNLOCK(stcb);
3071223132Stuexen			} else {
3072224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3073224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3074224918Stuexen				    (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) {
3075223132Stuexen					SCTP_INP_RLOCK(inp);
3076223132Stuexen					info->snd_sid = inp->def_send.sinfo_stream;
3077223132Stuexen					info->snd_flags = inp->def_send.sinfo_flags;
3078223162Stuexen					info->snd_flags &= 0xfff0;
3079223132Stuexen					info->snd_ppid = inp->def_send.sinfo_ppid;
3080223132Stuexen					info->snd_context = inp->def_send.sinfo_context;
3081223132Stuexen					SCTP_INP_RUNLOCK(inp);
3082223132Stuexen				} else {
3083223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3084223132Stuexen					error = EINVAL;
3085223132Stuexen				}
3086223132Stuexen			}
3087223132Stuexen			if (error == 0) {
3088223132Stuexen				*optsize = sizeof(struct sctp_sndinfo);
3089223132Stuexen			}
3090223132Stuexen			break;
3091223132Stuexen		}
3092223162Stuexen	case SCTP_DEFAULT_PRINFO:
3093223162Stuexen		{
3094223162Stuexen			struct sctp_default_prinfo *info;
3095223162Stuexen
3096223162Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize);
3097223162Stuexen			SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
3098223162Stuexen
3099223162Stuexen			if (stcb) {
3100223162Stuexen				info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
3101223162Stuexen				info->pr_value = stcb->asoc.def_send.sinfo_timetolive;
3102223162Stuexen				SCTP_TCB_UNLOCK(stcb);
3103223162Stuexen			} else {
3104224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3105224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3106224918Stuexen				    (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) {
3107223162Stuexen					SCTP_INP_RLOCK(inp);
3108223162Stuexen					info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
3109223162Stuexen					info->pr_value = inp->def_send.sinfo_timetolive;
3110223162Stuexen					SCTP_INP_RUNLOCK(inp);
3111223162Stuexen				} else {
3112223162Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3113223162Stuexen					error = EINVAL;
3114223162Stuexen				}
3115223162Stuexen			}
3116223162Stuexen			if (error == 0) {
3117223162Stuexen				*optsize = sizeof(struct sctp_default_prinfo);
3118223162Stuexen			}
3119223162Stuexen			break;
3120223162Stuexen		}
3121224641Stuexen	case SCTP_PEER_ADDR_THLDS:
3122224641Stuexen		{
3123224641Stuexen			struct sctp_paddrthlds *thlds;
3124224641Stuexen			struct sctp_nets *net;
3125224641Stuexen
3126224641Stuexen			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
3127224641Stuexen			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
3128224641Stuexen
3129224641Stuexen			net = NULL;
3130224641Stuexen			if (stcb) {
3131224641Stuexen				net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address);
3132224641Stuexen			} else {
3133224641Stuexen				/*
3134224641Stuexen				 * We increment here since
3135224641Stuexen				 * sctp_findassociation_ep_addr() wil do a
3136224641Stuexen				 * decrement if it finds the stcb as long as
3137224641Stuexen				 * the locked tcb (last argument) is NOT a
3138224641Stuexen				 * TCB.. aka NULL.
3139224641Stuexen				 */
3140224641Stuexen				SCTP_INP_INCR_REF(inp);
3141224641Stuexen				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL);
3142224641Stuexen				if (stcb == NULL) {
3143224641Stuexen					SCTP_INP_DECR_REF(inp);
3144224641Stuexen				}
3145224641Stuexen			}
3146224641Stuexen			if (stcb && (net == NULL)) {
3147224641Stuexen				struct sockaddr *sa;
3148224641Stuexen
3149224641Stuexen				sa = (struct sockaddr *)&thlds->spt_address;
3150224641Stuexen#ifdef INET
3151224641Stuexen				if (sa->sa_family == AF_INET) {
3152224641Stuexen					struct sockaddr_in *sin;
3153224641Stuexen
3154224641Stuexen					sin = (struct sockaddr_in *)sa;
3155224641Stuexen					if (sin->sin_addr.s_addr) {
3156224641Stuexen						error = EINVAL;
3157224641Stuexen						SCTP_TCB_UNLOCK(stcb);
3158224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3159224641Stuexen						break;
3160224641Stuexen					}
3161224641Stuexen				} else
3162224641Stuexen#endif
3163224641Stuexen#ifdef INET6
3164224641Stuexen				if (sa->sa_family == AF_INET6) {
3165224641Stuexen					struct sockaddr_in6 *sin6;
3166224641Stuexen
3167224641Stuexen					sin6 = (struct sockaddr_in6 *)sa;
3168224641Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3169224641Stuexen						error = EINVAL;
3170224641Stuexen						SCTP_TCB_UNLOCK(stcb);
3171224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3172224641Stuexen						break;
3173224641Stuexen					}
3174224641Stuexen				} else
3175224641Stuexen#endif
3176224641Stuexen				{
3177224641Stuexen					error = EAFNOSUPPORT;
3178224641Stuexen					SCTP_TCB_UNLOCK(stcb);
3179224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3180224641Stuexen					break;
3181224641Stuexen				}
3182224641Stuexen			}
3183224641Stuexen			if (stcb) {
3184224641Stuexen				if (net) {
3185224641Stuexen					thlds->spt_pathmaxrxt = net->failure_threshold;
3186224641Stuexen					thlds->spt_pathpfthld = net->pf_threshold;
3187224641Stuexen				} else {
3188224641Stuexen					thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
3189224641Stuexen					thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
3190224641Stuexen				}
3191224641Stuexen				thlds->spt_assoc_id = sctp_get_associd(stcb);
3192224641Stuexen				SCTP_TCB_UNLOCK(stcb);
3193224641Stuexen			} else {
3194224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3195224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3196224918Stuexen				    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
3197224641Stuexen					/* Use endpoint defaults */
3198224641Stuexen					SCTP_INP_RLOCK(inp);
3199224641Stuexen					thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
3200224641Stuexen					thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
3201224641Stuexen					SCTP_INP_RUNLOCK(inp);
3202224641Stuexen				} else {
3203224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3204224641Stuexen					error = EINVAL;
3205224641Stuexen				}
3206224641Stuexen			}
3207224641Stuexen			if (error == 0) {
3208224641Stuexen				*optsize = sizeof(struct sctp_paddrthlds);
3209224641Stuexen			}
3210224641Stuexen			break;
3211224641Stuexen		}
3212227755Stuexen	case SCTP_REMOTE_UDP_ENCAPS_PORT:
3213227755Stuexen		{
3214227755Stuexen			struct sctp_udpencaps *encaps;
3215227755Stuexen			struct sctp_nets *net;
3216227755Stuexen
3217227755Stuexen			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize);
3218227755Stuexen			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
3219227755Stuexen
3220227755Stuexen			if (stcb) {
3221227755Stuexen				net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address);
3222227755Stuexen			} else {
3223227755Stuexen				/*
3224227755Stuexen				 * We increment here since
3225227755Stuexen				 * sctp_findassociation_ep_addr() wil do a
3226227755Stuexen				 * decrement if it finds the stcb as long as
3227227755Stuexen				 * the locked tcb (last argument) is NOT a
3228227755Stuexen				 * TCB.. aka NULL.
3229227755Stuexen				 */
3230227755Stuexen				net = NULL;
3231227755Stuexen				SCTP_INP_INCR_REF(inp);
3232227755Stuexen				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL);
3233227755Stuexen				if (stcb == NULL) {
3234227755Stuexen					SCTP_INP_DECR_REF(inp);
3235227755Stuexen				}
3236227755Stuexen			}
3237227755Stuexen			if (stcb && (net == NULL)) {
3238227755Stuexen				struct sockaddr *sa;
3239227755Stuexen
3240227755Stuexen				sa = (struct sockaddr *)&encaps->sue_address;
3241227755Stuexen#ifdef INET
3242227755Stuexen				if (sa->sa_family == AF_INET) {
3243227755Stuexen					struct sockaddr_in *sin;
3244227755Stuexen
3245227755Stuexen					sin = (struct sockaddr_in *)sa;
3246227755Stuexen					if (sin->sin_addr.s_addr) {
3247227755Stuexen						error = EINVAL;
3248227755Stuexen						SCTP_TCB_UNLOCK(stcb);
3249227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3250227755Stuexen						break;
3251227755Stuexen					}
3252227755Stuexen				} else
3253227755Stuexen#endif
3254227755Stuexen#ifdef INET6
3255227755Stuexen				if (sa->sa_family == AF_INET6) {
3256227755Stuexen					struct sockaddr_in6 *sin6;
3257227755Stuexen
3258227755Stuexen					sin6 = (struct sockaddr_in6 *)sa;
3259227755Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3260227755Stuexen						error = EINVAL;
3261227755Stuexen						SCTP_TCB_UNLOCK(stcb);
3262227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3263227755Stuexen						break;
3264227755Stuexen					}
3265227755Stuexen				} else
3266227755Stuexen#endif
3267227755Stuexen				{
3268227755Stuexen					error = EAFNOSUPPORT;
3269227755Stuexen					SCTP_TCB_UNLOCK(stcb);
3270227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3271227755Stuexen					break;
3272227755Stuexen				}
3273227755Stuexen			}
3274227755Stuexen			if (stcb) {
3275227755Stuexen				if (net) {
3276227755Stuexen					encaps->sue_port = net->port;
3277227755Stuexen				} else {
3278227755Stuexen					encaps->sue_port = stcb->asoc.port;
3279227755Stuexen				}
3280227755Stuexen				SCTP_TCB_UNLOCK(stcb);
3281227755Stuexen			} else {
3282227755Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3283227755Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3284227755Stuexen				    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
3285227755Stuexen					SCTP_INP_RLOCK(inp);
3286227755Stuexen					encaps->sue_port = inp->sctp_ep.port;
3287227755Stuexen					SCTP_INP_RUNLOCK(inp);
3288227755Stuexen				} else {
3289227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3290227755Stuexen					error = EINVAL;
3291227755Stuexen				}
3292227755Stuexen			}
3293227755Stuexen			if (error == 0) {
3294258454Stuexen				*optsize = sizeof(struct sctp_udpencaps);
3295227755Stuexen			}
3296227755Stuexen			break;
3297227755Stuexen		}
3298270356Stuexen	case SCTP_ECN_SUPPORTED:
3299270356Stuexen		{
3300270356Stuexen			struct sctp_assoc_value *av;
3301270356Stuexen
3302270356Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3303270356Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3304270356Stuexen
3305270356Stuexen			if (stcb) {
3306270356Stuexen				av->assoc_value = stcb->asoc.ecn_supported;
3307270356Stuexen				SCTP_TCB_UNLOCK(stcb);
3308270356Stuexen			} else {
3309270356Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3310270356Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3311270356Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3312270356Stuexen					SCTP_INP_RLOCK(inp);
3313270356Stuexen					av->assoc_value = inp->ecn_supported;
3314270356Stuexen					SCTP_INP_RUNLOCK(inp);
3315270356Stuexen				} else {
3316270356Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3317270356Stuexen					error = EINVAL;
3318270356Stuexen				}
3319270356Stuexen			}
3320270356Stuexen			if (error == 0) {
3321270356Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3322270356Stuexen			}
3323270356Stuexen			break;
3324270356Stuexen		}
3325270357Stuexen	case SCTP_PR_SUPPORTED:
3326270357Stuexen		{
3327270357Stuexen			struct sctp_assoc_value *av;
3328270357Stuexen
3329270357Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3330270357Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3331270357Stuexen
3332270357Stuexen			if (stcb) {
3333270357Stuexen				av->assoc_value = stcb->asoc.prsctp_supported;
3334270357Stuexen				SCTP_TCB_UNLOCK(stcb);
3335270357Stuexen			} else {
3336270357Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3337270357Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3338270357Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3339270357Stuexen					SCTP_INP_RLOCK(inp);
3340270357Stuexen					av->assoc_value = inp->prsctp_supported;
3341270357Stuexen					SCTP_INP_RUNLOCK(inp);
3342270357Stuexen				} else {
3343270357Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3344270357Stuexen					error = EINVAL;
3345270357Stuexen				}
3346270357Stuexen			}
3347270357Stuexen			if (error == 0) {
3348270357Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3349270357Stuexen			}
3350270357Stuexen			break;
3351270357Stuexen		}
3352270362Stuexen	case SCTP_AUTH_SUPPORTED:
3353270362Stuexen		{
3354270362Stuexen			struct sctp_assoc_value *av;
3355270362Stuexen
3356270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3357270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3358270362Stuexen
3359270362Stuexen			if (stcb) {
3360270362Stuexen				av->assoc_value = stcb->asoc.auth_supported;
3361270362Stuexen				SCTP_TCB_UNLOCK(stcb);
3362270362Stuexen			} else {
3363270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3364270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3365270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3366270362Stuexen					SCTP_INP_RLOCK(inp);
3367270362Stuexen					av->assoc_value = inp->auth_supported;
3368270362Stuexen					SCTP_INP_RUNLOCK(inp);
3369270362Stuexen				} else {
3370270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3371270362Stuexen					error = EINVAL;
3372270362Stuexen				}
3373270362Stuexen			}
3374270362Stuexen			if (error == 0) {
3375270362Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3376270362Stuexen			}
3377270362Stuexen			break;
3378270362Stuexen		}
3379270362Stuexen	case SCTP_ASCONF_SUPPORTED:
3380270362Stuexen		{
3381270362Stuexen			struct sctp_assoc_value *av;
3382270362Stuexen
3383270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3384270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3385270362Stuexen
3386270362Stuexen			if (stcb) {
3387270362Stuexen				av->assoc_value = stcb->asoc.asconf_supported;
3388270362Stuexen				SCTP_TCB_UNLOCK(stcb);
3389270362Stuexen			} else {
3390270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3391270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3392270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3393270362Stuexen					SCTP_INP_RLOCK(inp);
3394270362Stuexen					av->assoc_value = inp->asconf_supported;
3395270362Stuexen					SCTP_INP_RUNLOCK(inp);
3396270362Stuexen				} else {
3397270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3398270362Stuexen					error = EINVAL;
3399270362Stuexen				}
3400270362Stuexen			}
3401270362Stuexen			if (error == 0) {
3402270362Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3403270362Stuexen			}
3404270362Stuexen			break;
3405270362Stuexen		}
3406270361Stuexen	case SCTP_RECONFIG_SUPPORTED:
3407270361Stuexen		{
3408270361Stuexen			struct sctp_assoc_value *av;
3409270361Stuexen
3410270361Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3411270361Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3412270361Stuexen
3413270361Stuexen			if (stcb) {
3414270361Stuexen				av->assoc_value = stcb->asoc.reconfig_supported;
3415270361Stuexen				SCTP_TCB_UNLOCK(stcb);
3416270361Stuexen			} else {
3417270361Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3418270361Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3419270361Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3420270361Stuexen					SCTP_INP_RLOCK(inp);
3421270361Stuexen					av->assoc_value = inp->reconfig_supported;
3422270361Stuexen					SCTP_INP_RUNLOCK(inp);
3423270361Stuexen				} else {
3424270361Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3425270361Stuexen					error = EINVAL;
3426270361Stuexen				}
3427270361Stuexen			}
3428270361Stuexen			if (error == 0) {
3429270361Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3430270361Stuexen			}
3431270361Stuexen			break;
3432270361Stuexen		}
3433270359Stuexen	case SCTP_NRSACK_SUPPORTED:
3434270359Stuexen		{
3435270359Stuexen			struct sctp_assoc_value *av;
3436270359Stuexen
3437270359Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3438270359Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3439270359Stuexen
3440270359Stuexen			if (stcb) {
3441270359Stuexen				av->assoc_value = stcb->asoc.nrsack_supported;
3442270359Stuexen				SCTP_TCB_UNLOCK(stcb);
3443270359Stuexen			} else {
3444270359Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3445270359Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3446270359Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3447270359Stuexen					SCTP_INP_RLOCK(inp);
3448270359Stuexen					av->assoc_value = inp->nrsack_supported;
3449270359Stuexen					SCTP_INP_RUNLOCK(inp);
3450270359Stuexen				} else {
3451270359Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3452270359Stuexen					error = EINVAL;
3453270359Stuexen				}
3454270359Stuexen			}
3455270359Stuexen			if (error == 0) {
3456270359Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3457270359Stuexen			}
3458270359Stuexen			break;
3459270359Stuexen		}
3460270360Stuexen	case SCTP_PKTDROP_SUPPORTED:
3461270360Stuexen		{
3462270360Stuexen			struct sctp_assoc_value *av;
3463270360Stuexen
3464270360Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3465270360Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3466270360Stuexen
3467270360Stuexen			if (stcb) {
3468270360Stuexen				av->assoc_value = stcb->asoc.pktdrop_supported;
3469270360Stuexen				SCTP_TCB_UNLOCK(stcb);
3470270360Stuexen			} else {
3471270360Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3472270360Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3473270360Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3474270360Stuexen					SCTP_INP_RLOCK(inp);
3475270360Stuexen					av->assoc_value = inp->pktdrop_supported;
3476270360Stuexen					SCTP_INP_RUNLOCK(inp);
3477270360Stuexen				} else {
3478270360Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3479270360Stuexen					error = EINVAL;
3480270360Stuexen				}
3481270360Stuexen			}
3482270360Stuexen			if (error == 0) {
3483270360Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3484270360Stuexen			}
3485270360Stuexen			break;
3486270360Stuexen		}
3487235021Stuexen	case SCTP_ENABLE_STREAM_RESET:
3488235021Stuexen		{
3489235021Stuexen			struct sctp_assoc_value *av;
3490235021Stuexen
3491235021Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3492235021Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3493235021Stuexen
3494235021Stuexen			if (stcb) {
3495235021Stuexen				av->assoc_value = (uint32_t) stcb->asoc.local_strreset_support;
3496235021Stuexen				SCTP_TCB_UNLOCK(stcb);
3497235021Stuexen			} else {
3498235021Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3499235021Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3500235021Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3501235021Stuexen					SCTP_INP_RLOCK(inp);
3502235021Stuexen					av->assoc_value = (uint32_t) inp->local_strreset_support;
3503235021Stuexen					SCTP_INP_RUNLOCK(inp);
3504235021Stuexen				} else {
3505235021Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3506235021Stuexen					error = EINVAL;
3507235021Stuexen				}
3508235021Stuexen			}
3509235021Stuexen			if (error == 0) {
3510235021Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3511235021Stuexen			}
3512235021Stuexen			break;
3513235021Stuexen		}
3514270363Stuexen	case SCTP_PR_STREAM_STATUS:
3515270363Stuexen		{
3516270363Stuexen			struct sctp_prstatus *sprstat;
3517270363Stuexen			uint16_t sid;
3518270363Stuexen			uint16_t policy;
3519270363Stuexen
3520270363Stuexen			SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
3521270363Stuexen			SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
3522270363Stuexen
3523270363Stuexen			sid = sprstat->sprstat_sid;
3524270363Stuexen			policy = sprstat->sprstat_policy;
3525270363Stuexen#if defined(SCTP_DETAILED_STR_STATS)
3526270363Stuexen			if ((stcb != NULL) &&
3527270363Stuexen			    (policy != SCTP_PR_SCTP_NONE) &&
3528270363Stuexen			    (sid < stcb->asoc.streamoutcnt) &&
3529270363Stuexen			    ((policy == SCTP_PR_SCTP_ALL) ||
3530270363Stuexen			    (PR_SCTP_VALID_POLICY(policy)))) {
3531270363Stuexen#else
3532270363Stuexen			if ((stcb != NULL) &&
3533270363Stuexen			    (policy != SCTP_PR_SCTP_NONE) &&
3534270363Stuexen			    (sid < stcb->asoc.streamoutcnt) &&
3535270363Stuexen			    (policy == SCTP_PR_SCTP_ALL)) {
3536270363Stuexen#endif
3537270363Stuexen				if (policy == SCTP_PR_SCTP_ALL) {
3538270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
3539270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
3540270363Stuexen				} else {
3541270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[policy];
3542270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[policy];
3543270363Stuexen				}
3544270363Stuexen				SCTP_TCB_UNLOCK(stcb);
3545270363Stuexen				*optsize = sizeof(struct sctp_prstatus);
3546270363Stuexen			} else {
3547270363Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3548270363Stuexen				error = EINVAL;
3549270363Stuexen			}
3550270363Stuexen			break;
3551270363Stuexen		}
3552270363Stuexen	case SCTP_PR_ASSOC_STATUS:
3553270363Stuexen		{
3554270363Stuexen			struct sctp_prstatus *sprstat;
3555270363Stuexen			uint16_t policy;
3556270363Stuexen
3557270363Stuexen			SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
3558270363Stuexen			SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
3559270363Stuexen
3560270363Stuexen			policy = sprstat->sprstat_policy;
3561270363Stuexen			if ((stcb != NULL) &&
3562270363Stuexen			    (policy != SCTP_PR_SCTP_NONE) &&
3563270363Stuexen			    ((policy == SCTP_PR_SCTP_ALL) ||
3564270363Stuexen			    (PR_SCTP_VALID_POLICY(policy)))) {
3565270363Stuexen				if (policy == SCTP_PR_SCTP_ALL) {
3566270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[0];
3567270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[0];
3568270363Stuexen				} else {
3569270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy];
3570270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy];
3571270363Stuexen				}
3572270363Stuexen				SCTP_TCB_UNLOCK(stcb);
3573270363Stuexen				*optsize = sizeof(struct sctp_prstatus);
3574270363Stuexen			} else {
3575270363Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3576270363Stuexen				error = EINVAL;
3577270363Stuexen			}
3578270363Stuexen			break;
3579270363Stuexen		}
3580163953Srrs	default:
3581171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3582163953Srrs		error = ENOPROTOOPT;
3583163953Srrs		break;
3584163953Srrs	}			/* end switch (sopt->sopt_name) */
3585223132Stuexen	if (error) {
3586223132Stuexen		*optsize = 0;
3587223132Stuexen	}
3588163953Srrs	return (error);
3589163953Srrs}
3590163953Srrs
3591163953Srrsstatic int
3592166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
3593166675Srrs    void *p)
3594163953Srrs{
3595166675Srrs	int error, set_opt;
3596166675Srrs	uint32_t *mopt;
3597163953Srrs	struct sctp_tcb *stcb = NULL;
3598171943Srrs	struct sctp_inpcb *inp = NULL;
3599167598Srrs	uint32_t vrf_id;
3600163953Srrs
3601166675Srrs	if (optval == NULL) {
3602169420Srrs		SCTP_PRINTF("optval is NULL\n");
3603171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3604163953Srrs		return (EINVAL);
3605163953Srrs	}
3606163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3607233005Stuexen	if (inp == NULL) {
3608169420Srrs		SCTP_PRINTF("inp is NULL?\n");
3609171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3610228907Stuexen		return (EINVAL);
3611167598Srrs	}
3612168299Srrs	vrf_id = inp->def_vrf_id;
3613163953Srrs
3614163953Srrs	error = 0;
3615166675Srrs	switch (optname) {
3616163953Srrs	case SCTP_NODELAY:
3617163953Srrs	case SCTP_AUTOCLOSE:
3618163953Srrs	case SCTP_AUTO_ASCONF:
3619163953Srrs	case SCTP_EXPLICIT_EOR:
3620163953Srrs	case SCTP_DISABLE_FRAGMENTS:
3621163953Srrs	case SCTP_USE_EXT_RCVINFO:
3622163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
3623163953Srrs		/* copy in the option value */
3624166675Srrs		SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
3625163953Srrs		set_opt = 0;
3626163953Srrs		if (error)
3627163953Srrs			break;
3628166675Srrs		switch (optname) {
3629163953Srrs		case SCTP_DISABLE_FRAGMENTS:
3630163953Srrs			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
3631163953Srrs			break;
3632163953Srrs		case SCTP_AUTO_ASCONF:
3633171943Srrs			/*
3634171943Srrs			 * NOTE: we don't really support this flag
3635171943Srrs			 */
3636171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3637171943Srrs				/* only valid for bound all sockets */
3638224641Stuexen				if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
3639224641Stuexen				    (*mopt != 0)) {
3640224641Stuexen					/* forbidden by admin */
3641224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
3642224641Stuexen					return (EPERM);
3643224641Stuexen				}
3644171943Srrs				set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
3645171943Srrs			} else {
3646171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3647171943Srrs				return (EINVAL);
3648171943Srrs			}
3649163953Srrs			break;
3650163953Srrs		case SCTP_EXPLICIT_EOR:
3651163953Srrs			set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
3652163953Srrs			break;
3653163953Srrs		case SCTP_USE_EXT_RCVINFO:
3654163953Srrs			set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
3655163953Srrs			break;
3656163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
3657163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3658163953Srrs				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
3659163953Srrs			} else {
3660171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3661163953Srrs				return (EINVAL);
3662163953Srrs			}
3663163953Srrs			break;
3664163953Srrs		case SCTP_NODELAY:
3665163953Srrs			set_opt = SCTP_PCB_FLAGS_NODELAY;
3666163953Srrs			break;
3667163953Srrs		case SCTP_AUTOCLOSE:
3668170056Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3669170056Srrs			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3670171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3671170056Srrs				return (EINVAL);
3672170056Srrs			}
3673163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
3674163953Srrs			/*
3675163953Srrs			 * The value is in ticks. Note this does not effect
3676163953Srrs			 * old associations, only new ones.
3677163953Srrs			 */
3678163953Srrs			inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
3679163953Srrs			break;
3680163953Srrs		}
3681163953Srrs		SCTP_INP_WLOCK(inp);
3682163953Srrs		if (*mopt != 0) {
3683163953Srrs			sctp_feature_on(inp, set_opt);
3684163953Srrs		} else {
3685163953Srrs			sctp_feature_off(inp, set_opt);
3686163953Srrs		}
3687163953Srrs		SCTP_INP_WUNLOCK(inp);
3688163953Srrs		break;
3689181054Srrs	case SCTP_REUSE_PORT:
3690181054Srrs		{
3691181054Srrs			SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
3692181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
3693181054Srrs				/* Can't set it after we are bound */
3694181054Srrs				error = EINVAL;
3695181054Srrs				break;
3696181054Srrs			}
3697181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
3698181054Srrs				/* Can't do this for a 1-m socket */
3699181054Srrs				error = EINVAL;
3700181054Srrs				break;
3701181054Srrs			}
3702181054Srrs			if (optval)
3703181054Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
3704181054Srrs			else
3705181054Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
3706223132Stuexen			break;
3707181054Srrs		}
3708163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
3709163953Srrs		{
3710166675Srrs			uint32_t *value;
3711166675Srrs
3712166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
3713167736Srrs			if (*value > SCTP_SB_LIMIT_RCV(so)) {
3714171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3715167736Srrs				error = EINVAL;
3716167736Srrs				break;
3717167736Srrs			}
3718166675Srrs			inp->partial_delivery_point = *value;
3719223132Stuexen			break;
3720163953Srrs		}
3721163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
3722163953Srrs		/* not yet until we re-write sctp_recvmsg() */
3723163953Srrs		{
3724168943Srrs			uint32_t *level;
3725163953Srrs
3726168943Srrs			SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
3727168943Srrs			if (*level == SCTP_FRAG_LEVEL_2) {
3728163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3729168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3730168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_1) {
3731168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3732168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3733168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_0) {
3734170056Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3735168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3736168943Srrs
3737163953Srrs			} else {
3738171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3739168943Srrs				error = EINVAL;
3740163953Srrs			}
3741223132Stuexen			break;
3742163953Srrs		}
3743163953Srrs	case SCTP_CMT_ON_OFF:
3744211944Stuexen		if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
3745163953Srrs			struct sctp_assoc_value *av;
3746163953Srrs
3747166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3748223132Stuexen			if (av->assoc_value > SCTP_CMT_MAX) {
3749223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3750223132Stuexen				error = EINVAL;
3751223132Stuexen				break;
3752223132Stuexen			}
3753211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3754211944Stuexen			if (stcb) {
3755223132Stuexen				stcb->asoc.sctp_cmt_on_off = av->assoc_value;
3756211944Stuexen				SCTP_TCB_UNLOCK(stcb);
3757166675Srrs			} else {
3758224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3759224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3760224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3761223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3762221460Stuexen					SCTP_INP_WLOCK(inp);
3763221460Stuexen					inp->sctp_cmt_on_off = av->assoc_value;
3764221460Stuexen					SCTP_INP_WUNLOCK(inp);
3765216669Stuexen				}
3766223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3767223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3768223132Stuexen					SCTP_INP_RLOCK(inp);
3769223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3770223132Stuexen						SCTP_TCB_LOCK(stcb);
3771223132Stuexen						stcb->asoc.sctp_cmt_on_off = av->assoc_value;
3772223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3773223132Stuexen					}
3774224918Stuexen					SCTP_INP_RUNLOCK(inp);
3775223132Stuexen				}
3776163953Srrs			}
3777211944Stuexen		} else {
3778211944Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3779211944Stuexen			error = ENOPROTOOPT;
3780163953Srrs		}
3781163953Srrs		break;
3782171440Srrs	case SCTP_PLUGGABLE_CC:
3783171440Srrs		{
3784171440Srrs			struct sctp_assoc_value *av;
3785219057Srrs			struct sctp_nets *net;
3786171440Srrs
3787171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3788223132Stuexen			if ((av->assoc_value != SCTP_CC_RFC2581) &&
3789223132Stuexen			    (av->assoc_value != SCTP_CC_HSTCP) &&
3790223132Stuexen			    (av->assoc_value != SCTP_CC_HTCP) &&
3791223132Stuexen			    (av->assoc_value != SCTP_CC_RTCC)) {
3792223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3793223132Stuexen				error = EINVAL;
3794223132Stuexen				break;
3795223132Stuexen			}
3796171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3797171440Srrs			if (stcb) {
3798223132Stuexen				stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3799223132Stuexen				stcb->asoc.congestion_control_module = av->assoc_value;
3800223132Stuexen				if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3801223132Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3802223132Stuexen						stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
3803219057Srrs					}
3804171440Srrs				}
3805217611Stuexen				SCTP_TCB_UNLOCK(stcb);
3806171440Srrs			} else {
3807224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3808224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3809224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3810223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3811217611Stuexen					SCTP_INP_WLOCK(inp);
3812171440Srrs					inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
3813217611Stuexen					SCTP_INP_WUNLOCK(inp);
3814217760Stuexen				}
3815223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3816223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3817223132Stuexen					SCTP_INP_RLOCK(inp);
3818223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3819223132Stuexen						SCTP_TCB_LOCK(stcb);
3820223132Stuexen						stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3821223132Stuexen						stcb->asoc.congestion_control_module = av->assoc_value;
3822223132Stuexen						if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3823223132Stuexen							TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3824223132Stuexen								stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
3825223132Stuexen							}
3826223132Stuexen						}
3827223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3828223132Stuexen					}
3829223132Stuexen					SCTP_INP_RUNLOCK(inp);
3830223132Stuexen				}
3831171440Srrs			}
3832223132Stuexen			break;
3833171440Srrs		}
3834219057Srrs	case SCTP_CC_OPTION:
3835219057Srrs		{
3836219057Srrs			struct sctp_cc_option *cc_opt;
3837219057Srrs
3838219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
3839219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
3840219057Srrs			if (stcb == NULL) {
3841223132Stuexen				if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) {
3842223132Stuexen					SCTP_INP_RLOCK(inp);
3843223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3844223132Stuexen						SCTP_TCB_LOCK(stcb);
3845223132Stuexen						if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) {
3846223132Stuexen							(*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt);
3847223132Stuexen						}
3848223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3849223132Stuexen					}
3850223132Stuexen					SCTP_INP_RUNLOCK(inp);
3851223132Stuexen				} else {
3852223132Stuexen					error = EINVAL;
3853223132Stuexen				}
3854219057Srrs			} else {
3855219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
3856219057Srrs					error = ENOTSUP;
3857219057Srrs				} else {
3858219057Srrs					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1,
3859219057Srrs					    cc_opt);
3860219057Srrs				}
3861219057Srrs				SCTP_TCB_UNLOCK(stcb);
3862219057Srrs			}
3863223132Stuexen			break;
3864219057Srrs		}
3865217760Stuexen	case SCTP_PLUGGABLE_SS:
3866217760Stuexen		{
3867217760Stuexen			struct sctp_assoc_value *av;
3868217760Stuexen
3869217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3870223132Stuexen			if ((av->assoc_value != SCTP_SS_DEFAULT) &&
3871223132Stuexen			    (av->assoc_value != SCTP_SS_ROUND_ROBIN) &&
3872223132Stuexen			    (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) &&
3873223132Stuexen			    (av->assoc_value != SCTP_SS_PRIORITY) &&
3874223132Stuexen			    (av->assoc_value != SCTP_SS_FAIR_BANDWITH) &&
3875223132Stuexen			    (av->assoc_value != SCTP_SS_FIRST_COME)) {
3876223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3877223132Stuexen				error = EINVAL;
3878223132Stuexen				break;
3879223132Stuexen			}
3880217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3881217760Stuexen			if (stcb) {
3882223132Stuexen				stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
3883223132Stuexen				stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
3884223132Stuexen				stcb->asoc.stream_scheduling_module = av->assoc_value;
3885223132Stuexen				stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
3886217760Stuexen				SCTP_TCB_UNLOCK(stcb);
3887217760Stuexen			} else {
3888224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3889224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3890224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3891223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3892217760Stuexen					SCTP_INP_WLOCK(inp);
3893217760Stuexen					inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
3894217760Stuexen					SCTP_INP_WUNLOCK(inp);
3895217760Stuexen				}
3896223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3897223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3898223132Stuexen					SCTP_INP_RLOCK(inp);
3899223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3900223132Stuexen						SCTP_TCB_LOCK(stcb);
3901223132Stuexen						stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
3902223132Stuexen						stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
3903223132Stuexen						stcb->asoc.stream_scheduling_module = av->assoc_value;
3904223132Stuexen						stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
3905223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3906223132Stuexen					}
3907223132Stuexen					SCTP_INP_RUNLOCK(inp);
3908223132Stuexen				}
3909217760Stuexen			}
3910223132Stuexen			break;
3911217760Stuexen		}
3912217760Stuexen	case SCTP_SS_VALUE:
3913217760Stuexen		{
3914217760Stuexen			struct sctp_stream_value *av;
3915217760Stuexen
3916217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
3917217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3918217760Stuexen			if (stcb) {
3919277807Sdelphij				if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
3920277807Sdelphij				    (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
3921277807Sdelphij				    av->stream_value) < 0)) {
3922217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3923217760Stuexen					error = EINVAL;
3924217760Stuexen				}
3925217760Stuexen				SCTP_TCB_UNLOCK(stcb);
3926217760Stuexen			} else {
3927223132Stuexen				if (av->assoc_id == SCTP_CURRENT_ASSOC) {
3928223132Stuexen					SCTP_INP_RLOCK(inp);
3929223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3930223132Stuexen						SCTP_TCB_LOCK(stcb);
3931277807Sdelphij						if (av->stream_id < stcb->asoc.streamoutcnt) {
3932277807Sdelphij							stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
3933277807Sdelphij							    &stcb->asoc,
3934277807Sdelphij							    &stcb->asoc.strmout[av->stream_id],
3935277807Sdelphij							    av->stream_value);
3936277807Sdelphij						}
3937223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3938223132Stuexen					}
3939223132Stuexen					SCTP_INP_RUNLOCK(inp);
3940223132Stuexen
3941223132Stuexen				} else {
3942223132Stuexen					/*
3943223132Stuexen					 * Can't set stream value without
3944223132Stuexen					 * association
3945223132Stuexen					 */
3946223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3947223132Stuexen					error = EINVAL;
3948223132Stuexen				}
3949217760Stuexen			}
3950223132Stuexen			break;
3951217760Stuexen		}
3952163953Srrs	case SCTP_CLR_STAT_LOG:
3953171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
3954163953Srrs		error = EOPNOTSUPP;
3955163953Srrs		break;
3956163953Srrs	case SCTP_CONTEXT:
3957163953Srrs		{
3958163953Srrs			struct sctp_assoc_value *av;
3959163953Srrs
3960166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3961166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3962166675Srrs
3963166675Srrs			if (stcb) {
3964166675Srrs				stcb->asoc.context = av->assoc_value;
3965166675Srrs				SCTP_TCB_UNLOCK(stcb);
3966163953Srrs			} else {
3967224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3968224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3969224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3970223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3971223132Stuexen					SCTP_INP_WLOCK(inp);
3972223132Stuexen					inp->sctp_context = av->assoc_value;
3973223132Stuexen					SCTP_INP_WUNLOCK(inp);
3974223132Stuexen				}
3975223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3976223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3977223132Stuexen					SCTP_INP_RLOCK(inp);
3978223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3979223132Stuexen						SCTP_TCB_LOCK(stcb);
3980223132Stuexen						stcb->asoc.context = av->assoc_value;
3981223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3982223132Stuexen					}
3983223132Stuexen					SCTP_INP_RUNLOCK(inp);
3984223132Stuexen				}
3985163953Srrs			}
3986223132Stuexen			break;
3987163953Srrs		}
3988167598Srrs	case SCTP_VRF_ID:
3989167598Srrs		{
3990170056Srrs			uint32_t *default_vrfid;
3991167598Srrs
3992170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
3993170056Srrs			if (*default_vrfid > SCTP_MAX_VRF_ID) {
3994171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3995167598Srrs				error = EINVAL;
3996167598Srrs				break;
3997167598Srrs			}
3998170056Srrs			inp->def_vrf_id = *default_vrfid;
3999167598Srrs			break;
4000167598Srrs		}
4001167598Srrs	case SCTP_DEL_VRF_ID:
4002167598Srrs		{
4003171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4004167598Srrs			error = EOPNOTSUPP;
4005167598Srrs			break;
4006167598Srrs		}
4007167598Srrs	case SCTP_ADD_VRF_ID:
4008167598Srrs		{
4009171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4010167598Srrs			error = EOPNOTSUPP;
4011167598Srrs			break;
4012167598Srrs		}
4013170056Srrs	case SCTP_DELAYED_SACK:
4014163953Srrs		{
4015170056Srrs			struct sctp_sack_info *sack;
4016163953Srrs
4017170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
4018170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
4019171477Srrs			if (sack->sack_delay) {
4020171477Srrs				if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
4021171477Srrs					sack->sack_delay = SCTP_MAX_SACK_DELAY;
4022223132Stuexen				if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
4023223132Stuexen					sack->sack_delay = TICKS_TO_MSEC(1);
4024223132Stuexen				}
4025171477Srrs			}
4026166675Srrs			if (stcb) {
4027170056Srrs				if (sack->sack_delay) {
4028170056Srrs					stcb->asoc.delayed_ack = sack->sack_delay;
4029170056Srrs				}
4030170056Srrs				if (sack->sack_freq) {
4031170056Srrs					stcb->asoc.sack_freq = sack->sack_freq;
4032170056Srrs				}
4033166675Srrs				SCTP_TCB_UNLOCK(stcb);
4034166675Srrs			} else {
4035224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4036224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4037224918Stuexen				    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
4038223132Stuexen				    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
4039223132Stuexen					SCTP_INP_WLOCK(inp);
4040223132Stuexen					if (sack->sack_delay) {
4041223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
4042170056Srrs					}
4043223132Stuexen					if (sack->sack_freq) {
4044223132Stuexen						inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
4045223132Stuexen					}
4046223132Stuexen					SCTP_INP_WUNLOCK(inp);
4047170056Srrs				}
4048223132Stuexen				if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
4049223132Stuexen				    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
4050223132Stuexen					SCTP_INP_RLOCK(inp);
4051223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4052223132Stuexen						SCTP_TCB_LOCK(stcb);
4053223132Stuexen						if (sack->sack_delay) {
4054223132Stuexen							stcb->asoc.delayed_ack = sack->sack_delay;
4055223132Stuexen						}
4056223132Stuexen						if (sack->sack_freq) {
4057223132Stuexen							stcb->asoc.sack_freq = sack->sack_freq;
4058223132Stuexen						}
4059223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4060223132Stuexen					}
4061223132Stuexen					SCTP_INP_RUNLOCK(inp);
4062170056Srrs				}
4063163953Srrs			}
4064166675Srrs			break;
4065163953Srrs		}
4066163953Srrs	case SCTP_AUTH_CHUNK:
4067163953Srrs		{
4068163953Srrs			struct sctp_authchunk *sauth;
4069163953Srrs
4070166675Srrs			SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
4071166675Srrs
4072166675Srrs			SCTP_INP_WLOCK(inp);
4073171943Srrs			if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
4074171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4075163953Srrs				error = EINVAL;
4076171943Srrs			}
4077166675Srrs			SCTP_INP_WUNLOCK(inp);
4078163953Srrs			break;
4079163953Srrs		}
4080163953Srrs	case SCTP_AUTH_KEY:
4081163953Srrs		{
4082163953Srrs			struct sctp_authkey *sca;
4083163953Srrs			struct sctp_keyhead *shared_keys;
4084163953Srrs			sctp_sharedkey_t *shared_key;
4085163953Srrs			sctp_key_t *key = NULL;
4086166675Srrs			size_t size;
4087163953Srrs
4088166675Srrs			SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
4089223697Stuexen			if (sca->sca_keylength == 0) {
4090223697Stuexen				size = optsize - sizeof(struct sctp_authkey);
4091223697Stuexen			} else {
4092223697Stuexen				if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
4093223697Stuexen					size = sca->sca_keylength;
4094223697Stuexen				} else {
4095223697Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4096223697Stuexen					error = EINVAL;
4097223697Stuexen					break;
4098223697Stuexen				}
4099223697Stuexen			}
4100169420Srrs			SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
4101166675Srrs
4102166675Srrs			if (stcb) {
4103163953Srrs				shared_keys = &stcb->asoc.shared_keys;
4104163953Srrs				/* clear the cached keys for this key id */
4105163953Srrs				sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
4106163953Srrs				/*
4107163953Srrs				 * create the new shared key and
4108163953Srrs				 * insert/replace it
4109163953Srrs				 */
4110163953Srrs				if (size > 0) {
4111163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
4112163953Srrs					if (key == NULL) {
4113171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4114163953Srrs						error = ENOMEM;
4115163953Srrs						SCTP_TCB_UNLOCK(stcb);
4116163953Srrs						break;
4117163953Srrs					}
4118163953Srrs				}
4119163953Srrs				shared_key = sctp_alloc_sharedkey();
4120163953Srrs				if (shared_key == NULL) {
4121163953Srrs					sctp_free_key(key);
4122171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4123163953Srrs					error = ENOMEM;
4124163953Srrs					SCTP_TCB_UNLOCK(stcb);
4125163953Srrs					break;
4126163953Srrs				}
4127163953Srrs				shared_key->key = key;
4128163953Srrs				shared_key->keyid = sca->sca_keynumber;
4129185694Srrs				error = sctp_insert_sharedkey(shared_keys, shared_key);
4130163953Srrs				SCTP_TCB_UNLOCK(stcb);
4131163953Srrs			} else {
4132224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4133224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4134224918Stuexen				    (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
4135223132Stuexen				    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
4136223132Stuexen					SCTP_INP_WLOCK(inp);
4137223132Stuexen					shared_keys = &inp->sctp_ep.shared_keys;
4138223132Stuexen					/*
4139223132Stuexen					 * clear the cached keys on all
4140223132Stuexen					 * assocs for this key id
4141223132Stuexen					 */
4142223132Stuexen					sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
4143223132Stuexen					/*
4144223132Stuexen					 * create the new shared key and
4145223132Stuexen					 * insert/replace it
4146223132Stuexen					 */
4147223132Stuexen					if (size > 0) {
4148223132Stuexen						key = sctp_set_key(sca->sca_key, (uint32_t) size);
4149223132Stuexen						if (key == NULL) {
4150223132Stuexen							SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4151223132Stuexen							error = ENOMEM;
4152223132Stuexen							SCTP_INP_WUNLOCK(inp);
4153223132Stuexen							break;
4154223132Stuexen						}
4155223132Stuexen					}
4156223132Stuexen					shared_key = sctp_alloc_sharedkey();
4157223132Stuexen					if (shared_key == NULL) {
4158223132Stuexen						sctp_free_key(key);
4159171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4160163953Srrs						error = ENOMEM;
4161163953Srrs						SCTP_INP_WUNLOCK(inp);
4162163953Srrs						break;
4163163953Srrs					}
4164223132Stuexen					shared_key->key = key;
4165223132Stuexen					shared_key->keyid = sca->sca_keynumber;
4166223132Stuexen					error = sctp_insert_sharedkey(shared_keys, shared_key);
4167163953Srrs					SCTP_INP_WUNLOCK(inp);
4168163953Srrs				}
4169223132Stuexen				if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
4170223132Stuexen				    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
4171223132Stuexen					SCTP_INP_RLOCK(inp);
4172223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4173223132Stuexen						SCTP_TCB_LOCK(stcb);
4174223132Stuexen						shared_keys = &stcb->asoc.shared_keys;
4175223132Stuexen						/*
4176223132Stuexen						 * clear the cached keys for
4177223132Stuexen						 * this key id
4178223132Stuexen						 */
4179223132Stuexen						sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
4180223132Stuexen						/*
4181223132Stuexen						 * create the new shared key
4182223132Stuexen						 * and insert/replace it
4183223132Stuexen						 */
4184223132Stuexen						if (size > 0) {
4185223132Stuexen							key = sctp_set_key(sca->sca_key, (uint32_t) size);
4186223132Stuexen							if (key == NULL) {
4187223132Stuexen								SCTP_TCB_UNLOCK(stcb);
4188223132Stuexen								continue;
4189223132Stuexen							}
4190223132Stuexen						}
4191223132Stuexen						shared_key = sctp_alloc_sharedkey();
4192223132Stuexen						if (shared_key == NULL) {
4193223132Stuexen							sctp_free_key(key);
4194223132Stuexen							SCTP_TCB_UNLOCK(stcb);
4195223132Stuexen							continue;
4196223132Stuexen						}
4197223132Stuexen						shared_key->key = key;
4198223132Stuexen						shared_key->keyid = sca->sca_keynumber;
4199223132Stuexen						error = sctp_insert_sharedkey(shared_keys, shared_key);
4200223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4201223132Stuexen					}
4202223132Stuexen					SCTP_INP_RUNLOCK(inp);
4203223132Stuexen				}
4204163953Srrs			}
4205163953Srrs			break;
4206163953Srrs		}
4207163953Srrs	case SCTP_HMAC_IDENT:
4208163953Srrs		{
4209163953Srrs			struct sctp_hmacalgo *shmac;
4210163953Srrs			sctp_hmaclist_t *hmaclist;
4211181054Srrs			uint16_t hmacid;
4212181054Srrs			uint32_t i;
4213181054Srrs
4214166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
4215271750Stuexen			if ((optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) ||
4216271750Stuexen			    (shmac->shmac_number_of_idents > 0xffff)) {
4217181054Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4218181054Srrs				error = EINVAL;
4219181054Srrs				break;
4220181054Srrs			}
4221271750Stuexen			hmaclist = sctp_alloc_hmaclist((uint16_t) shmac->shmac_number_of_idents);
4222163953Srrs			if (hmaclist == NULL) {
4223171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4224163953Srrs				error = ENOMEM;
4225163953Srrs				break;
4226163953Srrs			}
4227181054Srrs			for (i = 0; i < shmac->shmac_number_of_idents; i++) {
4228163953Srrs				hmacid = shmac->shmac_idents[i];
4229181054Srrs				if (sctp_auth_add_hmacid(hmaclist, hmacid)) {
4230163953Srrs					 /* invalid HMACs were found */ ;
4231171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4232163953Srrs					error = EINVAL;
4233164085Srrs					sctp_free_hmaclist(hmaclist);
4234163953Srrs					goto sctp_set_hmac_done;
4235163953Srrs				}
4236163953Srrs			}
4237170056Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
4238170056Srrs				if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
4239170056Srrs					/* already in list */
4240253858Stuexen					break;
4241170056Srrs				}
4242170056Srrs			}
4243253858Stuexen			if (i == hmaclist->num_algo) {
4244253858Stuexen				/* not found in list */
4245170056Srrs				sctp_free_hmaclist(hmaclist);
4246171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4247170056Srrs				error = EINVAL;
4248170056Srrs				break;
4249170056Srrs			}
4250163953Srrs			/* set it on the endpoint */
4251163953Srrs			SCTP_INP_WLOCK(inp);
4252163953Srrs			if (inp->sctp_ep.local_hmacs)
4253163953Srrs				sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
4254163953Srrs			inp->sctp_ep.local_hmacs = hmaclist;
4255163953Srrs			SCTP_INP_WUNLOCK(inp);
4256163953Srrs	sctp_set_hmac_done:
4257163953Srrs			break;
4258163953Srrs		}
4259163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
4260163953Srrs		{
4261163953Srrs			struct sctp_authkeyid *scact;
4262163953Srrs
4263223132Stuexen			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
4264166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
4265166675Srrs
4266163953Srrs			/* set the active key on the right place */
4267166675Srrs			if (stcb) {
4268163953Srrs				/* set the active key on the assoc */
4269185694Srrs				if (sctp_auth_setactivekey(stcb,
4270185694Srrs				    scact->scact_keynumber)) {
4271185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
4272185694Srrs					    SCTP_FROM_SCTP_USRREQ,
4273185694Srrs					    EINVAL);
4274163953Srrs					error = EINVAL;
4275171943Srrs				}
4276163953Srrs				SCTP_TCB_UNLOCK(stcb);
4277163953Srrs			} else {
4278224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4279224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4280224918Stuexen				    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4281223132Stuexen				    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
4282223132Stuexen					SCTP_INP_WLOCK(inp);
4283223132Stuexen					if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
4284223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4285223132Stuexen						error = EINVAL;
4286223132Stuexen					}
4287223132Stuexen					SCTP_INP_WUNLOCK(inp);
4288171943Srrs				}
4289223132Stuexen				if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4290223132Stuexen				    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
4291223132Stuexen					SCTP_INP_RLOCK(inp);
4292223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4293223132Stuexen						SCTP_TCB_LOCK(stcb);
4294223132Stuexen						sctp_auth_setactivekey(stcb, scact->scact_keynumber);
4295223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4296223132Stuexen					}
4297223132Stuexen					SCTP_INP_RUNLOCK(inp);
4298223132Stuexen				}
4299163953Srrs			}
4300163953Srrs			break;
4301163953Srrs		}
4302163953Srrs	case SCTP_AUTH_DELETE_KEY:
4303163953Srrs		{
4304163953Srrs			struct sctp_authkeyid *scdel;
4305163953Srrs
4306223132Stuexen			SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
4307166675Srrs			SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
4308166675Srrs
4309163953Srrs			/* delete the key from the right place */
4310166675Srrs			if (stcb) {
4311223132Stuexen				if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
4312223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4313163953Srrs					error = EINVAL;
4314171943Srrs				}
4315163953Srrs				SCTP_TCB_UNLOCK(stcb);
4316163953Srrs			} else {
4317224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4318224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4319224918Stuexen				    (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4320223132Stuexen				    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
4321223132Stuexen					SCTP_INP_WLOCK(inp);
4322223132Stuexen					if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
4323223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4324223132Stuexen						error = EINVAL;
4325223132Stuexen					}
4326223132Stuexen					SCTP_INP_WUNLOCK(inp);
4327171943Srrs				}
4328223132Stuexen				if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4329223132Stuexen				    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
4330223132Stuexen					SCTP_INP_RLOCK(inp);
4331223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4332223132Stuexen						SCTP_TCB_LOCK(stcb);
4333223132Stuexen						sctp_delete_sharedkey(stcb, scdel->scact_keynumber);
4334223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4335223132Stuexen					}
4336223132Stuexen					SCTP_INP_RUNLOCK(inp);
4337223132Stuexen				}
4338163953Srrs			}
4339163953Srrs			break;
4340163953Srrs		}
4341185694Srrs	case SCTP_AUTH_DEACTIVATE_KEY:
4342185694Srrs		{
4343185694Srrs			struct sctp_authkeyid *keyid;
4344163953Srrs
4345223132Stuexen			SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize);
4346185694Srrs			SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
4347185694Srrs
4348185694Srrs			/* deactivate the key from the right place */
4349185694Srrs			if (stcb) {
4350223132Stuexen				if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) {
4351223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4352185694Srrs					error = EINVAL;
4353185694Srrs				}
4354185694Srrs				SCTP_TCB_UNLOCK(stcb);
4355185694Srrs			} else {
4356224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4357224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4358224918Stuexen				    (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4359223132Stuexen				    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
4360223132Stuexen					SCTP_INP_WLOCK(inp);
4361223132Stuexen					if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
4362223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4363223132Stuexen						error = EINVAL;
4364223132Stuexen					}
4365223132Stuexen					SCTP_INP_WUNLOCK(inp);
4366185694Srrs				}
4367223132Stuexen				if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4368223132Stuexen				    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
4369223132Stuexen					SCTP_INP_RLOCK(inp);
4370223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4371223132Stuexen						SCTP_TCB_LOCK(stcb);
4372223132Stuexen						sctp_deact_sharedkey(stcb, keyid->scact_keynumber);
4373223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4374223132Stuexen					}
4375223132Stuexen					SCTP_INP_RUNLOCK(inp);
4376223132Stuexen				}
4377185694Srrs			}
4378185694Srrs			break;
4379185694Srrs		}
4380233660Srrs	case SCTP_ENABLE_STREAM_RESET:
4381233660Srrs		{
4382233660Srrs			struct sctp_assoc_value *av;
4383185694Srrs
4384233660Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4385233660Srrs			if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
4386233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4387233660Srrs				error = EINVAL;
4388233660Srrs				break;
4389233660Srrs			}
4390233660Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4391233660Srrs			if (stcb) {
4392235021Stuexen				stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value;
4393233660Srrs				SCTP_TCB_UNLOCK(stcb);
4394233660Srrs			} else {
4395233660Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4396233660Srrs				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4397233660Srrs				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4398233660Srrs				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4399233660Srrs					SCTP_INP_WLOCK(inp);
4400235021Stuexen					inp->local_strreset_support = (uint8_t) av->assoc_value;
4401233660Srrs					SCTP_INP_WUNLOCK(inp);
4402233660Srrs				}
4403233660Srrs				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4404233660Srrs				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4405233660Srrs					SCTP_INP_RLOCK(inp);
4406233660Srrs					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4407233660Srrs						SCTP_TCB_LOCK(stcb);
4408235021Stuexen						stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value;
4409233660Srrs						SCTP_TCB_UNLOCK(stcb);
4410233660Srrs					}
4411233660Srrs					SCTP_INP_RUNLOCK(inp);
4412233660Srrs				}
4413233660Srrs			}
4414233660Srrs			break;
4415233660Srrs		}
4416163953Srrs	case SCTP_RESET_STREAMS:
4417163953Srrs		{
4418233660Srrs			struct sctp_reset_streams *strrst;
4419233660Srrs			int i, send_out = 0;
4420233660Srrs			int send_in = 0;
4421163953Srrs
4422233660Srrs			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
4423233660Srrs			SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
4424163953Srrs			if (stcb == NULL) {
4425171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4426163953Srrs				error = ENOENT;
4427163953Srrs				break;
4428163953Srrs			}
4429270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4430163953Srrs				/*
4431233660Srrs				 * Peer does not support the chunk type.
4432163953Srrs				 */
4433233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4434233660Srrs				error = EOPNOTSUPP;
4435163953Srrs				SCTP_TCB_UNLOCK(stcb);
4436163953Srrs				break;
4437163953Srrs			}
4438273000Stuexen			if (sizeof(struct sctp_reset_streams) +
4439273000Stuexen			    strrst->srs_number_streams * sizeof(uint16_t) > optsize) {
4440273000Stuexen				error = EINVAL;
4441273000Stuexen				SCTP_TCB_UNLOCK(stcb);
4442273000Stuexen				break;
4443273000Stuexen			}
4444163953Srrs			if (stcb->asoc.stream_reset_outstanding) {
4445171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4446163953Srrs				error = EALREADY;
4447163953Srrs				SCTP_TCB_UNLOCK(stcb);
4448163953Srrs				break;
4449163953Srrs			}
4450233660Srrs			if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
4451163953Srrs				send_in = 1;
4452233660Srrs			}
4453233660Srrs			if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
4454163953Srrs				send_out = 1;
4455233660Srrs			}
4456233660Srrs			if ((send_in == 0) && (send_out == 0)) {
4457233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4458233660Srrs				error = EINVAL;
4459233660Srrs				SCTP_TCB_UNLOCK(stcb);
4460233660Srrs				break;
4461233660Srrs			}
4462233660Srrs			for (i = 0; i < strrst->srs_number_streams; i++) {
4463233660Srrs				if ((send_in) &&
4464233660Srrs				    (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
4465233660Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4466188854Srrs					error = EINVAL;
4467233660Srrs					break;
4468188854Srrs				}
4469233660Srrs				if ((send_out) &&
4470233660Srrs				    (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
4471233660Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4472233660Srrs					error = EINVAL;
4473233660Srrs					break;
4474188854Srrs				}
4475233660Srrs			}
4476233660Srrs			if (error) {
4477233660Srrs				SCTP_TCB_UNLOCK(stcb);
4478233660Srrs				break;
4479233660Srrs			}
4480233660Srrs			error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
4481233660Srrs			    strrst->srs_stream_list,
4482233660Srrs			    send_out, send_in, 0, 0, 0, 0, 0);
4483233660Srrs
4484233660Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4485233660Srrs			SCTP_TCB_UNLOCK(stcb);
4486233660Srrs			break;
4487233660Srrs		}
4488233660Srrs	case SCTP_ADD_STREAMS:
4489233660Srrs		{
4490233660Srrs			struct sctp_add_streams *stradd;
4491233660Srrs			uint8_t addstream = 0;
4492233660Srrs			uint16_t add_o_strmcnt = 0;
4493233660Srrs			uint16_t add_i_strmcnt = 0;
4494233660Srrs
4495233660Srrs			SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
4496233660Srrs			SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
4497233660Srrs			if (stcb == NULL) {
4498233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4499233660Srrs				error = ENOENT;
4500233660Srrs				break;
4501233660Srrs			}
4502270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4503235057Stuexen				/*
4504235057Stuexen				 * Peer does not support the chunk type.
4505235057Stuexen				 */
4506235057Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4507235057Stuexen				error = EOPNOTSUPP;
4508235057Stuexen				SCTP_TCB_UNLOCK(stcb);
4509235057Stuexen				break;
4510235057Stuexen			}
4511235057Stuexen			if (stcb->asoc.stream_reset_outstanding) {
4512235057Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4513235057Stuexen				error = EALREADY;
4514235057Stuexen				SCTP_TCB_UNLOCK(stcb);
4515235057Stuexen				break;
4516235057Stuexen			}
4517233660Srrs			if ((stradd->sas_outstrms == 0) &&
4518233660Srrs			    (stradd->sas_instrms == 0)) {
4519233660Srrs				error = EINVAL;
4520233660Srrs				goto skip_stuff;
4521233660Srrs			}
4522233660Srrs			if (stradd->sas_outstrms) {
4523188854Srrs				addstream = 1;
4524188854Srrs				/* We allocate here */
4525233660Srrs				add_o_strmcnt = stradd->sas_outstrms;
4526233660Srrs				if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
4527188854Srrs					/* You can't have more than 64k */
4528188854Srrs					error = EINVAL;
4529188854Srrs					goto skip_stuff;
4530188854Srrs				}
4531163953Srrs			}
4532233660Srrs			if (stradd->sas_instrms) {
4533233660Srrs				int cnt;
4534163953Srrs
4535233660Srrs				addstream |= 2;
4536233660Srrs				/*
4537233660Srrs				 * We allocate inside
4538233660Srrs				 * sctp_send_str_reset_req()
4539233660Srrs				 */
4540233660Srrs				add_i_strmcnt = stradd->sas_instrms;
4541233660Srrs				cnt = add_i_strmcnt;
4542233660Srrs				cnt += stcb->asoc.streamincnt;
4543233660Srrs				if (cnt > 0x0000ffff) {
4544233660Srrs					/* You can't have more than 64k */
4545163953Srrs					error = EINVAL;
4546233660Srrs					goto skip_stuff;
4547163953Srrs				}
4548233660Srrs				if (cnt > (int)stcb->asoc.max_inbound_streams) {
4549233660Srrs					/* More than you are allowed */
4550163953Srrs					error = EINVAL;
4551233660Srrs					goto skip_stuff;
4552163953Srrs				}
4553163953Srrs			}
4554233660Srrs			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
4555233660Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4556188854Srrs	skip_stuff:
4557233660Srrs			SCTP_TCB_UNLOCK(stcb);
4558233660Srrs			break;
4559233660Srrs		}
4560233660Srrs	case SCTP_RESET_ASSOC:
4561233660Srrs		{
4562233660Srrs			uint32_t *value;
4563233660Srrs
4564233660Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
4565233660Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
4566233660Srrs			if (stcb == NULL) {
4567233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4568233660Srrs				error = ENOENT;
4569233660Srrs				break;
4570233660Srrs			}
4571270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4572233660Srrs				/*
4573233660Srrs				 * Peer does not support the chunk type.
4574233660Srrs				 */
4575233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4576233660Srrs				error = EOPNOTSUPP;
4577163953Srrs				SCTP_TCB_UNLOCK(stcb);
4578163953Srrs				break;
4579163953Srrs			}
4580233660Srrs			if (stcb->asoc.stream_reset_outstanding) {
4581233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4582233660Srrs				error = EALREADY;
4583233660Srrs				SCTP_TCB_UNLOCK(stcb);
4584233660Srrs				break;
4585233660Srrs			}
4586233660Srrs			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0);
4587172090Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4588163953Srrs			SCTP_TCB_UNLOCK(stcb);
4589223132Stuexen			break;
4590163953Srrs		}
4591163953Srrs	case SCTP_CONNECT_X:
4592166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
4593171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4594163953Srrs			error = EINVAL;
4595163953Srrs			break;
4596163953Srrs		}
4597166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
4598163953Srrs		break;
4599163953Srrs	case SCTP_CONNECT_X_DELAYED:
4600166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
4601171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4602163953Srrs			error = EINVAL;
4603163953Srrs			break;
4604163953Srrs		}
4605166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
4606163953Srrs		break;
4607163953Srrs	case SCTP_CONNECT_X_COMPLETE:
4608163953Srrs		{
4609163953Srrs			struct sockaddr *sa;
4610163953Srrs			struct sctp_nets *net;
4611163953Srrs
4612166675Srrs			/* FIXME MT: check correct? */
4613166675Srrs			SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
4614166675Srrs
4615163953Srrs			/* find tcb */
4616163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4617163953Srrs				SCTP_INP_RLOCK(inp);
4618163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
4619163953Srrs				if (stcb) {
4620163953Srrs					SCTP_TCB_LOCK(stcb);
4621163953Srrs					net = sctp_findnet(stcb, sa);
4622163953Srrs				}
4623163953Srrs				SCTP_INP_RUNLOCK(inp);
4624163953Srrs			} else {
4625166675Srrs				/*
4626166675Srrs				 * We increment here since
4627166675Srrs				 * sctp_findassociation_ep_addr() wil do a
4628166675Srrs				 * decrement if it finds the stcb as long as
4629166675Srrs				 * the locked tcb (last argument) is NOT a
4630166675Srrs				 * TCB.. aka NULL.
4631166675Srrs				 */
4632163953Srrs				SCTP_INP_INCR_REF(inp);
4633163953Srrs				stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL);
4634163953Srrs				if (stcb == NULL) {
4635163953Srrs					SCTP_INP_DECR_REF(inp);
4636163953Srrs				}
4637163953Srrs			}
4638163953Srrs
4639163953Srrs			if (stcb == NULL) {
4640171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4641163953Srrs				error = ENOENT;
4642163953Srrs				break;
4643163953Srrs			}
4644163953Srrs			if (stcb->asoc.delayed_connection == 1) {
4645163953Srrs				stcb->asoc.delayed_connection = 0;
4646169378Srrs				(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
4647165220Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
4648165220Srrs				    stcb->asoc.primary_destination,
4649165220Srrs				    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
4650172090Srrs				sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
4651163953Srrs			} else {
4652163953Srrs				/*
4653163953Srrs				 * already expired or did not use delayed
4654163953Srrs				 * connectx
4655163953Srrs				 */
4656171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4657163953Srrs				error = EALREADY;
4658163953Srrs			}
4659163953Srrs			SCTP_TCB_UNLOCK(stcb);
4660223132Stuexen			break;
4661163953Srrs		}
4662170056Srrs	case SCTP_MAX_BURST:
4663163953Srrs		{
4664217895Stuexen			struct sctp_assoc_value *av;
4665163953Srrs
4666217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4667217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4668166675Srrs
4669217895Stuexen			if (stcb) {
4670217895Stuexen				stcb->asoc.max_burst = av->assoc_value;
4671217895Stuexen				SCTP_TCB_UNLOCK(stcb);
4672217895Stuexen			} else {
4673224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4674224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4675224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4676223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4677223132Stuexen					SCTP_INP_WLOCK(inp);
4678223132Stuexen					inp->sctp_ep.max_burst = av->assoc_value;
4679223132Stuexen					SCTP_INP_WUNLOCK(inp);
4680223132Stuexen				}
4681223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4682223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4683223132Stuexen					SCTP_INP_RLOCK(inp);
4684223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4685223132Stuexen						SCTP_TCB_LOCK(stcb);
4686223132Stuexen						stcb->asoc.max_burst = av->assoc_value;
4687223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4688223132Stuexen					}
4689223132Stuexen					SCTP_INP_RUNLOCK(inp);
4690223132Stuexen				}
4691217895Stuexen			}
4692223132Stuexen			break;
4693163953Srrs		}
4694163953Srrs	case SCTP_MAXSEG:
4695163953Srrs		{
4696167598Srrs			struct sctp_assoc_value *av;
4697163953Srrs			int ovh;
4698163953Srrs
4699167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4700167598Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4701166675Srrs
4702170056Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
4703170056Srrs				ovh = SCTP_MED_OVERHEAD;
4704170056Srrs			} else {
4705170056Srrs				ovh = SCTP_MED_V4_OVERHEAD;
4706170056Srrs			}
4707167598Srrs			if (stcb) {
4708170056Srrs				if (av->assoc_value) {
4709170056Srrs					stcb->asoc.sctp_frag_point = (av->assoc_value + ovh);
4710170056Srrs				} else {
4711170056Srrs					stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
4712170056Srrs				}
4713167598Srrs				SCTP_TCB_UNLOCK(stcb);
4714163953Srrs			} else {
4715224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4716224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4717224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4718223132Stuexen					SCTP_INP_WLOCK(inp);
4719223132Stuexen					/*
4720223132Stuexen					 * FIXME MT: I think this is not in
4721223132Stuexen					 * tune with the API ID
4722223132Stuexen					 */
4723223132Stuexen					if (av->assoc_value) {
4724223132Stuexen						inp->sctp_frag_point = (av->assoc_value + ovh);
4725223132Stuexen					} else {
4726223132Stuexen						inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
4727223132Stuexen					}
4728223132Stuexen					SCTP_INP_WUNLOCK(inp);
4729167598Srrs				} else {
4730223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4731223132Stuexen					error = EINVAL;
4732167598Srrs				}
4733163953Srrs			}
4734223132Stuexen			break;
4735163953Srrs		}
4736163953Srrs	case SCTP_EVENTS:
4737163953Srrs		{
4738163953Srrs			struct sctp_event_subscribe *events;
4739163953Srrs
4740166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
4741166675Srrs
4742163953Srrs			SCTP_INP_WLOCK(inp);
4743163953Srrs			if (events->sctp_data_io_event) {
4744163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
4745163953Srrs			} else {
4746163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
4747163953Srrs			}
4748163953Srrs
4749163953Srrs			if (events->sctp_association_event) {
4750163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4751163953Srrs			} else {
4752163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4753163953Srrs			}
4754163953Srrs
4755163953Srrs			if (events->sctp_address_event) {
4756163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
4757163953Srrs			} else {
4758163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
4759163953Srrs			}
4760163953Srrs
4761163953Srrs			if (events->sctp_send_failure_event) {
4762163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4763163953Srrs			} else {
4764163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4765163953Srrs			}
4766163953Srrs
4767163953Srrs			if (events->sctp_peer_error_event) {
4768163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
4769163953Srrs			} else {
4770163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
4771163953Srrs			}
4772163953Srrs
4773163953Srrs			if (events->sctp_shutdown_event) {
4774163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4775163953Srrs			} else {
4776163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4777163953Srrs			}
4778163953Srrs
4779163953Srrs			if (events->sctp_partial_delivery_event) {
4780163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
4781163953Srrs			} else {
4782163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
4783163953Srrs			}
4784163953Srrs
4785163953Srrs			if (events->sctp_adaptation_layer_event) {
4786163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
4787163953Srrs			} else {
4788163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
4789163953Srrs			}
4790163953Srrs
4791163953Srrs			if (events->sctp_authentication_event) {
4792163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
4793163953Srrs			} else {
4794163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
4795163953Srrs			}
4796163953Srrs
4797185694Srrs			if (events->sctp_sender_dry_event) {
4798185694Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
4799185694Srrs			} else {
4800185694Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
4801185694Srrs			}
4802185694Srrs
4803202520Srrs			if (events->sctp_stream_reset_event) {
4804163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
4805163953Srrs			} else {
4806163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
4807163953Srrs			}
4808163953Srrs			SCTP_INP_WUNLOCK(inp);
4809223132Stuexen
4810223132Stuexen			SCTP_INP_RLOCK(inp);
4811223132Stuexen			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4812223132Stuexen				SCTP_TCB_LOCK(stcb);
4813223132Stuexen				if (events->sctp_association_event) {
4814223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4815223132Stuexen				} else {
4816223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4817223132Stuexen				}
4818223132Stuexen				if (events->sctp_address_event) {
4819223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
4820223132Stuexen				} else {
4821223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
4822223132Stuexen				}
4823223132Stuexen				if (events->sctp_send_failure_event) {
4824223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4825223132Stuexen				} else {
4826223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4827223132Stuexen				}
4828223132Stuexen				if (events->sctp_peer_error_event) {
4829223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
4830223132Stuexen				} else {
4831223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
4832223132Stuexen				}
4833223132Stuexen				if (events->sctp_shutdown_event) {
4834223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4835223132Stuexen				} else {
4836223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4837223132Stuexen				}
4838223132Stuexen				if (events->sctp_partial_delivery_event) {
4839223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
4840223132Stuexen				} else {
4841223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
4842223132Stuexen				}
4843223132Stuexen				if (events->sctp_adaptation_layer_event) {
4844223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
4845223132Stuexen				} else {
4846223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
4847223132Stuexen				}
4848223132Stuexen				if (events->sctp_authentication_event) {
4849223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
4850223132Stuexen				} else {
4851223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
4852223132Stuexen				}
4853223132Stuexen				if (events->sctp_sender_dry_event) {
4854223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
4855223132Stuexen				} else {
4856223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
4857223132Stuexen				}
4858223132Stuexen				if (events->sctp_stream_reset_event) {
4859223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
4860223132Stuexen				} else {
4861223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
4862223132Stuexen				}
4863223132Stuexen				SCTP_TCB_UNLOCK(stcb);
4864223132Stuexen			}
4865223132Stuexen			/*
4866223132Stuexen			 * Send up the sender dry event only for 1-to-1
4867223132Stuexen			 * style sockets.
4868223132Stuexen			 */
4869223132Stuexen			if (events->sctp_sender_dry_event) {
4870223132Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4871223132Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
4872223132Stuexen					stcb = LIST_FIRST(&inp->sctp_asoc_list);
4873223132Stuexen					if (stcb) {
4874223132Stuexen						SCTP_TCB_LOCK(stcb);
4875223132Stuexen						if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
4876223132Stuexen						    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
4877223132Stuexen						    (stcb->asoc.stream_queue_cnt == 0)) {
4878223132Stuexen							sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
4879223132Stuexen						}
4880223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4881223132Stuexen					}
4882223132Stuexen				}
4883223132Stuexen			}
4884223132Stuexen			SCTP_INP_RUNLOCK(inp);
4885223132Stuexen			break;
4886163953Srrs		}
4887163953Srrs	case SCTP_ADAPTATION_LAYER:
4888163953Srrs		{
4889163953Srrs			struct sctp_setadaptation *adap_bits;
4890163953Srrs
4891166675Srrs			SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
4892163953Srrs			SCTP_INP_WLOCK(inp);
4893163953Srrs			inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
4894246687Stuexen			inp->sctp_ep.adaptation_layer_indicator_provided = 1;
4895163953Srrs			SCTP_INP_WUNLOCK(inp);
4896223132Stuexen			break;
4897163953Srrs		}
4898166675Srrs#ifdef SCTP_DEBUG
4899163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
4900163953Srrs		{
4901163953Srrs			uint32_t *vvv;
4902163953Srrs
4903166675Srrs			SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
4904163953Srrs			SCTP_INP_WLOCK(inp);
4905163953Srrs			inp->sctp_ep.initial_sequence_debug = *vvv;
4906163953Srrs			SCTP_INP_WUNLOCK(inp);
4907223132Stuexen			break;
4908163953Srrs		}
4909166675Srrs#endif
4910163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
4911163953Srrs		{
4912163953Srrs			struct sctp_sndrcvinfo *s_info;
4913163953Srrs
4914166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
4915166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
4916163953Srrs
4917166675Srrs			if (stcb) {
4918223132Stuexen				if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
4919170056Srrs					memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
4920163953Srrs				} else {
4921171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4922166675Srrs					error = EINVAL;
4923163953Srrs				}
4924166675Srrs				SCTP_TCB_UNLOCK(stcb);
4925166675Srrs			} else {
4926224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4927224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4928224918Stuexen				    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
4929223132Stuexen				    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
4930223132Stuexen					SCTP_INP_WLOCK(inp);
4931223132Stuexen					memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
4932223132Stuexen					SCTP_INP_WUNLOCK(inp);
4933223132Stuexen				}
4934223132Stuexen				if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
4935223132Stuexen				    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
4936223132Stuexen					SCTP_INP_RLOCK(inp);
4937223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4938223132Stuexen						SCTP_TCB_LOCK(stcb);
4939223132Stuexen						if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
4940223132Stuexen							memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
4941223132Stuexen						}
4942223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4943223132Stuexen					}
4944223132Stuexen					SCTP_INP_RUNLOCK(inp);
4945223132Stuexen				}
4946163953Srrs			}
4947223132Stuexen			break;
4948163953Srrs		}
4949163953Srrs	case SCTP_PEER_ADDR_PARAMS:
4950163953Srrs		{
4951163953Srrs			struct sctp_paddrparams *paddrp;
4952163953Srrs			struct sctp_nets *net;
4953163953Srrs
4954166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
4955166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
4956163953Srrs			net = NULL;
4957166675Srrs			if (stcb) {
4958166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
4959166675Srrs			} else {
4960166675Srrs				/*
4961166675Srrs				 * We increment here since
4962166675Srrs				 * sctp_findassociation_ep_addr() wil do a
4963166675Srrs				 * decrement if it finds the stcb as long as
4964166675Srrs				 * the locked tcb (last argument) is NOT a
4965166675Srrs				 * TCB.. aka NULL.
4966166675Srrs				 */
4967166675Srrs				SCTP_INP_INCR_REF(inp);
4968166675Srrs				stcb = sctp_findassociation_ep_addr(&inp,
4969166675Srrs				    (struct sockaddr *)&paddrp->spp_address,
4970166675Srrs				    &net, NULL, NULL);
4971163953Srrs				if (stcb == NULL) {
4972166675Srrs					SCTP_INP_DECR_REF(inp);
4973163953Srrs				}
4974163953Srrs			}
4975171943Srrs			if (stcb && (net == NULL)) {
4976171943Srrs				struct sockaddr *sa;
4977171943Srrs
4978171943Srrs				sa = (struct sockaddr *)&paddrp->spp_address;
4979221249Stuexen#ifdef INET
4980171943Srrs				if (sa->sa_family == AF_INET) {
4981221249Stuexen
4982171943Srrs					struct sockaddr_in *sin;
4983171943Srrs
4984171943Srrs					sin = (struct sockaddr_in *)sa;
4985171943Srrs					if (sin->sin_addr.s_addr) {
4986171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4987171943Srrs						SCTP_TCB_UNLOCK(stcb);
4988171943Srrs						error = EINVAL;
4989171943Srrs						break;
4990171943Srrs					}
4991221249Stuexen				} else
4992221249Stuexen#endif
4993221249Stuexen#ifdef INET6
4994221249Stuexen				if (sa->sa_family == AF_INET6) {
4995171943Srrs					struct sockaddr_in6 *sin6;
4996171943Srrs
4997171943Srrs					sin6 = (struct sockaddr_in6 *)sa;
4998171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
4999171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5000171943Srrs						SCTP_TCB_UNLOCK(stcb);
5001171943Srrs						error = EINVAL;
5002171943Srrs						break;
5003171943Srrs					}
5004221249Stuexen				} else
5005221249Stuexen#endif
5006221249Stuexen				{
5007171943Srrs					error = EAFNOSUPPORT;
5008171943Srrs					SCTP_TCB_UNLOCK(stcb);
5009171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5010171943Srrs					break;
5011171943Srrs				}
5012171943Srrs			}
5013170056Srrs			/* sanity checks */
5014170056Srrs			if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
5015170056Srrs				if (stcb)
5016170056Srrs					SCTP_TCB_UNLOCK(stcb);
5017171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5018170056Srrs				return (EINVAL);
5019170056Srrs			}
5020170056Srrs			if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
5021170056Srrs				if (stcb)
5022170056Srrs					SCTP_TCB_UNLOCK(stcb);
5023171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5024170056Srrs				return (EINVAL);
5025170056Srrs			}
5026163953Srrs			if (stcb) {
5027163953Srrs				/************************TCB SPECIFIC SET ******************/
5028163953Srrs				/*
5029163953Srrs				 * do we change the timer for HB, we run
5030163953Srrs				 * only one?
5031163953Srrs				 */
5032170056Srrs				int ovh = 0;
5033170056Srrs
5034170056Srrs				if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
5035170056Srrs					ovh = SCTP_MED_OVERHEAD;
5036170056Srrs				} else {
5037170056Srrs					ovh = SCTP_MED_V4_OVERHEAD;
5038170056Srrs				}
5039170056Srrs
5040163953Srrs				/* network sets ? */
5041163953Srrs				if (net) {
5042163953Srrs					/************************NET SPECIFIC SET ******************/
5043224641Stuexen					if (paddrp->spp_flags & SPP_HB_DISABLE) {
5044224641Stuexen						if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
5045224641Stuexen						    !(net->dest_state & SCTP_ADDR_NOHB)) {
5046224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5047224641Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
5048171440Srrs						}
5049163953Srrs						net->dest_state |= SCTP_ADDR_NOHB;
5050163953Srrs					}
5051163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5052224641Stuexen						if (paddrp->spp_hbinterval) {
5053224641Stuexen							net->heart_beat_delay = paddrp->spp_hbinterval;
5054224641Stuexen						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5055224641Stuexen							net->heart_beat_delay = 0;
5056224641Stuexen						}
5057224641Stuexen						sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5058224641Stuexen						    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
5059224641Stuexen						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5060163953Srrs						net->dest_state &= ~SCTP_ADDR_NOHB;
5061163953Srrs					}
5062224641Stuexen					if (paddrp->spp_flags & SPP_HB_DEMAND) {
5063224641Stuexen						/* on demand HB */
5064224641Stuexen						sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5065228391Stuexen						sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
5066224641Stuexen						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5067224641Stuexen					}
5068170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
5069165647Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5070165220Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
5071165220Srrs							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
5072163953Srrs						}
5073225635Stuexen						net->dest_state |= SCTP_ADDR_NO_PMTUD;
5074258454Stuexen						net->mtu = paddrp->spp_pathmtu + ovh;
5075258454Stuexen						if (net->mtu < stcb->asoc.smallest_mtu) {
5076258454Stuexen							sctp_pathmtu_adjustment(stcb, net->mtu);
5077163953Srrs						}
5078163953Srrs					}
5079163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5080225635Stuexen						if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5081163953Srrs							sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
5082163953Srrs						}
5083225635Stuexen						net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
5084163953Srrs					}
5085224641Stuexen					if (paddrp->spp_pathmaxrxt) {
5086224641Stuexen						if (net->dest_state & SCTP_ADDR_PF) {
5087224641Stuexen							if (net->error_count > paddrp->spp_pathmaxrxt) {
5088224641Stuexen								net->dest_state &= ~SCTP_ADDR_PF;
5089224641Stuexen							}
5090224641Stuexen						} else {
5091224641Stuexen							if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
5092224641Stuexen							    (net->error_count > net->pf_threshold)) {
5093224641Stuexen								net->dest_state |= SCTP_ADDR_PF;
5094224641Stuexen								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5095224641Stuexen								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
5096224641Stuexen								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5097224641Stuexen							}
5098224641Stuexen						}
5099224641Stuexen						if (net->dest_state & SCTP_ADDR_REACHABLE) {
5100224641Stuexen							if (net->error_count > paddrp->spp_pathmaxrxt) {
5101224641Stuexen								net->dest_state &= ~SCTP_ADDR_REACHABLE;
5102235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5103224641Stuexen							}
5104224641Stuexen						} else {
5105224641Stuexen							if (net->error_count <= paddrp->spp_pathmaxrxt) {
5106224641Stuexen								net->dest_state |= SCTP_ADDR_REACHABLE;
5107235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5108224641Stuexen							}
5109224641Stuexen						}
5110163953Srrs						net->failure_threshold = paddrp->spp_pathmaxrxt;
5111224641Stuexen					}
5112224870Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5113226252Stuexen						net->dscp = paddrp->spp_dscp & 0xfc;
5114225549Stuexen						net->dscp |= 0x01;
5115163953Srrs					}
5116167598Srrs#ifdef INET6
5117163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5118225549Stuexen						if (net->ro._l_addr.sa.sa_family == AF_INET6) {
5119224870Stuexen							net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5120225549Stuexen							net->flowlabel |= 0x80000000;
5121163953Srrs						}
5122163953Srrs					}
5123163953Srrs#endif
5124163953Srrs				} else {
5125163953Srrs					/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
5126224641Stuexen					if (paddrp->spp_pathmaxrxt) {
5127163953Srrs						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
5128224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5129224641Stuexen							if (net->dest_state & SCTP_ADDR_PF) {
5130224641Stuexen								if (net->error_count > paddrp->spp_pathmaxrxt) {
5131224641Stuexen									net->dest_state &= ~SCTP_ADDR_PF;
5132224641Stuexen								}
5133224641Stuexen							} else {
5134224641Stuexen								if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
5135224641Stuexen								    (net->error_count > net->pf_threshold)) {
5136224641Stuexen									net->dest_state |= SCTP_ADDR_PF;
5137224641Stuexen									sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5138224641Stuexen									sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
5139224641Stuexen									sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5140224641Stuexen								}
5141224641Stuexen							}
5142224641Stuexen							if (net->dest_state & SCTP_ADDR_REACHABLE) {
5143224641Stuexen								if (net->error_count > paddrp->spp_pathmaxrxt) {
5144224641Stuexen									net->dest_state &= ~SCTP_ADDR_REACHABLE;
5145235414Stuexen									sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5146224641Stuexen								}
5147224641Stuexen							} else {
5148224641Stuexen								if (net->error_count <= paddrp->spp_pathmaxrxt) {
5149224641Stuexen									net->dest_state |= SCTP_ADDR_REACHABLE;
5150235414Stuexen									sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5151224641Stuexen								}
5152224641Stuexen							}
5153224641Stuexen							net->failure_threshold = paddrp->spp_pathmaxrxt;
5154224641Stuexen						}
5155224641Stuexen					}
5156163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5157224641Stuexen						if (paddrp->spp_hbinterval) {
5158224641Stuexen							stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
5159224641Stuexen						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5160224641Stuexen							stcb->asoc.heart_beat_delay = 0;
5161224641Stuexen						}
5162163953Srrs						/* Turn back on the timer */
5163224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5164224641Stuexen							if (paddrp->spp_hbinterval) {
5165224641Stuexen								net->heart_beat_delay = paddrp->spp_hbinterval;
5166224641Stuexen							} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5167224641Stuexen								net->heart_beat_delay = 0;
5168224641Stuexen							}
5169224641Stuexen							if (net->dest_state & SCTP_ADDR_NOHB) {
5170224641Stuexen								net->dest_state &= ~SCTP_ADDR_NOHB;
5171224641Stuexen							}
5172224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5173224641Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
5174224641Stuexen							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5175224641Stuexen						}
5176225635Stuexen						sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5177163953Srrs					}
5178224641Stuexen					if (paddrp->spp_flags & SPP_HB_DISABLE) {
5179224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5180224641Stuexen							if (!(net->dest_state & SCTP_ADDR_NOHB)) {
5181224641Stuexen								net->dest_state |= SCTP_ADDR_NOHB;
5182224641Stuexen								if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
5183224641Stuexen									sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
5184224641Stuexen								}
5185224641Stuexen							}
5186224641Stuexen						}
5187225635Stuexen						sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5188224641Stuexen					}
5189170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
5190170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5191170056Srrs							if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5192170056Srrs								sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
5193170056Srrs								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
5194170056Srrs							}
5195225635Stuexen							net->dest_state |= SCTP_ADDR_NO_PMTUD;
5196258454Stuexen							net->mtu = paddrp->spp_pathmtu + ovh;
5197258454Stuexen							if (net->mtu < stcb->asoc.smallest_mtu) {
5198258454Stuexen								sctp_pathmtu_adjustment(stcb, net->mtu);
5199170056Srrs							}
5200170056Srrs						}
5201225635Stuexen						sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5202170056Srrs					}
5203170056Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5204170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5205225635Stuexen							if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5206170056Srrs								sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
5207170056Srrs							}
5208225635Stuexen							net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
5209170056Srrs						}
5210225635Stuexen						sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5211170056Srrs					}
5212224870Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5213224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5214226252Stuexen							net->dscp = paddrp->spp_dscp & 0xfc;
5215225549Stuexen							net->dscp |= 0x01;
5216163953Srrs						}
5217226252Stuexen						stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc;
5218225549Stuexen						stcb->asoc.default_dscp |= 0x01;
5219163953Srrs					}
5220225549Stuexen#ifdef INET6
5221224641Stuexen					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5222170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5223225549Stuexen							if (net->ro._l_addr.sa.sa_family == AF_INET6) {
5224225549Stuexen								net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5225225549Stuexen								net->flowlabel |= 0x80000000;
5226225549Stuexen							}
5227170056Srrs						}
5228225549Stuexen						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5229225549Stuexen						stcb->asoc.default_flowlabel |= 0x80000000;
5230163953Srrs					}
5231225549Stuexen#endif
5232163953Srrs				}
5233163953Srrs				SCTP_TCB_UNLOCK(stcb);
5234163953Srrs			} else {
5235163953Srrs				/************************NO TCB, SET TO default stuff ******************/
5236224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5237224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5238224918Stuexen				    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
5239223132Stuexen					SCTP_INP_WLOCK(inp);
5240223132Stuexen					/*
5241223132Stuexen					 * For the TOS/FLOWLABEL stuff you
5242223132Stuexen					 * set it with the options on the
5243223132Stuexen					 * socket
5244223132Stuexen					 */
5245223132Stuexen					if (paddrp->spp_pathmaxrxt) {
5246223132Stuexen						inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
5247223132Stuexen					}
5248223132Stuexen					if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
5249223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
5250223132Stuexen					else if (paddrp->spp_hbinterval) {
5251223132Stuexen						if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
5252223132Stuexen							paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL;
5253223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
5254223132Stuexen					}
5255223132Stuexen					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5256224641Stuexen						if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5257224641Stuexen							inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
5258224641Stuexen						} else if (paddrp->spp_hbinterval) {
5259224641Stuexen							inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
5260224641Stuexen						}
5261223132Stuexen						sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5262223132Stuexen					} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
5263223132Stuexen						sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5264223132Stuexen					}
5265225635Stuexen					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5266225635Stuexen						sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5267225635Stuexen					} else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
5268225635Stuexen						sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5269225635Stuexen					}
5270225549Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5271226252Stuexen						inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc;
5272225549Stuexen						inp->sctp_ep.default_dscp |= 0x01;
5273225549Stuexen					}
5274225549Stuexen#ifdef INET6
5275225549Stuexen					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5276225549Stuexen						if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
5277225549Stuexen							inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5278225549Stuexen							inp->sctp_ep.default_flowlabel |= 0x80000000;
5279225549Stuexen						}
5280225549Stuexen					}
5281225549Stuexen#endif
5282223132Stuexen					SCTP_INP_WUNLOCK(inp);
5283223132Stuexen				} else {
5284223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5285223132Stuexen					error = EINVAL;
5286163953Srrs				}
5287163953Srrs			}
5288223132Stuexen			break;
5289163953Srrs		}
5290163953Srrs	case SCTP_RTOINFO:
5291163953Srrs		{
5292163953Srrs			struct sctp_rtoinfo *srto;
5293169655Srrs			uint32_t new_init, new_min, new_max;
5294163953Srrs
5295166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
5296166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
5297166675Srrs
5298166675Srrs			if (stcb) {
5299167598Srrs				if (srto->srto_initial)
5300169655Srrs					new_init = srto->srto_initial;
5301169655Srrs				else
5302169655Srrs					new_init = stcb->asoc.initial_rto;
5303167598Srrs				if (srto->srto_max)
5304169655Srrs					new_max = srto->srto_max;
5305169655Srrs				else
5306169655Srrs					new_max = stcb->asoc.maxrto;
5307167598Srrs				if (srto->srto_min)
5308169655Srrs					new_min = srto->srto_min;
5309169655Srrs				else
5310169655Srrs					new_min = stcb->asoc.minrto;
5311169655Srrs				if ((new_min <= new_init) && (new_init <= new_max)) {
5312169655Srrs					stcb->asoc.initial_rto = new_init;
5313169655Srrs					stcb->asoc.maxrto = new_max;
5314169655Srrs					stcb->asoc.minrto = new_min;
5315169655Srrs				} else {
5316179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5317179783Srrs					error = EINVAL;
5318169655Srrs				}
5319166675Srrs				SCTP_TCB_UNLOCK(stcb);
5320166675Srrs			} else {
5321224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5322224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5323224918Stuexen				    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
5324223132Stuexen					SCTP_INP_WLOCK(inp);
5325223132Stuexen					if (srto->srto_initial)
5326223132Stuexen						new_init = srto->srto_initial;
5327223132Stuexen					else
5328223132Stuexen						new_init = inp->sctp_ep.initial_rto;
5329223132Stuexen					if (srto->srto_max)
5330223132Stuexen						new_max = srto->srto_max;
5331223132Stuexen					else
5332223132Stuexen						new_max = inp->sctp_ep.sctp_maxrto;
5333223132Stuexen					if (srto->srto_min)
5334223132Stuexen						new_min = srto->srto_min;
5335223132Stuexen					else
5336223132Stuexen						new_min = inp->sctp_ep.sctp_minrto;
5337223132Stuexen					if ((new_min <= new_init) && (new_init <= new_max)) {
5338223132Stuexen						inp->sctp_ep.initial_rto = new_init;
5339223132Stuexen						inp->sctp_ep.sctp_maxrto = new_max;
5340223132Stuexen						inp->sctp_ep.sctp_minrto = new_min;
5341223132Stuexen					} else {
5342223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5343223132Stuexen						error = EINVAL;
5344223132Stuexen					}
5345223132Stuexen					SCTP_INP_WUNLOCK(inp);
5346169655Srrs				} else {
5347179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5348179783Srrs					error = EINVAL;
5349169655Srrs				}
5350163953Srrs			}
5351223132Stuexen			break;
5352163953Srrs		}
5353163953Srrs	case SCTP_ASSOCINFO:
5354163953Srrs		{
5355163953Srrs			struct sctp_assocparams *sasoc;
5356163953Srrs
5357166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
5358166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
5359171477Srrs			if (sasoc->sasoc_cookie_life) {
5360171477Srrs				/* boundary check the cookie life */
5361171477Srrs				if (sasoc->sasoc_cookie_life < 1000)
5362171477Srrs					sasoc->sasoc_cookie_life = 1000;
5363171477Srrs				if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
5364171477Srrs					sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
5365171477Srrs				}
5366171477Srrs			}
5367163953Srrs			if (stcb) {
5368163953Srrs				if (sasoc->sasoc_asocmaxrxt)
5369163953Srrs					stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
5370170056Srrs				if (sasoc->sasoc_cookie_life) {
5371171572Srrs					stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
5372167598Srrs				}
5373163953Srrs				SCTP_TCB_UNLOCK(stcb);
5374163953Srrs			} else {
5375224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5376224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5377224918Stuexen				    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
5378223132Stuexen					SCTP_INP_WLOCK(inp);
5379223132Stuexen					if (sasoc->sasoc_asocmaxrxt)
5380223132Stuexen						inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
5381223132Stuexen					if (sasoc->sasoc_cookie_life) {
5382223132Stuexen						inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
5383223132Stuexen					}
5384223132Stuexen					SCTP_INP_WUNLOCK(inp);
5385223132Stuexen				} else {
5386223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5387223132Stuexen					error = EINVAL;
5388167598Srrs				}
5389163953Srrs			}
5390223132Stuexen			break;
5391163953Srrs		}
5392163953Srrs	case SCTP_INITMSG:
5393163953Srrs		{
5394163953Srrs			struct sctp_initmsg *sinit;
5395163953Srrs
5396166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
5397163953Srrs			SCTP_INP_WLOCK(inp);
5398163953Srrs			if (sinit->sinit_num_ostreams)
5399163953Srrs				inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
5400163953Srrs
5401163953Srrs			if (sinit->sinit_max_instreams)
5402163953Srrs				inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
5403163953Srrs
5404163953Srrs			if (sinit->sinit_max_attempts)
5405163953Srrs				inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
5406163953Srrs
5407167598Srrs			if (sinit->sinit_max_init_timeo)
5408163953Srrs				inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
5409163953Srrs			SCTP_INP_WUNLOCK(inp);
5410223132Stuexen			break;
5411163953Srrs		}
5412163953Srrs	case SCTP_PRIMARY_ADDR:
5413163953Srrs		{
5414163953Srrs			struct sctp_setprim *spa;
5415223132Stuexen			struct sctp_nets *net;
5416163953Srrs
5417166675Srrs			SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
5418166675Srrs			SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
5419163953Srrs
5420166675Srrs			net = NULL;
5421166675Srrs			if (stcb) {
5422166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
5423166675Srrs			} else {
5424166675Srrs				/*
5425166675Srrs				 * We increment here since
5426166675Srrs				 * sctp_findassociation_ep_addr() wil do a
5427166675Srrs				 * decrement if it finds the stcb as long as
5428166675Srrs				 * the locked tcb (last argument) is NOT a
5429166675Srrs				 * TCB.. aka NULL.
5430166675Srrs				 */
5431163953Srrs				SCTP_INP_INCR_REF(inp);
5432163953Srrs				stcb = sctp_findassociation_ep_addr(&inp,
5433163953Srrs				    (struct sockaddr *)&spa->ssp_addr,
5434163953Srrs				    &net, NULL, NULL);
5435163953Srrs				if (stcb == NULL) {
5436163953Srrs					SCTP_INP_DECR_REF(inp);
5437163953Srrs				}
5438163953Srrs			}
5439166675Srrs
5440166675Srrs			if ((stcb) && (net)) {
5441166675Srrs				if ((net != stcb->asoc.primary_destination) &&
5442166675Srrs				    (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
5443166675Srrs					/* Ok we need to set it */
5444166675Srrs					if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
5445224641Stuexen						if ((stcb->asoc.alternate) &&
5446224641Stuexen						    (!(net->dest_state & SCTP_ADDR_PF)) &&
5447224641Stuexen						    (net->dest_state & SCTP_ADDR_REACHABLE)) {
5448224641Stuexen							sctp_free_remote_addr(stcb->asoc.alternate);
5449224641Stuexen							stcb->asoc.alternate = NULL;
5450166675Srrs						}
5451163953Srrs					}
5452163953Srrs				}
5453166675Srrs			} else {
5454171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5455166675Srrs				error = EINVAL;
5456163953Srrs			}
5457166675Srrs			if (stcb) {
5458166675Srrs				SCTP_TCB_UNLOCK(stcb);
5459166675Srrs			}
5460223132Stuexen			break;
5461163953Srrs		}
5462167598Srrs	case SCTP_SET_DYNAMIC_PRIMARY:
5463167598Srrs		{
5464167598Srrs			union sctp_sockstore *ss;
5465163953Srrs
5466170587Srwatson			error = priv_check(curthread,
5467170587Srwatson			    PRIV_NETINET_RESERVEDPORT);
5468167598Srrs			if (error)
5469167598Srrs				break;
5470167598Srrs
5471167598Srrs			SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
5472167598Srrs			/* SUPER USER CHECK? */
5473167598Srrs			error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
5474223132Stuexen			break;
5475167598Srrs		}
5476163953Srrs	case SCTP_SET_PEER_PRIMARY_ADDR:
5477163953Srrs		{
5478163953Srrs			struct sctp_setpeerprim *sspp;
5479163953Srrs
5480166675Srrs			SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
5481166675Srrs			SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
5482169208Srrs			if (stcb != NULL) {
5483170056Srrs				struct sctp_ifa *ifa;
5484170056Srrs
5485170056Srrs				ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
5486172091Srrs				    stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
5487170056Srrs				if (ifa == NULL) {
5488171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5489166675Srrs					error = EINVAL;
5490170056Srrs					goto out_of_it;
5491166675Srrs				}
5492170056Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
5493170056Srrs					/*
5494170056Srrs					 * Must validate the ifa found is in
5495170056Srrs					 * our ep
5496170056Srrs					 */
5497170056Srrs					struct sctp_laddr *laddr;
5498170056Srrs					int found = 0;
5499170056Srrs
5500170056Srrs					LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
5501170056Srrs						if (laddr->ifa == NULL) {
5502170056Srrs							SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
5503170056Srrs							    __FUNCTION__);
5504170056Srrs							continue;
5505170056Srrs						}
5506170056Srrs						if (laddr->ifa == ifa) {
5507170056Srrs							found = 1;
5508170056Srrs							break;
5509170056Srrs						}
5510170056Srrs					}
5511170056Srrs					if (!found) {
5512171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5513170056Srrs						error = EINVAL;
5514170056Srrs						goto out_of_it;
5515170056Srrs					}
5516267769Stuexen				} else {
5517267769Stuexen					switch (sspp->sspp_addr.ss_family) {
5518267769Stuexen#ifdef INET
5519267769Stuexen					case AF_INET:
5520267769Stuexen						{
5521267769Stuexen							struct sockaddr_in *sin;
5522267769Stuexen
5523267769Stuexen							sin = (struct sockaddr_in *)&sspp->sspp_addr;
5524267769Stuexen							if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
5525267769Stuexen							    &sin->sin_addr) != 0) {
5526267769Stuexen								SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5527267769Stuexen								error = EINVAL;
5528267769Stuexen								goto out_of_it;
5529267769Stuexen							}
5530267769Stuexen							break;
5531267769Stuexen						}
5532267769Stuexen#endif
5533267769Stuexen#ifdef INET6
5534267769Stuexen					case AF_INET6:
5535267769Stuexen						{
5536267769Stuexen							struct sockaddr_in6 *sin6;
5537267769Stuexen
5538267769Stuexen							sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr;
5539267769Stuexen							if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
5540267769Stuexen							    &sin6->sin6_addr) != 0) {
5541267769Stuexen								SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5542267769Stuexen								error = EINVAL;
5543267769Stuexen								goto out_of_it;
5544267769Stuexen							}
5545267769Stuexen							break;
5546267769Stuexen						}
5547267769Stuexen#endif
5548267769Stuexen					default:
5549267769Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5550267769Stuexen						error = EINVAL;
5551267769Stuexen						goto out_of_it;
5552267769Stuexen					}
5553170056Srrs				}
5554170056Srrs				if (sctp_set_primary_ip_address_sa(stcb,
5555170056Srrs				    (struct sockaddr *)&sspp->sspp_addr) != 0) {
5556171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5557170056Srrs					error = EINVAL;
5558170056Srrs				}
5559170056Srrs		out_of_it:
5560169208Srrs				SCTP_TCB_UNLOCK(stcb);
5561166675Srrs			} else {
5562171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5563163953Srrs				error = EINVAL;
5564163953Srrs			}
5565223132Stuexen			break;
5566163953Srrs		}
5567163953Srrs	case SCTP_BINDX_ADD_ADDR:
5568163953Srrs		{
5569163953Srrs			struct sctp_getaddresses *addrs;
5570171477Srrs			struct thread *td;
5571163953Srrs
5572171477Srrs			td = (struct thread *)p;
5573170606Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
5574170606Srrs			    optsize);
5575221249Stuexen#ifdef INET
5576171477Srrs			if (addrs->addr->sa_family == AF_INET) {
5577238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
5578171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5579171477Srrs					error = EINVAL;
5580171477Srrs					break;
5581171477Srrs				}
5582188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
5583188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5584185435Sbz					break;
5585171477Srrs				}
5586221249Stuexen			} else
5587221249Stuexen#endif
5588185435Sbz#ifdef INET6
5589221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
5590238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
5591171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5592171477Srrs					error = EINVAL;
5593171477Srrs					break;
5594171477Srrs				}
5595188590Srrs				if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
5596188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
5597188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5598185435Sbz					break;
5599185435Sbz				}
5600221249Stuexen			} else
5601185435Sbz#endif
5602221249Stuexen			{
5603185435Sbz				error = EAFNOSUPPORT;
5604185435Sbz				break;
5605171477Srrs			}
5606170606Srrs			sctp_bindx_add_address(so, inp, addrs->addr,
5607170606Srrs			    addrs->sget_assoc_id, vrf_id,
5608170606Srrs			    &error, p);
5609223132Stuexen			break;
5610163953Srrs		}
5611163953Srrs	case SCTP_BINDX_REM_ADDR:
5612163953Srrs		{
5613163953Srrs			struct sctp_getaddresses *addrs;
5614171477Srrs			struct thread *td;
5615163953Srrs
5616171477Srrs			td = (struct thread *)p;
5617185435Sbz
5618166675Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
5619221249Stuexen#ifdef INET
5620171477Srrs			if (addrs->addr->sa_family == AF_INET) {
5621238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
5622171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5623171477Srrs					error = EINVAL;
5624171477Srrs					break;
5625171477Srrs				}
5626188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
5627188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5628185435Sbz					break;
5629171477Srrs				}
5630221249Stuexen			} else
5631221249Stuexen#endif
5632185435Sbz#ifdef INET6
5633221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
5634238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
5635171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5636171477Srrs					error = EINVAL;
5637171477Srrs					break;
5638171477Srrs				}
5639224641Stuexen				if (td != NULL &&
5640224641Stuexen				    (error = prison_local_ip6(td->td_ucred,
5641224641Stuexen				    &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
5642188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
5643188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5644185435Sbz					break;
5645185435Sbz				}
5646221249Stuexen			} else
5647185435Sbz#endif
5648221249Stuexen			{
5649185435Sbz				error = EAFNOSUPPORT;
5650185435Sbz				break;
5651171477Srrs			}
5652228653Stuexen			sctp_bindx_delete_address(inp, addrs->addr,
5653170606Srrs			    addrs->sget_assoc_id, vrf_id,
5654170606Srrs			    &error);
5655223132Stuexen			break;
5656163953Srrs		}
5657223132Stuexen	case SCTP_EVENT:
5658223132Stuexen		{
5659223132Stuexen			struct sctp_event *event;
5660223132Stuexen			uint32_t event_type;
5661223132Stuexen
5662223132Stuexen			SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize);
5663223132Stuexen			SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
5664223132Stuexen			switch (event->se_type) {
5665223132Stuexen			case SCTP_ASSOC_CHANGE:
5666223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
5667223132Stuexen				break;
5668223132Stuexen			case SCTP_PEER_ADDR_CHANGE:
5669223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
5670223132Stuexen				break;
5671223132Stuexen			case SCTP_REMOTE_ERROR:
5672223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPEERERR;
5673223132Stuexen				break;
5674223132Stuexen			case SCTP_SEND_FAILED:
5675223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
5676223132Stuexen				break;
5677223132Stuexen			case SCTP_SHUTDOWN_EVENT:
5678223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
5679223132Stuexen				break;
5680223132Stuexen			case SCTP_ADAPTATION_INDICATION:
5681223132Stuexen				event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
5682223132Stuexen				break;
5683223132Stuexen			case SCTP_PARTIAL_DELIVERY_EVENT:
5684223132Stuexen				event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
5685223132Stuexen				break;
5686223132Stuexen			case SCTP_AUTHENTICATION_EVENT:
5687223132Stuexen				event_type = SCTP_PCB_FLAGS_AUTHEVNT;
5688223132Stuexen				break;
5689223132Stuexen			case SCTP_STREAM_RESET_EVENT:
5690223132Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
5691223132Stuexen				break;
5692223132Stuexen			case SCTP_SENDER_DRY_EVENT:
5693223132Stuexen				event_type = SCTP_PCB_FLAGS_DRYEVNT;
5694223132Stuexen				break;
5695223132Stuexen			case SCTP_NOTIFICATIONS_STOPPED_EVENT:
5696223132Stuexen				event_type = 0;
5697223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
5698223132Stuexen				error = ENOTSUP;
5699223132Stuexen				break;
5700235009Stuexen			case SCTP_ASSOC_RESET_EVENT:
5701235009Stuexen				event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
5702235009Stuexen				break;
5703235009Stuexen			case SCTP_STREAM_CHANGE_EVENT:
5704235009Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
5705235009Stuexen				break;
5706235075Stuexen			case SCTP_SEND_FAILED_EVENT:
5707235075Stuexen				event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
5708235075Stuexen				break;
5709223132Stuexen			default:
5710223132Stuexen				event_type = 0;
5711223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5712223132Stuexen				error = EINVAL;
5713223132Stuexen				break;
5714223132Stuexen			}
5715223132Stuexen			if (event_type > 0) {
5716223132Stuexen				if (stcb) {
5717223132Stuexen					if (event->se_on) {
5718223132Stuexen						sctp_stcb_feature_on(inp, stcb, event_type);
5719223132Stuexen						if (event_type == SCTP_PCB_FLAGS_DRYEVNT) {
5720223132Stuexen							if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
5721223132Stuexen							    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
5722223132Stuexen							    (stcb->asoc.stream_queue_cnt == 0)) {
5723223132Stuexen								sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
5724223132Stuexen							}
5725223132Stuexen						}
5726223132Stuexen					} else {
5727223132Stuexen						sctp_stcb_feature_off(inp, stcb, event_type);
5728223132Stuexen					}
5729223132Stuexen					SCTP_TCB_UNLOCK(stcb);
5730223132Stuexen				} else {
5731223132Stuexen					/*
5732223132Stuexen					 * We don't want to send up a storm
5733223132Stuexen					 * of events, so return an error for
5734223132Stuexen					 * sender dry events
5735223132Stuexen					 */
5736223132Stuexen					if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
5737224918Stuexen					    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) &&
5738224918Stuexen					    ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
5739223132Stuexen					    ((event->se_assoc_id == SCTP_ALL_ASSOC) ||
5740223132Stuexen					    (event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
5741223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
5742223132Stuexen						error = ENOTSUP;
5743223132Stuexen						break;
5744223132Stuexen					}
5745224918Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5746224918Stuexen					    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5747224918Stuexen					    (event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
5748223132Stuexen					    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
5749223132Stuexen						SCTP_INP_WLOCK(inp);
5750223132Stuexen						if (event->se_on) {
5751223132Stuexen							sctp_feature_on(inp, event_type);
5752223132Stuexen						} else {
5753223132Stuexen							sctp_feature_off(inp, event_type);
5754223132Stuexen						}
5755223132Stuexen						SCTP_INP_WUNLOCK(inp);
5756223132Stuexen					}
5757223132Stuexen					if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
5758223132Stuexen					    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
5759223132Stuexen						SCTP_INP_RLOCK(inp);
5760223132Stuexen						LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5761223132Stuexen							SCTP_TCB_LOCK(stcb);
5762223132Stuexen							if (event->se_on) {
5763223132Stuexen								sctp_stcb_feature_on(inp, stcb, event_type);
5764223132Stuexen							} else {
5765223132Stuexen								sctp_stcb_feature_off(inp, stcb, event_type);
5766223132Stuexen							}
5767223132Stuexen							SCTP_TCB_UNLOCK(stcb);
5768223132Stuexen						}
5769223132Stuexen						SCTP_INP_RUNLOCK(inp);
5770223132Stuexen					}
5771223132Stuexen				}
5772223132Stuexen			}
5773223132Stuexen			break;
5774223132Stuexen		}
5775223132Stuexen	case SCTP_RECVRCVINFO:
5776223132Stuexen		{
5777223132Stuexen			int *onoff;
5778223132Stuexen
5779223132Stuexen			SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
5780223132Stuexen			SCTP_INP_WLOCK(inp);
5781223132Stuexen			if (*onoff != 0) {
5782223132Stuexen				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
5783223132Stuexen			} else {
5784223132Stuexen				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
5785223132Stuexen			}
5786223132Stuexen			SCTP_INP_WUNLOCK(inp);
5787223132Stuexen			break;
5788223132Stuexen		}
5789223132Stuexen	case SCTP_RECVNXTINFO:
5790223132Stuexen		{
5791223132Stuexen			int *onoff;
5792223132Stuexen
5793223132Stuexen			SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
5794223132Stuexen			SCTP_INP_WLOCK(inp);
5795223132Stuexen			if (*onoff != 0) {
5796223132Stuexen				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
5797223132Stuexen			} else {
5798223132Stuexen				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
5799223132Stuexen			}
5800223132Stuexen			SCTP_INP_WUNLOCK(inp);
5801223132Stuexen			break;
5802223132Stuexen		}
5803223132Stuexen	case SCTP_DEFAULT_SNDINFO:
5804223132Stuexen		{
5805223132Stuexen			struct sctp_sndinfo *info;
5806223162Stuexen			uint16_t policy;
5807223132Stuexen
5808223132Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize);
5809223132Stuexen			SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
5810223132Stuexen
5811223132Stuexen			if (stcb) {
5812223132Stuexen				if (info->snd_sid < stcb->asoc.streamoutcnt) {
5813223132Stuexen					stcb->asoc.def_send.sinfo_stream = info->snd_sid;
5814223162Stuexen					policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
5815223132Stuexen					stcb->asoc.def_send.sinfo_flags = info->snd_flags;
5816223162Stuexen					stcb->asoc.def_send.sinfo_flags |= policy;
5817223132Stuexen					stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
5818223132Stuexen					stcb->asoc.def_send.sinfo_context = info->snd_context;
5819223132Stuexen				} else {
5820223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5821223132Stuexen					error = EINVAL;
5822223132Stuexen				}
5823223132Stuexen				SCTP_TCB_UNLOCK(stcb);
5824223132Stuexen			} else {
5825224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5826224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5827224918Stuexen				    (info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
5828223132Stuexen				    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
5829223132Stuexen					SCTP_INP_WLOCK(inp);
5830223132Stuexen					inp->def_send.sinfo_stream = info->snd_sid;
5831223162Stuexen					policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
5832223132Stuexen					inp->def_send.sinfo_flags = info->snd_flags;
5833223162Stuexen					inp->def_send.sinfo_flags |= policy;
5834223132Stuexen					inp->def_send.sinfo_ppid = info->snd_ppid;
5835223132Stuexen					inp->def_send.sinfo_context = info->snd_context;
5836223132Stuexen					SCTP_INP_WUNLOCK(inp);
5837223132Stuexen				}
5838223132Stuexen				if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
5839223132Stuexen				    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
5840223132Stuexen					SCTP_INP_RLOCK(inp);
5841223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5842223132Stuexen						SCTP_TCB_LOCK(stcb);
5843223132Stuexen						if (info->snd_sid < stcb->asoc.streamoutcnt) {
5844223132Stuexen							stcb->asoc.def_send.sinfo_stream = info->snd_sid;
5845223162Stuexen							policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
5846223132Stuexen							stcb->asoc.def_send.sinfo_flags = info->snd_flags;
5847223162Stuexen							stcb->asoc.def_send.sinfo_flags |= policy;
5848223132Stuexen							stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
5849223132Stuexen							stcb->asoc.def_send.sinfo_context = info->snd_context;
5850223132Stuexen						}
5851223132Stuexen						SCTP_TCB_UNLOCK(stcb);
5852223132Stuexen					}
5853223132Stuexen					SCTP_INP_RUNLOCK(inp);
5854223132Stuexen				}
5855223132Stuexen			}
5856223132Stuexen			break;
5857223132Stuexen		}
5858223162Stuexen	case SCTP_DEFAULT_PRINFO:
5859223162Stuexen		{
5860223162Stuexen			struct sctp_default_prinfo *info;
5861223162Stuexen
5862223162Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize);
5863223162Stuexen			SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
5864223162Stuexen
5865223162Stuexen			if (PR_SCTP_INVALID_POLICY(info->pr_policy)) {
5866223162Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5867223162Stuexen				error = EINVAL;
5868223162Stuexen				break;
5869223162Stuexen			}
5870223162Stuexen			if (stcb) {
5871223162Stuexen				stcb->asoc.def_send.sinfo_flags &= 0xfff0;
5872223162Stuexen				stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
5873224918Stuexen				stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
5874223162Stuexen				SCTP_TCB_UNLOCK(stcb);
5875223162Stuexen			} else {
5876224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5877224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5878224918Stuexen				    (info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
5879223162Stuexen				    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
5880223162Stuexen					SCTP_INP_WLOCK(inp);
5881223162Stuexen					inp->def_send.sinfo_flags &= 0xfff0;
5882223162Stuexen					inp->def_send.sinfo_flags |= info->pr_policy;
5883224918Stuexen					inp->def_send.sinfo_timetolive = info->pr_value;
5884223162Stuexen					SCTP_INP_WUNLOCK(inp);
5885223162Stuexen				}
5886223162Stuexen				if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
5887223162Stuexen				    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
5888223162Stuexen					SCTP_INP_RLOCK(inp);
5889223162Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5890223162Stuexen						SCTP_TCB_LOCK(stcb);
5891223162Stuexen						stcb->asoc.def_send.sinfo_flags &= 0xfff0;
5892223162Stuexen						stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
5893224918Stuexen						stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
5894223162Stuexen						SCTP_TCB_UNLOCK(stcb);
5895223162Stuexen					}
5896223162Stuexen					SCTP_INP_RUNLOCK(inp);
5897223162Stuexen				}
5898223162Stuexen			}
5899223162Stuexen			break;
5900223162Stuexen		}
5901224641Stuexen	case SCTP_PEER_ADDR_THLDS:
5902224641Stuexen		/* Applies to the specific association */
5903224641Stuexen		{
5904224641Stuexen			struct sctp_paddrthlds *thlds;
5905224641Stuexen			struct sctp_nets *net;
5906224641Stuexen
5907224641Stuexen			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
5908224641Stuexen			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
5909224641Stuexen			net = NULL;
5910224641Stuexen			if (stcb) {
5911267770Stuexen				net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address);
5912224641Stuexen			} else {
5913224641Stuexen				/*
5914224641Stuexen				 * We increment here since
5915224641Stuexen				 * sctp_findassociation_ep_addr() wil do a
5916224641Stuexen				 * decrement if it finds the stcb as long as
5917224641Stuexen				 * the locked tcb (last argument) is NOT a
5918224641Stuexen				 * TCB.. aka NULL.
5919224641Stuexen				 */
5920224641Stuexen				SCTP_INP_INCR_REF(inp);
5921224641Stuexen				stcb = sctp_findassociation_ep_addr(&inp,
5922267770Stuexen				    (struct sockaddr *)&thlds->spt_address,
5923224641Stuexen				    &net, NULL, NULL);
5924224641Stuexen				if (stcb == NULL) {
5925224641Stuexen					SCTP_INP_DECR_REF(inp);
5926224641Stuexen				}
5927224641Stuexen			}
5928224641Stuexen			if (stcb && (net == NULL)) {
5929224641Stuexen				struct sockaddr *sa;
5930224641Stuexen
5931267770Stuexen				sa = (struct sockaddr *)&thlds->spt_address;
5932224641Stuexen#ifdef INET
5933224641Stuexen				if (sa->sa_family == AF_INET) {
5934224641Stuexen
5935224641Stuexen					struct sockaddr_in *sin;
5936224641Stuexen
5937224641Stuexen					sin = (struct sockaddr_in *)sa;
5938224641Stuexen					if (sin->sin_addr.s_addr) {
5939224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5940224641Stuexen						SCTP_TCB_UNLOCK(stcb);
5941224641Stuexen						error = EINVAL;
5942224641Stuexen						break;
5943224641Stuexen					}
5944224641Stuexen				} else
5945224641Stuexen#endif
5946224641Stuexen#ifdef INET6
5947224641Stuexen				if (sa->sa_family == AF_INET6) {
5948224641Stuexen					struct sockaddr_in6 *sin6;
5949224641Stuexen
5950224641Stuexen					sin6 = (struct sockaddr_in6 *)sa;
5951224641Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
5952224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5953224641Stuexen						SCTP_TCB_UNLOCK(stcb);
5954224641Stuexen						error = EINVAL;
5955224641Stuexen						break;
5956224641Stuexen					}
5957224641Stuexen				} else
5958224641Stuexen#endif
5959224641Stuexen				{
5960224641Stuexen					error = EAFNOSUPPORT;
5961224641Stuexen					SCTP_TCB_UNLOCK(stcb);
5962224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5963224641Stuexen					break;
5964224641Stuexen				}
5965224641Stuexen			}
5966224641Stuexen			if (stcb) {
5967224641Stuexen				if (net) {
5968224641Stuexen					if (net->dest_state & SCTP_ADDR_PF) {
5969224641Stuexen						if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
5970224641Stuexen						    (net->failure_threshold <= thlds->spt_pathpfthld)) {
5971224641Stuexen							net->dest_state &= ~SCTP_ADDR_PF;
5972224641Stuexen						}
5973224641Stuexen					} else {
5974224641Stuexen						if ((net->failure_threshold > thlds->spt_pathpfthld) &&
5975224641Stuexen						    (net->failure_threshold <= thlds->spt_pathmaxrxt)) {
5976224641Stuexen							net->dest_state |= SCTP_ADDR_PF;
5977224641Stuexen							sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5978224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
5979224641Stuexen							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5980224641Stuexen						}
5981224641Stuexen					}
5982224641Stuexen					if (net->dest_state & SCTP_ADDR_REACHABLE) {
5983224641Stuexen						if (net->failure_threshold > thlds->spt_pathmaxrxt) {
5984224641Stuexen							net->dest_state &= ~SCTP_ADDR_REACHABLE;
5985235414Stuexen							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5986224641Stuexen						}
5987224641Stuexen					} else {
5988224641Stuexen						if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
5989224641Stuexen							net->dest_state |= SCTP_ADDR_REACHABLE;
5990235414Stuexen							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5991224641Stuexen						}
5992224641Stuexen					}
5993224641Stuexen					net->failure_threshold = thlds->spt_pathmaxrxt;
5994224641Stuexen					net->pf_threshold = thlds->spt_pathpfthld;
5995224641Stuexen				} else {
5996224641Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5997224641Stuexen						if (net->dest_state & SCTP_ADDR_PF) {
5998224641Stuexen							if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
5999224641Stuexen							    (net->failure_threshold <= thlds->spt_pathpfthld)) {
6000224641Stuexen								net->dest_state &= ~SCTP_ADDR_PF;
6001224641Stuexen							}
6002224641Stuexen						} else {
6003224641Stuexen							if ((net->failure_threshold > thlds->spt_pathpfthld) &&
6004224641Stuexen							    (net->failure_threshold <= thlds->spt_pathmaxrxt)) {
6005224641Stuexen								net->dest_state |= SCTP_ADDR_PF;
6006224641Stuexen								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
6007224641Stuexen								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
6008224641Stuexen								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
6009224641Stuexen							}
6010224641Stuexen						}
6011224641Stuexen						if (net->dest_state & SCTP_ADDR_REACHABLE) {
6012224641Stuexen							if (net->failure_threshold > thlds->spt_pathmaxrxt) {
6013224641Stuexen								net->dest_state &= ~SCTP_ADDR_REACHABLE;
6014235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
6015224641Stuexen							}
6016224641Stuexen						} else {
6017224641Stuexen							if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
6018224641Stuexen								net->dest_state |= SCTP_ADDR_REACHABLE;
6019235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
6020224641Stuexen							}
6021224641Stuexen						}
6022224641Stuexen						net->failure_threshold = thlds->spt_pathmaxrxt;
6023224641Stuexen						net->pf_threshold = thlds->spt_pathpfthld;
6024224641Stuexen					}
6025224641Stuexen					stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
6026224641Stuexen					stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
6027224641Stuexen				}
6028224641Stuexen			} else {
6029224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6030224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6031224918Stuexen				    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
6032224641Stuexen					SCTP_INP_WLOCK(inp);
6033224641Stuexen					inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
6034224641Stuexen					inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
6035224641Stuexen					SCTP_INP_WUNLOCK(inp);
6036224641Stuexen				} else {
6037224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6038224641Stuexen					error = EINVAL;
6039224641Stuexen				}
6040224641Stuexen			}
6041224641Stuexen			break;
6042224641Stuexen		}
6043227755Stuexen	case SCTP_REMOTE_UDP_ENCAPS_PORT:
6044227755Stuexen		{
6045227755Stuexen			struct sctp_udpencaps *encaps;
6046227755Stuexen			struct sctp_nets *net;
6047227755Stuexen
6048227755Stuexen			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize);
6049227755Stuexen			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
6050227755Stuexen			if (stcb) {
6051227755Stuexen				net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address);
6052227755Stuexen			} else {
6053227755Stuexen				/*
6054227755Stuexen				 * We increment here since
6055227755Stuexen				 * sctp_findassociation_ep_addr() wil do a
6056227755Stuexen				 * decrement if it finds the stcb as long as
6057227755Stuexen				 * the locked tcb (last argument) is NOT a
6058227755Stuexen				 * TCB.. aka NULL.
6059227755Stuexen				 */
6060227755Stuexen				net = NULL;
6061227755Stuexen				SCTP_INP_INCR_REF(inp);
6062227755Stuexen				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL);
6063227755Stuexen				if (stcb == NULL) {
6064227755Stuexen					SCTP_INP_DECR_REF(inp);
6065227755Stuexen				}
6066227755Stuexen			}
6067227755Stuexen			if (stcb && (net == NULL)) {
6068227755Stuexen				struct sockaddr *sa;
6069227755Stuexen
6070227755Stuexen				sa = (struct sockaddr *)&encaps->sue_address;
6071227755Stuexen#ifdef INET
6072227755Stuexen				if (sa->sa_family == AF_INET) {
6073227755Stuexen
6074227755Stuexen					struct sockaddr_in *sin;
6075227755Stuexen
6076227755Stuexen					sin = (struct sockaddr_in *)sa;
6077227755Stuexen					if (sin->sin_addr.s_addr) {
6078227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6079227755Stuexen						SCTP_TCB_UNLOCK(stcb);
6080227755Stuexen						error = EINVAL;
6081227755Stuexen						break;
6082227755Stuexen					}
6083227755Stuexen				} else
6084227755Stuexen#endif
6085227755Stuexen#ifdef INET6
6086227755Stuexen				if (sa->sa_family == AF_INET6) {
6087227755Stuexen					struct sockaddr_in6 *sin6;
6088227755Stuexen
6089227755Stuexen					sin6 = (struct sockaddr_in6 *)sa;
6090227755Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
6091227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6092227755Stuexen						SCTP_TCB_UNLOCK(stcb);
6093227755Stuexen						error = EINVAL;
6094227755Stuexen						break;
6095227755Stuexen					}
6096227755Stuexen				} else
6097227755Stuexen#endif
6098227755Stuexen				{
6099227755Stuexen					error = EAFNOSUPPORT;
6100227755Stuexen					SCTP_TCB_UNLOCK(stcb);
6101227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6102227755Stuexen					break;
6103227755Stuexen				}
6104227755Stuexen			}
6105227755Stuexen			if (stcb) {
6106227755Stuexen				if (net) {
6107227755Stuexen					net->port = encaps->sue_port;
6108227755Stuexen				} else {
6109227755Stuexen					stcb->asoc.port = encaps->sue_port;
6110227755Stuexen				}
6111227755Stuexen				SCTP_TCB_UNLOCK(stcb);
6112227755Stuexen			} else {
6113227755Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6114227755Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6115227755Stuexen				    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
6116227755Stuexen					SCTP_INP_WLOCK(inp);
6117227755Stuexen					inp->sctp_ep.port = encaps->sue_port;
6118227755Stuexen					SCTP_INP_WUNLOCK(inp);
6119227755Stuexen				} else {
6120227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6121227755Stuexen					error = EINVAL;
6122227755Stuexen				}
6123227755Stuexen			}
6124227755Stuexen			break;
6125227755Stuexen		}
6126270356Stuexen	case SCTP_ECN_SUPPORTED:
6127270356Stuexen		{
6128270356Stuexen			struct sctp_assoc_value *av;
6129270356Stuexen
6130270356Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6131270356Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6132270356Stuexen
6133270356Stuexen			if (stcb) {
6134270356Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6135270356Stuexen				error = EINVAL;
6136270356Stuexen				SCTP_TCB_UNLOCK(stcb);
6137270356Stuexen			} else {
6138270356Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6139270356Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6140270356Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6141270356Stuexen					SCTP_INP_WLOCK(inp);
6142270356Stuexen					if (av->assoc_value == 0) {
6143270356Stuexen						inp->ecn_supported = 0;
6144270356Stuexen					} else {
6145270356Stuexen						inp->ecn_supported = 1;
6146270356Stuexen					}
6147270356Stuexen					SCTP_INP_WUNLOCK(inp);
6148270356Stuexen				} else {
6149270356Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6150270356Stuexen					error = EINVAL;
6151270356Stuexen				}
6152270356Stuexen			}
6153270356Stuexen			break;
6154270356Stuexen		}
6155270357Stuexen	case SCTP_PR_SUPPORTED:
6156270357Stuexen		{
6157270357Stuexen			struct sctp_assoc_value *av;
6158270357Stuexen
6159270357Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6160270357Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6161270357Stuexen
6162270357Stuexen			if (stcb) {
6163270357Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6164270357Stuexen				error = EINVAL;
6165270357Stuexen				SCTP_TCB_UNLOCK(stcb);
6166270357Stuexen			} else {
6167270357Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6168270357Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6169270357Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6170270357Stuexen					SCTP_INP_WLOCK(inp);
6171270357Stuexen					if (av->assoc_value == 0) {
6172270357Stuexen						inp->prsctp_supported = 0;
6173270357Stuexen					} else {
6174270357Stuexen						inp->prsctp_supported = 1;
6175270357Stuexen					}
6176270357Stuexen					SCTP_INP_WUNLOCK(inp);
6177270357Stuexen				} else {
6178270357Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6179270357Stuexen					error = EINVAL;
6180270357Stuexen				}
6181270357Stuexen			}
6182270357Stuexen			break;
6183270357Stuexen		}
6184270362Stuexen	case SCTP_AUTH_SUPPORTED:
6185270362Stuexen		{
6186270362Stuexen			struct sctp_assoc_value *av;
6187270362Stuexen
6188270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6189270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6190270362Stuexen
6191270362Stuexen			if (stcb) {
6192270362Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6193270362Stuexen				error = EINVAL;
6194270362Stuexen				SCTP_TCB_UNLOCK(stcb);
6195270362Stuexen			} else {
6196270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6197270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6198270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6199270362Stuexen					if ((av->assoc_value == 0) &&
6200270362Stuexen					    (inp->asconf_supported == 1)) {
6201270362Stuexen						/*
6202270362Stuexen						 * AUTH is required for
6203270362Stuexen						 * ASCONF
6204270362Stuexen						 */
6205270362Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6206270362Stuexen						error = EINVAL;
6207270362Stuexen					} else {
6208270362Stuexen						SCTP_INP_WLOCK(inp);
6209270362Stuexen						if (av->assoc_value == 0) {
6210270362Stuexen							inp->auth_supported = 0;
6211270362Stuexen						} else {
6212270362Stuexen							inp->auth_supported = 1;
6213270362Stuexen						}
6214270362Stuexen						SCTP_INP_WUNLOCK(inp);
6215270362Stuexen					}
6216270362Stuexen				} else {
6217270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6218270362Stuexen					error = EINVAL;
6219270362Stuexen				}
6220270362Stuexen			}
6221270362Stuexen			break;
6222270362Stuexen		}
6223270362Stuexen	case SCTP_ASCONF_SUPPORTED:
6224270362Stuexen		{
6225270362Stuexen			struct sctp_assoc_value *av;
6226270362Stuexen
6227270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6228270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6229270362Stuexen
6230270362Stuexen			if (stcb) {
6231270362Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6232270362Stuexen				error = EINVAL;
6233270362Stuexen				SCTP_TCB_UNLOCK(stcb);
6234270362Stuexen			} else {
6235270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6236270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6237270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6238270362Stuexen					if ((av->assoc_value != 0) &&
6239270362Stuexen					    (inp->auth_supported == 0)) {
6240270362Stuexen						/*
6241270362Stuexen						 * AUTH is required for
6242270362Stuexen						 * ASCONF
6243270362Stuexen						 */
6244270362Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6245270362Stuexen						error = EINVAL;
6246270362Stuexen					} else {
6247270362Stuexen						SCTP_INP_WLOCK(inp);
6248270362Stuexen						if (av->assoc_value == 0) {
6249270362Stuexen							inp->asconf_supported = 0;
6250270362Stuexen							sctp_auth_delete_chunk(SCTP_ASCONF,
6251270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6252270362Stuexen							sctp_auth_delete_chunk(SCTP_ASCONF_ACK,
6253270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6254270362Stuexen						} else {
6255270362Stuexen							inp->asconf_supported = 1;
6256270362Stuexen							sctp_auth_add_chunk(SCTP_ASCONF,
6257270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6258270362Stuexen							sctp_auth_add_chunk(SCTP_ASCONF_ACK,
6259270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6260270362Stuexen						}
6261270362Stuexen						SCTP_INP_WUNLOCK(inp);
6262270362Stuexen					}
6263270362Stuexen				} else {
6264270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6265270362Stuexen					error = EINVAL;
6266270362Stuexen				}
6267270362Stuexen			}
6268270362Stuexen			break;
6269270362Stuexen		}
6270270361Stuexen	case SCTP_RECONFIG_SUPPORTED:
6271270361Stuexen		{
6272270361Stuexen			struct sctp_assoc_value *av;
6273270361Stuexen
6274270361Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6275270361Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6276270361Stuexen
6277270361Stuexen			if (stcb) {
6278270361Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6279270361Stuexen				error = EINVAL;
6280270361Stuexen				SCTP_TCB_UNLOCK(stcb);
6281270361Stuexen			} else {
6282270361Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6283270361Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6284270361Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6285270361Stuexen					SCTP_INP_WLOCK(inp);
6286270361Stuexen					if (av->assoc_value == 0) {
6287270361Stuexen						inp->reconfig_supported = 0;
6288270361Stuexen					} else {
6289270361Stuexen						inp->reconfig_supported = 1;
6290270361Stuexen					}
6291270361Stuexen					SCTP_INP_WUNLOCK(inp);
6292270361Stuexen				} else {
6293270361Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6294270361Stuexen					error = EINVAL;
6295270361Stuexen				}
6296270361Stuexen			}
6297270361Stuexen			break;
6298270361Stuexen		}
6299270359Stuexen	case SCTP_NRSACK_SUPPORTED:
6300270359Stuexen		{
6301270359Stuexen			struct sctp_assoc_value *av;
6302270359Stuexen
6303270359Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6304270359Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6305270359Stuexen
6306270359Stuexen			if (stcb) {
6307270359Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6308270359Stuexen				error = EINVAL;
6309270359Stuexen				SCTP_TCB_UNLOCK(stcb);
6310270359Stuexen			} else {
6311270359Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6312270359Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6313270359Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6314270359Stuexen					SCTP_INP_WLOCK(inp);
6315270359Stuexen					if (av->assoc_value == 0) {
6316270359Stuexen						inp->nrsack_supported = 0;
6317270359Stuexen					} else {
6318270359Stuexen						inp->nrsack_supported = 1;
6319270359Stuexen					}
6320270359Stuexen					SCTP_INP_WUNLOCK(inp);
6321270359Stuexen				} else {
6322270359Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6323270359Stuexen					error = EINVAL;
6324270359Stuexen				}
6325270359Stuexen			}
6326270359Stuexen			break;
6327270359Stuexen		}
6328270360Stuexen	case SCTP_PKTDROP_SUPPORTED:
6329270360Stuexen		{
6330270360Stuexen			struct sctp_assoc_value *av;
6331270360Stuexen
6332270360Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6333270360Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6334270360Stuexen
6335270360Stuexen			if (stcb) {
6336270360Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6337270360Stuexen				error = EINVAL;
6338270360Stuexen				SCTP_TCB_UNLOCK(stcb);
6339270360Stuexen			} else {
6340270360Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6341270360Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6342270360Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6343270360Stuexen					SCTP_INP_WLOCK(inp);
6344270360Stuexen					if (av->assoc_value == 0) {
6345270360Stuexen						inp->pktdrop_supported = 0;
6346270360Stuexen					} else {
6347270360Stuexen						inp->pktdrop_supported = 1;
6348270360Stuexen					}
6349270360Stuexen					SCTP_INP_WUNLOCK(inp);
6350270360Stuexen				} else {
6351270360Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6352270360Stuexen					error = EINVAL;
6353270360Stuexen				}
6354270360Stuexen			}
6355270360Stuexen			break;
6356270360Stuexen		}
6357163953Srrs	default:
6358171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
6359163953Srrs		error = ENOPROTOOPT;
6360163953Srrs		break;
6361163953Srrs	}			/* end switch (opt) */
6362163953Srrs	return (error);
6363163953Srrs}
6364163953Srrs
6365163953Srrsint
6366163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt)
6367163953Srrs{
6368166675Srrs	void *optval = NULL;
6369166675Srrs	size_t optsize = 0;
6370166675Srrs	void *p;
6371166675Srrs	int error = 0;
6372163953Srrs
6373163953Srrs	if (sopt->sopt_level != IPPROTO_SCTP) {
6374163953Srrs		/* wrong proto level... send back up to IP */
6375163953Srrs#ifdef INET6
6376163953Srrs		if (INP_CHECK_SOCKAF(so, AF_INET6))
6377163953Srrs			error = ip6_ctloutput(so, sopt);
6378221249Stuexen#endif				/* INET6 */
6379237565Stuexen#if defined(INET) && defined(INET6)
6380163953Srrs		else
6381221249Stuexen#endif
6382221249Stuexen#ifdef INET
6383163953Srrs			error = ip_ctloutput(so, sopt);
6384221249Stuexen#endif
6385163953Srrs		return (error);
6386163953Srrs	}
6387166675Srrs	optsize = sopt->sopt_valsize;
6388166675Srrs	if (optsize) {
6389170091Srrs		SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
6390166675Srrs		if (optval == NULL) {
6391235091Stuexen			SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
6392163953Srrs			return (ENOBUFS);
6393163953Srrs		}
6394166675Srrs		error = sooptcopyin(sopt, optval, optsize, optsize);
6395163953Srrs		if (error) {
6396170091Srrs			SCTP_FREE(optval, SCTP_M_SOCKOPT);
6397163953Srrs			goto out;
6398163953Srrs		}
6399163953Srrs	}
6400166675Srrs	p = (void *)sopt->sopt_td;
6401163953Srrs	if (sopt->sopt_dir == SOPT_SET) {
6402166675Srrs		error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
6403163953Srrs	} else if (sopt->sopt_dir == SOPT_GET) {
6404166675Srrs		error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
6405163953Srrs	} else {
6406235091Stuexen		SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6407163953Srrs		error = EINVAL;
6408163953Srrs	}
6409166675Srrs	if ((error == 0) && (optval != NULL)) {
6410166675Srrs		error = sooptcopyout(sopt, optval, optsize);
6411170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
6412166675Srrs	} else if (optval != NULL) {
6413170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
6414163953Srrs	}
6415163953Srrsout:
6416163953Srrs	return (error);
6417163953Srrs}
6418163953Srrs
6419221249Stuexen#ifdef INET
6420163953Srrsstatic int
6421163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
6422163953Srrs{
6423163953Srrs	int error = 0;
6424163953Srrs	int create_lock_on = 0;
6425167598Srrs	uint32_t vrf_id;
6426163953Srrs	struct sctp_inpcb *inp;
6427163953Srrs	struct sctp_tcb *stcb = NULL;
6428163953Srrs
6429163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6430233005Stuexen	if (inp == NULL) {
6431163953Srrs		/* I made the same as TCP since we are not setup? */
6432171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6433163953Srrs		return (ECONNRESET);
6434163953Srrs	}
6435171943Srrs	if (addr == NULL) {
6436171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6437170056Srrs		return EINVAL;
6438171943Srrs	}
6439221249Stuexen	switch (addr->sa_family) {
6440185435Sbz#ifdef INET6
6441221249Stuexen	case AF_INET6:
6442221249Stuexen		{
6443221249Stuexen			struct sockaddr_in6 *sin6p;
6444185694Srrs
6445221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
6446221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6447221249Stuexen				return (EINVAL);
6448221249Stuexen			}
6449221249Stuexen			sin6p = (struct sockaddr_in6 *)addr;
6450221249Stuexen			if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
6451221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6452221249Stuexen				return (error);
6453221249Stuexen			}
6454221249Stuexen			break;
6455185435Sbz		}
6456185435Sbz#endif
6457221249Stuexen#ifdef INET
6458221249Stuexen	case AF_INET:
6459221249Stuexen		{
6460221249Stuexen			struct sockaddr_in *sinp;
6461185694Srrs
6462221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
6463221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6464221249Stuexen				return (EINVAL);
6465221249Stuexen			}
6466221249Stuexen			sinp = (struct sockaddr_in *)addr;
6467221249Stuexen			if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) {
6468221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6469221249Stuexen				return (error);
6470221249Stuexen			}
6471221249Stuexen			break;
6472185435Sbz		}
6473221249Stuexen#endif
6474221249Stuexen	default:
6475185435Sbz		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
6476185435Sbz		return (EAFNOSUPPORT);
6477170056Srrs	}
6478178202Srrs	SCTP_INP_INCR_REF(inp);
6479163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
6480163953Srrs	create_lock_on = 1;
6481163953Srrs
6482178202Srrs
6483163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
6484163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
6485163953Srrs		/* Should I really unlock ? */
6486171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
6487163953Srrs		error = EFAULT;
6488163953Srrs		goto out_now;
6489163953Srrs	}
6490163953Srrs#ifdef INET6
6491163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
6492163953Srrs	    (addr->sa_family == AF_INET6)) {
6493171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6494163953Srrs		error = EINVAL;
6495163953Srrs		goto out_now;
6496163953Srrs	}
6497246595Stuexen#endif
6498163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
6499163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
6500163953Srrs		/* Bind a ephemeral port */
6501171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
6502163953Srrs		if (error) {
6503163953Srrs			goto out_now;
6504163953Srrs		}
6505163953Srrs	}
6506163953Srrs	/* Now do we connect? */
6507181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
6508181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
6509171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6510163953Srrs		error = EINVAL;
6511163953Srrs		goto out_now;
6512163953Srrs	}
6513163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
6514163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
6515163953Srrs		/* We are already connected AND the TCP model */
6516171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
6517163953Srrs		error = EADDRINUSE;
6518163953Srrs		goto out_now;
6519163953Srrs	}
6520163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
6521163953Srrs		SCTP_INP_RLOCK(inp);
6522163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
6523163953Srrs		SCTP_INP_RUNLOCK(inp);
6524163953Srrs	} else {
6525163953Srrs		/*
6526166675Srrs		 * We increment here since sctp_findassociation_ep_addr()
6527181054Srrs		 * will do a decrement if it finds the stcb as long as the
6528166675Srrs		 * locked tcb (last argument) is NOT a TCB.. aka NULL.
6529163953Srrs		 */
6530163953Srrs		SCTP_INP_INCR_REF(inp);
6531163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
6532163953Srrs		if (stcb == NULL) {
6533163953Srrs			SCTP_INP_DECR_REF(inp);
6534168299Srrs		} else {
6535178202Srrs			SCTP_TCB_UNLOCK(stcb);
6536163953Srrs		}
6537163953Srrs	}
6538163953Srrs	if (stcb != NULL) {
6539163953Srrs		/* Already have or am bring up an association */
6540171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
6541163953Srrs		error = EALREADY;
6542163953Srrs		goto out_now;
6543163953Srrs	}
6544168299Srrs	vrf_id = inp->def_vrf_id;
6545163953Srrs	/* We are GOOD to go */
6546206137Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
6547163953Srrs	if (stcb == NULL) {
6548163953Srrs		/* Gak! no memory */
6549167598Srrs		goto out_now;
6550163953Srrs	}
6551163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
6552163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
6553163953Srrs		/* Set the connected flag so we can queue data */
6554163953Srrs		soisconnecting(so);
6555163953Srrs	}
6556171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
6557169378Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
6558163953Srrs
6559163953Srrs	/* initialize authentication parameters for the assoc */
6560163953Srrs	sctp_initialize_auth_params(inp, stcb);
6561163953Srrs
6562172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
6563168299Srrs	SCTP_TCB_UNLOCK(stcb);
6564163953Srrsout_now:
6565169420Srrs	if (create_lock_on) {
6566163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
6567169420Srrs	}
6568163953Srrs	SCTP_INP_DECR_REF(inp);
6569228907Stuexen	return (error);
6570163953Srrs}
6571163953Srrs
6572221249Stuexen#endif
6573221249Stuexen
6574163953Srrsint
6575163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p)
6576163953Srrs{
6577163953Srrs	/*
6578163953Srrs	 * Note this module depends on the protocol processing being called
6579163953Srrs	 * AFTER any socket level flags and backlog are applied to the
6580163953Srrs	 * socket. The traditional way that the socket flags are applied is
6581163953Srrs	 * AFTER protocol processing. We have made a change to the
6582163953Srrs	 * sys/kern/uipc_socket.c module to reverse this but this MUST be in
6583163953Srrs	 * place if the socket API for SCTP is to work properly.
6584163953Srrs	 */
6585163953Srrs
6586163953Srrs	int error = 0;
6587163953Srrs	struct sctp_inpcb *inp;
6588163953Srrs
6589163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6590233005Stuexen	if (inp == NULL) {
6591163953Srrs		/* I made the same as TCP since we are not setup? */
6592171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6593163953Srrs		return (ECONNRESET);
6594163953Srrs	}
6595181054Srrs	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
6596181054Srrs		/* See if we have a listener */
6597181054Srrs		struct sctp_inpcb *tinp;
6598267771Stuexen		union sctp_sockstore store;
6599181054Srrs
6600181054Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
6601181054Srrs			/* not bound all */
6602181054Srrs			struct sctp_laddr *laddr;
6603181054Srrs
6604181054Srrs			LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
6605181054Srrs				memcpy(&store, &laddr->ifa->address, sizeof(store));
6606267771Stuexen				switch (store.sa.sa_family) {
6607221249Stuexen#ifdef INET
6608221249Stuexen				case AF_INET:
6609267771Stuexen					store.sin.sin_port = inp->sctp_lport;
6610221249Stuexen					break;
6611221249Stuexen#endif
6612221249Stuexen#ifdef INET6
6613221249Stuexen				case AF_INET6:
6614267771Stuexen					store.sin6.sin6_port = inp->sctp_lport;
6615221249Stuexen					break;
6616221249Stuexen#endif
6617221249Stuexen				default:
6618221249Stuexen					break;
6619221249Stuexen				}
6620267771Stuexen				tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
6621181054Srrs				if (tinp && (tinp != inp) &&
6622181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
6623181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
6624181054Srrs				    (tinp->sctp_socket->so_qlimit)) {
6625181054Srrs					/*
6626181054Srrs					 * we have a listener already and
6627181054Srrs					 * its not this inp.
6628181054Srrs					 */
6629181054Srrs					SCTP_INP_DECR_REF(tinp);
6630181054Srrs					return (EADDRINUSE);
6631181054Srrs				} else if (tinp) {
6632181054Srrs					SCTP_INP_DECR_REF(tinp);
6633181054Srrs				}
6634181054Srrs			}
6635181054Srrs		} else {
6636181054Srrs			/* Setup a local addr bound all */
6637181054Srrs			memset(&store, 0, sizeof(store));
6638267771Stuexen#ifdef INET6
6639267771Stuexen			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
6640267771Stuexen				store.sa.sa_family = AF_INET6;
6641267771Stuexen				store.sa.sa_len = sizeof(struct sockaddr_in6);
6642267771Stuexen			}
6643267771Stuexen#endif
6644221249Stuexen#ifdef INET
6645267771Stuexen			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
6646267771Stuexen				store.sa.sa_family = AF_INET;
6647267771Stuexen				store.sa.sa_len = sizeof(struct sockaddr_in);
6648267771Stuexen			}
6649267771Stuexen#endif
6650267771Stuexen			switch (store.sa.sa_family) {
6651267771Stuexen#ifdef INET
6652221249Stuexen			case AF_INET:
6653221249Stuexen				store.sin.sin_port = inp->sctp_lport;
6654221249Stuexen				break;
6655221249Stuexen#endif
6656181054Srrs#ifdef INET6
6657221249Stuexen			case AF_INET6:
6658267771Stuexen				store.sin6.sin6_port = inp->sctp_lport;
6659221249Stuexen				break;
6660221249Stuexen#endif
6661221249Stuexen			default:
6662221249Stuexen				break;
6663221249Stuexen			}
6664267771Stuexen			tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
6665181054Srrs			if (tinp && (tinp != inp) &&
6666181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
6667181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
6668181054Srrs			    (tinp->sctp_socket->so_qlimit)) {
6669181054Srrs				/*
6670181054Srrs				 * we have a listener already and its not
6671181054Srrs				 * this inp.
6672181054Srrs				 */
6673181054Srrs				SCTP_INP_DECR_REF(tinp);
6674181054Srrs				return (EADDRINUSE);
6675181054Srrs			} else if (tinp) {
6676181054Srrs				SCTP_INP_DECR_REF(inp);
6677181054Srrs			}
6678181054Srrs		}
6679181054Srrs	}
6680163953Srrs	SCTP_INP_RLOCK(inp);
6681163953Srrs#ifdef SCTP_LOCK_LOGGING
6682179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
6683170744Srrs		sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
6684170744Srrs	}
6685163953Srrs#endif
6686163953Srrs	SOCK_LOCK(so);
6687163953Srrs	error = solisten_proto_check(so);
6688163953Srrs	if (error) {
6689163953Srrs		SOCK_UNLOCK(so);
6690169208Srrs		SCTP_INP_RUNLOCK(inp);
6691163953Srrs		return (error);
6692163953Srrs	}
6693181054Srrs	if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
6694181054Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
6695181054Srrs		/*
6696181054Srrs		 * The unlucky case - We are in the tcp pool with this guy.
6697181054Srrs		 * - Someone else is in the main inp slot. - We must move
6698181054Srrs		 * this guy (the listener) to the main slot - We must then
6699181054Srrs		 * move the guy that was listener to the TCP Pool.
6700181054Srrs		 */
6701181054Srrs		if (sctp_swap_inpcb_for_listen(inp)) {
6702181054Srrs			goto in_use;
6703181054Srrs		}
6704181054Srrs	}
6705163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
6706163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
6707163953Srrs		/* We are already connected AND the TCP model */
6708181054Srrsin_use:
6709163953Srrs		SCTP_INP_RUNLOCK(inp);
6710163953Srrs		SOCK_UNLOCK(so);
6711171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
6712163953Srrs		return (EADDRINUSE);
6713163953Srrs	}
6714181054Srrs	SCTP_INP_RUNLOCK(inp);
6715163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
6716163953Srrs		/* We must do a bind. */
6717166675Srrs		SOCK_UNLOCK(so);
6718171572Srrs		if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
6719163953Srrs			/* bind error, probably perm */
6720163953Srrs			return (error);
6721163953Srrs		}
6722166675Srrs		SOCK_LOCK(so);
6723163953Srrs	}
6724163953Srrs	/* It appears for 7.0 and on, we must always call this. */
6725163953Srrs	solisten_proto(so, backlog);
6726163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
6727163953Srrs		/* remove the ACCEPTCONN flag for one-to-many sockets */
6728163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
6729163953Srrs	}
6730163953Srrs	if (backlog == 0) {
6731163953Srrs		/* turning off listen */
6732163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
6733163953Srrs	}
6734163953Srrs	SOCK_UNLOCK(so);
6735163953Srrs	return (error);
6736163953Srrs}
6737163953Srrs
6738163953Srrsstatic int sctp_defered_wakeup_cnt = 0;
6739163953Srrs
6740163953Srrsint
6741163953Srrssctp_accept(struct socket *so, struct sockaddr **addr)
6742163953Srrs{
6743163953Srrs	struct sctp_tcb *stcb;
6744163953Srrs	struct sctp_inpcb *inp;
6745163953Srrs	union sctp_sockstore store;
6746163953Srrs
6747178251Srrs#ifdef INET6
6748163953Srrs	int error;
6749163953Srrs
6750178251Srrs#endif
6751163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6752163953Srrs
6753233005Stuexen	if (inp == NULL) {
6754171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6755163953Srrs		return (ECONNRESET);
6756163953Srrs	}
6757163953Srrs	SCTP_INP_RLOCK(inp);
6758163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
6759168299Srrs		SCTP_INP_RUNLOCK(inp);
6760171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
6761171943Srrs		return (EOPNOTSUPP);
6762163953Srrs	}
6763163953Srrs	if (so->so_state & SS_ISDISCONNECTED) {
6764163953Srrs		SCTP_INP_RUNLOCK(inp);
6765171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
6766163953Srrs		return (ECONNABORTED);
6767163953Srrs	}
6768163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
6769163953Srrs	if (stcb == NULL) {
6770163953Srrs		SCTP_INP_RUNLOCK(inp);
6771171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6772163953Srrs		return (ECONNRESET);
6773163953Srrs	}
6774163953Srrs	SCTP_TCB_LOCK(stcb);
6775163953Srrs	SCTP_INP_RUNLOCK(inp);
6776163953Srrs	store = stcb->asoc.primary_destination->ro._l_addr;
6777207924Srrs	stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
6778163953Srrs	SCTP_TCB_UNLOCK(stcb);
6779178251Srrs	switch (store.sa.sa_family) {
6780221249Stuexen#ifdef INET
6781178251Srrs	case AF_INET:
6782178251Srrs		{
6783178251Srrs			struct sockaddr_in *sin;
6784163953Srrs
6785178251Srrs			SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
6786208863Srrs			if (sin == NULL)
6787208863Srrs				return (ENOMEM);
6788178251Srrs			sin->sin_family = AF_INET;
6789178251Srrs			sin->sin_len = sizeof(*sin);
6790246595Stuexen			sin->sin_port = store.sin.sin_port;
6791246595Stuexen			sin->sin_addr = store.sin.sin_addr;
6792178251Srrs			*addr = (struct sockaddr *)sin;
6793178251Srrs			break;
6794178251Srrs		}
6795221249Stuexen#endif
6796178251Srrs#ifdef INET6
6797178251Srrs	case AF_INET6:
6798178251Srrs		{
6799178251Srrs			struct sockaddr_in6 *sin6;
6800163953Srrs
6801178251Srrs			SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
6802208863Srrs			if (sin6 == NULL)
6803208863Srrs				return (ENOMEM);
6804178251Srrs			sin6->sin6_family = AF_INET6;
6805178251Srrs			sin6->sin6_len = sizeof(*sin6);
6806246595Stuexen			sin6->sin6_port = store.sin6.sin6_port;
6807246595Stuexen			sin6->sin6_addr = store.sin6.sin6_addr;
6808178251Srrs			if ((error = sa6_recoverscope(sin6)) != 0) {
6809178251Srrs				SCTP_FREE_SONAME(sin6);
6810178251Srrs				return (error);
6811178251Srrs			}
6812178251Srrs			*addr = (struct sockaddr *)sin6;
6813178251Srrs			break;
6814164085Srrs		}
6815178251Srrs#endif
6816178251Srrs	default:
6817178251Srrs		/* TSNH */
6818178251Srrs		break;
6819163953Srrs	}
6820163953Srrs	/* Wake any delayed sleep action */
6821163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
6822166086Srrs		SCTP_INP_WLOCK(inp);
6823163953Srrs		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
6824163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
6825163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
6826166086Srrs			SCTP_INP_WUNLOCK(inp);
6827163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
6828163953Srrs			if (sowriteable(inp->sctp_socket)) {
6829163953Srrs				sowwakeup_locked(inp->sctp_socket);
6830163953Srrs			} else {
6831163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
6832163953Srrs			}
6833166086Srrs			SCTP_INP_WLOCK(inp);
6834163953Srrs		}
6835163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
6836163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
6837166086Srrs			SCTP_INP_WUNLOCK(inp);
6838163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
6839163953Srrs			if (soreadable(inp->sctp_socket)) {
6840163953Srrs				sctp_defered_wakeup_cnt++;
6841163953Srrs				sorwakeup_locked(inp->sctp_socket);
6842163953Srrs			} else {
6843163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
6844163953Srrs			}
6845166086Srrs			SCTP_INP_WLOCK(inp);
6846163953Srrs		}
6847166086Srrs		SCTP_INP_WUNLOCK(inp);
6848163953Srrs	}
6849207924Srrs	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
6850207924Srrs		SCTP_TCB_LOCK(stcb);
6851207924Srrs		sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
6852207924Srrs	}
6853163953Srrs	return (0);
6854163953Srrs}
6855163953Srrs
6856221249Stuexen#ifdef INET
6857163953Srrsint
6858163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr)
6859163953Srrs{
6860163953Srrs	struct sockaddr_in *sin;
6861167598Srrs	uint32_t vrf_id;
6862163953Srrs	struct sctp_inpcb *inp;
6863167695Srrs	struct sctp_ifa *sctp_ifa;
6864163953Srrs
6865163953Srrs	/*
6866163953Srrs	 * Do the malloc first in case it blocks.
6867163953Srrs	 */
6868163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
6869208863Srrs	if (sin == NULL)
6870208863Srrs		return (ENOMEM);
6871163953Srrs	sin->sin_family = AF_INET;
6872163953Srrs	sin->sin_len = sizeof(*sin);
6873163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6874163953Srrs	if (!inp) {
6875163953Srrs		SCTP_FREE_SONAME(sin);
6876171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6877228907Stuexen		return (ECONNRESET);
6878163953Srrs	}
6879163953Srrs	SCTP_INP_RLOCK(inp);
6880163953Srrs	sin->sin_port = inp->sctp_lport;
6881163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6882163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
6883163953Srrs			struct sctp_tcb *stcb;
6884163953Srrs			struct sockaddr_in *sin_a;
6885163953Srrs			struct sctp_nets *net;
6886163953Srrs			int fnd;
6887163953Srrs
6888163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
6889163953Srrs			if (stcb == NULL) {
6890163953Srrs				goto notConn;
6891163953Srrs			}
6892163953Srrs			fnd = 0;
6893163953Srrs			sin_a = NULL;
6894163953Srrs			SCTP_TCB_LOCK(stcb);
6895163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6896163953Srrs				sin_a = (struct sockaddr_in *)&net->ro._l_addr;
6897164085Srrs				if (sin_a == NULL)
6898164085Srrs					/* this will make coverity happy */
6899164085Srrs					continue;
6900164085Srrs
6901163953Srrs				if (sin_a->sin_family == AF_INET) {
6902163953Srrs					fnd = 1;
6903163953Srrs					break;
6904163953Srrs				}
6905163953Srrs			}
6906163953Srrs			if ((!fnd) || (sin_a == NULL)) {
6907163953Srrs				/* punt */
6908163953Srrs				SCTP_TCB_UNLOCK(stcb);
6909163953Srrs				goto notConn;
6910163953Srrs			}
6911168299Srrs			vrf_id = inp->def_vrf_id;
6912167598Srrs			sctp_ifa = sctp_source_address_selection(inp,
6913167598Srrs			    stcb,
6914168299Srrs			    (sctp_route_t *) & net->ro,
6915167598Srrs			    net, 0, vrf_id);
6916167598Srrs			if (sctp_ifa) {
6917167598Srrs				sin->sin_addr = sctp_ifa->address.sin.sin_addr;
6918167598Srrs				sctp_free_ifa(sctp_ifa);
6919167598Srrs			}
6920163953Srrs			SCTP_TCB_UNLOCK(stcb);
6921163953Srrs		} else {
6922163953Srrs			/* For the bound all case you get back 0 */
6923163953Srrs	notConn:
6924163953Srrs			sin->sin_addr.s_addr = 0;
6925163953Srrs		}
6926163953Srrs
6927163953Srrs	} else {
6928163953Srrs		/* Take the first IPv4 address in the list */
6929163953Srrs		struct sctp_laddr *laddr;
6930163953Srrs		int fnd = 0;
6931163953Srrs
6932163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
6933167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET) {
6934163953Srrs				struct sockaddr_in *sin_a;
6935163953Srrs
6936271746Stuexen				sin_a = &laddr->ifa->address.sin;
6937163953Srrs				sin->sin_addr = sin_a->sin_addr;
6938163953Srrs				fnd = 1;
6939163953Srrs				break;
6940163953Srrs			}
6941163953Srrs		}
6942163953Srrs		if (!fnd) {
6943163953Srrs			SCTP_FREE_SONAME(sin);
6944163953Srrs			SCTP_INP_RUNLOCK(inp);
6945171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
6946228907Stuexen			return (ENOENT);
6947163953Srrs		}
6948163953Srrs	}
6949163953Srrs	SCTP_INP_RUNLOCK(inp);
6950163953Srrs	(*addr) = (struct sockaddr *)sin;
6951163953Srrs	return (0);
6952163953Srrs}
6953163953Srrs
6954163953Srrsint
6955163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr)
6956163953Srrs{
6957231895Stuexen	struct sockaddr_in *sin;
6958166086Srrs	int fnd;
6959163953Srrs	struct sockaddr_in *sin_a;
6960163953Srrs	struct sctp_inpcb *inp;
6961163953Srrs	struct sctp_tcb *stcb;
6962163953Srrs	struct sctp_nets *net;
6963163953Srrs
6964163953Srrs	/* Do the malloc first in case it blocks. */
6965163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
6966208863Srrs	if (sin == NULL)
6967208863Srrs		return (ENOMEM);
6968163953Srrs	sin->sin_family = AF_INET;
6969163953Srrs	sin->sin_len = sizeof(*sin);
6970163953Srrs
6971163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6972228907Stuexen	if ((inp == NULL) ||
6973228907Stuexen	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
6974228907Stuexen		/* UDP type and listeners will drop out here */
6975163953Srrs		SCTP_FREE_SONAME(sin);
6976228907Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
6977228907Stuexen		return (ENOTCONN);
6978163953Srrs	}
6979163953Srrs	SCTP_INP_RLOCK(inp);
6980163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
6981169420Srrs	if (stcb) {
6982163953Srrs		SCTP_TCB_LOCK(stcb);
6983169420Srrs	}
6984163953Srrs	SCTP_INP_RUNLOCK(inp);
6985163953Srrs	if (stcb == NULL) {
6986163953Srrs		SCTP_FREE_SONAME(sin);
6987171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6988228907Stuexen		return (ECONNRESET);
6989163953Srrs	}
6990163953Srrs	fnd = 0;
6991163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6992163953Srrs		sin_a = (struct sockaddr_in *)&net->ro._l_addr;
6993163953Srrs		if (sin_a->sin_family == AF_INET) {
6994163953Srrs			fnd = 1;
6995163953Srrs			sin->sin_port = stcb->rport;
6996163953Srrs			sin->sin_addr = sin_a->sin_addr;
6997163953Srrs			break;
6998163953Srrs		}
6999163953Srrs	}
7000163953Srrs	SCTP_TCB_UNLOCK(stcb);
7001163953Srrs	if (!fnd) {
7002163953Srrs		/* No IPv4 address */
7003163953Srrs		SCTP_FREE_SONAME(sin);
7004171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
7005228907Stuexen		return (ENOENT);
7006163953Srrs	}
7007163953Srrs	(*addr) = (struct sockaddr *)sin;
7008163953Srrs	return (0);
7009163953Srrs}
7010163953Srrs
7011163953Srrsstruct pr_usrreqs sctp_usrreqs = {
7012163953Srrs	.pru_abort = sctp_abort,
7013163953Srrs	.pru_accept = sctp_accept,
7014163953Srrs	.pru_attach = sctp_attach,
7015163953Srrs	.pru_bind = sctp_bind,
7016163953Srrs	.pru_connect = sctp_connect,
7017163953Srrs	.pru_control = in_control,
7018163953Srrs	.pru_close = sctp_close,
7019163953Srrs	.pru_detach = sctp_close,
7020163953Srrs	.pru_sopoll = sopoll_generic,
7021178202Srrs	.pru_flush = sctp_flush,
7022163953Srrs	.pru_disconnect = sctp_disconnect,
7023163953Srrs	.pru_listen = sctp_listen,
7024163953Srrs	.pru_peeraddr = sctp_peeraddr,
7025163953Srrs	.pru_send = sctp_sendm,
7026163953Srrs	.pru_shutdown = sctp_shutdown,
7027163953Srrs	.pru_sockaddr = sctp_ingetaddr,
7028163953Srrs	.pru_sosend = sctp_sosend,
7029163953Srrs	.pru_soreceive = sctp_soreceive
7030163953Srrs};
7031221249Stuexen
7032221249Stuexen#endif
7033