sctp_usrreq.c revision 246595
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: head/sys/netinet/sctp_usrreq.c 246595 2013-02-09 17:26:14Z tuexen $");
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
217221249Stuexen#endif
218163953Srrs
219163953Srrsvoid
220163953Srrssctp_notify(struct sctp_inpcb *inp,
221172091Srrs    struct ip *ip,
222163953Srrs    struct sctphdr *sh,
223163953Srrs    struct sockaddr *to,
224163953Srrs    struct sctp_tcb *stcb,
225163953Srrs    struct sctp_nets *net)
226163953Srrs{
227237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
228172090Srrs	struct socket *so;
229172090Srrs
230172090Srrs#endif
231172091Srrs	struct icmp *icmph;
232172091Srrs
233235360Stuexen	/* protection */
234163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
235163953Srrs	    (sh == NULL) || (to == NULL)) {
236172091Srrs		if (stcb)
237172091Srrs			SCTP_TCB_UNLOCK(stcb);
238163953Srrs		return;
239163953Srrs	}
240163953Srrs	/* First job is to verify the vtag matches what I would send */
241163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
242172091Srrs		SCTP_TCB_UNLOCK(stcb);
243163953Srrs		return;
244163953Srrs	}
245172091Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
246172091Srrs	    sizeof(struct ip)));
247172091Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
248172091Srrs		/* We only care about unreachable */
249172091Srrs		SCTP_TCB_UNLOCK(stcb);
250172091Srrs		return;
251172091Srrs	}
252172091Srrs	if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
253172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST) ||
254172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
255172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
256172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
257172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
258172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
259172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
260163953Srrs
261163953Srrs		/*
262163953Srrs		 * Hmm reachablity problems we must examine closely. If its
263163953Srrs		 * not reachable, we may have lost a network. Or if there is
264163953Srrs		 * NO protocol at the other end named SCTP. well we consider
265163953Srrs		 * it a OOTB abort.
266163953Srrs		 */
267172091Srrs		if (net->dest_state & SCTP_ADDR_REACHABLE) {
268172091Srrs			/* Ok that destination is NOT reachable */
269172091Srrs			net->dest_state &= ~SCTP_ADDR_REACHABLE;
270224641Stuexen			net->dest_state &= ~SCTP_ADDR_PF;
271172091Srrs			sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
272235414Stuexen			    stcb, 0,
273172091Srrs			    (void *)net, SCTP_SO_NOT_LOCKED);
274172091Srrs		}
275172091Srrs		SCTP_TCB_UNLOCK(stcb);
276172091Srrs	} else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
277172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_PORT)) {
278172091Srrs		/*
279172091Srrs		 * Here the peer is either playing tricks on us, including
280172091Srrs		 * an address that belongs to someone who does not support
281172091Srrs		 * SCTP OR was a userland implementation that shutdown and
282172091Srrs		 * now is dead. In either case treat it like a OOTB abort
283172091Srrs		 * with no TCB
284172091Srrs		 */
285235403Stuexen		sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
286237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
287172091Srrs		so = SCTP_INP_SO(inp);
288172091Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
289172091Srrs		SCTP_TCB_UNLOCK(stcb);
290172091Srrs		SCTP_SOCKET_LOCK(so, 1);
291172091Srrs		SCTP_TCB_LOCK(stcb);
292172091Srrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
293172090Srrs#endif
294172091Srrs		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
295237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
296172091Srrs		SCTP_SOCKET_UNLOCK(so, 1);
297172091Srrs		/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
298172090Srrs#endif
299172091Srrs		/* no need to unlock here, since the TCB is gone */
300163953Srrs	} else {
301172091Srrs		SCTP_TCB_UNLOCK(stcb);
302163953Srrs	}
303163953Srrs}
304163953Srrs
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:
857163953Srrs					op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
858243882Sglebius					    0, M_NOWAIT, 1, MT_DATA);
859163953Srrs					if (op_err) {
860163953Srrs						/*
861163953Srrs						 * Fill in the user
862163953Srrs						 * initiated abort
863163953Srrs						 */
864163953Srrs						struct sctp_paramhdr *ph;
865163953Srrs						uint32_t *ippp;
866163953Srrs
867165647Srrs						SCTP_BUF_LEN(op_err) =
868163953Srrs						    (sizeof(struct sctp_paramhdr) + sizeof(uint32_t));
869163953Srrs						ph = mtod(op_err,
870163953Srrs						    struct sctp_paramhdr *);
871163953Srrs						ph->param_type = htons(
872163953Srrs						    SCTP_CAUSE_USER_INITIATED_ABT);
873165647Srrs						ph->param_length = htons(SCTP_BUF_LEN(op_err));
874163953Srrs						ippp = (uint32_t *) (ph + 1);
875165220Srrs						*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4);
876163953Srrs					}
877165220Srrs					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
878172090Srrs					sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
879163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
880163953Srrs					if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
881163953Srrs					    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
882163953Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
883163953Srrs					}
884163953Srrs					SCTP_INP_RUNLOCK(inp);
885171943Srrs					(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
886163953Srrs					return (0);
887171990Srrs				} else {
888172090Srrs					sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
889163953Srrs				}
890163953Srrs			}
891188067Srrs			soisdisconnecting(so);
892163953Srrs			SCTP_TCB_UNLOCK(stcb);
893163953Srrs			SCTP_INP_RUNLOCK(inp);
894163953Srrs			return (0);
895163953Srrs		}
896163953Srrs		/* not reached */
897163953Srrs	} else {
898163953Srrs		/* UDP model does not support this */
899163953Srrs		SCTP_INP_RUNLOCK(inp);
900171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
901228907Stuexen		return (EOPNOTSUPP);
902163953Srrs	}
903163953Srrs}
904163953Srrs
905163953Srrsint
906178202Srrssctp_flush(struct socket *so, int how)
907178202Srrs{
908178202Srrs	/*
909178202Srrs	 * We will just clear out the values and let subsequent close clear
910178202Srrs	 * out the data, if any. Note if the user did a shutdown(SHUT_RD)
911178202Srrs	 * they will not be able to read the data, the socket will block
912178202Srrs	 * that from happening.
913178202Srrs	 */
914209289Stuexen	struct sctp_inpcb *inp;
915209289Stuexen
916209289Stuexen	inp = (struct sctp_inpcb *)so->so_pcb;
917209289Stuexen	if (inp == NULL) {
918209289Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
919228907Stuexen		return (EINVAL);
920209289Stuexen	}
921209289Stuexen	SCTP_INP_RLOCK(inp);
922209289Stuexen	/* For the 1 to many model this does nothing */
923209289Stuexen	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
924209289Stuexen		SCTP_INP_RUNLOCK(inp);
925209289Stuexen		return (0);
926209289Stuexen	}
927209289Stuexen	SCTP_INP_RUNLOCK(inp);
928178202Srrs	if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
929178202Srrs		/*
930178202Srrs		 * First make sure the sb will be happy, we don't use these
931178202Srrs		 * except maybe the count
932178202Srrs		 */
933209289Stuexen		SCTP_INP_WLOCK(inp);
934209289Stuexen		SCTP_INP_READ_LOCK(inp);
935209289Stuexen		inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
936209289Stuexen		SCTP_INP_READ_UNLOCK(inp);
937209289Stuexen		SCTP_INP_WUNLOCK(inp);
938178202Srrs		so->so_rcv.sb_cc = 0;
939178202Srrs		so->so_rcv.sb_mbcnt = 0;
940178202Srrs		so->so_rcv.sb_mb = NULL;
941178202Srrs	}
942178202Srrs	if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
943178202Srrs		/*
944178202Srrs		 * First make sure the sb will be happy, we don't use these
945178202Srrs		 * except maybe the count
946178202Srrs		 */
947178202Srrs		so->so_snd.sb_cc = 0;
948178202Srrs		so->so_snd.sb_mbcnt = 0;
949178202Srrs		so->so_snd.sb_mb = NULL;
950178202Srrs
951178202Srrs	}
952178202Srrs	return (0);
953178202Srrs}
954178202Srrs
955178202Srrsint
956163953Srrssctp_shutdown(struct socket *so)
957163953Srrs{
958163953Srrs	struct sctp_inpcb *inp;
959163953Srrs
960163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
961233005Stuexen	if (inp == NULL) {
962171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
963228907Stuexen		return (EINVAL);
964163953Srrs	}
965163953Srrs	SCTP_INP_RLOCK(inp);
966163953Srrs	/* For UDP model this is a invalid call */
967243558Stuexen	if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
968243558Stuexen	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
969163953Srrs		/* Restore the flags that the soshutdown took away. */
970204096Stuexen		SOCKBUF_LOCK(&so->so_rcv);
971163953Srrs		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
972204096Stuexen		SOCKBUF_UNLOCK(&so->so_rcv);
973163953Srrs		/* This proc will wakeup for read and do nothing (I hope) */
974163953Srrs		SCTP_INP_RUNLOCK(inp);
975171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
976163953Srrs		return (EOPNOTSUPP);
977163953Srrs	}
978163953Srrs	/*
979163953Srrs	 * Ok if we reach here its the TCP model and it is either a SHUT_WR
980163953Srrs	 * or SHUT_RDWR. This means we put the shutdown flag against it.
981163953Srrs	 */
982163953Srrs	{
983163953Srrs		struct sctp_tcb *stcb;
984163953Srrs		struct sctp_association *asoc;
985163953Srrs
986188067Srrs		if ((so->so_state &
987188067Srrs		    (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
988188067Srrs			SCTP_INP_RUNLOCK(inp);
989188067Srrs			return (ENOTCONN);
990188067Srrs		}
991163953Srrs		socantsendmore(so);
992163953Srrs
993163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
994163953Srrs		if (stcb == NULL) {
995163953Srrs			/*
996163953Srrs			 * Ok we hit the case that the shutdown call was
997163953Srrs			 * made after an abort or something. Nothing to do
998163953Srrs			 * now.
999163953Srrs			 */
1000168299Srrs			SCTP_INP_RUNLOCK(inp);
1001163953Srrs			return (0);
1002163953Srrs		}
1003163953Srrs		SCTP_TCB_LOCK(stcb);
1004163953Srrs		asoc = &stcb->asoc;
1005163953Srrs		if (TAILQ_EMPTY(&asoc->send_queue) &&
1006163953Srrs		    TAILQ_EMPTY(&asoc->sent_queue) &&
1007163953Srrs		    (asoc->stream_queue_cnt == 0)) {
1008163953Srrs			if (asoc->locked_on_sending) {
1009163953Srrs				goto abort_anyway;
1010163953Srrs			}
1011163953Srrs			/* there is nothing queued to send, so I'm done... */
1012163953Srrs			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
1013163953Srrs				/* only send SHUTDOWN the first time through */
1014224641Stuexen				struct sctp_nets *netp;
1015224641Stuexen
1016246588Stuexen				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
1017246588Stuexen				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1018246588Stuexen					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1019246588Stuexen				}
1020246588Stuexen				SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
1021246588Stuexen				SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
1022246588Stuexen				sctp_stop_timers_for_shutdown(stcb);
1023224641Stuexen				if (stcb->asoc.alternate) {
1024224641Stuexen					netp = stcb->asoc.alternate;
1025224641Stuexen				} else {
1026224641Stuexen					netp = stcb->asoc.primary_destination;
1027224641Stuexen				}
1028224641Stuexen				sctp_send_shutdown(stcb, netp);
1029163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1030224641Stuexen				    stcb->sctp_ep, stcb, netp);
1031163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1032224641Stuexen				    stcb->sctp_ep, stcb, netp);
1033246588Stuexen				sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
1034163953Srrs			}
1035163953Srrs		} else {
1036163953Srrs			/*
1037163953Srrs			 * we still got (or just got) data to send, so set
1038163953Srrs			 * SHUTDOWN_PENDING
1039163953Srrs			 */
1040224641Stuexen			struct sctp_nets *netp;
1041224641Stuexen
1042224641Stuexen			if (stcb->asoc.alternate) {
1043224641Stuexen				netp = stcb->asoc.alternate;
1044224641Stuexen			} else {
1045224641Stuexen				netp = stcb->asoc.primary_destination;
1046224641Stuexen			}
1047224641Stuexen
1048163953Srrs			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1049163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
1050224641Stuexen			    netp);
1051163953Srrs
1052163953Srrs			if (asoc->locked_on_sending) {
1053163953Srrs				/* Locked to send out the data */
1054163953Srrs				struct sctp_stream_queue_pending *sp;
1055163953Srrs
1056163953Srrs				sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1057163953Srrs				if (sp == NULL) {
1058169420Srrs					SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1059163953Srrs					    asoc->locked_on_sending->stream_no);
1060163953Srrs				} else {
1061163953Srrs					if ((sp->length == 0) && (sp->msg_is_complete == 0)) {
1062163953Srrs						asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
1063163953Srrs					}
1064163953Srrs				}
1065163953Srrs			}
1066163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
1067163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
1068163953Srrs			    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1069163953Srrs				struct mbuf *op_err;
1070163953Srrs
1071163953Srrs		abort_anyway:
1072163953Srrs				op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
1073243882Sglebius				    0, M_NOWAIT, 1, MT_DATA);
1074163953Srrs				if (op_err) {
1075163953Srrs					/* Fill in the user initiated abort */
1076163953Srrs					struct sctp_paramhdr *ph;
1077163953Srrs					uint32_t *ippp;
1078163953Srrs
1079165647Srrs					SCTP_BUF_LEN(op_err) =
1080163953Srrs					    sizeof(struct sctp_paramhdr) + sizeof(uint32_t);
1081163953Srrs					ph = mtod(op_err,
1082163953Srrs					    struct sctp_paramhdr *);
1083163953Srrs					ph->param_type = htons(
1084163953Srrs					    SCTP_CAUSE_USER_INITIATED_ABT);
1085165647Srrs					ph->param_length = htons(SCTP_BUF_LEN(op_err));
1086163953Srrs					ippp = (uint32_t *) (ph + 1);
1087165220Srrs					*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
1088163953Srrs				}
1089165220Srrs				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
1090163953Srrs				sctp_abort_an_association(stcb->sctp_ep, stcb,
1091172090Srrs				    op_err, SCTP_SO_LOCKED);
1092163953Srrs				goto skip_unlock;
1093171990Srrs			} else {
1094172090Srrs				sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
1095163953Srrs			}
1096163953Srrs		}
1097163953Srrs		SCTP_TCB_UNLOCK(stcb);
1098163953Srrs	}
1099163953Srrsskip_unlock:
1100163953Srrs	SCTP_INP_RUNLOCK(inp);
1101228907Stuexen	return (0);
1102163953Srrs}
1103163953Srrs
1104163953Srrs/*
1105163953Srrs * copies a "user" presentable address and removes embedded scope, etc.
1106163953Srrs * returns 0 on success, 1 on error
1107163953Srrs */
1108163953Srrsstatic uint32_t
1109163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
1110163953Srrs{
1111178251Srrs#ifdef INET6
1112163953Srrs	struct sockaddr_in6 lsa6;
1113163953Srrs
1114163953Srrs	sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
1115163953Srrs	    &lsa6);
1116178251Srrs#endif
1117163953Srrs	memcpy(ss, sa, sa->sa_len);
1118163953Srrs	return (0);
1119163953Srrs}
1120163953Srrs
1121163953Srrs
1122163953Srrs
1123172091Srrs/*
1124172091Srrs * NOTE: assumes addr lock is held
1125172091Srrs */
1126166675Srrsstatic size_t
1127168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
1128163953Srrs    struct sctp_tcb *stcb,
1129166675Srrs    size_t limit,
1130167598Srrs    struct sockaddr_storage *sas,
1131167598Srrs    uint32_t vrf_id)
1132163953Srrs{
1133167598Srrs	struct sctp_ifn *sctp_ifn;
1134167598Srrs	struct sctp_ifa *sctp_ifa;
1135166675Srrs	int loopback_scope, ipv4_local_scope, local_scope, site_scope;
1136166675Srrs	size_t actual;
1137163953Srrs	int ipv4_addr_legal, ipv6_addr_legal;
1138167598Srrs	struct sctp_vrf *vrf;
1139163953Srrs
1140163953Srrs	actual = 0;
1141163953Srrs	if (limit <= 0)
1142163953Srrs		return (actual);
1143163953Srrs
1144163953Srrs	if (stcb) {
1145163953Srrs		/* Turn on all the appropriate scope */
1146246595Stuexen		loopback_scope = stcb->asoc.scope.loopback_scope;
1147246595Stuexen		ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
1148246595Stuexen		local_scope = stcb->asoc.scope.local_scope;
1149246595Stuexen		site_scope = stcb->asoc.scope.site_scope;
1150246595Stuexen		ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
1151246595Stuexen		ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
1152163953Srrs	} else {
1153246595Stuexen		/* Use generic values for endpoints. */
1154246595Stuexen		loopback_scope = 1;
1155246595Stuexen		ipv4_local_scope = 1;
1156246595Stuexen		local_scope = 1;
1157246595Stuexen		site_scope = 1;
1158246595Stuexen		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1159246595Stuexen			ipv6_addr_legal = 1;
1160246595Stuexen			if (SCTP_IPV6_V6ONLY(inp)) {
1161246595Stuexen				ipv4_addr_legal = 0;
1162246595Stuexen			} else {
1163246595Stuexen				ipv4_addr_legal = 1;
1164246595Stuexen			}
1165246595Stuexen		} else {
1166246595Stuexen			ipv6_addr_legal = 0;
1167163953Srrs			ipv4_addr_legal = 1;
1168163953Srrs		}
1169163953Srrs	}
1170167598Srrs	vrf = sctp_find_vrf(vrf_id);
1171167598Srrs	if (vrf == NULL) {
1172167598Srrs		return (0);
1173167598Srrs	}
1174163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1175167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1176163953Srrs			if ((loopback_scope == 0) &&
1177167598Srrs			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
1178163953Srrs				/* Skip loopback if loopback_scope not set */
1179163953Srrs				continue;
1180163953Srrs			}
1181167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1182163953Srrs				if (stcb) {
1183163953Srrs					/*
1184163953Srrs					 * For the BOUND-ALL case, the list
1185163953Srrs					 * associated with a TCB is Always
1186163953Srrs					 * considered a reverse list.. i.e.
1187163953Srrs					 * it lists addresses that are NOT
1188163953Srrs					 * part of the association. If this
1189163953Srrs					 * is one of those we must skip it.
1190163953Srrs					 */
1191163953Srrs					if (sctp_is_addr_restricted(stcb,
1192167598Srrs					    sctp_ifa)) {
1193163953Srrs						continue;
1194163953Srrs					}
1195163953Srrs				}
1196178251Srrs				switch (sctp_ifa->address.sa.sa_family) {
1197221249Stuexen#ifdef INET
1198178251Srrs				case AF_INET:
1199178251Srrs					if (ipv4_addr_legal) {
1200178251Srrs						struct sockaddr_in *sin;
1201163953Srrs
1202178251Srrs						sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
1203178251Srrs						if (sin->sin_addr.s_addr == 0) {
1204178251Srrs							/*
1205178251Srrs							 * we skip
1206178251Srrs							 * unspecifed
1207178251Srrs							 * addresses
1208178251Srrs							 */
1209178251Srrs							continue;
1210178251Srrs						}
1211178251Srrs						if ((ipv4_local_scope == 0) &&
1212178251Srrs						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
1213178251Srrs							continue;
1214178251Srrs						}
1215178251Srrs#ifdef INET6
1216178251Srrs						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
1217178251Srrs							in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
1218178251Srrs							((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1219178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
1220178251Srrs							actual += sizeof(struct sockaddr_in6);
1221178251Srrs						} else {
1222178251Srrs#endif
1223178251Srrs							memcpy(sas, sin, sizeof(*sin));
1224178251Srrs							((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1225178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
1226178251Srrs							actual += sizeof(*sin);
1227178251Srrs#ifdef INET6
1228178251Srrs						}
1229178251Srrs#endif
1230178251Srrs						if (actual >= limit) {
1231178251Srrs							return (actual);
1232178251Srrs						}
1233178251Srrs					} else {
1234163953Srrs						continue;
1235163953Srrs					}
1236178251Srrs					break;
1237221249Stuexen#endif
1238178251Srrs#ifdef INET6
1239178251Srrs				case AF_INET6:
1240178251Srrs					if (ipv6_addr_legal) {
1241178251Srrs						struct sockaddr_in6 *sin6;
1242163953Srrs
1243178251Srrs						sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
1244178251Srrs						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1245178251Srrs							/*
1246178251Srrs							 * we skip
1247178251Srrs							 * unspecifed
1248178251Srrs							 * addresses
1249178251Srrs							 */
1250163953Srrs							continue;
1251178251Srrs						}
1252178251Srrs						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1253178251Srrs							if (local_scope == 0)
1254163953Srrs								continue;
1255178251Srrs							if (sin6->sin6_scope_id == 0) {
1256178251Srrs								if (sa6_recoverscope(sin6) != 0)
1257178251Srrs									/*
1258178251Srrs									 *
1259178251Srrs									 * bad
1260178251Srrs									 *
1261178251Srrs									 * li
1262178251Srrs									 * nk
1263178251Srrs									 *
1264178251Srrs									 * loc
1265178251Srrs									 * al
1266178251Srrs									 *
1267178251Srrs									 * add
1268178251Srrs									 * re
1269178251Srrs									 * ss
1270178251Srrs									 * */
1271178251Srrs									continue;
1272178251Srrs							}
1273163953Srrs						}
1274178251Srrs						if ((site_scope == 0) &&
1275178251Srrs						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
1276178251Srrs							continue;
1277178251Srrs						}
1278178251Srrs						memcpy(sas, sin6, sizeof(*sin6));
1279178251Srrs						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1280178251Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
1281178251Srrs						actual += sizeof(*sin6);
1282178251Srrs						if (actual >= limit) {
1283178251Srrs							return (actual);
1284178251Srrs						}
1285178251Srrs					} else {
1286163953Srrs						continue;
1287163953Srrs					}
1288178251Srrs					break;
1289178251Srrs#endif
1290178251Srrs				default:
1291178251Srrs					/* TSNH */
1292178251Srrs					break;
1293163953Srrs				}
1294163953Srrs			}
1295163953Srrs		}
1296163953Srrs	} else {
1297163953Srrs		struct sctp_laddr *laddr;
1298163953Srrs
1299167598Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1300167598Srrs			if (stcb) {
1301167598Srrs				if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
1302163953Srrs					continue;
1303163953Srrs				}
1304163953Srrs			}
1305167598Srrs			if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
1306167598Srrs				continue;
1307246595Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1308246595Stuexen#ifdef INET
1309246595Stuexen			case AF_INET:
1310246595Stuexen				((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1311246595Stuexen				break;
1312246595Stuexen#endif
1313246595Stuexen#ifdef INET6
1314246595Stuexen			case AF_INET6:
1315246595Stuexen				((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1316246595Stuexen				break;
1317246595Stuexen#endif
1318246595Stuexen			default:
1319246595Stuexen				/* TSNH */
1320246595Stuexen				break;
1321246595Stuexen			}
1322167598Srrs			sas = (struct sockaddr_storage *)((caddr_t)sas +
1323167598Srrs			    laddr->ifa->address.sa.sa_len);
1324167598Srrs			actual += laddr->ifa->address.sa.sa_len;
1325167598Srrs			if (actual >= limit) {
1326167598Srrs				return (actual);
1327163953Srrs			}
1328163953Srrs		}
1329163953Srrs	}
1330163953Srrs	return (actual);
1331163953Srrs}
1332163953Srrs
1333168124Srrsstatic size_t
1334168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp,
1335168124Srrs    struct sctp_tcb *stcb,
1336168124Srrs    size_t limit,
1337168124Srrs    struct sockaddr_storage *sas)
1338168124Srrs{
1339168124Srrs	size_t size = 0;
1340168124Srrs
1341172218Srrs	SCTP_IPI_ADDR_RLOCK();
1342168124Srrs	/* fill up addresses for the endpoint's default vrf */
1343168124Srrs	size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
1344168124Srrs	    inp->def_vrf_id);
1345172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1346168124Srrs	return (size);
1347168124Srrs}
1348168124Srrs
1349172091Srrs/*
1350172091Srrs * NOTE: assumes addr lock is held
1351172091Srrs */
1352163953Srrsstatic int
1353168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
1354163953Srrs{
1355163953Srrs	int cnt = 0;
1356167598Srrs	struct sctp_vrf *vrf = NULL;
1357163953Srrs
1358163953Srrs	/*
1359163953Srrs	 * In both sub-set bound an bound_all cases we return the MAXIMUM
1360163953Srrs	 * number of addresses that you COULD get. In reality the sub-set
1361163953Srrs	 * bound may have an exclusion list for a given TCB OR in the
1362163953Srrs	 * bound-all case a TCB may NOT include the loopback or other
1363163953Srrs	 * addresses as well.
1364163953Srrs	 */
1365167598Srrs	vrf = sctp_find_vrf(vrf_id);
1366167598Srrs	if (vrf == NULL) {
1367167598Srrs		return (0);
1368167598Srrs	}
1369163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1370167598Srrs		struct sctp_ifn *sctp_ifn;
1371167598Srrs		struct sctp_ifa *sctp_ifa;
1372163953Srrs
1373167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1374167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1375163953Srrs				/* Count them if they are the right type */
1376221249Stuexen				switch (sctp_ifa->address.sa.sa_family) {
1377221249Stuexen#ifdef INET
1378221249Stuexen				case AF_INET:
1379178251Srrs					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1380163953Srrs						cnt += sizeof(struct sockaddr_in6);
1381163953Srrs					else
1382163953Srrs						cnt += sizeof(struct sockaddr_in);
1383221249Stuexen					break;
1384221249Stuexen#endif
1385221249Stuexen#ifdef INET6
1386221249Stuexen				case AF_INET6:
1387163953Srrs					cnt += sizeof(struct sockaddr_in6);
1388221249Stuexen					break;
1389221249Stuexen#endif
1390221249Stuexen				default:
1391221249Stuexen					break;
1392221249Stuexen				}
1393163953Srrs			}
1394163953Srrs		}
1395163953Srrs	} else {
1396163953Srrs		struct sctp_laddr *laddr;
1397163953Srrs
1398163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1399221249Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1400221249Stuexen#ifdef INET
1401221249Stuexen			case AF_INET:
1402178251Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1403163953Srrs					cnt += sizeof(struct sockaddr_in6);
1404163953Srrs				else
1405163953Srrs					cnt += sizeof(struct sockaddr_in);
1406221249Stuexen				break;
1407221249Stuexen#endif
1408221249Stuexen#ifdef INET6
1409221249Stuexen			case AF_INET6:
1410163953Srrs				cnt += sizeof(struct sockaddr_in6);
1411221249Stuexen				break;
1412221249Stuexen#endif
1413221249Stuexen			default:
1414221249Stuexen				break;
1415221249Stuexen			}
1416163953Srrs		}
1417163953Srrs	}
1418163953Srrs	return (cnt);
1419163953Srrs}
1420163953Srrs
1421168124Srrsstatic int
1422168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp)
1423168124Srrs{
1424168124Srrs	int cnt = 0;
1425166675Srrs
1426172218Srrs	SCTP_IPI_ADDR_RLOCK();
1427168124Srrs	/* count addresses for the endpoint's default VRF */
1428168124Srrs	cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
1429172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1430168124Srrs	return (cnt);
1431168124Srrs}
1432168124Srrs
1433163953Srrsstatic int
1434166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
1435166675Srrs    size_t optsize, void *p, int delay)
1436163953Srrs{
1437163953Srrs	int error = 0;
1438163953Srrs	int creat_lock_on = 0;
1439163953Srrs	struct sctp_tcb *stcb = NULL;
1440163953Srrs	struct sockaddr *sa;
1441169352Srrs	int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
1442167598Srrs	uint32_t vrf_id;
1443170056Srrs	int bad_addresses = 0;
1444167598Srrs	sctp_assoc_t *a_id;
1445163953Srrs
1446169420Srrs	SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
1447163953Srrs
1448163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1449163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1450163953Srrs		/* We are already connected AND the TCP model */
1451171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
1452163953Srrs		return (EADDRINUSE);
1453163953Srrs	}
1454181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
1455181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
1456171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1457163953Srrs		return (EINVAL);
1458163953Srrs	}
1459163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1460163953Srrs		SCTP_INP_RLOCK(inp);
1461163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1462163953Srrs		SCTP_INP_RUNLOCK(inp);
1463163953Srrs	}
1464163953Srrs	if (stcb) {
1465171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1466163953Srrs		return (EALREADY);
1467163953Srrs	}
1468163953Srrs	SCTP_INP_INCR_REF(inp);
1469163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
1470163953Srrs	creat_lock_on = 1;
1471163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1472163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
1473171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
1474163953Srrs		error = EFAULT;
1475163953Srrs		goto out_now;
1476163953Srrs	}
1477166675Srrs	totaddrp = (int *)optval;
1478163953Srrs	totaddr = *totaddrp;
1479163953Srrs	sa = (struct sockaddr *)(totaddrp + 1);
1480170056Srrs	stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
1481170056Srrs	if ((stcb != NULL) || bad_addresses) {
1482169352Srrs		/* Already have or am bring up an association */
1483169352Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1484169352Srrs		creat_lock_on = 0;
1485170931Srrs		if (stcb)
1486170931Srrs			SCTP_TCB_UNLOCK(stcb);
1487171943Srrs		if (bad_addresses == 0) {
1488171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1489170056Srrs			error = EALREADY;
1490171943Srrs		}
1491169352Srrs		goto out_now;
1492163953Srrs	}
1493163953Srrs#ifdef INET6
1494163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
1495163953Srrs	    (num_v6 > 0)) {
1496163953Srrs		error = EINVAL;
1497163953Srrs		goto out_now;
1498163953Srrs	}
1499163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1500163953Srrs	    (num_v4 > 0)) {
1501163953Srrs		struct in6pcb *inp6;
1502163953Srrs
1503163953Srrs		inp6 = (struct in6pcb *)inp;
1504166023Srrs		if (SCTP_IPV6_V6ONLY(inp6)) {
1505163953Srrs			/*
1506163953Srrs			 * if IPV6_V6ONLY flag, ignore connections destined
1507163953Srrs			 * to a v4 addr or v4-mapped addr
1508163953Srrs			 */
1509171943Srrs			SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1510163953Srrs			error = EINVAL;
1511163953Srrs			goto out_now;
1512163953Srrs		}
1513163953Srrs	}
1514163953Srrs#endif				/* INET6 */
1515163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1516163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
1517163953Srrs		/* Bind a ephemeral port */
1518171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
1519163953Srrs		if (error) {
1520163953Srrs			goto out_now;
1521163953Srrs		}
1522163953Srrs	}
1523167695Srrs	/* FIX ME: do we want to pass in a vrf on the connect call? */
1524167695Srrs	vrf_id = inp->def_vrf_id;
1525167695Srrs
1526181054Srrs
1527163953Srrs	/* We are GOOD to go */
1528206137Stuexen	stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id,
1529171531Srrs	    (struct thread *)p
1530171531Srrs	    );
1531163953Srrs	if (stcb == NULL) {
1532163953Srrs		/* Gak! no memory */
1533163953Srrs		goto out_now;
1534163953Srrs	}
1535225559Stuexen	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1536225559Stuexen		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1537225559Stuexen		/* Set the connected flag so we can queue data */
1538225559Stuexen		soisconnecting(so);
1539225559Stuexen	}
1540171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
1541163953Srrs	/* move to second address */
1542221249Stuexen	switch (sa->sa_family) {
1543221249Stuexen#ifdef INET
1544221249Stuexen	case AF_INET:
1545163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
1546221249Stuexen		break;
1547221249Stuexen#endif
1548221249Stuexen#ifdef INET6
1549221249Stuexen	case AF_INET6:
1550163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
1551221249Stuexen		break;
1552221249Stuexen#endif
1553221249Stuexen	default:
1554221249Stuexen		break;
1555221249Stuexen	}
1556163953Srrs
1557170056Srrs	error = 0;
1558223132Stuexen	sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
1559167598Srrs	/* Fill in the return id */
1560170056Srrs	if (error) {
1561207924Srrs		(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
1562170056Srrs		goto out_now;
1563170056Srrs	}
1564167598Srrs	a_id = (sctp_assoc_t *) optval;
1565167598Srrs	*a_id = sctp_get_associd(stcb);
1566163953Srrs
1567163953Srrs	/* initialize authentication parameters for the assoc */
1568163953Srrs	sctp_initialize_auth_params(inp, stcb);
1569163953Srrs
1570163953Srrs	if (delay) {
1571163953Srrs		/* doing delayed connection */
1572163953Srrs		stcb->asoc.delayed_connection = 1;
1573163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
1574163953Srrs	} else {
1575169378Srrs		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1576172090Srrs		sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
1577163953Srrs	}
1578163953Srrs	SCTP_TCB_UNLOCK(stcb);
1579163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1580163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1581163953Srrs		/* Set the connected flag so we can queue data */
1582163953Srrs		soisconnecting(so);
1583163953Srrs	}
1584163953Srrsout_now:
1585169655Srrs	if (creat_lock_on) {
1586163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1587169655Srrs	}
1588163953Srrs	SCTP_INP_DECR_REF(inp);
1589228907Stuexen	return (error);
1590163953Srrs}
1591163953Srrs
1592169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
1593169655Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\
1594169655Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \
1595166675Srrs		SCTP_INP_RLOCK(inp); \
1596166675Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list); \
1597169655Srrs		if (stcb) { \
1598166675Srrs			SCTP_TCB_LOCK(stcb); \
1599169655Srrs                } \
1600166675Srrs		SCTP_INP_RUNLOCK(inp); \
1601223132Stuexen	} else if (assoc_id > SCTP_ALL_ASSOC) { \
1602166675Srrs		stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
1603166675Srrs		if (stcb == NULL) { \
1604171943Srrs		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
1605166675Srrs			error = ENOENT; \
1606166675Srrs			break; \
1607166675Srrs		} \
1608166675Srrs	} else { \
1609166675Srrs		stcb = NULL; \
1610169420Srrs        } \
1611169420Srrs  }
1612163953Srrs
1613169420Srrs
1614234464Stuexen#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
1615166675Srrs	if (size < sizeof(type)) { \
1616171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
1617166675Srrs		error = EINVAL; \
1618166675Srrs		break; \
1619166675Srrs	} else { \
1620166675Srrs		destp = (type *)srcp; \
1621169420Srrs	} \
1622169420Srrs      }
1623163953Srrs
1624163953Srrsstatic int
1625166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
1626166675Srrs    void *p)
1627163953Srrs{
1628171943Srrs	struct sctp_inpcb *inp = NULL;
1629166675Srrs	int error, val = 0;
1630163953Srrs	struct sctp_tcb *stcb = NULL;
1631163953Srrs
1632166675Srrs	if (optval == NULL) {
1633171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1634166675Srrs		return (EINVAL);
1635166675Srrs	}
1636163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1637233005Stuexen	if (inp == NULL) {
1638171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1639163953Srrs		return EINVAL;
1640171943Srrs	}
1641163953Srrs	error = 0;
1642163953Srrs
1643166675Srrs	switch (optname) {
1644163953Srrs	case SCTP_NODELAY:
1645163953Srrs	case SCTP_AUTOCLOSE:
1646163953Srrs	case SCTP_EXPLICIT_EOR:
1647163953Srrs	case SCTP_AUTO_ASCONF:
1648163953Srrs	case SCTP_DISABLE_FRAGMENTS:
1649163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
1650163953Srrs	case SCTP_USE_EXT_RCVINFO:
1651163953Srrs		SCTP_INP_RLOCK(inp);
1652166675Srrs		switch (optname) {
1653163953Srrs		case SCTP_DISABLE_FRAGMENTS:
1654166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
1655163953Srrs			break;
1656163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
1657166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
1658163953Srrs			break;
1659163953Srrs		case SCTP_AUTO_ASCONF:
1660171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1661171943Srrs				/* only valid for bound all sockets */
1662171943Srrs				val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
1663171943Srrs			} else {
1664171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1665171943Srrs				error = EINVAL;
1666171943Srrs				goto flags_out;
1667171943Srrs			}
1668163953Srrs			break;
1669163953Srrs		case SCTP_EXPLICIT_EOR:
1670166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
1671163953Srrs			break;
1672163953Srrs		case SCTP_NODELAY:
1673166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
1674163953Srrs			break;
1675163953Srrs		case SCTP_USE_EXT_RCVINFO:
1676166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
1677163953Srrs			break;
1678163953Srrs		case SCTP_AUTOCLOSE:
1679163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
1680166675Srrs				val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
1681163953Srrs			else
1682166675Srrs				val = 0;
1683163953Srrs			break;
1684163953Srrs
1685163953Srrs		default:
1686171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
1687163953Srrs			error = ENOPROTOOPT;
1688163953Srrs		}		/* end switch (sopt->sopt_name) */
1689166675Srrs		if (*optsize < sizeof(val)) {
1690171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1691163953Srrs			error = EINVAL;
1692163953Srrs		}
1693171943Srrsflags_out:
1694163953Srrs		SCTP_INP_RUNLOCK(inp);
1695163953Srrs		if (error == 0) {
1696163953Srrs			/* return the option value */
1697166675Srrs			*(int *)optval = val;
1698166675Srrs			*optsize = sizeof(val);
1699163953Srrs		}
1700163953Srrs		break;
1701170091Srrs	case SCTP_GET_PACKET_LOG:
1702170091Srrs		{
1703170091Srrs#ifdef  SCTP_PACKET_LOGGING
1704170091Srrs			uint8_t *target;
1705170091Srrs			int ret;
1706167598Srrs
1707170091Srrs			SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize);
1708170091Srrs			ret = sctp_copy_out_packet_log(target, (int)*optsize);
1709170091Srrs			*optsize = ret;
1710170091Srrs#else
1711171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1712170091Srrs			error = EOPNOTSUPP;
1713170091Srrs#endif
1714170091Srrs			break;
1715170091Srrs		}
1716181054Srrs	case SCTP_REUSE_PORT:
1717181054Srrs		{
1718181054Srrs			uint32_t *value;
1719181054Srrs
1720181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
1721181054Srrs				/* Can't do this for a 1-m socket */
1722181054Srrs				error = EINVAL;
1723181054Srrs				break;
1724181054Srrs			}
1725181054Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1726181054Srrs			*value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
1727181054Srrs			*optsize = sizeof(uint32_t);
1728223132Stuexen			break;
1729181054Srrs		}
1730163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
1731163953Srrs		{
1732166675Srrs			uint32_t *value;
1733166675Srrs
1734166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1735166675Srrs			*value = inp->partial_delivery_point;
1736166675Srrs			*optsize = sizeof(uint32_t);
1737223132Stuexen			break;
1738163953Srrs		}
1739163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
1740163953Srrs		{
1741166675Srrs			uint32_t *value;
1742166675Srrs
1743166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1744168943Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
1745168943Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
1746168943Srrs					*value = SCTP_FRAG_LEVEL_2;
1747168943Srrs				} else {
1748168943Srrs					*value = SCTP_FRAG_LEVEL_1;
1749168943Srrs				}
1750168943Srrs			} else {
1751168943Srrs				*value = SCTP_FRAG_LEVEL_0;
1752168943Srrs			}
1753166675Srrs			*optsize = sizeof(uint32_t);
1754223132Stuexen			break;
1755163953Srrs		}
1756163953Srrs	case SCTP_CMT_ON_OFF:
1757163953Srrs		{
1758166675Srrs			struct sctp_assoc_value *av;
1759166675Srrs
1760166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1761211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1762211944Stuexen			if (stcb) {
1763211944Stuexen				av->assoc_value = stcb->asoc.sctp_cmt_on_off;
1764211944Stuexen				SCTP_TCB_UNLOCK(stcb);
1765166675Srrs			} else {
1766224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1767224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1768224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1769223132Stuexen					SCTP_INP_RLOCK(inp);
1770223132Stuexen					av->assoc_value = inp->sctp_cmt_on_off;
1771223132Stuexen					SCTP_INP_RUNLOCK(inp);
1772223132Stuexen				} else {
1773223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1774223132Stuexen					error = EINVAL;
1775223132Stuexen				}
1776163953Srrs			}
1777223132Stuexen			if (error == 0) {
1778223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1779223132Stuexen			}
1780223132Stuexen			break;
1781163953Srrs		}
1782171440Srrs	case SCTP_PLUGGABLE_CC:
1783171440Srrs		{
1784171440Srrs			struct sctp_assoc_value *av;
1785171440Srrs
1786171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1787171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1788171440Srrs			if (stcb) {
1789171440Srrs				av->assoc_value = stcb->asoc.congestion_control_module;
1790171440Srrs				SCTP_TCB_UNLOCK(stcb);
1791171440Srrs			} else {
1792224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1793224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1794224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1795223132Stuexen					SCTP_INP_RLOCK(inp);
1796223132Stuexen					av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
1797223132Stuexen					SCTP_INP_RUNLOCK(inp);
1798223132Stuexen				} else {
1799223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1800223132Stuexen					error = EINVAL;
1801223132Stuexen				}
1802171440Srrs			}
1803223132Stuexen			if (error == 0) {
1804223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1805223132Stuexen			}
1806223132Stuexen			break;
1807171440Srrs		}
1808219057Srrs	case SCTP_CC_OPTION:
1809219057Srrs		{
1810219057Srrs			struct sctp_cc_option *cc_opt;
1811219057Srrs
1812219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize);
1813219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
1814219057Srrs			if (stcb == NULL) {
1815219057Srrs				error = EINVAL;
1816219057Srrs			} else {
1817219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
1818219057Srrs					error = ENOTSUP;
1819219057Srrs				} else {
1820223132Stuexen					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt);
1821223132Stuexen					*optsize = sizeof(struct sctp_cc_option);
1822219057Srrs				}
1823219057Srrs				SCTP_TCB_UNLOCK(stcb);
1824219057Srrs			}
1825223132Stuexen			break;
1826219057Srrs		}
1827217760Stuexen	case SCTP_PLUGGABLE_SS:
1828217760Stuexen		{
1829217760Stuexen			struct sctp_assoc_value *av;
1830217760Stuexen
1831217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1832217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1833217760Stuexen			if (stcb) {
1834217760Stuexen				av->assoc_value = stcb->asoc.stream_scheduling_module;
1835217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1836217760Stuexen			} else {
1837224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1838224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1839224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1840223132Stuexen					SCTP_INP_RLOCK(inp);
1841223132Stuexen					av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
1842223132Stuexen					SCTP_INP_RUNLOCK(inp);
1843223132Stuexen				} else {
1844223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1845223132Stuexen					error = EINVAL;
1846223132Stuexen				}
1847217760Stuexen			}
1848223132Stuexen			if (error == 0) {
1849223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1850223132Stuexen			}
1851223132Stuexen			break;
1852217760Stuexen		}
1853217760Stuexen	case SCTP_SS_VALUE:
1854217760Stuexen		{
1855217760Stuexen			struct sctp_stream_value *av;
1856217760Stuexen
1857217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
1858217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1859217760Stuexen			if (stcb) {
1860217760Stuexen				if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
1861217760Stuexen				    &av->stream_value) < 0) {
1862217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1863217760Stuexen					error = EINVAL;
1864217760Stuexen				} else {
1865223132Stuexen					*optsize = sizeof(struct sctp_stream_value);
1866217760Stuexen				}
1867217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1868217760Stuexen			} else {
1869217760Stuexen				/*
1870217760Stuexen				 * Can't get stream value without
1871217760Stuexen				 * association
1872217760Stuexen				 */
1873217760Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1874217760Stuexen				error = EINVAL;
1875217760Stuexen			}
1876223132Stuexen			break;
1877217760Stuexen		}
1878163953Srrs	case SCTP_GET_ADDR_LEN:
1879163953Srrs		{
1880163953Srrs			struct sctp_assoc_value *av;
1881163953Srrs
1882166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1883163953Srrs			error = EINVAL;
1884167598Srrs#ifdef INET
1885163953Srrs			if (av->assoc_value == AF_INET) {
1886163953Srrs				av->assoc_value = sizeof(struct sockaddr_in);
1887163953Srrs				error = 0;
1888163953Srrs			}
1889163953Srrs#endif
1890167598Srrs#ifdef INET6
1891163953Srrs			if (av->assoc_value == AF_INET6) {
1892163953Srrs				av->assoc_value = sizeof(struct sockaddr_in6);
1893163953Srrs				error = 0;
1894163953Srrs			}
1895163953Srrs#endif
1896172091Srrs			if (error) {
1897171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1898223132Stuexen			} else {
1899223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1900172091Srrs			}
1901223132Stuexen			break;
1902163953Srrs		}
1903169655Srrs	case SCTP_GET_ASSOC_NUMBER:
1904163953Srrs		{
1905169655Srrs			uint32_t *value, cnt;
1906163953Srrs
1907169655Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1908163953Srrs			cnt = 0;
1909163953Srrs			SCTP_INP_RLOCK(inp);
1910169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1911169655Srrs				cnt++;
1912163953Srrs			}
1913169655Srrs			SCTP_INP_RUNLOCK(inp);
1914169655Srrs			*value = cnt;
1915169655Srrs			*optsize = sizeof(uint32_t);
1916223132Stuexen			break;
1917169655Srrs		}
1918169655Srrs	case SCTP_GET_ASSOC_ID_LIST:
1919169655Srrs		{
1920169655Srrs			struct sctp_assoc_ids *ids;
1921169655Srrs			unsigned int at, limit;
1922169655Srrs
1923169655Srrs			SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
1924163953Srrs			at = 0;
1925185694Srrs			limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t);
1926169655Srrs			SCTP_INP_RLOCK(inp);
1927169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1928169655Srrs				if (at < limit) {
1929169655Srrs					ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
1930169655Srrs				} else {
1931169655Srrs					error = EINVAL;
1932171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1933163953Srrs					break;
1934163953Srrs				}
1935163953Srrs			}
1936163953Srrs			SCTP_INP_RUNLOCK(inp);
1937223132Stuexen			if (error == 0) {
1938223132Stuexen				ids->gaids_number_of_ids = at;
1939223132Stuexen				*optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
1940223132Stuexen			}
1941223132Stuexen			break;
1942163953Srrs		}
1943163953Srrs	case SCTP_CONTEXT:
1944163953Srrs		{
1945163953Srrs			struct sctp_assoc_value *av;
1946163953Srrs
1947166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1948166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1949166675Srrs
1950166675Srrs			if (stcb) {
1951166675Srrs				av->assoc_value = stcb->asoc.context;
1952166675Srrs				SCTP_TCB_UNLOCK(stcb);
1953163953Srrs			} else {
1954224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1955224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1956224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1957223132Stuexen					SCTP_INP_RLOCK(inp);
1958223132Stuexen					av->assoc_value = inp->sctp_context;
1959223132Stuexen					SCTP_INP_RUNLOCK(inp);
1960223132Stuexen				} else {
1961223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1962223132Stuexen					error = EINVAL;
1963223132Stuexen				}
1964163953Srrs			}
1965223132Stuexen			if (error == 0) {
1966223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1967223132Stuexen			}
1968223132Stuexen			break;
1969163953Srrs		}
1970167598Srrs	case SCTP_VRF_ID:
1971167598Srrs		{
1972170056Srrs			uint32_t *default_vrfid;
1973167598Srrs
1974170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
1975170056Srrs			*default_vrfid = inp->def_vrf_id;
1976223132Stuexen			*optsize = sizeof(uint32_t);
1977167598Srrs			break;
1978167598Srrs		}
1979167598Srrs	case SCTP_GET_ASOC_VRF:
1980167598Srrs		{
1981167598Srrs			struct sctp_assoc_value *id;
1982167598Srrs
1983167598Srrs			SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
1984167598Srrs			SCTP_FIND_STCB(inp, stcb, id->assoc_id);
1985167598Srrs			if (stcb == NULL) {
1986167598Srrs				error = EINVAL;
1987171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1988223132Stuexen			} else {
1989223132Stuexen				id->assoc_value = stcb->asoc.vrf_id;
1990223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1991167598Srrs			}
1992167598Srrs			break;
1993167598Srrs		}
1994167598Srrs	case SCTP_GET_VRF_IDS:
1995167598Srrs		{
1996171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1997167598Srrs			error = EOPNOTSUPP;
1998167598Srrs			break;
1999167598Srrs		}
2000163953Srrs	case SCTP_GET_NONCE_VALUES:
2001163953Srrs		{
2002163953Srrs			struct sctp_get_nonce_values *gnv;
2003163953Srrs
2004166675Srrs			SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
2005166675Srrs			SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
2006166675Srrs
2007166675Srrs			if (stcb) {
2008163953Srrs				gnv->gn_peers_tag = stcb->asoc.peer_vtag;
2009163953Srrs				gnv->gn_local_tag = stcb->asoc.my_vtag;
2010163953Srrs				SCTP_TCB_UNLOCK(stcb);
2011223132Stuexen				*optsize = sizeof(struct sctp_get_nonce_values);
2012166675Srrs			} else {
2013171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2014166675Srrs				error = ENOTCONN;
2015163953Srrs			}
2016223132Stuexen			break;
2017163953Srrs		}
2018170056Srrs	case SCTP_DELAYED_SACK:
2019163953Srrs		{
2020170056Srrs			struct sctp_sack_info *sack;
2021163953Srrs
2022170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
2023170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
2024166675Srrs			if (stcb) {
2025170056Srrs				sack->sack_delay = stcb->asoc.delayed_ack;
2026170056Srrs				sack->sack_freq = stcb->asoc.sack_freq;
2027166675Srrs				SCTP_TCB_UNLOCK(stcb);
2028166675Srrs			} else {
2029224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2030224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2031224918Stuexen				    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) {
2032223132Stuexen					SCTP_INP_RLOCK(inp);
2033223132Stuexen					sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
2034223132Stuexen					sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
2035223132Stuexen					SCTP_INP_RUNLOCK(inp);
2036223132Stuexen				} else {
2037223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2038223132Stuexen					error = EINVAL;
2039223132Stuexen				}
2040163953Srrs			}
2041223132Stuexen			if (error == 0) {
2042223132Stuexen				*optsize = sizeof(struct sctp_sack_info);
2043223132Stuexen			}
2044223132Stuexen			break;
2045163953Srrs		}
2046163953Srrs	case SCTP_GET_SNDBUF_USE:
2047166675Srrs		{
2048163953Srrs			struct sctp_sockstat *ss;
2049163953Srrs
2050166675Srrs			SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
2051166675Srrs			SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
2052166675Srrs
2053166675Srrs			if (stcb) {
2054166675Srrs				ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
2055166675Srrs				ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
2056166675Srrs				    stcb->asoc.size_on_all_streams);
2057166675Srrs				SCTP_TCB_UNLOCK(stcb);
2058223132Stuexen				*optsize = sizeof(struct sctp_sockstat);
2059166675Srrs			} else {
2060171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2061163953Srrs				error = ENOTCONN;
2062163953Srrs			}
2063223132Stuexen			break;
2064163953Srrs		}
2065170056Srrs	case SCTP_MAX_BURST:
2066163953Srrs		{
2067217895Stuexen			struct sctp_assoc_value *av;
2068163953Srrs
2069217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2070217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2071166675Srrs
2072217895Stuexen			if (stcb) {
2073217895Stuexen				av->assoc_value = stcb->asoc.max_burst;
2074217895Stuexen				SCTP_TCB_UNLOCK(stcb);
2075217894Stuexen			} else {
2076224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2077224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2078224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2079223132Stuexen					SCTP_INP_RLOCK(inp);
2080223132Stuexen					av->assoc_value = inp->sctp_ep.max_burst;
2081223132Stuexen					SCTP_INP_RUNLOCK(inp);
2082223132Stuexen				} else {
2083223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2084223132Stuexen					error = EINVAL;
2085223132Stuexen				}
2086217894Stuexen			}
2087223132Stuexen			if (error == 0) {
2088223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2089223132Stuexen			}
2090223132Stuexen			break;
2091163953Srrs		}
2092163953Srrs	case SCTP_MAXSEG:
2093163953Srrs		{
2094167598Srrs			struct sctp_assoc_value *av;
2095163953Srrs			int ovh;
2096163953Srrs
2097167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2098170056Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2099163953Srrs
2100167598Srrs			if (stcb) {
2101167598Srrs				av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
2102167598Srrs				SCTP_TCB_UNLOCK(stcb);
2103163953Srrs			} else {
2104224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2105224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2106224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2107223132Stuexen					SCTP_INP_RLOCK(inp);
2108223132Stuexen					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2109223132Stuexen						ovh = SCTP_MED_OVERHEAD;
2110223132Stuexen					} else {
2111223132Stuexen						ovh = SCTP_MED_V4_OVERHEAD;
2112223132Stuexen					}
2113223132Stuexen					if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
2114223132Stuexen						av->assoc_value = 0;
2115223132Stuexen					else
2116223132Stuexen						av->assoc_value = inp->sctp_frag_point - ovh;
2117223132Stuexen					SCTP_INP_RUNLOCK(inp);
2118167598Srrs				} else {
2119223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2120223132Stuexen					error = EINVAL;
2121167598Srrs				}
2122163953Srrs			}
2123223132Stuexen			if (error == 0) {
2124223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2125223132Stuexen			}
2126223132Stuexen			break;
2127163953Srrs		}
2128163953Srrs	case SCTP_GET_STAT_LOG:
2129167598Srrs		error = sctp_fill_stat_log(optval, optsize);
2130163953Srrs		break;
2131163953Srrs	case SCTP_EVENTS:
2132163953Srrs		{
2133163953Srrs			struct sctp_event_subscribe *events;
2134163953Srrs
2135166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
2136223132Stuexen			memset(events, 0, sizeof(struct sctp_event_subscribe));
2137163953Srrs			SCTP_INP_RLOCK(inp);
2138163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
2139163953Srrs				events->sctp_data_io_event = 1;
2140163953Srrs
2141163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
2142163953Srrs				events->sctp_association_event = 1;
2143163953Srrs
2144163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
2145163953Srrs				events->sctp_address_event = 1;
2146163953Srrs
2147163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
2148163953Srrs				events->sctp_send_failure_event = 1;
2149163953Srrs
2150163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
2151163953Srrs				events->sctp_peer_error_event = 1;
2152163953Srrs
2153163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
2154163953Srrs				events->sctp_shutdown_event = 1;
2155163953Srrs
2156163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
2157163953Srrs				events->sctp_partial_delivery_event = 1;
2158163953Srrs
2159163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
2160163953Srrs				events->sctp_adaptation_layer_event = 1;
2161163953Srrs
2162163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
2163163953Srrs				events->sctp_authentication_event = 1;
2164163953Srrs
2165185694Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
2166185694Srrs				events->sctp_sender_dry_event = 1;
2167185694Srrs
2168163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
2169202520Srrs				events->sctp_stream_reset_event = 1;
2170163953Srrs			SCTP_INP_RUNLOCK(inp);
2171166675Srrs			*optsize = sizeof(struct sctp_event_subscribe);
2172223132Stuexen			break;
2173163953Srrs		}
2174163953Srrs	case SCTP_ADAPTATION_LAYER:
2175166675Srrs		{
2176166675Srrs			uint32_t *value;
2177166675Srrs
2178166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2179166675Srrs
2180166675Srrs			SCTP_INP_RLOCK(inp);
2181166675Srrs			*value = inp->sctp_ep.adaptation_layer_indicator;
2182166675Srrs			SCTP_INP_RUNLOCK(inp);
2183166675Srrs			*optsize = sizeof(uint32_t);
2184223132Stuexen			break;
2185163953Srrs		}
2186163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
2187166675Srrs		{
2188166675Srrs			uint32_t *value;
2189166675Srrs
2190166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2191166675Srrs			SCTP_INP_RLOCK(inp);
2192166675Srrs			*value = inp->sctp_ep.initial_sequence_debug;
2193166675Srrs			SCTP_INP_RUNLOCK(inp);
2194166675Srrs			*optsize = sizeof(uint32_t);
2195223132Stuexen			break;
2196163953Srrs		}
2197163953Srrs	case SCTP_GET_LOCAL_ADDR_SIZE:
2198166675Srrs		{
2199166675Srrs			uint32_t *value;
2200166675Srrs
2201166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2202166675Srrs			SCTP_INP_RLOCK(inp);
2203168124Srrs			*value = sctp_count_max_addresses(inp);
2204166675Srrs			SCTP_INP_RUNLOCK(inp);
2205166675Srrs			*optsize = sizeof(uint32_t);
2206223132Stuexen			break;
2207163953Srrs		}
2208163953Srrs	case SCTP_GET_REMOTE_ADDR_SIZE:
2209163953Srrs		{
2210166675Srrs			uint32_t *value;
2211166675Srrs			size_t size;
2212163953Srrs			struct sctp_nets *net;
2213163953Srrs
2214166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2215166675Srrs			/* FIXME MT: change to sctp_assoc_value? */
2216166675Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
2217166675Srrs
2218166675Srrs			if (stcb) {
2219166675Srrs				size = 0;
2220166675Srrs				/* Count the sizes */
2221166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2222221249Stuexen					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2223166675Srrs						size += sizeof(struct sockaddr_in6);
2224166675Srrs					} else {
2225221249Stuexen						switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
2226221249Stuexen#ifdef INET
2227221249Stuexen						case AF_INET:
2228221249Stuexen							size += sizeof(struct sockaddr_in);
2229221249Stuexen							break;
2230221249Stuexen#endif
2231221249Stuexen#ifdef INET6
2232221249Stuexen						case AF_INET6:
2233221249Stuexen							size += sizeof(struct sockaddr_in6);
2234221249Stuexen							break;
2235221249Stuexen#endif
2236221249Stuexen						default:
2237221249Stuexen							break;
2238221249Stuexen						}
2239166675Srrs					}
2240163953Srrs				}
2241166675Srrs				SCTP_TCB_UNLOCK(stcb);
2242166675Srrs				*value = (uint32_t) size;
2243223132Stuexen				*optsize = sizeof(uint32_t);
2244166675Srrs			} else {
2245171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2246166675Srrs				error = ENOTCONN;
2247163953Srrs			}
2248223132Stuexen			break;
2249163953Srrs		}
2250163953Srrs	case SCTP_GET_PEER_ADDRESSES:
2251163953Srrs		/*
2252163953Srrs		 * Get the address information, an array is passed in to
2253163953Srrs		 * fill up we pack it.
2254163953Srrs		 */
2255163953Srrs		{
2256166675Srrs			size_t cpsz, left;
2257163953Srrs			struct sockaddr_storage *sas;
2258163953Srrs			struct sctp_nets *net;
2259163953Srrs			struct sctp_getaddresses *saddr;
2260163953Srrs
2261166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2262166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2263163953Srrs
2264166675Srrs			if (stcb) {
2265166675Srrs				left = (*optsize) - sizeof(struct sctp_getaddresses);
2266166675Srrs				*optsize = sizeof(struct sctp_getaddresses);
2267166675Srrs				sas = (struct sockaddr_storage *)&saddr->addr[0];
2268166675Srrs
2269166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2270221249Stuexen					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2271166675Srrs						cpsz = sizeof(struct sockaddr_in6);
2272166675Srrs					} else {
2273221249Stuexen						switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
2274221249Stuexen#ifdef INET
2275221249Stuexen						case AF_INET:
2276221249Stuexen							cpsz = sizeof(struct sockaddr_in);
2277221249Stuexen							break;
2278221249Stuexen#endif
2279221249Stuexen#ifdef INET6
2280221249Stuexen						case AF_INET6:
2281221249Stuexen							cpsz = sizeof(struct sockaddr_in6);
2282221249Stuexen							break;
2283221249Stuexen#endif
2284221249Stuexen						default:
2285221249Stuexen							cpsz = 0;
2286221249Stuexen							break;
2287221249Stuexen						}
2288221249Stuexen					}
2289221249Stuexen					if (cpsz == 0) {
2290166675Srrs						break;
2291166675Srrs					}
2292166675Srrs					if (left < cpsz) {
2293166675Srrs						/* not enough room. */
2294166675Srrs						break;
2295166675Srrs					}
2296221249Stuexen#if defined(INET) && defined(INET6)
2297178251Srrs					if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
2298166675Srrs					    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
2299166675Srrs						/* Must map the address */
2300166675Srrs						in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
2301166675Srrs						    (struct sockaddr_in6 *)sas);
2302166675Srrs					} else {
2303178251Srrs#endif
2304166675Srrs						memcpy(sas, &net->ro._l_addr, cpsz);
2305221249Stuexen#if defined(INET) && defined(INET6)
2306166675Srrs					}
2307178251Srrs#endif
2308166675Srrs					((struct sockaddr_in *)sas)->sin_port = stcb->rport;
2309166675Srrs
2310166675Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
2311166675Srrs					left -= cpsz;
2312166675Srrs					*optsize += cpsz;
2313163953Srrs				}
2314166675Srrs				SCTP_TCB_UNLOCK(stcb);
2315166675Srrs			} else {
2316171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2317166675Srrs				error = ENOENT;
2318163953Srrs			}
2319223132Stuexen			break;
2320163953Srrs		}
2321163953Srrs	case SCTP_GET_LOCAL_ADDRESSES:
2322163953Srrs		{
2323166675Srrs			size_t limit, actual;
2324163953Srrs			struct sockaddr_storage *sas;
2325163953Srrs			struct sctp_getaddresses *saddr;
2326163953Srrs
2327166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2328166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2329163953Srrs
2330163953Srrs			sas = (struct sockaddr_storage *)&saddr->addr[0];
2331166675Srrs			limit = *optsize - sizeof(sctp_assoc_t);
2332168124Srrs			actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
2333169655Srrs			if (stcb) {
2334163953Srrs				SCTP_TCB_UNLOCK(stcb);
2335169655Srrs			}
2336166675Srrs			*optsize = sizeof(struct sockaddr_storage) + actual;
2337223132Stuexen			break;
2338163953Srrs		}
2339163953Srrs	case SCTP_PEER_ADDR_PARAMS:
2340163953Srrs		{
2341163953Srrs			struct sctp_paddrparams *paddrp;
2342163953Srrs			struct sctp_nets *net;
2343163953Srrs
2344166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
2345166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
2346163953Srrs
2347163953Srrs			net = NULL;
2348166675Srrs			if (stcb) {
2349166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
2350166675Srrs			} else {
2351166675Srrs				/*
2352166675Srrs				 * We increment here since
2353166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2354166675Srrs				 * decrement if it finds the stcb as long as
2355166675Srrs				 * the locked tcb (last argument) is NOT a
2356166675Srrs				 * TCB.. aka NULL.
2357166675Srrs				 */
2358166675Srrs				SCTP_INP_INCR_REF(inp);
2359166675Srrs				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL);
2360163953Srrs				if (stcb == NULL) {
2361166675Srrs					SCTP_INP_DECR_REF(inp);
2362163953Srrs				}
2363163953Srrs			}
2364171943Srrs			if (stcb && (net == NULL)) {
2365171943Srrs				struct sockaddr *sa;
2366163953Srrs
2367171943Srrs				sa = (struct sockaddr *)&paddrp->spp_address;
2368221249Stuexen#ifdef INET
2369171943Srrs				if (sa->sa_family == AF_INET) {
2370171943Srrs					struct sockaddr_in *sin;
2371171943Srrs
2372171943Srrs					sin = (struct sockaddr_in *)sa;
2373171943Srrs					if (sin->sin_addr.s_addr) {
2374171943Srrs						error = EINVAL;
2375171943Srrs						SCTP_TCB_UNLOCK(stcb);
2376171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2377171943Srrs						break;
2378171943Srrs					}
2379221249Stuexen				} else
2380221249Stuexen#endif
2381221249Stuexen#ifdef INET6
2382221249Stuexen				if (sa->sa_family == AF_INET6) {
2383171943Srrs					struct sockaddr_in6 *sin6;
2384171943Srrs
2385171943Srrs					sin6 = (struct sockaddr_in6 *)sa;
2386171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
2387171943Srrs						error = EINVAL;
2388171943Srrs						SCTP_TCB_UNLOCK(stcb);
2389171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2390171943Srrs						break;
2391171943Srrs					}
2392221249Stuexen				} else
2393221249Stuexen#endif
2394221249Stuexen				{
2395171943Srrs					error = EAFNOSUPPORT;
2396171943Srrs					SCTP_TCB_UNLOCK(stcb);
2397171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2398171943Srrs					break;
2399171943Srrs				}
2400171943Srrs			}
2401163953Srrs			if (stcb) {
2402224641Stuexen				/* Applies to the specific association */
2403163953Srrs				paddrp->spp_flags = 0;
2404163953Srrs				if (net) {
2405170056Srrs					int ovh;
2406170056Srrs
2407170056Srrs					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2408170056Srrs						ovh = SCTP_MED_OVERHEAD;
2409170056Srrs					} else {
2410170056Srrs						ovh = SCTP_MED_V4_OVERHEAD;
2411170056Srrs					}
2412170056Srrs
2413224641Stuexen					paddrp->spp_hbinterval = net->heart_beat_delay;
2414163953Srrs					paddrp->spp_pathmaxrxt = net->failure_threshold;
2415170056Srrs					paddrp->spp_pathmtu = net->mtu - ovh;
2416163953Srrs					/* get flags for HB */
2417225635Stuexen					if (net->dest_state & SCTP_ADDR_NOHB) {
2418163953Srrs						paddrp->spp_flags |= SPP_HB_DISABLE;
2419225635Stuexen					} else {
2420163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2421225635Stuexen					}
2422163953Srrs					/* get flags for PMTU */
2423225635Stuexen					if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
2424163953Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2425163953Srrs					} else {
2426163953Srrs						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2427163953Srrs					}
2428225549Stuexen					if (net->dscp & 0x01) {
2429226252Stuexen						paddrp->spp_dscp = net->dscp & 0xfc;
2430224870Stuexen						paddrp->spp_flags |= SPP_DSCP;
2431163953Srrs					}
2432167598Srrs#ifdef INET6
2433225549Stuexen					if ((net->ro._l_addr.sa.sa_family == AF_INET6) &&
2434225549Stuexen					    (net->flowlabel & 0x80000000)) {
2435225549Stuexen						paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff;
2436163953Srrs						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2437163953Srrs					}
2438163953Srrs#endif
2439163953Srrs				} else {
2440163953Srrs					/*
2441163953Srrs					 * No destination so return default
2442163953Srrs					 * value
2443163953Srrs					 */
2444163953Srrs					paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
2445163953Srrs					paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
2446225549Stuexen					if (stcb->asoc.default_dscp & 0x01) {
2447226252Stuexen						paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
2448225549Stuexen						paddrp->spp_flags |= SPP_DSCP;
2449225549Stuexen					}
2450167598Srrs#ifdef INET6
2451225549Stuexen					if (stcb->asoc.default_flowlabel & 0x80000000) {
2452225549Stuexen						paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff;
2453225549Stuexen						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2454225549Stuexen					}
2455163953Srrs#endif
2456163953Srrs					/* default settings should be these */
2457225635Stuexen					if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2458224641Stuexen						paddrp->spp_flags |= SPP_HB_DISABLE;
2459224641Stuexen					} else {
2460163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2461163953Srrs					}
2462225635Stuexen					if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
2463225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2464225635Stuexen					} else {
2465170056Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2466170056Srrs					}
2467225635Stuexen					paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
2468163953Srrs				}
2469163953Srrs				paddrp->spp_assoc_id = sctp_get_associd(stcb);
2470163953Srrs				SCTP_TCB_UNLOCK(stcb);
2471163953Srrs			} else {
2472224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2473224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2474224918Stuexen				    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
2475223132Stuexen					/* Use endpoint defaults */
2476223132Stuexen					SCTP_INP_RLOCK(inp);
2477223132Stuexen					paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
2478223132Stuexen					paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
2479223132Stuexen					paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
2480223132Stuexen					/* get inp's default */
2481225549Stuexen					if (inp->sctp_ep.default_dscp & 0x01) {
2482226252Stuexen						paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc;
2483225549Stuexen						paddrp->spp_flags |= SPP_DSCP;
2484225549Stuexen					}
2485167598Srrs#ifdef INET6
2486225549Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
2487225549Stuexen					    (inp->sctp_ep.default_flowlabel & 0x80000000)) {
2488225549Stuexen						paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff;
2489223132Stuexen						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2490223132Stuexen					}
2491163953Srrs#endif
2492223132Stuexen					/* can't return this */
2493223132Stuexen					paddrp->spp_pathmtu = 0;
2494170056Srrs
2495223132Stuexen					if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2496223132Stuexen						paddrp->spp_flags |= SPP_HB_ENABLE;
2497223132Stuexen					} else {
2498223132Stuexen						paddrp->spp_flags |= SPP_HB_DISABLE;
2499223132Stuexen					}
2500225635Stuexen					if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
2501225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2502225635Stuexen					} else {
2503225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2504225635Stuexen					}
2505223132Stuexen					SCTP_INP_RUNLOCK(inp);
2506170056Srrs				} else {
2507223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2508223132Stuexen					error = EINVAL;
2509170056Srrs				}
2510163953Srrs			}
2511223132Stuexen			if (error == 0) {
2512223132Stuexen				*optsize = sizeof(struct sctp_paddrparams);
2513223132Stuexen			}
2514223132Stuexen			break;
2515163953Srrs		}
2516163953Srrs	case SCTP_GET_PEER_ADDR_INFO:
2517163953Srrs		{
2518163953Srrs			struct sctp_paddrinfo *paddri;
2519163953Srrs			struct sctp_nets *net;
2520163953Srrs
2521166675Srrs			SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
2522166675Srrs			SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
2523166675Srrs
2524163953Srrs			net = NULL;
2525166675Srrs			if (stcb) {
2526166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address);
2527166675Srrs			} else {
2528166675Srrs				/*
2529166675Srrs				 * We increment here since
2530166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2531166675Srrs				 * decrement if it finds the stcb as long as
2532166675Srrs				 * the locked tcb (last argument) is NOT a
2533166675Srrs				 * TCB.. aka NULL.
2534166675Srrs				 */
2535166675Srrs				SCTP_INP_INCR_REF(inp);
2536166675Srrs				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL);
2537166675Srrs				if (stcb == NULL) {
2538166675Srrs					SCTP_INP_DECR_REF(inp);
2539163953Srrs				}
2540166675Srrs			}
2541163953Srrs
2542166675Srrs			if ((stcb) && (net)) {
2543217635Srrs				if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2544217638Stuexen					/* It's unconfirmed */
2545217635Srrs					paddri->spinfo_state = SCTP_UNCONFIRMED;
2546217635Srrs				} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2547217638Stuexen					/* It's active */
2548217635Srrs					paddri->spinfo_state = SCTP_ACTIVE;
2549217635Srrs				} else {
2550217638Stuexen					/* It's inactive */
2551217635Srrs					paddri->spinfo_state = SCTP_INACTIVE;
2552217635Srrs				}
2553166675Srrs				paddri->spinfo_cwnd = net->cwnd;
2554219014Stuexen				paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2555166675Srrs				paddri->spinfo_rto = net->RTO;
2556166675Srrs				paddri->spinfo_assoc_id = sctp_get_associd(stcb);
2557222029Stuexen				paddri->spinfo_mtu = net->mtu;
2558166675Srrs				SCTP_TCB_UNLOCK(stcb);
2559223132Stuexen				*optsize = sizeof(struct sctp_paddrinfo);
2560163953Srrs			} else {
2561163953Srrs				if (stcb) {
2562163953Srrs					SCTP_TCB_UNLOCK(stcb);
2563163953Srrs				}
2564171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2565163953Srrs				error = ENOENT;
2566163953Srrs			}
2567223132Stuexen			break;
2568163953Srrs		}
2569163953Srrs	case SCTP_PCB_STATUS:
2570163953Srrs		{
2571163953Srrs			struct sctp_pcbinfo *spcb;
2572163953Srrs
2573166675Srrs			SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
2574163953Srrs			sctp_fill_pcbinfo(spcb);
2575166675Srrs			*optsize = sizeof(struct sctp_pcbinfo);
2576223132Stuexen			break;
2577163953Srrs		}
2578163953Srrs	case SCTP_STATUS:
2579163953Srrs		{
2580163953Srrs			struct sctp_nets *net;
2581163953Srrs			struct sctp_status *sstat;
2582163953Srrs
2583166675Srrs			SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
2584166675Srrs			SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
2585163953Srrs
2586163953Srrs			if (stcb == NULL) {
2587223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2588163953Srrs				error = EINVAL;
2589163953Srrs				break;
2590163953Srrs			}
2591163953Srrs			/*
2592163953Srrs			 * I think passing the state is fine since
2593163953Srrs			 * sctp_constants.h will be available to the user
2594163953Srrs			 * land.
2595163953Srrs			 */
2596163953Srrs			sstat->sstat_state = stcb->asoc.state;
2597173179Srrs			sstat->sstat_assoc_id = sctp_get_associd(stcb);
2598163953Srrs			sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
2599163953Srrs			sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
2600163953Srrs			/*
2601163953Srrs			 * We can't include chunks that have been passed to
2602163953Srrs			 * the socket layer. Only things in queue.
2603163953Srrs			 */
2604163953Srrs			sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
2605163953Srrs			    stcb->asoc.cnt_on_all_streams);
2606163953Srrs
2607163953Srrs
2608163953Srrs			sstat->sstat_instrms = stcb->asoc.streamincnt;
2609163953Srrs			sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
2610163953Srrs			sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
2611163953Srrs			memcpy(&sstat->sstat_primary.spinfo_address,
2612163953Srrs			    &stcb->asoc.primary_destination->ro._l_addr,
2613163953Srrs			    ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
2614163953Srrs			net = stcb->asoc.primary_destination;
2615163953Srrs			((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
2616163953Srrs			/*
2617163953Srrs			 * Again the user can get info from sctp_constants.h
2618163953Srrs			 * for what the state of the network is.
2619163953Srrs			 */
2620217635Srrs			if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2621217635Srrs				/* It's unconfirmed */
2622217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
2623217635Srrs			} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2624217638Stuexen				/* It's active */
2625217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
2626217635Srrs			} else {
2627217638Stuexen				/* It's inactive */
2628217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
2629217635Srrs			}
2630163953Srrs			sstat->sstat_primary.spinfo_cwnd = net->cwnd;
2631219014Stuexen			sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2632163953Srrs			sstat->sstat_primary.spinfo_rto = net->RTO;
2633163953Srrs			sstat->sstat_primary.spinfo_mtu = net->mtu;
2634163953Srrs			sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
2635163953Srrs			SCTP_TCB_UNLOCK(stcb);
2636223132Stuexen			*optsize = sizeof(struct sctp_status);
2637223132Stuexen			break;
2638163953Srrs		}
2639163953Srrs	case SCTP_RTOINFO:
2640163953Srrs		{
2641163953Srrs			struct sctp_rtoinfo *srto;
2642163953Srrs
2643166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
2644166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
2645166675Srrs
2646166675Srrs			if (stcb) {
2647166675Srrs				srto->srto_initial = stcb->asoc.initial_rto;
2648166675Srrs				srto->srto_max = stcb->asoc.maxrto;
2649166675Srrs				srto->srto_min = stcb->asoc.minrto;
2650166675Srrs				SCTP_TCB_UNLOCK(stcb);
2651166675Srrs			} else {
2652224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2653224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2654224918Stuexen				    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
2655223132Stuexen					SCTP_INP_RLOCK(inp);
2656223132Stuexen					srto->srto_initial = inp->sctp_ep.initial_rto;
2657223132Stuexen					srto->srto_max = inp->sctp_ep.sctp_maxrto;
2658223132Stuexen					srto->srto_min = inp->sctp_ep.sctp_minrto;
2659223132Stuexen					SCTP_INP_RUNLOCK(inp);
2660223132Stuexen				} else {
2661223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2662223132Stuexen					error = EINVAL;
2663223132Stuexen				}
2664163953Srrs			}
2665223132Stuexen			if (error == 0) {
2666223132Stuexen				*optsize = sizeof(struct sctp_rtoinfo);
2667223132Stuexen			}
2668223132Stuexen			break;
2669163953Srrs		}
2670215410Stuexen	case SCTP_TIMEOUTS:
2671215410Stuexen		{
2672215410Stuexen			struct sctp_timeouts *stimo;
2673215410Stuexen
2674215410Stuexen			SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize);
2675215410Stuexen			SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id);
2676215410Stuexen
2677215410Stuexen			if (stcb) {
2678215410Stuexen				stimo->stimo_init = stcb->asoc.timoinit;
2679215410Stuexen				stimo->stimo_data = stcb->asoc.timodata;
2680215410Stuexen				stimo->stimo_sack = stcb->asoc.timosack;
2681215410Stuexen				stimo->stimo_shutdown = stcb->asoc.timoshutdown;
2682215410Stuexen				stimo->stimo_heartbeat = stcb->asoc.timoheartbeat;
2683215410Stuexen				stimo->stimo_cookie = stcb->asoc.timocookie;
2684215410Stuexen				stimo->stimo_shutdownack = stcb->asoc.timoshutdownack;
2685215410Stuexen				SCTP_TCB_UNLOCK(stcb);
2686223132Stuexen				*optsize = sizeof(struct sctp_timeouts);
2687215410Stuexen			} else {
2688223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2689215410Stuexen				error = EINVAL;
2690215410Stuexen			}
2691223132Stuexen			break;
2692215410Stuexen		}
2693163953Srrs	case SCTP_ASSOCINFO:
2694163953Srrs		{
2695163953Srrs			struct sctp_assocparams *sasoc;
2696163953Srrs
2697166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
2698166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
2699163953Srrs
2700163953Srrs			if (stcb) {
2701171477Srrs				sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
2702163953Srrs				sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
2703163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
2704163953Srrs				sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
2705163953Srrs				sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
2706163953Srrs				SCTP_TCB_UNLOCK(stcb);
2707163953Srrs			} else {
2708224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2709224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2710224918Stuexen				    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
2711223132Stuexen					SCTP_INP_RLOCK(inp);
2712223132Stuexen					sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
2713223132Stuexen					sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
2714223132Stuexen					sasoc->sasoc_number_peer_destinations = 0;
2715223132Stuexen					sasoc->sasoc_peer_rwnd = 0;
2716223132Stuexen					sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
2717223132Stuexen					SCTP_INP_RUNLOCK(inp);
2718223132Stuexen				} else {
2719223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2720223132Stuexen					error = EINVAL;
2721223132Stuexen				}
2722163953Srrs			}
2723223132Stuexen			if (error == 0) {
2724223132Stuexen				*optsize = sizeof(struct sctp_assocparams);
2725223132Stuexen			}
2726223132Stuexen			break;
2727163953Srrs		}
2728163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
2729163953Srrs		{
2730163953Srrs			struct sctp_sndrcvinfo *s_info;
2731163953Srrs
2732166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
2733166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
2734166675Srrs
2735166675Srrs			if (stcb) {
2736170056Srrs				memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
2737166675Srrs				SCTP_TCB_UNLOCK(stcb);
2738166675Srrs			} else {
2739224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2740224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2741224918Stuexen				    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) {
2742223132Stuexen					SCTP_INP_RLOCK(inp);
2743223132Stuexen					memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
2744223132Stuexen					SCTP_INP_RUNLOCK(inp);
2745223132Stuexen				} else {
2746223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2747223132Stuexen					error = EINVAL;
2748223132Stuexen				}
2749163953Srrs			}
2750223132Stuexen			if (error == 0) {
2751223132Stuexen				*optsize = sizeof(struct sctp_sndrcvinfo);
2752223132Stuexen			}
2753223132Stuexen			break;
2754163953Srrs		}
2755163953Srrs	case SCTP_INITMSG:
2756163953Srrs		{
2757163953Srrs			struct sctp_initmsg *sinit;
2758163953Srrs
2759166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
2760163953Srrs			SCTP_INP_RLOCK(inp);
2761163953Srrs			sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
2762163953Srrs			sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
2763163953Srrs			sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
2764163953Srrs			sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
2765163953Srrs			SCTP_INP_RUNLOCK(inp);
2766223132Stuexen			*optsize = sizeof(struct sctp_initmsg);
2767223132Stuexen			break;
2768163953Srrs		}
2769163953Srrs	case SCTP_PRIMARY_ADDR:
2770163953Srrs		/* we allow a "get" operation on this */
2771163953Srrs		{
2772163953Srrs			struct sctp_setprim *ssp;
2773163953Srrs
2774166675Srrs			SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
2775166675Srrs			SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
2776166675Srrs
2777166675Srrs			if (stcb) {
2778166675Srrs				/* simply copy out the sockaddr_storage... */
2779170056Srrs				int len;
2780170056Srrs
2781170056Srrs				len = *optsize;
2782170056Srrs				if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len)
2783170056Srrs					len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len;
2784170056Srrs
2785170056Srrs				memcpy(&ssp->ssp_addr,
2786170056Srrs				    &stcb->asoc.primary_destination->ro._l_addr,
2787170056Srrs				    len);
2788166675Srrs				SCTP_TCB_UNLOCK(stcb);
2789223132Stuexen				*optsize = sizeof(struct sctp_setprim);
2790166675Srrs			} else {
2791223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2792163953Srrs				error = EINVAL;
2793163953Srrs			}
2794223132Stuexen			break;
2795163953Srrs		}
2796163953Srrs	case SCTP_HMAC_IDENT:
2797163953Srrs		{
2798163953Srrs			struct sctp_hmacalgo *shmac;
2799163953Srrs			sctp_hmaclist_t *hmaclist;
2800163953Srrs			uint32_t size;
2801163953Srrs			int i;
2802163953Srrs
2803166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
2804166675Srrs
2805163953Srrs			SCTP_INP_RLOCK(inp);
2806163953Srrs			hmaclist = inp->sctp_ep.local_hmacs;
2807163953Srrs			if (hmaclist == NULL) {
2808163953Srrs				/* no HMACs to return */
2809166675Srrs				*optsize = sizeof(*shmac);
2810168299Srrs				SCTP_INP_RUNLOCK(inp);
2811163953Srrs				break;
2812163953Srrs			}
2813163953Srrs			/* is there room for all of the hmac ids? */
2814163953Srrs			size = sizeof(*shmac) + (hmaclist->num_algo *
2815163953Srrs			    sizeof(shmac->shmac_idents[0]));
2816166675Srrs			if ((size_t)(*optsize) < size) {
2817223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2818163953Srrs				error = EINVAL;
2819163953Srrs				SCTP_INP_RUNLOCK(inp);
2820163953Srrs				break;
2821163953Srrs			}
2822163953Srrs			/* copy in the list */
2823181054Srrs			shmac->shmac_number_of_idents = hmaclist->num_algo;
2824181054Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
2825163953Srrs				shmac->shmac_idents[i] = hmaclist->hmac[i];
2826181054Srrs			}
2827163953Srrs			SCTP_INP_RUNLOCK(inp);
2828166675Srrs			*optsize = size;
2829163953Srrs			break;
2830163953Srrs		}
2831163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
2832163953Srrs		{
2833163953Srrs			struct sctp_authkeyid *scact;
2834163953Srrs
2835166675Srrs			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
2836166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
2837166675Srrs
2838166675Srrs			if (stcb) {
2839163953Srrs				/* get the active key on the assoc */
2840185694Srrs				scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
2841163953Srrs				SCTP_TCB_UNLOCK(stcb);
2842163953Srrs			} else {
2843224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2844224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2845224918Stuexen				    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) {
2846223132Stuexen					/* get the endpoint active key */
2847223132Stuexen					SCTP_INP_RLOCK(inp);
2848223132Stuexen					scact->scact_keynumber = inp->sctp_ep.default_keyid;
2849223132Stuexen					SCTP_INP_RUNLOCK(inp);
2850223132Stuexen				} else {
2851223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2852223132Stuexen					error = EINVAL;
2853223132Stuexen				}
2854163953Srrs			}
2855223132Stuexen			if (error == 0) {
2856223132Stuexen				*optsize = sizeof(struct sctp_authkeyid);
2857223132Stuexen			}
2858163953Srrs			break;
2859163953Srrs		}
2860163953Srrs	case SCTP_LOCAL_AUTH_CHUNKS:
2861163953Srrs		{
2862163953Srrs			struct sctp_authchunks *sac;
2863163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2864166675Srrs			size_t size = 0;
2865163953Srrs
2866166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2867166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2868166675Srrs
2869166675Srrs			if (stcb) {
2870163953Srrs				/* get off the assoc */
2871163953Srrs				chklist = stcb->asoc.local_auth_chunks;
2872163953Srrs				/* is there enough space? */
2873163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2874166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2875163953Srrs					error = EINVAL;
2876171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2877166675Srrs				} else {
2878166675Srrs					/* copy in the chunks */
2879169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2880234832Stuexen					sac->gauth_number_of_chunks = (uint32_t) size;
2881223132Stuexen					*optsize = sizeof(struct sctp_authchunks) + size;
2882163953Srrs				}
2883163953Srrs				SCTP_TCB_UNLOCK(stcb);
2884163953Srrs			} else {
2885224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2886224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2887224918Stuexen				    (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) {
2888223132Stuexen					/* get off the endpoint */
2889223132Stuexen					SCTP_INP_RLOCK(inp);
2890223132Stuexen					chklist = inp->sctp_ep.local_auth_chunks;
2891223132Stuexen					/* is there enough space? */
2892223132Stuexen					size = sctp_auth_get_chklist_size(chklist);
2893223132Stuexen					if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2894223132Stuexen						error = EINVAL;
2895223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2896223132Stuexen					} else {
2897223132Stuexen						/* copy in the chunks */
2898223132Stuexen						(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2899234832Stuexen						sac->gauth_number_of_chunks = (uint32_t) size;
2900223132Stuexen						*optsize = sizeof(struct sctp_authchunks) + size;
2901223132Stuexen					}
2902223132Stuexen					SCTP_INP_RUNLOCK(inp);
2903223132Stuexen				} else {
2904223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2905163953Srrs					error = EINVAL;
2906163953Srrs				}
2907163953Srrs			}
2908163953Srrs			break;
2909163953Srrs		}
2910163953Srrs	case SCTP_PEER_AUTH_CHUNKS:
2911163953Srrs		{
2912163953Srrs			struct sctp_authchunks *sac;
2913163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2914166675Srrs			size_t size = 0;
2915163953Srrs
2916166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2917166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2918166675Srrs
2919166675Srrs			if (stcb) {
2920166675Srrs				/* get off the assoc */
2921166675Srrs				chklist = stcb->asoc.peer_auth_chunks;
2922166675Srrs				/* is there enough space? */
2923166675Srrs				size = sctp_auth_get_chklist_size(chklist);
2924166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2925166675Srrs					error = EINVAL;
2926171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2927166675Srrs				} else {
2928166675Srrs					/* copy in the chunks */
2929169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2930234832Stuexen					sac->gauth_number_of_chunks = (uint32_t) size;
2931223132Stuexen					*optsize = sizeof(struct sctp_authchunks) + size;
2932166675Srrs				}
2933166675Srrs				SCTP_TCB_UNLOCK(stcb);
2934166675Srrs			} else {
2935171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2936163953Srrs				error = ENOENT;
2937163953Srrs			}
2938163953Srrs			break;
2939163953Srrs		}
2940223132Stuexen	case SCTP_EVENT:
2941223132Stuexen		{
2942223132Stuexen			struct sctp_event *event;
2943223132Stuexen			uint32_t event_type;
2944163953Srrs
2945223132Stuexen			SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize);
2946223132Stuexen			SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
2947163953Srrs
2948223132Stuexen			switch (event->se_type) {
2949223132Stuexen			case SCTP_ASSOC_CHANGE:
2950223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
2951223132Stuexen				break;
2952223132Stuexen			case SCTP_PEER_ADDR_CHANGE:
2953223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
2954223132Stuexen				break;
2955223132Stuexen			case SCTP_REMOTE_ERROR:
2956223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPEERERR;
2957223132Stuexen				break;
2958223132Stuexen			case SCTP_SEND_FAILED:
2959223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
2960223132Stuexen				break;
2961223132Stuexen			case SCTP_SHUTDOWN_EVENT:
2962223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
2963223132Stuexen				break;
2964223132Stuexen			case SCTP_ADAPTATION_INDICATION:
2965223132Stuexen				event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
2966223132Stuexen				break;
2967223132Stuexen			case SCTP_PARTIAL_DELIVERY_EVENT:
2968223132Stuexen				event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
2969223132Stuexen				break;
2970223132Stuexen			case SCTP_AUTHENTICATION_EVENT:
2971223132Stuexen				event_type = SCTP_PCB_FLAGS_AUTHEVNT;
2972223132Stuexen				break;
2973223132Stuexen			case SCTP_STREAM_RESET_EVENT:
2974223132Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
2975223132Stuexen				break;
2976223132Stuexen			case SCTP_SENDER_DRY_EVENT:
2977223132Stuexen				event_type = SCTP_PCB_FLAGS_DRYEVNT;
2978223132Stuexen				break;
2979223132Stuexen			case SCTP_NOTIFICATIONS_STOPPED_EVENT:
2980223132Stuexen				event_type = 0;
2981223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
2982223132Stuexen				error = ENOTSUP;
2983223132Stuexen				break;
2984235009Stuexen			case SCTP_ASSOC_RESET_EVENT:
2985235009Stuexen				event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
2986235009Stuexen				break;
2987235009Stuexen			case SCTP_STREAM_CHANGE_EVENT:
2988235009Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
2989235009Stuexen				break;
2990235075Stuexen			case SCTP_SEND_FAILED_EVENT:
2991235075Stuexen				event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
2992235075Stuexen				break;
2993223132Stuexen			default:
2994223132Stuexen				event_type = 0;
2995223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2996223132Stuexen				error = EINVAL;
2997223132Stuexen				break;
2998223132Stuexen			}
2999223132Stuexen			if (event_type > 0) {
3000223132Stuexen				if (stcb) {
3001223132Stuexen					event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
3002223132Stuexen					SCTP_TCB_UNLOCK(stcb);
3003223132Stuexen				} else {
3004224918Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3005224918Stuexen					    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3006224918Stuexen					    (event->se_assoc_id == SCTP_FUTURE_ASSOC)) {
3007223132Stuexen						SCTP_INP_RLOCK(inp);
3008223132Stuexen						event->se_on = sctp_is_feature_on(inp, event_type);
3009223132Stuexen						SCTP_INP_RUNLOCK(inp);
3010223132Stuexen					} else {
3011223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3012223132Stuexen						error = EINVAL;
3013223132Stuexen					}
3014223132Stuexen				}
3015223132Stuexen			}
3016223132Stuexen			if (error == 0) {
3017223132Stuexen				*optsize = sizeof(struct sctp_event);
3018223132Stuexen			}
3019223132Stuexen			break;
3020223132Stuexen		}
3021223132Stuexen	case SCTP_RECVRCVINFO:
3022223132Stuexen		{
3023223132Stuexen			int onoff;
3024223132Stuexen
3025223132Stuexen			if (*optsize < sizeof(int)) {
3026223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3027223132Stuexen				error = EINVAL;
3028223132Stuexen			} else {
3029230104Stuexen				SCTP_INP_RLOCK(inp);
3030223132Stuexen				onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
3031223132Stuexen				SCTP_INP_RUNLOCK(inp);
3032223132Stuexen			}
3033223132Stuexen			if (error == 0) {
3034223132Stuexen				/* return the option value */
3035223132Stuexen				*(int *)optval = onoff;
3036223132Stuexen				*optsize = sizeof(int);
3037223132Stuexen			}
3038223132Stuexen			break;
3039223132Stuexen		}
3040223132Stuexen	case SCTP_RECVNXTINFO:
3041223132Stuexen		{
3042223132Stuexen			int onoff;
3043223132Stuexen
3044223132Stuexen			if (*optsize < sizeof(int)) {
3045223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3046223132Stuexen				error = EINVAL;
3047223132Stuexen			} else {
3048230104Stuexen				SCTP_INP_RLOCK(inp);
3049223132Stuexen				onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
3050223132Stuexen				SCTP_INP_RUNLOCK(inp);
3051223132Stuexen			}
3052223132Stuexen			if (error == 0) {
3053223132Stuexen				/* return the option value */
3054223132Stuexen				*(int *)optval = onoff;
3055223132Stuexen				*optsize = sizeof(int);
3056223132Stuexen			}
3057223132Stuexen			break;
3058223132Stuexen		}
3059223132Stuexen	case SCTP_DEFAULT_SNDINFO:
3060223132Stuexen		{
3061223132Stuexen			struct sctp_sndinfo *info;
3062223132Stuexen
3063223132Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize);
3064223132Stuexen			SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
3065223132Stuexen
3066223132Stuexen			if (stcb) {
3067223132Stuexen				info->snd_sid = stcb->asoc.def_send.sinfo_stream;
3068223132Stuexen				info->snd_flags = stcb->asoc.def_send.sinfo_flags;
3069223162Stuexen				info->snd_flags &= 0xfff0;
3070223132Stuexen				info->snd_ppid = stcb->asoc.def_send.sinfo_ppid;
3071223132Stuexen				info->snd_context = stcb->asoc.def_send.sinfo_context;
3072223132Stuexen				SCTP_TCB_UNLOCK(stcb);
3073223132Stuexen			} else {
3074224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3075224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3076224918Stuexen				    (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) {
3077223132Stuexen					SCTP_INP_RLOCK(inp);
3078223132Stuexen					info->snd_sid = inp->def_send.sinfo_stream;
3079223132Stuexen					info->snd_flags = inp->def_send.sinfo_flags;
3080223162Stuexen					info->snd_flags &= 0xfff0;
3081223132Stuexen					info->snd_ppid = inp->def_send.sinfo_ppid;
3082223132Stuexen					info->snd_context = inp->def_send.sinfo_context;
3083223132Stuexen					SCTP_INP_RUNLOCK(inp);
3084223132Stuexen				} else {
3085223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3086223132Stuexen					error = EINVAL;
3087223132Stuexen				}
3088223132Stuexen			}
3089223132Stuexen			if (error == 0) {
3090223132Stuexen				*optsize = sizeof(struct sctp_sndinfo);
3091223132Stuexen			}
3092223132Stuexen			break;
3093223132Stuexen		}
3094223162Stuexen	case SCTP_DEFAULT_PRINFO:
3095223162Stuexen		{
3096223162Stuexen			struct sctp_default_prinfo *info;
3097223162Stuexen
3098223162Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize);
3099223162Stuexen			SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
3100223162Stuexen
3101223162Stuexen			if (stcb) {
3102223162Stuexen				info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
3103223162Stuexen				info->pr_value = stcb->asoc.def_send.sinfo_timetolive;
3104223162Stuexen				SCTP_TCB_UNLOCK(stcb);
3105223162Stuexen			} else {
3106224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3107224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3108224918Stuexen				    (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) {
3109223162Stuexen					SCTP_INP_RLOCK(inp);
3110223162Stuexen					info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
3111223162Stuexen					info->pr_value = inp->def_send.sinfo_timetolive;
3112223162Stuexen					SCTP_INP_RUNLOCK(inp);
3113223162Stuexen				} else {
3114223162Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3115223162Stuexen					error = EINVAL;
3116223162Stuexen				}
3117223162Stuexen			}
3118223162Stuexen			if (error == 0) {
3119223162Stuexen				*optsize = sizeof(struct sctp_default_prinfo);
3120223162Stuexen			}
3121223162Stuexen			break;
3122223162Stuexen		}
3123224641Stuexen	case SCTP_PEER_ADDR_THLDS:
3124224641Stuexen		{
3125224641Stuexen			struct sctp_paddrthlds *thlds;
3126224641Stuexen			struct sctp_nets *net;
3127224641Stuexen
3128224641Stuexen			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
3129224641Stuexen			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
3130224641Stuexen
3131224641Stuexen			net = NULL;
3132224641Stuexen			if (stcb) {
3133224641Stuexen				net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address);
3134224641Stuexen			} else {
3135224641Stuexen				/*
3136224641Stuexen				 * We increment here since
3137224641Stuexen				 * sctp_findassociation_ep_addr() wil do a
3138224641Stuexen				 * decrement if it finds the stcb as long as
3139224641Stuexen				 * the locked tcb (last argument) is NOT a
3140224641Stuexen				 * TCB.. aka NULL.
3141224641Stuexen				 */
3142224641Stuexen				SCTP_INP_INCR_REF(inp);
3143224641Stuexen				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL);
3144224641Stuexen				if (stcb == NULL) {
3145224641Stuexen					SCTP_INP_DECR_REF(inp);
3146224641Stuexen				}
3147224641Stuexen			}
3148224641Stuexen			if (stcb && (net == NULL)) {
3149224641Stuexen				struct sockaddr *sa;
3150224641Stuexen
3151224641Stuexen				sa = (struct sockaddr *)&thlds->spt_address;
3152224641Stuexen#ifdef INET
3153224641Stuexen				if (sa->sa_family == AF_INET) {
3154224641Stuexen					struct sockaddr_in *sin;
3155224641Stuexen
3156224641Stuexen					sin = (struct sockaddr_in *)sa;
3157224641Stuexen					if (sin->sin_addr.s_addr) {
3158224641Stuexen						error = EINVAL;
3159224641Stuexen						SCTP_TCB_UNLOCK(stcb);
3160224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3161224641Stuexen						break;
3162224641Stuexen					}
3163224641Stuexen				} else
3164224641Stuexen#endif
3165224641Stuexen#ifdef INET6
3166224641Stuexen				if (sa->sa_family == AF_INET6) {
3167224641Stuexen					struct sockaddr_in6 *sin6;
3168224641Stuexen
3169224641Stuexen					sin6 = (struct sockaddr_in6 *)sa;
3170224641Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3171224641Stuexen						error = EINVAL;
3172224641Stuexen						SCTP_TCB_UNLOCK(stcb);
3173224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3174224641Stuexen						break;
3175224641Stuexen					}
3176224641Stuexen				} else
3177224641Stuexen#endif
3178224641Stuexen				{
3179224641Stuexen					error = EAFNOSUPPORT;
3180224641Stuexen					SCTP_TCB_UNLOCK(stcb);
3181224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3182224641Stuexen					break;
3183224641Stuexen				}
3184224641Stuexen			}
3185224641Stuexen			if (stcb) {
3186224641Stuexen				if (net) {
3187224641Stuexen					thlds->spt_pathmaxrxt = net->failure_threshold;
3188224641Stuexen					thlds->spt_pathpfthld = net->pf_threshold;
3189224641Stuexen				} else {
3190224641Stuexen					thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
3191224641Stuexen					thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
3192224641Stuexen				}
3193224641Stuexen				thlds->spt_assoc_id = sctp_get_associd(stcb);
3194224641Stuexen				SCTP_TCB_UNLOCK(stcb);
3195224641Stuexen			} else {
3196224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3197224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3198224918Stuexen				    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
3199224641Stuexen					/* Use endpoint defaults */
3200224641Stuexen					SCTP_INP_RLOCK(inp);
3201224641Stuexen					thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
3202224641Stuexen					thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
3203224641Stuexen					SCTP_INP_RUNLOCK(inp);
3204224641Stuexen				} else {
3205224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3206224641Stuexen					error = EINVAL;
3207224641Stuexen				}
3208224641Stuexen			}
3209224641Stuexen			if (error == 0) {
3210224641Stuexen				*optsize = sizeof(struct sctp_paddrthlds);
3211224641Stuexen			}
3212224641Stuexen			break;
3213224641Stuexen		}
3214227755Stuexen	case SCTP_REMOTE_UDP_ENCAPS_PORT:
3215227755Stuexen		{
3216227755Stuexen			struct sctp_udpencaps *encaps;
3217227755Stuexen			struct sctp_nets *net;
3218227755Stuexen
3219227755Stuexen			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize);
3220227755Stuexen			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
3221227755Stuexen
3222227755Stuexen			if (stcb) {
3223227755Stuexen				net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address);
3224227755Stuexen			} else {
3225227755Stuexen				/*
3226227755Stuexen				 * We increment here since
3227227755Stuexen				 * sctp_findassociation_ep_addr() wil do a
3228227755Stuexen				 * decrement if it finds the stcb as long as
3229227755Stuexen				 * the locked tcb (last argument) is NOT a
3230227755Stuexen				 * TCB.. aka NULL.
3231227755Stuexen				 */
3232227755Stuexen				net = NULL;
3233227755Stuexen				SCTP_INP_INCR_REF(inp);
3234227755Stuexen				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL);
3235227755Stuexen				if (stcb == NULL) {
3236227755Stuexen					SCTP_INP_DECR_REF(inp);
3237227755Stuexen				}
3238227755Stuexen			}
3239227755Stuexen			if (stcb && (net == NULL)) {
3240227755Stuexen				struct sockaddr *sa;
3241227755Stuexen
3242227755Stuexen				sa = (struct sockaddr *)&encaps->sue_address;
3243227755Stuexen#ifdef INET
3244227755Stuexen				if (sa->sa_family == AF_INET) {
3245227755Stuexen					struct sockaddr_in *sin;
3246227755Stuexen
3247227755Stuexen					sin = (struct sockaddr_in *)sa;
3248227755Stuexen					if (sin->sin_addr.s_addr) {
3249227755Stuexen						error = EINVAL;
3250227755Stuexen						SCTP_TCB_UNLOCK(stcb);
3251227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3252227755Stuexen						break;
3253227755Stuexen					}
3254227755Stuexen				} else
3255227755Stuexen#endif
3256227755Stuexen#ifdef INET6
3257227755Stuexen				if (sa->sa_family == AF_INET6) {
3258227755Stuexen					struct sockaddr_in6 *sin6;
3259227755Stuexen
3260227755Stuexen					sin6 = (struct sockaddr_in6 *)sa;
3261227755Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3262227755Stuexen						error = EINVAL;
3263227755Stuexen						SCTP_TCB_UNLOCK(stcb);
3264227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3265227755Stuexen						break;
3266227755Stuexen					}
3267227755Stuexen				} else
3268227755Stuexen#endif
3269227755Stuexen				{
3270227755Stuexen					error = EAFNOSUPPORT;
3271227755Stuexen					SCTP_TCB_UNLOCK(stcb);
3272227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3273227755Stuexen					break;
3274227755Stuexen				}
3275227755Stuexen			}
3276227755Stuexen			if (stcb) {
3277227755Stuexen				if (net) {
3278227755Stuexen					encaps->sue_port = net->port;
3279227755Stuexen				} else {
3280227755Stuexen					encaps->sue_port = stcb->asoc.port;
3281227755Stuexen				}
3282227755Stuexen				SCTP_TCB_UNLOCK(stcb);
3283227755Stuexen			} else {
3284227755Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3285227755Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3286227755Stuexen				    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
3287227755Stuexen					SCTP_INP_RLOCK(inp);
3288227755Stuexen					encaps->sue_port = inp->sctp_ep.port;
3289227755Stuexen					SCTP_INP_RUNLOCK(inp);
3290227755Stuexen				} else {
3291227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3292227755Stuexen					error = EINVAL;
3293227755Stuexen				}
3294227755Stuexen			}
3295227755Stuexen			if (error == 0) {
3296227755Stuexen				*optsize = sizeof(struct sctp_paddrparams);
3297227755Stuexen			}
3298227755Stuexen			break;
3299227755Stuexen		}
3300235021Stuexen	case SCTP_ENABLE_STREAM_RESET:
3301235021Stuexen		{
3302235021Stuexen			struct sctp_assoc_value *av;
3303235021Stuexen
3304235021Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3305235021Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3306235021Stuexen
3307235021Stuexen			if (stcb) {
3308235021Stuexen				av->assoc_value = (uint32_t) stcb->asoc.local_strreset_support;
3309235021Stuexen				SCTP_TCB_UNLOCK(stcb);
3310235021Stuexen			} else {
3311235021Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3312235021Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3313235021Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3314235021Stuexen					SCTP_INP_RLOCK(inp);
3315235021Stuexen					av->assoc_value = (uint32_t) inp->local_strreset_support;
3316235021Stuexen					SCTP_INP_RUNLOCK(inp);
3317235021Stuexen				} else {
3318235021Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3319235021Stuexen					error = EINVAL;
3320235021Stuexen				}
3321235021Stuexen			}
3322235021Stuexen			if (error == 0) {
3323235021Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3324235021Stuexen			}
3325235021Stuexen			break;
3326235021Stuexen		}
3327163953Srrs	default:
3328171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3329163953Srrs		error = ENOPROTOOPT;
3330163953Srrs		break;
3331163953Srrs	}			/* end switch (sopt->sopt_name) */
3332223132Stuexen	if (error) {
3333223132Stuexen		*optsize = 0;
3334223132Stuexen	}
3335163953Srrs	return (error);
3336163953Srrs}
3337163953Srrs
3338163953Srrsstatic int
3339166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
3340166675Srrs    void *p)
3341163953Srrs{
3342166675Srrs	int error, set_opt;
3343166675Srrs	uint32_t *mopt;
3344163953Srrs	struct sctp_tcb *stcb = NULL;
3345171943Srrs	struct sctp_inpcb *inp = NULL;
3346167598Srrs	uint32_t vrf_id;
3347163953Srrs
3348166675Srrs	if (optval == NULL) {
3349169420Srrs		SCTP_PRINTF("optval is NULL\n");
3350171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3351163953Srrs		return (EINVAL);
3352163953Srrs	}
3353163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3354233005Stuexen	if (inp == NULL) {
3355169420Srrs		SCTP_PRINTF("inp is NULL?\n");
3356171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3357228907Stuexen		return (EINVAL);
3358167598Srrs	}
3359168299Srrs	vrf_id = inp->def_vrf_id;
3360163953Srrs
3361163953Srrs	error = 0;
3362166675Srrs	switch (optname) {
3363163953Srrs	case SCTP_NODELAY:
3364163953Srrs	case SCTP_AUTOCLOSE:
3365163953Srrs	case SCTP_AUTO_ASCONF:
3366163953Srrs	case SCTP_EXPLICIT_EOR:
3367163953Srrs	case SCTP_DISABLE_FRAGMENTS:
3368163953Srrs	case SCTP_USE_EXT_RCVINFO:
3369163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
3370163953Srrs		/* copy in the option value */
3371166675Srrs		SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
3372163953Srrs		set_opt = 0;
3373163953Srrs		if (error)
3374163953Srrs			break;
3375166675Srrs		switch (optname) {
3376163953Srrs		case SCTP_DISABLE_FRAGMENTS:
3377163953Srrs			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
3378163953Srrs			break;
3379163953Srrs		case SCTP_AUTO_ASCONF:
3380171943Srrs			/*
3381171943Srrs			 * NOTE: we don't really support this flag
3382171943Srrs			 */
3383171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3384171943Srrs				/* only valid for bound all sockets */
3385224641Stuexen				if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
3386224641Stuexen				    (*mopt != 0)) {
3387224641Stuexen					/* forbidden by admin */
3388224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
3389224641Stuexen					return (EPERM);
3390224641Stuexen				}
3391171943Srrs				set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
3392171943Srrs			} else {
3393171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3394171943Srrs				return (EINVAL);
3395171943Srrs			}
3396163953Srrs			break;
3397163953Srrs		case SCTP_EXPLICIT_EOR:
3398163953Srrs			set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
3399163953Srrs			break;
3400163953Srrs		case SCTP_USE_EXT_RCVINFO:
3401163953Srrs			set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
3402163953Srrs			break;
3403163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
3404163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3405163953Srrs				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
3406163953Srrs			} else {
3407171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3408163953Srrs				return (EINVAL);
3409163953Srrs			}
3410163953Srrs			break;
3411163953Srrs		case SCTP_NODELAY:
3412163953Srrs			set_opt = SCTP_PCB_FLAGS_NODELAY;
3413163953Srrs			break;
3414163953Srrs		case SCTP_AUTOCLOSE:
3415170056Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3416170056Srrs			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3417171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3418170056Srrs				return (EINVAL);
3419170056Srrs			}
3420163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
3421163953Srrs			/*
3422163953Srrs			 * The value is in ticks. Note this does not effect
3423163953Srrs			 * old associations, only new ones.
3424163953Srrs			 */
3425163953Srrs			inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
3426163953Srrs			break;
3427163953Srrs		}
3428163953Srrs		SCTP_INP_WLOCK(inp);
3429163953Srrs		if (*mopt != 0) {
3430163953Srrs			sctp_feature_on(inp, set_opt);
3431163953Srrs		} else {
3432163953Srrs			sctp_feature_off(inp, set_opt);
3433163953Srrs		}
3434163953Srrs		SCTP_INP_WUNLOCK(inp);
3435163953Srrs		break;
3436181054Srrs	case SCTP_REUSE_PORT:
3437181054Srrs		{
3438181054Srrs			SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
3439181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
3440181054Srrs				/* Can't set it after we are bound */
3441181054Srrs				error = EINVAL;
3442181054Srrs				break;
3443181054Srrs			}
3444181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
3445181054Srrs				/* Can't do this for a 1-m socket */
3446181054Srrs				error = EINVAL;
3447181054Srrs				break;
3448181054Srrs			}
3449181054Srrs			if (optval)
3450181054Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
3451181054Srrs			else
3452181054Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
3453223132Stuexen			break;
3454181054Srrs		}
3455163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
3456163953Srrs		{
3457166675Srrs			uint32_t *value;
3458166675Srrs
3459166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
3460167736Srrs			if (*value > SCTP_SB_LIMIT_RCV(so)) {
3461171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3462167736Srrs				error = EINVAL;
3463167736Srrs				break;
3464167736Srrs			}
3465166675Srrs			inp->partial_delivery_point = *value;
3466223132Stuexen			break;
3467163953Srrs		}
3468163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
3469163953Srrs		/* not yet until we re-write sctp_recvmsg() */
3470163953Srrs		{
3471168943Srrs			uint32_t *level;
3472163953Srrs
3473168943Srrs			SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
3474168943Srrs			if (*level == SCTP_FRAG_LEVEL_2) {
3475163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3476168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3477168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_1) {
3478168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3479168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3480168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_0) {
3481170056Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3482168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3483168943Srrs
3484163953Srrs			} else {
3485171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3486168943Srrs				error = EINVAL;
3487163953Srrs			}
3488223132Stuexen			break;
3489163953Srrs		}
3490163953Srrs	case SCTP_CMT_ON_OFF:
3491211944Stuexen		if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
3492163953Srrs			struct sctp_assoc_value *av;
3493163953Srrs
3494166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3495223132Stuexen			if (av->assoc_value > SCTP_CMT_MAX) {
3496223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3497223132Stuexen				error = EINVAL;
3498223132Stuexen				break;
3499223132Stuexen			}
3500211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3501211944Stuexen			if (stcb) {
3502223132Stuexen				stcb->asoc.sctp_cmt_on_off = av->assoc_value;
3503211944Stuexen				SCTP_TCB_UNLOCK(stcb);
3504166675Srrs			} else {
3505224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3506224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3507224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3508223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3509221460Stuexen					SCTP_INP_WLOCK(inp);
3510221460Stuexen					inp->sctp_cmt_on_off = av->assoc_value;
3511221460Stuexen					SCTP_INP_WUNLOCK(inp);
3512216669Stuexen				}
3513223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3514223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3515223132Stuexen					SCTP_INP_RLOCK(inp);
3516223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3517223132Stuexen						SCTP_TCB_LOCK(stcb);
3518223132Stuexen						stcb->asoc.sctp_cmt_on_off = av->assoc_value;
3519223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3520223132Stuexen					}
3521224918Stuexen					SCTP_INP_RUNLOCK(inp);
3522223132Stuexen				}
3523163953Srrs			}
3524211944Stuexen		} else {
3525211944Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3526211944Stuexen			error = ENOPROTOOPT;
3527163953Srrs		}
3528163953Srrs		break;
3529171440Srrs	case SCTP_PLUGGABLE_CC:
3530171440Srrs		{
3531171440Srrs			struct sctp_assoc_value *av;
3532219057Srrs			struct sctp_nets *net;
3533171440Srrs
3534171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3535223132Stuexen			if ((av->assoc_value != SCTP_CC_RFC2581) &&
3536223132Stuexen			    (av->assoc_value != SCTP_CC_HSTCP) &&
3537223132Stuexen			    (av->assoc_value != SCTP_CC_HTCP) &&
3538223132Stuexen			    (av->assoc_value != SCTP_CC_RTCC)) {
3539223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3540223132Stuexen				error = EINVAL;
3541223132Stuexen				break;
3542223132Stuexen			}
3543171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3544171440Srrs			if (stcb) {
3545223132Stuexen				stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3546223132Stuexen				stcb->asoc.congestion_control_module = av->assoc_value;
3547223132Stuexen				if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3548223132Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3549223132Stuexen						stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
3550219057Srrs					}
3551171440Srrs				}
3552217611Stuexen				SCTP_TCB_UNLOCK(stcb);
3553171440Srrs			} else {
3554224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3555224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3556224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3557223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3558217611Stuexen					SCTP_INP_WLOCK(inp);
3559171440Srrs					inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
3560217611Stuexen					SCTP_INP_WUNLOCK(inp);
3561217760Stuexen				}
3562223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3563223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3564223132Stuexen					SCTP_INP_RLOCK(inp);
3565223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3566223132Stuexen						SCTP_TCB_LOCK(stcb);
3567223132Stuexen						stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3568223132Stuexen						stcb->asoc.congestion_control_module = av->assoc_value;
3569223132Stuexen						if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3570223132Stuexen							TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3571223132Stuexen								stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
3572223132Stuexen							}
3573223132Stuexen						}
3574223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3575223132Stuexen					}
3576223132Stuexen					SCTP_INP_RUNLOCK(inp);
3577223132Stuexen				}
3578171440Srrs			}
3579223132Stuexen			break;
3580171440Srrs		}
3581219057Srrs	case SCTP_CC_OPTION:
3582219057Srrs		{
3583219057Srrs			struct sctp_cc_option *cc_opt;
3584219057Srrs
3585219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
3586219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
3587219057Srrs			if (stcb == NULL) {
3588223132Stuexen				if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) {
3589223132Stuexen					SCTP_INP_RLOCK(inp);
3590223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3591223132Stuexen						SCTP_TCB_LOCK(stcb);
3592223132Stuexen						if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) {
3593223132Stuexen							(*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt);
3594223132Stuexen						}
3595223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3596223132Stuexen					}
3597223132Stuexen					SCTP_INP_RUNLOCK(inp);
3598223132Stuexen				} else {
3599223132Stuexen					error = EINVAL;
3600223132Stuexen				}
3601219057Srrs			} else {
3602219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
3603219057Srrs					error = ENOTSUP;
3604219057Srrs				} else {
3605219057Srrs					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1,
3606219057Srrs					    cc_opt);
3607219057Srrs				}
3608219057Srrs				SCTP_TCB_UNLOCK(stcb);
3609219057Srrs			}
3610223132Stuexen			break;
3611219057Srrs		}
3612217760Stuexen	case SCTP_PLUGGABLE_SS:
3613217760Stuexen		{
3614217760Stuexen			struct sctp_assoc_value *av;
3615217760Stuexen
3616217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3617223132Stuexen			if ((av->assoc_value != SCTP_SS_DEFAULT) &&
3618223132Stuexen			    (av->assoc_value != SCTP_SS_ROUND_ROBIN) &&
3619223132Stuexen			    (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) &&
3620223132Stuexen			    (av->assoc_value != SCTP_SS_PRIORITY) &&
3621223132Stuexen			    (av->assoc_value != SCTP_SS_FAIR_BANDWITH) &&
3622223132Stuexen			    (av->assoc_value != SCTP_SS_FIRST_COME)) {
3623223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3624223132Stuexen				error = EINVAL;
3625223132Stuexen				break;
3626223132Stuexen			}
3627217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3628217760Stuexen			if (stcb) {
3629223132Stuexen				stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
3630223132Stuexen				stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
3631223132Stuexen				stcb->asoc.stream_scheduling_module = av->assoc_value;
3632223132Stuexen				stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
3633217760Stuexen				SCTP_TCB_UNLOCK(stcb);
3634217760Stuexen			} else {
3635224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3636224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3637224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3638223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3639217760Stuexen					SCTP_INP_WLOCK(inp);
3640217760Stuexen					inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
3641217760Stuexen					SCTP_INP_WUNLOCK(inp);
3642217760Stuexen				}
3643223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3644223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3645223132Stuexen					SCTP_INP_RLOCK(inp);
3646223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3647223132Stuexen						SCTP_TCB_LOCK(stcb);
3648223132Stuexen						stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
3649223132Stuexen						stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
3650223132Stuexen						stcb->asoc.stream_scheduling_module = av->assoc_value;
3651223132Stuexen						stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
3652223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3653223132Stuexen					}
3654223132Stuexen					SCTP_INP_RUNLOCK(inp);
3655223132Stuexen				}
3656217760Stuexen			}
3657223132Stuexen			break;
3658217760Stuexen		}
3659217760Stuexen	case SCTP_SS_VALUE:
3660217760Stuexen		{
3661217760Stuexen			struct sctp_stream_value *av;
3662217760Stuexen
3663217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
3664217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3665217760Stuexen			if (stcb) {
3666217760Stuexen				if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
3667217760Stuexen				    av->stream_value) < 0) {
3668217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3669217760Stuexen					error = EINVAL;
3670217760Stuexen				}
3671217760Stuexen				SCTP_TCB_UNLOCK(stcb);
3672217760Stuexen			} else {
3673223132Stuexen				if (av->assoc_id == SCTP_CURRENT_ASSOC) {
3674223132Stuexen					SCTP_INP_RLOCK(inp);
3675223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3676223132Stuexen						SCTP_TCB_LOCK(stcb);
3677223132Stuexen						stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
3678223132Stuexen						    &stcb->asoc,
3679223132Stuexen						    &stcb->asoc.strmout[av->stream_id],
3680223132Stuexen						    av->stream_value);
3681223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3682223132Stuexen					}
3683223132Stuexen					SCTP_INP_RUNLOCK(inp);
3684223132Stuexen
3685223132Stuexen				} else {
3686223132Stuexen					/*
3687223132Stuexen					 * Can't set stream value without
3688223132Stuexen					 * association
3689223132Stuexen					 */
3690223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3691223132Stuexen					error = EINVAL;
3692223132Stuexen				}
3693217760Stuexen			}
3694223132Stuexen			break;
3695217760Stuexen		}
3696163953Srrs	case SCTP_CLR_STAT_LOG:
3697171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
3698163953Srrs		error = EOPNOTSUPP;
3699163953Srrs		break;
3700163953Srrs	case SCTP_CONTEXT:
3701163953Srrs		{
3702163953Srrs			struct sctp_assoc_value *av;
3703163953Srrs
3704166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3705166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3706166675Srrs
3707166675Srrs			if (stcb) {
3708166675Srrs				stcb->asoc.context = av->assoc_value;
3709166675Srrs				SCTP_TCB_UNLOCK(stcb);
3710163953Srrs			} else {
3711224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3712224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3713224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3714223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3715223132Stuexen					SCTP_INP_WLOCK(inp);
3716223132Stuexen					inp->sctp_context = av->assoc_value;
3717223132Stuexen					SCTP_INP_WUNLOCK(inp);
3718223132Stuexen				}
3719223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3720223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3721223132Stuexen					SCTP_INP_RLOCK(inp);
3722223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3723223132Stuexen						SCTP_TCB_LOCK(stcb);
3724223132Stuexen						stcb->asoc.context = av->assoc_value;
3725223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3726223132Stuexen					}
3727223132Stuexen					SCTP_INP_RUNLOCK(inp);
3728223132Stuexen				}
3729163953Srrs			}
3730223132Stuexen			break;
3731163953Srrs		}
3732167598Srrs	case SCTP_VRF_ID:
3733167598Srrs		{
3734170056Srrs			uint32_t *default_vrfid;
3735167598Srrs
3736170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
3737170056Srrs			if (*default_vrfid > SCTP_MAX_VRF_ID) {
3738171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3739167598Srrs				error = EINVAL;
3740167598Srrs				break;
3741167598Srrs			}
3742170056Srrs			inp->def_vrf_id = *default_vrfid;
3743167598Srrs			break;
3744167598Srrs		}
3745167598Srrs	case SCTP_DEL_VRF_ID:
3746167598Srrs		{
3747171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
3748167598Srrs			error = EOPNOTSUPP;
3749167598Srrs			break;
3750167598Srrs		}
3751167598Srrs	case SCTP_ADD_VRF_ID:
3752167598Srrs		{
3753171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
3754167598Srrs			error = EOPNOTSUPP;
3755167598Srrs			break;
3756167598Srrs		}
3757170056Srrs	case SCTP_DELAYED_SACK:
3758163953Srrs		{
3759170056Srrs			struct sctp_sack_info *sack;
3760163953Srrs
3761170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
3762170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
3763171477Srrs			if (sack->sack_delay) {
3764171477Srrs				if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
3765171477Srrs					sack->sack_delay = SCTP_MAX_SACK_DELAY;
3766223132Stuexen				if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
3767223132Stuexen					sack->sack_delay = TICKS_TO_MSEC(1);
3768223132Stuexen				}
3769171477Srrs			}
3770166675Srrs			if (stcb) {
3771170056Srrs				if (sack->sack_delay) {
3772170056Srrs					stcb->asoc.delayed_ack = sack->sack_delay;
3773170056Srrs				}
3774170056Srrs				if (sack->sack_freq) {
3775170056Srrs					stcb->asoc.sack_freq = sack->sack_freq;
3776170056Srrs				}
3777166675Srrs				SCTP_TCB_UNLOCK(stcb);
3778166675Srrs			} else {
3779224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3780224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3781224918Stuexen				    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
3782223132Stuexen				    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
3783223132Stuexen					SCTP_INP_WLOCK(inp);
3784223132Stuexen					if (sack->sack_delay) {
3785223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
3786170056Srrs					}
3787223132Stuexen					if (sack->sack_freq) {
3788223132Stuexen						inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
3789223132Stuexen					}
3790223132Stuexen					SCTP_INP_WUNLOCK(inp);
3791170056Srrs				}
3792223132Stuexen				if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
3793223132Stuexen				    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
3794223132Stuexen					SCTP_INP_RLOCK(inp);
3795223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3796223132Stuexen						SCTP_TCB_LOCK(stcb);
3797223132Stuexen						if (sack->sack_delay) {
3798223132Stuexen							stcb->asoc.delayed_ack = sack->sack_delay;
3799223132Stuexen						}
3800223132Stuexen						if (sack->sack_freq) {
3801223132Stuexen							stcb->asoc.sack_freq = sack->sack_freq;
3802223132Stuexen						}
3803223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3804223132Stuexen					}
3805223132Stuexen					SCTP_INP_RUNLOCK(inp);
3806170056Srrs				}
3807163953Srrs			}
3808166675Srrs			break;
3809163953Srrs		}
3810163953Srrs	case SCTP_AUTH_CHUNK:
3811163953Srrs		{
3812163953Srrs			struct sctp_authchunk *sauth;
3813163953Srrs
3814166675Srrs			SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
3815166675Srrs
3816166675Srrs			SCTP_INP_WLOCK(inp);
3817171943Srrs			if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
3818171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3819163953Srrs				error = EINVAL;
3820171943Srrs			}
3821166675Srrs			SCTP_INP_WUNLOCK(inp);
3822163953Srrs			break;
3823163953Srrs		}
3824163953Srrs	case SCTP_AUTH_KEY:
3825163953Srrs		{
3826163953Srrs			struct sctp_authkey *sca;
3827163953Srrs			struct sctp_keyhead *shared_keys;
3828163953Srrs			sctp_sharedkey_t *shared_key;
3829163953Srrs			sctp_key_t *key = NULL;
3830166675Srrs			size_t size;
3831163953Srrs
3832166675Srrs			SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
3833223697Stuexen			if (sca->sca_keylength == 0) {
3834223697Stuexen				size = optsize - sizeof(struct sctp_authkey);
3835223697Stuexen			} else {
3836223697Stuexen				if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
3837223697Stuexen					size = sca->sca_keylength;
3838223697Stuexen				} else {
3839223697Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3840223697Stuexen					error = EINVAL;
3841223697Stuexen					break;
3842223697Stuexen				}
3843223697Stuexen			}
3844169420Srrs			SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
3845166675Srrs
3846166675Srrs			if (stcb) {
3847163953Srrs				shared_keys = &stcb->asoc.shared_keys;
3848163953Srrs				/* clear the cached keys for this key id */
3849163953Srrs				sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
3850163953Srrs				/*
3851163953Srrs				 * create the new shared key and
3852163953Srrs				 * insert/replace it
3853163953Srrs				 */
3854163953Srrs				if (size > 0) {
3855163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
3856163953Srrs					if (key == NULL) {
3857171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3858163953Srrs						error = ENOMEM;
3859163953Srrs						SCTP_TCB_UNLOCK(stcb);
3860163953Srrs						break;
3861163953Srrs					}
3862163953Srrs				}
3863163953Srrs				shared_key = sctp_alloc_sharedkey();
3864163953Srrs				if (shared_key == NULL) {
3865163953Srrs					sctp_free_key(key);
3866171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3867163953Srrs					error = ENOMEM;
3868163953Srrs					SCTP_TCB_UNLOCK(stcb);
3869163953Srrs					break;
3870163953Srrs				}
3871163953Srrs				shared_key->key = key;
3872163953Srrs				shared_key->keyid = sca->sca_keynumber;
3873185694Srrs				error = sctp_insert_sharedkey(shared_keys, shared_key);
3874163953Srrs				SCTP_TCB_UNLOCK(stcb);
3875163953Srrs			} else {
3876224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3877224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3878224918Stuexen				    (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
3879223132Stuexen				    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
3880223132Stuexen					SCTP_INP_WLOCK(inp);
3881223132Stuexen					shared_keys = &inp->sctp_ep.shared_keys;
3882223132Stuexen					/*
3883223132Stuexen					 * clear the cached keys on all
3884223132Stuexen					 * assocs for this key id
3885223132Stuexen					 */
3886223132Stuexen					sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
3887223132Stuexen					/*
3888223132Stuexen					 * create the new shared key and
3889223132Stuexen					 * insert/replace it
3890223132Stuexen					 */
3891223132Stuexen					if (size > 0) {
3892223132Stuexen						key = sctp_set_key(sca->sca_key, (uint32_t) size);
3893223132Stuexen						if (key == NULL) {
3894223132Stuexen							SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3895223132Stuexen							error = ENOMEM;
3896223132Stuexen							SCTP_INP_WUNLOCK(inp);
3897223132Stuexen							break;
3898223132Stuexen						}
3899223132Stuexen					}
3900223132Stuexen					shared_key = sctp_alloc_sharedkey();
3901223132Stuexen					if (shared_key == NULL) {
3902223132Stuexen						sctp_free_key(key);
3903171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3904163953Srrs						error = ENOMEM;
3905163953Srrs						SCTP_INP_WUNLOCK(inp);
3906163953Srrs						break;
3907163953Srrs					}
3908223132Stuexen					shared_key->key = key;
3909223132Stuexen					shared_key->keyid = sca->sca_keynumber;
3910223132Stuexen					error = sctp_insert_sharedkey(shared_keys, shared_key);
3911163953Srrs					SCTP_INP_WUNLOCK(inp);
3912163953Srrs				}
3913223132Stuexen				if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
3914223132Stuexen				    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
3915223132Stuexen					SCTP_INP_RLOCK(inp);
3916223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3917223132Stuexen						SCTP_TCB_LOCK(stcb);
3918223132Stuexen						shared_keys = &stcb->asoc.shared_keys;
3919223132Stuexen						/*
3920223132Stuexen						 * clear the cached keys for
3921223132Stuexen						 * this key id
3922223132Stuexen						 */
3923223132Stuexen						sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
3924223132Stuexen						/*
3925223132Stuexen						 * create the new shared key
3926223132Stuexen						 * and insert/replace it
3927223132Stuexen						 */
3928223132Stuexen						if (size > 0) {
3929223132Stuexen							key = sctp_set_key(sca->sca_key, (uint32_t) size);
3930223132Stuexen							if (key == NULL) {
3931223132Stuexen								SCTP_TCB_UNLOCK(stcb);
3932223132Stuexen								continue;
3933223132Stuexen							}
3934223132Stuexen						}
3935223132Stuexen						shared_key = sctp_alloc_sharedkey();
3936223132Stuexen						if (shared_key == NULL) {
3937223132Stuexen							sctp_free_key(key);
3938223132Stuexen							SCTP_TCB_UNLOCK(stcb);
3939223132Stuexen							continue;
3940223132Stuexen						}
3941223132Stuexen						shared_key->key = key;
3942223132Stuexen						shared_key->keyid = sca->sca_keynumber;
3943223132Stuexen						error = sctp_insert_sharedkey(shared_keys, shared_key);
3944223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3945223132Stuexen					}
3946223132Stuexen					SCTP_INP_RUNLOCK(inp);
3947223132Stuexen				}
3948163953Srrs			}
3949163953Srrs			break;
3950163953Srrs		}
3951163953Srrs	case SCTP_HMAC_IDENT:
3952163953Srrs		{
3953163953Srrs			struct sctp_hmacalgo *shmac;
3954163953Srrs			sctp_hmaclist_t *hmaclist;
3955181054Srrs			uint16_t hmacid;
3956181054Srrs			uint32_t i;
3957181054Srrs			size_t found;
3958181054Srrs
3959166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
3960181054Srrs			if (optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) {
3961181054Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3962181054Srrs				error = EINVAL;
3963181054Srrs				break;
3964181054Srrs			}
3965181054Srrs			hmaclist = sctp_alloc_hmaclist(shmac->shmac_number_of_idents);
3966163953Srrs			if (hmaclist == NULL) {
3967171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3968163953Srrs				error = ENOMEM;
3969163953Srrs				break;
3970163953Srrs			}
3971181054Srrs			for (i = 0; i < shmac->shmac_number_of_idents; i++) {
3972163953Srrs				hmacid = shmac->shmac_idents[i];
3973181054Srrs				if (sctp_auth_add_hmacid(hmaclist, hmacid)) {
3974163953Srrs					 /* invalid HMACs were found */ ;
3975171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3976163953Srrs					error = EINVAL;
3977164085Srrs					sctp_free_hmaclist(hmaclist);
3978163953Srrs					goto sctp_set_hmac_done;
3979163953Srrs				}
3980163953Srrs			}
3981170056Srrs			found = 0;
3982170056Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
3983170056Srrs				if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
3984170056Srrs					/* already in list */
3985170056Srrs					found = 1;
3986170056Srrs				}
3987170056Srrs			}
3988170056Srrs			if (!found) {
3989170056Srrs				sctp_free_hmaclist(hmaclist);
3990171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3991170056Srrs				error = EINVAL;
3992170056Srrs				break;
3993170056Srrs			}
3994163953Srrs			/* set it on the endpoint */
3995163953Srrs			SCTP_INP_WLOCK(inp);
3996163953Srrs			if (inp->sctp_ep.local_hmacs)
3997163953Srrs				sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
3998163953Srrs			inp->sctp_ep.local_hmacs = hmaclist;
3999163953Srrs			SCTP_INP_WUNLOCK(inp);
4000163953Srrs	sctp_set_hmac_done:
4001163953Srrs			break;
4002163953Srrs		}
4003163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
4004163953Srrs		{
4005163953Srrs			struct sctp_authkeyid *scact;
4006163953Srrs
4007223132Stuexen			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
4008166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
4009166675Srrs
4010163953Srrs			/* set the active key on the right place */
4011166675Srrs			if (stcb) {
4012163953Srrs				/* set the active key on the assoc */
4013185694Srrs				if (sctp_auth_setactivekey(stcb,
4014185694Srrs				    scact->scact_keynumber)) {
4015185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
4016185694Srrs					    SCTP_FROM_SCTP_USRREQ,
4017185694Srrs					    EINVAL);
4018163953Srrs					error = EINVAL;
4019171943Srrs				}
4020163953Srrs				SCTP_TCB_UNLOCK(stcb);
4021163953Srrs			} else {
4022224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4023224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4024224918Stuexen				    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4025223132Stuexen				    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
4026223132Stuexen					SCTP_INP_WLOCK(inp);
4027223132Stuexen					if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
4028223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4029223132Stuexen						error = EINVAL;
4030223132Stuexen					}
4031223132Stuexen					SCTP_INP_WUNLOCK(inp);
4032171943Srrs				}
4033223132Stuexen				if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4034223132Stuexen				    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
4035223132Stuexen					SCTP_INP_RLOCK(inp);
4036223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4037223132Stuexen						SCTP_TCB_LOCK(stcb);
4038223132Stuexen						sctp_auth_setactivekey(stcb, scact->scact_keynumber);
4039223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4040223132Stuexen					}
4041223132Stuexen					SCTP_INP_RUNLOCK(inp);
4042223132Stuexen				}
4043163953Srrs			}
4044163953Srrs			break;
4045163953Srrs		}
4046163953Srrs	case SCTP_AUTH_DELETE_KEY:
4047163953Srrs		{
4048163953Srrs			struct sctp_authkeyid *scdel;
4049163953Srrs
4050223132Stuexen			SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
4051166675Srrs			SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
4052166675Srrs
4053163953Srrs			/* delete the key from the right place */
4054166675Srrs			if (stcb) {
4055223132Stuexen				if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
4056223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4057163953Srrs					error = EINVAL;
4058171943Srrs				}
4059163953Srrs				SCTP_TCB_UNLOCK(stcb);
4060163953Srrs			} else {
4061224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4062224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4063224918Stuexen				    (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4064223132Stuexen				    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
4065223132Stuexen					SCTP_INP_WLOCK(inp);
4066223132Stuexen					if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
4067223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4068223132Stuexen						error = EINVAL;
4069223132Stuexen					}
4070223132Stuexen					SCTP_INP_WUNLOCK(inp);
4071171943Srrs				}
4072223132Stuexen				if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4073223132Stuexen				    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
4074223132Stuexen					SCTP_INP_RLOCK(inp);
4075223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4076223132Stuexen						SCTP_TCB_LOCK(stcb);
4077223132Stuexen						sctp_delete_sharedkey(stcb, scdel->scact_keynumber);
4078223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4079223132Stuexen					}
4080223132Stuexen					SCTP_INP_RUNLOCK(inp);
4081223132Stuexen				}
4082163953Srrs			}
4083163953Srrs			break;
4084163953Srrs		}
4085185694Srrs	case SCTP_AUTH_DEACTIVATE_KEY:
4086185694Srrs		{
4087185694Srrs			struct sctp_authkeyid *keyid;
4088163953Srrs
4089223132Stuexen			SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize);
4090185694Srrs			SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
4091185694Srrs
4092185694Srrs			/* deactivate the key from the right place */
4093185694Srrs			if (stcb) {
4094223132Stuexen				if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) {
4095223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4096185694Srrs					error = EINVAL;
4097185694Srrs				}
4098185694Srrs				SCTP_TCB_UNLOCK(stcb);
4099185694Srrs			} else {
4100224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4101224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4102224918Stuexen				    (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4103223132Stuexen				    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
4104223132Stuexen					SCTP_INP_WLOCK(inp);
4105223132Stuexen					if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
4106223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4107223132Stuexen						error = EINVAL;
4108223132Stuexen					}
4109223132Stuexen					SCTP_INP_WUNLOCK(inp);
4110185694Srrs				}
4111223132Stuexen				if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4112223132Stuexen				    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
4113223132Stuexen					SCTP_INP_RLOCK(inp);
4114223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4115223132Stuexen						SCTP_TCB_LOCK(stcb);
4116223132Stuexen						sctp_deact_sharedkey(stcb, keyid->scact_keynumber);
4117223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4118223132Stuexen					}
4119223132Stuexen					SCTP_INP_RUNLOCK(inp);
4120223132Stuexen				}
4121185694Srrs			}
4122185694Srrs			break;
4123185694Srrs		}
4124233660Srrs	case SCTP_ENABLE_STREAM_RESET:
4125233660Srrs		{
4126233660Srrs			struct sctp_assoc_value *av;
4127185694Srrs
4128233660Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4129233660Srrs			if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
4130233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4131233660Srrs				error = EINVAL;
4132233660Srrs				break;
4133233660Srrs			}
4134233660Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4135233660Srrs			if (stcb) {
4136235021Stuexen				stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value;
4137233660Srrs				SCTP_TCB_UNLOCK(stcb);
4138233660Srrs			} else {
4139233660Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4140233660Srrs				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4141233660Srrs				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4142233660Srrs				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4143233660Srrs					SCTP_INP_WLOCK(inp);
4144235021Stuexen					inp->local_strreset_support = (uint8_t) av->assoc_value;
4145233660Srrs					SCTP_INP_WUNLOCK(inp);
4146233660Srrs				}
4147233660Srrs				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4148233660Srrs				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4149233660Srrs					SCTP_INP_RLOCK(inp);
4150233660Srrs					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4151233660Srrs						SCTP_TCB_LOCK(stcb);
4152235021Stuexen						stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value;
4153233660Srrs						SCTP_TCB_UNLOCK(stcb);
4154233660Srrs					}
4155233660Srrs					SCTP_INP_RUNLOCK(inp);
4156233660Srrs				}
4157233660Srrs			}
4158233660Srrs			break;
4159233660Srrs		}
4160163953Srrs	case SCTP_RESET_STREAMS:
4161163953Srrs		{
4162233660Srrs			struct sctp_reset_streams *strrst;
4163233660Srrs			int i, send_out = 0;
4164233660Srrs			int send_in = 0;
4165163953Srrs
4166233660Srrs			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
4167233660Srrs			SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
4168163953Srrs			if (stcb == NULL) {
4169171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4170163953Srrs				error = ENOENT;
4171163953Srrs				break;
4172163953Srrs			}
4173163953Srrs			if (stcb->asoc.peer_supports_strreset == 0) {
4174163953Srrs				/*
4175233660Srrs				 * Peer does not support the chunk type.
4176163953Srrs				 */
4177233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4178233660Srrs				error = EOPNOTSUPP;
4179163953Srrs				SCTP_TCB_UNLOCK(stcb);
4180163953Srrs				break;
4181163953Srrs			}
4182163953Srrs			if (stcb->asoc.stream_reset_outstanding) {
4183171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4184163953Srrs				error = EALREADY;
4185163953Srrs				SCTP_TCB_UNLOCK(stcb);
4186163953Srrs				break;
4187163953Srrs			}
4188233660Srrs			if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
4189163953Srrs				send_in = 1;
4190233660Srrs			}
4191233660Srrs			if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
4192163953Srrs				send_out = 1;
4193233660Srrs			}
4194233660Srrs			if ((send_in == 0) && (send_out == 0)) {
4195233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4196233660Srrs				error = EINVAL;
4197233660Srrs				SCTP_TCB_UNLOCK(stcb);
4198233660Srrs				break;
4199233660Srrs			}
4200233660Srrs			for (i = 0; i < strrst->srs_number_streams; i++) {
4201233660Srrs				if ((send_in) &&
4202233660Srrs				    (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
4203233660Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4204188854Srrs					error = EINVAL;
4205233660Srrs					break;
4206188854Srrs				}
4207233660Srrs				if ((send_out) &&
4208233660Srrs				    (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
4209233660Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4210233660Srrs					error = EINVAL;
4211233660Srrs					break;
4212188854Srrs				}
4213233660Srrs			}
4214233660Srrs			if (error) {
4215233660Srrs				SCTP_TCB_UNLOCK(stcb);
4216233660Srrs				break;
4217233660Srrs			}
4218233660Srrs			error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
4219233660Srrs			    strrst->srs_stream_list,
4220233660Srrs			    send_out, send_in, 0, 0, 0, 0, 0);
4221233660Srrs
4222233660Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4223233660Srrs			SCTP_TCB_UNLOCK(stcb);
4224233660Srrs			break;
4225233660Srrs		}
4226233660Srrs	case SCTP_ADD_STREAMS:
4227233660Srrs		{
4228233660Srrs			struct sctp_add_streams *stradd;
4229233660Srrs			uint8_t addstream = 0;
4230233660Srrs			uint16_t add_o_strmcnt = 0;
4231233660Srrs			uint16_t add_i_strmcnt = 0;
4232233660Srrs
4233233660Srrs			SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
4234233660Srrs			SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
4235233660Srrs			if (stcb == NULL) {
4236233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4237233660Srrs				error = ENOENT;
4238233660Srrs				break;
4239233660Srrs			}
4240235057Stuexen			if (stcb->asoc.peer_supports_strreset == 0) {
4241235057Stuexen				/*
4242235057Stuexen				 * Peer does not support the chunk type.
4243235057Stuexen				 */
4244235057Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4245235057Stuexen				error = EOPNOTSUPP;
4246235057Stuexen				SCTP_TCB_UNLOCK(stcb);
4247235057Stuexen				break;
4248235057Stuexen			}
4249235057Stuexen			if (stcb->asoc.stream_reset_outstanding) {
4250235057Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4251235057Stuexen				error = EALREADY;
4252235057Stuexen				SCTP_TCB_UNLOCK(stcb);
4253235057Stuexen				break;
4254235057Stuexen			}
4255233660Srrs			if ((stradd->sas_outstrms == 0) &&
4256233660Srrs			    (stradd->sas_instrms == 0)) {
4257233660Srrs				error = EINVAL;
4258233660Srrs				goto skip_stuff;
4259233660Srrs			}
4260233660Srrs			if (stradd->sas_outstrms) {
4261188854Srrs				addstream = 1;
4262188854Srrs				/* We allocate here */
4263233660Srrs				add_o_strmcnt = stradd->sas_outstrms;
4264233660Srrs				if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
4265188854Srrs					/* You can't have more than 64k */
4266188854Srrs					error = EINVAL;
4267188854Srrs					goto skip_stuff;
4268188854Srrs				}
4269163953Srrs			}
4270233660Srrs			if (stradd->sas_instrms) {
4271233660Srrs				int cnt;
4272163953Srrs
4273233660Srrs				addstream |= 2;
4274233660Srrs				/*
4275233660Srrs				 * We allocate inside
4276233660Srrs				 * sctp_send_str_reset_req()
4277233660Srrs				 */
4278233660Srrs				add_i_strmcnt = stradd->sas_instrms;
4279233660Srrs				cnt = add_i_strmcnt;
4280233660Srrs				cnt += stcb->asoc.streamincnt;
4281233660Srrs				if (cnt > 0x0000ffff) {
4282233660Srrs					/* You can't have more than 64k */
4283163953Srrs					error = EINVAL;
4284233660Srrs					goto skip_stuff;
4285163953Srrs				}
4286233660Srrs				if (cnt > (int)stcb->asoc.max_inbound_streams) {
4287233660Srrs					/* More than you are allowed */
4288163953Srrs					error = EINVAL;
4289233660Srrs					goto skip_stuff;
4290163953Srrs				}
4291163953Srrs			}
4292233660Srrs			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
4293233660Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4294188854Srrs	skip_stuff:
4295233660Srrs			SCTP_TCB_UNLOCK(stcb);
4296233660Srrs			break;
4297233660Srrs		}
4298233660Srrs	case SCTP_RESET_ASSOC:
4299233660Srrs		{
4300233660Srrs			uint32_t *value;
4301233660Srrs
4302233660Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
4303233660Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
4304233660Srrs			if (stcb == NULL) {
4305233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4306233660Srrs				error = ENOENT;
4307233660Srrs				break;
4308233660Srrs			}
4309233660Srrs			if (stcb->asoc.peer_supports_strreset == 0) {
4310233660Srrs				/*
4311233660Srrs				 * Peer does not support the chunk type.
4312233660Srrs				 */
4313233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4314233660Srrs				error = EOPNOTSUPP;
4315163953Srrs				SCTP_TCB_UNLOCK(stcb);
4316163953Srrs				break;
4317163953Srrs			}
4318233660Srrs			if (stcb->asoc.stream_reset_outstanding) {
4319233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4320233660Srrs				error = EALREADY;
4321233660Srrs				SCTP_TCB_UNLOCK(stcb);
4322233660Srrs				break;
4323233660Srrs			}
4324233660Srrs			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0);
4325172090Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4326163953Srrs			SCTP_TCB_UNLOCK(stcb);
4327223132Stuexen			break;
4328163953Srrs		}
4329163953Srrs	case SCTP_CONNECT_X:
4330166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
4331171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4332163953Srrs			error = EINVAL;
4333163953Srrs			break;
4334163953Srrs		}
4335166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
4336163953Srrs		break;
4337163953Srrs	case SCTP_CONNECT_X_DELAYED:
4338166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
4339171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4340163953Srrs			error = EINVAL;
4341163953Srrs			break;
4342163953Srrs		}
4343166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
4344163953Srrs		break;
4345163953Srrs	case SCTP_CONNECT_X_COMPLETE:
4346163953Srrs		{
4347163953Srrs			struct sockaddr *sa;
4348163953Srrs			struct sctp_nets *net;
4349163953Srrs
4350166675Srrs			/* FIXME MT: check correct? */
4351166675Srrs			SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
4352166675Srrs
4353163953Srrs			/* find tcb */
4354163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4355163953Srrs				SCTP_INP_RLOCK(inp);
4356163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
4357163953Srrs				if (stcb) {
4358163953Srrs					SCTP_TCB_LOCK(stcb);
4359163953Srrs					net = sctp_findnet(stcb, sa);
4360163953Srrs				}
4361163953Srrs				SCTP_INP_RUNLOCK(inp);
4362163953Srrs			} else {
4363166675Srrs				/*
4364166675Srrs				 * We increment here since
4365166675Srrs				 * sctp_findassociation_ep_addr() wil do a
4366166675Srrs				 * decrement if it finds the stcb as long as
4367166675Srrs				 * the locked tcb (last argument) is NOT a
4368166675Srrs				 * TCB.. aka NULL.
4369166675Srrs				 */
4370163953Srrs				SCTP_INP_INCR_REF(inp);
4371163953Srrs				stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL);
4372163953Srrs				if (stcb == NULL) {
4373163953Srrs					SCTP_INP_DECR_REF(inp);
4374163953Srrs				}
4375163953Srrs			}
4376163953Srrs
4377163953Srrs			if (stcb == NULL) {
4378171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4379163953Srrs				error = ENOENT;
4380163953Srrs				break;
4381163953Srrs			}
4382163953Srrs			if (stcb->asoc.delayed_connection == 1) {
4383163953Srrs				stcb->asoc.delayed_connection = 0;
4384169378Srrs				(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
4385165220Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
4386165220Srrs				    stcb->asoc.primary_destination,
4387165220Srrs				    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
4388172090Srrs				sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
4389163953Srrs			} else {
4390163953Srrs				/*
4391163953Srrs				 * already expired or did not use delayed
4392163953Srrs				 * connectx
4393163953Srrs				 */
4394171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4395163953Srrs				error = EALREADY;
4396163953Srrs			}
4397163953Srrs			SCTP_TCB_UNLOCK(stcb);
4398223132Stuexen			break;
4399163953Srrs		}
4400170056Srrs	case SCTP_MAX_BURST:
4401163953Srrs		{
4402217895Stuexen			struct sctp_assoc_value *av;
4403163953Srrs
4404217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4405217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4406166675Srrs
4407217895Stuexen			if (stcb) {
4408217895Stuexen				stcb->asoc.max_burst = av->assoc_value;
4409217895Stuexen				SCTP_TCB_UNLOCK(stcb);
4410217895Stuexen			} else {
4411224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4412224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4413224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4414223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4415223132Stuexen					SCTP_INP_WLOCK(inp);
4416223132Stuexen					inp->sctp_ep.max_burst = av->assoc_value;
4417223132Stuexen					SCTP_INP_WUNLOCK(inp);
4418223132Stuexen				}
4419223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4420223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4421223132Stuexen					SCTP_INP_RLOCK(inp);
4422223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4423223132Stuexen						SCTP_TCB_LOCK(stcb);
4424223132Stuexen						stcb->asoc.max_burst = av->assoc_value;
4425223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4426223132Stuexen					}
4427223132Stuexen					SCTP_INP_RUNLOCK(inp);
4428223132Stuexen				}
4429217895Stuexen			}
4430223132Stuexen			break;
4431163953Srrs		}
4432163953Srrs	case SCTP_MAXSEG:
4433163953Srrs		{
4434167598Srrs			struct sctp_assoc_value *av;
4435163953Srrs			int ovh;
4436163953Srrs
4437167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4438167598Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4439166675Srrs
4440170056Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
4441170056Srrs				ovh = SCTP_MED_OVERHEAD;
4442170056Srrs			} else {
4443170056Srrs				ovh = SCTP_MED_V4_OVERHEAD;
4444170056Srrs			}
4445167598Srrs			if (stcb) {
4446170056Srrs				if (av->assoc_value) {
4447170056Srrs					stcb->asoc.sctp_frag_point = (av->assoc_value + ovh);
4448170056Srrs				} else {
4449170056Srrs					stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
4450170056Srrs				}
4451167598Srrs				SCTP_TCB_UNLOCK(stcb);
4452163953Srrs			} else {
4453224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4454224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4455224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4456223132Stuexen					SCTP_INP_WLOCK(inp);
4457223132Stuexen					/*
4458223132Stuexen					 * FIXME MT: I think this is not in
4459223132Stuexen					 * tune with the API ID
4460223132Stuexen					 */
4461223132Stuexen					if (av->assoc_value) {
4462223132Stuexen						inp->sctp_frag_point = (av->assoc_value + ovh);
4463223132Stuexen					} else {
4464223132Stuexen						inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
4465223132Stuexen					}
4466223132Stuexen					SCTP_INP_WUNLOCK(inp);
4467167598Srrs				} else {
4468223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4469223132Stuexen					error = EINVAL;
4470167598Srrs				}
4471163953Srrs			}
4472223132Stuexen			break;
4473163953Srrs		}
4474163953Srrs	case SCTP_EVENTS:
4475163953Srrs		{
4476163953Srrs			struct sctp_event_subscribe *events;
4477163953Srrs
4478166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
4479166675Srrs
4480163953Srrs			SCTP_INP_WLOCK(inp);
4481163953Srrs			if (events->sctp_data_io_event) {
4482163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
4483163953Srrs			} else {
4484163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
4485163953Srrs			}
4486163953Srrs
4487163953Srrs			if (events->sctp_association_event) {
4488163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4489163953Srrs			} else {
4490163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4491163953Srrs			}
4492163953Srrs
4493163953Srrs			if (events->sctp_address_event) {
4494163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
4495163953Srrs			} else {
4496163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
4497163953Srrs			}
4498163953Srrs
4499163953Srrs			if (events->sctp_send_failure_event) {
4500163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4501163953Srrs			} else {
4502163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4503163953Srrs			}
4504163953Srrs
4505163953Srrs			if (events->sctp_peer_error_event) {
4506163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
4507163953Srrs			} else {
4508163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
4509163953Srrs			}
4510163953Srrs
4511163953Srrs			if (events->sctp_shutdown_event) {
4512163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4513163953Srrs			} else {
4514163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4515163953Srrs			}
4516163953Srrs
4517163953Srrs			if (events->sctp_partial_delivery_event) {
4518163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
4519163953Srrs			} else {
4520163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
4521163953Srrs			}
4522163953Srrs
4523163953Srrs			if (events->sctp_adaptation_layer_event) {
4524163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
4525163953Srrs			} else {
4526163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
4527163953Srrs			}
4528163953Srrs
4529163953Srrs			if (events->sctp_authentication_event) {
4530163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
4531163953Srrs			} else {
4532163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
4533163953Srrs			}
4534163953Srrs
4535185694Srrs			if (events->sctp_sender_dry_event) {
4536185694Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
4537185694Srrs			} else {
4538185694Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
4539185694Srrs			}
4540185694Srrs
4541202520Srrs			if (events->sctp_stream_reset_event) {
4542163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
4543163953Srrs			} else {
4544163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
4545163953Srrs			}
4546163953Srrs			SCTP_INP_WUNLOCK(inp);
4547223132Stuexen
4548223132Stuexen			SCTP_INP_RLOCK(inp);
4549223132Stuexen			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4550223132Stuexen				SCTP_TCB_LOCK(stcb);
4551223132Stuexen				if (events->sctp_association_event) {
4552223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4553223132Stuexen				} else {
4554223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4555223132Stuexen				}
4556223132Stuexen				if (events->sctp_address_event) {
4557223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
4558223132Stuexen				} else {
4559223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
4560223132Stuexen				}
4561223132Stuexen				if (events->sctp_send_failure_event) {
4562223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4563223132Stuexen				} else {
4564223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4565223132Stuexen				}
4566223132Stuexen				if (events->sctp_peer_error_event) {
4567223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
4568223132Stuexen				} else {
4569223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
4570223132Stuexen				}
4571223132Stuexen				if (events->sctp_shutdown_event) {
4572223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4573223132Stuexen				} else {
4574223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4575223132Stuexen				}
4576223132Stuexen				if (events->sctp_partial_delivery_event) {
4577223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
4578223132Stuexen				} else {
4579223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
4580223132Stuexen				}
4581223132Stuexen				if (events->sctp_adaptation_layer_event) {
4582223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
4583223132Stuexen				} else {
4584223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
4585223132Stuexen				}
4586223132Stuexen				if (events->sctp_authentication_event) {
4587223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
4588223132Stuexen				} else {
4589223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
4590223132Stuexen				}
4591223132Stuexen				if (events->sctp_sender_dry_event) {
4592223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
4593223132Stuexen				} else {
4594223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
4595223132Stuexen				}
4596223132Stuexen				if (events->sctp_stream_reset_event) {
4597223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
4598223132Stuexen				} else {
4599223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
4600223132Stuexen				}
4601223132Stuexen				SCTP_TCB_UNLOCK(stcb);
4602223132Stuexen			}
4603223132Stuexen			/*
4604223132Stuexen			 * Send up the sender dry event only for 1-to-1
4605223132Stuexen			 * style sockets.
4606223132Stuexen			 */
4607223132Stuexen			if (events->sctp_sender_dry_event) {
4608223132Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4609223132Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
4610223132Stuexen					stcb = LIST_FIRST(&inp->sctp_asoc_list);
4611223132Stuexen					if (stcb) {
4612223132Stuexen						SCTP_TCB_LOCK(stcb);
4613223132Stuexen						if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
4614223132Stuexen						    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
4615223132Stuexen						    (stcb->asoc.stream_queue_cnt == 0)) {
4616223132Stuexen							sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
4617223132Stuexen						}
4618223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4619223132Stuexen					}
4620223132Stuexen				}
4621223132Stuexen			}
4622223132Stuexen			SCTP_INP_RUNLOCK(inp);
4623223132Stuexen			break;
4624163953Srrs		}
4625163953Srrs	case SCTP_ADAPTATION_LAYER:
4626163953Srrs		{
4627163953Srrs			struct sctp_setadaptation *adap_bits;
4628163953Srrs
4629166675Srrs			SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
4630163953Srrs			SCTP_INP_WLOCK(inp);
4631163953Srrs			inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
4632163953Srrs			SCTP_INP_WUNLOCK(inp);
4633223132Stuexen			break;
4634163953Srrs		}
4635166675Srrs#ifdef SCTP_DEBUG
4636163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
4637163953Srrs		{
4638163953Srrs			uint32_t *vvv;
4639163953Srrs
4640166675Srrs			SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
4641163953Srrs			SCTP_INP_WLOCK(inp);
4642163953Srrs			inp->sctp_ep.initial_sequence_debug = *vvv;
4643163953Srrs			SCTP_INP_WUNLOCK(inp);
4644223132Stuexen			break;
4645163953Srrs		}
4646166675Srrs#endif
4647163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
4648163953Srrs		{
4649163953Srrs			struct sctp_sndrcvinfo *s_info;
4650163953Srrs
4651166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
4652166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
4653163953Srrs
4654166675Srrs			if (stcb) {
4655223132Stuexen				if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
4656170056Srrs					memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
4657163953Srrs				} else {
4658171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4659166675Srrs					error = EINVAL;
4660163953Srrs				}
4661166675Srrs				SCTP_TCB_UNLOCK(stcb);
4662166675Srrs			} else {
4663224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4664224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4665224918Stuexen				    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
4666223132Stuexen				    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
4667223132Stuexen					SCTP_INP_WLOCK(inp);
4668223132Stuexen					memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
4669223132Stuexen					SCTP_INP_WUNLOCK(inp);
4670223132Stuexen				}
4671223132Stuexen				if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
4672223132Stuexen				    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
4673223132Stuexen					SCTP_INP_RLOCK(inp);
4674223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4675223132Stuexen						SCTP_TCB_LOCK(stcb);
4676223132Stuexen						if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
4677223132Stuexen							memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
4678223132Stuexen						}
4679223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4680223132Stuexen					}
4681223132Stuexen					SCTP_INP_RUNLOCK(inp);
4682223132Stuexen				}
4683163953Srrs			}
4684223132Stuexen			break;
4685163953Srrs		}
4686163953Srrs	case SCTP_PEER_ADDR_PARAMS:
4687163953Srrs		{
4688163953Srrs			struct sctp_paddrparams *paddrp;
4689163953Srrs			struct sctp_nets *net;
4690163953Srrs
4691166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
4692166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
4693163953Srrs			net = NULL;
4694166675Srrs			if (stcb) {
4695166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
4696166675Srrs			} else {
4697166675Srrs				/*
4698166675Srrs				 * We increment here since
4699166675Srrs				 * sctp_findassociation_ep_addr() wil do a
4700166675Srrs				 * decrement if it finds the stcb as long as
4701166675Srrs				 * the locked tcb (last argument) is NOT a
4702166675Srrs				 * TCB.. aka NULL.
4703166675Srrs				 */
4704166675Srrs				SCTP_INP_INCR_REF(inp);
4705166675Srrs				stcb = sctp_findassociation_ep_addr(&inp,
4706166675Srrs				    (struct sockaddr *)&paddrp->spp_address,
4707166675Srrs				    &net, NULL, NULL);
4708163953Srrs				if (stcb == NULL) {
4709166675Srrs					SCTP_INP_DECR_REF(inp);
4710163953Srrs				}
4711163953Srrs			}
4712171943Srrs			if (stcb && (net == NULL)) {
4713171943Srrs				struct sockaddr *sa;
4714171943Srrs
4715171943Srrs				sa = (struct sockaddr *)&paddrp->spp_address;
4716221249Stuexen#ifdef INET
4717171943Srrs				if (sa->sa_family == AF_INET) {
4718221249Stuexen
4719171943Srrs					struct sockaddr_in *sin;
4720171943Srrs
4721171943Srrs					sin = (struct sockaddr_in *)sa;
4722171943Srrs					if (sin->sin_addr.s_addr) {
4723171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4724171943Srrs						SCTP_TCB_UNLOCK(stcb);
4725171943Srrs						error = EINVAL;
4726171943Srrs						break;
4727171943Srrs					}
4728221249Stuexen				} else
4729221249Stuexen#endif
4730221249Stuexen#ifdef INET6
4731221249Stuexen				if (sa->sa_family == AF_INET6) {
4732171943Srrs					struct sockaddr_in6 *sin6;
4733171943Srrs
4734171943Srrs					sin6 = (struct sockaddr_in6 *)sa;
4735171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
4736171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4737171943Srrs						SCTP_TCB_UNLOCK(stcb);
4738171943Srrs						error = EINVAL;
4739171943Srrs						break;
4740171943Srrs					}
4741221249Stuexen				} else
4742221249Stuexen#endif
4743221249Stuexen				{
4744171943Srrs					error = EAFNOSUPPORT;
4745171943Srrs					SCTP_TCB_UNLOCK(stcb);
4746171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4747171943Srrs					break;
4748171943Srrs				}
4749171943Srrs			}
4750170056Srrs			/* sanity checks */
4751170056Srrs			if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
4752170056Srrs				if (stcb)
4753170056Srrs					SCTP_TCB_UNLOCK(stcb);
4754171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4755170056Srrs				return (EINVAL);
4756170056Srrs			}
4757170056Srrs			if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
4758170056Srrs				if (stcb)
4759170056Srrs					SCTP_TCB_UNLOCK(stcb);
4760171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4761170056Srrs				return (EINVAL);
4762170056Srrs			}
4763163953Srrs			if (stcb) {
4764163953Srrs				/************************TCB SPECIFIC SET ******************/
4765163953Srrs				/*
4766163953Srrs				 * do we change the timer for HB, we run
4767163953Srrs				 * only one?
4768163953Srrs				 */
4769170056Srrs				int ovh = 0;
4770170056Srrs
4771170056Srrs				if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
4772170056Srrs					ovh = SCTP_MED_OVERHEAD;
4773170056Srrs				} else {
4774170056Srrs					ovh = SCTP_MED_V4_OVERHEAD;
4775170056Srrs				}
4776170056Srrs
4777163953Srrs				/* network sets ? */
4778163953Srrs				if (net) {
4779163953Srrs					/************************NET SPECIFIC SET ******************/
4780224641Stuexen					if (paddrp->spp_flags & SPP_HB_DISABLE) {
4781224641Stuexen						if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
4782224641Stuexen						    !(net->dest_state & SCTP_ADDR_NOHB)) {
4783224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
4784224641Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
4785171440Srrs						}
4786163953Srrs						net->dest_state |= SCTP_ADDR_NOHB;
4787163953Srrs					}
4788163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
4789224641Stuexen						if (paddrp->spp_hbinterval) {
4790224641Stuexen							net->heart_beat_delay = paddrp->spp_hbinterval;
4791224641Stuexen						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
4792224641Stuexen							net->heart_beat_delay = 0;
4793224641Stuexen						}
4794224641Stuexen						sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
4795224641Stuexen						    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
4796224641Stuexen						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
4797163953Srrs						net->dest_state &= ~SCTP_ADDR_NOHB;
4798163953Srrs					}
4799224641Stuexen					if (paddrp->spp_flags & SPP_HB_DEMAND) {
4800224641Stuexen						/* on demand HB */
4801224641Stuexen						sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
4802228391Stuexen						sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
4803224641Stuexen						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
4804224641Stuexen					}
4805170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
4806165647Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
4807165220Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
4808165220Srrs							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
4809163953Srrs						}
4810225635Stuexen						net->dest_state |= SCTP_ADDR_NO_PMTUD;
4811163953Srrs						if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
4812170056Srrs							net->mtu = paddrp->spp_pathmtu + ovh;
4813169352Srrs							if (net->mtu < stcb->asoc.smallest_mtu) {
4814228653Stuexen								sctp_pathmtu_adjustment(stcb, net->mtu);
4815169352Srrs							}
4816163953Srrs						}
4817163953Srrs					}
4818163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
4819225635Stuexen						if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
4820163953Srrs							sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
4821163953Srrs						}
4822225635Stuexen						net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
4823163953Srrs					}
4824224641Stuexen					if (paddrp->spp_pathmaxrxt) {
4825224641Stuexen						if (net->dest_state & SCTP_ADDR_PF) {
4826224641Stuexen							if (net->error_count > paddrp->spp_pathmaxrxt) {
4827224641Stuexen								net->dest_state &= ~SCTP_ADDR_PF;
4828224641Stuexen							}
4829224641Stuexen						} else {
4830224641Stuexen							if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
4831224641Stuexen							    (net->error_count > net->pf_threshold)) {
4832224641Stuexen								net->dest_state |= SCTP_ADDR_PF;
4833224641Stuexen								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
4834224641Stuexen								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
4835224641Stuexen								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
4836224641Stuexen							}
4837224641Stuexen						}
4838224641Stuexen						if (net->dest_state & SCTP_ADDR_REACHABLE) {
4839224641Stuexen							if (net->error_count > paddrp->spp_pathmaxrxt) {
4840224641Stuexen								net->dest_state &= ~SCTP_ADDR_REACHABLE;
4841235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
4842224641Stuexen							}
4843224641Stuexen						} else {
4844224641Stuexen							if (net->error_count <= paddrp->spp_pathmaxrxt) {
4845224641Stuexen								net->dest_state |= SCTP_ADDR_REACHABLE;
4846235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
4847224641Stuexen							}
4848224641Stuexen						}
4849163953Srrs						net->failure_threshold = paddrp->spp_pathmaxrxt;
4850224641Stuexen					}
4851224870Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
4852226252Stuexen						net->dscp = paddrp->spp_dscp & 0xfc;
4853225549Stuexen						net->dscp |= 0x01;
4854163953Srrs					}
4855167598Srrs#ifdef INET6
4856163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
4857225549Stuexen						if (net->ro._l_addr.sa.sa_family == AF_INET6) {
4858224870Stuexen							net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
4859225549Stuexen							net->flowlabel |= 0x80000000;
4860163953Srrs						}
4861163953Srrs					}
4862163953Srrs#endif
4863163953Srrs				} else {
4864163953Srrs					/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
4865224641Stuexen					if (paddrp->spp_pathmaxrxt) {
4866163953Srrs						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
4867224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4868224641Stuexen							if (net->dest_state & SCTP_ADDR_PF) {
4869224641Stuexen								if (net->error_count > paddrp->spp_pathmaxrxt) {
4870224641Stuexen									net->dest_state &= ~SCTP_ADDR_PF;
4871224641Stuexen								}
4872224641Stuexen							} else {
4873224641Stuexen								if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
4874224641Stuexen								    (net->error_count > net->pf_threshold)) {
4875224641Stuexen									net->dest_state |= SCTP_ADDR_PF;
4876224641Stuexen									sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
4877224641Stuexen									sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
4878224641Stuexen									sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
4879224641Stuexen								}
4880224641Stuexen							}
4881224641Stuexen							if (net->dest_state & SCTP_ADDR_REACHABLE) {
4882224641Stuexen								if (net->error_count > paddrp->spp_pathmaxrxt) {
4883224641Stuexen									net->dest_state &= ~SCTP_ADDR_REACHABLE;
4884235414Stuexen									sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
4885224641Stuexen								}
4886224641Stuexen							} else {
4887224641Stuexen								if (net->error_count <= paddrp->spp_pathmaxrxt) {
4888224641Stuexen									net->dest_state |= SCTP_ADDR_REACHABLE;
4889235414Stuexen									sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
4890224641Stuexen								}
4891224641Stuexen							}
4892224641Stuexen							net->failure_threshold = paddrp->spp_pathmaxrxt;
4893224641Stuexen						}
4894224641Stuexen					}
4895163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
4896224641Stuexen						if (paddrp->spp_hbinterval) {
4897224641Stuexen							stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
4898224641Stuexen						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
4899224641Stuexen							stcb->asoc.heart_beat_delay = 0;
4900224641Stuexen						}
4901163953Srrs						/* Turn back on the timer */
4902224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4903224641Stuexen							if (paddrp->spp_hbinterval) {
4904224641Stuexen								net->heart_beat_delay = paddrp->spp_hbinterval;
4905224641Stuexen							} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
4906224641Stuexen								net->heart_beat_delay = 0;
4907224641Stuexen							}
4908224641Stuexen							if (net->dest_state & SCTP_ADDR_NOHB) {
4909224641Stuexen								net->dest_state &= ~SCTP_ADDR_NOHB;
4910224641Stuexen							}
4911224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
4912224641Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
4913224641Stuexen							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
4914224641Stuexen						}
4915225635Stuexen						sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
4916163953Srrs					}
4917224641Stuexen					if (paddrp->spp_flags & SPP_HB_DISABLE) {
4918224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4919224641Stuexen							if (!(net->dest_state & SCTP_ADDR_NOHB)) {
4920224641Stuexen								net->dest_state |= SCTP_ADDR_NOHB;
4921224641Stuexen								if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
4922224641Stuexen									sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
4923224641Stuexen								}
4924224641Stuexen							}
4925224641Stuexen						}
4926225635Stuexen						sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
4927224641Stuexen					}
4928170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
4929170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4930170056Srrs							if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
4931170056Srrs								sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
4932170056Srrs								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
4933170056Srrs							}
4934225635Stuexen							net->dest_state |= SCTP_ADDR_NO_PMTUD;
4935170056Srrs							if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
4936170056Srrs								net->mtu = paddrp->spp_pathmtu + ovh;
4937170056Srrs								if (net->mtu < stcb->asoc.smallest_mtu) {
4938228653Stuexen									sctp_pathmtu_adjustment(stcb, net->mtu);
4939170056Srrs								}
4940170056Srrs							}
4941170056Srrs						}
4942225635Stuexen						sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
4943170056Srrs					}
4944170056Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
4945170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4946225635Stuexen							if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
4947170056Srrs								sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
4948170056Srrs							}
4949225635Stuexen							net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
4950170056Srrs						}
4951225635Stuexen						sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
4952170056Srrs					}
4953224870Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
4954224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4955226252Stuexen							net->dscp = paddrp->spp_dscp & 0xfc;
4956225549Stuexen							net->dscp |= 0x01;
4957163953Srrs						}
4958226252Stuexen						stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc;
4959225549Stuexen						stcb->asoc.default_dscp |= 0x01;
4960163953Srrs					}
4961225549Stuexen#ifdef INET6
4962224641Stuexen					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
4963170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4964225549Stuexen							if (net->ro._l_addr.sa.sa_family == AF_INET6) {
4965225549Stuexen								net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
4966225549Stuexen								net->flowlabel |= 0x80000000;
4967225549Stuexen							}
4968170056Srrs						}
4969225549Stuexen						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
4970225549Stuexen						stcb->asoc.default_flowlabel |= 0x80000000;
4971163953Srrs					}
4972225549Stuexen#endif
4973163953Srrs				}
4974163953Srrs				SCTP_TCB_UNLOCK(stcb);
4975163953Srrs			} else {
4976163953Srrs				/************************NO TCB, SET TO default stuff ******************/
4977224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4978224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4979224918Stuexen				    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
4980223132Stuexen					SCTP_INP_WLOCK(inp);
4981223132Stuexen					/*
4982223132Stuexen					 * For the TOS/FLOWLABEL stuff you
4983223132Stuexen					 * set it with the options on the
4984223132Stuexen					 * socket
4985223132Stuexen					 */
4986223132Stuexen					if (paddrp->spp_pathmaxrxt) {
4987223132Stuexen						inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
4988223132Stuexen					}
4989223132Stuexen					if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
4990223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
4991223132Stuexen					else if (paddrp->spp_hbinterval) {
4992223132Stuexen						if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
4993223132Stuexen							paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL;
4994223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
4995223132Stuexen					}
4996223132Stuexen					if (paddrp->spp_flags & SPP_HB_ENABLE) {
4997224641Stuexen						if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
4998224641Stuexen							inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
4999224641Stuexen						} else if (paddrp->spp_hbinterval) {
5000224641Stuexen							inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
5001224641Stuexen						}
5002223132Stuexen						sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5003223132Stuexen					} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
5004223132Stuexen						sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5005223132Stuexen					}
5006225635Stuexen					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5007225635Stuexen						sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5008225635Stuexen					} else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
5009225635Stuexen						sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5010225635Stuexen					}
5011225549Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5012226252Stuexen						inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc;
5013225549Stuexen						inp->sctp_ep.default_dscp |= 0x01;
5014225549Stuexen					}
5015225549Stuexen#ifdef INET6
5016225549Stuexen					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5017225549Stuexen						if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
5018225549Stuexen							inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5019225549Stuexen							inp->sctp_ep.default_flowlabel |= 0x80000000;
5020225549Stuexen						}
5021225549Stuexen					}
5022225549Stuexen#endif
5023223132Stuexen					SCTP_INP_WUNLOCK(inp);
5024223132Stuexen				} else {
5025223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5026223132Stuexen					error = EINVAL;
5027163953Srrs				}
5028163953Srrs			}
5029223132Stuexen			break;
5030163953Srrs		}
5031163953Srrs	case SCTP_RTOINFO:
5032163953Srrs		{
5033163953Srrs			struct sctp_rtoinfo *srto;
5034169655Srrs			uint32_t new_init, new_min, new_max;
5035163953Srrs
5036166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
5037166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
5038166675Srrs
5039166675Srrs			if (stcb) {
5040167598Srrs				if (srto->srto_initial)
5041169655Srrs					new_init = srto->srto_initial;
5042169655Srrs				else
5043169655Srrs					new_init = stcb->asoc.initial_rto;
5044167598Srrs				if (srto->srto_max)
5045169655Srrs					new_max = srto->srto_max;
5046169655Srrs				else
5047169655Srrs					new_max = stcb->asoc.maxrto;
5048167598Srrs				if (srto->srto_min)
5049169655Srrs					new_min = srto->srto_min;
5050169655Srrs				else
5051169655Srrs					new_min = stcb->asoc.minrto;
5052169655Srrs				if ((new_min <= new_init) && (new_init <= new_max)) {
5053169655Srrs					stcb->asoc.initial_rto = new_init;
5054169655Srrs					stcb->asoc.maxrto = new_max;
5055169655Srrs					stcb->asoc.minrto = new_min;
5056169655Srrs				} else {
5057179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5058179783Srrs					error = EINVAL;
5059169655Srrs				}
5060166675Srrs				SCTP_TCB_UNLOCK(stcb);
5061166675Srrs			} else {
5062224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5063224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5064224918Stuexen				    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
5065223132Stuexen					SCTP_INP_WLOCK(inp);
5066223132Stuexen					if (srto->srto_initial)
5067223132Stuexen						new_init = srto->srto_initial;
5068223132Stuexen					else
5069223132Stuexen						new_init = inp->sctp_ep.initial_rto;
5070223132Stuexen					if (srto->srto_max)
5071223132Stuexen						new_max = srto->srto_max;
5072223132Stuexen					else
5073223132Stuexen						new_max = inp->sctp_ep.sctp_maxrto;
5074223132Stuexen					if (srto->srto_min)
5075223132Stuexen						new_min = srto->srto_min;
5076223132Stuexen					else
5077223132Stuexen						new_min = inp->sctp_ep.sctp_minrto;
5078223132Stuexen					if ((new_min <= new_init) && (new_init <= new_max)) {
5079223132Stuexen						inp->sctp_ep.initial_rto = new_init;
5080223132Stuexen						inp->sctp_ep.sctp_maxrto = new_max;
5081223132Stuexen						inp->sctp_ep.sctp_minrto = new_min;
5082223132Stuexen					} else {
5083223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5084223132Stuexen						error = EINVAL;
5085223132Stuexen					}
5086223132Stuexen					SCTP_INP_WUNLOCK(inp);
5087169655Srrs				} else {
5088179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5089179783Srrs					error = EINVAL;
5090169655Srrs				}
5091163953Srrs			}
5092223132Stuexen			break;
5093163953Srrs		}
5094163953Srrs	case SCTP_ASSOCINFO:
5095163953Srrs		{
5096163953Srrs			struct sctp_assocparams *sasoc;
5097163953Srrs
5098166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
5099166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
5100171477Srrs			if (sasoc->sasoc_cookie_life) {
5101171477Srrs				/* boundary check the cookie life */
5102171477Srrs				if (sasoc->sasoc_cookie_life < 1000)
5103171477Srrs					sasoc->sasoc_cookie_life = 1000;
5104171477Srrs				if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
5105171477Srrs					sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
5106171477Srrs				}
5107171477Srrs			}
5108163953Srrs			if (stcb) {
5109163953Srrs				if (sasoc->sasoc_asocmaxrxt)
5110163953Srrs					stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
5111170056Srrs				if (sasoc->sasoc_cookie_life) {
5112171572Srrs					stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
5113167598Srrs				}
5114163953Srrs				SCTP_TCB_UNLOCK(stcb);
5115163953Srrs			} else {
5116224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5117224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5118224918Stuexen				    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
5119223132Stuexen					SCTP_INP_WLOCK(inp);
5120223132Stuexen					if (sasoc->sasoc_asocmaxrxt)
5121223132Stuexen						inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
5122223132Stuexen					if (sasoc->sasoc_cookie_life) {
5123223132Stuexen						inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
5124223132Stuexen					}
5125223132Stuexen					SCTP_INP_WUNLOCK(inp);
5126223132Stuexen				} else {
5127223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5128223132Stuexen					error = EINVAL;
5129167598Srrs				}
5130163953Srrs			}
5131223132Stuexen			break;
5132163953Srrs		}
5133163953Srrs	case SCTP_INITMSG:
5134163953Srrs		{
5135163953Srrs			struct sctp_initmsg *sinit;
5136163953Srrs
5137166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
5138163953Srrs			SCTP_INP_WLOCK(inp);
5139163953Srrs			if (sinit->sinit_num_ostreams)
5140163953Srrs				inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
5141163953Srrs
5142163953Srrs			if (sinit->sinit_max_instreams)
5143163953Srrs				inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
5144163953Srrs
5145163953Srrs			if (sinit->sinit_max_attempts)
5146163953Srrs				inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
5147163953Srrs
5148167598Srrs			if (sinit->sinit_max_init_timeo)
5149163953Srrs				inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
5150163953Srrs			SCTP_INP_WUNLOCK(inp);
5151223132Stuexen			break;
5152163953Srrs		}
5153163953Srrs	case SCTP_PRIMARY_ADDR:
5154163953Srrs		{
5155163953Srrs			struct sctp_setprim *spa;
5156223132Stuexen			struct sctp_nets *net;
5157163953Srrs
5158166675Srrs			SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
5159166675Srrs			SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
5160163953Srrs
5161166675Srrs			net = NULL;
5162166675Srrs			if (stcb) {
5163166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
5164166675Srrs			} else {
5165166675Srrs				/*
5166166675Srrs				 * We increment here since
5167166675Srrs				 * sctp_findassociation_ep_addr() wil do a
5168166675Srrs				 * decrement if it finds the stcb as long as
5169166675Srrs				 * the locked tcb (last argument) is NOT a
5170166675Srrs				 * TCB.. aka NULL.
5171166675Srrs				 */
5172163953Srrs				SCTP_INP_INCR_REF(inp);
5173163953Srrs				stcb = sctp_findassociation_ep_addr(&inp,
5174163953Srrs				    (struct sockaddr *)&spa->ssp_addr,
5175163953Srrs				    &net, NULL, NULL);
5176163953Srrs				if (stcb == NULL) {
5177163953Srrs					SCTP_INP_DECR_REF(inp);
5178163953Srrs				}
5179163953Srrs			}
5180166675Srrs
5181166675Srrs			if ((stcb) && (net)) {
5182166675Srrs				if ((net != stcb->asoc.primary_destination) &&
5183166675Srrs				    (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
5184166675Srrs					/* Ok we need to set it */
5185166675Srrs					if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
5186224641Stuexen						if ((stcb->asoc.alternate) &&
5187224641Stuexen						    (!(net->dest_state & SCTP_ADDR_PF)) &&
5188224641Stuexen						    (net->dest_state & SCTP_ADDR_REACHABLE)) {
5189224641Stuexen							sctp_free_remote_addr(stcb->asoc.alternate);
5190224641Stuexen							stcb->asoc.alternate = NULL;
5191166675Srrs						}
5192163953Srrs					}
5193163953Srrs				}
5194166675Srrs			} else {
5195171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5196166675Srrs				error = EINVAL;
5197163953Srrs			}
5198166675Srrs			if (stcb) {
5199166675Srrs				SCTP_TCB_UNLOCK(stcb);
5200166675Srrs			}
5201223132Stuexen			break;
5202163953Srrs		}
5203167598Srrs	case SCTP_SET_DYNAMIC_PRIMARY:
5204167598Srrs		{
5205167598Srrs			union sctp_sockstore *ss;
5206163953Srrs
5207170587Srwatson			error = priv_check(curthread,
5208170587Srwatson			    PRIV_NETINET_RESERVEDPORT);
5209167598Srrs			if (error)
5210167598Srrs				break;
5211167598Srrs
5212167598Srrs			SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
5213167598Srrs			/* SUPER USER CHECK? */
5214167598Srrs			error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
5215223132Stuexen			break;
5216167598Srrs		}
5217163953Srrs	case SCTP_SET_PEER_PRIMARY_ADDR:
5218163953Srrs		{
5219163953Srrs			struct sctp_setpeerprim *sspp;
5220163953Srrs
5221166675Srrs			SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
5222166675Srrs			SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
5223169208Srrs			if (stcb != NULL) {
5224170056Srrs				struct sctp_ifa *ifa;
5225170056Srrs
5226170056Srrs				ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
5227172091Srrs				    stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
5228170056Srrs				if (ifa == NULL) {
5229171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5230166675Srrs					error = EINVAL;
5231170056Srrs					goto out_of_it;
5232166675Srrs				}
5233170056Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
5234170056Srrs					/*
5235170056Srrs					 * Must validate the ifa found is in
5236170056Srrs					 * our ep
5237170056Srrs					 */
5238170056Srrs					struct sctp_laddr *laddr;
5239170056Srrs					int found = 0;
5240170056Srrs
5241170056Srrs					LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
5242170056Srrs						if (laddr->ifa == NULL) {
5243170056Srrs							SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
5244170056Srrs							    __FUNCTION__);
5245170056Srrs							continue;
5246170056Srrs						}
5247170056Srrs						if (laddr->ifa == ifa) {
5248170056Srrs							found = 1;
5249170056Srrs							break;
5250170056Srrs						}
5251170056Srrs					}
5252170056Srrs					if (!found) {
5253171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5254170056Srrs						error = EINVAL;
5255170056Srrs						goto out_of_it;
5256170056Srrs					}
5257170056Srrs				}
5258170056Srrs				if (sctp_set_primary_ip_address_sa(stcb,
5259170056Srrs				    (struct sockaddr *)&sspp->sspp_addr) != 0) {
5260171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5261170056Srrs					error = EINVAL;
5262170056Srrs				}
5263170056Srrs		out_of_it:
5264169208Srrs				SCTP_TCB_UNLOCK(stcb);
5265166675Srrs			} else {
5266171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5267163953Srrs				error = EINVAL;
5268163953Srrs			}
5269223132Stuexen			break;
5270163953Srrs		}
5271163953Srrs	case SCTP_BINDX_ADD_ADDR:
5272163953Srrs		{
5273163953Srrs			struct sctp_getaddresses *addrs;
5274171477Srrs			struct thread *td;
5275163953Srrs
5276171477Srrs			td = (struct thread *)p;
5277170606Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
5278170606Srrs			    optsize);
5279221249Stuexen#ifdef INET
5280171477Srrs			if (addrs->addr->sa_family == AF_INET) {
5281238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
5282171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5283171477Srrs					error = EINVAL;
5284171477Srrs					break;
5285171477Srrs				}
5286188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
5287188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5288185435Sbz					break;
5289171477Srrs				}
5290221249Stuexen			} else
5291221249Stuexen#endif
5292185435Sbz#ifdef INET6
5293221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
5294238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
5295171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5296171477Srrs					error = EINVAL;
5297171477Srrs					break;
5298171477Srrs				}
5299188590Srrs				if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
5300188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
5301188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5302185435Sbz					break;
5303185435Sbz				}
5304221249Stuexen			} else
5305185435Sbz#endif
5306221249Stuexen			{
5307185435Sbz				error = EAFNOSUPPORT;
5308185435Sbz				break;
5309171477Srrs			}
5310170606Srrs			sctp_bindx_add_address(so, inp, addrs->addr,
5311170606Srrs			    addrs->sget_assoc_id, vrf_id,
5312170606Srrs			    &error, p);
5313223132Stuexen			break;
5314163953Srrs		}
5315163953Srrs	case SCTP_BINDX_REM_ADDR:
5316163953Srrs		{
5317163953Srrs			struct sctp_getaddresses *addrs;
5318171477Srrs			struct thread *td;
5319163953Srrs
5320171477Srrs			td = (struct thread *)p;
5321185435Sbz
5322166675Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
5323221249Stuexen#ifdef INET
5324171477Srrs			if (addrs->addr->sa_family == AF_INET) {
5325238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
5326171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5327171477Srrs					error = EINVAL;
5328171477Srrs					break;
5329171477Srrs				}
5330188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
5331188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5332185435Sbz					break;
5333171477Srrs				}
5334221249Stuexen			} else
5335221249Stuexen#endif
5336185435Sbz#ifdef INET6
5337221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
5338238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
5339171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5340171477Srrs					error = EINVAL;
5341171477Srrs					break;
5342171477Srrs				}
5343224641Stuexen				if (td != NULL &&
5344224641Stuexen				    (error = prison_local_ip6(td->td_ucred,
5345224641Stuexen				    &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
5346188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
5347188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5348185435Sbz					break;
5349185435Sbz				}
5350221249Stuexen			} else
5351185435Sbz#endif
5352221249Stuexen			{
5353185435Sbz				error = EAFNOSUPPORT;
5354185435Sbz				break;
5355171477Srrs			}
5356228653Stuexen			sctp_bindx_delete_address(inp, addrs->addr,
5357170606Srrs			    addrs->sget_assoc_id, vrf_id,
5358170606Srrs			    &error);
5359223132Stuexen			break;
5360163953Srrs		}
5361223132Stuexen	case SCTP_EVENT:
5362223132Stuexen		{
5363223132Stuexen			struct sctp_event *event;
5364223132Stuexen			uint32_t event_type;
5365223132Stuexen
5366223132Stuexen			SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize);
5367223132Stuexen			SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
5368223132Stuexen			switch (event->se_type) {
5369223132Stuexen			case SCTP_ASSOC_CHANGE:
5370223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
5371223132Stuexen				break;
5372223132Stuexen			case SCTP_PEER_ADDR_CHANGE:
5373223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
5374223132Stuexen				break;
5375223132Stuexen			case SCTP_REMOTE_ERROR:
5376223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPEERERR;
5377223132Stuexen				break;
5378223132Stuexen			case SCTP_SEND_FAILED:
5379223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
5380223132Stuexen				break;
5381223132Stuexen			case SCTP_SHUTDOWN_EVENT:
5382223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
5383223132Stuexen				break;
5384223132Stuexen			case SCTP_ADAPTATION_INDICATION:
5385223132Stuexen				event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
5386223132Stuexen				break;
5387223132Stuexen			case SCTP_PARTIAL_DELIVERY_EVENT:
5388223132Stuexen				event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
5389223132Stuexen				break;
5390223132Stuexen			case SCTP_AUTHENTICATION_EVENT:
5391223132Stuexen				event_type = SCTP_PCB_FLAGS_AUTHEVNT;
5392223132Stuexen				break;
5393223132Stuexen			case SCTP_STREAM_RESET_EVENT:
5394223132Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
5395223132Stuexen				break;
5396223132Stuexen			case SCTP_SENDER_DRY_EVENT:
5397223132Stuexen				event_type = SCTP_PCB_FLAGS_DRYEVNT;
5398223132Stuexen				break;
5399223132Stuexen			case SCTP_NOTIFICATIONS_STOPPED_EVENT:
5400223132Stuexen				event_type = 0;
5401223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
5402223132Stuexen				error = ENOTSUP;
5403223132Stuexen				break;
5404235009Stuexen			case SCTP_ASSOC_RESET_EVENT:
5405235009Stuexen				event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
5406235009Stuexen				break;
5407235009Stuexen			case SCTP_STREAM_CHANGE_EVENT:
5408235009Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
5409235009Stuexen				break;
5410235075Stuexen			case SCTP_SEND_FAILED_EVENT:
5411235075Stuexen				event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
5412235075Stuexen				break;
5413223132Stuexen			default:
5414223132Stuexen				event_type = 0;
5415223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5416223132Stuexen				error = EINVAL;
5417223132Stuexen				break;
5418223132Stuexen			}
5419223132Stuexen			if (event_type > 0) {
5420223132Stuexen				if (stcb) {
5421223132Stuexen					if (event->se_on) {
5422223132Stuexen						sctp_stcb_feature_on(inp, stcb, event_type);
5423223132Stuexen						if (event_type == SCTP_PCB_FLAGS_DRYEVNT) {
5424223132Stuexen							if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
5425223132Stuexen							    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
5426223132Stuexen							    (stcb->asoc.stream_queue_cnt == 0)) {
5427223132Stuexen								sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
5428223132Stuexen							}
5429223132Stuexen						}
5430223132Stuexen					} else {
5431223132Stuexen						sctp_stcb_feature_off(inp, stcb, event_type);
5432223132Stuexen					}
5433223132Stuexen					SCTP_TCB_UNLOCK(stcb);
5434223132Stuexen				} else {
5435223132Stuexen					/*
5436223132Stuexen					 * We don't want to send up a storm
5437223132Stuexen					 * of events, so return an error for
5438223132Stuexen					 * sender dry events
5439223132Stuexen					 */
5440223132Stuexen					if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
5441224918Stuexen					    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) &&
5442224918Stuexen					    ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
5443223132Stuexen					    ((event->se_assoc_id == SCTP_ALL_ASSOC) ||
5444223132Stuexen					    (event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
5445223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
5446223132Stuexen						error = ENOTSUP;
5447223132Stuexen						break;
5448223132Stuexen					}
5449224918Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5450224918Stuexen					    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5451224918Stuexen					    (event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
5452223132Stuexen					    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
5453223132Stuexen						SCTP_INP_WLOCK(inp);
5454223132Stuexen						if (event->se_on) {
5455223132Stuexen							sctp_feature_on(inp, event_type);
5456223132Stuexen						} else {
5457223132Stuexen							sctp_feature_off(inp, event_type);
5458223132Stuexen						}
5459223132Stuexen						SCTP_INP_WUNLOCK(inp);
5460223132Stuexen					}
5461223132Stuexen					if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
5462223132Stuexen					    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
5463223132Stuexen						SCTP_INP_RLOCK(inp);
5464223132Stuexen						LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5465223132Stuexen							SCTP_TCB_LOCK(stcb);
5466223132Stuexen							if (event->se_on) {
5467223132Stuexen								sctp_stcb_feature_on(inp, stcb, event_type);
5468223132Stuexen							} else {
5469223132Stuexen								sctp_stcb_feature_off(inp, stcb, event_type);
5470223132Stuexen							}
5471223132Stuexen							SCTP_TCB_UNLOCK(stcb);
5472223132Stuexen						}
5473223132Stuexen						SCTP_INP_RUNLOCK(inp);
5474223132Stuexen					}
5475223132Stuexen				}
5476223132Stuexen			}
5477223132Stuexen			break;
5478223132Stuexen		}
5479223132Stuexen	case SCTP_RECVRCVINFO:
5480223132Stuexen		{
5481223132Stuexen			int *onoff;
5482223132Stuexen
5483223132Stuexen			SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
5484223132Stuexen			SCTP_INP_WLOCK(inp);
5485223132Stuexen			if (*onoff != 0) {
5486223132Stuexen				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
5487223132Stuexen			} else {
5488223132Stuexen				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
5489223132Stuexen			}
5490223132Stuexen			SCTP_INP_WUNLOCK(inp);
5491223132Stuexen			break;
5492223132Stuexen		}
5493223132Stuexen	case SCTP_RECVNXTINFO:
5494223132Stuexen		{
5495223132Stuexen			int *onoff;
5496223132Stuexen
5497223132Stuexen			SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
5498223132Stuexen			SCTP_INP_WLOCK(inp);
5499223132Stuexen			if (*onoff != 0) {
5500223132Stuexen				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
5501223132Stuexen			} else {
5502223132Stuexen				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
5503223132Stuexen			}
5504223132Stuexen			SCTP_INP_WUNLOCK(inp);
5505223132Stuexen			break;
5506223132Stuexen		}
5507223132Stuexen	case SCTP_DEFAULT_SNDINFO:
5508223132Stuexen		{
5509223132Stuexen			struct sctp_sndinfo *info;
5510223162Stuexen			uint16_t policy;
5511223132Stuexen
5512223132Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize);
5513223132Stuexen			SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
5514223132Stuexen
5515223132Stuexen			if (stcb) {
5516223132Stuexen				if (info->snd_sid < stcb->asoc.streamoutcnt) {
5517223132Stuexen					stcb->asoc.def_send.sinfo_stream = info->snd_sid;
5518223162Stuexen					policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
5519223132Stuexen					stcb->asoc.def_send.sinfo_flags = info->snd_flags;
5520223162Stuexen					stcb->asoc.def_send.sinfo_flags |= policy;
5521223132Stuexen					stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
5522223132Stuexen					stcb->asoc.def_send.sinfo_context = info->snd_context;
5523223132Stuexen				} else {
5524223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5525223132Stuexen					error = EINVAL;
5526223132Stuexen				}
5527223132Stuexen				SCTP_TCB_UNLOCK(stcb);
5528223132Stuexen			} else {
5529224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5530224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5531224918Stuexen				    (info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
5532223132Stuexen				    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
5533223132Stuexen					SCTP_INP_WLOCK(inp);
5534223132Stuexen					inp->def_send.sinfo_stream = info->snd_sid;
5535223162Stuexen					policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
5536223132Stuexen					inp->def_send.sinfo_flags = info->snd_flags;
5537223162Stuexen					inp->def_send.sinfo_flags |= policy;
5538223132Stuexen					inp->def_send.sinfo_ppid = info->snd_ppid;
5539223132Stuexen					inp->def_send.sinfo_context = info->snd_context;
5540223132Stuexen					SCTP_INP_WUNLOCK(inp);
5541223132Stuexen				}
5542223132Stuexen				if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
5543223132Stuexen				    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
5544223132Stuexen					SCTP_INP_RLOCK(inp);
5545223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5546223132Stuexen						SCTP_TCB_LOCK(stcb);
5547223132Stuexen						if (info->snd_sid < stcb->asoc.streamoutcnt) {
5548223132Stuexen							stcb->asoc.def_send.sinfo_stream = info->snd_sid;
5549223162Stuexen							policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
5550223132Stuexen							stcb->asoc.def_send.sinfo_flags = info->snd_flags;
5551223162Stuexen							stcb->asoc.def_send.sinfo_flags |= policy;
5552223132Stuexen							stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
5553223132Stuexen							stcb->asoc.def_send.sinfo_context = info->snd_context;
5554223132Stuexen						}
5555223132Stuexen						SCTP_TCB_UNLOCK(stcb);
5556223132Stuexen					}
5557223132Stuexen					SCTP_INP_RUNLOCK(inp);
5558223132Stuexen				}
5559223132Stuexen			}
5560223132Stuexen			break;
5561223132Stuexen		}
5562223162Stuexen	case SCTP_DEFAULT_PRINFO:
5563223162Stuexen		{
5564223162Stuexen			struct sctp_default_prinfo *info;
5565223162Stuexen
5566223162Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize);
5567223162Stuexen			SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
5568223162Stuexen
5569223162Stuexen			if (PR_SCTP_INVALID_POLICY(info->pr_policy)) {
5570223162Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5571223162Stuexen				error = EINVAL;
5572223162Stuexen				break;
5573223162Stuexen			}
5574223162Stuexen			if (stcb) {
5575223162Stuexen				stcb->asoc.def_send.sinfo_flags &= 0xfff0;
5576223162Stuexen				stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
5577224918Stuexen				stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
5578223162Stuexen				SCTP_TCB_UNLOCK(stcb);
5579223162Stuexen			} else {
5580224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5581224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5582224918Stuexen				    (info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
5583223162Stuexen				    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
5584223162Stuexen					SCTP_INP_WLOCK(inp);
5585223162Stuexen					inp->def_send.sinfo_flags &= 0xfff0;
5586223162Stuexen					inp->def_send.sinfo_flags |= info->pr_policy;
5587224918Stuexen					inp->def_send.sinfo_timetolive = info->pr_value;
5588223162Stuexen					SCTP_INP_WUNLOCK(inp);
5589223162Stuexen				}
5590223162Stuexen				if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
5591223162Stuexen				    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
5592223162Stuexen					SCTP_INP_RLOCK(inp);
5593223162Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5594223162Stuexen						SCTP_TCB_LOCK(stcb);
5595223162Stuexen						stcb->asoc.def_send.sinfo_flags &= 0xfff0;
5596223162Stuexen						stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
5597224918Stuexen						stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
5598223162Stuexen						SCTP_TCB_UNLOCK(stcb);
5599223162Stuexen					}
5600223162Stuexen					SCTP_INP_RUNLOCK(inp);
5601223162Stuexen				}
5602223162Stuexen			}
5603223162Stuexen			break;
5604223162Stuexen		}
5605224641Stuexen	case SCTP_PEER_ADDR_THLDS:
5606224641Stuexen		/* Applies to the specific association */
5607224641Stuexen		{
5608224641Stuexen			struct sctp_paddrthlds *thlds;
5609224641Stuexen			struct sctp_nets *net;
5610224641Stuexen
5611224641Stuexen			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
5612224641Stuexen			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
5613224641Stuexen			net = NULL;
5614224641Stuexen			if (stcb) {
5615224641Stuexen				net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id);
5616224641Stuexen			} else {
5617224641Stuexen				/*
5618224641Stuexen				 * We increment here since
5619224641Stuexen				 * sctp_findassociation_ep_addr() wil do a
5620224641Stuexen				 * decrement if it finds the stcb as long as
5621224641Stuexen				 * the locked tcb (last argument) is NOT a
5622224641Stuexen				 * TCB.. aka NULL.
5623224641Stuexen				 */
5624224641Stuexen				SCTP_INP_INCR_REF(inp);
5625224641Stuexen				stcb = sctp_findassociation_ep_addr(&inp,
5626224641Stuexen				    (struct sockaddr *)&thlds->spt_assoc_id,
5627224641Stuexen				    &net, NULL, NULL);
5628224641Stuexen				if (stcb == NULL) {
5629224641Stuexen					SCTP_INP_DECR_REF(inp);
5630224641Stuexen				}
5631224641Stuexen			}
5632224641Stuexen			if (stcb && (net == NULL)) {
5633224641Stuexen				struct sockaddr *sa;
5634224641Stuexen
5635224641Stuexen				sa = (struct sockaddr *)&thlds->spt_assoc_id;
5636224641Stuexen#ifdef INET
5637224641Stuexen				if (sa->sa_family == AF_INET) {
5638224641Stuexen
5639224641Stuexen					struct sockaddr_in *sin;
5640224641Stuexen
5641224641Stuexen					sin = (struct sockaddr_in *)sa;
5642224641Stuexen					if (sin->sin_addr.s_addr) {
5643224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5644224641Stuexen						SCTP_TCB_UNLOCK(stcb);
5645224641Stuexen						error = EINVAL;
5646224641Stuexen						break;
5647224641Stuexen					}
5648224641Stuexen				} else
5649224641Stuexen#endif
5650224641Stuexen#ifdef INET6
5651224641Stuexen				if (sa->sa_family == AF_INET6) {
5652224641Stuexen					struct sockaddr_in6 *sin6;
5653224641Stuexen
5654224641Stuexen					sin6 = (struct sockaddr_in6 *)sa;
5655224641Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
5656224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5657224641Stuexen						SCTP_TCB_UNLOCK(stcb);
5658224641Stuexen						error = EINVAL;
5659224641Stuexen						break;
5660224641Stuexen					}
5661224641Stuexen				} else
5662224641Stuexen#endif
5663224641Stuexen				{
5664224641Stuexen					error = EAFNOSUPPORT;
5665224641Stuexen					SCTP_TCB_UNLOCK(stcb);
5666224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5667224641Stuexen					break;
5668224641Stuexen				}
5669224641Stuexen			}
5670224641Stuexen			if (stcb) {
5671224641Stuexen				if (net) {
5672224641Stuexen					if (net->dest_state & SCTP_ADDR_PF) {
5673224641Stuexen						if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
5674224641Stuexen						    (net->failure_threshold <= thlds->spt_pathpfthld)) {
5675224641Stuexen							net->dest_state &= ~SCTP_ADDR_PF;
5676224641Stuexen						}
5677224641Stuexen					} else {
5678224641Stuexen						if ((net->failure_threshold > thlds->spt_pathpfthld) &&
5679224641Stuexen						    (net->failure_threshold <= thlds->spt_pathmaxrxt)) {
5680224641Stuexen							net->dest_state |= SCTP_ADDR_PF;
5681224641Stuexen							sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5682224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
5683224641Stuexen							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5684224641Stuexen						}
5685224641Stuexen					}
5686224641Stuexen					if (net->dest_state & SCTP_ADDR_REACHABLE) {
5687224641Stuexen						if (net->failure_threshold > thlds->spt_pathmaxrxt) {
5688224641Stuexen							net->dest_state &= ~SCTP_ADDR_REACHABLE;
5689235414Stuexen							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5690224641Stuexen						}
5691224641Stuexen					} else {
5692224641Stuexen						if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
5693224641Stuexen							net->dest_state |= SCTP_ADDR_REACHABLE;
5694235414Stuexen							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5695224641Stuexen						}
5696224641Stuexen					}
5697224641Stuexen					net->failure_threshold = thlds->spt_pathmaxrxt;
5698224641Stuexen					net->pf_threshold = thlds->spt_pathpfthld;
5699224641Stuexen				} else {
5700224641Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5701224641Stuexen						if (net->dest_state & SCTP_ADDR_PF) {
5702224641Stuexen							if ((net->failure_threshold > thlds->spt_pathmaxrxt) ||
5703224641Stuexen							    (net->failure_threshold <= thlds->spt_pathpfthld)) {
5704224641Stuexen								net->dest_state &= ~SCTP_ADDR_PF;
5705224641Stuexen							}
5706224641Stuexen						} else {
5707224641Stuexen							if ((net->failure_threshold > thlds->spt_pathpfthld) &&
5708224641Stuexen							    (net->failure_threshold <= thlds->spt_pathmaxrxt)) {
5709224641Stuexen								net->dest_state |= SCTP_ADDR_PF;
5710224641Stuexen								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5711224641Stuexen								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3);
5712224641Stuexen								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5713224641Stuexen							}
5714224641Stuexen						}
5715224641Stuexen						if (net->dest_state & SCTP_ADDR_REACHABLE) {
5716224641Stuexen							if (net->failure_threshold > thlds->spt_pathmaxrxt) {
5717224641Stuexen								net->dest_state &= ~SCTP_ADDR_REACHABLE;
5718235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5719224641Stuexen							}
5720224641Stuexen						} else {
5721224641Stuexen							if (net->failure_threshold <= thlds->spt_pathmaxrxt) {
5722224641Stuexen								net->dest_state |= SCTP_ADDR_REACHABLE;
5723235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5724224641Stuexen							}
5725224641Stuexen						}
5726224641Stuexen						net->failure_threshold = thlds->spt_pathmaxrxt;
5727224641Stuexen						net->pf_threshold = thlds->spt_pathpfthld;
5728224641Stuexen					}
5729224641Stuexen					stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
5730224641Stuexen					stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
5731224641Stuexen				}
5732224641Stuexen			} else {
5733224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5734224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5735224918Stuexen				    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
5736224641Stuexen					SCTP_INP_WLOCK(inp);
5737224641Stuexen					inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
5738224641Stuexen					inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
5739224641Stuexen					SCTP_INP_WUNLOCK(inp);
5740224641Stuexen				} else {
5741224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5742224641Stuexen					error = EINVAL;
5743224641Stuexen				}
5744224641Stuexen			}
5745224641Stuexen			break;
5746224641Stuexen		}
5747227755Stuexen	case SCTP_REMOTE_UDP_ENCAPS_PORT:
5748227755Stuexen		{
5749227755Stuexen			struct sctp_udpencaps *encaps;
5750227755Stuexen			struct sctp_nets *net;
5751227755Stuexen
5752227755Stuexen			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize);
5753227755Stuexen			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
5754227755Stuexen			if (stcb) {
5755227755Stuexen				net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address);
5756227755Stuexen			} else {
5757227755Stuexen				/*
5758227755Stuexen				 * We increment here since
5759227755Stuexen				 * sctp_findassociation_ep_addr() wil do a
5760227755Stuexen				 * decrement if it finds the stcb as long as
5761227755Stuexen				 * the locked tcb (last argument) is NOT a
5762227755Stuexen				 * TCB.. aka NULL.
5763227755Stuexen				 */
5764227755Stuexen				net = NULL;
5765227755Stuexen				SCTP_INP_INCR_REF(inp);
5766227755Stuexen				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL);
5767227755Stuexen				if (stcb == NULL) {
5768227755Stuexen					SCTP_INP_DECR_REF(inp);
5769227755Stuexen				}
5770227755Stuexen			}
5771227755Stuexen			if (stcb && (net == NULL)) {
5772227755Stuexen				struct sockaddr *sa;
5773227755Stuexen
5774227755Stuexen				sa = (struct sockaddr *)&encaps->sue_address;
5775227755Stuexen#ifdef INET
5776227755Stuexen				if (sa->sa_family == AF_INET) {
5777227755Stuexen
5778227755Stuexen					struct sockaddr_in *sin;
5779227755Stuexen
5780227755Stuexen					sin = (struct sockaddr_in *)sa;
5781227755Stuexen					if (sin->sin_addr.s_addr) {
5782227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5783227755Stuexen						SCTP_TCB_UNLOCK(stcb);
5784227755Stuexen						error = EINVAL;
5785227755Stuexen						break;
5786227755Stuexen					}
5787227755Stuexen				} else
5788227755Stuexen#endif
5789227755Stuexen#ifdef INET6
5790227755Stuexen				if (sa->sa_family == AF_INET6) {
5791227755Stuexen					struct sockaddr_in6 *sin6;
5792227755Stuexen
5793227755Stuexen					sin6 = (struct sockaddr_in6 *)sa;
5794227755Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
5795227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5796227755Stuexen						SCTP_TCB_UNLOCK(stcb);
5797227755Stuexen						error = EINVAL;
5798227755Stuexen						break;
5799227755Stuexen					}
5800227755Stuexen				} else
5801227755Stuexen#endif
5802227755Stuexen				{
5803227755Stuexen					error = EAFNOSUPPORT;
5804227755Stuexen					SCTP_TCB_UNLOCK(stcb);
5805227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5806227755Stuexen					break;
5807227755Stuexen				}
5808227755Stuexen			}
5809227755Stuexen			if (stcb) {
5810227755Stuexen				if (net) {
5811227755Stuexen					net->port = encaps->sue_port;
5812227755Stuexen				} else {
5813227755Stuexen					stcb->asoc.port = encaps->sue_port;
5814227755Stuexen				}
5815227755Stuexen				SCTP_TCB_UNLOCK(stcb);
5816227755Stuexen			} else {
5817227755Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5818227755Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5819227755Stuexen				    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
5820227755Stuexen					SCTP_INP_WLOCK(inp);
5821227755Stuexen					inp->sctp_ep.port = encaps->sue_port;
5822227755Stuexen					SCTP_INP_WUNLOCK(inp);
5823227755Stuexen				} else {
5824227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5825227755Stuexen					error = EINVAL;
5826227755Stuexen				}
5827227755Stuexen			}
5828227755Stuexen			break;
5829227755Stuexen		}
5830163953Srrs	default:
5831171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
5832163953Srrs		error = ENOPROTOOPT;
5833163953Srrs		break;
5834163953Srrs	}			/* end switch (opt) */
5835163953Srrs	return (error);
5836163953Srrs}
5837163953Srrs
5838163953Srrsint
5839163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt)
5840163953Srrs{
5841166675Srrs	void *optval = NULL;
5842166675Srrs	size_t optsize = 0;
5843166675Srrs	void *p;
5844166675Srrs	int error = 0;
5845163953Srrs
5846163953Srrs	if (sopt->sopt_level != IPPROTO_SCTP) {
5847163953Srrs		/* wrong proto level... send back up to IP */
5848163953Srrs#ifdef INET6
5849163953Srrs		if (INP_CHECK_SOCKAF(so, AF_INET6))
5850163953Srrs			error = ip6_ctloutput(so, sopt);
5851221249Stuexen#endif				/* INET6 */
5852237565Stuexen#if defined(INET) && defined(INET6)
5853163953Srrs		else
5854221249Stuexen#endif
5855221249Stuexen#ifdef INET
5856163953Srrs			error = ip_ctloutput(so, sopt);
5857221249Stuexen#endif
5858163953Srrs		return (error);
5859163953Srrs	}
5860166675Srrs	optsize = sopt->sopt_valsize;
5861166675Srrs	if (optsize) {
5862170091Srrs		SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
5863166675Srrs		if (optval == NULL) {
5864235091Stuexen			SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
5865163953Srrs			return (ENOBUFS);
5866163953Srrs		}
5867166675Srrs		error = sooptcopyin(sopt, optval, optsize, optsize);
5868163953Srrs		if (error) {
5869170091Srrs			SCTP_FREE(optval, SCTP_M_SOCKOPT);
5870163953Srrs			goto out;
5871163953Srrs		}
5872163953Srrs	}
5873166675Srrs	p = (void *)sopt->sopt_td;
5874163953Srrs	if (sopt->sopt_dir == SOPT_SET) {
5875166675Srrs		error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
5876163953Srrs	} else if (sopt->sopt_dir == SOPT_GET) {
5877166675Srrs		error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
5878163953Srrs	} else {
5879235091Stuexen		SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5880163953Srrs		error = EINVAL;
5881163953Srrs	}
5882166675Srrs	if ((error == 0) && (optval != NULL)) {
5883166675Srrs		error = sooptcopyout(sopt, optval, optsize);
5884170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
5885166675Srrs	} else if (optval != NULL) {
5886170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
5887163953Srrs	}
5888163953Srrsout:
5889163953Srrs	return (error);
5890163953Srrs}
5891163953Srrs
5892221249Stuexen#ifdef INET
5893163953Srrsstatic int
5894163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
5895163953Srrs{
5896163953Srrs	int error = 0;
5897163953Srrs	int create_lock_on = 0;
5898167598Srrs	uint32_t vrf_id;
5899163953Srrs	struct sctp_inpcb *inp;
5900163953Srrs	struct sctp_tcb *stcb = NULL;
5901163953Srrs
5902163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
5903233005Stuexen	if (inp == NULL) {
5904163953Srrs		/* I made the same as TCP since we are not setup? */
5905171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5906163953Srrs		return (ECONNRESET);
5907163953Srrs	}
5908171943Srrs	if (addr == NULL) {
5909171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5910170056Srrs		return EINVAL;
5911171943Srrs	}
5912221249Stuexen	switch (addr->sa_family) {
5913185435Sbz#ifdef INET6
5914221249Stuexen	case AF_INET6:
5915221249Stuexen		{
5916221249Stuexen			struct sockaddr_in6 *sin6p;
5917185694Srrs
5918221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
5919221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5920221249Stuexen				return (EINVAL);
5921221249Stuexen			}
5922221249Stuexen			sin6p = (struct sockaddr_in6 *)addr;
5923221249Stuexen			if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
5924221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5925221249Stuexen				return (error);
5926221249Stuexen			}
5927221249Stuexen			break;
5928185435Sbz		}
5929185435Sbz#endif
5930221249Stuexen#ifdef INET
5931221249Stuexen	case AF_INET:
5932221249Stuexen		{
5933221249Stuexen			struct sockaddr_in *sinp;
5934185694Srrs
5935221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
5936221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5937221249Stuexen				return (EINVAL);
5938221249Stuexen			}
5939221249Stuexen			sinp = (struct sockaddr_in *)addr;
5940221249Stuexen			if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) {
5941221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5942221249Stuexen				return (error);
5943221249Stuexen			}
5944221249Stuexen			break;
5945185435Sbz		}
5946221249Stuexen#endif
5947221249Stuexen	default:
5948185435Sbz		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
5949185435Sbz		return (EAFNOSUPPORT);
5950170056Srrs	}
5951178202Srrs	SCTP_INP_INCR_REF(inp);
5952163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
5953163953Srrs	create_lock_on = 1;
5954163953Srrs
5955178202Srrs
5956163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
5957163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
5958163953Srrs		/* Should I really unlock ? */
5959171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
5960163953Srrs		error = EFAULT;
5961163953Srrs		goto out_now;
5962163953Srrs	}
5963163953Srrs#ifdef INET6
5964163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
5965163953Srrs	    (addr->sa_family == AF_INET6)) {
5966171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5967163953Srrs		error = EINVAL;
5968163953Srrs		goto out_now;
5969163953Srrs	}
5970246595Stuexen#endif
5971163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
5972163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
5973163953Srrs		/* Bind a ephemeral port */
5974171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
5975163953Srrs		if (error) {
5976163953Srrs			goto out_now;
5977163953Srrs		}
5978163953Srrs	}
5979163953Srrs	/* Now do we connect? */
5980181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
5981181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
5982171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5983163953Srrs		error = EINVAL;
5984163953Srrs		goto out_now;
5985163953Srrs	}
5986163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
5987163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
5988163953Srrs		/* We are already connected AND the TCP model */
5989171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
5990163953Srrs		error = EADDRINUSE;
5991163953Srrs		goto out_now;
5992163953Srrs	}
5993163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
5994163953Srrs		SCTP_INP_RLOCK(inp);
5995163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
5996163953Srrs		SCTP_INP_RUNLOCK(inp);
5997163953Srrs	} else {
5998163953Srrs		/*
5999166675Srrs		 * We increment here since sctp_findassociation_ep_addr()
6000181054Srrs		 * will do a decrement if it finds the stcb as long as the
6001166675Srrs		 * locked tcb (last argument) is NOT a TCB.. aka NULL.
6002163953Srrs		 */
6003163953Srrs		SCTP_INP_INCR_REF(inp);
6004163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
6005163953Srrs		if (stcb == NULL) {
6006163953Srrs			SCTP_INP_DECR_REF(inp);
6007168299Srrs		} else {
6008178202Srrs			SCTP_TCB_UNLOCK(stcb);
6009163953Srrs		}
6010163953Srrs	}
6011163953Srrs	if (stcb != NULL) {
6012163953Srrs		/* Already have or am bring up an association */
6013171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
6014163953Srrs		error = EALREADY;
6015163953Srrs		goto out_now;
6016163953Srrs	}
6017168299Srrs	vrf_id = inp->def_vrf_id;
6018163953Srrs	/* We are GOOD to go */
6019206137Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
6020163953Srrs	if (stcb == NULL) {
6021163953Srrs		/* Gak! no memory */
6022167598Srrs		goto out_now;
6023163953Srrs	}
6024163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
6025163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
6026163953Srrs		/* Set the connected flag so we can queue data */
6027163953Srrs		soisconnecting(so);
6028163953Srrs	}
6029171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
6030169378Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
6031163953Srrs
6032163953Srrs	/* initialize authentication parameters for the assoc */
6033163953Srrs	sctp_initialize_auth_params(inp, stcb);
6034163953Srrs
6035172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
6036168299Srrs	SCTP_TCB_UNLOCK(stcb);
6037163953Srrsout_now:
6038169420Srrs	if (create_lock_on) {
6039163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
6040169420Srrs	}
6041163953Srrs	SCTP_INP_DECR_REF(inp);
6042228907Stuexen	return (error);
6043163953Srrs}
6044163953Srrs
6045221249Stuexen#endif
6046221249Stuexen
6047163953Srrsint
6048163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p)
6049163953Srrs{
6050163953Srrs	/*
6051163953Srrs	 * Note this module depends on the protocol processing being called
6052163953Srrs	 * AFTER any socket level flags and backlog are applied to the
6053163953Srrs	 * socket. The traditional way that the socket flags are applied is
6054163953Srrs	 * AFTER protocol processing. We have made a change to the
6055163953Srrs	 * sys/kern/uipc_socket.c module to reverse this but this MUST be in
6056163953Srrs	 * place if the socket API for SCTP is to work properly.
6057163953Srrs	 */
6058163953Srrs
6059163953Srrs	int error = 0;
6060163953Srrs	struct sctp_inpcb *inp;
6061163953Srrs
6062163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6063233005Stuexen	if (inp == NULL) {
6064163953Srrs		/* I made the same as TCP since we are not setup? */
6065171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6066163953Srrs		return (ECONNRESET);
6067163953Srrs	}
6068181054Srrs	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
6069181054Srrs		/* See if we have a listener */
6070181054Srrs		struct sctp_inpcb *tinp;
6071181054Srrs		union sctp_sockstore store, *sp;
6072181054Srrs
6073181054Srrs		sp = &store;
6074181054Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
6075181054Srrs			/* not bound all */
6076181054Srrs			struct sctp_laddr *laddr;
6077181054Srrs
6078181054Srrs			LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
6079181054Srrs				memcpy(&store, &laddr->ifa->address, sizeof(store));
6080221249Stuexen				switch (sp->sa.sa_family) {
6081221249Stuexen#ifdef INET
6082221249Stuexen				case AF_INET:
6083221249Stuexen					sp->sin.sin_port = inp->sctp_lport;
6084221249Stuexen					break;
6085221249Stuexen#endif
6086221249Stuexen#ifdef INET6
6087221249Stuexen				case AF_INET6:
6088221249Stuexen					sp->sin6.sin6_port = inp->sctp_lport;
6089221249Stuexen					break;
6090221249Stuexen#endif
6091221249Stuexen				default:
6092221249Stuexen					break;
6093221249Stuexen				}
6094181054Srrs				tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id);
6095181054Srrs				if (tinp && (tinp != inp) &&
6096181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
6097181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
6098181054Srrs				    (tinp->sctp_socket->so_qlimit)) {
6099181054Srrs					/*
6100181054Srrs					 * we have a listener already and
6101181054Srrs					 * its not this inp.
6102181054Srrs					 */
6103181054Srrs					SCTP_INP_DECR_REF(tinp);
6104181054Srrs					return (EADDRINUSE);
6105181054Srrs				} else if (tinp) {
6106181054Srrs					SCTP_INP_DECR_REF(tinp);
6107181054Srrs				}
6108181054Srrs			}
6109181054Srrs		} else {
6110181054Srrs			/* Setup a local addr bound all */
6111181054Srrs			memset(&store, 0, sizeof(store));
6112221249Stuexen			switch (sp->sa.sa_family) {
6113221249Stuexen#ifdef INET
6114221249Stuexen			case AF_INET:
6115221249Stuexen				store.sin.sin_port = inp->sctp_lport;
6116221249Stuexen				break;
6117221249Stuexen#endif
6118181054Srrs#ifdef INET6
6119221249Stuexen			case AF_INET6:
6120221249Stuexen				sp->sin6.sin6_port = inp->sctp_lport;
6121221249Stuexen				break;
6122221249Stuexen#endif
6123221249Stuexen			default:
6124221249Stuexen				break;
6125221249Stuexen			}
6126221249Stuexen#ifdef INET6
6127181054Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
6128181054Srrs				store.sa.sa_family = AF_INET6;
6129181054Srrs				store.sa.sa_len = sizeof(struct sockaddr_in6);
6130181054Srrs			}
6131181054Srrs#endif
6132221249Stuexen#ifdef INET
6133181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
6134181054Srrs				store.sa.sa_family = AF_INET;
6135181054Srrs				store.sa.sa_len = sizeof(struct sockaddr_in);
6136181054Srrs			}
6137221249Stuexen#endif
6138181054Srrs			tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id);
6139181054Srrs			if (tinp && (tinp != inp) &&
6140181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
6141181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
6142181054Srrs			    (tinp->sctp_socket->so_qlimit)) {
6143181054Srrs				/*
6144181054Srrs				 * we have a listener already and its not
6145181054Srrs				 * this inp.
6146181054Srrs				 */
6147181054Srrs				SCTP_INP_DECR_REF(tinp);
6148181054Srrs				return (EADDRINUSE);
6149181054Srrs			} else if (tinp) {
6150181054Srrs				SCTP_INP_DECR_REF(inp);
6151181054Srrs			}
6152181054Srrs		}
6153181054Srrs	}
6154163953Srrs	SCTP_INP_RLOCK(inp);
6155163953Srrs#ifdef SCTP_LOCK_LOGGING
6156179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
6157170744Srrs		sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
6158170744Srrs	}
6159163953Srrs#endif
6160163953Srrs	SOCK_LOCK(so);
6161163953Srrs	error = solisten_proto_check(so);
6162163953Srrs	if (error) {
6163163953Srrs		SOCK_UNLOCK(so);
6164169208Srrs		SCTP_INP_RUNLOCK(inp);
6165163953Srrs		return (error);
6166163953Srrs	}
6167181054Srrs	if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
6168181054Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
6169181054Srrs		/*
6170181054Srrs		 * The unlucky case - We are in the tcp pool with this guy.
6171181054Srrs		 * - Someone else is in the main inp slot. - We must move
6172181054Srrs		 * this guy (the listener) to the main slot - We must then
6173181054Srrs		 * move the guy that was listener to the TCP Pool.
6174181054Srrs		 */
6175181054Srrs		if (sctp_swap_inpcb_for_listen(inp)) {
6176181054Srrs			goto in_use;
6177181054Srrs		}
6178181054Srrs	}
6179163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
6180163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
6181163953Srrs		/* We are already connected AND the TCP model */
6182181054Srrsin_use:
6183163953Srrs		SCTP_INP_RUNLOCK(inp);
6184163953Srrs		SOCK_UNLOCK(so);
6185171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
6186163953Srrs		return (EADDRINUSE);
6187163953Srrs	}
6188181054Srrs	SCTP_INP_RUNLOCK(inp);
6189163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
6190163953Srrs		/* We must do a bind. */
6191166675Srrs		SOCK_UNLOCK(so);
6192171572Srrs		if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
6193163953Srrs			/* bind error, probably perm */
6194163953Srrs			return (error);
6195163953Srrs		}
6196166675Srrs		SOCK_LOCK(so);
6197163953Srrs	}
6198163953Srrs	/* It appears for 7.0 and on, we must always call this. */
6199163953Srrs	solisten_proto(so, backlog);
6200163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
6201163953Srrs		/* remove the ACCEPTCONN flag for one-to-many sockets */
6202163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
6203163953Srrs	}
6204163953Srrs	if (backlog == 0) {
6205163953Srrs		/* turning off listen */
6206163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
6207163953Srrs	}
6208163953Srrs	SOCK_UNLOCK(so);
6209163953Srrs	return (error);
6210163953Srrs}
6211163953Srrs
6212163953Srrsstatic int sctp_defered_wakeup_cnt = 0;
6213163953Srrs
6214163953Srrsint
6215163953Srrssctp_accept(struct socket *so, struct sockaddr **addr)
6216163953Srrs{
6217163953Srrs	struct sctp_tcb *stcb;
6218163953Srrs	struct sctp_inpcb *inp;
6219163953Srrs	union sctp_sockstore store;
6220163953Srrs
6221178251Srrs#ifdef INET6
6222163953Srrs	int error;
6223163953Srrs
6224178251Srrs#endif
6225163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6226163953Srrs
6227233005Stuexen	if (inp == NULL) {
6228171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6229163953Srrs		return (ECONNRESET);
6230163953Srrs	}
6231163953Srrs	SCTP_INP_RLOCK(inp);
6232163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
6233168299Srrs		SCTP_INP_RUNLOCK(inp);
6234171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
6235171943Srrs		return (EOPNOTSUPP);
6236163953Srrs	}
6237163953Srrs	if (so->so_state & SS_ISDISCONNECTED) {
6238163953Srrs		SCTP_INP_RUNLOCK(inp);
6239171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
6240163953Srrs		return (ECONNABORTED);
6241163953Srrs	}
6242163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
6243163953Srrs	if (stcb == NULL) {
6244163953Srrs		SCTP_INP_RUNLOCK(inp);
6245171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6246163953Srrs		return (ECONNRESET);
6247163953Srrs	}
6248163953Srrs	SCTP_TCB_LOCK(stcb);
6249163953Srrs	SCTP_INP_RUNLOCK(inp);
6250163953Srrs	store = stcb->asoc.primary_destination->ro._l_addr;
6251207924Srrs	stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
6252163953Srrs	SCTP_TCB_UNLOCK(stcb);
6253178251Srrs	switch (store.sa.sa_family) {
6254221249Stuexen#ifdef INET
6255178251Srrs	case AF_INET:
6256178251Srrs		{
6257178251Srrs			struct sockaddr_in *sin;
6258163953Srrs
6259178251Srrs			SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
6260208863Srrs			if (sin == NULL)
6261208863Srrs				return (ENOMEM);
6262178251Srrs			sin->sin_family = AF_INET;
6263178251Srrs			sin->sin_len = sizeof(*sin);
6264246595Stuexen			sin->sin_port = store.sin.sin_port;
6265246595Stuexen			sin->sin_addr = store.sin.sin_addr;
6266178251Srrs			*addr = (struct sockaddr *)sin;
6267178251Srrs			break;
6268178251Srrs		}
6269221249Stuexen#endif
6270178251Srrs#ifdef INET6
6271178251Srrs	case AF_INET6:
6272178251Srrs		{
6273178251Srrs			struct sockaddr_in6 *sin6;
6274163953Srrs
6275178251Srrs			SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
6276208863Srrs			if (sin6 == NULL)
6277208863Srrs				return (ENOMEM);
6278178251Srrs			sin6->sin6_family = AF_INET6;
6279178251Srrs			sin6->sin6_len = sizeof(*sin6);
6280246595Stuexen			sin6->sin6_port = store.sin6.sin6_port;
6281246595Stuexen			sin6->sin6_addr = store.sin6.sin6_addr;
6282178251Srrs			if ((error = sa6_recoverscope(sin6)) != 0) {
6283178251Srrs				SCTP_FREE_SONAME(sin6);
6284178251Srrs				return (error);
6285178251Srrs			}
6286178251Srrs			*addr = (struct sockaddr *)sin6;
6287178251Srrs			break;
6288164085Srrs		}
6289178251Srrs#endif
6290178251Srrs	default:
6291178251Srrs		/* TSNH */
6292178251Srrs		break;
6293163953Srrs	}
6294163953Srrs	/* Wake any delayed sleep action */
6295163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
6296166086Srrs		SCTP_INP_WLOCK(inp);
6297163953Srrs		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
6298163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
6299163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
6300166086Srrs			SCTP_INP_WUNLOCK(inp);
6301163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
6302163953Srrs			if (sowriteable(inp->sctp_socket)) {
6303163953Srrs				sowwakeup_locked(inp->sctp_socket);
6304163953Srrs			} else {
6305163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
6306163953Srrs			}
6307166086Srrs			SCTP_INP_WLOCK(inp);
6308163953Srrs		}
6309163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
6310163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
6311166086Srrs			SCTP_INP_WUNLOCK(inp);
6312163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
6313163953Srrs			if (soreadable(inp->sctp_socket)) {
6314163953Srrs				sctp_defered_wakeup_cnt++;
6315163953Srrs				sorwakeup_locked(inp->sctp_socket);
6316163953Srrs			} else {
6317163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
6318163953Srrs			}
6319166086Srrs			SCTP_INP_WLOCK(inp);
6320163953Srrs		}
6321166086Srrs		SCTP_INP_WUNLOCK(inp);
6322163953Srrs	}
6323207924Srrs	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
6324207924Srrs		SCTP_TCB_LOCK(stcb);
6325207924Srrs		sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
6326207924Srrs	}
6327163953Srrs	return (0);
6328163953Srrs}
6329163953Srrs
6330221249Stuexen#ifdef INET
6331163953Srrsint
6332163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr)
6333163953Srrs{
6334163953Srrs	struct sockaddr_in *sin;
6335167598Srrs	uint32_t vrf_id;
6336163953Srrs	struct sctp_inpcb *inp;
6337167695Srrs	struct sctp_ifa *sctp_ifa;
6338163953Srrs
6339163953Srrs	/*
6340163953Srrs	 * Do the malloc first in case it blocks.
6341163953Srrs	 */
6342163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
6343208863Srrs	if (sin == NULL)
6344208863Srrs		return (ENOMEM);
6345163953Srrs	sin->sin_family = AF_INET;
6346163953Srrs	sin->sin_len = sizeof(*sin);
6347163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6348163953Srrs	if (!inp) {
6349163953Srrs		SCTP_FREE_SONAME(sin);
6350171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6351228907Stuexen		return (ECONNRESET);
6352163953Srrs	}
6353163953Srrs	SCTP_INP_RLOCK(inp);
6354163953Srrs	sin->sin_port = inp->sctp_lport;
6355163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
6356163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
6357163953Srrs			struct sctp_tcb *stcb;
6358163953Srrs			struct sockaddr_in *sin_a;
6359163953Srrs			struct sctp_nets *net;
6360163953Srrs			int fnd;
6361163953Srrs
6362163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
6363163953Srrs			if (stcb == NULL) {
6364163953Srrs				goto notConn;
6365163953Srrs			}
6366163953Srrs			fnd = 0;
6367163953Srrs			sin_a = NULL;
6368163953Srrs			SCTP_TCB_LOCK(stcb);
6369163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6370163953Srrs				sin_a = (struct sockaddr_in *)&net->ro._l_addr;
6371164085Srrs				if (sin_a == NULL)
6372164085Srrs					/* this will make coverity happy */
6373164085Srrs					continue;
6374164085Srrs
6375163953Srrs				if (sin_a->sin_family == AF_INET) {
6376163953Srrs					fnd = 1;
6377163953Srrs					break;
6378163953Srrs				}
6379163953Srrs			}
6380163953Srrs			if ((!fnd) || (sin_a == NULL)) {
6381163953Srrs				/* punt */
6382163953Srrs				SCTP_TCB_UNLOCK(stcb);
6383163953Srrs				goto notConn;
6384163953Srrs			}
6385168299Srrs			vrf_id = inp->def_vrf_id;
6386167598Srrs			sctp_ifa = sctp_source_address_selection(inp,
6387167598Srrs			    stcb,
6388168299Srrs			    (sctp_route_t *) & net->ro,
6389167598Srrs			    net, 0, vrf_id);
6390167598Srrs			if (sctp_ifa) {
6391167598Srrs				sin->sin_addr = sctp_ifa->address.sin.sin_addr;
6392167598Srrs				sctp_free_ifa(sctp_ifa);
6393167598Srrs			}
6394163953Srrs			SCTP_TCB_UNLOCK(stcb);
6395163953Srrs		} else {
6396163953Srrs			/* For the bound all case you get back 0 */
6397163953Srrs	notConn:
6398163953Srrs			sin->sin_addr.s_addr = 0;
6399163953Srrs		}
6400163953Srrs
6401163953Srrs	} else {
6402163953Srrs		/* Take the first IPv4 address in the list */
6403163953Srrs		struct sctp_laddr *laddr;
6404163953Srrs		int fnd = 0;
6405163953Srrs
6406163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
6407167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET) {
6408163953Srrs				struct sockaddr_in *sin_a;
6409163953Srrs
6410167598Srrs				sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa;
6411163953Srrs				sin->sin_addr = sin_a->sin_addr;
6412163953Srrs				fnd = 1;
6413163953Srrs				break;
6414163953Srrs			}
6415163953Srrs		}
6416163953Srrs		if (!fnd) {
6417163953Srrs			SCTP_FREE_SONAME(sin);
6418163953Srrs			SCTP_INP_RUNLOCK(inp);
6419171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
6420228907Stuexen			return (ENOENT);
6421163953Srrs		}
6422163953Srrs	}
6423163953Srrs	SCTP_INP_RUNLOCK(inp);
6424163953Srrs	(*addr) = (struct sockaddr *)sin;
6425163953Srrs	return (0);
6426163953Srrs}
6427163953Srrs
6428163953Srrsint
6429163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr)
6430163953Srrs{
6431231895Stuexen	struct sockaddr_in *sin;
6432166086Srrs	int fnd;
6433163953Srrs	struct sockaddr_in *sin_a;
6434163953Srrs	struct sctp_inpcb *inp;
6435163953Srrs	struct sctp_tcb *stcb;
6436163953Srrs	struct sctp_nets *net;
6437163953Srrs
6438163953Srrs	/* Do the malloc first in case it blocks. */
6439163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
6440208863Srrs	if (sin == NULL)
6441208863Srrs		return (ENOMEM);
6442163953Srrs	sin->sin_family = AF_INET;
6443163953Srrs	sin->sin_len = sizeof(*sin);
6444163953Srrs
6445163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6446228907Stuexen	if ((inp == NULL) ||
6447228907Stuexen	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
6448228907Stuexen		/* UDP type and listeners will drop out here */
6449163953Srrs		SCTP_FREE_SONAME(sin);
6450228907Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
6451228907Stuexen		return (ENOTCONN);
6452163953Srrs	}
6453163953Srrs	SCTP_INP_RLOCK(inp);
6454163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
6455169420Srrs	if (stcb) {
6456163953Srrs		SCTP_TCB_LOCK(stcb);
6457169420Srrs	}
6458163953Srrs	SCTP_INP_RUNLOCK(inp);
6459163953Srrs	if (stcb == NULL) {
6460163953Srrs		SCTP_FREE_SONAME(sin);
6461171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6462228907Stuexen		return (ECONNRESET);
6463163953Srrs	}
6464163953Srrs	fnd = 0;
6465163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6466163953Srrs		sin_a = (struct sockaddr_in *)&net->ro._l_addr;
6467163953Srrs		if (sin_a->sin_family == AF_INET) {
6468163953Srrs			fnd = 1;
6469163953Srrs			sin->sin_port = stcb->rport;
6470163953Srrs			sin->sin_addr = sin_a->sin_addr;
6471163953Srrs			break;
6472163953Srrs		}
6473163953Srrs	}
6474163953Srrs	SCTP_TCB_UNLOCK(stcb);
6475163953Srrs	if (!fnd) {
6476163953Srrs		/* No IPv4 address */
6477163953Srrs		SCTP_FREE_SONAME(sin);
6478171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
6479228907Stuexen		return (ENOENT);
6480163953Srrs	}
6481163953Srrs	(*addr) = (struct sockaddr *)sin;
6482163953Srrs	return (0);
6483163953Srrs}
6484163953Srrs
6485163953Srrsstruct pr_usrreqs sctp_usrreqs = {
6486163953Srrs	.pru_abort = sctp_abort,
6487163953Srrs	.pru_accept = sctp_accept,
6488163953Srrs	.pru_attach = sctp_attach,
6489163953Srrs	.pru_bind = sctp_bind,
6490163953Srrs	.pru_connect = sctp_connect,
6491163953Srrs	.pru_control = in_control,
6492163953Srrs	.pru_close = sctp_close,
6493163953Srrs	.pru_detach = sctp_close,
6494163953Srrs	.pru_sopoll = sopoll_generic,
6495178202Srrs	.pru_flush = sctp_flush,
6496163953Srrs	.pru_disconnect = sctp_disconnect,
6497163953Srrs	.pru_listen = sctp_listen,
6498163953Srrs	.pru_peeraddr = sctp_peeraddr,
6499163953Srrs	.pru_send = sctp_sendm,
6500163953Srrs	.pru_shutdown = sctp_shutdown,
6501163953Srrs	.pru_sockaddr = sctp_ingetaddr,
6502163953Srrs	.pru_sosend = sctp_sosend,
6503163953Srrs	.pru_soreceive = sctp_soreceive
6504163953Srrs};
6505221249Stuexen
6506221249Stuexen#endif
6507