sctp_usrreq.c revision 294222
1163953Srrs/*-
2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5163953Srrs *
6163953Srrs * Redistribution and use in source and binary forms, with or without
7163953Srrs * modification, are permitted provided that the following conditions are met:
8163953Srrs *
9163953Srrs * a) Redistributions of source code must retain the above copyright notice,
10228653Stuexen *    this list of conditions and the following disclaimer.
11163953Srrs *
12163953Srrs * b) Redistributions in binary form must reproduce the above copyright
13163953Srrs *    notice, this list of conditions and the following disclaimer in
14228653Stuexen *    the documentation and/or other materials provided with the distribution.
15163953Srrs *
16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
17163953Srrs *    contributors may be used to endorse or promote products derived
18163953Srrs *    from this software without specific prior written permission.
19163953Srrs *
20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
31163953Srrs */
32163953Srrs
33163953Srrs#include <sys/cdefs.h>
34163953Srrs__FBSDID("$FreeBSD: stable/10/sys/netinet/sctp_usrreq.c 294222 2016-01-17 14:10:37Z 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
42283699Stuexen#include <netinet6/sctp6_var.h>
43167695Srrs#endif
44167598Srrs#include <netinet/sctp_sysctl.h>
45163953Srrs#include <netinet/sctp_output.h>
46163953Srrs#include <netinet/sctp_uio.h>
47163953Srrs#include <netinet/sctp_asconf.h>
48163953Srrs#include <netinet/sctputil.h>
49163953Srrs#include <netinet/sctp_indata.h>
50163953Srrs#include <netinet/sctp_timer.h>
51163953Srrs#include <netinet/sctp_auth.h>
52170091Srrs#include <netinet/sctp_bsd_addr.h>
53185694Srrs#include <netinet/udp.h>
54164085Srrs
55163953Srrs
56163953Srrs
57217611Stuexenextern struct sctp_cc_functions sctp_cc_functions[];
58217760Stuexenextern struct sctp_ss_functions sctp_ss_functions[];
59170091Srrs
60163953Srrsvoid
61163953Srrssctp_init(void)
62163953Srrs{
63163953Srrs	u_long sb_max_adj;
64163953Srrs
65179783Srrs	/* Initialize and modify the sysctled variables */
66179783Srrs	sctp_init_sysctls();
67163953Srrs	if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
68179783Srrs		SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8);
69163953Srrs	/*
70163953Srrs	 * Allow a user to take no more than 1/2 the number of clusters or
71163953Srrs	 * the SB_MAX whichever is smaller for the send window.
72163953Srrs	 */
73163953Srrs	sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
74179783Srrs	SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj,
75170056Srrs	    (((uint32_t) nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
76163953Srrs	/*
77163953Srrs	 * Now for the recv window, should we take the same amount? or
78163953Srrs	 * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
79163953Srrs	 * now I will just copy.
80163953Srrs	 */
81179783Srrs	SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace);
82179783Srrs	SCTP_BASE_VAR(first_time) = 0;
83179783Srrs	SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
84179783Srrs	sctp_pcb_init();
85179783Srrs#if defined(SCTP_PACKET_LOGGING)
86179783Srrs	SCTP_BASE_VAR(packet_log_writers) = 0;
87179783Srrs	SCTP_BASE_VAR(packet_log_end) = 0;
88179783Srrs	bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE);
89179783Srrs#endif
90163953Srrs}
91163953Srrs
92179783Srrsvoid
93179783Srrssctp_finish(void)
94179783Srrs{
95179783Srrs	sctp_pcb_finish();
96179783Srrs}
97163953Srrs
98166023Srrs
99163953Srrs
100179157Srrsvoid
101228653Stuexensctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz)
102163953Srrs{
103163953Srrs	struct sctp_tmit_chunk *chk;
104197257Stuexen	uint16_t overhead;
105163953Srrs
106163953Srrs	/* Adjust that too */
107163953Srrs	stcb->asoc.smallest_mtu = nxtsz;
108163953Srrs	/* now off to subtract IP_DF flag if needed */
109197257Stuexen	overhead = IP_HDR_SIZE;
110197257Stuexen	if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
111197257Stuexen		overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id);
112197257Stuexen	}
113163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
114197257Stuexen		if ((chk->send_size + overhead) > nxtsz) {
115163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
116163953Srrs		}
117163953Srrs	}
118163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
119197257Stuexen		if ((chk->send_size + overhead) > nxtsz) {
120163953Srrs			/*
121163953Srrs			 * For this guy we also mark for immediate resend
122163953Srrs			 * since we sent to big of chunk
123163953Srrs			 */
124163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
125190689Srrs			if (chk->sent < SCTP_DATAGRAM_RESEND) {
126190689Srrs				sctp_flight_size_decrease(chk);
127190689Srrs				sctp_total_flight_decrease(stcb, chk);
128283729Stuexen				chk->sent = SCTP_DATAGRAM_RESEND;
129163953Srrs				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
130283729Stuexen				chk->rec.data.doing_fast_retransmit = 0;
131283729Stuexen				if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
132283729Stuexen					sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
133283729Stuexen					    chk->whoTo->flight_size,
134283729Stuexen					    chk->book_size,
135283729Stuexen					    (uintptr_t) chk->whoTo,
136283729Stuexen					    chk->rec.data.TSN_seq);
137283729Stuexen				}
138283729Stuexen				/* Clear any time so NO RTT is being done */
139283729Stuexen				chk->do_rtt = 0;
140163953Srrs			}
141163953Srrs		}
142163953Srrs	}
143163953Srrs}
144163953Srrs
145221249Stuexen#ifdef INET
146163953Srrsstatic void
147163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp,
148163953Srrs    struct sctp_tcb *stcb,
149163953Srrs    struct sctp_nets *net,
150163953Srrs    struct ip *ip,
151163953Srrs    struct sctphdr *sh)
152163953Srrs{
153163953Srrs	struct icmp *icmph;
154163953Srrs	int totsz, tmr_stopped = 0;
155163953Srrs	uint16_t nxtsz;
156163953Srrs
157163953Srrs	/* protection */
158163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
159163953Srrs	    (ip == NULL) || (sh == NULL)) {
160169420Srrs		if (stcb != NULL) {
161163953Srrs			SCTP_TCB_UNLOCK(stcb);
162169420Srrs		}
163163953Srrs		return;
164163953Srrs	}
165163953Srrs	/* First job is to verify the vtag matches what I would send */
166163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
167163953Srrs		SCTP_TCB_UNLOCK(stcb);
168163953Srrs		return;
169163953Srrs	}
170163953Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
171163953Srrs	    sizeof(struct ip)));
172163953Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
173163953Srrs		/* We only care about unreachable */
174163953Srrs		SCTP_TCB_UNLOCK(stcb);
175163953Srrs		return;
176163953Srrs	}
177163953Srrs	if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
178163953Srrs		/* not a unreachable message due to frag. */
179163953Srrs		SCTP_TCB_UNLOCK(stcb);
180163953Srrs		return;
181163953Srrs	}
182241913Sglebius	totsz = ntohs(ip->ip_len);
183163953Srrs
184171943Srrs	nxtsz = ntohs(icmph->icmp_nextmtu);
185163953Srrs	if (nxtsz == 0) {
186163953Srrs		/*
187163953Srrs		 * old type router that does not tell us what the next size
188163953Srrs		 * mtu is. Rats we will have to guess (in a educated fashion
189163953Srrs		 * of course)
190163953Srrs		 */
191214939Stuexen		nxtsz = sctp_get_prev_mtu(totsz);
192163953Srrs	}
193163953Srrs	/* Stop any PMTU timer */
194165647Srrs	if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
195163953Srrs		tmr_stopped = 1;
196165220Srrs		sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
197165220Srrs		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
198163953Srrs	}
199163953Srrs	/* Adjust destination size limit */
200163953Srrs	if (net->mtu > nxtsz) {
201163953Srrs		net->mtu = nxtsz;
202185694Srrs		if (net->port) {
203185694Srrs			net->mtu -= sizeof(struct udphdr);
204185694Srrs		}
205163953Srrs	}
206163953Srrs	/* now what about the ep? */
207163953Srrs	if (stcb->asoc.smallest_mtu > nxtsz) {
208228653Stuexen		sctp_pathmtu_adjustment(stcb, nxtsz);
209163953Srrs	}
210163953Srrs	if (tmr_stopped)
211163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
212163953Srrs
213163953Srrs	SCTP_TCB_UNLOCK(stcb);
214163953Srrs}
215163953Srrs
216163953Srrsvoid
217163953Srrssctp_notify(struct sctp_inpcb *inp,
218172091Srrs    struct ip *ip,
219163953Srrs    struct sctphdr *sh,
220163953Srrs    struct sockaddr *to,
221163953Srrs    struct sctp_tcb *stcb,
222163953Srrs    struct sctp_nets *net)
223163953Srrs{
224237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
225172090Srrs	struct socket *so;
226172090Srrs
227172090Srrs#endif
228172091Srrs	struct icmp *icmph;
229172091Srrs
230235360Stuexen	/* protection */
231163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
232163953Srrs	    (sh == NULL) || (to == NULL)) {
233172091Srrs		if (stcb)
234172091Srrs			SCTP_TCB_UNLOCK(stcb);
235163953Srrs		return;
236163953Srrs	}
237163953Srrs	/* First job is to verify the vtag matches what I would send */
238163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
239172091Srrs		SCTP_TCB_UNLOCK(stcb);
240163953Srrs		return;
241163953Srrs	}
242172091Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
243172091Srrs	    sizeof(struct ip)));
244172091Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
245172091Srrs		/* We only care about unreachable */
246172091Srrs		SCTP_TCB_UNLOCK(stcb);
247172091Srrs		return;
248172091Srrs	}
249172091Srrs	if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
250172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST) ||
251172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
252172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
253172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
254172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
255172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
256172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
257163953Srrs
258163953Srrs		/*
259163953Srrs		 * Hmm reachablity problems we must examine closely. If its
260163953Srrs		 * not reachable, we may have lost a network. Or if there is
261163953Srrs		 * NO protocol at the other end named SCTP. well we consider
262163953Srrs		 * it a OOTB abort.
263163953Srrs		 */
264172091Srrs		if (net->dest_state & SCTP_ADDR_REACHABLE) {
265172091Srrs			/* Ok that destination is NOT reachable */
266172091Srrs			net->dest_state &= ~SCTP_ADDR_REACHABLE;
267224641Stuexen			net->dest_state &= ~SCTP_ADDR_PF;
268172091Srrs			sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
269235414Stuexen			    stcb, 0,
270172091Srrs			    (void *)net, SCTP_SO_NOT_LOCKED);
271172091Srrs		}
272172091Srrs		SCTP_TCB_UNLOCK(stcb);
273172091Srrs	} else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
274172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_PORT)) {
275172091Srrs		/*
276172091Srrs		 * Here the peer is either playing tricks on us, including
277172091Srrs		 * an address that belongs to someone who does not support
278172091Srrs		 * SCTP OR was a userland implementation that shutdown and
279172091Srrs		 * now is dead. In either case treat it like a OOTB abort
280172091Srrs		 * with no TCB
281172091Srrs		 */
282235403Stuexen		sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
283237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
284172091Srrs		so = SCTP_INP_SO(inp);
285172091Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
286172091Srrs		SCTP_TCB_UNLOCK(stcb);
287172091Srrs		SCTP_SOCKET_LOCK(so, 1);
288172091Srrs		SCTP_TCB_LOCK(stcb);
289172091Srrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
290172090Srrs#endif
291283822Stuexen		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
292283822Stuexen		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
293237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
294172091Srrs		SCTP_SOCKET_UNLOCK(so, 1);
295172091Srrs		/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
296172090Srrs#endif
297172091Srrs		/* no need to unlock here, since the TCB is gone */
298163953Srrs	} else {
299172091Srrs		SCTP_TCB_UNLOCK(stcb);
300163953Srrs	}
301163953Srrs}
302163953Srrs
303270350Stuexen#endif
304270350Stuexen
305221249Stuexen#ifdef INET
306163953Srrsvoid
307163953Srrssctp_ctlinput(cmd, sa, vip)
308163953Srrs	int cmd;
309163953Srrs	struct sockaddr *sa;
310163953Srrs	void *vip;
311163953Srrs{
312163953Srrs	struct ip *ip = vip;
313163953Srrs	struct sctphdr *sh;
314167598Srrs	uint32_t vrf_id;
315163953Srrs
316168299Srrs	/* FIX, for non-bsd is this right? */
317167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
318163953Srrs	if (sa->sa_family != AF_INET ||
319163953Srrs	    ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
320163953Srrs		return;
321163953Srrs	}
322163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
323163953Srrs		ip = 0;
324163953Srrs	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
325163953Srrs		return;
326163953Srrs	}
327163953Srrs	if (ip) {
328163953Srrs		struct sctp_inpcb *inp = NULL;
329163953Srrs		struct sctp_tcb *stcb = NULL;
330163953Srrs		struct sctp_nets *net = NULL;
331163953Srrs		struct sockaddr_in to, from;
332163953Srrs
333163953Srrs		sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
334163953Srrs		bzero(&to, sizeof(to));
335163953Srrs		bzero(&from, sizeof(from));
336163953Srrs		from.sin_family = to.sin_family = AF_INET;
337163953Srrs		from.sin_len = to.sin_len = sizeof(to);
338163953Srrs		from.sin_port = sh->src_port;
339163953Srrs		from.sin_addr = ip->ip_src;
340163953Srrs		to.sin_port = sh->dest_port;
341163953Srrs		to.sin_addr = ip->ip_dst;
342163953Srrs
343163953Srrs		/*
344163953Srrs		 * 'to' holds the dest of the packet that failed to be sent.
345163953Srrs		 * 'from' holds our local endpoint address. Thus we reverse
346163953Srrs		 * the to and the from in the lookup.
347163953Srrs		 */
348237715Stuexen		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to,
349237715Stuexen		    (struct sockaddr *)&from,
350167598Srrs		    &inp, &net, 1, vrf_id);
351163953Srrs		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
352163953Srrs			if (cmd != PRC_MSGSIZE) {
353172091Srrs				sctp_notify(inp, ip, sh,
354163953Srrs				    (struct sockaddr *)&to, stcb,
355163953Srrs				    net);
356163953Srrs			} else {
357163953Srrs				/* handle possible ICMP size messages */
358163953Srrs				sctp_notify_mbuf(inp, stcb, net, ip, sh);
359163953Srrs			}
360163953Srrs		} else {
361163953Srrs			if ((stcb == NULL) && (inp != NULL)) {
362163953Srrs				/* reduce ref-count */
363163953Srrs				SCTP_INP_WLOCK(inp);
364163953Srrs				SCTP_INP_DECR_REF(inp);
365163953Srrs				SCTP_INP_WUNLOCK(inp);
366163953Srrs			}
367209029Srrs			if (stcb) {
368209029Srrs				SCTP_TCB_UNLOCK(stcb);
369209029Srrs			}
370163953Srrs		}
371163953Srrs	}
372163953Srrs	return;
373163953Srrs}
374163953Srrs
375221249Stuexen#endif
376221249Stuexen
377163953Srrsstatic int
378163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS)
379163953Srrs{
380164085Srrs	struct xucred xuc;
381163953Srrs	struct sockaddr_in addrs[2];
382163953Srrs	struct sctp_inpcb *inp;
383163953Srrs	struct sctp_nets *net;
384163953Srrs	struct sctp_tcb *stcb;
385164085Srrs	int error;
386167598Srrs	uint32_t vrf_id;
387163953Srrs
388168299Srrs	/* FIX, for non-bsd is this right? */
389167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
390168299Srrs
391170587Srwatson	error = priv_check(req->td, PRIV_NETINET_GETCRED);
392170587Srwatson
393163953Srrs	if (error)
394163953Srrs		return (error);
395164039Srwatson
396163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
397163953Srrs	if (error)
398163953Srrs		return (error);
399163953Srrs
400237715Stuexen	stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]),
401237715Stuexen	    sintosa(&addrs[0]),
402167598Srrs	    &inp, &net, 1, vrf_id);
403163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
404163953Srrs		if ((inp != NULL) && (stcb == NULL)) {
405163953Srrs			/* reduce ref-count */
406163953Srrs			SCTP_INP_WLOCK(inp);
407163953Srrs			SCTP_INP_DECR_REF(inp);
408164085Srrs			goto cred_can_cont;
409163953Srrs		}
410171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
411163953Srrs		error = ENOENT;
412163953Srrs		goto out;
413163953Srrs	}
414163953Srrs	SCTP_TCB_UNLOCK(stcb);
415164085Srrs	/*
416164085Srrs	 * We use the write lock here, only since in the error leg we need
417164085Srrs	 * it. If we used RLOCK, then we would have to
418164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
419164085Srrs	 * Better to use higher wlock.
420164085Srrs	 */
421164085Srrs	SCTP_INP_WLOCK(inp);
422164085Srrscred_can_cont:
423164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
424164085Srrs	if (error) {
425164085Srrs		SCTP_INP_WUNLOCK(inp);
426164085Srrs		goto out;
427164085Srrs	}
428164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
429164085Srrs	SCTP_INP_WUNLOCK(inp);
430164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
431163953Srrsout:
432163953Srrs	return (error);
433163953Srrs}
434163953Srrs
435163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
436163953Srrs    0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
437163953Srrs
438163953Srrs
439221249Stuexen#ifdef INET
440163953Srrsstatic void
441163953Srrssctp_abort(struct socket *so)
442163953Srrs{
443163953Srrs	struct sctp_inpcb *inp;
444163953Srrs	uint32_t flags;
445163953Srrs
446163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
447233005Stuexen	if (inp == NULL) {
448163953Srrs		return;
449171943Srrs	}
450163953Srrssctp_must_try_again:
451163953Srrs	flags = inp->sctp_flags;
452163953Srrs#ifdef SCTP_LOG_CLOSING
453163953Srrs	sctp_log_closing(inp, NULL, 17);
454163953Srrs#endif
455163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
456163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
457163953Srrs#ifdef SCTP_LOG_CLOSING
458163953Srrs		sctp_log_closing(inp, NULL, 16);
459163953Srrs#endif
460169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
461169380Srrs		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
462163953Srrs		SOCK_LOCK(so);
463167695Srrs		SCTP_SB_CLEAR(so->so_snd);
464163953Srrs		/*
465163953Srrs		 * same for the rcv ones, they are only here for the
466163953Srrs		 * accounting/select.
467163953Srrs		 */
468167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
469167695Srrs
470167695Srrs		/* Now null out the reference, we are completely detached. */
471163953Srrs		so->so_pcb = NULL;
472163953Srrs		SOCK_UNLOCK(so);
473163953Srrs	} else {
474163953Srrs		flags = inp->sctp_flags;
475163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
476163953Srrs			goto sctp_must_try_again;
477163953Srrs		}
478163953Srrs	}
479163953Srrs	return;
480163953Srrs}
481163953Srrs
482163953Srrsstatic int
483228653Stuexensctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
484163953Srrs{
485163953Srrs	struct sctp_inpcb *inp;
486163953Srrs	struct inpcb *ip_inp;
487166086Srrs	int error;
488170205Srrs	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
489185694Srrs
490163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
491163953Srrs	if (inp != 0) {
492171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
493228907Stuexen		return (EINVAL);
494163953Srrs	}
495184030Srrs	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
496184030Srrs		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
497184030Srrs		if (error) {
498228907Stuexen			return (error);
499184030Srrs		}
500163953Srrs	}
501170205Srrs	error = sctp_inpcb_alloc(so, vrf_id);
502163953Srrs	if (error) {
503228907Stuexen		return (error);
504163953Srrs	}
505163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
506163953Srrs	SCTP_INP_WLOCK(inp);
507163953Srrs	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;	/* I'm not v6! */
508163953Srrs	ip_inp = &inp->ip_inp.inp;
509163953Srrs	ip_inp->inp_vflag |= INP_IPV4;
510197288Srrs	ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
511163953Srrs	SCTP_INP_WUNLOCK(inp);
512228907Stuexen	return (0);
513163953Srrs}
514163953Srrs
515163953Srrsstatic int
516163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
517163953Srrs{
518244730Stuexen	struct sctp_inpcb *inp;
519163953Srrs
520163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
521233005Stuexen	if (inp == NULL) {
522171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
523228907Stuexen		return (EINVAL);
524171943Srrs	}
525244730Stuexen	if (addr != NULL) {
526244730Stuexen		if ((addr->sa_family != AF_INET) ||
527244730Stuexen		    (addr->sa_len != sizeof(struct sockaddr_in))) {
528244730Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
529244730Stuexen			return (EINVAL);
530244730Stuexen		}
531244730Stuexen	}
532244730Stuexen	return (sctp_inpcb_bind(so, addr, NULL, p));
533163953Srrs}
534163953Srrs
535221249Stuexen#endif
536171990Srrsvoid
537163953Srrssctp_close(struct socket *so)
538163953Srrs{
539163953Srrs	struct sctp_inpcb *inp;
540163953Srrs	uint32_t flags;
541163953Srrs
542163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
543233005Stuexen	if (inp == NULL)
544163953Srrs		return;
545163953Srrs
546163953Srrs	/*
547163953Srrs	 * Inform all the lower layer assoc that we are done.
548163953Srrs	 */
549163953Srrssctp_must_try_again:
550163953Srrs	flags = inp->sctp_flags;
551163953Srrs#ifdef SCTP_LOG_CLOSING
552163953Srrs	sctp_log_closing(inp, NULL, 17);
553163953Srrs#endif
554163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
555163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
556163953Srrs		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
557163953Srrs		    (so->so_rcv.sb_cc > 0)) {
558163953Srrs#ifdef SCTP_LOG_CLOSING
559163953Srrs			sctp_log_closing(inp, NULL, 13);
560163953Srrs#endif
561169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
562169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
563163953Srrs		} else {
564163953Srrs#ifdef SCTP_LOG_CLOSING
565163953Srrs			sctp_log_closing(inp, NULL, 14);
566163953Srrs#endif
567169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
568169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
569163953Srrs		}
570163953Srrs		/*
571163953Srrs		 * The socket is now detached, no matter what the state of
572163953Srrs		 * the SCTP association.
573163953Srrs		 */
574163953Srrs		SOCK_LOCK(so);
575167695Srrs		SCTP_SB_CLEAR(so->so_snd);
576163953Srrs		/*
577163953Srrs		 * same for the rcv ones, they are only here for the
578163953Srrs		 * accounting/select.
579163953Srrs		 */
580167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
581167695Srrs
582167695Srrs		/* Now null out the reference, we are completely detached. */
583163953Srrs		so->so_pcb = NULL;
584163953Srrs		SOCK_UNLOCK(so);
585163953Srrs	} else {
586163953Srrs		flags = inp->sctp_flags;
587163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
588163953Srrs			goto sctp_must_try_again;
589163953Srrs		}
590163953Srrs	}
591163953Srrs	return;
592163953Srrs}
593163953Srrs
594163953Srrs
595163953Srrsint
596163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
597163953Srrs    struct mbuf *control, struct thread *p);
598163953Srrs
599163953Srrs
600163953Srrsint
601163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
602163953Srrs    struct mbuf *control, struct thread *p)
603163953Srrs{
604163953Srrs	struct sctp_inpcb *inp;
605163953Srrs	int error;
606163953Srrs
607163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
608233005Stuexen	if (inp == NULL) {
609163953Srrs		if (control) {
610163953Srrs			sctp_m_freem(control);
611163953Srrs			control = NULL;
612163953Srrs		}
613171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
614163953Srrs		sctp_m_freem(m);
615228907Stuexen		return (EINVAL);
616163953Srrs	}
617163953Srrs	/* Got to have an to address if we are NOT a connected socket */
618163953Srrs	if ((addr == NULL) &&
619163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
620228907Stuexen	    (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) {
621163953Srrs		goto connected_type;
622163953Srrs	} else if (addr == NULL) {
623171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
624163953Srrs		error = EDESTADDRREQ;
625163953Srrs		sctp_m_freem(m);
626163953Srrs		if (control) {
627163953Srrs			sctp_m_freem(control);
628163953Srrs			control = NULL;
629163953Srrs		}
630163953Srrs		return (error);
631163953Srrs	}
632163953Srrs#ifdef INET6
633163953Srrs	if (addr->sa_family != AF_INET) {
634163953Srrs		/* must be a v4 address! */
635171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
636163953Srrs		sctp_m_freem(m);
637163953Srrs		if (control) {
638163953Srrs			sctp_m_freem(control);
639163953Srrs			control = NULL;
640163953Srrs		}
641163953Srrs		error = EDESTADDRREQ;
642223132Stuexen		return (error);
643163953Srrs	}
644163953Srrs#endif				/* INET6 */
645163953Srrsconnected_type:
646163953Srrs	/* now what about control */
647163953Srrs	if (control) {
648163953Srrs		if (inp->control) {
649169420Srrs			SCTP_PRINTF("huh? control set?\n");
650163953Srrs			sctp_m_freem(inp->control);
651163953Srrs			inp->control = NULL;
652163953Srrs		}
653163953Srrs		inp->control = control;
654163953Srrs	}
655163953Srrs	/* Place the data */
656163953Srrs	if (inp->pkt) {
657165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
658163953Srrs		inp->pkt_last = m;
659163953Srrs	} else {
660163953Srrs		inp->pkt_last = inp->pkt = m;
661163953Srrs	}
662163953Srrs	if (
663163953Srrs	/* FreeBSD uses a flag passed */
664163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
665163953Srrs	    ) {
666163953Srrs		/*
667163953Srrs		 * note with the current version this code will only be used
668163953Srrs		 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
669163953Srrs		 * re-defining sosend to use the sctp_sosend. One can
670163953Srrs		 * optionally switch back to this code (by changing back the
671163953Srrs		 * definitions) but this is not advisable. This code is used
672163953Srrs		 * by FreeBSD when sending a file with sendfile() though.
673163953Srrs		 */
674163953Srrs		int ret;
675163953Srrs
676163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
677163953Srrs		inp->pkt = NULL;
678163953Srrs		inp->control = NULL;
679163953Srrs		return (ret);
680163953Srrs	} else {
681163953Srrs		return (0);
682163953Srrs	}
683163953Srrs}
684163953Srrs
685171990Srrsint
686163953Srrssctp_disconnect(struct socket *so)
687163953Srrs{
688163953Srrs	struct sctp_inpcb *inp;
689163953Srrs
690163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
691163953Srrs	if (inp == NULL) {
692171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
693163953Srrs		return (ENOTCONN);
694163953Srrs	}
695163953Srrs	SCTP_INP_RLOCK(inp);
696171745Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
697171745Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
698199437Stuexen		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
699163953Srrs			/* No connection */
700163953Srrs			SCTP_INP_RUNLOCK(inp);
701163953Srrs			return (0);
702163953Srrs		} else {
703163953Srrs			struct sctp_association *asoc;
704163953Srrs			struct sctp_tcb *stcb;
705163953Srrs
706163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
707163953Srrs			if (stcb == NULL) {
708163953Srrs				SCTP_INP_RUNLOCK(inp);
709171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
710163953Srrs				return (EINVAL);
711163953Srrs			}
712163953Srrs			SCTP_TCB_LOCK(stcb);
713163953Srrs			asoc = &stcb->asoc;
714163953Srrs			if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
715163953Srrs				/* We are about to be freed, out of here */
716163953Srrs				SCTP_TCB_UNLOCK(stcb);
717163953Srrs				SCTP_INP_RUNLOCK(inp);
718163953Srrs				return (0);
719163953Srrs			}
720163953Srrs			if (((so->so_options & SO_LINGER) &&
721163953Srrs			    (so->so_linger == 0)) ||
722163953Srrs			    (so->so_rcv.sb_cc > 0)) {
723163953Srrs				if (SCTP_GET_STATE(asoc) !=
724163953Srrs				    SCTP_STATE_COOKIE_WAIT) {
725163953Srrs					/* Left with Data unread */
726163953Srrs					struct mbuf *err;
727163953Srrs
728243882Sglebius					err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
729163953Srrs					if (err) {
730163953Srrs						/*
731163953Srrs						 * Fill in the user
732163953Srrs						 * initiated abort
733163953Srrs						 */
734163953Srrs						struct sctp_paramhdr *ph;
735163953Srrs
736163953Srrs						ph = mtod(err, struct sctp_paramhdr *);
737165647Srrs						SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr);
738163953Srrs						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
739165647Srrs						ph->param_length = htons(SCTP_BUF_LEN(err));
740163953Srrs					}
741172090Srrs					sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
742163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
743163953Srrs				}
744163953Srrs				SCTP_INP_RUNLOCK(inp);
745163953Srrs				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
746163953Srrs				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
747163953Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
748163953Srrs				}
749283822Stuexen				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
750283822Stuexen				    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
751163953Srrs				/* No unlock tcb assoc is gone */
752163953Srrs				return (0);
753163953Srrs			}
754163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
755163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
756163953Srrs			    (asoc->stream_queue_cnt == 0)) {
757163953Srrs				/* there is nothing queued to send, so done */
758163953Srrs				if (asoc->locked_on_sending) {
759163953Srrs					goto abort_anyway;
760163953Srrs				}
761166675Srrs				if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
762166675Srrs				    (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
763163953Srrs					/* only send SHUTDOWN 1st time thru */
764224641Stuexen					struct sctp_nets *netp;
765224641Stuexen
766246588Stuexen					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
767246588Stuexen					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
768246588Stuexen						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
769246588Stuexen					}
770246588Stuexen					SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
771246588Stuexen					SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
772246588Stuexen					sctp_stop_timers_for_shutdown(stcb);
773224641Stuexen					if (stcb->asoc.alternate) {
774224641Stuexen						netp = stcb->asoc.alternate;
775224641Stuexen					} else {
776224641Stuexen						netp = stcb->asoc.primary_destination;
777224641Stuexen					}
778224641Stuexen					sctp_send_shutdown(stcb, netp);
779163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
780224641Stuexen					    stcb->sctp_ep, stcb, netp);
781163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
782224641Stuexen					    stcb->sctp_ep, stcb, netp);
783246588Stuexen					sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
784163953Srrs				}
785163953Srrs			} else {
786163953Srrs				/*
787163953Srrs				 * we still got (or just got) data to send,
788163953Srrs				 * so set SHUTDOWN_PENDING
789163953Srrs				 */
790163953Srrs				/*
791163953Srrs				 * XXX sockets draft says that SCTP_EOF
792163953Srrs				 * should be sent with no data. currently,
793163953Srrs				 * we will allow user data to be sent first
794163953Srrs				 * and move to SHUTDOWN-PENDING
795163953Srrs				 */
796224641Stuexen				struct sctp_nets *netp;
797224641Stuexen
798224641Stuexen				if (stcb->asoc.alternate) {
799224641Stuexen					netp = stcb->asoc.alternate;
800224641Stuexen				} else {
801224641Stuexen					netp = stcb->asoc.primary_destination;
802224641Stuexen				}
803224641Stuexen
804163953Srrs				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
805163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
806224641Stuexen				    netp);
807163953Srrs				if (asoc->locked_on_sending) {
808163953Srrs					/* Locked to send out the data */
809163953Srrs					struct sctp_stream_queue_pending *sp;
810163953Srrs
811163953Srrs					sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
812163953Srrs					if (sp == NULL) {
813169420Srrs						SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
814163953Srrs						    asoc->locked_on_sending->stream_no);
815163953Srrs					} else {
816163953Srrs						if ((sp->length == 0) && (sp->msg_is_complete == 0))
817163953Srrs							asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
818163953Srrs					}
819163953Srrs				}
820163953Srrs				if (TAILQ_EMPTY(&asoc->send_queue) &&
821163953Srrs				    TAILQ_EMPTY(&asoc->sent_queue) &&
822163953Srrs				    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
823163953Srrs					struct mbuf *op_err;
824163953Srrs
825163953Srrs			abort_anyway:
826267723Stuexen					op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
827165220Srrs					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
828172090Srrs					sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
829163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
830163953Srrs					if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
831163953Srrs					    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
832163953Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
833163953Srrs					}
834163953Srrs					SCTP_INP_RUNLOCK(inp);
835283822Stuexen					(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
836283822Stuexen					    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
837163953Srrs					return (0);
838171990Srrs				} else {
839172090Srrs					sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
840163953Srrs				}
841163953Srrs			}
842188067Srrs			soisdisconnecting(so);
843163953Srrs			SCTP_TCB_UNLOCK(stcb);
844163953Srrs			SCTP_INP_RUNLOCK(inp);
845163953Srrs			return (0);
846163953Srrs		}
847163953Srrs		/* not reached */
848163953Srrs	} else {
849163953Srrs		/* UDP model does not support this */
850163953Srrs		SCTP_INP_RUNLOCK(inp);
851171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
852228907Stuexen		return (EOPNOTSUPP);
853163953Srrs	}
854163953Srrs}
855163953Srrs
856163953Srrsint
857178202Srrssctp_flush(struct socket *so, int how)
858178202Srrs{
859178202Srrs	/*
860178202Srrs	 * We will just clear out the values and let subsequent close clear
861178202Srrs	 * out the data, if any. Note if the user did a shutdown(SHUT_RD)
862178202Srrs	 * they will not be able to read the data, the socket will block
863178202Srrs	 * that from happening.
864178202Srrs	 */
865209289Stuexen	struct sctp_inpcb *inp;
866209289Stuexen
867209289Stuexen	inp = (struct sctp_inpcb *)so->so_pcb;
868209289Stuexen	if (inp == NULL) {
869209289Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
870228907Stuexen		return (EINVAL);
871209289Stuexen	}
872209289Stuexen	SCTP_INP_RLOCK(inp);
873209289Stuexen	/* For the 1 to many model this does nothing */
874209289Stuexen	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
875209289Stuexen		SCTP_INP_RUNLOCK(inp);
876209289Stuexen		return (0);
877209289Stuexen	}
878209289Stuexen	SCTP_INP_RUNLOCK(inp);
879178202Srrs	if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
880178202Srrs		/*
881178202Srrs		 * First make sure the sb will be happy, we don't use these
882178202Srrs		 * except maybe the count
883178202Srrs		 */
884209289Stuexen		SCTP_INP_WLOCK(inp);
885209289Stuexen		SCTP_INP_READ_LOCK(inp);
886209289Stuexen		inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
887209289Stuexen		SCTP_INP_READ_UNLOCK(inp);
888209289Stuexen		SCTP_INP_WUNLOCK(inp);
889178202Srrs		so->so_rcv.sb_cc = 0;
890178202Srrs		so->so_rcv.sb_mbcnt = 0;
891178202Srrs		so->so_rcv.sb_mb = NULL;
892178202Srrs	}
893178202Srrs	if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
894178202Srrs		/*
895178202Srrs		 * First make sure the sb will be happy, we don't use these
896178202Srrs		 * except maybe the count
897178202Srrs		 */
898178202Srrs		so->so_snd.sb_cc = 0;
899178202Srrs		so->so_snd.sb_mbcnt = 0;
900178202Srrs		so->so_snd.sb_mb = NULL;
901178202Srrs
902178202Srrs	}
903178202Srrs	return (0);
904178202Srrs}
905178202Srrs
906178202Srrsint
907163953Srrssctp_shutdown(struct socket *so)
908163953Srrs{
909163953Srrs	struct sctp_inpcb *inp;
910163953Srrs
911163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
912233005Stuexen	if (inp == NULL) {
913171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
914228907Stuexen		return (EINVAL);
915163953Srrs	}
916163953Srrs	SCTP_INP_RLOCK(inp);
917163953Srrs	/* For UDP model this is a invalid call */
918243558Stuexen	if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
919243558Stuexen	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
920163953Srrs		/* Restore the flags that the soshutdown took away. */
921204096Stuexen		SOCKBUF_LOCK(&so->so_rcv);
922163953Srrs		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
923204096Stuexen		SOCKBUF_UNLOCK(&so->so_rcv);
924163953Srrs		/* This proc will wakeup for read and do nothing (I hope) */
925163953Srrs		SCTP_INP_RUNLOCK(inp);
926171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
927163953Srrs		return (EOPNOTSUPP);
928294182Stuexen	} else {
929294182Stuexen		/*
930294182Stuexen		 * Ok, if we reach here its the TCP model and it is either a
931294182Stuexen		 * SHUT_WR or SHUT_RDWR. This means we put the shutdown flag
932294182Stuexen		 * against it.
933294182Stuexen		 */
934163953Srrs		struct sctp_tcb *stcb;
935163953Srrs		struct sctp_association *asoc;
936294182Stuexen		struct sctp_nets *netp;
937163953Srrs
938188067Srrs		if ((so->so_state &
939188067Srrs		    (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
940188067Srrs			SCTP_INP_RUNLOCK(inp);
941188067Srrs			return (ENOTCONN);
942188067Srrs		}
943163953Srrs		socantsendmore(so);
944163953Srrs
945163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
946163953Srrs		if (stcb == NULL) {
947163953Srrs			/*
948294182Stuexen			 * Ok, we hit the case that the shutdown call was
949163953Srrs			 * made after an abort or something. Nothing to do
950163953Srrs			 * now.
951163953Srrs			 */
952168299Srrs			SCTP_INP_RUNLOCK(inp);
953163953Srrs			return (0);
954163953Srrs		}
955163953Srrs		SCTP_TCB_LOCK(stcb);
956163953Srrs		asoc = &stcb->asoc;
957294182Stuexen		if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
958294182Stuexen			SCTP_TCB_UNLOCK(stcb);
959294182Stuexen			SCTP_INP_RUNLOCK(inp);
960294182Stuexen			return (0);
961294182Stuexen		}
962294182Stuexen		if ((SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_WAIT) &&
963294182Stuexen		    (SCTP_GET_STATE(asoc) != SCTP_STATE_COOKIE_ECHOED) &&
964294182Stuexen		    (SCTP_GET_STATE(asoc) != SCTP_STATE_OPEN)) {
965294182Stuexen			/*
966294182Stuexen			 * If we are not in or before ESTABLISHED, there is
967294182Stuexen			 * no protocol action required.
968294182Stuexen			 */
969294182Stuexen			SCTP_TCB_UNLOCK(stcb);
970294182Stuexen			SCTP_INP_RUNLOCK(inp);
971294182Stuexen			return (0);
972294182Stuexen		}
973294182Stuexen		if (stcb->asoc.alternate) {
974294182Stuexen			netp = stcb->asoc.alternate;
975294182Stuexen		} else {
976294182Stuexen			netp = stcb->asoc.primary_destination;
977294182Stuexen		}
978294184Stuexen		if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) &&
979294184Stuexen		    TAILQ_EMPTY(&asoc->send_queue) &&
980163953Srrs		    TAILQ_EMPTY(&asoc->sent_queue) &&
981163953Srrs		    (asoc->stream_queue_cnt == 0)) {
982163953Srrs			if (asoc->locked_on_sending) {
983163953Srrs				goto abort_anyway;
984163953Srrs			}
985163953Srrs			/* there is nothing queued to send, so I'm done... */
986294184Stuexen			SCTP_STAT_DECR_GAUGE32(sctps_currestab);
987294182Stuexen			SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
988294182Stuexen			SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
989294182Stuexen			sctp_stop_timers_for_shutdown(stcb);
990294182Stuexen			sctp_send_shutdown(stcb, netp);
991294182Stuexen			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
992294182Stuexen			    stcb->sctp_ep, stcb, netp);
993163953Srrs		} else {
994163953Srrs			/*
995294182Stuexen			 * We still got (or just got) data to send, so set
996294182Stuexen			 * SHUTDOWN_PENDING.
997163953Srrs			 */
998294182Stuexen			SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
999163953Srrs			if (asoc->locked_on_sending) {
1000163953Srrs				/* Locked to send out the data */
1001163953Srrs				struct sctp_stream_queue_pending *sp;
1002163953Srrs
1003163953Srrs				sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1004163953Srrs				if (sp == NULL) {
1005169420Srrs					SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1006163953Srrs					    asoc->locked_on_sending->stream_no);
1007163953Srrs				} else {
1008163953Srrs					if ((sp->length == 0) && (sp->msg_is_complete == 0)) {
1009294182Stuexen						SCTP_ADD_SUBSTATE(asoc, SCTP_STATE_PARTIAL_MSG_LEFT);
1010163953Srrs					}
1011163953Srrs				}
1012163953Srrs			}
1013163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
1014163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
1015163953Srrs			    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1016163953Srrs				struct mbuf *op_err;
1017163953Srrs
1018163953Srrs		abort_anyway:
1019267723Stuexen				op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
1020165220Srrs				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
1021163953Srrs				sctp_abort_an_association(stcb->sctp_ep, stcb,
1022172090Srrs				    op_err, SCTP_SO_LOCKED);
1023294182Stuexen				SCTP_INP_RUNLOCK(inp);
1024294182Stuexen				return (0);
1025163953Srrs			}
1026163953Srrs		}
1027294182Stuexen		sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, netp);
1028294182Stuexen		/*
1029294182Stuexen		 * XXX: Why do this in the case where we have still data
1030294182Stuexen		 * queued?
1031294182Stuexen		 */
1032294182Stuexen		sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
1033163953Srrs		SCTP_TCB_UNLOCK(stcb);
1034294182Stuexen		SCTP_INP_RUNLOCK(inp);
1035294182Stuexen		return (0);
1036163953Srrs	}
1037163953Srrs}
1038163953Srrs
1039163953Srrs/*
1040163953Srrs * copies a "user" presentable address and removes embedded scope, etc.
1041163953Srrs * returns 0 on success, 1 on error
1042163953Srrs */
1043163953Srrsstatic uint32_t
1044163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
1045163953Srrs{
1046178251Srrs#ifdef INET6
1047163953Srrs	struct sockaddr_in6 lsa6;
1048163953Srrs
1049163953Srrs	sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
1050163953Srrs	    &lsa6);
1051178251Srrs#endif
1052163953Srrs	memcpy(ss, sa, sa->sa_len);
1053163953Srrs	return (0);
1054163953Srrs}
1055163953Srrs
1056163953Srrs
1057163953Srrs
1058172091Srrs/*
1059172091Srrs * NOTE: assumes addr lock is held
1060172091Srrs */
1061166675Srrsstatic size_t
1062168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
1063163953Srrs    struct sctp_tcb *stcb,
1064166675Srrs    size_t limit,
1065167598Srrs    struct sockaddr_storage *sas,
1066167598Srrs    uint32_t vrf_id)
1067163953Srrs{
1068167598Srrs	struct sctp_ifn *sctp_ifn;
1069167598Srrs	struct sctp_ifa *sctp_ifa;
1070166675Srrs	size_t actual;
1071258454Stuexen	int loopback_scope;
1072258454Stuexen
1073258454Stuexen#if defined(INET)
1074258454Stuexen	int ipv4_local_scope, ipv4_addr_legal;
1075258454Stuexen
1076258454Stuexen#endif
1077258454Stuexen#if defined(INET6)
1078258454Stuexen	int local_scope, site_scope, ipv6_addr_legal;
1079258454Stuexen
1080258454Stuexen#endif
1081167598Srrs	struct sctp_vrf *vrf;
1082163953Srrs
1083163953Srrs	actual = 0;
1084163953Srrs	if (limit <= 0)
1085163953Srrs		return (actual);
1086163953Srrs
1087163953Srrs	if (stcb) {
1088163953Srrs		/* Turn on all the appropriate scope */
1089246595Stuexen		loopback_scope = stcb->asoc.scope.loopback_scope;
1090258454Stuexen#if defined(INET)
1091246595Stuexen		ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
1092258454Stuexen		ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
1093258454Stuexen#endif
1094258454Stuexen#if defined(INET6)
1095246595Stuexen		local_scope = stcb->asoc.scope.local_scope;
1096246595Stuexen		site_scope = stcb->asoc.scope.site_scope;
1097246595Stuexen		ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
1098258454Stuexen#endif
1099163953Srrs	} else {
1100246595Stuexen		/* Use generic values for endpoints. */
1101246595Stuexen		loopback_scope = 1;
1102258454Stuexen#if defined(INET)
1103246595Stuexen		ipv4_local_scope = 1;
1104258454Stuexen#endif
1105258454Stuexen#if defined(INET6)
1106246595Stuexen		local_scope = 1;
1107246595Stuexen		site_scope = 1;
1108258454Stuexen#endif
1109246595Stuexen		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1110258454Stuexen#if defined(INET6)
1111246595Stuexen			ipv6_addr_legal = 1;
1112258454Stuexen#endif
1113258454Stuexen#if defined(INET)
1114246595Stuexen			if (SCTP_IPV6_V6ONLY(inp)) {
1115246595Stuexen				ipv4_addr_legal = 0;
1116246595Stuexen			} else {
1117246595Stuexen				ipv4_addr_legal = 1;
1118246595Stuexen			}
1119258454Stuexen#endif
1120246595Stuexen		} else {
1121258454Stuexen#if defined(INET6)
1122246595Stuexen			ipv6_addr_legal = 0;
1123258454Stuexen#endif
1124258454Stuexen#if defined(INET)
1125163953Srrs			ipv4_addr_legal = 1;
1126258454Stuexen#endif
1127163953Srrs		}
1128163953Srrs	}
1129167598Srrs	vrf = sctp_find_vrf(vrf_id);
1130167598Srrs	if (vrf == NULL) {
1131167598Srrs		return (0);
1132167598Srrs	}
1133163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1134167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1135163953Srrs			if ((loopback_scope == 0) &&
1136167598Srrs			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
1137163953Srrs				/* Skip loopback if loopback_scope not set */
1138163953Srrs				continue;
1139163953Srrs			}
1140167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1141163953Srrs				if (stcb) {
1142163953Srrs					/*
1143163953Srrs					 * For the BOUND-ALL case, the list
1144163953Srrs					 * associated with a TCB is Always
1145163953Srrs					 * considered a reverse list.. i.e.
1146163953Srrs					 * it lists addresses that are NOT
1147163953Srrs					 * part of the association. If this
1148163953Srrs					 * is one of those we must skip it.
1149163953Srrs					 */
1150163953Srrs					if (sctp_is_addr_restricted(stcb,
1151167598Srrs					    sctp_ifa)) {
1152163953Srrs						continue;
1153163953Srrs					}
1154163953Srrs				}
1155178251Srrs				switch (sctp_ifa->address.sa.sa_family) {
1156221249Stuexen#ifdef INET
1157178251Srrs				case AF_INET:
1158178251Srrs					if (ipv4_addr_legal) {
1159178251Srrs						struct sockaddr_in *sin;
1160163953Srrs
1161271746Stuexen						sin = &sctp_ifa->address.sin;
1162178251Srrs						if (sin->sin_addr.s_addr == 0) {
1163178251Srrs							/*
1164178251Srrs							 * we skip
1165178251Srrs							 * unspecifed
1166178251Srrs							 * addresses
1167178251Srrs							 */
1168178251Srrs							continue;
1169178251Srrs						}
1170267769Stuexen						if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
1171267769Stuexen						    &sin->sin_addr) != 0) {
1172267769Stuexen							continue;
1173267769Stuexen						}
1174178251Srrs						if ((ipv4_local_scope == 0) &&
1175178251Srrs						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
1176178251Srrs							continue;
1177178251Srrs						}
1178178251Srrs#ifdef INET6
1179178251Srrs						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
1180178251Srrs							in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
1181178251Srrs							((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1182178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
1183178251Srrs							actual += sizeof(struct sockaddr_in6);
1184178251Srrs						} else {
1185178251Srrs#endif
1186178251Srrs							memcpy(sas, sin, sizeof(*sin));
1187178251Srrs							((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1188178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
1189178251Srrs							actual += sizeof(*sin);
1190178251Srrs#ifdef INET6
1191178251Srrs						}
1192178251Srrs#endif
1193178251Srrs						if (actual >= limit) {
1194178251Srrs							return (actual);
1195178251Srrs						}
1196178251Srrs					} else {
1197163953Srrs						continue;
1198163953Srrs					}
1199178251Srrs					break;
1200221249Stuexen#endif
1201178251Srrs#ifdef INET6
1202178251Srrs				case AF_INET6:
1203178251Srrs					if (ipv6_addr_legal) {
1204178251Srrs						struct sockaddr_in6 *sin6;
1205163953Srrs
1206271746Stuexen						sin6 = &sctp_ifa->address.sin6;
1207178251Srrs						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1208178251Srrs							/*
1209178251Srrs							 * we skip
1210178251Srrs							 * unspecifed
1211178251Srrs							 * addresses
1212178251Srrs							 */
1213163953Srrs							continue;
1214178251Srrs						}
1215267769Stuexen						if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
1216267769Stuexen						    &sin6->sin6_addr) != 0) {
1217267769Stuexen							continue;
1218267769Stuexen						}
1219178251Srrs						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1220178251Srrs							if (local_scope == 0)
1221163953Srrs								continue;
1222178251Srrs							if (sin6->sin6_scope_id == 0) {
1223178251Srrs								if (sa6_recoverscope(sin6) != 0)
1224178251Srrs									/*
1225178251Srrs									 *
1226178251Srrs									 * bad
1227178251Srrs									 *
1228178251Srrs									 * li
1229178251Srrs									 * nk
1230178251Srrs									 *
1231178251Srrs									 * loc
1232178251Srrs									 * al
1233178251Srrs									 *
1234178251Srrs									 * add
1235178251Srrs									 * re
1236178251Srrs									 * ss
1237178251Srrs									 * */
1238178251Srrs									continue;
1239178251Srrs							}
1240163953Srrs						}
1241178251Srrs						if ((site_scope == 0) &&
1242178251Srrs						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
1243178251Srrs							continue;
1244178251Srrs						}
1245178251Srrs						memcpy(sas, sin6, sizeof(*sin6));
1246178251Srrs						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1247178251Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
1248178251Srrs						actual += sizeof(*sin6);
1249178251Srrs						if (actual >= limit) {
1250178251Srrs							return (actual);
1251178251Srrs						}
1252178251Srrs					} else {
1253163953Srrs						continue;
1254163953Srrs					}
1255178251Srrs					break;
1256178251Srrs#endif
1257178251Srrs				default:
1258178251Srrs					/* TSNH */
1259178251Srrs					break;
1260163953Srrs				}
1261163953Srrs			}
1262163953Srrs		}
1263163953Srrs	} else {
1264163953Srrs		struct sctp_laddr *laddr;
1265163953Srrs
1266167598Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1267167598Srrs			if (stcb) {
1268167598Srrs				if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
1269163953Srrs					continue;
1270163953Srrs				}
1271163953Srrs			}
1272167598Srrs			if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
1273167598Srrs				continue;
1274246595Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1275246595Stuexen#ifdef INET
1276246595Stuexen			case AF_INET:
1277246595Stuexen				((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1278246595Stuexen				break;
1279246595Stuexen#endif
1280246595Stuexen#ifdef INET6
1281246595Stuexen			case AF_INET6:
1282246595Stuexen				((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1283246595Stuexen				break;
1284246595Stuexen#endif
1285246595Stuexen			default:
1286246595Stuexen				/* TSNH */
1287246595Stuexen				break;
1288246595Stuexen			}
1289167598Srrs			sas = (struct sockaddr_storage *)((caddr_t)sas +
1290167598Srrs			    laddr->ifa->address.sa.sa_len);
1291167598Srrs			actual += laddr->ifa->address.sa.sa_len;
1292167598Srrs			if (actual >= limit) {
1293167598Srrs				return (actual);
1294163953Srrs			}
1295163953Srrs		}
1296163953Srrs	}
1297163953Srrs	return (actual);
1298163953Srrs}
1299163953Srrs
1300168124Srrsstatic size_t
1301168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp,
1302168124Srrs    struct sctp_tcb *stcb,
1303168124Srrs    size_t limit,
1304168124Srrs    struct sockaddr_storage *sas)
1305168124Srrs{
1306168124Srrs	size_t size = 0;
1307168124Srrs
1308172218Srrs	SCTP_IPI_ADDR_RLOCK();
1309168124Srrs	/* fill up addresses for the endpoint's default vrf */
1310168124Srrs	size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
1311168124Srrs	    inp->def_vrf_id);
1312172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1313168124Srrs	return (size);
1314168124Srrs}
1315168124Srrs
1316172091Srrs/*
1317172091Srrs * NOTE: assumes addr lock is held
1318172091Srrs */
1319163953Srrsstatic int
1320168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
1321163953Srrs{
1322163953Srrs	int cnt = 0;
1323167598Srrs	struct sctp_vrf *vrf = NULL;
1324163953Srrs
1325163953Srrs	/*
1326163953Srrs	 * In both sub-set bound an bound_all cases we return the MAXIMUM
1327163953Srrs	 * number of addresses that you COULD get. In reality the sub-set
1328163953Srrs	 * bound may have an exclusion list for a given TCB OR in the
1329163953Srrs	 * bound-all case a TCB may NOT include the loopback or other
1330163953Srrs	 * addresses as well.
1331163953Srrs	 */
1332167598Srrs	vrf = sctp_find_vrf(vrf_id);
1333167598Srrs	if (vrf == NULL) {
1334167598Srrs		return (0);
1335167598Srrs	}
1336163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1337167598Srrs		struct sctp_ifn *sctp_ifn;
1338167598Srrs		struct sctp_ifa *sctp_ifa;
1339163953Srrs
1340167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1341167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1342163953Srrs				/* Count them if they are the right type */
1343221249Stuexen				switch (sctp_ifa->address.sa.sa_family) {
1344221249Stuexen#ifdef INET
1345221249Stuexen				case AF_INET:
1346283699Stuexen#ifdef INET6
1347178251Srrs					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1348163953Srrs						cnt += sizeof(struct sockaddr_in6);
1349163953Srrs					else
1350163953Srrs						cnt += sizeof(struct sockaddr_in);
1351283699Stuexen#else
1352283699Stuexen					cnt += sizeof(struct sockaddr_in);
1353283699Stuexen#endif
1354221249Stuexen					break;
1355221249Stuexen#endif
1356221249Stuexen#ifdef INET6
1357221249Stuexen				case AF_INET6:
1358163953Srrs					cnt += sizeof(struct sockaddr_in6);
1359221249Stuexen					break;
1360221249Stuexen#endif
1361221249Stuexen				default:
1362221249Stuexen					break;
1363221249Stuexen				}
1364163953Srrs			}
1365163953Srrs		}
1366163953Srrs	} else {
1367163953Srrs		struct sctp_laddr *laddr;
1368163953Srrs
1369163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1370221249Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1371221249Stuexen#ifdef INET
1372221249Stuexen			case AF_INET:
1373283699Stuexen#ifdef INET6
1374178251Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1375163953Srrs					cnt += sizeof(struct sockaddr_in6);
1376163953Srrs				else
1377163953Srrs					cnt += sizeof(struct sockaddr_in);
1378283699Stuexen#else
1379283699Stuexen				cnt += sizeof(struct sockaddr_in);
1380283699Stuexen#endif
1381221249Stuexen				break;
1382221249Stuexen#endif
1383221249Stuexen#ifdef INET6
1384221249Stuexen			case AF_INET6:
1385163953Srrs				cnt += sizeof(struct sockaddr_in6);
1386221249Stuexen				break;
1387221249Stuexen#endif
1388221249Stuexen			default:
1389221249Stuexen				break;
1390221249Stuexen			}
1391163953Srrs		}
1392163953Srrs	}
1393163953Srrs	return (cnt);
1394163953Srrs}
1395163953Srrs
1396168124Srrsstatic int
1397168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp)
1398168124Srrs{
1399168124Srrs	int cnt = 0;
1400166675Srrs
1401172218Srrs	SCTP_IPI_ADDR_RLOCK();
1402168124Srrs	/* count addresses for the endpoint's default VRF */
1403168124Srrs	cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
1404172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1405168124Srrs	return (cnt);
1406168124Srrs}
1407168124Srrs
1408163953Srrsstatic int
1409166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
1410166675Srrs    size_t optsize, void *p, int delay)
1411163953Srrs{
1412163953Srrs	int error = 0;
1413163953Srrs	int creat_lock_on = 0;
1414163953Srrs	struct sctp_tcb *stcb = NULL;
1415163953Srrs	struct sockaddr *sa;
1416169352Srrs	int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
1417167598Srrs	uint32_t vrf_id;
1418170056Srrs	int bad_addresses = 0;
1419167598Srrs	sctp_assoc_t *a_id;
1420163953Srrs
1421169420Srrs	SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
1422163953Srrs
1423163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1424163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1425163953Srrs		/* We are already connected AND the TCP model */
1426171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
1427163953Srrs		return (EADDRINUSE);
1428163953Srrs	}
1429181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
1430181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
1431171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1432163953Srrs		return (EINVAL);
1433163953Srrs	}
1434163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1435163953Srrs		SCTP_INP_RLOCK(inp);
1436163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1437163953Srrs		SCTP_INP_RUNLOCK(inp);
1438163953Srrs	}
1439163953Srrs	if (stcb) {
1440171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1441163953Srrs		return (EALREADY);
1442163953Srrs	}
1443163953Srrs	SCTP_INP_INCR_REF(inp);
1444163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
1445163953Srrs	creat_lock_on = 1;
1446163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1447163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
1448171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
1449163953Srrs		error = EFAULT;
1450163953Srrs		goto out_now;
1451163953Srrs	}
1452166675Srrs	totaddrp = (int *)optval;
1453163953Srrs	totaddr = *totaddrp;
1454163953Srrs	sa = (struct sockaddr *)(totaddrp + 1);
1455170056Srrs	stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
1456170056Srrs	if ((stcb != NULL) || bad_addresses) {
1457169352Srrs		/* Already have or am bring up an association */
1458169352Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1459169352Srrs		creat_lock_on = 0;
1460170931Srrs		if (stcb)
1461170931Srrs			SCTP_TCB_UNLOCK(stcb);
1462171943Srrs		if (bad_addresses == 0) {
1463171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1464170056Srrs			error = EALREADY;
1465171943Srrs		}
1466169352Srrs		goto out_now;
1467163953Srrs	}
1468163953Srrs#ifdef INET6
1469163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
1470163953Srrs	    (num_v6 > 0)) {
1471163953Srrs		error = EINVAL;
1472163953Srrs		goto out_now;
1473163953Srrs	}
1474163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1475163953Srrs	    (num_v4 > 0)) {
1476163953Srrs		struct in6pcb *inp6;
1477163953Srrs
1478163953Srrs		inp6 = (struct in6pcb *)inp;
1479166023Srrs		if (SCTP_IPV6_V6ONLY(inp6)) {
1480163953Srrs			/*
1481163953Srrs			 * if IPV6_V6ONLY flag, ignore connections destined
1482163953Srrs			 * to a v4 addr or v4-mapped addr
1483163953Srrs			 */
1484171943Srrs			SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1485163953Srrs			error = EINVAL;
1486163953Srrs			goto out_now;
1487163953Srrs		}
1488163953Srrs	}
1489163953Srrs#endif				/* INET6 */
1490163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1491163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
1492163953Srrs		/* Bind a ephemeral port */
1493171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
1494163953Srrs		if (error) {
1495163953Srrs			goto out_now;
1496163953Srrs		}
1497163953Srrs	}
1498167695Srrs	/* FIX ME: do we want to pass in a vrf on the connect call? */
1499167695Srrs	vrf_id = inp->def_vrf_id;
1500167695Srrs
1501181054Srrs
1502163953Srrs	/* We are GOOD to go */
1503206137Stuexen	stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id,
1504294215Stuexen	    inp->sctp_ep.pre_open_stream_count,
1505171531Srrs	    (struct thread *)p
1506171531Srrs	    );
1507163953Srrs	if (stcb == NULL) {
1508163953Srrs		/* Gak! no memory */
1509163953Srrs		goto out_now;
1510163953Srrs	}
1511225559Stuexen	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1512225559Stuexen		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1513225559Stuexen		/* Set the connected flag so we can queue data */
1514225559Stuexen		soisconnecting(so);
1515225559Stuexen	}
1516171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
1517163953Srrs	/* move to second address */
1518221249Stuexen	switch (sa->sa_family) {
1519221249Stuexen#ifdef INET
1520221249Stuexen	case AF_INET:
1521163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
1522221249Stuexen		break;
1523221249Stuexen#endif
1524221249Stuexen#ifdef INET6
1525221249Stuexen	case AF_INET6:
1526163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
1527221249Stuexen		break;
1528221249Stuexen#endif
1529221249Stuexen	default:
1530221249Stuexen		break;
1531221249Stuexen	}
1532163953Srrs
1533170056Srrs	error = 0;
1534223132Stuexen	sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
1535167598Srrs	/* Fill in the return id */
1536170056Srrs	if (error) {
1537283822Stuexen		(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE,
1538283822Stuexen		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
1539170056Srrs		goto out_now;
1540170056Srrs	}
1541167598Srrs	a_id = (sctp_assoc_t *) optval;
1542167598Srrs	*a_id = sctp_get_associd(stcb);
1543163953Srrs
1544163953Srrs	/* initialize authentication parameters for the assoc */
1545163953Srrs	sctp_initialize_auth_params(inp, stcb);
1546163953Srrs
1547163953Srrs	if (delay) {
1548163953Srrs		/* doing delayed connection */
1549163953Srrs		stcb->asoc.delayed_connection = 1;
1550163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
1551163953Srrs	} else {
1552169378Srrs		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1553172090Srrs		sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
1554163953Srrs	}
1555163953Srrs	SCTP_TCB_UNLOCK(stcb);
1556163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1557163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1558163953Srrs		/* Set the connected flag so we can queue data */
1559163953Srrs		soisconnecting(so);
1560163953Srrs	}
1561163953Srrsout_now:
1562169655Srrs	if (creat_lock_on) {
1563163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1564169655Srrs	}
1565163953Srrs	SCTP_INP_DECR_REF(inp);
1566228907Stuexen	return (error);
1567163953Srrs}
1568163953Srrs
1569169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
1570169655Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\
1571169655Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \
1572166675Srrs		SCTP_INP_RLOCK(inp); \
1573166675Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list); \
1574169655Srrs		if (stcb) { \
1575166675Srrs			SCTP_TCB_LOCK(stcb); \
1576169655Srrs                } \
1577166675Srrs		SCTP_INP_RUNLOCK(inp); \
1578223132Stuexen	} else if (assoc_id > SCTP_ALL_ASSOC) { \
1579166675Srrs		stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
1580166675Srrs		if (stcb == NULL) { \
1581171943Srrs		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
1582166675Srrs			error = ENOENT; \
1583166675Srrs			break; \
1584166675Srrs		} \
1585166675Srrs	} else { \
1586166675Srrs		stcb = NULL; \
1587169420Srrs        } \
1588169420Srrs  }
1589163953Srrs
1590169420Srrs
1591234464Stuexen#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
1592166675Srrs	if (size < sizeof(type)) { \
1593171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
1594166675Srrs		error = EINVAL; \
1595166675Srrs		break; \
1596166675Srrs	} else { \
1597166675Srrs		destp = (type *)srcp; \
1598169420Srrs	} \
1599169420Srrs      }
1600163953Srrs
1601163953Srrsstatic int
1602166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
1603166675Srrs    void *p)
1604163953Srrs{
1605171943Srrs	struct sctp_inpcb *inp = NULL;
1606166675Srrs	int error, val = 0;
1607163953Srrs	struct sctp_tcb *stcb = NULL;
1608163953Srrs
1609166675Srrs	if (optval == NULL) {
1610171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1611166675Srrs		return (EINVAL);
1612166675Srrs	}
1613163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1614233005Stuexen	if (inp == NULL) {
1615171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1616163953Srrs		return EINVAL;
1617171943Srrs	}
1618163953Srrs	error = 0;
1619163953Srrs
1620166675Srrs	switch (optname) {
1621163953Srrs	case SCTP_NODELAY:
1622163953Srrs	case SCTP_AUTOCLOSE:
1623163953Srrs	case SCTP_EXPLICIT_EOR:
1624163953Srrs	case SCTP_AUTO_ASCONF:
1625163953Srrs	case SCTP_DISABLE_FRAGMENTS:
1626163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
1627163953Srrs	case SCTP_USE_EXT_RCVINFO:
1628163953Srrs		SCTP_INP_RLOCK(inp);
1629166675Srrs		switch (optname) {
1630163953Srrs		case SCTP_DISABLE_FRAGMENTS:
1631166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
1632163953Srrs			break;
1633163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
1634166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
1635163953Srrs			break;
1636163953Srrs		case SCTP_AUTO_ASCONF:
1637171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1638171943Srrs				/* only valid for bound all sockets */
1639171943Srrs				val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
1640171943Srrs			} else {
1641171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1642171943Srrs				error = EINVAL;
1643171943Srrs				goto flags_out;
1644171943Srrs			}
1645163953Srrs			break;
1646163953Srrs		case SCTP_EXPLICIT_EOR:
1647166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
1648163953Srrs			break;
1649163953Srrs		case SCTP_NODELAY:
1650166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
1651163953Srrs			break;
1652163953Srrs		case SCTP_USE_EXT_RCVINFO:
1653166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
1654163953Srrs			break;
1655163953Srrs		case SCTP_AUTOCLOSE:
1656163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
1657166675Srrs				val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
1658163953Srrs			else
1659166675Srrs				val = 0;
1660163953Srrs			break;
1661163953Srrs
1662163953Srrs		default:
1663171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
1664163953Srrs			error = ENOPROTOOPT;
1665163953Srrs		}		/* end switch (sopt->sopt_name) */
1666166675Srrs		if (*optsize < sizeof(val)) {
1667171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1668163953Srrs			error = EINVAL;
1669163953Srrs		}
1670171943Srrsflags_out:
1671163953Srrs		SCTP_INP_RUNLOCK(inp);
1672163953Srrs		if (error == 0) {
1673163953Srrs			/* return the option value */
1674166675Srrs			*(int *)optval = val;
1675166675Srrs			*optsize = sizeof(val);
1676163953Srrs		}
1677163953Srrs		break;
1678170091Srrs	case SCTP_GET_PACKET_LOG:
1679170091Srrs		{
1680170091Srrs#ifdef  SCTP_PACKET_LOGGING
1681170091Srrs			uint8_t *target;
1682170091Srrs			int ret;
1683167598Srrs
1684170091Srrs			SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize);
1685170091Srrs			ret = sctp_copy_out_packet_log(target, (int)*optsize);
1686170091Srrs			*optsize = ret;
1687170091Srrs#else
1688171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1689170091Srrs			error = EOPNOTSUPP;
1690170091Srrs#endif
1691170091Srrs			break;
1692170091Srrs		}
1693181054Srrs	case SCTP_REUSE_PORT:
1694181054Srrs		{
1695181054Srrs			uint32_t *value;
1696181054Srrs
1697181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
1698181054Srrs				/* Can't do this for a 1-m socket */
1699181054Srrs				error = EINVAL;
1700181054Srrs				break;
1701181054Srrs			}
1702181054Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1703181054Srrs			*value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
1704181054Srrs			*optsize = sizeof(uint32_t);
1705223132Stuexen			break;
1706181054Srrs		}
1707163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
1708163953Srrs		{
1709166675Srrs			uint32_t *value;
1710166675Srrs
1711166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1712166675Srrs			*value = inp->partial_delivery_point;
1713166675Srrs			*optsize = sizeof(uint32_t);
1714223132Stuexen			break;
1715163953Srrs		}
1716163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
1717163953Srrs		{
1718166675Srrs			uint32_t *value;
1719166675Srrs
1720166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1721168943Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
1722168943Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
1723168943Srrs					*value = SCTP_FRAG_LEVEL_2;
1724168943Srrs				} else {
1725168943Srrs					*value = SCTP_FRAG_LEVEL_1;
1726168943Srrs				}
1727168943Srrs			} else {
1728168943Srrs				*value = SCTP_FRAG_LEVEL_0;
1729168943Srrs			}
1730166675Srrs			*optsize = sizeof(uint32_t);
1731223132Stuexen			break;
1732163953Srrs		}
1733163953Srrs	case SCTP_CMT_ON_OFF:
1734163953Srrs		{
1735166675Srrs			struct sctp_assoc_value *av;
1736166675Srrs
1737166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1738211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1739211944Stuexen			if (stcb) {
1740211944Stuexen				av->assoc_value = stcb->asoc.sctp_cmt_on_off;
1741211944Stuexen				SCTP_TCB_UNLOCK(stcb);
1742166675Srrs			} else {
1743224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1744224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1745224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1746223132Stuexen					SCTP_INP_RLOCK(inp);
1747223132Stuexen					av->assoc_value = inp->sctp_cmt_on_off;
1748223132Stuexen					SCTP_INP_RUNLOCK(inp);
1749223132Stuexen				} else {
1750223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1751223132Stuexen					error = EINVAL;
1752223132Stuexen				}
1753163953Srrs			}
1754223132Stuexen			if (error == 0) {
1755223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1756223132Stuexen			}
1757223132Stuexen			break;
1758163953Srrs		}
1759171440Srrs	case SCTP_PLUGGABLE_CC:
1760171440Srrs		{
1761171440Srrs			struct sctp_assoc_value *av;
1762171440Srrs
1763171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1764171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1765171440Srrs			if (stcb) {
1766171440Srrs				av->assoc_value = stcb->asoc.congestion_control_module;
1767171440Srrs				SCTP_TCB_UNLOCK(stcb);
1768171440Srrs			} else {
1769224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1770224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1771224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1772223132Stuexen					SCTP_INP_RLOCK(inp);
1773223132Stuexen					av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
1774223132Stuexen					SCTP_INP_RUNLOCK(inp);
1775223132Stuexen				} else {
1776223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1777223132Stuexen					error = EINVAL;
1778223132Stuexen				}
1779171440Srrs			}
1780223132Stuexen			if (error == 0) {
1781223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1782223132Stuexen			}
1783223132Stuexen			break;
1784171440Srrs		}
1785219057Srrs	case SCTP_CC_OPTION:
1786219057Srrs		{
1787219057Srrs			struct sctp_cc_option *cc_opt;
1788219057Srrs
1789219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize);
1790219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
1791219057Srrs			if (stcb == NULL) {
1792219057Srrs				error = EINVAL;
1793219057Srrs			} else {
1794219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
1795219057Srrs					error = ENOTSUP;
1796219057Srrs				} else {
1797223132Stuexen					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt);
1798223132Stuexen					*optsize = sizeof(struct sctp_cc_option);
1799219057Srrs				}
1800219057Srrs				SCTP_TCB_UNLOCK(stcb);
1801219057Srrs			}
1802223132Stuexen			break;
1803219057Srrs		}
1804217760Stuexen	case SCTP_PLUGGABLE_SS:
1805217760Stuexen		{
1806217760Stuexen			struct sctp_assoc_value *av;
1807217760Stuexen
1808217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1809217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1810217760Stuexen			if (stcb) {
1811217760Stuexen				av->assoc_value = stcb->asoc.stream_scheduling_module;
1812217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1813217760Stuexen			} else {
1814224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1815224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1816224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1817223132Stuexen					SCTP_INP_RLOCK(inp);
1818223132Stuexen					av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
1819223132Stuexen					SCTP_INP_RUNLOCK(inp);
1820223132Stuexen				} else {
1821223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1822223132Stuexen					error = EINVAL;
1823223132Stuexen				}
1824217760Stuexen			}
1825223132Stuexen			if (error == 0) {
1826223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1827223132Stuexen			}
1828223132Stuexen			break;
1829217760Stuexen		}
1830217760Stuexen	case SCTP_SS_VALUE:
1831217760Stuexen		{
1832217760Stuexen			struct sctp_stream_value *av;
1833217760Stuexen
1834217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
1835217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1836217760Stuexen			if (stcb) {
1837277807Sdelphij				if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
1838277807Sdelphij				    (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
1839277807Sdelphij				    &av->stream_value) < 0)) {
1840217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1841217760Stuexen					error = EINVAL;
1842217760Stuexen				} else {
1843223132Stuexen					*optsize = sizeof(struct sctp_stream_value);
1844217760Stuexen				}
1845217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1846217760Stuexen			} else {
1847217760Stuexen				/*
1848217760Stuexen				 * Can't get stream value without
1849217760Stuexen				 * association
1850217760Stuexen				 */
1851217760Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1852217760Stuexen				error = EINVAL;
1853217760Stuexen			}
1854223132Stuexen			break;
1855217760Stuexen		}
1856163953Srrs	case SCTP_GET_ADDR_LEN:
1857163953Srrs		{
1858163953Srrs			struct sctp_assoc_value *av;
1859163953Srrs
1860166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1861163953Srrs			error = EINVAL;
1862167598Srrs#ifdef INET
1863163953Srrs			if (av->assoc_value == AF_INET) {
1864163953Srrs				av->assoc_value = sizeof(struct sockaddr_in);
1865163953Srrs				error = 0;
1866163953Srrs			}
1867163953Srrs#endif
1868167598Srrs#ifdef INET6
1869163953Srrs			if (av->assoc_value == AF_INET6) {
1870163953Srrs				av->assoc_value = sizeof(struct sockaddr_in6);
1871163953Srrs				error = 0;
1872163953Srrs			}
1873163953Srrs#endif
1874172091Srrs			if (error) {
1875171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1876223132Stuexen			} else {
1877223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1878172091Srrs			}
1879223132Stuexen			break;
1880163953Srrs		}
1881169655Srrs	case SCTP_GET_ASSOC_NUMBER:
1882163953Srrs		{
1883169655Srrs			uint32_t *value, cnt;
1884163953Srrs
1885169655Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1886294222Stuexen			SCTP_INP_RLOCK(inp);
1887294222Stuexen			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1888294222Stuexen			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
1889294222Stuexen				/* Can't do this for a 1-1 socket */
1890294222Stuexen				error = EINVAL;
1891294222Stuexen				SCTP_INP_RUNLOCK(inp);
1892294222Stuexen				break;
1893294222Stuexen			}
1894163953Srrs			cnt = 0;
1895169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1896169655Srrs				cnt++;
1897163953Srrs			}
1898169655Srrs			SCTP_INP_RUNLOCK(inp);
1899169655Srrs			*value = cnt;
1900169655Srrs			*optsize = sizeof(uint32_t);
1901223132Stuexen			break;
1902169655Srrs		}
1903169655Srrs	case SCTP_GET_ASSOC_ID_LIST:
1904169655Srrs		{
1905169655Srrs			struct sctp_assoc_ids *ids;
1906169655Srrs			unsigned int at, limit;
1907169655Srrs
1908169655Srrs			SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
1909294222Stuexen			SCTP_INP_RLOCK(inp);
1910294222Stuexen			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1911294222Stuexen			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
1912294222Stuexen				/* Can't do this for a 1-1 socket */
1913294222Stuexen				error = EINVAL;
1914294222Stuexen				SCTP_INP_RUNLOCK(inp);
1915294222Stuexen				break;
1916294222Stuexen			}
1917163953Srrs			at = 0;
1918185694Srrs			limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t);
1919169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1920169655Srrs				if (at < limit) {
1921169655Srrs					ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
1922169655Srrs				} else {
1923169655Srrs					error = EINVAL;
1924171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1925163953Srrs					break;
1926163953Srrs				}
1927163953Srrs			}
1928163953Srrs			SCTP_INP_RUNLOCK(inp);
1929223132Stuexen			if (error == 0) {
1930223132Stuexen				ids->gaids_number_of_ids = at;
1931223132Stuexen				*optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
1932223132Stuexen			}
1933223132Stuexen			break;
1934163953Srrs		}
1935163953Srrs	case SCTP_CONTEXT:
1936163953Srrs		{
1937163953Srrs			struct sctp_assoc_value *av;
1938163953Srrs
1939166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1940166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1941166675Srrs
1942166675Srrs			if (stcb) {
1943166675Srrs				av->assoc_value = stcb->asoc.context;
1944166675Srrs				SCTP_TCB_UNLOCK(stcb);
1945163953Srrs			} else {
1946224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1947224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1948224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1949223132Stuexen					SCTP_INP_RLOCK(inp);
1950223132Stuexen					av->assoc_value = inp->sctp_context;
1951223132Stuexen					SCTP_INP_RUNLOCK(inp);
1952223132Stuexen				} else {
1953223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1954223132Stuexen					error = EINVAL;
1955223132Stuexen				}
1956163953Srrs			}
1957223132Stuexen			if (error == 0) {
1958223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1959223132Stuexen			}
1960223132Stuexen			break;
1961163953Srrs		}
1962167598Srrs	case SCTP_VRF_ID:
1963167598Srrs		{
1964170056Srrs			uint32_t *default_vrfid;
1965167598Srrs
1966170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
1967170056Srrs			*default_vrfid = inp->def_vrf_id;
1968223132Stuexen			*optsize = sizeof(uint32_t);
1969167598Srrs			break;
1970167598Srrs		}
1971167598Srrs	case SCTP_GET_ASOC_VRF:
1972167598Srrs		{
1973167598Srrs			struct sctp_assoc_value *id;
1974167598Srrs
1975167598Srrs			SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
1976167598Srrs			SCTP_FIND_STCB(inp, stcb, id->assoc_id);
1977167598Srrs			if (stcb == NULL) {
1978167598Srrs				error = EINVAL;
1979171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1980223132Stuexen			} else {
1981223132Stuexen				id->assoc_value = stcb->asoc.vrf_id;
1982223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1983167598Srrs			}
1984167598Srrs			break;
1985167598Srrs		}
1986167598Srrs	case SCTP_GET_VRF_IDS:
1987167598Srrs		{
1988171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1989167598Srrs			error = EOPNOTSUPP;
1990167598Srrs			break;
1991167598Srrs		}
1992163953Srrs	case SCTP_GET_NONCE_VALUES:
1993163953Srrs		{
1994163953Srrs			struct sctp_get_nonce_values *gnv;
1995163953Srrs
1996166675Srrs			SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
1997166675Srrs			SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
1998166675Srrs
1999166675Srrs			if (stcb) {
2000163953Srrs				gnv->gn_peers_tag = stcb->asoc.peer_vtag;
2001163953Srrs				gnv->gn_local_tag = stcb->asoc.my_vtag;
2002163953Srrs				SCTP_TCB_UNLOCK(stcb);
2003223132Stuexen				*optsize = sizeof(struct sctp_get_nonce_values);
2004166675Srrs			} else {
2005171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2006166675Srrs				error = ENOTCONN;
2007163953Srrs			}
2008223132Stuexen			break;
2009163953Srrs		}
2010170056Srrs	case SCTP_DELAYED_SACK:
2011163953Srrs		{
2012170056Srrs			struct sctp_sack_info *sack;
2013163953Srrs
2014170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
2015170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
2016166675Srrs			if (stcb) {
2017170056Srrs				sack->sack_delay = stcb->asoc.delayed_ack;
2018170056Srrs				sack->sack_freq = stcb->asoc.sack_freq;
2019166675Srrs				SCTP_TCB_UNLOCK(stcb);
2020166675Srrs			} else {
2021224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2022224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2023224918Stuexen				    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) {
2024223132Stuexen					SCTP_INP_RLOCK(inp);
2025223132Stuexen					sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
2026223132Stuexen					sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
2027223132Stuexen					SCTP_INP_RUNLOCK(inp);
2028223132Stuexen				} else {
2029223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2030223132Stuexen					error = EINVAL;
2031223132Stuexen				}
2032163953Srrs			}
2033223132Stuexen			if (error == 0) {
2034223132Stuexen				*optsize = sizeof(struct sctp_sack_info);
2035223132Stuexen			}
2036223132Stuexen			break;
2037163953Srrs		}
2038163953Srrs	case SCTP_GET_SNDBUF_USE:
2039166675Srrs		{
2040163953Srrs			struct sctp_sockstat *ss;
2041163953Srrs
2042166675Srrs			SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
2043166675Srrs			SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
2044166675Srrs
2045166675Srrs			if (stcb) {
2046166675Srrs				ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
2047166675Srrs				ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
2048166675Srrs				    stcb->asoc.size_on_all_streams);
2049166675Srrs				SCTP_TCB_UNLOCK(stcb);
2050223132Stuexen				*optsize = sizeof(struct sctp_sockstat);
2051166675Srrs			} else {
2052171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2053163953Srrs				error = ENOTCONN;
2054163953Srrs			}
2055223132Stuexen			break;
2056163953Srrs		}
2057170056Srrs	case SCTP_MAX_BURST:
2058163953Srrs		{
2059217895Stuexen			struct sctp_assoc_value *av;
2060163953Srrs
2061217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2062217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2063166675Srrs
2064217895Stuexen			if (stcb) {
2065217895Stuexen				av->assoc_value = stcb->asoc.max_burst;
2066217895Stuexen				SCTP_TCB_UNLOCK(stcb);
2067217894Stuexen			} else {
2068224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2069224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2070224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2071223132Stuexen					SCTP_INP_RLOCK(inp);
2072223132Stuexen					av->assoc_value = inp->sctp_ep.max_burst;
2073223132Stuexen					SCTP_INP_RUNLOCK(inp);
2074223132Stuexen				} else {
2075223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2076223132Stuexen					error = EINVAL;
2077223132Stuexen				}
2078217894Stuexen			}
2079223132Stuexen			if (error == 0) {
2080223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2081223132Stuexen			}
2082223132Stuexen			break;
2083163953Srrs		}
2084163953Srrs	case SCTP_MAXSEG:
2085163953Srrs		{
2086167598Srrs			struct sctp_assoc_value *av;
2087163953Srrs			int ovh;
2088163953Srrs
2089167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2090170056Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2091163953Srrs
2092167598Srrs			if (stcb) {
2093167598Srrs				av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
2094167598Srrs				SCTP_TCB_UNLOCK(stcb);
2095163953Srrs			} else {
2096224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2097224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2098224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2099223132Stuexen					SCTP_INP_RLOCK(inp);
2100223132Stuexen					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2101223132Stuexen						ovh = SCTP_MED_OVERHEAD;
2102223132Stuexen					} else {
2103223132Stuexen						ovh = SCTP_MED_V4_OVERHEAD;
2104223132Stuexen					}
2105223132Stuexen					if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
2106223132Stuexen						av->assoc_value = 0;
2107223132Stuexen					else
2108223132Stuexen						av->assoc_value = inp->sctp_frag_point - ovh;
2109223132Stuexen					SCTP_INP_RUNLOCK(inp);
2110167598Srrs				} else {
2111223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2112223132Stuexen					error = EINVAL;
2113167598Srrs				}
2114163953Srrs			}
2115223132Stuexen			if (error == 0) {
2116223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2117223132Stuexen			}
2118223132Stuexen			break;
2119163953Srrs		}
2120163953Srrs	case SCTP_GET_STAT_LOG:
2121167598Srrs		error = sctp_fill_stat_log(optval, optsize);
2122163953Srrs		break;
2123163953Srrs	case SCTP_EVENTS:
2124163953Srrs		{
2125163953Srrs			struct sctp_event_subscribe *events;
2126163953Srrs
2127166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
2128223132Stuexen			memset(events, 0, sizeof(struct sctp_event_subscribe));
2129163953Srrs			SCTP_INP_RLOCK(inp);
2130163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
2131163953Srrs				events->sctp_data_io_event = 1;
2132163953Srrs
2133163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
2134163953Srrs				events->sctp_association_event = 1;
2135163953Srrs
2136163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
2137163953Srrs				events->sctp_address_event = 1;
2138163953Srrs
2139163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
2140163953Srrs				events->sctp_send_failure_event = 1;
2141163953Srrs
2142163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
2143163953Srrs				events->sctp_peer_error_event = 1;
2144163953Srrs
2145163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
2146163953Srrs				events->sctp_shutdown_event = 1;
2147163953Srrs
2148163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
2149163953Srrs				events->sctp_partial_delivery_event = 1;
2150163953Srrs
2151163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
2152163953Srrs				events->sctp_adaptation_layer_event = 1;
2153163953Srrs
2154163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
2155163953Srrs				events->sctp_authentication_event = 1;
2156163953Srrs
2157185694Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
2158185694Srrs				events->sctp_sender_dry_event = 1;
2159185694Srrs
2160163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
2161202520Srrs				events->sctp_stream_reset_event = 1;
2162163953Srrs			SCTP_INP_RUNLOCK(inp);
2163166675Srrs			*optsize = sizeof(struct sctp_event_subscribe);
2164223132Stuexen			break;
2165163953Srrs		}
2166163953Srrs	case SCTP_ADAPTATION_LAYER:
2167166675Srrs		{
2168166675Srrs			uint32_t *value;
2169166675Srrs
2170166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2171166675Srrs
2172166675Srrs			SCTP_INP_RLOCK(inp);
2173166675Srrs			*value = inp->sctp_ep.adaptation_layer_indicator;
2174166675Srrs			SCTP_INP_RUNLOCK(inp);
2175166675Srrs			*optsize = sizeof(uint32_t);
2176223132Stuexen			break;
2177163953Srrs		}
2178163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
2179166675Srrs		{
2180166675Srrs			uint32_t *value;
2181166675Srrs
2182166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2183166675Srrs			SCTP_INP_RLOCK(inp);
2184166675Srrs			*value = inp->sctp_ep.initial_sequence_debug;
2185166675Srrs			SCTP_INP_RUNLOCK(inp);
2186166675Srrs			*optsize = sizeof(uint32_t);
2187223132Stuexen			break;
2188163953Srrs		}
2189163953Srrs	case SCTP_GET_LOCAL_ADDR_SIZE:
2190166675Srrs		{
2191166675Srrs			uint32_t *value;
2192166675Srrs
2193166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2194166675Srrs			SCTP_INP_RLOCK(inp);
2195168124Srrs			*value = sctp_count_max_addresses(inp);
2196166675Srrs			SCTP_INP_RUNLOCK(inp);
2197166675Srrs			*optsize = sizeof(uint32_t);
2198223132Stuexen			break;
2199163953Srrs		}
2200163953Srrs	case SCTP_GET_REMOTE_ADDR_SIZE:
2201163953Srrs		{
2202166675Srrs			uint32_t *value;
2203166675Srrs			size_t size;
2204163953Srrs			struct sctp_nets *net;
2205163953Srrs
2206166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2207166675Srrs			/* FIXME MT: change to sctp_assoc_value? */
2208166675Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
2209166675Srrs
2210166675Srrs			if (stcb) {
2211166675Srrs				size = 0;
2212166675Srrs				/* Count the sizes */
2213166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2214283699Stuexen					switch (net->ro._l_addr.sa.sa_family) {
2215221249Stuexen#ifdef INET
2216283699Stuexen					case AF_INET:
2217283699Stuexen#ifdef INET6
2218283699Stuexen						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2219283699Stuexen							size += sizeof(struct sockaddr_in6);
2220283699Stuexen						} else {
2221221249Stuexen							size += sizeof(struct sockaddr_in);
2222283699Stuexen						}
2223283699Stuexen#else
2224283699Stuexen						size += sizeof(struct sockaddr_in);
2225221249Stuexen#endif
2226283699Stuexen						break;
2227283699Stuexen#endif
2228221249Stuexen#ifdef INET6
2229283699Stuexen					case AF_INET6:
2230283699Stuexen						size += sizeof(struct sockaddr_in6);
2231283699Stuexen						break;
2232221249Stuexen#endif
2233283699Stuexen					default:
2234283699Stuexen						break;
2235166675Srrs					}
2236163953Srrs				}
2237166675Srrs				SCTP_TCB_UNLOCK(stcb);
2238166675Srrs				*value = (uint32_t) size;
2239223132Stuexen				*optsize = sizeof(uint32_t);
2240166675Srrs			} else {
2241171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2242166675Srrs				error = ENOTCONN;
2243163953Srrs			}
2244223132Stuexen			break;
2245163953Srrs		}
2246163953Srrs	case SCTP_GET_PEER_ADDRESSES:
2247163953Srrs		/*
2248163953Srrs		 * Get the address information, an array is passed in to
2249163953Srrs		 * fill up we pack it.
2250163953Srrs		 */
2251163953Srrs		{
2252166675Srrs			size_t cpsz, left;
2253163953Srrs			struct sockaddr_storage *sas;
2254163953Srrs			struct sctp_nets *net;
2255163953Srrs			struct sctp_getaddresses *saddr;
2256163953Srrs
2257166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2258166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2259163953Srrs
2260166675Srrs			if (stcb) {
2261166675Srrs				left = (*optsize) - sizeof(struct sctp_getaddresses);
2262166675Srrs				*optsize = sizeof(struct sctp_getaddresses);
2263166675Srrs				sas = (struct sockaddr_storage *)&saddr->addr[0];
2264166675Srrs
2265166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2266283699Stuexen					switch (net->ro._l_addr.sa.sa_family) {
2267221249Stuexen#ifdef INET
2268283699Stuexen					case AF_INET:
2269283699Stuexen#ifdef INET6
2270283699Stuexen						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2271283699Stuexen							cpsz = sizeof(struct sockaddr_in6);
2272283699Stuexen						} else {
2273221249Stuexen							cpsz = sizeof(struct sockaddr_in);
2274283699Stuexen						}
2275283699Stuexen#else
2276283699Stuexen						cpsz = sizeof(struct sockaddr_in);
2277221249Stuexen#endif
2278283699Stuexen						break;
2279283699Stuexen#endif
2280221249Stuexen#ifdef INET6
2281283699Stuexen					case AF_INET6:
2282283699Stuexen						cpsz = sizeof(struct sockaddr_in6);
2283283699Stuexen						break;
2284221249Stuexen#endif
2285283699Stuexen					default:
2286283699Stuexen						cpsz = 0;
2287283699Stuexen						break;
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)) &&
2298283699Stuexen					    (net->ro._l_addr.sa.sa_family == AF_INET)) {
2299166675Srrs						/* Must map the address */
2300283699Stuexen						in6_sin_2_v4mapsin6(&net->ro._l_addr.sin,
2301166675Srrs						    (struct sockaddr_in6 *)sas);
2302166675Srrs					} else {
2303166675Srrs						memcpy(sas, &net->ro._l_addr, cpsz);
2304166675Srrs					}
2305283699Stuexen#else
2306283699Stuexen					memcpy(sas, &net->ro._l_addr, cpsz);
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;
2343283699Stuexen			struct sockaddr *addr;
2344163953Srrs
2345283699Stuexen#if defined(INET) && defined(INET6)
2346283699Stuexen			struct sockaddr_in sin_store;
2347283699Stuexen
2348283699Stuexen#endif
2349283699Stuexen
2350166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
2351166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
2352163953Srrs
2353283699Stuexen#if defined(INET) && defined(INET6)
2354283699Stuexen			if (paddrp->spp_address.ss_family == AF_INET6) {
2355283699Stuexen				struct sockaddr_in6 *sin6;
2356283699Stuexen
2357283699Stuexen				sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
2358283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
2359283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
2360283699Stuexen					addr = (struct sockaddr *)&sin_store;
2361283699Stuexen				} else {
2362283699Stuexen					addr = (struct sockaddr *)&paddrp->spp_address;
2363283699Stuexen				}
2364166675Srrs			} else {
2365283699Stuexen				addr = (struct sockaddr *)&paddrp->spp_address;
2366283699Stuexen			}
2367283699Stuexen#else
2368283699Stuexen			addr = (struct sockaddr *)&paddrp->spp_address;
2369283699Stuexen#endif
2370283699Stuexen			if (stcb != NULL) {
2371283699Stuexen				net = sctp_findnet(stcb, addr);
2372283699Stuexen			} else {
2373166675Srrs				/*
2374166675Srrs				 * We increment here since
2375166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2376166675Srrs				 * decrement if it finds the stcb as long as
2377166675Srrs				 * the locked tcb (last argument) is NOT a
2378166675Srrs				 * TCB.. aka NULL.
2379166675Srrs				 */
2380283699Stuexen				net = NULL;
2381166675Srrs				SCTP_INP_INCR_REF(inp);
2382283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
2383163953Srrs				if (stcb == NULL) {
2384166675Srrs					SCTP_INP_DECR_REF(inp);
2385163953Srrs				}
2386163953Srrs			}
2387283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
2388221249Stuexen#ifdef INET
2389283699Stuexen				if (addr->sa_family == AF_INET) {
2390171943Srrs					struct sockaddr_in *sin;
2391171943Srrs
2392283699Stuexen					sin = (struct sockaddr_in *)addr;
2393283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
2394171943Srrs						error = EINVAL;
2395171943Srrs						SCTP_TCB_UNLOCK(stcb);
2396171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2397171943Srrs						break;
2398171943Srrs					}
2399221249Stuexen				} else
2400221249Stuexen#endif
2401221249Stuexen#ifdef INET6
2402283699Stuexen				if (addr->sa_family == AF_INET6) {
2403171943Srrs					struct sockaddr_in6 *sin6;
2404171943Srrs
2405283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
2406171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
2407171943Srrs						error = EINVAL;
2408171943Srrs						SCTP_TCB_UNLOCK(stcb);
2409171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2410171943Srrs						break;
2411171943Srrs					}
2412221249Stuexen				} else
2413221249Stuexen#endif
2414221249Stuexen				{
2415171943Srrs					error = EAFNOSUPPORT;
2416171943Srrs					SCTP_TCB_UNLOCK(stcb);
2417171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2418171943Srrs					break;
2419171943Srrs				}
2420171943Srrs			}
2421283699Stuexen			if (stcb != NULL) {
2422224641Stuexen				/* Applies to the specific association */
2423163953Srrs				paddrp->spp_flags = 0;
2424283699Stuexen				if (net != NULL) {
2425224641Stuexen					paddrp->spp_hbinterval = net->heart_beat_delay;
2426163953Srrs					paddrp->spp_pathmaxrxt = net->failure_threshold;
2427283829Stuexen					paddrp->spp_pathmtu = net->mtu;
2428283829Stuexen					switch (net->ro._l_addr.sa.sa_family) {
2429283829Stuexen#ifdef INET
2430283829Stuexen					case AF_INET:
2431283829Stuexen						paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD;
2432283829Stuexen						break;
2433283829Stuexen#endif
2434283829Stuexen#ifdef INET6
2435283829Stuexen					case AF_INET6:
2436283829Stuexen						paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD;
2437283829Stuexen						break;
2438283829Stuexen#endif
2439283829Stuexen					default:
2440283829Stuexen						break;
2441283829Stuexen					}
2442163953Srrs					/* get flags for HB */
2443225635Stuexen					if (net->dest_state & SCTP_ADDR_NOHB) {
2444163953Srrs						paddrp->spp_flags |= SPP_HB_DISABLE;
2445225635Stuexen					} else {
2446163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2447225635Stuexen					}
2448163953Srrs					/* get flags for PMTU */
2449225635Stuexen					if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
2450284440Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2451284440Stuexen					} else {
2452163953Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2453163953Srrs					}
2454225549Stuexen					if (net->dscp & 0x01) {
2455226252Stuexen						paddrp->spp_dscp = net->dscp & 0xfc;
2456224870Stuexen						paddrp->spp_flags |= SPP_DSCP;
2457163953Srrs					}
2458167598Srrs#ifdef INET6
2459225549Stuexen					if ((net->ro._l_addr.sa.sa_family == AF_INET6) &&
2460225549Stuexen					    (net->flowlabel & 0x80000000)) {
2461225549Stuexen						paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff;
2462163953Srrs						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2463163953Srrs					}
2464163953Srrs#endif
2465163953Srrs				} else {
2466163953Srrs					/*
2467163953Srrs					 * No destination so return default
2468163953Srrs					 * value
2469163953Srrs					 */
2470163953Srrs					paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
2471283829Stuexen					paddrp->spp_pathmtu = 0;
2472225549Stuexen					if (stcb->asoc.default_dscp & 0x01) {
2473226252Stuexen						paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
2474225549Stuexen						paddrp->spp_flags |= SPP_DSCP;
2475225549Stuexen					}
2476167598Srrs#ifdef INET6
2477225549Stuexen					if (stcb->asoc.default_flowlabel & 0x80000000) {
2478225549Stuexen						paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff;
2479225549Stuexen						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2480225549Stuexen					}
2481163953Srrs#endif
2482163953Srrs					/* default settings should be these */
2483225635Stuexen					if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2484224641Stuexen						paddrp->spp_flags |= SPP_HB_DISABLE;
2485224641Stuexen					} else {
2486163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2487163953Srrs					}
2488225635Stuexen					if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
2489225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2490225635Stuexen					} else {
2491170056Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2492170056Srrs					}
2493225635Stuexen					paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
2494163953Srrs				}
2495163953Srrs				paddrp->spp_assoc_id = sctp_get_associd(stcb);
2496163953Srrs				SCTP_TCB_UNLOCK(stcb);
2497163953Srrs			} else {
2498224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2499224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2500224918Stuexen				    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
2501223132Stuexen					/* Use endpoint defaults */
2502223132Stuexen					SCTP_INP_RLOCK(inp);
2503223132Stuexen					paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
2504223132Stuexen					paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
2505223132Stuexen					paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
2506223132Stuexen					/* get inp's default */
2507225549Stuexen					if (inp->sctp_ep.default_dscp & 0x01) {
2508226252Stuexen						paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc;
2509225549Stuexen						paddrp->spp_flags |= SPP_DSCP;
2510225549Stuexen					}
2511167598Srrs#ifdef INET6
2512225549Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
2513225549Stuexen					    (inp->sctp_ep.default_flowlabel & 0x80000000)) {
2514225549Stuexen						paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff;
2515223132Stuexen						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2516223132Stuexen					}
2517163953Srrs#endif
2518223132Stuexen					/* can't return this */
2519223132Stuexen					paddrp->spp_pathmtu = 0;
2520170056Srrs
2521223132Stuexen					if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2522223132Stuexen						paddrp->spp_flags |= SPP_HB_ENABLE;
2523223132Stuexen					} else {
2524223132Stuexen						paddrp->spp_flags |= SPP_HB_DISABLE;
2525223132Stuexen					}
2526225635Stuexen					if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
2527225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2528225635Stuexen					} else {
2529225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2530225635Stuexen					}
2531223132Stuexen					SCTP_INP_RUNLOCK(inp);
2532170056Srrs				} else {
2533223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2534223132Stuexen					error = EINVAL;
2535170056Srrs				}
2536163953Srrs			}
2537223132Stuexen			if (error == 0) {
2538223132Stuexen				*optsize = sizeof(struct sctp_paddrparams);
2539223132Stuexen			}
2540223132Stuexen			break;
2541163953Srrs		}
2542163953Srrs	case SCTP_GET_PEER_ADDR_INFO:
2543163953Srrs		{
2544163953Srrs			struct sctp_paddrinfo *paddri;
2545163953Srrs			struct sctp_nets *net;
2546283699Stuexen			struct sockaddr *addr;
2547163953Srrs
2548283699Stuexen#if defined(INET) && defined(INET6)
2549283699Stuexen			struct sockaddr_in sin_store;
2550283699Stuexen
2551283699Stuexen#endif
2552283699Stuexen
2553166675Srrs			SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
2554166675Srrs			SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
2555166675Srrs
2556283699Stuexen#if defined(INET) && defined(INET6)
2557283699Stuexen			if (paddri->spinfo_address.ss_family == AF_INET6) {
2558283699Stuexen				struct sockaddr_in6 *sin6;
2559283699Stuexen
2560283699Stuexen				sin6 = (struct sockaddr_in6 *)&paddri->spinfo_address;
2561283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
2562283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
2563283699Stuexen					addr = (struct sockaddr *)&sin_store;
2564283699Stuexen				} else {
2565283699Stuexen					addr = (struct sockaddr *)&paddri->spinfo_address;
2566283699Stuexen				}
2567166675Srrs			} else {
2568283699Stuexen				addr = (struct sockaddr *)&paddri->spinfo_address;
2569283699Stuexen			}
2570283699Stuexen#else
2571283699Stuexen			addr = (struct sockaddr *)&paddri->spinfo_address;
2572283699Stuexen#endif
2573283699Stuexen			if (stcb != NULL) {
2574283699Stuexen				net = sctp_findnet(stcb, addr);
2575283699Stuexen			} else {
2576166675Srrs				/*
2577166675Srrs				 * We increment here since
2578166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2579166675Srrs				 * decrement if it finds the stcb as long as
2580166675Srrs				 * the locked tcb (last argument) is NOT a
2581166675Srrs				 * TCB.. aka NULL.
2582166675Srrs				 */
2583283699Stuexen				net = NULL;
2584166675Srrs				SCTP_INP_INCR_REF(inp);
2585283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
2586166675Srrs				if (stcb == NULL) {
2587166675Srrs					SCTP_INP_DECR_REF(inp);
2588163953Srrs				}
2589166675Srrs			}
2590163953Srrs
2591283699Stuexen			if ((stcb != NULL) && (net != NULL)) {
2592217635Srrs				if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2593217638Stuexen					/* It's unconfirmed */
2594217635Srrs					paddri->spinfo_state = SCTP_UNCONFIRMED;
2595217635Srrs				} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2596217638Stuexen					/* It's active */
2597217635Srrs					paddri->spinfo_state = SCTP_ACTIVE;
2598217635Srrs				} else {
2599217638Stuexen					/* It's inactive */
2600217635Srrs					paddri->spinfo_state = SCTP_INACTIVE;
2601217635Srrs				}
2602166675Srrs				paddri->spinfo_cwnd = net->cwnd;
2603219014Stuexen				paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2604166675Srrs				paddri->spinfo_rto = net->RTO;
2605166675Srrs				paddri->spinfo_assoc_id = sctp_get_associd(stcb);
2606222029Stuexen				paddri->spinfo_mtu = net->mtu;
2607283829Stuexen				switch (addr->sa_family) {
2608283829Stuexen#if defined(INET)
2609283829Stuexen				case AF_INET:
2610283829Stuexen					paddri->spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
2611283829Stuexen					break;
2612283829Stuexen#endif
2613283829Stuexen#if defined(INET6)
2614283829Stuexen				case AF_INET6:
2615283829Stuexen					paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD;
2616283829Stuexen					break;
2617283829Stuexen#endif
2618283829Stuexen				default:
2619283829Stuexen					break;
2620283829Stuexen				}
2621166675Srrs				SCTP_TCB_UNLOCK(stcb);
2622223132Stuexen				*optsize = sizeof(struct sctp_paddrinfo);
2623163953Srrs			} else {
2624283699Stuexen				if (stcb != NULL) {
2625163953Srrs					SCTP_TCB_UNLOCK(stcb);
2626163953Srrs				}
2627171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2628163953Srrs				error = ENOENT;
2629163953Srrs			}
2630223132Stuexen			break;
2631163953Srrs		}
2632163953Srrs	case SCTP_PCB_STATUS:
2633163953Srrs		{
2634163953Srrs			struct sctp_pcbinfo *spcb;
2635163953Srrs
2636166675Srrs			SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
2637163953Srrs			sctp_fill_pcbinfo(spcb);
2638166675Srrs			*optsize = sizeof(struct sctp_pcbinfo);
2639223132Stuexen			break;
2640163953Srrs		}
2641163953Srrs	case SCTP_STATUS:
2642163953Srrs		{
2643163953Srrs			struct sctp_nets *net;
2644163953Srrs			struct sctp_status *sstat;
2645163953Srrs
2646166675Srrs			SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
2647166675Srrs			SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
2648163953Srrs
2649163953Srrs			if (stcb == NULL) {
2650223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2651163953Srrs				error = EINVAL;
2652163953Srrs				break;
2653163953Srrs			}
2654294149Stuexen			sstat->sstat_state = sctp_map_assoc_state(stcb->asoc.state);
2655173179Srrs			sstat->sstat_assoc_id = sctp_get_associd(stcb);
2656163953Srrs			sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
2657163953Srrs			sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
2658163953Srrs			/*
2659163953Srrs			 * We can't include chunks that have been passed to
2660163953Srrs			 * the socket layer. Only things in queue.
2661163953Srrs			 */
2662163953Srrs			sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
2663163953Srrs			    stcb->asoc.cnt_on_all_streams);
2664163953Srrs
2665163953Srrs
2666163953Srrs			sstat->sstat_instrms = stcb->asoc.streamincnt;
2667163953Srrs			sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
2668163953Srrs			sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
2669163953Srrs			memcpy(&sstat->sstat_primary.spinfo_address,
2670163953Srrs			    &stcb->asoc.primary_destination->ro._l_addr,
2671163953Srrs			    ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
2672163953Srrs			net = stcb->asoc.primary_destination;
2673163953Srrs			((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
2674163953Srrs			/*
2675163953Srrs			 * Again the user can get info from sctp_constants.h
2676163953Srrs			 * for what the state of the network is.
2677163953Srrs			 */
2678217635Srrs			if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2679217635Srrs				/* It's unconfirmed */
2680217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
2681217635Srrs			} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2682217638Stuexen				/* It's active */
2683217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
2684217635Srrs			} else {
2685217638Stuexen				/* It's inactive */
2686217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
2687217635Srrs			}
2688163953Srrs			sstat->sstat_primary.spinfo_cwnd = net->cwnd;
2689219014Stuexen			sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2690163953Srrs			sstat->sstat_primary.spinfo_rto = net->RTO;
2691163953Srrs			sstat->sstat_primary.spinfo_mtu = net->mtu;
2692283829Stuexen			switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) {
2693283829Stuexen#if defined(INET)
2694283829Stuexen			case AF_INET:
2695283829Stuexen				sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
2696283829Stuexen				break;
2697283829Stuexen#endif
2698283829Stuexen#if defined(INET6)
2699283829Stuexen			case AF_INET6:
2700283829Stuexen				sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD;
2701283829Stuexen				break;
2702283829Stuexen#endif
2703283829Stuexen			default:
2704283829Stuexen				break;
2705283829Stuexen			}
2706163953Srrs			sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
2707163953Srrs			SCTP_TCB_UNLOCK(stcb);
2708223132Stuexen			*optsize = sizeof(struct sctp_status);
2709223132Stuexen			break;
2710163953Srrs		}
2711163953Srrs	case SCTP_RTOINFO:
2712163953Srrs		{
2713163953Srrs			struct sctp_rtoinfo *srto;
2714163953Srrs
2715166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
2716166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
2717166675Srrs
2718166675Srrs			if (stcb) {
2719166675Srrs				srto->srto_initial = stcb->asoc.initial_rto;
2720166675Srrs				srto->srto_max = stcb->asoc.maxrto;
2721166675Srrs				srto->srto_min = stcb->asoc.minrto;
2722166675Srrs				SCTP_TCB_UNLOCK(stcb);
2723166675Srrs			} else {
2724224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2725224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2726224918Stuexen				    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
2727223132Stuexen					SCTP_INP_RLOCK(inp);
2728223132Stuexen					srto->srto_initial = inp->sctp_ep.initial_rto;
2729223132Stuexen					srto->srto_max = inp->sctp_ep.sctp_maxrto;
2730223132Stuexen					srto->srto_min = inp->sctp_ep.sctp_minrto;
2731223132Stuexen					SCTP_INP_RUNLOCK(inp);
2732223132Stuexen				} else {
2733223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2734223132Stuexen					error = EINVAL;
2735223132Stuexen				}
2736163953Srrs			}
2737223132Stuexen			if (error == 0) {
2738223132Stuexen				*optsize = sizeof(struct sctp_rtoinfo);
2739223132Stuexen			}
2740223132Stuexen			break;
2741163953Srrs		}
2742215410Stuexen	case SCTP_TIMEOUTS:
2743215410Stuexen		{
2744215410Stuexen			struct sctp_timeouts *stimo;
2745215410Stuexen
2746215410Stuexen			SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize);
2747215410Stuexen			SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id);
2748215410Stuexen
2749215410Stuexen			if (stcb) {
2750215410Stuexen				stimo->stimo_init = stcb->asoc.timoinit;
2751215410Stuexen				stimo->stimo_data = stcb->asoc.timodata;
2752215410Stuexen				stimo->stimo_sack = stcb->asoc.timosack;
2753215410Stuexen				stimo->stimo_shutdown = stcb->asoc.timoshutdown;
2754215410Stuexen				stimo->stimo_heartbeat = stcb->asoc.timoheartbeat;
2755215410Stuexen				stimo->stimo_cookie = stcb->asoc.timocookie;
2756215410Stuexen				stimo->stimo_shutdownack = stcb->asoc.timoshutdownack;
2757215410Stuexen				SCTP_TCB_UNLOCK(stcb);
2758223132Stuexen				*optsize = sizeof(struct sctp_timeouts);
2759215410Stuexen			} else {
2760223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2761215410Stuexen				error = EINVAL;
2762215410Stuexen			}
2763223132Stuexen			break;
2764215410Stuexen		}
2765163953Srrs	case SCTP_ASSOCINFO:
2766163953Srrs		{
2767163953Srrs			struct sctp_assocparams *sasoc;
2768163953Srrs
2769166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
2770166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
2771163953Srrs
2772163953Srrs			if (stcb) {
2773171477Srrs				sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
2774163953Srrs				sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
2775163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
2776163953Srrs				sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
2777163953Srrs				sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
2778163953Srrs				SCTP_TCB_UNLOCK(stcb);
2779163953Srrs			} else {
2780224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2781224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2782224918Stuexen				    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
2783223132Stuexen					SCTP_INP_RLOCK(inp);
2784223132Stuexen					sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
2785223132Stuexen					sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
2786223132Stuexen					sasoc->sasoc_number_peer_destinations = 0;
2787223132Stuexen					sasoc->sasoc_peer_rwnd = 0;
2788223132Stuexen					sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
2789223132Stuexen					SCTP_INP_RUNLOCK(inp);
2790223132Stuexen				} else {
2791223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2792223132Stuexen					error = EINVAL;
2793223132Stuexen				}
2794163953Srrs			}
2795223132Stuexen			if (error == 0) {
2796223132Stuexen				*optsize = sizeof(struct sctp_assocparams);
2797223132Stuexen			}
2798223132Stuexen			break;
2799163953Srrs		}
2800163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
2801163953Srrs		{
2802163953Srrs			struct sctp_sndrcvinfo *s_info;
2803163953Srrs
2804166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
2805166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
2806166675Srrs
2807166675Srrs			if (stcb) {
2808170056Srrs				memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
2809166675Srrs				SCTP_TCB_UNLOCK(stcb);
2810166675Srrs			} else {
2811224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2812224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2813224918Stuexen				    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) {
2814223132Stuexen					SCTP_INP_RLOCK(inp);
2815223132Stuexen					memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
2816223132Stuexen					SCTP_INP_RUNLOCK(inp);
2817223132Stuexen				} else {
2818223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2819223132Stuexen					error = EINVAL;
2820223132Stuexen				}
2821163953Srrs			}
2822223132Stuexen			if (error == 0) {
2823223132Stuexen				*optsize = sizeof(struct sctp_sndrcvinfo);
2824223132Stuexen			}
2825223132Stuexen			break;
2826163953Srrs		}
2827163953Srrs	case SCTP_INITMSG:
2828163953Srrs		{
2829163953Srrs			struct sctp_initmsg *sinit;
2830163953Srrs
2831166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
2832163953Srrs			SCTP_INP_RLOCK(inp);
2833163953Srrs			sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
2834163953Srrs			sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
2835163953Srrs			sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
2836163953Srrs			sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
2837163953Srrs			SCTP_INP_RUNLOCK(inp);
2838223132Stuexen			*optsize = sizeof(struct sctp_initmsg);
2839223132Stuexen			break;
2840163953Srrs		}
2841163953Srrs	case SCTP_PRIMARY_ADDR:
2842163953Srrs		/* we allow a "get" operation on this */
2843163953Srrs		{
2844163953Srrs			struct sctp_setprim *ssp;
2845163953Srrs
2846166675Srrs			SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
2847166675Srrs			SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
2848166675Srrs
2849166675Srrs			if (stcb) {
2850283699Stuexen				union sctp_sockstore *addr;
2851170056Srrs
2852283699Stuexen				addr = &stcb->asoc.primary_destination->ro._l_addr;
2853283699Stuexen				switch (addr->sa.sa_family) {
2854283699Stuexen#ifdef INET
2855283699Stuexen				case AF_INET:
2856283699Stuexen#ifdef INET6
2857283699Stuexen					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2858283699Stuexen						in6_sin_2_v4mapsin6(&addr->sin,
2859283699Stuexen						    (struct sockaddr_in6 *)&ssp->ssp_addr);
2860283699Stuexen					} else {
2861283699Stuexen						memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
2862283699Stuexen					}
2863283699Stuexen#else
2864283699Stuexen					memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
2865283699Stuexen#endif
2866283699Stuexen					break;
2867283699Stuexen#endif
2868283699Stuexen#ifdef INET6
2869283699Stuexen				case AF_INET6:
2870283699Stuexen					memcpy(&ssp->ssp_addr, &addr->sin6, sizeof(struct sockaddr_in6));
2871283699Stuexen					break;
2872283699Stuexen#endif
2873283699Stuexen				default:
2874283699Stuexen					break;
2875283699Stuexen				}
2876166675Srrs				SCTP_TCB_UNLOCK(stcb);
2877223132Stuexen				*optsize = sizeof(struct sctp_setprim);
2878166675Srrs			} else {
2879223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2880163953Srrs				error = EINVAL;
2881163953Srrs			}
2882223132Stuexen			break;
2883163953Srrs		}
2884163953Srrs	case SCTP_HMAC_IDENT:
2885163953Srrs		{
2886163953Srrs			struct sctp_hmacalgo *shmac;
2887163953Srrs			sctp_hmaclist_t *hmaclist;
2888163953Srrs			uint32_t size;
2889163953Srrs			int i;
2890163953Srrs
2891166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
2892166675Srrs
2893163953Srrs			SCTP_INP_RLOCK(inp);
2894163953Srrs			hmaclist = inp->sctp_ep.local_hmacs;
2895163953Srrs			if (hmaclist == NULL) {
2896163953Srrs				/* no HMACs to return */
2897166675Srrs				*optsize = sizeof(*shmac);
2898168299Srrs				SCTP_INP_RUNLOCK(inp);
2899163953Srrs				break;
2900163953Srrs			}
2901163953Srrs			/* is there room for all of the hmac ids? */
2902163953Srrs			size = sizeof(*shmac) + (hmaclist->num_algo *
2903163953Srrs			    sizeof(shmac->shmac_idents[0]));
2904166675Srrs			if ((size_t)(*optsize) < size) {
2905223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2906163953Srrs				error = EINVAL;
2907163953Srrs				SCTP_INP_RUNLOCK(inp);
2908163953Srrs				break;
2909163953Srrs			}
2910163953Srrs			/* copy in the list */
2911181054Srrs			shmac->shmac_number_of_idents = hmaclist->num_algo;
2912181054Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
2913163953Srrs				shmac->shmac_idents[i] = hmaclist->hmac[i];
2914181054Srrs			}
2915163953Srrs			SCTP_INP_RUNLOCK(inp);
2916166675Srrs			*optsize = size;
2917163953Srrs			break;
2918163953Srrs		}
2919163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
2920163953Srrs		{
2921163953Srrs			struct sctp_authkeyid *scact;
2922163953Srrs
2923166675Srrs			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
2924166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
2925166675Srrs
2926166675Srrs			if (stcb) {
2927163953Srrs				/* get the active key on the assoc */
2928185694Srrs				scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
2929163953Srrs				SCTP_TCB_UNLOCK(stcb);
2930163953Srrs			} else {
2931224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2932224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2933224918Stuexen				    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) {
2934223132Stuexen					/* get the endpoint active key */
2935223132Stuexen					SCTP_INP_RLOCK(inp);
2936223132Stuexen					scact->scact_keynumber = inp->sctp_ep.default_keyid;
2937223132Stuexen					SCTP_INP_RUNLOCK(inp);
2938223132Stuexen				} else {
2939223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2940223132Stuexen					error = EINVAL;
2941223132Stuexen				}
2942163953Srrs			}
2943223132Stuexen			if (error == 0) {
2944223132Stuexen				*optsize = sizeof(struct sctp_authkeyid);
2945223132Stuexen			}
2946163953Srrs			break;
2947163953Srrs		}
2948163953Srrs	case SCTP_LOCAL_AUTH_CHUNKS:
2949163953Srrs		{
2950163953Srrs			struct sctp_authchunks *sac;
2951163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2952166675Srrs			size_t size = 0;
2953163953Srrs
2954166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2955166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2956166675Srrs
2957166675Srrs			if (stcb) {
2958163953Srrs				/* get off the assoc */
2959163953Srrs				chklist = stcb->asoc.local_auth_chunks;
2960163953Srrs				/* is there enough space? */
2961163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2962166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2963163953Srrs					error = EINVAL;
2964171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2965166675Srrs				} else {
2966166675Srrs					/* copy in the chunks */
2967169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2968234832Stuexen					sac->gauth_number_of_chunks = (uint32_t) size;
2969223132Stuexen					*optsize = sizeof(struct sctp_authchunks) + size;
2970163953Srrs				}
2971163953Srrs				SCTP_TCB_UNLOCK(stcb);
2972163953Srrs			} else {
2973224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2974224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2975224918Stuexen				    (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) {
2976223132Stuexen					/* get off the endpoint */
2977223132Stuexen					SCTP_INP_RLOCK(inp);
2978223132Stuexen					chklist = inp->sctp_ep.local_auth_chunks;
2979223132Stuexen					/* is there enough space? */
2980223132Stuexen					size = sctp_auth_get_chklist_size(chklist);
2981223132Stuexen					if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2982223132Stuexen						error = EINVAL;
2983223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2984223132Stuexen					} else {
2985223132Stuexen						/* copy in the chunks */
2986223132Stuexen						(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2987234832Stuexen						sac->gauth_number_of_chunks = (uint32_t) size;
2988223132Stuexen						*optsize = sizeof(struct sctp_authchunks) + size;
2989223132Stuexen					}
2990223132Stuexen					SCTP_INP_RUNLOCK(inp);
2991223132Stuexen				} else {
2992223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2993163953Srrs					error = EINVAL;
2994163953Srrs				}
2995163953Srrs			}
2996163953Srrs			break;
2997163953Srrs		}
2998163953Srrs	case SCTP_PEER_AUTH_CHUNKS:
2999163953Srrs		{
3000163953Srrs			struct sctp_authchunks *sac;
3001163953Srrs			sctp_auth_chklist_t *chklist = NULL;
3002166675Srrs			size_t size = 0;
3003163953Srrs
3004166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
3005166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
3006166675Srrs
3007166675Srrs			if (stcb) {
3008166675Srrs				/* get off the assoc */
3009166675Srrs				chklist = stcb->asoc.peer_auth_chunks;
3010166675Srrs				/* is there enough space? */
3011166675Srrs				size = sctp_auth_get_chklist_size(chklist);
3012166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
3013166675Srrs					error = EINVAL;
3014171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3015166675Srrs				} else {
3016166675Srrs					/* copy in the chunks */
3017169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
3018234832Stuexen					sac->gauth_number_of_chunks = (uint32_t) size;
3019223132Stuexen					*optsize = sizeof(struct sctp_authchunks) + size;
3020166675Srrs				}
3021166675Srrs				SCTP_TCB_UNLOCK(stcb);
3022166675Srrs			} else {
3023171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
3024163953Srrs				error = ENOENT;
3025163953Srrs			}
3026163953Srrs			break;
3027163953Srrs		}
3028223132Stuexen	case SCTP_EVENT:
3029223132Stuexen		{
3030223132Stuexen			struct sctp_event *event;
3031223132Stuexen			uint32_t event_type;
3032163953Srrs
3033223132Stuexen			SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize);
3034223132Stuexen			SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
3035163953Srrs
3036223132Stuexen			switch (event->se_type) {
3037223132Stuexen			case SCTP_ASSOC_CHANGE:
3038223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
3039223132Stuexen				break;
3040223132Stuexen			case SCTP_PEER_ADDR_CHANGE:
3041223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
3042223132Stuexen				break;
3043223132Stuexen			case SCTP_REMOTE_ERROR:
3044223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPEERERR;
3045223132Stuexen				break;
3046223132Stuexen			case SCTP_SEND_FAILED:
3047223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
3048223132Stuexen				break;
3049223132Stuexen			case SCTP_SHUTDOWN_EVENT:
3050223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
3051223132Stuexen				break;
3052223132Stuexen			case SCTP_ADAPTATION_INDICATION:
3053223132Stuexen				event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
3054223132Stuexen				break;
3055223132Stuexen			case SCTP_PARTIAL_DELIVERY_EVENT:
3056223132Stuexen				event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
3057223132Stuexen				break;
3058223132Stuexen			case SCTP_AUTHENTICATION_EVENT:
3059223132Stuexen				event_type = SCTP_PCB_FLAGS_AUTHEVNT;
3060223132Stuexen				break;
3061223132Stuexen			case SCTP_STREAM_RESET_EVENT:
3062223132Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
3063223132Stuexen				break;
3064223132Stuexen			case SCTP_SENDER_DRY_EVENT:
3065223132Stuexen				event_type = SCTP_PCB_FLAGS_DRYEVNT;
3066223132Stuexen				break;
3067223132Stuexen			case SCTP_NOTIFICATIONS_STOPPED_EVENT:
3068223132Stuexen				event_type = 0;
3069223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
3070223132Stuexen				error = ENOTSUP;
3071223132Stuexen				break;
3072235009Stuexen			case SCTP_ASSOC_RESET_EVENT:
3073235009Stuexen				event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
3074235009Stuexen				break;
3075235009Stuexen			case SCTP_STREAM_CHANGE_EVENT:
3076235009Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
3077235009Stuexen				break;
3078235075Stuexen			case SCTP_SEND_FAILED_EVENT:
3079235075Stuexen				event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
3080235075Stuexen				break;
3081223132Stuexen			default:
3082223132Stuexen				event_type = 0;
3083223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3084223132Stuexen				error = EINVAL;
3085223132Stuexen				break;
3086223132Stuexen			}
3087223132Stuexen			if (event_type > 0) {
3088223132Stuexen				if (stcb) {
3089223132Stuexen					event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
3090223132Stuexen					SCTP_TCB_UNLOCK(stcb);
3091223132Stuexen				} else {
3092224918Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3093224918Stuexen					    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3094224918Stuexen					    (event->se_assoc_id == SCTP_FUTURE_ASSOC)) {
3095223132Stuexen						SCTP_INP_RLOCK(inp);
3096223132Stuexen						event->se_on = sctp_is_feature_on(inp, event_type);
3097223132Stuexen						SCTP_INP_RUNLOCK(inp);
3098223132Stuexen					} else {
3099223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3100223132Stuexen						error = EINVAL;
3101223132Stuexen					}
3102223132Stuexen				}
3103223132Stuexen			}
3104223132Stuexen			if (error == 0) {
3105223132Stuexen				*optsize = sizeof(struct sctp_event);
3106223132Stuexen			}
3107223132Stuexen			break;
3108223132Stuexen		}
3109223132Stuexen	case SCTP_RECVRCVINFO:
3110223132Stuexen		{
3111223132Stuexen			int onoff;
3112223132Stuexen
3113223132Stuexen			if (*optsize < sizeof(int)) {
3114223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3115223132Stuexen				error = EINVAL;
3116223132Stuexen			} else {
3117230104Stuexen				SCTP_INP_RLOCK(inp);
3118223132Stuexen				onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
3119223132Stuexen				SCTP_INP_RUNLOCK(inp);
3120223132Stuexen			}
3121223132Stuexen			if (error == 0) {
3122223132Stuexen				/* return the option value */
3123223132Stuexen				*(int *)optval = onoff;
3124223132Stuexen				*optsize = sizeof(int);
3125223132Stuexen			}
3126223132Stuexen			break;
3127223132Stuexen		}
3128223132Stuexen	case SCTP_RECVNXTINFO:
3129223132Stuexen		{
3130223132Stuexen			int onoff;
3131223132Stuexen
3132223132Stuexen			if (*optsize < sizeof(int)) {
3133223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3134223132Stuexen				error = EINVAL;
3135223132Stuexen			} else {
3136230104Stuexen				SCTP_INP_RLOCK(inp);
3137223132Stuexen				onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
3138223132Stuexen				SCTP_INP_RUNLOCK(inp);
3139223132Stuexen			}
3140223132Stuexen			if (error == 0) {
3141223132Stuexen				/* return the option value */
3142223132Stuexen				*(int *)optval = onoff;
3143223132Stuexen				*optsize = sizeof(int);
3144223132Stuexen			}
3145223132Stuexen			break;
3146223132Stuexen		}
3147223132Stuexen	case SCTP_DEFAULT_SNDINFO:
3148223132Stuexen		{
3149223132Stuexen			struct sctp_sndinfo *info;
3150223132Stuexen
3151223132Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize);
3152223132Stuexen			SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
3153223132Stuexen
3154223132Stuexen			if (stcb) {
3155223132Stuexen				info->snd_sid = stcb->asoc.def_send.sinfo_stream;
3156223132Stuexen				info->snd_flags = stcb->asoc.def_send.sinfo_flags;
3157223162Stuexen				info->snd_flags &= 0xfff0;
3158223132Stuexen				info->snd_ppid = stcb->asoc.def_send.sinfo_ppid;
3159223132Stuexen				info->snd_context = stcb->asoc.def_send.sinfo_context;
3160223132Stuexen				SCTP_TCB_UNLOCK(stcb);
3161223132Stuexen			} else {
3162224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3163224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3164224918Stuexen				    (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) {
3165223132Stuexen					SCTP_INP_RLOCK(inp);
3166223132Stuexen					info->snd_sid = inp->def_send.sinfo_stream;
3167223132Stuexen					info->snd_flags = inp->def_send.sinfo_flags;
3168223162Stuexen					info->snd_flags &= 0xfff0;
3169223132Stuexen					info->snd_ppid = inp->def_send.sinfo_ppid;
3170223132Stuexen					info->snd_context = inp->def_send.sinfo_context;
3171223132Stuexen					SCTP_INP_RUNLOCK(inp);
3172223132Stuexen				} else {
3173223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3174223132Stuexen					error = EINVAL;
3175223132Stuexen				}
3176223132Stuexen			}
3177223132Stuexen			if (error == 0) {
3178223132Stuexen				*optsize = sizeof(struct sctp_sndinfo);
3179223132Stuexen			}
3180223132Stuexen			break;
3181223132Stuexen		}
3182223162Stuexen	case SCTP_DEFAULT_PRINFO:
3183223162Stuexen		{
3184223162Stuexen			struct sctp_default_prinfo *info;
3185223162Stuexen
3186223162Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize);
3187223162Stuexen			SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
3188223162Stuexen
3189223162Stuexen			if (stcb) {
3190223162Stuexen				info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
3191223162Stuexen				info->pr_value = stcb->asoc.def_send.sinfo_timetolive;
3192223162Stuexen				SCTP_TCB_UNLOCK(stcb);
3193223162Stuexen			} else {
3194224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3195224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3196224918Stuexen				    (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) {
3197223162Stuexen					SCTP_INP_RLOCK(inp);
3198223162Stuexen					info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
3199223162Stuexen					info->pr_value = inp->def_send.sinfo_timetolive;
3200223162Stuexen					SCTP_INP_RUNLOCK(inp);
3201223162Stuexen				} else {
3202223162Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3203223162Stuexen					error = EINVAL;
3204223162Stuexen				}
3205223162Stuexen			}
3206223162Stuexen			if (error == 0) {
3207223162Stuexen				*optsize = sizeof(struct sctp_default_prinfo);
3208223162Stuexen			}
3209223162Stuexen			break;
3210223162Stuexen		}
3211224641Stuexen	case SCTP_PEER_ADDR_THLDS:
3212224641Stuexen		{
3213224641Stuexen			struct sctp_paddrthlds *thlds;
3214224641Stuexen			struct sctp_nets *net;
3215283699Stuexen			struct sockaddr *addr;
3216224641Stuexen
3217283699Stuexen#if defined(INET) && defined(INET6)
3218283699Stuexen			struct sockaddr_in sin_store;
3219283699Stuexen
3220283699Stuexen#endif
3221283699Stuexen
3222224641Stuexen			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
3223224641Stuexen			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
3224224641Stuexen
3225283699Stuexen#if defined(INET) && defined(INET6)
3226283699Stuexen			if (thlds->spt_address.ss_family == AF_INET6) {
3227283699Stuexen				struct sockaddr_in6 *sin6;
3228283699Stuexen
3229283699Stuexen				sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
3230283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3231283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
3232283699Stuexen					addr = (struct sockaddr *)&sin_store;
3233283699Stuexen				} else {
3234283699Stuexen					addr = (struct sockaddr *)&thlds->spt_address;
3235283699Stuexen				}
3236224641Stuexen			} else {
3237283699Stuexen				addr = (struct sockaddr *)&thlds->spt_address;
3238283699Stuexen			}
3239283699Stuexen#else
3240283699Stuexen			addr = (struct sockaddr *)&thlds->spt_address;
3241283699Stuexen#endif
3242283699Stuexen			if (stcb != NULL) {
3243283699Stuexen				net = sctp_findnet(stcb, addr);
3244283699Stuexen			} else {
3245224641Stuexen				/*
3246224641Stuexen				 * We increment here since
3247224641Stuexen				 * sctp_findassociation_ep_addr() wil do a
3248224641Stuexen				 * decrement if it finds the stcb as long as
3249224641Stuexen				 * the locked tcb (last argument) is NOT a
3250224641Stuexen				 * TCB.. aka NULL.
3251224641Stuexen				 */
3252283699Stuexen				net = NULL;
3253224641Stuexen				SCTP_INP_INCR_REF(inp);
3254283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
3255224641Stuexen				if (stcb == NULL) {
3256224641Stuexen					SCTP_INP_DECR_REF(inp);
3257224641Stuexen				}
3258224641Stuexen			}
3259283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
3260224641Stuexen#ifdef INET
3261283699Stuexen				if (addr->sa_family == AF_INET) {
3262224641Stuexen					struct sockaddr_in *sin;
3263224641Stuexen
3264283699Stuexen					sin = (struct sockaddr_in *)addr;
3265283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
3266224641Stuexen						error = EINVAL;
3267224641Stuexen						SCTP_TCB_UNLOCK(stcb);
3268224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3269224641Stuexen						break;
3270224641Stuexen					}
3271224641Stuexen				} else
3272224641Stuexen#endif
3273224641Stuexen#ifdef INET6
3274283699Stuexen				if (addr->sa_family == AF_INET6) {
3275224641Stuexen					struct sockaddr_in6 *sin6;
3276224641Stuexen
3277283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
3278224641Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3279224641Stuexen						error = EINVAL;
3280224641Stuexen						SCTP_TCB_UNLOCK(stcb);
3281224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3282224641Stuexen						break;
3283224641Stuexen					}
3284224641Stuexen				} else
3285224641Stuexen#endif
3286224641Stuexen				{
3287224641Stuexen					error = EAFNOSUPPORT;
3288224641Stuexen					SCTP_TCB_UNLOCK(stcb);
3289224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3290224641Stuexen					break;
3291224641Stuexen				}
3292224641Stuexen			}
3293283699Stuexen			if (stcb != NULL) {
3294283699Stuexen				if (net != NULL) {
3295224641Stuexen					thlds->spt_pathmaxrxt = net->failure_threshold;
3296224641Stuexen					thlds->spt_pathpfthld = net->pf_threshold;
3297224641Stuexen				} else {
3298224641Stuexen					thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
3299224641Stuexen					thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
3300224641Stuexen				}
3301224641Stuexen				thlds->spt_assoc_id = sctp_get_associd(stcb);
3302224641Stuexen				SCTP_TCB_UNLOCK(stcb);
3303224641Stuexen			} else {
3304224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3305224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3306224918Stuexen				    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
3307224641Stuexen					/* Use endpoint defaults */
3308224641Stuexen					SCTP_INP_RLOCK(inp);
3309224641Stuexen					thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
3310224641Stuexen					thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
3311224641Stuexen					SCTP_INP_RUNLOCK(inp);
3312224641Stuexen				} else {
3313224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3314224641Stuexen					error = EINVAL;
3315224641Stuexen				}
3316224641Stuexen			}
3317224641Stuexen			if (error == 0) {
3318224641Stuexen				*optsize = sizeof(struct sctp_paddrthlds);
3319224641Stuexen			}
3320224641Stuexen			break;
3321224641Stuexen		}
3322227755Stuexen	case SCTP_REMOTE_UDP_ENCAPS_PORT:
3323227755Stuexen		{
3324227755Stuexen			struct sctp_udpencaps *encaps;
3325227755Stuexen			struct sctp_nets *net;
3326283699Stuexen			struct sockaddr *addr;
3327227755Stuexen
3328283699Stuexen#if defined(INET) && defined(INET6)
3329283699Stuexen			struct sockaddr_in sin_store;
3330283699Stuexen
3331283699Stuexen#endif
3332283699Stuexen
3333227755Stuexen			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize);
3334227755Stuexen			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
3335227755Stuexen
3336283699Stuexen#if defined(INET) && defined(INET6)
3337283699Stuexen			if (encaps->sue_address.ss_family == AF_INET6) {
3338283699Stuexen				struct sockaddr_in6 *sin6;
3339283699Stuexen
3340283699Stuexen				sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
3341283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3342283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
3343283699Stuexen					addr = (struct sockaddr *)&sin_store;
3344283699Stuexen				} else {
3345283699Stuexen					addr = (struct sockaddr *)&encaps->sue_address;
3346283699Stuexen				}
3347283699Stuexen			} else {
3348283699Stuexen				addr = (struct sockaddr *)&encaps->sue_address;
3349283699Stuexen			}
3350283699Stuexen#else
3351283699Stuexen			addr = (struct sockaddr *)&encaps->sue_address;
3352283699Stuexen#endif
3353227755Stuexen			if (stcb) {
3354283699Stuexen				net = sctp_findnet(stcb, addr);
3355227755Stuexen			} else {
3356227755Stuexen				/*
3357227755Stuexen				 * We increment here since
3358227755Stuexen				 * sctp_findassociation_ep_addr() wil do a
3359227755Stuexen				 * decrement if it finds the stcb as long as
3360227755Stuexen				 * the locked tcb (last argument) is NOT a
3361227755Stuexen				 * TCB.. aka NULL.
3362227755Stuexen				 */
3363227755Stuexen				net = NULL;
3364227755Stuexen				SCTP_INP_INCR_REF(inp);
3365283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
3366227755Stuexen				if (stcb == NULL) {
3367227755Stuexen					SCTP_INP_DECR_REF(inp);
3368227755Stuexen				}
3369227755Stuexen			}
3370283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
3371227755Stuexen#ifdef INET
3372283699Stuexen				if (addr->sa_family == AF_INET) {
3373227755Stuexen					struct sockaddr_in *sin;
3374227755Stuexen
3375283699Stuexen					sin = (struct sockaddr_in *)addr;
3376283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
3377227755Stuexen						error = EINVAL;
3378227755Stuexen						SCTP_TCB_UNLOCK(stcb);
3379227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3380227755Stuexen						break;
3381227755Stuexen					}
3382227755Stuexen				} else
3383227755Stuexen#endif
3384227755Stuexen#ifdef INET6
3385283699Stuexen				if (addr->sa_family == AF_INET6) {
3386227755Stuexen					struct sockaddr_in6 *sin6;
3387227755Stuexen
3388283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
3389227755Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3390227755Stuexen						error = EINVAL;
3391227755Stuexen						SCTP_TCB_UNLOCK(stcb);
3392227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3393227755Stuexen						break;
3394227755Stuexen					}
3395227755Stuexen				} else
3396227755Stuexen#endif
3397227755Stuexen				{
3398227755Stuexen					error = EAFNOSUPPORT;
3399227755Stuexen					SCTP_TCB_UNLOCK(stcb);
3400227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3401227755Stuexen					break;
3402227755Stuexen				}
3403227755Stuexen			}
3404283699Stuexen			if (stcb != NULL) {
3405227755Stuexen				if (net) {
3406227755Stuexen					encaps->sue_port = net->port;
3407227755Stuexen				} else {
3408227755Stuexen					encaps->sue_port = stcb->asoc.port;
3409227755Stuexen				}
3410227755Stuexen				SCTP_TCB_UNLOCK(stcb);
3411227755Stuexen			} else {
3412227755Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3413227755Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3414227755Stuexen				    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
3415227755Stuexen					SCTP_INP_RLOCK(inp);
3416227755Stuexen					encaps->sue_port = inp->sctp_ep.port;
3417227755Stuexen					SCTP_INP_RUNLOCK(inp);
3418227755Stuexen				} else {
3419227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3420227755Stuexen					error = EINVAL;
3421227755Stuexen				}
3422227755Stuexen			}
3423227755Stuexen			if (error == 0) {
3424258454Stuexen				*optsize = sizeof(struct sctp_udpencaps);
3425227755Stuexen			}
3426227755Stuexen			break;
3427227755Stuexen		}
3428270356Stuexen	case SCTP_ECN_SUPPORTED:
3429270356Stuexen		{
3430270356Stuexen			struct sctp_assoc_value *av;
3431270356Stuexen
3432270356Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3433270356Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3434270356Stuexen
3435270356Stuexen			if (stcb) {
3436270356Stuexen				av->assoc_value = stcb->asoc.ecn_supported;
3437270356Stuexen				SCTP_TCB_UNLOCK(stcb);
3438270356Stuexen			} else {
3439270356Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3440270356Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3441270356Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3442270356Stuexen					SCTP_INP_RLOCK(inp);
3443270356Stuexen					av->assoc_value = inp->ecn_supported;
3444270356Stuexen					SCTP_INP_RUNLOCK(inp);
3445270356Stuexen				} else {
3446270356Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3447270356Stuexen					error = EINVAL;
3448270356Stuexen				}
3449270356Stuexen			}
3450270356Stuexen			if (error == 0) {
3451270356Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3452270356Stuexen			}
3453270356Stuexen			break;
3454270356Stuexen		}
3455270357Stuexen	case SCTP_PR_SUPPORTED:
3456270357Stuexen		{
3457270357Stuexen			struct sctp_assoc_value *av;
3458270357Stuexen
3459270357Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3460270357Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3461270357Stuexen
3462270357Stuexen			if (stcb) {
3463270357Stuexen				av->assoc_value = stcb->asoc.prsctp_supported;
3464270357Stuexen				SCTP_TCB_UNLOCK(stcb);
3465270357Stuexen			} else {
3466270357Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3467270357Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3468270357Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3469270357Stuexen					SCTP_INP_RLOCK(inp);
3470270357Stuexen					av->assoc_value = inp->prsctp_supported;
3471270357Stuexen					SCTP_INP_RUNLOCK(inp);
3472270357Stuexen				} else {
3473270357Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3474270357Stuexen					error = EINVAL;
3475270357Stuexen				}
3476270357Stuexen			}
3477270357Stuexen			if (error == 0) {
3478270357Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3479270357Stuexen			}
3480270357Stuexen			break;
3481270357Stuexen		}
3482270362Stuexen	case SCTP_AUTH_SUPPORTED:
3483270362Stuexen		{
3484270362Stuexen			struct sctp_assoc_value *av;
3485270362Stuexen
3486270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3487270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3488270362Stuexen
3489270362Stuexen			if (stcb) {
3490270362Stuexen				av->assoc_value = stcb->asoc.auth_supported;
3491270362Stuexen				SCTP_TCB_UNLOCK(stcb);
3492270362Stuexen			} else {
3493270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3494270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3495270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3496270362Stuexen					SCTP_INP_RLOCK(inp);
3497270362Stuexen					av->assoc_value = inp->auth_supported;
3498270362Stuexen					SCTP_INP_RUNLOCK(inp);
3499270362Stuexen				} else {
3500270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3501270362Stuexen					error = EINVAL;
3502270362Stuexen				}
3503270362Stuexen			}
3504270362Stuexen			if (error == 0) {
3505270362Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3506270362Stuexen			}
3507270362Stuexen			break;
3508270362Stuexen		}
3509270362Stuexen	case SCTP_ASCONF_SUPPORTED:
3510270362Stuexen		{
3511270362Stuexen			struct sctp_assoc_value *av;
3512270362Stuexen
3513270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3514270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3515270362Stuexen
3516270362Stuexen			if (stcb) {
3517270362Stuexen				av->assoc_value = stcb->asoc.asconf_supported;
3518270362Stuexen				SCTP_TCB_UNLOCK(stcb);
3519270362Stuexen			} else {
3520270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3521270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3522270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3523270362Stuexen					SCTP_INP_RLOCK(inp);
3524270362Stuexen					av->assoc_value = inp->asconf_supported;
3525270362Stuexen					SCTP_INP_RUNLOCK(inp);
3526270362Stuexen				} else {
3527270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3528270362Stuexen					error = EINVAL;
3529270362Stuexen				}
3530270362Stuexen			}
3531270362Stuexen			if (error == 0) {
3532270362Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3533270362Stuexen			}
3534270362Stuexen			break;
3535270362Stuexen		}
3536270361Stuexen	case SCTP_RECONFIG_SUPPORTED:
3537270361Stuexen		{
3538270361Stuexen			struct sctp_assoc_value *av;
3539270361Stuexen
3540270361Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3541270361Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3542270361Stuexen
3543270361Stuexen			if (stcb) {
3544270361Stuexen				av->assoc_value = stcb->asoc.reconfig_supported;
3545270361Stuexen				SCTP_TCB_UNLOCK(stcb);
3546270361Stuexen			} else {
3547270361Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3548270361Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3549270361Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3550270361Stuexen					SCTP_INP_RLOCK(inp);
3551270361Stuexen					av->assoc_value = inp->reconfig_supported;
3552270361Stuexen					SCTP_INP_RUNLOCK(inp);
3553270361Stuexen				} else {
3554270361Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3555270361Stuexen					error = EINVAL;
3556270361Stuexen				}
3557270361Stuexen			}
3558270361Stuexen			if (error == 0) {
3559270361Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3560270361Stuexen			}
3561270361Stuexen			break;
3562270361Stuexen		}
3563270359Stuexen	case SCTP_NRSACK_SUPPORTED:
3564270359Stuexen		{
3565270359Stuexen			struct sctp_assoc_value *av;
3566270359Stuexen
3567270359Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3568270359Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3569270359Stuexen
3570270359Stuexen			if (stcb) {
3571270359Stuexen				av->assoc_value = stcb->asoc.nrsack_supported;
3572270359Stuexen				SCTP_TCB_UNLOCK(stcb);
3573270359Stuexen			} else {
3574270359Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3575270359Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3576270359Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3577270359Stuexen					SCTP_INP_RLOCK(inp);
3578270359Stuexen					av->assoc_value = inp->nrsack_supported;
3579270359Stuexen					SCTP_INP_RUNLOCK(inp);
3580270359Stuexen				} else {
3581270359Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3582270359Stuexen					error = EINVAL;
3583270359Stuexen				}
3584270359Stuexen			}
3585270359Stuexen			if (error == 0) {
3586270359Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3587270359Stuexen			}
3588270359Stuexen			break;
3589270359Stuexen		}
3590270360Stuexen	case SCTP_PKTDROP_SUPPORTED:
3591270360Stuexen		{
3592270360Stuexen			struct sctp_assoc_value *av;
3593270360Stuexen
3594270360Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3595270360Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3596270360Stuexen
3597270360Stuexen			if (stcb) {
3598270360Stuexen				av->assoc_value = stcb->asoc.pktdrop_supported;
3599270360Stuexen				SCTP_TCB_UNLOCK(stcb);
3600270360Stuexen			} else {
3601270360Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3602270360Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3603270360Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3604270360Stuexen					SCTP_INP_RLOCK(inp);
3605270360Stuexen					av->assoc_value = inp->pktdrop_supported;
3606270360Stuexen					SCTP_INP_RUNLOCK(inp);
3607270360Stuexen				} else {
3608270360Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3609270360Stuexen					error = EINVAL;
3610270360Stuexen				}
3611270360Stuexen			}
3612270360Stuexen			if (error == 0) {
3613270360Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3614270360Stuexen			}
3615270360Stuexen			break;
3616270360Stuexen		}
3617235021Stuexen	case SCTP_ENABLE_STREAM_RESET:
3618235021Stuexen		{
3619235021Stuexen			struct sctp_assoc_value *av;
3620235021Stuexen
3621235021Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3622235021Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3623235021Stuexen
3624235021Stuexen			if (stcb) {
3625235021Stuexen				av->assoc_value = (uint32_t) stcb->asoc.local_strreset_support;
3626235021Stuexen				SCTP_TCB_UNLOCK(stcb);
3627235021Stuexen			} else {
3628235021Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3629235021Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3630235021Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3631235021Stuexen					SCTP_INP_RLOCK(inp);
3632235021Stuexen					av->assoc_value = (uint32_t) inp->local_strreset_support;
3633235021Stuexen					SCTP_INP_RUNLOCK(inp);
3634235021Stuexen				} else {
3635235021Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3636235021Stuexen					error = EINVAL;
3637235021Stuexen				}
3638235021Stuexen			}
3639235021Stuexen			if (error == 0) {
3640235021Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3641235021Stuexen			}
3642235021Stuexen			break;
3643235021Stuexen		}
3644270363Stuexen	case SCTP_PR_STREAM_STATUS:
3645270363Stuexen		{
3646270363Stuexen			struct sctp_prstatus *sprstat;
3647270363Stuexen			uint16_t sid;
3648270363Stuexen			uint16_t policy;
3649270363Stuexen
3650270363Stuexen			SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
3651270363Stuexen			SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
3652270363Stuexen
3653270363Stuexen			sid = sprstat->sprstat_sid;
3654270363Stuexen			policy = sprstat->sprstat_policy;
3655270363Stuexen#if defined(SCTP_DETAILED_STR_STATS)
3656270363Stuexen			if ((stcb != NULL) &&
3657283706Stuexen			    (sid < stcb->asoc.streamoutcnt) &&
3658270363Stuexen			    (policy != SCTP_PR_SCTP_NONE) &&
3659283706Stuexen			    ((policy <= SCTP_PR_SCTP_MAX) ||
3660283706Stuexen			    (policy == SCTP_PR_SCTP_ALL))) {
3661270363Stuexen				if (policy == SCTP_PR_SCTP_ALL) {
3662270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
3663270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
3664270363Stuexen				} else {
3665270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[policy];
3666270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[policy];
3667270363Stuexen				}
3668283705Stuexen#else
3669283705Stuexen			if ((stcb != NULL) &&
3670283706Stuexen			    (sid < stcb->asoc.streamoutcnt) &&
3671283706Stuexen			    (policy == SCTP_PR_SCTP_ALL)) {
3672283705Stuexen				sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
3673283705Stuexen				sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
3674283705Stuexen#endif
3675270363Stuexen				SCTP_TCB_UNLOCK(stcb);
3676270363Stuexen				*optsize = sizeof(struct sctp_prstatus);
3677270363Stuexen			} else {
3678270363Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3679270363Stuexen				error = EINVAL;
3680270363Stuexen			}
3681270363Stuexen			break;
3682270363Stuexen		}
3683270363Stuexen	case SCTP_PR_ASSOC_STATUS:
3684270363Stuexen		{
3685270363Stuexen			struct sctp_prstatus *sprstat;
3686270363Stuexen			uint16_t policy;
3687270363Stuexen
3688270363Stuexen			SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
3689270363Stuexen			SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
3690270363Stuexen
3691270363Stuexen			policy = sprstat->sprstat_policy;
3692270363Stuexen			if ((stcb != NULL) &&
3693270363Stuexen			    (policy != SCTP_PR_SCTP_NONE) &&
3694283706Stuexen			    ((policy <= SCTP_PR_SCTP_MAX) ||
3695283706Stuexen			    (policy == SCTP_PR_SCTP_ALL))) {
3696270363Stuexen				if (policy == SCTP_PR_SCTP_ALL) {
3697270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[0];
3698270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[0];
3699270363Stuexen				} else {
3700270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy];
3701270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy];
3702270363Stuexen				}
3703270363Stuexen				SCTP_TCB_UNLOCK(stcb);
3704270363Stuexen				*optsize = sizeof(struct sctp_prstatus);
3705270363Stuexen			} else {
3706270363Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3707270363Stuexen				error = EINVAL;
3708270363Stuexen			}
3709270363Stuexen			break;
3710270363Stuexen		}
3711283724Stuexen	case SCTP_MAX_CWND:
3712283724Stuexen		{
3713283724Stuexen			struct sctp_assoc_value *av;
3714283724Stuexen
3715283724Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3716283724Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3717283724Stuexen
3718283724Stuexen			if (stcb) {
3719283724Stuexen				av->assoc_value = stcb->asoc.max_cwnd;
3720283724Stuexen				SCTP_TCB_UNLOCK(stcb);
3721283724Stuexen			} else {
3722283724Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3723283724Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3724283724Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3725283724Stuexen					SCTP_INP_RLOCK(inp);
3726283724Stuexen					av->assoc_value = inp->max_cwnd;
3727283724Stuexen					SCTP_INP_RUNLOCK(inp);
3728283724Stuexen				} else {
3729283724Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3730283724Stuexen					error = EINVAL;
3731283724Stuexen				}
3732283724Stuexen			}
3733283724Stuexen			if (error == 0) {
3734283724Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3735283724Stuexen			}
3736283724Stuexen			break;
3737283724Stuexen		}
3738163953Srrs	default:
3739171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3740163953Srrs		error = ENOPROTOOPT;
3741163953Srrs		break;
3742163953Srrs	}			/* end switch (sopt->sopt_name) */
3743223132Stuexen	if (error) {
3744223132Stuexen		*optsize = 0;
3745223132Stuexen	}
3746163953Srrs	return (error);
3747163953Srrs}
3748163953Srrs
3749163953Srrsstatic int
3750166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
3751166675Srrs    void *p)
3752163953Srrs{
3753166675Srrs	int error, set_opt;
3754166675Srrs	uint32_t *mopt;
3755163953Srrs	struct sctp_tcb *stcb = NULL;
3756171943Srrs	struct sctp_inpcb *inp = NULL;
3757167598Srrs	uint32_t vrf_id;
3758163953Srrs
3759166675Srrs	if (optval == NULL) {
3760169420Srrs		SCTP_PRINTF("optval is NULL\n");
3761171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3762163953Srrs		return (EINVAL);
3763163953Srrs	}
3764163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3765233005Stuexen	if (inp == NULL) {
3766169420Srrs		SCTP_PRINTF("inp is NULL?\n");
3767171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3768228907Stuexen		return (EINVAL);
3769167598Srrs	}
3770168299Srrs	vrf_id = inp->def_vrf_id;
3771163953Srrs
3772163953Srrs	error = 0;
3773166675Srrs	switch (optname) {
3774163953Srrs	case SCTP_NODELAY:
3775163953Srrs	case SCTP_AUTOCLOSE:
3776163953Srrs	case SCTP_AUTO_ASCONF:
3777163953Srrs	case SCTP_EXPLICIT_EOR:
3778163953Srrs	case SCTP_DISABLE_FRAGMENTS:
3779163953Srrs	case SCTP_USE_EXT_RCVINFO:
3780163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
3781163953Srrs		/* copy in the option value */
3782166675Srrs		SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
3783163953Srrs		set_opt = 0;
3784163953Srrs		if (error)
3785163953Srrs			break;
3786166675Srrs		switch (optname) {
3787163953Srrs		case SCTP_DISABLE_FRAGMENTS:
3788163953Srrs			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
3789163953Srrs			break;
3790163953Srrs		case SCTP_AUTO_ASCONF:
3791171943Srrs			/*
3792171943Srrs			 * NOTE: we don't really support this flag
3793171943Srrs			 */
3794171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3795171943Srrs				/* only valid for bound all sockets */
3796224641Stuexen				if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
3797224641Stuexen				    (*mopt != 0)) {
3798224641Stuexen					/* forbidden by admin */
3799224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
3800224641Stuexen					return (EPERM);
3801224641Stuexen				}
3802171943Srrs				set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
3803171943Srrs			} else {
3804171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3805171943Srrs				return (EINVAL);
3806171943Srrs			}
3807163953Srrs			break;
3808163953Srrs		case SCTP_EXPLICIT_EOR:
3809163953Srrs			set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
3810163953Srrs			break;
3811163953Srrs		case SCTP_USE_EXT_RCVINFO:
3812163953Srrs			set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
3813163953Srrs			break;
3814163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
3815163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3816163953Srrs				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
3817163953Srrs			} else {
3818171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3819163953Srrs				return (EINVAL);
3820163953Srrs			}
3821163953Srrs			break;
3822163953Srrs		case SCTP_NODELAY:
3823163953Srrs			set_opt = SCTP_PCB_FLAGS_NODELAY;
3824163953Srrs			break;
3825163953Srrs		case SCTP_AUTOCLOSE:
3826170056Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3827170056Srrs			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3828171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3829170056Srrs				return (EINVAL);
3830170056Srrs			}
3831163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
3832163953Srrs			/*
3833163953Srrs			 * The value is in ticks. Note this does not effect
3834163953Srrs			 * old associations, only new ones.
3835163953Srrs			 */
3836163953Srrs			inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
3837163953Srrs			break;
3838163953Srrs		}
3839163953Srrs		SCTP_INP_WLOCK(inp);
3840163953Srrs		if (*mopt != 0) {
3841163953Srrs			sctp_feature_on(inp, set_opt);
3842163953Srrs		} else {
3843163953Srrs			sctp_feature_off(inp, set_opt);
3844163953Srrs		}
3845163953Srrs		SCTP_INP_WUNLOCK(inp);
3846163953Srrs		break;
3847181054Srrs	case SCTP_REUSE_PORT:
3848181054Srrs		{
3849181054Srrs			SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
3850181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
3851181054Srrs				/* Can't set it after we are bound */
3852181054Srrs				error = EINVAL;
3853181054Srrs				break;
3854181054Srrs			}
3855181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
3856181054Srrs				/* Can't do this for a 1-m socket */
3857181054Srrs				error = EINVAL;
3858181054Srrs				break;
3859181054Srrs			}
3860181054Srrs			if (optval)
3861181054Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
3862181054Srrs			else
3863181054Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
3864223132Stuexen			break;
3865181054Srrs		}
3866163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
3867163953Srrs		{
3868166675Srrs			uint32_t *value;
3869166675Srrs
3870166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
3871167736Srrs			if (*value > SCTP_SB_LIMIT_RCV(so)) {
3872171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3873167736Srrs				error = EINVAL;
3874167736Srrs				break;
3875167736Srrs			}
3876166675Srrs			inp->partial_delivery_point = *value;
3877223132Stuexen			break;
3878163953Srrs		}
3879163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
3880163953Srrs		/* not yet until we re-write sctp_recvmsg() */
3881163953Srrs		{
3882168943Srrs			uint32_t *level;
3883163953Srrs
3884168943Srrs			SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
3885168943Srrs			if (*level == SCTP_FRAG_LEVEL_2) {
3886163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3887168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3888168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_1) {
3889168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3890168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3891168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_0) {
3892170056Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3893168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3894168943Srrs
3895163953Srrs			} else {
3896171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3897168943Srrs				error = EINVAL;
3898163953Srrs			}
3899223132Stuexen			break;
3900163953Srrs		}
3901163953Srrs	case SCTP_CMT_ON_OFF:
3902211944Stuexen		if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
3903163953Srrs			struct sctp_assoc_value *av;
3904163953Srrs
3905166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3906223132Stuexen			if (av->assoc_value > SCTP_CMT_MAX) {
3907223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3908223132Stuexen				error = EINVAL;
3909223132Stuexen				break;
3910223132Stuexen			}
3911211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3912211944Stuexen			if (stcb) {
3913223132Stuexen				stcb->asoc.sctp_cmt_on_off = av->assoc_value;
3914211944Stuexen				SCTP_TCB_UNLOCK(stcb);
3915166675Srrs			} else {
3916224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3917224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3918224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3919223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3920221460Stuexen					SCTP_INP_WLOCK(inp);
3921221460Stuexen					inp->sctp_cmt_on_off = av->assoc_value;
3922221460Stuexen					SCTP_INP_WUNLOCK(inp);
3923216669Stuexen				}
3924223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3925223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3926223132Stuexen					SCTP_INP_RLOCK(inp);
3927223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3928223132Stuexen						SCTP_TCB_LOCK(stcb);
3929223132Stuexen						stcb->asoc.sctp_cmt_on_off = av->assoc_value;
3930223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3931223132Stuexen					}
3932224918Stuexen					SCTP_INP_RUNLOCK(inp);
3933223132Stuexen				}
3934163953Srrs			}
3935211944Stuexen		} else {
3936211944Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3937211944Stuexen			error = ENOPROTOOPT;
3938163953Srrs		}
3939163953Srrs		break;
3940171440Srrs	case SCTP_PLUGGABLE_CC:
3941171440Srrs		{
3942171440Srrs			struct sctp_assoc_value *av;
3943219057Srrs			struct sctp_nets *net;
3944171440Srrs
3945171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3946223132Stuexen			if ((av->assoc_value != SCTP_CC_RFC2581) &&
3947223132Stuexen			    (av->assoc_value != SCTP_CC_HSTCP) &&
3948223132Stuexen			    (av->assoc_value != SCTP_CC_HTCP) &&
3949223132Stuexen			    (av->assoc_value != SCTP_CC_RTCC)) {
3950223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3951223132Stuexen				error = EINVAL;
3952223132Stuexen				break;
3953223132Stuexen			}
3954171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3955171440Srrs			if (stcb) {
3956223132Stuexen				stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3957223132Stuexen				stcb->asoc.congestion_control_module = av->assoc_value;
3958223132Stuexen				if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3959223132Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3960223132Stuexen						stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
3961219057Srrs					}
3962171440Srrs				}
3963217611Stuexen				SCTP_TCB_UNLOCK(stcb);
3964171440Srrs			} else {
3965224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3966224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3967224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3968223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3969217611Stuexen					SCTP_INP_WLOCK(inp);
3970171440Srrs					inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
3971217611Stuexen					SCTP_INP_WUNLOCK(inp);
3972217760Stuexen				}
3973223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3974223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3975223132Stuexen					SCTP_INP_RLOCK(inp);
3976223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3977223132Stuexen						SCTP_TCB_LOCK(stcb);
3978223132Stuexen						stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3979223132Stuexen						stcb->asoc.congestion_control_module = av->assoc_value;
3980223132Stuexen						if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3981223132Stuexen							TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3982223132Stuexen								stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
3983223132Stuexen							}
3984223132Stuexen						}
3985223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3986223132Stuexen					}
3987223132Stuexen					SCTP_INP_RUNLOCK(inp);
3988223132Stuexen				}
3989171440Srrs			}
3990223132Stuexen			break;
3991171440Srrs		}
3992219057Srrs	case SCTP_CC_OPTION:
3993219057Srrs		{
3994219057Srrs			struct sctp_cc_option *cc_opt;
3995219057Srrs
3996219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
3997219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
3998219057Srrs			if (stcb == NULL) {
3999223132Stuexen				if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) {
4000223132Stuexen					SCTP_INP_RLOCK(inp);
4001223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4002223132Stuexen						SCTP_TCB_LOCK(stcb);
4003223132Stuexen						if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) {
4004223132Stuexen							(*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt);
4005223132Stuexen						}
4006223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4007223132Stuexen					}
4008223132Stuexen					SCTP_INP_RUNLOCK(inp);
4009223132Stuexen				} else {
4010223132Stuexen					error = EINVAL;
4011223132Stuexen				}
4012219057Srrs			} else {
4013219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
4014219057Srrs					error = ENOTSUP;
4015219057Srrs				} else {
4016219057Srrs					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1,
4017219057Srrs					    cc_opt);
4018219057Srrs				}
4019219057Srrs				SCTP_TCB_UNLOCK(stcb);
4020219057Srrs			}
4021223132Stuexen			break;
4022219057Srrs		}
4023217760Stuexen	case SCTP_PLUGGABLE_SS:
4024217760Stuexen		{
4025217760Stuexen			struct sctp_assoc_value *av;
4026217760Stuexen
4027217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4028223132Stuexen			if ((av->assoc_value != SCTP_SS_DEFAULT) &&
4029223132Stuexen			    (av->assoc_value != SCTP_SS_ROUND_ROBIN) &&
4030223132Stuexen			    (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) &&
4031223132Stuexen			    (av->assoc_value != SCTP_SS_PRIORITY) &&
4032223132Stuexen			    (av->assoc_value != SCTP_SS_FAIR_BANDWITH) &&
4033223132Stuexen			    (av->assoc_value != SCTP_SS_FIRST_COME)) {
4034223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4035223132Stuexen				error = EINVAL;
4036223132Stuexen				break;
4037223132Stuexen			}
4038217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4039217760Stuexen			if (stcb) {
4040223132Stuexen				stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
4041223132Stuexen				stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
4042223132Stuexen				stcb->asoc.stream_scheduling_module = av->assoc_value;
4043223132Stuexen				stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
4044217760Stuexen				SCTP_TCB_UNLOCK(stcb);
4045217760Stuexen			} else {
4046224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4047224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4048224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4049223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4050217760Stuexen					SCTP_INP_WLOCK(inp);
4051217760Stuexen					inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
4052217760Stuexen					SCTP_INP_WUNLOCK(inp);
4053217760Stuexen				}
4054223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4055223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4056223132Stuexen					SCTP_INP_RLOCK(inp);
4057223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4058223132Stuexen						SCTP_TCB_LOCK(stcb);
4059223132Stuexen						stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
4060223132Stuexen						stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
4061223132Stuexen						stcb->asoc.stream_scheduling_module = av->assoc_value;
4062223132Stuexen						stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
4063223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4064223132Stuexen					}
4065223132Stuexen					SCTP_INP_RUNLOCK(inp);
4066223132Stuexen				}
4067217760Stuexen			}
4068223132Stuexen			break;
4069217760Stuexen		}
4070217760Stuexen	case SCTP_SS_VALUE:
4071217760Stuexen		{
4072217760Stuexen			struct sctp_stream_value *av;
4073217760Stuexen
4074217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
4075217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4076217760Stuexen			if (stcb) {
4077277807Sdelphij				if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
4078277807Sdelphij				    (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
4079277807Sdelphij				    av->stream_value) < 0)) {
4080217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4081217760Stuexen					error = EINVAL;
4082217760Stuexen				}
4083217760Stuexen				SCTP_TCB_UNLOCK(stcb);
4084217760Stuexen			} else {
4085223132Stuexen				if (av->assoc_id == SCTP_CURRENT_ASSOC) {
4086223132Stuexen					SCTP_INP_RLOCK(inp);
4087223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4088223132Stuexen						SCTP_TCB_LOCK(stcb);
4089277807Sdelphij						if (av->stream_id < stcb->asoc.streamoutcnt) {
4090277807Sdelphij							stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
4091277807Sdelphij							    &stcb->asoc,
4092277807Sdelphij							    &stcb->asoc.strmout[av->stream_id],
4093277807Sdelphij							    av->stream_value);
4094277807Sdelphij						}
4095223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4096223132Stuexen					}
4097223132Stuexen					SCTP_INP_RUNLOCK(inp);
4098223132Stuexen				} else {
4099223132Stuexen					/*
4100223132Stuexen					 * Can't set stream value without
4101223132Stuexen					 * association
4102223132Stuexen					 */
4103223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4104223132Stuexen					error = EINVAL;
4105223132Stuexen				}
4106217760Stuexen			}
4107223132Stuexen			break;
4108217760Stuexen		}
4109163953Srrs	case SCTP_CLR_STAT_LOG:
4110171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4111163953Srrs		error = EOPNOTSUPP;
4112163953Srrs		break;
4113163953Srrs	case SCTP_CONTEXT:
4114163953Srrs		{
4115163953Srrs			struct sctp_assoc_value *av;
4116163953Srrs
4117166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4118166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4119166675Srrs
4120166675Srrs			if (stcb) {
4121166675Srrs				stcb->asoc.context = av->assoc_value;
4122166675Srrs				SCTP_TCB_UNLOCK(stcb);
4123163953Srrs			} else {
4124224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4125224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4126224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4127223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4128223132Stuexen					SCTP_INP_WLOCK(inp);
4129223132Stuexen					inp->sctp_context = av->assoc_value;
4130223132Stuexen					SCTP_INP_WUNLOCK(inp);
4131223132Stuexen				}
4132223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4133223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4134223132Stuexen					SCTP_INP_RLOCK(inp);
4135223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4136223132Stuexen						SCTP_TCB_LOCK(stcb);
4137223132Stuexen						stcb->asoc.context = av->assoc_value;
4138223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4139223132Stuexen					}
4140223132Stuexen					SCTP_INP_RUNLOCK(inp);
4141223132Stuexen				}
4142163953Srrs			}
4143223132Stuexen			break;
4144163953Srrs		}
4145167598Srrs	case SCTP_VRF_ID:
4146167598Srrs		{
4147170056Srrs			uint32_t *default_vrfid;
4148167598Srrs
4149170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
4150170056Srrs			if (*default_vrfid > SCTP_MAX_VRF_ID) {
4151171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4152167598Srrs				error = EINVAL;
4153167598Srrs				break;
4154167598Srrs			}
4155170056Srrs			inp->def_vrf_id = *default_vrfid;
4156167598Srrs			break;
4157167598Srrs		}
4158167598Srrs	case SCTP_DEL_VRF_ID:
4159167598Srrs		{
4160171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4161167598Srrs			error = EOPNOTSUPP;
4162167598Srrs			break;
4163167598Srrs		}
4164167598Srrs	case SCTP_ADD_VRF_ID:
4165167598Srrs		{
4166171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4167167598Srrs			error = EOPNOTSUPP;
4168167598Srrs			break;
4169167598Srrs		}
4170170056Srrs	case SCTP_DELAYED_SACK:
4171163953Srrs		{
4172170056Srrs			struct sctp_sack_info *sack;
4173163953Srrs
4174170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
4175170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
4176171477Srrs			if (sack->sack_delay) {
4177171477Srrs				if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
4178171477Srrs					sack->sack_delay = SCTP_MAX_SACK_DELAY;
4179223132Stuexen				if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
4180223132Stuexen					sack->sack_delay = TICKS_TO_MSEC(1);
4181223132Stuexen				}
4182171477Srrs			}
4183166675Srrs			if (stcb) {
4184170056Srrs				if (sack->sack_delay) {
4185170056Srrs					stcb->asoc.delayed_ack = sack->sack_delay;
4186170056Srrs				}
4187170056Srrs				if (sack->sack_freq) {
4188170056Srrs					stcb->asoc.sack_freq = sack->sack_freq;
4189170056Srrs				}
4190166675Srrs				SCTP_TCB_UNLOCK(stcb);
4191166675Srrs			} else {
4192224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4193224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4194224918Stuexen				    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
4195223132Stuexen				    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
4196223132Stuexen					SCTP_INP_WLOCK(inp);
4197223132Stuexen					if (sack->sack_delay) {
4198223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
4199170056Srrs					}
4200223132Stuexen					if (sack->sack_freq) {
4201223132Stuexen						inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
4202223132Stuexen					}
4203223132Stuexen					SCTP_INP_WUNLOCK(inp);
4204170056Srrs				}
4205223132Stuexen				if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
4206223132Stuexen				    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
4207223132Stuexen					SCTP_INP_RLOCK(inp);
4208223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4209223132Stuexen						SCTP_TCB_LOCK(stcb);
4210223132Stuexen						if (sack->sack_delay) {
4211223132Stuexen							stcb->asoc.delayed_ack = sack->sack_delay;
4212223132Stuexen						}
4213223132Stuexen						if (sack->sack_freq) {
4214223132Stuexen							stcb->asoc.sack_freq = sack->sack_freq;
4215223132Stuexen						}
4216223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4217223132Stuexen					}
4218223132Stuexen					SCTP_INP_RUNLOCK(inp);
4219170056Srrs				}
4220163953Srrs			}
4221166675Srrs			break;
4222163953Srrs		}
4223163953Srrs	case SCTP_AUTH_CHUNK:
4224163953Srrs		{
4225163953Srrs			struct sctp_authchunk *sauth;
4226163953Srrs
4227166675Srrs			SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
4228166675Srrs
4229166675Srrs			SCTP_INP_WLOCK(inp);
4230171943Srrs			if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
4231171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4232163953Srrs				error = EINVAL;
4233171943Srrs			}
4234166675Srrs			SCTP_INP_WUNLOCK(inp);
4235163953Srrs			break;
4236163953Srrs		}
4237163953Srrs	case SCTP_AUTH_KEY:
4238163953Srrs		{
4239163953Srrs			struct sctp_authkey *sca;
4240163953Srrs			struct sctp_keyhead *shared_keys;
4241163953Srrs			sctp_sharedkey_t *shared_key;
4242163953Srrs			sctp_key_t *key = NULL;
4243166675Srrs			size_t size;
4244163953Srrs
4245166675Srrs			SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
4246223697Stuexen			if (sca->sca_keylength == 0) {
4247223697Stuexen				size = optsize - sizeof(struct sctp_authkey);
4248223697Stuexen			} else {
4249223697Stuexen				if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
4250223697Stuexen					size = sca->sca_keylength;
4251223697Stuexen				} else {
4252223697Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4253223697Stuexen					error = EINVAL;
4254223697Stuexen					break;
4255223697Stuexen				}
4256223697Stuexen			}
4257169420Srrs			SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
4258166675Srrs
4259166675Srrs			if (stcb) {
4260163953Srrs				shared_keys = &stcb->asoc.shared_keys;
4261163953Srrs				/* clear the cached keys for this key id */
4262163953Srrs				sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
4263163953Srrs				/*
4264163953Srrs				 * create the new shared key and
4265163953Srrs				 * insert/replace it
4266163953Srrs				 */
4267163953Srrs				if (size > 0) {
4268163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
4269163953Srrs					if (key == NULL) {
4270171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4271163953Srrs						error = ENOMEM;
4272163953Srrs						SCTP_TCB_UNLOCK(stcb);
4273163953Srrs						break;
4274163953Srrs					}
4275163953Srrs				}
4276163953Srrs				shared_key = sctp_alloc_sharedkey();
4277163953Srrs				if (shared_key == NULL) {
4278163953Srrs					sctp_free_key(key);
4279171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4280163953Srrs					error = ENOMEM;
4281163953Srrs					SCTP_TCB_UNLOCK(stcb);
4282163953Srrs					break;
4283163953Srrs				}
4284163953Srrs				shared_key->key = key;
4285163953Srrs				shared_key->keyid = sca->sca_keynumber;
4286185694Srrs				error = sctp_insert_sharedkey(shared_keys, shared_key);
4287163953Srrs				SCTP_TCB_UNLOCK(stcb);
4288163953Srrs			} else {
4289224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4290224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4291224918Stuexen				    (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
4292223132Stuexen				    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
4293223132Stuexen					SCTP_INP_WLOCK(inp);
4294223132Stuexen					shared_keys = &inp->sctp_ep.shared_keys;
4295223132Stuexen					/*
4296223132Stuexen					 * clear the cached keys on all
4297223132Stuexen					 * assocs for this key id
4298223132Stuexen					 */
4299223132Stuexen					sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
4300223132Stuexen					/*
4301223132Stuexen					 * create the new shared key and
4302223132Stuexen					 * insert/replace it
4303223132Stuexen					 */
4304223132Stuexen					if (size > 0) {
4305223132Stuexen						key = sctp_set_key(sca->sca_key, (uint32_t) size);
4306223132Stuexen						if (key == NULL) {
4307223132Stuexen							SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4308223132Stuexen							error = ENOMEM;
4309223132Stuexen							SCTP_INP_WUNLOCK(inp);
4310223132Stuexen							break;
4311223132Stuexen						}
4312223132Stuexen					}
4313223132Stuexen					shared_key = sctp_alloc_sharedkey();
4314223132Stuexen					if (shared_key == NULL) {
4315223132Stuexen						sctp_free_key(key);
4316171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4317163953Srrs						error = ENOMEM;
4318163953Srrs						SCTP_INP_WUNLOCK(inp);
4319163953Srrs						break;
4320163953Srrs					}
4321223132Stuexen					shared_key->key = key;
4322223132Stuexen					shared_key->keyid = sca->sca_keynumber;
4323223132Stuexen					error = sctp_insert_sharedkey(shared_keys, shared_key);
4324163953Srrs					SCTP_INP_WUNLOCK(inp);
4325163953Srrs				}
4326223132Stuexen				if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
4327223132Stuexen				    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
4328223132Stuexen					SCTP_INP_RLOCK(inp);
4329223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4330223132Stuexen						SCTP_TCB_LOCK(stcb);
4331223132Stuexen						shared_keys = &stcb->asoc.shared_keys;
4332223132Stuexen						/*
4333223132Stuexen						 * clear the cached keys for
4334223132Stuexen						 * this key id
4335223132Stuexen						 */
4336223132Stuexen						sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
4337223132Stuexen						/*
4338223132Stuexen						 * create the new shared key
4339223132Stuexen						 * and insert/replace it
4340223132Stuexen						 */
4341223132Stuexen						if (size > 0) {
4342223132Stuexen							key = sctp_set_key(sca->sca_key, (uint32_t) size);
4343223132Stuexen							if (key == NULL) {
4344223132Stuexen								SCTP_TCB_UNLOCK(stcb);
4345223132Stuexen								continue;
4346223132Stuexen							}
4347223132Stuexen						}
4348223132Stuexen						shared_key = sctp_alloc_sharedkey();
4349223132Stuexen						if (shared_key == NULL) {
4350223132Stuexen							sctp_free_key(key);
4351223132Stuexen							SCTP_TCB_UNLOCK(stcb);
4352223132Stuexen							continue;
4353223132Stuexen						}
4354223132Stuexen						shared_key->key = key;
4355223132Stuexen						shared_key->keyid = sca->sca_keynumber;
4356223132Stuexen						error = sctp_insert_sharedkey(shared_keys, shared_key);
4357223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4358223132Stuexen					}
4359223132Stuexen					SCTP_INP_RUNLOCK(inp);
4360223132Stuexen				}
4361163953Srrs			}
4362163953Srrs			break;
4363163953Srrs		}
4364163953Srrs	case SCTP_HMAC_IDENT:
4365163953Srrs		{
4366163953Srrs			struct sctp_hmacalgo *shmac;
4367163953Srrs			sctp_hmaclist_t *hmaclist;
4368181054Srrs			uint16_t hmacid;
4369181054Srrs			uint32_t i;
4370181054Srrs
4371166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
4372271750Stuexen			if ((optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) ||
4373271750Stuexen			    (shmac->shmac_number_of_idents > 0xffff)) {
4374181054Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4375181054Srrs				error = EINVAL;
4376181054Srrs				break;
4377181054Srrs			}
4378271750Stuexen			hmaclist = sctp_alloc_hmaclist((uint16_t) shmac->shmac_number_of_idents);
4379163953Srrs			if (hmaclist == NULL) {
4380171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4381163953Srrs				error = ENOMEM;
4382163953Srrs				break;
4383163953Srrs			}
4384181054Srrs			for (i = 0; i < shmac->shmac_number_of_idents; i++) {
4385163953Srrs				hmacid = shmac->shmac_idents[i];
4386181054Srrs				if (sctp_auth_add_hmacid(hmaclist, hmacid)) {
4387163953Srrs					 /* invalid HMACs were found */ ;
4388171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4389163953Srrs					error = EINVAL;
4390164085Srrs					sctp_free_hmaclist(hmaclist);
4391163953Srrs					goto sctp_set_hmac_done;
4392163953Srrs				}
4393163953Srrs			}
4394170056Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
4395170056Srrs				if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
4396170056Srrs					/* already in list */
4397253858Stuexen					break;
4398170056Srrs				}
4399170056Srrs			}
4400253858Stuexen			if (i == hmaclist->num_algo) {
4401253858Stuexen				/* not found in list */
4402170056Srrs				sctp_free_hmaclist(hmaclist);
4403171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4404170056Srrs				error = EINVAL;
4405170056Srrs				break;
4406170056Srrs			}
4407163953Srrs			/* set it on the endpoint */
4408163953Srrs			SCTP_INP_WLOCK(inp);
4409163953Srrs			if (inp->sctp_ep.local_hmacs)
4410163953Srrs				sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
4411163953Srrs			inp->sctp_ep.local_hmacs = hmaclist;
4412163953Srrs			SCTP_INP_WUNLOCK(inp);
4413163953Srrs	sctp_set_hmac_done:
4414163953Srrs			break;
4415163953Srrs		}
4416163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
4417163953Srrs		{
4418163953Srrs			struct sctp_authkeyid *scact;
4419163953Srrs
4420223132Stuexen			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
4421166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
4422166675Srrs
4423163953Srrs			/* set the active key on the right place */
4424166675Srrs			if (stcb) {
4425163953Srrs				/* set the active key on the assoc */
4426185694Srrs				if (sctp_auth_setactivekey(stcb,
4427185694Srrs				    scact->scact_keynumber)) {
4428185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
4429185694Srrs					    SCTP_FROM_SCTP_USRREQ,
4430185694Srrs					    EINVAL);
4431163953Srrs					error = EINVAL;
4432171943Srrs				}
4433163953Srrs				SCTP_TCB_UNLOCK(stcb);
4434163953Srrs			} else {
4435224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4436224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4437224918Stuexen				    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4438223132Stuexen				    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
4439223132Stuexen					SCTP_INP_WLOCK(inp);
4440223132Stuexen					if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
4441223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4442223132Stuexen						error = EINVAL;
4443223132Stuexen					}
4444223132Stuexen					SCTP_INP_WUNLOCK(inp);
4445171943Srrs				}
4446223132Stuexen				if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4447223132Stuexen				    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
4448223132Stuexen					SCTP_INP_RLOCK(inp);
4449223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4450223132Stuexen						SCTP_TCB_LOCK(stcb);
4451223132Stuexen						sctp_auth_setactivekey(stcb, scact->scact_keynumber);
4452223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4453223132Stuexen					}
4454223132Stuexen					SCTP_INP_RUNLOCK(inp);
4455223132Stuexen				}
4456163953Srrs			}
4457163953Srrs			break;
4458163953Srrs		}
4459163953Srrs	case SCTP_AUTH_DELETE_KEY:
4460163953Srrs		{
4461163953Srrs			struct sctp_authkeyid *scdel;
4462163953Srrs
4463223132Stuexen			SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
4464166675Srrs			SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
4465166675Srrs
4466163953Srrs			/* delete the key from the right place */
4467166675Srrs			if (stcb) {
4468223132Stuexen				if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
4469223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4470163953Srrs					error = EINVAL;
4471171943Srrs				}
4472163953Srrs				SCTP_TCB_UNLOCK(stcb);
4473163953Srrs			} else {
4474224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4475224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4476224918Stuexen				    (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4477223132Stuexen				    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
4478223132Stuexen					SCTP_INP_WLOCK(inp);
4479223132Stuexen					if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
4480223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4481223132Stuexen						error = EINVAL;
4482223132Stuexen					}
4483223132Stuexen					SCTP_INP_WUNLOCK(inp);
4484171943Srrs				}
4485223132Stuexen				if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4486223132Stuexen				    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
4487223132Stuexen					SCTP_INP_RLOCK(inp);
4488223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4489223132Stuexen						SCTP_TCB_LOCK(stcb);
4490223132Stuexen						sctp_delete_sharedkey(stcb, scdel->scact_keynumber);
4491223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4492223132Stuexen					}
4493223132Stuexen					SCTP_INP_RUNLOCK(inp);
4494223132Stuexen				}
4495163953Srrs			}
4496163953Srrs			break;
4497163953Srrs		}
4498185694Srrs	case SCTP_AUTH_DEACTIVATE_KEY:
4499185694Srrs		{
4500185694Srrs			struct sctp_authkeyid *keyid;
4501163953Srrs
4502223132Stuexen			SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize);
4503185694Srrs			SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
4504185694Srrs
4505185694Srrs			/* deactivate the key from the right place */
4506185694Srrs			if (stcb) {
4507223132Stuexen				if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) {
4508223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4509185694Srrs					error = EINVAL;
4510185694Srrs				}
4511185694Srrs				SCTP_TCB_UNLOCK(stcb);
4512185694Srrs			} else {
4513224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4514224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4515224918Stuexen				    (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4516223132Stuexen				    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
4517223132Stuexen					SCTP_INP_WLOCK(inp);
4518223132Stuexen					if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
4519223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4520223132Stuexen						error = EINVAL;
4521223132Stuexen					}
4522223132Stuexen					SCTP_INP_WUNLOCK(inp);
4523185694Srrs				}
4524223132Stuexen				if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4525223132Stuexen				    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
4526223132Stuexen					SCTP_INP_RLOCK(inp);
4527223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4528223132Stuexen						SCTP_TCB_LOCK(stcb);
4529223132Stuexen						sctp_deact_sharedkey(stcb, keyid->scact_keynumber);
4530223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4531223132Stuexen					}
4532223132Stuexen					SCTP_INP_RUNLOCK(inp);
4533223132Stuexen				}
4534185694Srrs			}
4535185694Srrs			break;
4536185694Srrs		}
4537233660Srrs	case SCTP_ENABLE_STREAM_RESET:
4538233660Srrs		{
4539233660Srrs			struct sctp_assoc_value *av;
4540185694Srrs
4541233660Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4542233660Srrs			if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
4543233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4544233660Srrs				error = EINVAL;
4545233660Srrs				break;
4546233660Srrs			}
4547233660Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4548233660Srrs			if (stcb) {
4549235021Stuexen				stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value;
4550233660Srrs				SCTP_TCB_UNLOCK(stcb);
4551233660Srrs			} else {
4552233660Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4553233660Srrs				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4554233660Srrs				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4555233660Srrs				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4556233660Srrs					SCTP_INP_WLOCK(inp);
4557235021Stuexen					inp->local_strreset_support = (uint8_t) av->assoc_value;
4558233660Srrs					SCTP_INP_WUNLOCK(inp);
4559233660Srrs				}
4560233660Srrs				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4561233660Srrs				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4562233660Srrs					SCTP_INP_RLOCK(inp);
4563233660Srrs					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4564233660Srrs						SCTP_TCB_LOCK(stcb);
4565235021Stuexen						stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value;
4566233660Srrs						SCTP_TCB_UNLOCK(stcb);
4567233660Srrs					}
4568233660Srrs					SCTP_INP_RUNLOCK(inp);
4569233660Srrs				}
4570233660Srrs			}
4571233660Srrs			break;
4572233660Srrs		}
4573163953Srrs	case SCTP_RESET_STREAMS:
4574163953Srrs		{
4575233660Srrs			struct sctp_reset_streams *strrst;
4576233660Srrs			int i, send_out = 0;
4577233660Srrs			int send_in = 0;
4578163953Srrs
4579233660Srrs			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
4580233660Srrs			SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
4581163953Srrs			if (stcb == NULL) {
4582171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4583163953Srrs				error = ENOENT;
4584163953Srrs				break;
4585163953Srrs			}
4586270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4587163953Srrs				/*
4588233660Srrs				 * Peer does not support the chunk type.
4589163953Srrs				 */
4590233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4591233660Srrs				error = EOPNOTSUPP;
4592163953Srrs				SCTP_TCB_UNLOCK(stcb);
4593163953Srrs				break;
4594163953Srrs			}
4595273000Stuexen			if (sizeof(struct sctp_reset_streams) +
4596273000Stuexen			    strrst->srs_number_streams * sizeof(uint16_t) > optsize) {
4597273000Stuexen				error = EINVAL;
4598273000Stuexen				SCTP_TCB_UNLOCK(stcb);
4599273000Stuexen				break;
4600273000Stuexen			}
4601233660Srrs			if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
4602163953Srrs				send_in = 1;
4603294140Stuexen				if (stcb->asoc.stream_reset_outstanding) {
4604294140Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4605294140Stuexen					error = EALREADY;
4606294140Stuexen					SCTP_TCB_UNLOCK(stcb);
4607294140Stuexen					break;
4608294140Stuexen				}
4609233660Srrs			}
4610233660Srrs			if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
4611163953Srrs				send_out = 1;
4612233660Srrs			}
4613294140Stuexen			if ((strrst->srs_number_streams > SCTP_MAX_STREAMS_AT_ONCE_RESET) && send_in) {
4614294140Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4615294140Stuexen				error = ENOMEM;
4616294140Stuexen				SCTP_TCB_UNLOCK(stcb);
4617294140Stuexen				break;
4618294140Stuexen			}
4619233660Srrs			if ((send_in == 0) && (send_out == 0)) {
4620233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4621233660Srrs				error = EINVAL;
4622233660Srrs				SCTP_TCB_UNLOCK(stcb);
4623233660Srrs				break;
4624233660Srrs			}
4625233660Srrs			for (i = 0; i < strrst->srs_number_streams; i++) {
4626233660Srrs				if ((send_in) &&
4627233660Srrs				    (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
4628233660Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4629188854Srrs					error = EINVAL;
4630233660Srrs					break;
4631188854Srrs				}
4632233660Srrs				if ((send_out) &&
4633233660Srrs				    (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
4634233660Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4635233660Srrs					error = EINVAL;
4636233660Srrs					break;
4637188854Srrs				}
4638233660Srrs			}
4639233660Srrs			if (error) {
4640233660Srrs				SCTP_TCB_UNLOCK(stcb);
4641233660Srrs				break;
4642233660Srrs			}
4643294140Stuexen			if (send_out) {
4644294140Stuexen				int cnt;
4645294140Stuexen				uint16_t strm;
4646233660Srrs
4647294140Stuexen				if (strrst->srs_number_streams) {
4648294140Stuexen					for (i = 0, cnt = 0; i < strrst->srs_number_streams; i++) {
4649294140Stuexen						strm = strrst->srs_stream_list[i];
4650294140Stuexen						if (stcb->asoc.strmout[strm].state == SCTP_STREAM_OPEN) {
4651294140Stuexen							stcb->asoc.strmout[strm].state = SCTP_STREAM_RESET_PENDING;
4652294140Stuexen							cnt++;
4653294140Stuexen						}
4654294140Stuexen					}
4655294140Stuexen				} else {
4656294140Stuexen					/* Its all */
4657294140Stuexen					for (i = 0, cnt = 0; i < stcb->asoc.streamoutcnt; i++) {
4658294140Stuexen						if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN) {
4659294140Stuexen							stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING;
4660294140Stuexen							cnt++;
4661294140Stuexen						}
4662294140Stuexen					}
4663294140Stuexen				}
4664294140Stuexen			}
4665294140Stuexen			if (send_in) {
4666294140Stuexen				error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
4667294140Stuexen				    strrst->srs_stream_list,
4668294140Stuexen				    send_in, 0, 0, 0, 0, 0);
4669294206Stuexen			} else {
4670294141Stuexen				error = sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_LOCKED);
4671294206Stuexen			}
4672294206Stuexen			if (error == 0) {
4673294140Stuexen				sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4674294206Stuexen			} else {
4675294206Stuexen				/*
4676294206Stuexen				 * For outgoing streams don't report any
4677294206Stuexen				 * problems in sending the request to the
4678294206Stuexen				 * application. XXX: Double check resetting
4679294206Stuexen				 * incoming streams.
4680294206Stuexen				 */
4681294206Stuexen				error = 0;
4682294206Stuexen			}
4683233660Srrs			SCTP_TCB_UNLOCK(stcb);
4684233660Srrs			break;
4685233660Srrs		}
4686233660Srrs	case SCTP_ADD_STREAMS:
4687233660Srrs		{
4688233660Srrs			struct sctp_add_streams *stradd;
4689233660Srrs			uint8_t addstream = 0;
4690233660Srrs			uint16_t add_o_strmcnt = 0;
4691233660Srrs			uint16_t add_i_strmcnt = 0;
4692233660Srrs
4693233660Srrs			SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
4694233660Srrs			SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
4695233660Srrs			if (stcb == NULL) {
4696233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4697233660Srrs				error = ENOENT;
4698233660Srrs				break;
4699233660Srrs			}
4700270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4701235057Stuexen				/*
4702235057Stuexen				 * Peer does not support the chunk type.
4703235057Stuexen				 */
4704235057Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4705235057Stuexen				error = EOPNOTSUPP;
4706235057Stuexen				SCTP_TCB_UNLOCK(stcb);
4707235057Stuexen				break;
4708235057Stuexen			}
4709235057Stuexen			if (stcb->asoc.stream_reset_outstanding) {
4710235057Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4711235057Stuexen				error = EALREADY;
4712235057Stuexen				SCTP_TCB_UNLOCK(stcb);
4713235057Stuexen				break;
4714235057Stuexen			}
4715233660Srrs			if ((stradd->sas_outstrms == 0) &&
4716233660Srrs			    (stradd->sas_instrms == 0)) {
4717233660Srrs				error = EINVAL;
4718233660Srrs				goto skip_stuff;
4719233660Srrs			}
4720233660Srrs			if (stradd->sas_outstrms) {
4721188854Srrs				addstream = 1;
4722188854Srrs				/* We allocate here */
4723233660Srrs				add_o_strmcnt = stradd->sas_outstrms;
4724233660Srrs				if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
4725188854Srrs					/* You can't have more than 64k */
4726188854Srrs					error = EINVAL;
4727188854Srrs					goto skip_stuff;
4728188854Srrs				}
4729163953Srrs			}
4730233660Srrs			if (stradd->sas_instrms) {
4731233660Srrs				int cnt;
4732163953Srrs
4733233660Srrs				addstream |= 2;
4734233660Srrs				/*
4735233660Srrs				 * We allocate inside
4736233660Srrs				 * sctp_send_str_reset_req()
4737233660Srrs				 */
4738233660Srrs				add_i_strmcnt = stradd->sas_instrms;
4739233660Srrs				cnt = add_i_strmcnt;
4740233660Srrs				cnt += stcb->asoc.streamincnt;
4741233660Srrs				if (cnt > 0x0000ffff) {
4742233660Srrs					/* You can't have more than 64k */
4743163953Srrs					error = EINVAL;
4744233660Srrs					goto skip_stuff;
4745163953Srrs				}
4746233660Srrs				if (cnt > (int)stcb->asoc.max_inbound_streams) {
4747233660Srrs					/* More than you are allowed */
4748163953Srrs					error = EINVAL;
4749233660Srrs					goto skip_stuff;
4750163953Srrs				}
4751163953Srrs			}
4752294140Stuexen			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
4753233660Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4754188854Srrs	skip_stuff:
4755233660Srrs			SCTP_TCB_UNLOCK(stcb);
4756233660Srrs			break;
4757233660Srrs		}
4758233660Srrs	case SCTP_RESET_ASSOC:
4759233660Srrs		{
4760294140Stuexen			int i;
4761233660Srrs			uint32_t *value;
4762233660Srrs
4763233660Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
4764233660Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
4765233660Srrs			if (stcb == NULL) {
4766233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4767233660Srrs				error = ENOENT;
4768233660Srrs				break;
4769233660Srrs			}
4770270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4771233660Srrs				/*
4772233660Srrs				 * Peer does not support the chunk type.
4773233660Srrs				 */
4774233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4775233660Srrs				error = EOPNOTSUPP;
4776163953Srrs				SCTP_TCB_UNLOCK(stcb);
4777163953Srrs				break;
4778163953Srrs			}
4779233660Srrs			if (stcb->asoc.stream_reset_outstanding) {
4780233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4781233660Srrs				error = EALREADY;
4782233660Srrs				SCTP_TCB_UNLOCK(stcb);
4783233660Srrs				break;
4784233660Srrs			}
4785294140Stuexen			/*
4786294140Stuexen			 * Is there any data pending in the send or sent
4787294140Stuexen			 * queues?
4788294140Stuexen			 */
4789294140Stuexen			if (!TAILQ_EMPTY(&stcb->asoc.send_queue) ||
4790294140Stuexen			    !TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
4791294140Stuexen		busy_out:
4792294140Stuexen				error = EBUSY;
4793294140Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4794294140Stuexen				SCTP_TCB_UNLOCK(stcb);
4795294140Stuexen				break;
4796294140Stuexen			}
4797294140Stuexen			/* Do any streams have data queued? */
4798294140Stuexen			for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
4799294140Stuexen				if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
4800294140Stuexen					goto busy_out;
4801294140Stuexen				}
4802294140Stuexen			}
4803294140Stuexen			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 1, 0, 0, 0, 0);
4804172090Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4805163953Srrs			SCTP_TCB_UNLOCK(stcb);
4806223132Stuexen			break;
4807163953Srrs		}
4808163953Srrs	case SCTP_CONNECT_X:
4809166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
4810171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4811163953Srrs			error = EINVAL;
4812163953Srrs			break;
4813163953Srrs		}
4814166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
4815163953Srrs		break;
4816163953Srrs	case SCTP_CONNECT_X_DELAYED:
4817166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
4818171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4819163953Srrs			error = EINVAL;
4820163953Srrs			break;
4821163953Srrs		}
4822166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
4823163953Srrs		break;
4824163953Srrs	case SCTP_CONNECT_X_COMPLETE:
4825163953Srrs		{
4826163953Srrs			struct sockaddr *sa;
4827163953Srrs
4828166675Srrs			/* FIXME MT: check correct? */
4829166675Srrs			SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
4830166675Srrs
4831163953Srrs			/* find tcb */
4832163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4833163953Srrs				SCTP_INP_RLOCK(inp);
4834163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
4835163953Srrs				if (stcb) {
4836163953Srrs					SCTP_TCB_LOCK(stcb);
4837163953Srrs				}
4838163953Srrs				SCTP_INP_RUNLOCK(inp);
4839163953Srrs			} else {
4840166675Srrs				/*
4841166675Srrs				 * We increment here since
4842166675Srrs				 * sctp_findassociation_ep_addr() wil do a
4843166675Srrs				 * decrement if it finds the stcb as long as
4844166675Srrs				 * the locked tcb (last argument) is NOT a
4845166675Srrs				 * TCB.. aka NULL.
4846166675Srrs				 */
4847163953Srrs				SCTP_INP_INCR_REF(inp);
4848283716Stuexen				stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
4849163953Srrs				if (stcb == NULL) {
4850163953Srrs					SCTP_INP_DECR_REF(inp);
4851163953Srrs				}
4852163953Srrs			}
4853163953Srrs
4854163953Srrs			if (stcb == NULL) {
4855171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4856163953Srrs				error = ENOENT;
4857163953Srrs				break;
4858163953Srrs			}
4859163953Srrs			if (stcb->asoc.delayed_connection == 1) {
4860163953Srrs				stcb->asoc.delayed_connection = 0;
4861169378Srrs				(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
4862165220Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
4863165220Srrs				    stcb->asoc.primary_destination,
4864283822Stuexen				    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
4865172090Srrs				sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
4866163953Srrs			} else {
4867163953Srrs				/*
4868163953Srrs				 * already expired or did not use delayed
4869163953Srrs				 * connectx
4870163953Srrs				 */
4871171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4872163953Srrs				error = EALREADY;
4873163953Srrs			}
4874163953Srrs			SCTP_TCB_UNLOCK(stcb);
4875223132Stuexen			break;
4876163953Srrs		}
4877170056Srrs	case SCTP_MAX_BURST:
4878163953Srrs		{
4879217895Stuexen			struct sctp_assoc_value *av;
4880163953Srrs
4881217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4882217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4883166675Srrs
4884217895Stuexen			if (stcb) {
4885217895Stuexen				stcb->asoc.max_burst = av->assoc_value;
4886217895Stuexen				SCTP_TCB_UNLOCK(stcb);
4887217895Stuexen			} else {
4888224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4889224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4890224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4891223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4892223132Stuexen					SCTP_INP_WLOCK(inp);
4893223132Stuexen					inp->sctp_ep.max_burst = av->assoc_value;
4894223132Stuexen					SCTP_INP_WUNLOCK(inp);
4895223132Stuexen				}
4896223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4897223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4898223132Stuexen					SCTP_INP_RLOCK(inp);
4899223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4900223132Stuexen						SCTP_TCB_LOCK(stcb);
4901223132Stuexen						stcb->asoc.max_burst = av->assoc_value;
4902223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4903223132Stuexen					}
4904223132Stuexen					SCTP_INP_RUNLOCK(inp);
4905223132Stuexen				}
4906217895Stuexen			}
4907223132Stuexen			break;
4908163953Srrs		}
4909163953Srrs	case SCTP_MAXSEG:
4910163953Srrs		{
4911167598Srrs			struct sctp_assoc_value *av;
4912163953Srrs			int ovh;
4913163953Srrs
4914167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4915167598Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4916166675Srrs
4917170056Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
4918170056Srrs				ovh = SCTP_MED_OVERHEAD;
4919170056Srrs			} else {
4920170056Srrs				ovh = SCTP_MED_V4_OVERHEAD;
4921170056Srrs			}
4922167598Srrs			if (stcb) {
4923170056Srrs				if (av->assoc_value) {
4924170056Srrs					stcb->asoc.sctp_frag_point = (av->assoc_value + ovh);
4925170056Srrs				} else {
4926170056Srrs					stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
4927170056Srrs				}
4928167598Srrs				SCTP_TCB_UNLOCK(stcb);
4929163953Srrs			} else {
4930224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4931224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4932224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4933223132Stuexen					SCTP_INP_WLOCK(inp);
4934223132Stuexen					/*
4935223132Stuexen					 * FIXME MT: I think this is not in
4936223132Stuexen					 * tune with the API ID
4937223132Stuexen					 */
4938223132Stuexen					if (av->assoc_value) {
4939223132Stuexen						inp->sctp_frag_point = (av->assoc_value + ovh);
4940223132Stuexen					} else {
4941223132Stuexen						inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
4942223132Stuexen					}
4943223132Stuexen					SCTP_INP_WUNLOCK(inp);
4944167598Srrs				} else {
4945223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4946223132Stuexen					error = EINVAL;
4947167598Srrs				}
4948163953Srrs			}
4949223132Stuexen			break;
4950163953Srrs		}
4951163953Srrs	case SCTP_EVENTS:
4952163953Srrs		{
4953163953Srrs			struct sctp_event_subscribe *events;
4954163953Srrs
4955166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
4956166675Srrs
4957163953Srrs			SCTP_INP_WLOCK(inp);
4958163953Srrs			if (events->sctp_data_io_event) {
4959163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
4960163953Srrs			} else {
4961163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
4962163953Srrs			}
4963163953Srrs
4964163953Srrs			if (events->sctp_association_event) {
4965163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4966163953Srrs			} else {
4967163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4968163953Srrs			}
4969163953Srrs
4970163953Srrs			if (events->sctp_address_event) {
4971163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
4972163953Srrs			} else {
4973163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
4974163953Srrs			}
4975163953Srrs
4976163953Srrs			if (events->sctp_send_failure_event) {
4977163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4978163953Srrs			} else {
4979163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4980163953Srrs			}
4981163953Srrs
4982163953Srrs			if (events->sctp_peer_error_event) {
4983163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
4984163953Srrs			} else {
4985163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
4986163953Srrs			}
4987163953Srrs
4988163953Srrs			if (events->sctp_shutdown_event) {
4989163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4990163953Srrs			} else {
4991163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4992163953Srrs			}
4993163953Srrs
4994163953Srrs			if (events->sctp_partial_delivery_event) {
4995163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
4996163953Srrs			} else {
4997163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
4998163953Srrs			}
4999163953Srrs
5000163953Srrs			if (events->sctp_adaptation_layer_event) {
5001163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5002163953Srrs			} else {
5003163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5004163953Srrs			}
5005163953Srrs
5006163953Srrs			if (events->sctp_authentication_event) {
5007163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
5008163953Srrs			} else {
5009163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
5010163953Srrs			}
5011163953Srrs
5012185694Srrs			if (events->sctp_sender_dry_event) {
5013185694Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
5014185694Srrs			} else {
5015185694Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
5016185694Srrs			}
5017185694Srrs
5018202520Srrs			if (events->sctp_stream_reset_event) {
5019163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5020163953Srrs			} else {
5021163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5022163953Srrs			}
5023163953Srrs			SCTP_INP_WUNLOCK(inp);
5024223132Stuexen
5025223132Stuexen			SCTP_INP_RLOCK(inp);
5026223132Stuexen			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5027223132Stuexen				SCTP_TCB_LOCK(stcb);
5028223132Stuexen				if (events->sctp_association_event) {
5029223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
5030223132Stuexen				} else {
5031223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
5032223132Stuexen				}
5033223132Stuexen				if (events->sctp_address_event) {
5034223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
5035223132Stuexen				} else {
5036223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
5037223132Stuexen				}
5038223132Stuexen				if (events->sctp_send_failure_event) {
5039223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
5040223132Stuexen				} else {
5041223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
5042223132Stuexen				}
5043223132Stuexen				if (events->sctp_peer_error_event) {
5044223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
5045223132Stuexen				} else {
5046223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
5047223132Stuexen				}
5048223132Stuexen				if (events->sctp_shutdown_event) {
5049223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5050223132Stuexen				} else {
5051223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5052223132Stuexen				}
5053223132Stuexen				if (events->sctp_partial_delivery_event) {
5054223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
5055223132Stuexen				} else {
5056223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
5057223132Stuexen				}
5058223132Stuexen				if (events->sctp_adaptation_layer_event) {
5059223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5060223132Stuexen				} else {
5061223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5062223132Stuexen				}
5063223132Stuexen				if (events->sctp_authentication_event) {
5064223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
5065223132Stuexen				} else {
5066223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
5067223132Stuexen				}
5068223132Stuexen				if (events->sctp_sender_dry_event) {
5069223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
5070223132Stuexen				} else {
5071223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
5072223132Stuexen				}
5073223132Stuexen				if (events->sctp_stream_reset_event) {
5074223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5075223132Stuexen				} else {
5076223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5077223132Stuexen				}
5078223132Stuexen				SCTP_TCB_UNLOCK(stcb);
5079223132Stuexen			}
5080223132Stuexen			/*
5081223132Stuexen			 * Send up the sender dry event only for 1-to-1
5082223132Stuexen			 * style sockets.
5083223132Stuexen			 */
5084223132Stuexen			if (events->sctp_sender_dry_event) {
5085223132Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5086223132Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
5087223132Stuexen					stcb = LIST_FIRST(&inp->sctp_asoc_list);
5088223132Stuexen					if (stcb) {
5089223132Stuexen						SCTP_TCB_LOCK(stcb);
5090223132Stuexen						if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
5091223132Stuexen						    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
5092223132Stuexen						    (stcb->asoc.stream_queue_cnt == 0)) {
5093223132Stuexen							sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
5094223132Stuexen						}
5095223132Stuexen						SCTP_TCB_UNLOCK(stcb);
5096223132Stuexen					}
5097223132Stuexen				}
5098223132Stuexen			}
5099223132Stuexen			SCTP_INP_RUNLOCK(inp);
5100223132Stuexen			break;
5101163953Srrs		}
5102163953Srrs	case SCTP_ADAPTATION_LAYER:
5103163953Srrs		{
5104163953Srrs			struct sctp_setadaptation *adap_bits;
5105163953Srrs
5106166675Srrs			SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
5107163953Srrs			SCTP_INP_WLOCK(inp);
5108163953Srrs			inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
5109246687Stuexen			inp->sctp_ep.adaptation_layer_indicator_provided = 1;
5110163953Srrs			SCTP_INP_WUNLOCK(inp);
5111223132Stuexen			break;
5112163953Srrs		}
5113166675Srrs#ifdef SCTP_DEBUG
5114163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
5115163953Srrs		{
5116163953Srrs			uint32_t *vvv;
5117163953Srrs
5118166675Srrs			SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
5119163953Srrs			SCTP_INP_WLOCK(inp);
5120163953Srrs			inp->sctp_ep.initial_sequence_debug = *vvv;
5121163953Srrs			SCTP_INP_WUNLOCK(inp);
5122223132Stuexen			break;
5123163953Srrs		}
5124166675Srrs#endif
5125163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
5126163953Srrs		{
5127163953Srrs			struct sctp_sndrcvinfo *s_info;
5128163953Srrs
5129166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
5130166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
5131163953Srrs
5132166675Srrs			if (stcb) {
5133223132Stuexen				if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
5134170056Srrs					memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
5135163953Srrs				} else {
5136171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5137166675Srrs					error = EINVAL;
5138163953Srrs				}
5139166675Srrs				SCTP_TCB_UNLOCK(stcb);
5140166675Srrs			} else {
5141224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5142224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5143224918Stuexen				    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
5144223132Stuexen				    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
5145223132Stuexen					SCTP_INP_WLOCK(inp);
5146223132Stuexen					memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
5147223132Stuexen					SCTP_INP_WUNLOCK(inp);
5148223132Stuexen				}
5149223132Stuexen				if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
5150223132Stuexen				    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
5151223132Stuexen					SCTP_INP_RLOCK(inp);
5152223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5153223132Stuexen						SCTP_TCB_LOCK(stcb);
5154223132Stuexen						if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
5155223132Stuexen							memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
5156223132Stuexen						}
5157223132Stuexen						SCTP_TCB_UNLOCK(stcb);
5158223132Stuexen					}
5159223132Stuexen					SCTP_INP_RUNLOCK(inp);
5160223132Stuexen				}
5161163953Srrs			}
5162223132Stuexen			break;
5163163953Srrs		}
5164163953Srrs	case SCTP_PEER_ADDR_PARAMS:
5165163953Srrs		{
5166163953Srrs			struct sctp_paddrparams *paddrp;
5167163953Srrs			struct sctp_nets *net;
5168283699Stuexen			struct sockaddr *addr;
5169163953Srrs
5170283699Stuexen#if defined(INET) && defined(INET6)
5171283699Stuexen			struct sockaddr_in sin_store;
5172283699Stuexen
5173283699Stuexen#endif
5174283699Stuexen
5175166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
5176166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
5177283699Stuexen
5178283699Stuexen#if defined(INET) && defined(INET6)
5179283699Stuexen			if (paddrp->spp_address.ss_family == AF_INET6) {
5180283699Stuexen				struct sockaddr_in6 *sin6;
5181283699Stuexen
5182283699Stuexen				sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
5183283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5184283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
5185283699Stuexen					addr = (struct sockaddr *)&sin_store;
5186283699Stuexen				} else {
5187283699Stuexen					addr = (struct sockaddr *)&paddrp->spp_address;
5188283699Stuexen				}
5189166675Srrs			} else {
5190283699Stuexen				addr = (struct sockaddr *)&paddrp->spp_address;
5191283699Stuexen			}
5192283699Stuexen#else
5193283699Stuexen			addr = (struct sockaddr *)&paddrp->spp_address;
5194283699Stuexen#endif
5195283699Stuexen			if (stcb != NULL) {
5196283699Stuexen				net = sctp_findnet(stcb, addr);
5197283699Stuexen			} else {
5198166675Srrs				/*
5199166675Srrs				 * We increment here since
5200166675Srrs				 * sctp_findassociation_ep_addr() wil do a
5201166675Srrs				 * decrement if it finds the stcb as long as
5202166675Srrs				 * the locked tcb (last argument) is NOT a
5203166675Srrs				 * TCB.. aka NULL.
5204166675Srrs				 */
5205283699Stuexen				net = NULL;
5206166675Srrs				SCTP_INP_INCR_REF(inp);
5207283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr,
5208166675Srrs				    &net, NULL, NULL);
5209163953Srrs				if (stcb == NULL) {
5210166675Srrs					SCTP_INP_DECR_REF(inp);
5211163953Srrs				}
5212163953Srrs			}
5213283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
5214221249Stuexen#ifdef INET
5215283699Stuexen				if (addr->sa_family == AF_INET) {
5216221249Stuexen
5217171943Srrs					struct sockaddr_in *sin;
5218171943Srrs
5219283699Stuexen					sin = (struct sockaddr_in *)addr;
5220283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
5221171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5222171943Srrs						SCTP_TCB_UNLOCK(stcb);
5223171943Srrs						error = EINVAL;
5224171943Srrs						break;
5225171943Srrs					}
5226221249Stuexen				} else
5227221249Stuexen#endif
5228221249Stuexen#ifdef INET6
5229283699Stuexen				if (addr->sa_family == AF_INET6) {
5230171943Srrs					struct sockaddr_in6 *sin6;
5231171943Srrs
5232283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
5233171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
5234171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5235171943Srrs						SCTP_TCB_UNLOCK(stcb);
5236171943Srrs						error = EINVAL;
5237171943Srrs						break;
5238171943Srrs					}
5239221249Stuexen				} else
5240221249Stuexen#endif
5241221249Stuexen				{
5242171943Srrs					error = EAFNOSUPPORT;
5243171943Srrs					SCTP_TCB_UNLOCK(stcb);
5244171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5245171943Srrs					break;
5246171943Srrs				}
5247171943Srrs			}
5248170056Srrs			/* sanity checks */
5249170056Srrs			if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
5250170056Srrs				if (stcb)
5251170056Srrs					SCTP_TCB_UNLOCK(stcb);
5252171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5253170056Srrs				return (EINVAL);
5254170056Srrs			}
5255170056Srrs			if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
5256170056Srrs				if (stcb)
5257170056Srrs					SCTP_TCB_UNLOCK(stcb);
5258171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5259170056Srrs				return (EINVAL);
5260170056Srrs			}
5261283699Stuexen			if (stcb != NULL) {
5262163953Srrs				/************************TCB SPECIFIC SET ******************/
5263283699Stuexen				if (net != NULL) {
5264163953Srrs					/************************NET SPECIFIC SET ******************/
5265224641Stuexen					if (paddrp->spp_flags & SPP_HB_DISABLE) {
5266224641Stuexen						if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
5267224641Stuexen						    !(net->dest_state & SCTP_ADDR_NOHB)) {
5268224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5269283822Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
5270171440Srrs						}
5271163953Srrs						net->dest_state |= SCTP_ADDR_NOHB;
5272163953Srrs					}
5273163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5274224641Stuexen						if (paddrp->spp_hbinterval) {
5275224641Stuexen							net->heart_beat_delay = paddrp->spp_hbinterval;
5276224641Stuexen						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5277224641Stuexen							net->heart_beat_delay = 0;
5278224641Stuexen						}
5279224641Stuexen						sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5280224641Stuexen						    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
5281224641Stuexen						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5282163953Srrs						net->dest_state &= ~SCTP_ADDR_NOHB;
5283163953Srrs					}
5284224641Stuexen					if (paddrp->spp_flags & SPP_HB_DEMAND) {
5285224641Stuexen						/* on demand HB */
5286224641Stuexen						sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5287228391Stuexen						sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
5288224641Stuexen						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5289224641Stuexen					}
5290170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
5291165647Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5292165220Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
5293283822Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
5294163953Srrs						}
5295225635Stuexen						net->dest_state |= SCTP_ADDR_NO_PMTUD;
5296283829Stuexen						net->mtu = paddrp->spp_pathmtu;
5297283829Stuexen						switch (net->ro._l_addr.sa.sa_family) {
5298283829Stuexen#ifdef INET
5299283829Stuexen						case AF_INET:
5300283829Stuexen							net->mtu += SCTP_MIN_V4_OVERHEAD;
5301283829Stuexen							break;
5302283829Stuexen#endif
5303283829Stuexen#ifdef INET6
5304283829Stuexen						case AF_INET6:
5305283829Stuexen							net->mtu += SCTP_MIN_OVERHEAD;
5306283829Stuexen							break;
5307283829Stuexen#endif
5308283829Stuexen						default:
5309283829Stuexen							break;
5310283829Stuexen						}
5311258454Stuexen						if (net->mtu < stcb->asoc.smallest_mtu) {
5312258454Stuexen							sctp_pathmtu_adjustment(stcb, net->mtu);
5313163953Srrs						}
5314163953Srrs					}
5315163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5316225635Stuexen						if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5317163953Srrs							sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
5318163953Srrs						}
5319225635Stuexen						net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
5320163953Srrs					}
5321224641Stuexen					if (paddrp->spp_pathmaxrxt) {
5322224641Stuexen						if (net->dest_state & SCTP_ADDR_PF) {
5323224641Stuexen							if (net->error_count > paddrp->spp_pathmaxrxt) {
5324224641Stuexen								net->dest_state &= ~SCTP_ADDR_PF;
5325224641Stuexen							}
5326224641Stuexen						} else {
5327224641Stuexen							if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
5328224641Stuexen							    (net->error_count > net->pf_threshold)) {
5329224641Stuexen								net->dest_state |= SCTP_ADDR_PF;
5330224641Stuexen								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5331283822Stuexen								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
5332283822Stuexen								    stcb->sctp_ep, stcb, net,
5333283822Stuexen								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12);
5334224641Stuexen								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5335224641Stuexen							}
5336224641Stuexen						}
5337224641Stuexen						if (net->dest_state & SCTP_ADDR_REACHABLE) {
5338224641Stuexen							if (net->error_count > paddrp->spp_pathmaxrxt) {
5339224641Stuexen								net->dest_state &= ~SCTP_ADDR_REACHABLE;
5340235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5341224641Stuexen							}
5342224641Stuexen						} else {
5343224641Stuexen							if (net->error_count <= paddrp->spp_pathmaxrxt) {
5344224641Stuexen								net->dest_state |= SCTP_ADDR_REACHABLE;
5345235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5346224641Stuexen							}
5347224641Stuexen						}
5348163953Srrs						net->failure_threshold = paddrp->spp_pathmaxrxt;
5349224641Stuexen					}
5350224870Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5351226252Stuexen						net->dscp = paddrp->spp_dscp & 0xfc;
5352225549Stuexen						net->dscp |= 0x01;
5353163953Srrs					}
5354167598Srrs#ifdef INET6
5355163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5356225549Stuexen						if (net->ro._l_addr.sa.sa_family == AF_INET6) {
5357224870Stuexen							net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5358225549Stuexen							net->flowlabel |= 0x80000000;
5359163953Srrs						}
5360163953Srrs					}
5361163953Srrs#endif
5362163953Srrs				} else {
5363163953Srrs					/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
5364283699Stuexen					if (paddrp->spp_pathmaxrxt != 0) {
5365163953Srrs						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
5366224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5367224641Stuexen							if (net->dest_state & SCTP_ADDR_PF) {
5368224641Stuexen								if (net->error_count > paddrp->spp_pathmaxrxt) {
5369224641Stuexen									net->dest_state &= ~SCTP_ADDR_PF;
5370224641Stuexen								}
5371224641Stuexen							} else {
5372224641Stuexen								if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
5373224641Stuexen								    (net->error_count > net->pf_threshold)) {
5374224641Stuexen									net->dest_state |= SCTP_ADDR_PF;
5375224641Stuexen									sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5376283822Stuexen									sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
5377283822Stuexen									    stcb->sctp_ep, stcb, net,
5378283822Stuexen									    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_13);
5379224641Stuexen									sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5380224641Stuexen								}
5381224641Stuexen							}
5382224641Stuexen							if (net->dest_state & SCTP_ADDR_REACHABLE) {
5383224641Stuexen								if (net->error_count > paddrp->spp_pathmaxrxt) {
5384224641Stuexen									net->dest_state &= ~SCTP_ADDR_REACHABLE;
5385235414Stuexen									sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5386224641Stuexen								}
5387224641Stuexen							} else {
5388224641Stuexen								if (net->error_count <= paddrp->spp_pathmaxrxt) {
5389224641Stuexen									net->dest_state |= SCTP_ADDR_REACHABLE;
5390235414Stuexen									sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5391224641Stuexen								}
5392224641Stuexen							}
5393224641Stuexen							net->failure_threshold = paddrp->spp_pathmaxrxt;
5394224641Stuexen						}
5395224641Stuexen					}
5396163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5397283699Stuexen						if (paddrp->spp_hbinterval != 0) {
5398224641Stuexen							stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
5399224641Stuexen						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5400224641Stuexen							stcb->asoc.heart_beat_delay = 0;
5401224641Stuexen						}
5402163953Srrs						/* Turn back on the timer */
5403224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5404283699Stuexen							if (paddrp->spp_hbinterval != 0) {
5405224641Stuexen								net->heart_beat_delay = paddrp->spp_hbinterval;
5406224641Stuexen							} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5407224641Stuexen								net->heart_beat_delay = 0;
5408224641Stuexen							}
5409224641Stuexen							if (net->dest_state & SCTP_ADDR_NOHB) {
5410224641Stuexen								net->dest_state &= ~SCTP_ADDR_NOHB;
5411224641Stuexen							}
5412224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5413283822Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_14);
5414224641Stuexen							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5415224641Stuexen						}
5416225635Stuexen						sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5417163953Srrs					}
5418224641Stuexen					if (paddrp->spp_flags & SPP_HB_DISABLE) {
5419224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5420224641Stuexen							if (!(net->dest_state & SCTP_ADDR_NOHB)) {
5421224641Stuexen								net->dest_state |= SCTP_ADDR_NOHB;
5422224641Stuexen								if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
5423283822Stuexen									sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
5424283822Stuexen									    inp, stcb, net,
5425283822Stuexen									    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15);
5426224641Stuexen								}
5427224641Stuexen							}
5428224641Stuexen						}
5429225635Stuexen						sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5430224641Stuexen					}
5431170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
5432170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5433170056Srrs							if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5434170056Srrs								sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
5435283822Stuexen								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16);
5436170056Srrs							}
5437225635Stuexen							net->dest_state |= SCTP_ADDR_NO_PMTUD;
5438283829Stuexen							net->mtu = paddrp->spp_pathmtu;
5439283829Stuexen							switch (net->ro._l_addr.sa.sa_family) {
5440283829Stuexen#ifdef INET
5441283829Stuexen							case AF_INET:
5442283829Stuexen								net->mtu += SCTP_MIN_V4_OVERHEAD;
5443283829Stuexen								break;
5444283829Stuexen#endif
5445283829Stuexen#ifdef INET6
5446283829Stuexen							case AF_INET6:
5447283829Stuexen								net->mtu += SCTP_MIN_OVERHEAD;
5448283829Stuexen								break;
5449283829Stuexen#endif
5450283829Stuexen							default:
5451283829Stuexen								break;
5452283829Stuexen							}
5453258454Stuexen							if (net->mtu < stcb->asoc.smallest_mtu) {
5454258454Stuexen								sctp_pathmtu_adjustment(stcb, net->mtu);
5455170056Srrs							}
5456170056Srrs						}
5457225635Stuexen						sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5458170056Srrs					}
5459170056Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5460170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5461225635Stuexen							if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5462170056Srrs								sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
5463170056Srrs							}
5464225635Stuexen							net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
5465170056Srrs						}
5466225635Stuexen						sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5467170056Srrs					}
5468224870Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5469224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5470226252Stuexen							net->dscp = paddrp->spp_dscp & 0xfc;
5471225549Stuexen							net->dscp |= 0x01;
5472163953Srrs						}
5473226252Stuexen						stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc;
5474225549Stuexen						stcb->asoc.default_dscp |= 0x01;
5475163953Srrs					}
5476225549Stuexen#ifdef INET6
5477224641Stuexen					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5478170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5479225549Stuexen							if (net->ro._l_addr.sa.sa_family == AF_INET6) {
5480225549Stuexen								net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5481225549Stuexen								net->flowlabel |= 0x80000000;
5482225549Stuexen							}
5483170056Srrs						}
5484225549Stuexen						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5485225549Stuexen						stcb->asoc.default_flowlabel |= 0x80000000;
5486163953Srrs					}
5487225549Stuexen#endif
5488163953Srrs				}
5489163953Srrs				SCTP_TCB_UNLOCK(stcb);
5490163953Srrs			} else {
5491163953Srrs				/************************NO TCB, SET TO default stuff ******************/
5492224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5493224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5494224918Stuexen				    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
5495223132Stuexen					SCTP_INP_WLOCK(inp);
5496223132Stuexen					/*
5497223132Stuexen					 * For the TOS/FLOWLABEL stuff you
5498223132Stuexen					 * set it with the options on the
5499223132Stuexen					 * socket
5500223132Stuexen					 */
5501283699Stuexen					if (paddrp->spp_pathmaxrxt != 0) {
5502223132Stuexen						inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
5503223132Stuexen					}
5504223132Stuexen					if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
5505223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
5506283699Stuexen					else if (paddrp->spp_hbinterval != 0) {
5507223132Stuexen						if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
5508223132Stuexen							paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL;
5509223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
5510223132Stuexen					}
5511223132Stuexen					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5512224641Stuexen						if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5513224641Stuexen							inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
5514224641Stuexen						} else if (paddrp->spp_hbinterval) {
5515224641Stuexen							inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
5516224641Stuexen						}
5517223132Stuexen						sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5518223132Stuexen					} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
5519223132Stuexen						sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5520223132Stuexen					}
5521225635Stuexen					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5522225635Stuexen						sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5523225635Stuexen					} else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
5524225635Stuexen						sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5525225635Stuexen					}
5526225549Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5527226252Stuexen						inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc;
5528225549Stuexen						inp->sctp_ep.default_dscp |= 0x01;
5529225549Stuexen					}
5530225549Stuexen#ifdef INET6
5531225549Stuexen					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5532225549Stuexen						if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
5533225549Stuexen							inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5534225549Stuexen							inp->sctp_ep.default_flowlabel |= 0x80000000;
5535225549Stuexen						}
5536225549Stuexen					}
5537225549Stuexen#endif
5538223132Stuexen					SCTP_INP_WUNLOCK(inp);
5539223132Stuexen				} else {
5540223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5541223132Stuexen					error = EINVAL;
5542163953Srrs				}
5543163953Srrs			}
5544223132Stuexen			break;
5545163953Srrs		}
5546163953Srrs	case SCTP_RTOINFO:
5547163953Srrs		{
5548163953Srrs			struct sctp_rtoinfo *srto;
5549169655Srrs			uint32_t new_init, new_min, new_max;
5550163953Srrs
5551166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
5552166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
5553166675Srrs
5554166675Srrs			if (stcb) {
5555167598Srrs				if (srto->srto_initial)
5556169655Srrs					new_init = srto->srto_initial;
5557169655Srrs				else
5558169655Srrs					new_init = stcb->asoc.initial_rto;
5559167598Srrs				if (srto->srto_max)
5560169655Srrs					new_max = srto->srto_max;
5561169655Srrs				else
5562169655Srrs					new_max = stcb->asoc.maxrto;
5563167598Srrs				if (srto->srto_min)
5564169655Srrs					new_min = srto->srto_min;
5565169655Srrs				else
5566169655Srrs					new_min = stcb->asoc.minrto;
5567169655Srrs				if ((new_min <= new_init) && (new_init <= new_max)) {
5568169655Srrs					stcb->asoc.initial_rto = new_init;
5569169655Srrs					stcb->asoc.maxrto = new_max;
5570169655Srrs					stcb->asoc.minrto = new_min;
5571169655Srrs				} else {
5572179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5573179783Srrs					error = EINVAL;
5574169655Srrs				}
5575166675Srrs				SCTP_TCB_UNLOCK(stcb);
5576166675Srrs			} else {
5577224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5578224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5579224918Stuexen				    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
5580223132Stuexen					SCTP_INP_WLOCK(inp);
5581223132Stuexen					if (srto->srto_initial)
5582223132Stuexen						new_init = srto->srto_initial;
5583223132Stuexen					else
5584223132Stuexen						new_init = inp->sctp_ep.initial_rto;
5585223132Stuexen					if (srto->srto_max)
5586223132Stuexen						new_max = srto->srto_max;
5587223132Stuexen					else
5588223132Stuexen						new_max = inp->sctp_ep.sctp_maxrto;
5589223132Stuexen					if (srto->srto_min)
5590223132Stuexen						new_min = srto->srto_min;
5591223132Stuexen					else
5592223132Stuexen						new_min = inp->sctp_ep.sctp_minrto;
5593223132Stuexen					if ((new_min <= new_init) && (new_init <= new_max)) {
5594223132Stuexen						inp->sctp_ep.initial_rto = new_init;
5595223132Stuexen						inp->sctp_ep.sctp_maxrto = new_max;
5596223132Stuexen						inp->sctp_ep.sctp_minrto = new_min;
5597223132Stuexen					} else {
5598223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5599223132Stuexen						error = EINVAL;
5600223132Stuexen					}
5601223132Stuexen					SCTP_INP_WUNLOCK(inp);
5602169655Srrs				} else {
5603179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5604179783Srrs					error = EINVAL;
5605169655Srrs				}
5606163953Srrs			}
5607223132Stuexen			break;
5608163953Srrs		}
5609163953Srrs	case SCTP_ASSOCINFO:
5610163953Srrs		{
5611163953Srrs			struct sctp_assocparams *sasoc;
5612163953Srrs
5613166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
5614166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
5615171477Srrs			if (sasoc->sasoc_cookie_life) {
5616171477Srrs				/* boundary check the cookie life */
5617171477Srrs				if (sasoc->sasoc_cookie_life < 1000)
5618171477Srrs					sasoc->sasoc_cookie_life = 1000;
5619171477Srrs				if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
5620171477Srrs					sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
5621171477Srrs				}
5622171477Srrs			}
5623163953Srrs			if (stcb) {
5624163953Srrs				if (sasoc->sasoc_asocmaxrxt)
5625163953Srrs					stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
5626170056Srrs				if (sasoc->sasoc_cookie_life) {
5627171572Srrs					stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
5628167598Srrs				}
5629163953Srrs				SCTP_TCB_UNLOCK(stcb);
5630163953Srrs			} else {
5631224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5632224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5633224918Stuexen				    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
5634223132Stuexen					SCTP_INP_WLOCK(inp);
5635223132Stuexen					if (sasoc->sasoc_asocmaxrxt)
5636223132Stuexen						inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
5637223132Stuexen					if (sasoc->sasoc_cookie_life) {
5638223132Stuexen						inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
5639223132Stuexen					}
5640223132Stuexen					SCTP_INP_WUNLOCK(inp);
5641223132Stuexen				} else {
5642223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5643223132Stuexen					error = EINVAL;
5644167598Srrs				}
5645163953Srrs			}
5646223132Stuexen			break;
5647163953Srrs		}
5648163953Srrs	case SCTP_INITMSG:
5649163953Srrs		{
5650163953Srrs			struct sctp_initmsg *sinit;
5651163953Srrs
5652166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
5653163953Srrs			SCTP_INP_WLOCK(inp);
5654163953Srrs			if (sinit->sinit_num_ostreams)
5655163953Srrs				inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
5656163953Srrs
5657163953Srrs			if (sinit->sinit_max_instreams)
5658163953Srrs				inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
5659163953Srrs
5660163953Srrs			if (sinit->sinit_max_attempts)
5661163953Srrs				inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
5662163953Srrs
5663167598Srrs			if (sinit->sinit_max_init_timeo)
5664163953Srrs				inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
5665163953Srrs			SCTP_INP_WUNLOCK(inp);
5666223132Stuexen			break;
5667163953Srrs		}
5668163953Srrs	case SCTP_PRIMARY_ADDR:
5669163953Srrs		{
5670163953Srrs			struct sctp_setprim *spa;
5671223132Stuexen			struct sctp_nets *net;
5672283699Stuexen			struct sockaddr *addr;
5673163953Srrs
5674283699Stuexen#if defined(INET) && defined(INET6)
5675283699Stuexen			struct sockaddr_in sin_store;
5676283699Stuexen
5677283699Stuexen#endif
5678283699Stuexen
5679166675Srrs			SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
5680166675Srrs			SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
5681163953Srrs
5682283699Stuexen#if defined(INET) && defined(INET6)
5683283699Stuexen			if (spa->ssp_addr.ss_family == AF_INET6) {
5684283699Stuexen				struct sockaddr_in6 *sin6;
5685283699Stuexen
5686283699Stuexen				sin6 = (struct sockaddr_in6 *)&spa->ssp_addr;
5687283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5688283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
5689283699Stuexen					addr = (struct sockaddr *)&sin_store;
5690283699Stuexen				} else {
5691283699Stuexen					addr = (struct sockaddr *)&spa->ssp_addr;
5692283699Stuexen				}
5693166675Srrs			} else {
5694283699Stuexen				addr = (struct sockaddr *)&spa->ssp_addr;
5695283699Stuexen			}
5696283699Stuexen#else
5697283699Stuexen			addr = (struct sockaddr *)&spa->ssp_addr;
5698283699Stuexen#endif
5699283699Stuexen			if (stcb != NULL) {
5700283699Stuexen				net = sctp_findnet(stcb, addr);
5701283699Stuexen			} else {
5702166675Srrs				/*
5703166675Srrs				 * We increment here since
5704166675Srrs				 * sctp_findassociation_ep_addr() wil do a
5705166675Srrs				 * decrement if it finds the stcb as long as
5706166675Srrs				 * the locked tcb (last argument) is NOT a
5707166675Srrs				 * TCB.. aka NULL.
5708166675Srrs				 */
5709283699Stuexen				net = NULL;
5710163953Srrs				SCTP_INP_INCR_REF(inp);
5711283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr,
5712163953Srrs				    &net, NULL, NULL);
5713163953Srrs				if (stcb == NULL) {
5714163953Srrs					SCTP_INP_DECR_REF(inp);
5715163953Srrs				}
5716163953Srrs			}
5717166675Srrs
5718283699Stuexen			if ((stcb != NULL) && (net != NULL)) {
5719284693Stuexen				if (net != stcb->asoc.primary_destination) {
5720284693Stuexen					if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
5721284693Stuexen						/* Ok we need to set it */
5722284693Stuexen						if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
5723284693Stuexen							if ((stcb->asoc.alternate) &&
5724284693Stuexen							    (!(net->dest_state & SCTP_ADDR_PF)) &&
5725284693Stuexen							    (net->dest_state & SCTP_ADDR_REACHABLE)) {
5726284693Stuexen								sctp_free_remote_addr(stcb->asoc.alternate);
5727284693Stuexen								stcb->asoc.alternate = NULL;
5728284693Stuexen							}
5729284693Stuexen						} else {
5730284693Stuexen							SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5731284693Stuexen							error = EINVAL;
5732166675Srrs						}
5733284693Stuexen					} else {
5734284693Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5735284693Stuexen						error = EINVAL;
5736163953Srrs					}
5737163953Srrs				}
5738166675Srrs			} else {
5739171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5740166675Srrs				error = EINVAL;
5741163953Srrs			}
5742283699Stuexen			if (stcb != NULL) {
5743166675Srrs				SCTP_TCB_UNLOCK(stcb);
5744166675Srrs			}
5745223132Stuexen			break;
5746163953Srrs		}
5747167598Srrs	case SCTP_SET_DYNAMIC_PRIMARY:
5748167598Srrs		{
5749167598Srrs			union sctp_sockstore *ss;
5750163953Srrs
5751170587Srwatson			error = priv_check(curthread,
5752170587Srwatson			    PRIV_NETINET_RESERVEDPORT);
5753167598Srrs			if (error)
5754167598Srrs				break;
5755167598Srrs
5756167598Srrs			SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
5757167598Srrs			/* SUPER USER CHECK? */
5758167598Srrs			error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
5759223132Stuexen			break;
5760167598Srrs		}
5761163953Srrs	case SCTP_SET_PEER_PRIMARY_ADDR:
5762163953Srrs		{
5763163953Srrs			struct sctp_setpeerprim *sspp;
5764283699Stuexen			struct sockaddr *addr;
5765163953Srrs
5766283699Stuexen#if defined(INET) && defined(INET6)
5767283699Stuexen			struct sockaddr_in sin_store;
5768283699Stuexen
5769283699Stuexen#endif
5770283699Stuexen
5771166675Srrs			SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
5772166675Srrs			SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
5773169208Srrs			if (stcb != NULL) {
5774170056Srrs				struct sctp_ifa *ifa;
5775170056Srrs
5776283699Stuexen#if defined(INET) && defined(INET6)
5777283699Stuexen				if (sspp->sspp_addr.ss_family == AF_INET6) {
5778283699Stuexen					struct sockaddr_in6 *sin6;
5779283699Stuexen
5780283699Stuexen					sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr;
5781283699Stuexen					if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5782283699Stuexen						in6_sin6_2_sin(&sin_store, sin6);
5783283699Stuexen						addr = (struct sockaddr *)&sin_store;
5784283699Stuexen					} else {
5785283699Stuexen						addr = (struct sockaddr *)&sspp->sspp_addr;
5786283699Stuexen					}
5787283699Stuexen				} else {
5788283699Stuexen					addr = (struct sockaddr *)&sspp->sspp_addr;
5789283699Stuexen				}
5790283699Stuexen#else
5791283699Stuexen				addr = (struct sockaddr *)&sspp->sspp_addr;
5792283699Stuexen#endif
5793283699Stuexen				ifa = sctp_find_ifa_by_addr(addr, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
5794170056Srrs				if (ifa == NULL) {
5795171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5796166675Srrs					error = EINVAL;
5797170056Srrs					goto out_of_it;
5798166675Srrs				}
5799170056Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
5800170056Srrs					/*
5801170056Srrs					 * Must validate the ifa found is in
5802170056Srrs					 * our ep
5803170056Srrs					 */
5804170056Srrs					struct sctp_laddr *laddr;
5805170056Srrs					int found = 0;
5806170056Srrs
5807170056Srrs					LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
5808170056Srrs						if (laddr->ifa == NULL) {
5809170056Srrs							SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
5810294174Stuexen							    __func__);
5811170056Srrs							continue;
5812170056Srrs						}
5813170056Srrs						if (laddr->ifa == ifa) {
5814170056Srrs							found = 1;
5815170056Srrs							break;
5816170056Srrs						}
5817170056Srrs					}
5818170056Srrs					if (!found) {
5819171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5820170056Srrs						error = EINVAL;
5821170056Srrs						goto out_of_it;
5822170056Srrs					}
5823267769Stuexen				} else {
5824283699Stuexen					switch (addr->sa_family) {
5825267769Stuexen#ifdef INET
5826267769Stuexen					case AF_INET:
5827267769Stuexen						{
5828267769Stuexen							struct sockaddr_in *sin;
5829267769Stuexen
5830283699Stuexen							sin = (struct sockaddr_in *)addr;
5831267769Stuexen							if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
5832267769Stuexen							    &sin->sin_addr) != 0) {
5833267769Stuexen								SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5834267769Stuexen								error = EINVAL;
5835267769Stuexen								goto out_of_it;
5836267769Stuexen							}
5837267769Stuexen							break;
5838267769Stuexen						}
5839267769Stuexen#endif
5840267769Stuexen#ifdef INET6
5841267769Stuexen					case AF_INET6:
5842267769Stuexen						{
5843267769Stuexen							struct sockaddr_in6 *sin6;
5844267769Stuexen
5845283699Stuexen							sin6 = (struct sockaddr_in6 *)addr;
5846267769Stuexen							if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
5847267769Stuexen							    &sin6->sin6_addr) != 0) {
5848267769Stuexen								SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5849267769Stuexen								error = EINVAL;
5850267769Stuexen								goto out_of_it;
5851267769Stuexen							}
5852267769Stuexen							break;
5853267769Stuexen						}
5854267769Stuexen#endif
5855267769Stuexen					default:
5856267769Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5857267769Stuexen						error = EINVAL;
5858267769Stuexen						goto out_of_it;
5859267769Stuexen					}
5860170056Srrs				}
5861283699Stuexen				if (sctp_set_primary_ip_address_sa(stcb, addr) != 0) {
5862171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5863170056Srrs					error = EINVAL;
5864170056Srrs				}
5865170056Srrs		out_of_it:
5866169208Srrs				SCTP_TCB_UNLOCK(stcb);
5867166675Srrs			} else {
5868171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5869163953Srrs				error = EINVAL;
5870163953Srrs			}
5871223132Stuexen			break;
5872163953Srrs		}
5873163953Srrs	case SCTP_BINDX_ADD_ADDR:
5874163953Srrs		{
5875163953Srrs			struct sctp_getaddresses *addrs;
5876171477Srrs			struct thread *td;
5877163953Srrs
5878171477Srrs			td = (struct thread *)p;
5879170606Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
5880170606Srrs			    optsize);
5881221249Stuexen#ifdef INET
5882171477Srrs			if (addrs->addr->sa_family == AF_INET) {
5883238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
5884171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5885171477Srrs					error = EINVAL;
5886171477Srrs					break;
5887171477Srrs				}
5888188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
5889188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5890185435Sbz					break;
5891171477Srrs				}
5892221249Stuexen			} else
5893221249Stuexen#endif
5894185435Sbz#ifdef INET6
5895221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
5896238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
5897171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5898171477Srrs					error = EINVAL;
5899171477Srrs					break;
5900171477Srrs				}
5901188590Srrs				if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
5902188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
5903188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5904185435Sbz					break;
5905185435Sbz				}
5906221249Stuexen			} else
5907185435Sbz#endif
5908221249Stuexen			{
5909185435Sbz				error = EAFNOSUPPORT;
5910185435Sbz				break;
5911171477Srrs			}
5912170606Srrs			sctp_bindx_add_address(so, inp, addrs->addr,
5913170606Srrs			    addrs->sget_assoc_id, vrf_id,
5914170606Srrs			    &error, p);
5915223132Stuexen			break;
5916163953Srrs		}
5917163953Srrs	case SCTP_BINDX_REM_ADDR:
5918163953Srrs		{
5919163953Srrs			struct sctp_getaddresses *addrs;
5920171477Srrs			struct thread *td;
5921163953Srrs
5922171477Srrs			td = (struct thread *)p;
5923185435Sbz
5924166675Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
5925221249Stuexen#ifdef INET
5926171477Srrs			if (addrs->addr->sa_family == AF_INET) {
5927238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
5928171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5929171477Srrs					error = EINVAL;
5930171477Srrs					break;
5931171477Srrs				}
5932188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
5933188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5934185435Sbz					break;
5935171477Srrs				}
5936221249Stuexen			} else
5937221249Stuexen#endif
5938185435Sbz#ifdef INET6
5939221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
5940238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
5941171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5942171477Srrs					error = EINVAL;
5943171477Srrs					break;
5944171477Srrs				}
5945224641Stuexen				if (td != NULL &&
5946224641Stuexen				    (error = prison_local_ip6(td->td_ucred,
5947224641Stuexen				    &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
5948188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
5949188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5950185435Sbz					break;
5951185435Sbz				}
5952221249Stuexen			} else
5953185435Sbz#endif
5954221249Stuexen			{
5955185435Sbz				error = EAFNOSUPPORT;
5956185435Sbz				break;
5957171477Srrs			}
5958228653Stuexen			sctp_bindx_delete_address(inp, addrs->addr,
5959170606Srrs			    addrs->sget_assoc_id, vrf_id,
5960170606Srrs			    &error);
5961223132Stuexen			break;
5962163953Srrs		}
5963223132Stuexen	case SCTP_EVENT:
5964223132Stuexen		{
5965223132Stuexen			struct sctp_event *event;
5966223132Stuexen			uint32_t event_type;
5967223132Stuexen
5968223132Stuexen			SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize);
5969223132Stuexen			SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
5970223132Stuexen			switch (event->se_type) {
5971223132Stuexen			case SCTP_ASSOC_CHANGE:
5972223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
5973223132Stuexen				break;
5974223132Stuexen			case SCTP_PEER_ADDR_CHANGE:
5975223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
5976223132Stuexen				break;
5977223132Stuexen			case SCTP_REMOTE_ERROR:
5978223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPEERERR;
5979223132Stuexen				break;
5980223132Stuexen			case SCTP_SEND_FAILED:
5981223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
5982223132Stuexen				break;
5983223132Stuexen			case SCTP_SHUTDOWN_EVENT:
5984223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
5985223132Stuexen				break;
5986223132Stuexen			case SCTP_ADAPTATION_INDICATION:
5987223132Stuexen				event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
5988223132Stuexen				break;
5989223132Stuexen			case SCTP_PARTIAL_DELIVERY_EVENT:
5990223132Stuexen				event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
5991223132Stuexen				break;
5992223132Stuexen			case SCTP_AUTHENTICATION_EVENT:
5993223132Stuexen				event_type = SCTP_PCB_FLAGS_AUTHEVNT;
5994223132Stuexen				break;
5995223132Stuexen			case SCTP_STREAM_RESET_EVENT:
5996223132Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
5997223132Stuexen				break;
5998223132Stuexen			case SCTP_SENDER_DRY_EVENT:
5999223132Stuexen				event_type = SCTP_PCB_FLAGS_DRYEVNT;
6000223132Stuexen				break;
6001223132Stuexen			case SCTP_NOTIFICATIONS_STOPPED_EVENT:
6002223132Stuexen				event_type = 0;
6003223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
6004223132Stuexen				error = ENOTSUP;
6005223132Stuexen				break;
6006235009Stuexen			case SCTP_ASSOC_RESET_EVENT:
6007235009Stuexen				event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
6008235009Stuexen				break;
6009235009Stuexen			case SCTP_STREAM_CHANGE_EVENT:
6010235009Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
6011235009Stuexen				break;
6012235075Stuexen			case SCTP_SEND_FAILED_EVENT:
6013235075Stuexen				event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
6014235075Stuexen				break;
6015223132Stuexen			default:
6016223132Stuexen				event_type = 0;
6017223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6018223132Stuexen				error = EINVAL;
6019223132Stuexen				break;
6020223132Stuexen			}
6021223132Stuexen			if (event_type > 0) {
6022223132Stuexen				if (stcb) {
6023223132Stuexen					if (event->se_on) {
6024223132Stuexen						sctp_stcb_feature_on(inp, stcb, event_type);
6025223132Stuexen						if (event_type == SCTP_PCB_FLAGS_DRYEVNT) {
6026223132Stuexen							if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
6027223132Stuexen							    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
6028223132Stuexen							    (stcb->asoc.stream_queue_cnt == 0)) {
6029223132Stuexen								sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
6030223132Stuexen							}
6031223132Stuexen						}
6032223132Stuexen					} else {
6033223132Stuexen						sctp_stcb_feature_off(inp, stcb, event_type);
6034223132Stuexen					}
6035223132Stuexen					SCTP_TCB_UNLOCK(stcb);
6036223132Stuexen				} else {
6037223132Stuexen					/*
6038223132Stuexen					 * We don't want to send up a storm
6039223132Stuexen					 * of events, so return an error for
6040223132Stuexen					 * sender dry events
6041223132Stuexen					 */
6042223132Stuexen					if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
6043224918Stuexen					    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) &&
6044224918Stuexen					    ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
6045223132Stuexen					    ((event->se_assoc_id == SCTP_ALL_ASSOC) ||
6046223132Stuexen					    (event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
6047223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
6048223132Stuexen						error = ENOTSUP;
6049223132Stuexen						break;
6050223132Stuexen					}
6051224918Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6052224918Stuexen					    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6053224918Stuexen					    (event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
6054223132Stuexen					    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
6055223132Stuexen						SCTP_INP_WLOCK(inp);
6056223132Stuexen						if (event->se_on) {
6057223132Stuexen							sctp_feature_on(inp, event_type);
6058223132Stuexen						} else {
6059223132Stuexen							sctp_feature_off(inp, event_type);
6060223132Stuexen						}
6061223132Stuexen						SCTP_INP_WUNLOCK(inp);
6062223132Stuexen					}
6063223132Stuexen					if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
6064223132Stuexen					    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
6065223132Stuexen						SCTP_INP_RLOCK(inp);
6066223132Stuexen						LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6067223132Stuexen							SCTP_TCB_LOCK(stcb);
6068223132Stuexen							if (event->se_on) {
6069223132Stuexen								sctp_stcb_feature_on(inp, stcb, event_type);
6070223132Stuexen							} else {
6071223132Stuexen								sctp_stcb_feature_off(inp, stcb, event_type);
6072223132Stuexen							}
6073223132Stuexen							SCTP_TCB_UNLOCK(stcb);
6074223132Stuexen						}
6075223132Stuexen						SCTP_INP_RUNLOCK(inp);
6076223132Stuexen					}
6077223132Stuexen				}
6078223132Stuexen			}
6079223132Stuexen			break;
6080223132Stuexen		}
6081223132Stuexen	case SCTP_RECVRCVINFO:
6082223132Stuexen		{
6083223132Stuexen			int *onoff;
6084223132Stuexen
6085223132Stuexen			SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
6086223132Stuexen			SCTP_INP_WLOCK(inp);
6087223132Stuexen			if (*onoff != 0) {
6088223132Stuexen				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
6089223132Stuexen			} else {
6090223132Stuexen				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
6091223132Stuexen			}
6092223132Stuexen			SCTP_INP_WUNLOCK(inp);
6093223132Stuexen			break;
6094223132Stuexen		}
6095223132Stuexen	case SCTP_RECVNXTINFO:
6096223132Stuexen		{
6097223132Stuexen			int *onoff;
6098223132Stuexen
6099223132Stuexen			SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
6100223132Stuexen			SCTP_INP_WLOCK(inp);
6101223132Stuexen			if (*onoff != 0) {
6102223132Stuexen				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
6103223132Stuexen			} else {
6104223132Stuexen				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
6105223132Stuexen			}
6106223132Stuexen			SCTP_INP_WUNLOCK(inp);
6107223132Stuexen			break;
6108223132Stuexen		}
6109223132Stuexen	case SCTP_DEFAULT_SNDINFO:
6110223132Stuexen		{
6111223132Stuexen			struct sctp_sndinfo *info;
6112223162Stuexen			uint16_t policy;
6113223132Stuexen
6114223132Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize);
6115223132Stuexen			SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
6116223132Stuexen
6117223132Stuexen			if (stcb) {
6118223132Stuexen				if (info->snd_sid < stcb->asoc.streamoutcnt) {
6119223132Stuexen					stcb->asoc.def_send.sinfo_stream = info->snd_sid;
6120223162Stuexen					policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
6121223132Stuexen					stcb->asoc.def_send.sinfo_flags = info->snd_flags;
6122223162Stuexen					stcb->asoc.def_send.sinfo_flags |= policy;
6123223132Stuexen					stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
6124223132Stuexen					stcb->asoc.def_send.sinfo_context = info->snd_context;
6125223132Stuexen				} else {
6126223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6127223132Stuexen					error = EINVAL;
6128223132Stuexen				}
6129223132Stuexen				SCTP_TCB_UNLOCK(stcb);
6130223132Stuexen			} else {
6131224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6132224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6133224918Stuexen				    (info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
6134223132Stuexen				    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
6135223132Stuexen					SCTP_INP_WLOCK(inp);
6136223132Stuexen					inp->def_send.sinfo_stream = info->snd_sid;
6137223162Stuexen					policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
6138223132Stuexen					inp->def_send.sinfo_flags = info->snd_flags;
6139223162Stuexen					inp->def_send.sinfo_flags |= policy;
6140223132Stuexen					inp->def_send.sinfo_ppid = info->snd_ppid;
6141223132Stuexen					inp->def_send.sinfo_context = info->snd_context;
6142223132Stuexen					SCTP_INP_WUNLOCK(inp);
6143223132Stuexen				}
6144223132Stuexen				if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
6145223132Stuexen				    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
6146223132Stuexen					SCTP_INP_RLOCK(inp);
6147223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6148223132Stuexen						SCTP_TCB_LOCK(stcb);
6149223132Stuexen						if (info->snd_sid < stcb->asoc.streamoutcnt) {
6150223132Stuexen							stcb->asoc.def_send.sinfo_stream = info->snd_sid;
6151223162Stuexen							policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
6152223132Stuexen							stcb->asoc.def_send.sinfo_flags = info->snd_flags;
6153223162Stuexen							stcb->asoc.def_send.sinfo_flags |= policy;
6154223132Stuexen							stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
6155223132Stuexen							stcb->asoc.def_send.sinfo_context = info->snd_context;
6156223132Stuexen						}
6157223132Stuexen						SCTP_TCB_UNLOCK(stcb);
6158223132Stuexen					}
6159223132Stuexen					SCTP_INP_RUNLOCK(inp);
6160223132Stuexen				}
6161223132Stuexen			}
6162223132Stuexen			break;
6163223132Stuexen		}
6164223162Stuexen	case SCTP_DEFAULT_PRINFO:
6165223162Stuexen		{
6166223162Stuexen			struct sctp_default_prinfo *info;
6167223162Stuexen
6168223162Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize);
6169223162Stuexen			SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
6170223162Stuexen
6171283706Stuexen			if (info->pr_policy > SCTP_PR_SCTP_MAX) {
6172223162Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6173223162Stuexen				error = EINVAL;
6174223162Stuexen				break;
6175223162Stuexen			}
6176223162Stuexen			if (stcb) {
6177223162Stuexen				stcb->asoc.def_send.sinfo_flags &= 0xfff0;
6178223162Stuexen				stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
6179224918Stuexen				stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
6180223162Stuexen				SCTP_TCB_UNLOCK(stcb);
6181223162Stuexen			} else {
6182224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6183224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6184224918Stuexen				    (info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
6185223162Stuexen				    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
6186223162Stuexen					SCTP_INP_WLOCK(inp);
6187223162Stuexen					inp->def_send.sinfo_flags &= 0xfff0;
6188223162Stuexen					inp->def_send.sinfo_flags |= info->pr_policy;
6189224918Stuexen					inp->def_send.sinfo_timetolive = info->pr_value;
6190223162Stuexen					SCTP_INP_WUNLOCK(inp);
6191223162Stuexen				}
6192223162Stuexen				if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
6193223162Stuexen				    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
6194223162Stuexen					SCTP_INP_RLOCK(inp);
6195223162Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6196223162Stuexen						SCTP_TCB_LOCK(stcb);
6197223162Stuexen						stcb->asoc.def_send.sinfo_flags &= 0xfff0;
6198223162Stuexen						stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
6199224918Stuexen						stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
6200223162Stuexen						SCTP_TCB_UNLOCK(stcb);
6201223162Stuexen					}
6202223162Stuexen					SCTP_INP_RUNLOCK(inp);
6203223162Stuexen				}
6204223162Stuexen			}
6205223162Stuexen			break;
6206223162Stuexen		}
6207224641Stuexen	case SCTP_PEER_ADDR_THLDS:
6208224641Stuexen		/* Applies to the specific association */
6209224641Stuexen		{
6210224641Stuexen			struct sctp_paddrthlds *thlds;
6211224641Stuexen			struct sctp_nets *net;
6212283699Stuexen			struct sockaddr *addr;
6213224641Stuexen
6214283699Stuexen#if defined(INET) && defined(INET6)
6215283699Stuexen			struct sockaddr_in sin_store;
6216283699Stuexen
6217283699Stuexen#endif
6218283699Stuexen
6219224641Stuexen			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
6220224641Stuexen			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
6221283699Stuexen
6222283699Stuexen#if defined(INET) && defined(INET6)
6223283699Stuexen			if (thlds->spt_address.ss_family == AF_INET6) {
6224283699Stuexen				struct sockaddr_in6 *sin6;
6225283699Stuexen
6226283699Stuexen				sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
6227283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6228283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
6229283699Stuexen					addr = (struct sockaddr *)&sin_store;
6230283699Stuexen				} else {
6231283699Stuexen					addr = (struct sockaddr *)&thlds->spt_address;
6232283699Stuexen				}
6233224641Stuexen			} else {
6234283699Stuexen				addr = (struct sockaddr *)&thlds->spt_address;
6235283699Stuexen			}
6236283699Stuexen#else
6237283699Stuexen			addr = (struct sockaddr *)&thlds->spt_address;
6238283699Stuexen#endif
6239283699Stuexen			if (stcb != NULL) {
6240283699Stuexen				net = sctp_findnet(stcb, addr);
6241283699Stuexen			} else {
6242224641Stuexen				/*
6243224641Stuexen				 * We increment here since
6244224641Stuexen				 * sctp_findassociation_ep_addr() wil do a
6245224641Stuexen				 * decrement if it finds the stcb as long as
6246224641Stuexen				 * the locked tcb (last argument) is NOT a
6247224641Stuexen				 * TCB.. aka NULL.
6248224641Stuexen				 */
6249283699Stuexen				net = NULL;
6250224641Stuexen				SCTP_INP_INCR_REF(inp);
6251283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr,
6252224641Stuexen				    &net, NULL, NULL);
6253224641Stuexen				if (stcb == NULL) {
6254224641Stuexen					SCTP_INP_DECR_REF(inp);
6255224641Stuexen				}
6256224641Stuexen			}
6257283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
6258224641Stuexen#ifdef INET
6259283699Stuexen				if (addr->sa_family == AF_INET) {
6260224641Stuexen
6261224641Stuexen					struct sockaddr_in *sin;
6262224641Stuexen
6263283699Stuexen					sin = (struct sockaddr_in *)addr;
6264283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
6265224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6266224641Stuexen						SCTP_TCB_UNLOCK(stcb);
6267224641Stuexen						error = EINVAL;
6268224641Stuexen						break;
6269224641Stuexen					}
6270224641Stuexen				} else
6271224641Stuexen#endif
6272224641Stuexen#ifdef INET6
6273283699Stuexen				if (addr->sa_family == AF_INET6) {
6274224641Stuexen					struct sockaddr_in6 *sin6;
6275224641Stuexen
6276283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
6277224641Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
6278224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6279224641Stuexen						SCTP_TCB_UNLOCK(stcb);
6280224641Stuexen						error = EINVAL;
6281224641Stuexen						break;
6282224641Stuexen					}
6283224641Stuexen				} else
6284224641Stuexen#endif
6285224641Stuexen				{
6286224641Stuexen					error = EAFNOSUPPORT;
6287224641Stuexen					SCTP_TCB_UNLOCK(stcb);
6288224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6289224641Stuexen					break;
6290224641Stuexen				}
6291224641Stuexen			}
6292283699Stuexen			if (stcb != NULL) {
6293283699Stuexen				if (net != NULL) {
6294283727Stuexen					net->failure_threshold = thlds->spt_pathmaxrxt;
6295283727Stuexen					net->pf_threshold = thlds->spt_pathpfthld;
6296224641Stuexen					if (net->dest_state & SCTP_ADDR_PF) {
6297283727Stuexen						if ((net->error_count > net->failure_threshold) ||
6298283727Stuexen						    (net->error_count <= net->pf_threshold)) {
6299224641Stuexen							net->dest_state &= ~SCTP_ADDR_PF;
6300224641Stuexen						}
6301224641Stuexen					} else {
6302283727Stuexen						if ((net->error_count > net->pf_threshold) &&
6303283727Stuexen						    (net->error_count <= net->failure_threshold)) {
6304224641Stuexen							net->dest_state |= SCTP_ADDR_PF;
6305224641Stuexen							sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
6306283822Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
6307283822Stuexen							    stcb->sctp_ep, stcb, net,
6308283822Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_17);
6309224641Stuexen							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
6310224641Stuexen						}
6311224641Stuexen					}
6312224641Stuexen					if (net->dest_state & SCTP_ADDR_REACHABLE) {
6313283727Stuexen						if (net->error_count > net->failure_threshold) {
6314224641Stuexen							net->dest_state &= ~SCTP_ADDR_REACHABLE;
6315235414Stuexen							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
6316224641Stuexen						}
6317224641Stuexen					} else {
6318283727Stuexen						if (net->error_count <= net->failure_threshold) {
6319224641Stuexen							net->dest_state |= SCTP_ADDR_REACHABLE;
6320235414Stuexen							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
6321224641Stuexen						}
6322224641Stuexen					}
6323224641Stuexen				} else {
6324224641Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6325283727Stuexen						net->failure_threshold = thlds->spt_pathmaxrxt;
6326283727Stuexen						net->pf_threshold = thlds->spt_pathpfthld;
6327224641Stuexen						if (net->dest_state & SCTP_ADDR_PF) {
6328283727Stuexen							if ((net->error_count > net->failure_threshold) ||
6329283727Stuexen							    (net->error_count <= net->pf_threshold)) {
6330224641Stuexen								net->dest_state &= ~SCTP_ADDR_PF;
6331224641Stuexen							}
6332224641Stuexen						} else {
6333283727Stuexen							if ((net->error_count > net->pf_threshold) &&
6334283727Stuexen							    (net->error_count <= net->failure_threshold)) {
6335224641Stuexen								net->dest_state |= SCTP_ADDR_PF;
6336224641Stuexen								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
6337283822Stuexen								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
6338283822Stuexen								    stcb->sctp_ep, stcb, net,
6339283822Stuexen								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_18);
6340224641Stuexen								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
6341224641Stuexen							}
6342224641Stuexen						}
6343224641Stuexen						if (net->dest_state & SCTP_ADDR_REACHABLE) {
6344283727Stuexen							if (net->error_count > net->failure_threshold) {
6345224641Stuexen								net->dest_state &= ~SCTP_ADDR_REACHABLE;
6346235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
6347224641Stuexen							}
6348224641Stuexen						} else {
6349283727Stuexen							if (net->error_count <= net->failure_threshold) {
6350224641Stuexen								net->dest_state |= SCTP_ADDR_REACHABLE;
6351235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
6352224641Stuexen							}
6353224641Stuexen						}
6354224641Stuexen					}
6355224641Stuexen					stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
6356224641Stuexen					stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
6357224641Stuexen				}
6358283725Stuexen				SCTP_TCB_UNLOCK(stcb);
6359224641Stuexen			} else {
6360224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6361224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6362224918Stuexen				    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
6363224641Stuexen					SCTP_INP_WLOCK(inp);
6364224641Stuexen					inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
6365224641Stuexen					inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
6366224641Stuexen					SCTP_INP_WUNLOCK(inp);
6367224641Stuexen				} else {
6368224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6369224641Stuexen					error = EINVAL;
6370224641Stuexen				}
6371224641Stuexen			}
6372224641Stuexen			break;
6373224641Stuexen		}
6374227755Stuexen	case SCTP_REMOTE_UDP_ENCAPS_PORT:
6375227755Stuexen		{
6376227755Stuexen			struct sctp_udpencaps *encaps;
6377227755Stuexen			struct sctp_nets *net;
6378283699Stuexen			struct sockaddr *addr;
6379227755Stuexen
6380283699Stuexen#if defined(INET) && defined(INET6)
6381283699Stuexen			struct sockaddr_in sin_store;
6382283699Stuexen
6383283699Stuexen#endif
6384283699Stuexen
6385227755Stuexen			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize);
6386227755Stuexen			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
6387283699Stuexen
6388283699Stuexen#if defined(INET) && defined(INET6)
6389283699Stuexen			if (encaps->sue_address.ss_family == AF_INET6) {
6390283699Stuexen				struct sockaddr_in6 *sin6;
6391283699Stuexen
6392283699Stuexen				sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
6393283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6394283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
6395283699Stuexen					addr = (struct sockaddr *)&sin_store;
6396283699Stuexen				} else {
6397283699Stuexen					addr = (struct sockaddr *)&encaps->sue_address;
6398283699Stuexen				}
6399227755Stuexen			} else {
6400283699Stuexen				addr = (struct sockaddr *)&encaps->sue_address;
6401283699Stuexen			}
6402283699Stuexen#else
6403283699Stuexen			addr = (struct sockaddr *)&encaps->sue_address;
6404283699Stuexen#endif
6405283699Stuexen			if (stcb != NULL) {
6406283699Stuexen				net = sctp_findnet(stcb, addr);
6407283699Stuexen			} else {
6408227755Stuexen				/*
6409227755Stuexen				 * We increment here since
6410227755Stuexen				 * sctp_findassociation_ep_addr() wil do a
6411227755Stuexen				 * decrement if it finds the stcb as long as
6412227755Stuexen				 * the locked tcb (last argument) is NOT a
6413227755Stuexen				 * TCB.. aka NULL.
6414227755Stuexen				 */
6415227755Stuexen				net = NULL;
6416227755Stuexen				SCTP_INP_INCR_REF(inp);
6417283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
6418227755Stuexen				if (stcb == NULL) {
6419227755Stuexen					SCTP_INP_DECR_REF(inp);
6420227755Stuexen				}
6421227755Stuexen			}
6422283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
6423227755Stuexen#ifdef INET
6424283699Stuexen				if (addr->sa_family == AF_INET) {
6425227755Stuexen
6426227755Stuexen					struct sockaddr_in *sin;
6427227755Stuexen
6428283699Stuexen					sin = (struct sockaddr_in *)addr;
6429283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
6430227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6431227755Stuexen						SCTP_TCB_UNLOCK(stcb);
6432227755Stuexen						error = EINVAL;
6433227755Stuexen						break;
6434227755Stuexen					}
6435227755Stuexen				} else
6436227755Stuexen#endif
6437227755Stuexen#ifdef INET6
6438283699Stuexen				if (addr->sa_family == AF_INET6) {
6439227755Stuexen					struct sockaddr_in6 *sin6;
6440227755Stuexen
6441283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
6442227755Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
6443227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6444227755Stuexen						SCTP_TCB_UNLOCK(stcb);
6445227755Stuexen						error = EINVAL;
6446227755Stuexen						break;
6447227755Stuexen					}
6448227755Stuexen				} else
6449227755Stuexen#endif
6450227755Stuexen				{
6451227755Stuexen					error = EAFNOSUPPORT;
6452227755Stuexen					SCTP_TCB_UNLOCK(stcb);
6453227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6454227755Stuexen					break;
6455227755Stuexen				}
6456227755Stuexen			}
6457283699Stuexen			if (stcb != NULL) {
6458283699Stuexen				if (net != NULL) {
6459227755Stuexen					net->port = encaps->sue_port;
6460227755Stuexen				} else {
6461227755Stuexen					stcb->asoc.port = encaps->sue_port;
6462227755Stuexen				}
6463227755Stuexen				SCTP_TCB_UNLOCK(stcb);
6464227755Stuexen			} else {
6465227755Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6466227755Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6467227755Stuexen				    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
6468227755Stuexen					SCTP_INP_WLOCK(inp);
6469227755Stuexen					inp->sctp_ep.port = encaps->sue_port;
6470227755Stuexen					SCTP_INP_WUNLOCK(inp);
6471227755Stuexen				} else {
6472227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6473227755Stuexen					error = EINVAL;
6474227755Stuexen				}
6475227755Stuexen			}
6476227755Stuexen			break;
6477227755Stuexen		}
6478270356Stuexen	case SCTP_ECN_SUPPORTED:
6479270356Stuexen		{
6480270356Stuexen			struct sctp_assoc_value *av;
6481270356Stuexen
6482270356Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6483270356Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6484270356Stuexen
6485270356Stuexen			if (stcb) {
6486270356Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6487270356Stuexen				error = EINVAL;
6488270356Stuexen				SCTP_TCB_UNLOCK(stcb);
6489270356Stuexen			} else {
6490270356Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6491270356Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6492270356Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6493270356Stuexen					SCTP_INP_WLOCK(inp);
6494270356Stuexen					if (av->assoc_value == 0) {
6495270356Stuexen						inp->ecn_supported = 0;
6496270356Stuexen					} else {
6497270356Stuexen						inp->ecn_supported = 1;
6498270356Stuexen					}
6499270356Stuexen					SCTP_INP_WUNLOCK(inp);
6500270356Stuexen				} else {
6501270356Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6502270356Stuexen					error = EINVAL;
6503270356Stuexen				}
6504270356Stuexen			}
6505270356Stuexen			break;
6506270356Stuexen		}
6507270357Stuexen	case SCTP_PR_SUPPORTED:
6508270357Stuexen		{
6509270357Stuexen			struct sctp_assoc_value *av;
6510270357Stuexen
6511270357Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6512270357Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6513270357Stuexen
6514270357Stuexen			if (stcb) {
6515270357Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6516270357Stuexen				error = EINVAL;
6517270357Stuexen				SCTP_TCB_UNLOCK(stcb);
6518270357Stuexen			} else {
6519270357Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6520270357Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6521270357Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6522270357Stuexen					SCTP_INP_WLOCK(inp);
6523270357Stuexen					if (av->assoc_value == 0) {
6524270357Stuexen						inp->prsctp_supported = 0;
6525270357Stuexen					} else {
6526270357Stuexen						inp->prsctp_supported = 1;
6527270357Stuexen					}
6528270357Stuexen					SCTP_INP_WUNLOCK(inp);
6529270357Stuexen				} else {
6530270357Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6531270357Stuexen					error = EINVAL;
6532270357Stuexen				}
6533270357Stuexen			}
6534270357Stuexen			break;
6535270357Stuexen		}
6536270362Stuexen	case SCTP_AUTH_SUPPORTED:
6537270362Stuexen		{
6538270362Stuexen			struct sctp_assoc_value *av;
6539270362Stuexen
6540270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6541270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6542270362Stuexen
6543270362Stuexen			if (stcb) {
6544270362Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6545270362Stuexen				error = EINVAL;
6546270362Stuexen				SCTP_TCB_UNLOCK(stcb);
6547270362Stuexen			} else {
6548270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6549270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6550270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6551270362Stuexen					if ((av->assoc_value == 0) &&
6552270362Stuexen					    (inp->asconf_supported == 1)) {
6553270362Stuexen						/*
6554270362Stuexen						 * AUTH is required for
6555270362Stuexen						 * ASCONF
6556270362Stuexen						 */
6557270362Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6558270362Stuexen						error = EINVAL;
6559270362Stuexen					} else {
6560270362Stuexen						SCTP_INP_WLOCK(inp);
6561270362Stuexen						if (av->assoc_value == 0) {
6562270362Stuexen							inp->auth_supported = 0;
6563270362Stuexen						} else {
6564270362Stuexen							inp->auth_supported = 1;
6565270362Stuexen						}
6566270362Stuexen						SCTP_INP_WUNLOCK(inp);
6567270362Stuexen					}
6568270362Stuexen				} else {
6569270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6570270362Stuexen					error = EINVAL;
6571270362Stuexen				}
6572270362Stuexen			}
6573270362Stuexen			break;
6574270362Stuexen		}
6575270362Stuexen	case SCTP_ASCONF_SUPPORTED:
6576270362Stuexen		{
6577270362Stuexen			struct sctp_assoc_value *av;
6578270362Stuexen
6579270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6580270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6581270362Stuexen
6582270362Stuexen			if (stcb) {
6583270362Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6584270362Stuexen				error = EINVAL;
6585270362Stuexen				SCTP_TCB_UNLOCK(stcb);
6586270362Stuexen			} else {
6587270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6588270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6589270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6590270362Stuexen					if ((av->assoc_value != 0) &&
6591270362Stuexen					    (inp->auth_supported == 0)) {
6592270362Stuexen						/*
6593270362Stuexen						 * AUTH is required for
6594270362Stuexen						 * ASCONF
6595270362Stuexen						 */
6596270362Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6597270362Stuexen						error = EINVAL;
6598270362Stuexen					} else {
6599270362Stuexen						SCTP_INP_WLOCK(inp);
6600270362Stuexen						if (av->assoc_value == 0) {
6601270362Stuexen							inp->asconf_supported = 0;
6602270362Stuexen							sctp_auth_delete_chunk(SCTP_ASCONF,
6603270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6604270362Stuexen							sctp_auth_delete_chunk(SCTP_ASCONF_ACK,
6605270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6606270362Stuexen						} else {
6607270362Stuexen							inp->asconf_supported = 1;
6608270362Stuexen							sctp_auth_add_chunk(SCTP_ASCONF,
6609270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6610270362Stuexen							sctp_auth_add_chunk(SCTP_ASCONF_ACK,
6611270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6612270362Stuexen						}
6613270362Stuexen						SCTP_INP_WUNLOCK(inp);
6614270362Stuexen					}
6615270362Stuexen				} else {
6616270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6617270362Stuexen					error = EINVAL;
6618270362Stuexen				}
6619270362Stuexen			}
6620270362Stuexen			break;
6621270362Stuexen		}
6622270361Stuexen	case SCTP_RECONFIG_SUPPORTED:
6623270361Stuexen		{
6624270361Stuexen			struct sctp_assoc_value *av;
6625270361Stuexen
6626270361Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6627270361Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6628270361Stuexen
6629270361Stuexen			if (stcb) {
6630270361Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6631270361Stuexen				error = EINVAL;
6632270361Stuexen				SCTP_TCB_UNLOCK(stcb);
6633270361Stuexen			} else {
6634270361Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6635270361Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6636270361Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6637270361Stuexen					SCTP_INP_WLOCK(inp);
6638270361Stuexen					if (av->assoc_value == 0) {
6639270361Stuexen						inp->reconfig_supported = 0;
6640270361Stuexen					} else {
6641270361Stuexen						inp->reconfig_supported = 1;
6642270361Stuexen					}
6643270361Stuexen					SCTP_INP_WUNLOCK(inp);
6644270361Stuexen				} else {
6645270361Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6646270361Stuexen					error = EINVAL;
6647270361Stuexen				}
6648270361Stuexen			}
6649270361Stuexen			break;
6650270361Stuexen		}
6651270359Stuexen	case SCTP_NRSACK_SUPPORTED:
6652270359Stuexen		{
6653270359Stuexen			struct sctp_assoc_value *av;
6654270359Stuexen
6655270359Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6656270359Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6657270359Stuexen
6658270359Stuexen			if (stcb) {
6659270359Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6660270359Stuexen				error = EINVAL;
6661270359Stuexen				SCTP_TCB_UNLOCK(stcb);
6662270359Stuexen			} else {
6663270359Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6664270359Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6665270359Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6666270359Stuexen					SCTP_INP_WLOCK(inp);
6667270359Stuexen					if (av->assoc_value == 0) {
6668270359Stuexen						inp->nrsack_supported = 0;
6669270359Stuexen					} else {
6670270359Stuexen						inp->nrsack_supported = 1;
6671270359Stuexen					}
6672270359Stuexen					SCTP_INP_WUNLOCK(inp);
6673270359Stuexen				} else {
6674270359Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6675270359Stuexen					error = EINVAL;
6676270359Stuexen				}
6677270359Stuexen			}
6678270359Stuexen			break;
6679270359Stuexen		}
6680270360Stuexen	case SCTP_PKTDROP_SUPPORTED:
6681270360Stuexen		{
6682270360Stuexen			struct sctp_assoc_value *av;
6683270360Stuexen
6684270360Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6685270360Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6686270360Stuexen
6687270360Stuexen			if (stcb) {
6688270360Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6689270360Stuexen				error = EINVAL;
6690270360Stuexen				SCTP_TCB_UNLOCK(stcb);
6691270360Stuexen			} else {
6692270360Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6693270360Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6694270360Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6695270360Stuexen					SCTP_INP_WLOCK(inp);
6696270360Stuexen					if (av->assoc_value == 0) {
6697270360Stuexen						inp->pktdrop_supported = 0;
6698270360Stuexen					} else {
6699270360Stuexen						inp->pktdrop_supported = 1;
6700270360Stuexen					}
6701270360Stuexen					SCTP_INP_WUNLOCK(inp);
6702270360Stuexen				} else {
6703270360Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6704270360Stuexen					error = EINVAL;
6705270360Stuexen				}
6706270360Stuexen			}
6707270360Stuexen			break;
6708270360Stuexen		}
6709283724Stuexen	case SCTP_MAX_CWND:
6710283724Stuexen		{
6711283724Stuexen			struct sctp_assoc_value *av;
6712283724Stuexen			struct sctp_nets *net;
6713283724Stuexen
6714283724Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6715283724Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6716283724Stuexen
6717283724Stuexen			if (stcb) {
6718283724Stuexen				stcb->asoc.max_cwnd = av->assoc_value;
6719283724Stuexen				if (stcb->asoc.max_cwnd > 0) {
6720283724Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6721283724Stuexen						if ((net->cwnd > stcb->asoc.max_cwnd) &&
6722283724Stuexen						    (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
6723283724Stuexen							net->cwnd = stcb->asoc.max_cwnd;
6724283724Stuexen							if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
6725283724Stuexen								net->cwnd = net->mtu - sizeof(struct sctphdr);
6726283724Stuexen							}
6727283724Stuexen						}
6728283724Stuexen					}
6729283724Stuexen				}
6730283724Stuexen				SCTP_TCB_UNLOCK(stcb);
6731283724Stuexen			} else {
6732283724Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6733283724Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6734283724Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6735283724Stuexen					SCTP_INP_WLOCK(inp);
6736283724Stuexen					inp->max_cwnd = av->assoc_value;
6737283724Stuexen					SCTP_INP_WUNLOCK(inp);
6738283724Stuexen				} else {
6739283724Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6740283724Stuexen					error = EINVAL;
6741283724Stuexen				}
6742283724Stuexen			}
6743283724Stuexen			break;
6744283724Stuexen		}
6745163953Srrs	default:
6746171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
6747163953Srrs		error = ENOPROTOOPT;
6748163953Srrs		break;
6749163953Srrs	}			/* end switch (opt) */
6750163953Srrs	return (error);
6751163953Srrs}
6752163953Srrs
6753163953Srrsint
6754163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt)
6755163953Srrs{
6756166675Srrs	void *optval = NULL;
6757166675Srrs	size_t optsize = 0;
6758166675Srrs	void *p;
6759166675Srrs	int error = 0;
6760284633Stuexen	struct sctp_inpcb *inp;
6761163953Srrs
6762284633Stuexen	if ((sopt->sopt_level == SOL_SOCKET) &&
6763284633Stuexen	    (sopt->sopt_name == SO_SETFIB)) {
6764284633Stuexen		inp = (struct sctp_inpcb *)so->so_pcb;
6765284633Stuexen		if (inp == NULL) {
6766284633Stuexen			SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
6767284633Stuexen			return (EINVAL);
6768284633Stuexen		}
6769284633Stuexen		SCTP_INP_WLOCK(inp);
6770284633Stuexen		inp->fibnum = so->so_fibnum;
6771284633Stuexen		SCTP_INP_WUNLOCK(inp);
6772284633Stuexen		return (0);
6773284633Stuexen	}
6774163953Srrs	if (sopt->sopt_level != IPPROTO_SCTP) {
6775163953Srrs		/* wrong proto level... send back up to IP */
6776163953Srrs#ifdef INET6
6777163953Srrs		if (INP_CHECK_SOCKAF(so, AF_INET6))
6778163953Srrs			error = ip6_ctloutput(so, sopt);
6779221249Stuexen#endif				/* INET6 */
6780237565Stuexen#if defined(INET) && defined(INET6)
6781163953Srrs		else
6782221249Stuexen#endif
6783221249Stuexen#ifdef INET
6784163953Srrs			error = ip_ctloutput(so, sopt);
6785221249Stuexen#endif
6786163953Srrs		return (error);
6787163953Srrs	}
6788166675Srrs	optsize = sopt->sopt_valsize;
6789166675Srrs	if (optsize) {
6790170091Srrs		SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
6791166675Srrs		if (optval == NULL) {
6792235091Stuexen			SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
6793163953Srrs			return (ENOBUFS);
6794163953Srrs		}
6795166675Srrs		error = sooptcopyin(sopt, optval, optsize, optsize);
6796163953Srrs		if (error) {
6797170091Srrs			SCTP_FREE(optval, SCTP_M_SOCKOPT);
6798163953Srrs			goto out;
6799163953Srrs		}
6800163953Srrs	}
6801166675Srrs	p = (void *)sopt->sopt_td;
6802163953Srrs	if (sopt->sopt_dir == SOPT_SET) {
6803166675Srrs		error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
6804163953Srrs	} else if (sopt->sopt_dir == SOPT_GET) {
6805166675Srrs		error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
6806163953Srrs	} else {
6807235091Stuexen		SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6808163953Srrs		error = EINVAL;
6809163953Srrs	}
6810166675Srrs	if ((error == 0) && (optval != NULL)) {
6811166675Srrs		error = sooptcopyout(sopt, optval, optsize);
6812170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
6813166675Srrs	} else if (optval != NULL) {
6814170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
6815163953Srrs	}
6816163953Srrsout:
6817163953Srrs	return (error);
6818163953Srrs}
6819163953Srrs
6820221249Stuexen#ifdef INET
6821163953Srrsstatic int
6822163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
6823163953Srrs{
6824163953Srrs	int error = 0;
6825163953Srrs	int create_lock_on = 0;
6826167598Srrs	uint32_t vrf_id;
6827163953Srrs	struct sctp_inpcb *inp;
6828163953Srrs	struct sctp_tcb *stcb = NULL;
6829163953Srrs
6830163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6831233005Stuexen	if (inp == NULL) {
6832163953Srrs		/* I made the same as TCP since we are not setup? */
6833171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6834163953Srrs		return (ECONNRESET);
6835163953Srrs	}
6836171943Srrs	if (addr == NULL) {
6837171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6838170056Srrs		return EINVAL;
6839171943Srrs	}
6840221249Stuexen	switch (addr->sa_family) {
6841185435Sbz#ifdef INET6
6842221249Stuexen	case AF_INET6:
6843221249Stuexen		{
6844221249Stuexen			struct sockaddr_in6 *sin6p;
6845185694Srrs
6846221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
6847221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6848221249Stuexen				return (EINVAL);
6849221249Stuexen			}
6850221249Stuexen			sin6p = (struct sockaddr_in6 *)addr;
6851221249Stuexen			if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
6852221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6853221249Stuexen				return (error);
6854221249Stuexen			}
6855221249Stuexen			break;
6856185435Sbz		}
6857185435Sbz#endif
6858221249Stuexen#ifdef INET
6859221249Stuexen	case AF_INET:
6860221249Stuexen		{
6861221249Stuexen			struct sockaddr_in *sinp;
6862185694Srrs
6863221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
6864221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6865221249Stuexen				return (EINVAL);
6866221249Stuexen			}
6867221249Stuexen			sinp = (struct sockaddr_in *)addr;
6868221249Stuexen			if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) {
6869221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6870221249Stuexen				return (error);
6871221249Stuexen			}
6872221249Stuexen			break;
6873185435Sbz		}
6874221249Stuexen#endif
6875221249Stuexen	default:
6876185435Sbz		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
6877185435Sbz		return (EAFNOSUPPORT);
6878170056Srrs	}
6879178202Srrs	SCTP_INP_INCR_REF(inp);
6880163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
6881163953Srrs	create_lock_on = 1;
6882163953Srrs
6883178202Srrs
6884163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
6885163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
6886163953Srrs		/* Should I really unlock ? */
6887171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
6888163953Srrs		error = EFAULT;
6889163953Srrs		goto out_now;
6890163953Srrs	}
6891163953Srrs#ifdef INET6
6892163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
6893163953Srrs	    (addr->sa_family == AF_INET6)) {
6894171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6895163953Srrs		error = EINVAL;
6896163953Srrs		goto out_now;
6897163953Srrs	}
6898246595Stuexen#endif
6899163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
6900163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
6901163953Srrs		/* Bind a ephemeral port */
6902171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
6903163953Srrs		if (error) {
6904163953Srrs			goto out_now;
6905163953Srrs		}
6906163953Srrs	}
6907163953Srrs	/* Now do we connect? */
6908181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
6909181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
6910171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6911163953Srrs		error = EINVAL;
6912163953Srrs		goto out_now;
6913163953Srrs	}
6914163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
6915163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
6916163953Srrs		/* We are already connected AND the TCP model */
6917171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
6918163953Srrs		error = EADDRINUSE;
6919163953Srrs		goto out_now;
6920163953Srrs	}
6921163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
6922163953Srrs		SCTP_INP_RLOCK(inp);
6923163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
6924163953Srrs		SCTP_INP_RUNLOCK(inp);
6925163953Srrs	} else {
6926163953Srrs		/*
6927166675Srrs		 * We increment here since sctp_findassociation_ep_addr()
6928181054Srrs		 * will do a decrement if it finds the stcb as long as the
6929166675Srrs		 * locked tcb (last argument) is NOT a TCB.. aka NULL.
6930163953Srrs		 */
6931163953Srrs		SCTP_INP_INCR_REF(inp);
6932163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
6933163953Srrs		if (stcb == NULL) {
6934163953Srrs			SCTP_INP_DECR_REF(inp);
6935168299Srrs		} else {
6936178202Srrs			SCTP_TCB_UNLOCK(stcb);
6937163953Srrs		}
6938163953Srrs	}
6939163953Srrs	if (stcb != NULL) {
6940163953Srrs		/* Already have or am bring up an association */
6941171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
6942163953Srrs		error = EALREADY;
6943163953Srrs		goto out_now;
6944163953Srrs	}
6945168299Srrs	vrf_id = inp->def_vrf_id;
6946163953Srrs	/* We are GOOD to go */
6947294215Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, p);
6948163953Srrs	if (stcb == NULL) {
6949163953Srrs		/* Gak! no memory */
6950167598Srrs		goto out_now;
6951163953Srrs	}
6952163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
6953163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
6954163953Srrs		/* Set the connected flag so we can queue data */
6955163953Srrs		soisconnecting(so);
6956163953Srrs	}
6957171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
6958169378Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
6959163953Srrs
6960163953Srrs	/* initialize authentication parameters for the assoc */
6961163953Srrs	sctp_initialize_auth_params(inp, stcb);
6962163953Srrs
6963172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
6964168299Srrs	SCTP_TCB_UNLOCK(stcb);
6965163953Srrsout_now:
6966169420Srrs	if (create_lock_on) {
6967163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
6968169420Srrs	}
6969163953Srrs	SCTP_INP_DECR_REF(inp);
6970228907Stuexen	return (error);
6971163953Srrs}
6972163953Srrs
6973221249Stuexen#endif
6974221249Stuexen
6975163953Srrsint
6976163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p)
6977163953Srrs{
6978163953Srrs	/*
6979163953Srrs	 * Note this module depends on the protocol processing being called
6980163953Srrs	 * AFTER any socket level flags and backlog are applied to the
6981163953Srrs	 * socket. The traditional way that the socket flags are applied is
6982163953Srrs	 * AFTER protocol processing. We have made a change to the
6983163953Srrs	 * sys/kern/uipc_socket.c module to reverse this but this MUST be in
6984163953Srrs	 * place if the socket API for SCTP is to work properly.
6985163953Srrs	 */
6986163953Srrs
6987163953Srrs	int error = 0;
6988163953Srrs	struct sctp_inpcb *inp;
6989163953Srrs
6990163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6991233005Stuexen	if (inp == NULL) {
6992163953Srrs		/* I made the same as TCP since we are not setup? */
6993171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6994163953Srrs		return (ECONNRESET);
6995163953Srrs	}
6996181054Srrs	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
6997181054Srrs		/* See if we have a listener */
6998181054Srrs		struct sctp_inpcb *tinp;
6999267771Stuexen		union sctp_sockstore store;
7000181054Srrs
7001181054Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
7002181054Srrs			/* not bound all */
7003181054Srrs			struct sctp_laddr *laddr;
7004181054Srrs
7005181054Srrs			LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
7006181054Srrs				memcpy(&store, &laddr->ifa->address, sizeof(store));
7007267771Stuexen				switch (store.sa.sa_family) {
7008221249Stuexen#ifdef INET
7009221249Stuexen				case AF_INET:
7010267771Stuexen					store.sin.sin_port = inp->sctp_lport;
7011221249Stuexen					break;
7012221249Stuexen#endif
7013221249Stuexen#ifdef INET6
7014221249Stuexen				case AF_INET6:
7015267771Stuexen					store.sin6.sin6_port = inp->sctp_lport;
7016221249Stuexen					break;
7017221249Stuexen#endif
7018221249Stuexen				default:
7019221249Stuexen					break;
7020221249Stuexen				}
7021267771Stuexen				tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
7022181054Srrs				if (tinp && (tinp != inp) &&
7023181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
7024181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
7025181054Srrs				    (tinp->sctp_socket->so_qlimit)) {
7026181054Srrs					/*
7027181054Srrs					 * we have a listener already and
7028181054Srrs					 * its not this inp.
7029181054Srrs					 */
7030181054Srrs					SCTP_INP_DECR_REF(tinp);
7031181054Srrs					return (EADDRINUSE);
7032181054Srrs				} else if (tinp) {
7033181054Srrs					SCTP_INP_DECR_REF(tinp);
7034181054Srrs				}
7035181054Srrs			}
7036181054Srrs		} else {
7037181054Srrs			/* Setup a local addr bound all */
7038181054Srrs			memset(&store, 0, sizeof(store));
7039267771Stuexen#ifdef INET6
7040267771Stuexen			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
7041267771Stuexen				store.sa.sa_family = AF_INET6;
7042267771Stuexen				store.sa.sa_len = sizeof(struct sockaddr_in6);
7043267771Stuexen			}
7044267771Stuexen#endif
7045221249Stuexen#ifdef INET
7046267771Stuexen			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
7047267771Stuexen				store.sa.sa_family = AF_INET;
7048267771Stuexen				store.sa.sa_len = sizeof(struct sockaddr_in);
7049267771Stuexen			}
7050267771Stuexen#endif
7051267771Stuexen			switch (store.sa.sa_family) {
7052267771Stuexen#ifdef INET
7053221249Stuexen			case AF_INET:
7054221249Stuexen				store.sin.sin_port = inp->sctp_lport;
7055221249Stuexen				break;
7056221249Stuexen#endif
7057181054Srrs#ifdef INET6
7058221249Stuexen			case AF_INET6:
7059267771Stuexen				store.sin6.sin6_port = inp->sctp_lport;
7060221249Stuexen				break;
7061221249Stuexen#endif
7062221249Stuexen			default:
7063221249Stuexen				break;
7064221249Stuexen			}
7065267771Stuexen			tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
7066181054Srrs			if (tinp && (tinp != inp) &&
7067181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
7068181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
7069181054Srrs			    (tinp->sctp_socket->so_qlimit)) {
7070181054Srrs				/*
7071181054Srrs				 * we have a listener already and its not
7072181054Srrs				 * this inp.
7073181054Srrs				 */
7074181054Srrs				SCTP_INP_DECR_REF(tinp);
7075181054Srrs				return (EADDRINUSE);
7076181054Srrs			} else if (tinp) {
7077283733Stuexen				SCTP_INP_DECR_REF(tinp);
7078181054Srrs			}
7079181054Srrs		}
7080181054Srrs	}
7081163953Srrs	SCTP_INP_RLOCK(inp);
7082163953Srrs#ifdef SCTP_LOCK_LOGGING
7083179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
7084170744Srrs		sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
7085170744Srrs	}
7086163953Srrs#endif
7087163953Srrs	SOCK_LOCK(so);
7088163953Srrs	error = solisten_proto_check(so);
7089283732Stuexen	SOCK_UNLOCK(so);
7090163953Srrs	if (error) {
7091169208Srrs		SCTP_INP_RUNLOCK(inp);
7092163953Srrs		return (error);
7093163953Srrs	}
7094181054Srrs	if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
7095181054Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
7096181054Srrs		/*
7097181054Srrs		 * The unlucky case - We are in the tcp pool with this guy.
7098181054Srrs		 * - Someone else is in the main inp slot. - We must move
7099181054Srrs		 * this guy (the listener) to the main slot - We must then
7100181054Srrs		 * move the guy that was listener to the TCP Pool.
7101181054Srrs		 */
7102181054Srrs		if (sctp_swap_inpcb_for_listen(inp)) {
7103283732Stuexen			SCTP_INP_RUNLOCK(inp);
7104283732Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
7105283732Stuexen			return (EADDRINUSE);
7106181054Srrs		}
7107181054Srrs	}
7108163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
7109163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
7110163953Srrs		/* We are already connected AND the TCP model */
7111163953Srrs		SCTP_INP_RUNLOCK(inp);
7112171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
7113163953Srrs		return (EADDRINUSE);
7114163953Srrs	}
7115181054Srrs	SCTP_INP_RUNLOCK(inp);
7116163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
7117163953Srrs		/* We must do a bind. */
7118171572Srrs		if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
7119163953Srrs			/* bind error, probably perm */
7120163953Srrs			return (error);
7121163953Srrs		}
7122163953Srrs	}
7123283732Stuexen	SOCK_LOCK(so);
7124163953Srrs	/* It appears for 7.0 and on, we must always call this. */
7125163953Srrs	solisten_proto(so, backlog);
7126163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
7127163953Srrs		/* remove the ACCEPTCONN flag for one-to-many sockets */
7128163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
7129163953Srrs	}
7130163953Srrs	if (backlog == 0) {
7131163953Srrs		/* turning off listen */
7132163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
7133163953Srrs	}
7134163953Srrs	SOCK_UNLOCK(so);
7135163953Srrs	return (error);
7136163953Srrs}
7137163953Srrs
7138163953Srrsstatic int sctp_defered_wakeup_cnt = 0;
7139163953Srrs
7140163953Srrsint
7141163953Srrssctp_accept(struct socket *so, struct sockaddr **addr)
7142163953Srrs{
7143163953Srrs	struct sctp_tcb *stcb;
7144163953Srrs	struct sctp_inpcb *inp;
7145163953Srrs	union sctp_sockstore store;
7146163953Srrs
7147178251Srrs#ifdef INET6
7148163953Srrs	int error;
7149163953Srrs
7150178251Srrs#endif
7151163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
7152163953Srrs
7153233005Stuexen	if (inp == NULL) {
7154171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7155163953Srrs		return (ECONNRESET);
7156163953Srrs	}
7157163953Srrs	SCTP_INP_RLOCK(inp);
7158163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
7159168299Srrs		SCTP_INP_RUNLOCK(inp);
7160171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
7161171943Srrs		return (EOPNOTSUPP);
7162163953Srrs	}
7163163953Srrs	if (so->so_state & SS_ISDISCONNECTED) {
7164163953Srrs		SCTP_INP_RUNLOCK(inp);
7165171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
7166163953Srrs		return (ECONNABORTED);
7167163953Srrs	}
7168163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
7169163953Srrs	if (stcb == NULL) {
7170163953Srrs		SCTP_INP_RUNLOCK(inp);
7171171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7172163953Srrs		return (ECONNRESET);
7173163953Srrs	}
7174163953Srrs	SCTP_TCB_LOCK(stcb);
7175163953Srrs	SCTP_INP_RUNLOCK(inp);
7176163953Srrs	store = stcb->asoc.primary_destination->ro._l_addr;
7177207924Srrs	stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
7178163953Srrs	SCTP_TCB_UNLOCK(stcb);
7179178251Srrs	switch (store.sa.sa_family) {
7180221249Stuexen#ifdef INET
7181178251Srrs	case AF_INET:
7182178251Srrs		{
7183178251Srrs			struct sockaddr_in *sin;
7184163953Srrs
7185178251Srrs			SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
7186208863Srrs			if (sin == NULL)
7187208863Srrs				return (ENOMEM);
7188178251Srrs			sin->sin_family = AF_INET;
7189178251Srrs			sin->sin_len = sizeof(*sin);
7190246595Stuexen			sin->sin_port = store.sin.sin_port;
7191246595Stuexen			sin->sin_addr = store.sin.sin_addr;
7192178251Srrs			*addr = (struct sockaddr *)sin;
7193178251Srrs			break;
7194178251Srrs		}
7195221249Stuexen#endif
7196178251Srrs#ifdef INET6
7197178251Srrs	case AF_INET6:
7198178251Srrs		{
7199178251Srrs			struct sockaddr_in6 *sin6;
7200163953Srrs
7201178251Srrs			SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
7202208863Srrs			if (sin6 == NULL)
7203208863Srrs				return (ENOMEM);
7204178251Srrs			sin6->sin6_family = AF_INET6;
7205178251Srrs			sin6->sin6_len = sizeof(*sin6);
7206246595Stuexen			sin6->sin6_port = store.sin6.sin6_port;
7207246595Stuexen			sin6->sin6_addr = store.sin6.sin6_addr;
7208178251Srrs			if ((error = sa6_recoverscope(sin6)) != 0) {
7209178251Srrs				SCTP_FREE_SONAME(sin6);
7210178251Srrs				return (error);
7211178251Srrs			}
7212178251Srrs			*addr = (struct sockaddr *)sin6;
7213178251Srrs			break;
7214164085Srrs		}
7215178251Srrs#endif
7216178251Srrs	default:
7217178251Srrs		/* TSNH */
7218178251Srrs		break;
7219163953Srrs	}
7220163953Srrs	/* Wake any delayed sleep action */
7221163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
7222166086Srrs		SCTP_INP_WLOCK(inp);
7223163953Srrs		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
7224163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
7225163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
7226166086Srrs			SCTP_INP_WUNLOCK(inp);
7227163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
7228163953Srrs			if (sowriteable(inp->sctp_socket)) {
7229163953Srrs				sowwakeup_locked(inp->sctp_socket);
7230163953Srrs			} else {
7231163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
7232163953Srrs			}
7233166086Srrs			SCTP_INP_WLOCK(inp);
7234163953Srrs		}
7235163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
7236163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
7237166086Srrs			SCTP_INP_WUNLOCK(inp);
7238163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
7239163953Srrs			if (soreadable(inp->sctp_socket)) {
7240163953Srrs				sctp_defered_wakeup_cnt++;
7241163953Srrs				sorwakeup_locked(inp->sctp_socket);
7242163953Srrs			} else {
7243163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
7244163953Srrs			}
7245166086Srrs			SCTP_INP_WLOCK(inp);
7246163953Srrs		}
7247166086Srrs		SCTP_INP_WUNLOCK(inp);
7248163953Srrs	}
7249207924Srrs	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
7250207924Srrs		SCTP_TCB_LOCK(stcb);
7251283822Stuexen		sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
7252283822Stuexen		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19);
7253207924Srrs	}
7254163953Srrs	return (0);
7255163953Srrs}
7256163953Srrs
7257221249Stuexen#ifdef INET
7258163953Srrsint
7259163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr)
7260163953Srrs{
7261163953Srrs	struct sockaddr_in *sin;
7262167598Srrs	uint32_t vrf_id;
7263163953Srrs	struct sctp_inpcb *inp;
7264167695Srrs	struct sctp_ifa *sctp_ifa;
7265163953Srrs
7266163953Srrs	/*
7267163953Srrs	 * Do the malloc first in case it blocks.
7268163953Srrs	 */
7269163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
7270208863Srrs	if (sin == NULL)
7271208863Srrs		return (ENOMEM);
7272163953Srrs	sin->sin_family = AF_INET;
7273163953Srrs	sin->sin_len = sizeof(*sin);
7274163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
7275163953Srrs	if (!inp) {
7276163953Srrs		SCTP_FREE_SONAME(sin);
7277171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7278228907Stuexen		return (ECONNRESET);
7279163953Srrs	}
7280163953Srrs	SCTP_INP_RLOCK(inp);
7281163953Srrs	sin->sin_port = inp->sctp_lport;
7282163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
7283163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
7284163953Srrs			struct sctp_tcb *stcb;
7285163953Srrs			struct sockaddr_in *sin_a;
7286163953Srrs			struct sctp_nets *net;
7287163953Srrs			int fnd;
7288163953Srrs
7289163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
7290163953Srrs			if (stcb == NULL) {
7291163953Srrs				goto notConn;
7292163953Srrs			}
7293163953Srrs			fnd = 0;
7294163953Srrs			sin_a = NULL;
7295163953Srrs			SCTP_TCB_LOCK(stcb);
7296163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
7297163953Srrs				sin_a = (struct sockaddr_in *)&net->ro._l_addr;
7298164085Srrs				if (sin_a == NULL)
7299164085Srrs					/* this will make coverity happy */
7300164085Srrs					continue;
7301164085Srrs
7302163953Srrs				if (sin_a->sin_family == AF_INET) {
7303163953Srrs					fnd = 1;
7304163953Srrs					break;
7305163953Srrs				}
7306163953Srrs			}
7307163953Srrs			if ((!fnd) || (sin_a == NULL)) {
7308163953Srrs				/* punt */
7309163953Srrs				SCTP_TCB_UNLOCK(stcb);
7310163953Srrs				goto notConn;
7311163953Srrs			}
7312168299Srrs			vrf_id = inp->def_vrf_id;
7313167598Srrs			sctp_ifa = sctp_source_address_selection(inp,
7314167598Srrs			    stcb,
7315168299Srrs			    (sctp_route_t *) & net->ro,
7316167598Srrs			    net, 0, vrf_id);
7317167598Srrs			if (sctp_ifa) {
7318167598Srrs				sin->sin_addr = sctp_ifa->address.sin.sin_addr;
7319167598Srrs				sctp_free_ifa(sctp_ifa);
7320167598Srrs			}
7321163953Srrs			SCTP_TCB_UNLOCK(stcb);
7322163953Srrs		} else {
7323163953Srrs			/* For the bound all case you get back 0 */
7324163953Srrs	notConn:
7325163953Srrs			sin->sin_addr.s_addr = 0;
7326163953Srrs		}
7327163953Srrs
7328163953Srrs	} else {
7329163953Srrs		/* Take the first IPv4 address in the list */
7330163953Srrs		struct sctp_laddr *laddr;
7331163953Srrs		int fnd = 0;
7332163953Srrs
7333163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
7334167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET) {
7335163953Srrs				struct sockaddr_in *sin_a;
7336163953Srrs
7337271746Stuexen				sin_a = &laddr->ifa->address.sin;
7338163953Srrs				sin->sin_addr = sin_a->sin_addr;
7339163953Srrs				fnd = 1;
7340163953Srrs				break;
7341163953Srrs			}
7342163953Srrs		}
7343163953Srrs		if (!fnd) {
7344163953Srrs			SCTP_FREE_SONAME(sin);
7345163953Srrs			SCTP_INP_RUNLOCK(inp);
7346171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
7347228907Stuexen			return (ENOENT);
7348163953Srrs		}
7349163953Srrs	}
7350163953Srrs	SCTP_INP_RUNLOCK(inp);
7351163953Srrs	(*addr) = (struct sockaddr *)sin;
7352163953Srrs	return (0);
7353163953Srrs}
7354163953Srrs
7355163953Srrsint
7356163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr)
7357163953Srrs{
7358231895Stuexen	struct sockaddr_in *sin;
7359166086Srrs	int fnd;
7360163953Srrs	struct sockaddr_in *sin_a;
7361163953Srrs	struct sctp_inpcb *inp;
7362163953Srrs	struct sctp_tcb *stcb;
7363163953Srrs	struct sctp_nets *net;
7364163953Srrs
7365163953Srrs	/* Do the malloc first in case it blocks. */
7366163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
7367208863Srrs	if (sin == NULL)
7368208863Srrs		return (ENOMEM);
7369163953Srrs	sin->sin_family = AF_INET;
7370163953Srrs	sin->sin_len = sizeof(*sin);
7371163953Srrs
7372163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
7373228907Stuexen	if ((inp == NULL) ||
7374228907Stuexen	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
7375228907Stuexen		/* UDP type and listeners will drop out here */
7376163953Srrs		SCTP_FREE_SONAME(sin);
7377228907Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
7378228907Stuexen		return (ENOTCONN);
7379163953Srrs	}
7380163953Srrs	SCTP_INP_RLOCK(inp);
7381163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
7382169420Srrs	if (stcb) {
7383163953Srrs		SCTP_TCB_LOCK(stcb);
7384169420Srrs	}
7385163953Srrs	SCTP_INP_RUNLOCK(inp);
7386163953Srrs	if (stcb == NULL) {
7387163953Srrs		SCTP_FREE_SONAME(sin);
7388171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7389228907Stuexen		return (ECONNRESET);
7390163953Srrs	}
7391163953Srrs	fnd = 0;
7392163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
7393163953Srrs		sin_a = (struct sockaddr_in *)&net->ro._l_addr;
7394163953Srrs		if (sin_a->sin_family == AF_INET) {
7395163953Srrs			fnd = 1;
7396163953Srrs			sin->sin_port = stcb->rport;
7397163953Srrs			sin->sin_addr = sin_a->sin_addr;
7398163953Srrs			break;
7399163953Srrs		}
7400163953Srrs	}
7401163953Srrs	SCTP_TCB_UNLOCK(stcb);
7402163953Srrs	if (!fnd) {
7403163953Srrs		/* No IPv4 address */
7404163953Srrs		SCTP_FREE_SONAME(sin);
7405171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
7406228907Stuexen		return (ENOENT);
7407163953Srrs	}
7408163953Srrs	(*addr) = (struct sockaddr *)sin;
7409163953Srrs	return (0);
7410163953Srrs}
7411163953Srrs
7412163953Srrsstruct pr_usrreqs sctp_usrreqs = {
7413163953Srrs	.pru_abort = sctp_abort,
7414163953Srrs	.pru_accept = sctp_accept,
7415163953Srrs	.pru_attach = sctp_attach,
7416163953Srrs	.pru_bind = sctp_bind,
7417163953Srrs	.pru_connect = sctp_connect,
7418163953Srrs	.pru_control = in_control,
7419163953Srrs	.pru_close = sctp_close,
7420163953Srrs	.pru_detach = sctp_close,
7421163953Srrs	.pru_sopoll = sopoll_generic,
7422178202Srrs	.pru_flush = sctp_flush,
7423163953Srrs	.pru_disconnect = sctp_disconnect,
7424163953Srrs	.pru_listen = sctp_listen,
7425163953Srrs	.pru_peeraddr = sctp_peeraddr,
7426163953Srrs	.pru_send = sctp_sendm,
7427163953Srrs	.pru_shutdown = sctp_shutdown,
7428163953Srrs	.pru_sockaddr = sctp_ingetaddr,
7429163953Srrs	.pru_sosend = sctp_sosend,
7430163953Srrs	.pru_soreceive = sctp_soreceive
7431163953Srrs};
7432221249Stuexen
7433221249Stuexen#endif
7434