sctp_usrreq.c revision 294174
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 294174 2016-01-16 17:56:06Z 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
490171167Sgnn#ifdef IPSEC
491163953Srrs	uint32_t flags;
492185694Srrs
493185435Sbz#endif
494171440Srrs
495163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
496163953Srrs	if (inp != 0) {
497171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
498228907Stuexen		return (EINVAL);
499163953Srrs	}
500184030Srrs	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
501184030Srrs		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
502184030Srrs		if (error) {
503228907Stuexen			return (error);
504184030Srrs		}
505163953Srrs	}
506170205Srrs	error = sctp_inpcb_alloc(so, vrf_id);
507163953Srrs	if (error) {
508228907Stuexen		return (error);
509163953Srrs	}
510163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
511163953Srrs	SCTP_INP_WLOCK(inp);
512163953Srrs	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;	/* I'm not v6! */
513163953Srrs	ip_inp = &inp->ip_inp.inp;
514163953Srrs	ip_inp->inp_vflag |= INP_IPV4;
515197288Srrs	ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
516171167Sgnn#ifdef IPSEC
517171133Sgnn	error = ipsec_init_policy(so, &ip_inp->inp_sp);
518163953Srrs#ifdef SCTP_LOG_CLOSING
519163953Srrs	sctp_log_closing(inp, NULL, 17);
520163953Srrs#endif
521163953Srrs	if (error != 0) {
522202523Srrstry_again:
523163953Srrs		flags = inp->sctp_flags;
524163953Srrs		if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
525163953Srrs		    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
526163953Srrs#ifdef SCTP_LOG_CLOSING
527163953Srrs			sctp_log_closing(inp, NULL, 15);
528163953Srrs#endif
529169352Srrs			SCTP_INP_WUNLOCK(inp);
530169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
531169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
532169254Srrs		} else {
533202523Srrs			flags = inp->sctp_flags;
534202523Srrs			if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
535202523Srrs				goto try_again;
536202523Srrs			} else {
537202523Srrs				SCTP_INP_WUNLOCK(inp);
538202523Srrs			}
539163953Srrs		}
540228907Stuexen		return (error);
541163953Srrs	}
542171167Sgnn#endif				/* IPSEC */
543163953Srrs	SCTP_INP_WUNLOCK(inp);
544228907Stuexen	return (0);
545163953Srrs}
546163953Srrs
547163953Srrsstatic int
548163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
549163953Srrs{
550244730Stuexen	struct sctp_inpcb *inp;
551163953Srrs
552163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
553233005Stuexen	if (inp == NULL) {
554171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
555228907Stuexen		return (EINVAL);
556171943Srrs	}
557244730Stuexen	if (addr != NULL) {
558244730Stuexen		if ((addr->sa_family != AF_INET) ||
559244730Stuexen		    (addr->sa_len != sizeof(struct sockaddr_in))) {
560244730Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
561244730Stuexen			return (EINVAL);
562244730Stuexen		}
563244730Stuexen	}
564244730Stuexen	return (sctp_inpcb_bind(so, addr, NULL, p));
565163953Srrs}
566163953Srrs
567221249Stuexen#endif
568171990Srrsvoid
569163953Srrssctp_close(struct socket *so)
570163953Srrs{
571163953Srrs	struct sctp_inpcb *inp;
572163953Srrs	uint32_t flags;
573163953Srrs
574163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
575233005Stuexen	if (inp == NULL)
576163953Srrs		return;
577163953Srrs
578163953Srrs	/*
579163953Srrs	 * Inform all the lower layer assoc that we are done.
580163953Srrs	 */
581163953Srrssctp_must_try_again:
582163953Srrs	flags = inp->sctp_flags;
583163953Srrs#ifdef SCTP_LOG_CLOSING
584163953Srrs	sctp_log_closing(inp, NULL, 17);
585163953Srrs#endif
586163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
587163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
588163953Srrs		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
589163953Srrs		    (so->so_rcv.sb_cc > 0)) {
590163953Srrs#ifdef SCTP_LOG_CLOSING
591163953Srrs			sctp_log_closing(inp, NULL, 13);
592163953Srrs#endif
593169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
594169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
595163953Srrs		} else {
596163953Srrs#ifdef SCTP_LOG_CLOSING
597163953Srrs			sctp_log_closing(inp, NULL, 14);
598163953Srrs#endif
599169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
600169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
601163953Srrs		}
602163953Srrs		/*
603163953Srrs		 * The socket is now detached, no matter what the state of
604163953Srrs		 * the SCTP association.
605163953Srrs		 */
606163953Srrs		SOCK_LOCK(so);
607167695Srrs		SCTP_SB_CLEAR(so->so_snd);
608163953Srrs		/*
609163953Srrs		 * same for the rcv ones, they are only here for the
610163953Srrs		 * accounting/select.
611163953Srrs		 */
612167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
613167695Srrs
614167695Srrs		/* Now null out the reference, we are completely detached. */
615163953Srrs		so->so_pcb = NULL;
616163953Srrs		SOCK_UNLOCK(so);
617163953Srrs	} else {
618163953Srrs		flags = inp->sctp_flags;
619163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
620163953Srrs			goto sctp_must_try_again;
621163953Srrs		}
622163953Srrs	}
623163953Srrs	return;
624163953Srrs}
625163953Srrs
626163953Srrs
627163953Srrsint
628163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
629163953Srrs    struct mbuf *control, struct thread *p);
630163953Srrs
631163953Srrs
632163953Srrsint
633163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
634163953Srrs    struct mbuf *control, struct thread *p)
635163953Srrs{
636163953Srrs	struct sctp_inpcb *inp;
637163953Srrs	int error;
638163953Srrs
639163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
640233005Stuexen	if (inp == NULL) {
641163953Srrs		if (control) {
642163953Srrs			sctp_m_freem(control);
643163953Srrs			control = NULL;
644163953Srrs		}
645171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
646163953Srrs		sctp_m_freem(m);
647228907Stuexen		return (EINVAL);
648163953Srrs	}
649163953Srrs	/* Got to have an to address if we are NOT a connected socket */
650163953Srrs	if ((addr == NULL) &&
651163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
652228907Stuexen	    (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) {
653163953Srrs		goto connected_type;
654163953Srrs	} else if (addr == NULL) {
655171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
656163953Srrs		error = EDESTADDRREQ;
657163953Srrs		sctp_m_freem(m);
658163953Srrs		if (control) {
659163953Srrs			sctp_m_freem(control);
660163953Srrs			control = NULL;
661163953Srrs		}
662163953Srrs		return (error);
663163953Srrs	}
664163953Srrs#ifdef INET6
665163953Srrs	if (addr->sa_family != AF_INET) {
666163953Srrs		/* must be a v4 address! */
667171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
668163953Srrs		sctp_m_freem(m);
669163953Srrs		if (control) {
670163953Srrs			sctp_m_freem(control);
671163953Srrs			control = NULL;
672163953Srrs		}
673163953Srrs		error = EDESTADDRREQ;
674223132Stuexen		return (error);
675163953Srrs	}
676163953Srrs#endif				/* INET6 */
677163953Srrsconnected_type:
678163953Srrs	/* now what about control */
679163953Srrs	if (control) {
680163953Srrs		if (inp->control) {
681169420Srrs			SCTP_PRINTF("huh? control set?\n");
682163953Srrs			sctp_m_freem(inp->control);
683163953Srrs			inp->control = NULL;
684163953Srrs		}
685163953Srrs		inp->control = control;
686163953Srrs	}
687163953Srrs	/* Place the data */
688163953Srrs	if (inp->pkt) {
689165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
690163953Srrs		inp->pkt_last = m;
691163953Srrs	} else {
692163953Srrs		inp->pkt_last = inp->pkt = m;
693163953Srrs	}
694163953Srrs	if (
695163953Srrs	/* FreeBSD uses a flag passed */
696163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
697163953Srrs	    ) {
698163953Srrs		/*
699163953Srrs		 * note with the current version this code will only be used
700163953Srrs		 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
701163953Srrs		 * re-defining sosend to use the sctp_sosend. One can
702163953Srrs		 * optionally switch back to this code (by changing back the
703163953Srrs		 * definitions) but this is not advisable. This code is used
704163953Srrs		 * by FreeBSD when sending a file with sendfile() though.
705163953Srrs		 */
706163953Srrs		int ret;
707163953Srrs
708163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
709163953Srrs		inp->pkt = NULL;
710163953Srrs		inp->control = NULL;
711163953Srrs		return (ret);
712163953Srrs	} else {
713163953Srrs		return (0);
714163953Srrs	}
715163953Srrs}
716163953Srrs
717171990Srrsint
718163953Srrssctp_disconnect(struct socket *so)
719163953Srrs{
720163953Srrs	struct sctp_inpcb *inp;
721163953Srrs
722163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
723163953Srrs	if (inp == NULL) {
724171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
725163953Srrs		return (ENOTCONN);
726163953Srrs	}
727163953Srrs	SCTP_INP_RLOCK(inp);
728171745Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
729171745Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
730199437Stuexen		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
731163953Srrs			/* No connection */
732163953Srrs			SCTP_INP_RUNLOCK(inp);
733163953Srrs			return (0);
734163953Srrs		} else {
735163953Srrs			struct sctp_association *asoc;
736163953Srrs			struct sctp_tcb *stcb;
737163953Srrs
738163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
739163953Srrs			if (stcb == NULL) {
740163953Srrs				SCTP_INP_RUNLOCK(inp);
741171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
742163953Srrs				return (EINVAL);
743163953Srrs			}
744163953Srrs			SCTP_TCB_LOCK(stcb);
745163953Srrs			asoc = &stcb->asoc;
746163953Srrs			if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
747163953Srrs				/* We are about to be freed, out of here */
748163953Srrs				SCTP_TCB_UNLOCK(stcb);
749163953Srrs				SCTP_INP_RUNLOCK(inp);
750163953Srrs				return (0);
751163953Srrs			}
752163953Srrs			if (((so->so_options & SO_LINGER) &&
753163953Srrs			    (so->so_linger == 0)) ||
754163953Srrs			    (so->so_rcv.sb_cc > 0)) {
755163953Srrs				if (SCTP_GET_STATE(asoc) !=
756163953Srrs				    SCTP_STATE_COOKIE_WAIT) {
757163953Srrs					/* Left with Data unread */
758163953Srrs					struct mbuf *err;
759163953Srrs
760243882Sglebius					err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
761163953Srrs					if (err) {
762163953Srrs						/*
763163953Srrs						 * Fill in the user
764163953Srrs						 * initiated abort
765163953Srrs						 */
766163953Srrs						struct sctp_paramhdr *ph;
767163953Srrs
768163953Srrs						ph = mtod(err, struct sctp_paramhdr *);
769165647Srrs						SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr);
770163953Srrs						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
771165647Srrs						ph->param_length = htons(SCTP_BUF_LEN(err));
772163953Srrs					}
773172090Srrs					sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
774163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
775163953Srrs				}
776163953Srrs				SCTP_INP_RUNLOCK(inp);
777163953Srrs				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
778163953Srrs				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
779163953Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
780163953Srrs				}
781283822Stuexen				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
782283822Stuexen				    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
783163953Srrs				/* No unlock tcb assoc is gone */
784163953Srrs				return (0);
785163953Srrs			}
786163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
787163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
788163953Srrs			    (asoc->stream_queue_cnt == 0)) {
789163953Srrs				/* there is nothing queued to send, so done */
790163953Srrs				if (asoc->locked_on_sending) {
791163953Srrs					goto abort_anyway;
792163953Srrs				}
793166675Srrs				if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
794166675Srrs				    (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
795163953Srrs					/* only send SHUTDOWN 1st time thru */
796224641Stuexen					struct sctp_nets *netp;
797224641Stuexen
798246588Stuexen					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
799246588Stuexen					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
800246588Stuexen						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
801246588Stuexen					}
802246588Stuexen					SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
803246588Stuexen					SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
804246588Stuexen					sctp_stop_timers_for_shutdown(stcb);
805224641Stuexen					if (stcb->asoc.alternate) {
806224641Stuexen						netp = stcb->asoc.alternate;
807224641Stuexen					} else {
808224641Stuexen						netp = stcb->asoc.primary_destination;
809224641Stuexen					}
810224641Stuexen					sctp_send_shutdown(stcb, netp);
811163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
812224641Stuexen					    stcb->sctp_ep, stcb, netp);
813163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
814224641Stuexen					    stcb->sctp_ep, stcb, netp);
815246588Stuexen					sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
816163953Srrs				}
817163953Srrs			} else {
818163953Srrs				/*
819163953Srrs				 * we still got (or just got) data to send,
820163953Srrs				 * so set SHUTDOWN_PENDING
821163953Srrs				 */
822163953Srrs				/*
823163953Srrs				 * XXX sockets draft says that SCTP_EOF
824163953Srrs				 * should be sent with no data. currently,
825163953Srrs				 * we will allow user data to be sent first
826163953Srrs				 * and move to SHUTDOWN-PENDING
827163953Srrs				 */
828224641Stuexen				struct sctp_nets *netp;
829224641Stuexen
830224641Stuexen				if (stcb->asoc.alternate) {
831224641Stuexen					netp = stcb->asoc.alternate;
832224641Stuexen				} else {
833224641Stuexen					netp = stcb->asoc.primary_destination;
834224641Stuexen				}
835224641Stuexen
836163953Srrs				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
837163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
838224641Stuexen				    netp);
839163953Srrs				if (asoc->locked_on_sending) {
840163953Srrs					/* Locked to send out the data */
841163953Srrs					struct sctp_stream_queue_pending *sp;
842163953Srrs
843163953Srrs					sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
844163953Srrs					if (sp == NULL) {
845169420Srrs						SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
846163953Srrs						    asoc->locked_on_sending->stream_no);
847163953Srrs					} else {
848163953Srrs						if ((sp->length == 0) && (sp->msg_is_complete == 0))
849163953Srrs							asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
850163953Srrs					}
851163953Srrs				}
852163953Srrs				if (TAILQ_EMPTY(&asoc->send_queue) &&
853163953Srrs				    TAILQ_EMPTY(&asoc->sent_queue) &&
854163953Srrs				    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
855163953Srrs					struct mbuf *op_err;
856163953Srrs
857163953Srrs			abort_anyway:
858267723Stuexen					op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
859165220Srrs					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
860172090Srrs					sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
861163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
862163953Srrs					if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
863163953Srrs					    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
864163953Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
865163953Srrs					}
866163953Srrs					SCTP_INP_RUNLOCK(inp);
867283822Stuexen					(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
868283822Stuexen					    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
869163953Srrs					return (0);
870171990Srrs				} else {
871172090Srrs					sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
872163953Srrs				}
873163953Srrs			}
874188067Srrs			soisdisconnecting(so);
875163953Srrs			SCTP_TCB_UNLOCK(stcb);
876163953Srrs			SCTP_INP_RUNLOCK(inp);
877163953Srrs			return (0);
878163953Srrs		}
879163953Srrs		/* not reached */
880163953Srrs	} else {
881163953Srrs		/* UDP model does not support this */
882163953Srrs		SCTP_INP_RUNLOCK(inp);
883171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
884228907Stuexen		return (EOPNOTSUPP);
885163953Srrs	}
886163953Srrs}
887163953Srrs
888163953Srrsint
889178202Srrssctp_flush(struct socket *so, int how)
890178202Srrs{
891178202Srrs	/*
892178202Srrs	 * We will just clear out the values and let subsequent close clear
893178202Srrs	 * out the data, if any. Note if the user did a shutdown(SHUT_RD)
894178202Srrs	 * they will not be able to read the data, the socket will block
895178202Srrs	 * that from happening.
896178202Srrs	 */
897209289Stuexen	struct sctp_inpcb *inp;
898209289Stuexen
899209289Stuexen	inp = (struct sctp_inpcb *)so->so_pcb;
900209289Stuexen	if (inp == NULL) {
901209289Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
902228907Stuexen		return (EINVAL);
903209289Stuexen	}
904209289Stuexen	SCTP_INP_RLOCK(inp);
905209289Stuexen	/* For the 1 to many model this does nothing */
906209289Stuexen	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
907209289Stuexen		SCTP_INP_RUNLOCK(inp);
908209289Stuexen		return (0);
909209289Stuexen	}
910209289Stuexen	SCTP_INP_RUNLOCK(inp);
911178202Srrs	if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
912178202Srrs		/*
913178202Srrs		 * First make sure the sb will be happy, we don't use these
914178202Srrs		 * except maybe the count
915178202Srrs		 */
916209289Stuexen		SCTP_INP_WLOCK(inp);
917209289Stuexen		SCTP_INP_READ_LOCK(inp);
918209289Stuexen		inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
919209289Stuexen		SCTP_INP_READ_UNLOCK(inp);
920209289Stuexen		SCTP_INP_WUNLOCK(inp);
921178202Srrs		so->so_rcv.sb_cc = 0;
922178202Srrs		so->so_rcv.sb_mbcnt = 0;
923178202Srrs		so->so_rcv.sb_mb = NULL;
924178202Srrs	}
925178202Srrs	if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
926178202Srrs		/*
927178202Srrs		 * First make sure the sb will be happy, we don't use these
928178202Srrs		 * except maybe the count
929178202Srrs		 */
930178202Srrs		so->so_snd.sb_cc = 0;
931178202Srrs		so->so_snd.sb_mbcnt = 0;
932178202Srrs		so->so_snd.sb_mb = NULL;
933178202Srrs
934178202Srrs	}
935178202Srrs	return (0);
936178202Srrs}
937178202Srrs
938178202Srrsint
939163953Srrssctp_shutdown(struct socket *so)
940163953Srrs{
941163953Srrs	struct sctp_inpcb *inp;
942163953Srrs
943163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
944233005Stuexen	if (inp == NULL) {
945171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
946228907Stuexen		return (EINVAL);
947163953Srrs	}
948163953Srrs	SCTP_INP_RLOCK(inp);
949163953Srrs	/* For UDP model this is a invalid call */
950243558Stuexen	if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
951243558Stuexen	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
952163953Srrs		/* Restore the flags that the soshutdown took away. */
953204096Stuexen		SOCKBUF_LOCK(&so->so_rcv);
954163953Srrs		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
955204096Stuexen		SOCKBUF_UNLOCK(&so->so_rcv);
956163953Srrs		/* This proc will wakeup for read and do nothing (I hope) */
957163953Srrs		SCTP_INP_RUNLOCK(inp);
958171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
959163953Srrs		return (EOPNOTSUPP);
960163953Srrs	}
961163953Srrs	/*
962163953Srrs	 * Ok if we reach here its the TCP model and it is either a SHUT_WR
963163953Srrs	 * or SHUT_RDWR. This means we put the shutdown flag against it.
964163953Srrs	 */
965163953Srrs	{
966163953Srrs		struct sctp_tcb *stcb;
967163953Srrs		struct sctp_association *asoc;
968163953Srrs
969188067Srrs		if ((so->so_state &
970188067Srrs		    (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
971188067Srrs			SCTP_INP_RUNLOCK(inp);
972188067Srrs			return (ENOTCONN);
973188067Srrs		}
974163953Srrs		socantsendmore(so);
975163953Srrs
976163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
977163953Srrs		if (stcb == NULL) {
978163953Srrs			/*
979163953Srrs			 * Ok we hit the case that the shutdown call was
980163953Srrs			 * made after an abort or something. Nothing to do
981163953Srrs			 * now.
982163953Srrs			 */
983168299Srrs			SCTP_INP_RUNLOCK(inp);
984163953Srrs			return (0);
985163953Srrs		}
986163953Srrs		SCTP_TCB_LOCK(stcb);
987163953Srrs		asoc = &stcb->asoc;
988163953Srrs		if (TAILQ_EMPTY(&asoc->send_queue) &&
989163953Srrs		    TAILQ_EMPTY(&asoc->sent_queue) &&
990163953Srrs		    (asoc->stream_queue_cnt == 0)) {
991163953Srrs			if (asoc->locked_on_sending) {
992163953Srrs				goto abort_anyway;
993163953Srrs			}
994163953Srrs			/* there is nothing queued to send, so I'm done... */
995163953Srrs			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
996163953Srrs				/* only send SHUTDOWN the first time through */
997224641Stuexen				struct sctp_nets *netp;
998224641Stuexen
999246588Stuexen				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
1000246588Stuexen				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1001246588Stuexen					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1002246588Stuexen				}
1003246588Stuexen				SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
1004246588Stuexen				SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
1005246588Stuexen				sctp_stop_timers_for_shutdown(stcb);
1006224641Stuexen				if (stcb->asoc.alternate) {
1007224641Stuexen					netp = stcb->asoc.alternate;
1008224641Stuexen				} else {
1009224641Stuexen					netp = stcb->asoc.primary_destination;
1010224641Stuexen				}
1011224641Stuexen				sctp_send_shutdown(stcb, netp);
1012163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1013224641Stuexen				    stcb->sctp_ep, stcb, netp);
1014163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1015224641Stuexen				    stcb->sctp_ep, stcb, netp);
1016246588Stuexen				sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
1017163953Srrs			}
1018163953Srrs		} else {
1019163953Srrs			/*
1020163953Srrs			 * we still got (or just got) data to send, so set
1021163953Srrs			 * SHUTDOWN_PENDING
1022163953Srrs			 */
1023224641Stuexen			struct sctp_nets *netp;
1024224641Stuexen
1025224641Stuexen			if (stcb->asoc.alternate) {
1026224641Stuexen				netp = stcb->asoc.alternate;
1027224641Stuexen			} else {
1028224641Stuexen				netp = stcb->asoc.primary_destination;
1029224641Stuexen			}
1030224641Stuexen
1031163953Srrs			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1032163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
1033224641Stuexen			    netp);
1034163953Srrs
1035163953Srrs			if (asoc->locked_on_sending) {
1036163953Srrs				/* Locked to send out the data */
1037163953Srrs				struct sctp_stream_queue_pending *sp;
1038163953Srrs
1039163953Srrs				sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1040163953Srrs				if (sp == NULL) {
1041169420Srrs					SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1042163953Srrs					    asoc->locked_on_sending->stream_no);
1043163953Srrs				} else {
1044163953Srrs					if ((sp->length == 0) && (sp->msg_is_complete == 0)) {
1045163953Srrs						asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
1046163953Srrs					}
1047163953Srrs				}
1048163953Srrs			}
1049163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
1050163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
1051163953Srrs			    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1052163953Srrs				struct mbuf *op_err;
1053163953Srrs
1054163953Srrs		abort_anyway:
1055267723Stuexen				op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
1056165220Srrs				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
1057163953Srrs				sctp_abort_an_association(stcb->sctp_ep, stcb,
1058172090Srrs				    op_err, SCTP_SO_LOCKED);
1059163953Srrs				goto skip_unlock;
1060171990Srrs			} else {
1061172090Srrs				sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
1062163953Srrs			}
1063163953Srrs		}
1064163953Srrs		SCTP_TCB_UNLOCK(stcb);
1065163953Srrs	}
1066163953Srrsskip_unlock:
1067163953Srrs	SCTP_INP_RUNLOCK(inp);
1068228907Stuexen	return (0);
1069163953Srrs}
1070163953Srrs
1071163953Srrs/*
1072163953Srrs * copies a "user" presentable address and removes embedded scope, etc.
1073163953Srrs * returns 0 on success, 1 on error
1074163953Srrs */
1075163953Srrsstatic uint32_t
1076163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
1077163953Srrs{
1078178251Srrs#ifdef INET6
1079163953Srrs	struct sockaddr_in6 lsa6;
1080163953Srrs
1081163953Srrs	sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
1082163953Srrs	    &lsa6);
1083178251Srrs#endif
1084163953Srrs	memcpy(ss, sa, sa->sa_len);
1085163953Srrs	return (0);
1086163953Srrs}
1087163953Srrs
1088163953Srrs
1089163953Srrs
1090172091Srrs/*
1091172091Srrs * NOTE: assumes addr lock is held
1092172091Srrs */
1093166675Srrsstatic size_t
1094168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
1095163953Srrs    struct sctp_tcb *stcb,
1096166675Srrs    size_t limit,
1097167598Srrs    struct sockaddr_storage *sas,
1098167598Srrs    uint32_t vrf_id)
1099163953Srrs{
1100167598Srrs	struct sctp_ifn *sctp_ifn;
1101167598Srrs	struct sctp_ifa *sctp_ifa;
1102166675Srrs	size_t actual;
1103258454Stuexen	int loopback_scope;
1104258454Stuexen
1105258454Stuexen#if defined(INET)
1106258454Stuexen	int ipv4_local_scope, ipv4_addr_legal;
1107258454Stuexen
1108258454Stuexen#endif
1109258454Stuexen#if defined(INET6)
1110258454Stuexen	int local_scope, site_scope, ipv6_addr_legal;
1111258454Stuexen
1112258454Stuexen#endif
1113167598Srrs	struct sctp_vrf *vrf;
1114163953Srrs
1115163953Srrs	actual = 0;
1116163953Srrs	if (limit <= 0)
1117163953Srrs		return (actual);
1118163953Srrs
1119163953Srrs	if (stcb) {
1120163953Srrs		/* Turn on all the appropriate scope */
1121246595Stuexen		loopback_scope = stcb->asoc.scope.loopback_scope;
1122258454Stuexen#if defined(INET)
1123246595Stuexen		ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
1124258454Stuexen		ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
1125258454Stuexen#endif
1126258454Stuexen#if defined(INET6)
1127246595Stuexen		local_scope = stcb->asoc.scope.local_scope;
1128246595Stuexen		site_scope = stcb->asoc.scope.site_scope;
1129246595Stuexen		ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
1130258454Stuexen#endif
1131163953Srrs	} else {
1132246595Stuexen		/* Use generic values for endpoints. */
1133246595Stuexen		loopback_scope = 1;
1134258454Stuexen#if defined(INET)
1135246595Stuexen		ipv4_local_scope = 1;
1136258454Stuexen#endif
1137258454Stuexen#if defined(INET6)
1138246595Stuexen		local_scope = 1;
1139246595Stuexen		site_scope = 1;
1140258454Stuexen#endif
1141246595Stuexen		if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1142258454Stuexen#if defined(INET6)
1143246595Stuexen			ipv6_addr_legal = 1;
1144258454Stuexen#endif
1145258454Stuexen#if defined(INET)
1146246595Stuexen			if (SCTP_IPV6_V6ONLY(inp)) {
1147246595Stuexen				ipv4_addr_legal = 0;
1148246595Stuexen			} else {
1149246595Stuexen				ipv4_addr_legal = 1;
1150246595Stuexen			}
1151258454Stuexen#endif
1152246595Stuexen		} else {
1153258454Stuexen#if defined(INET6)
1154246595Stuexen			ipv6_addr_legal = 0;
1155258454Stuexen#endif
1156258454Stuexen#if defined(INET)
1157163953Srrs			ipv4_addr_legal = 1;
1158258454Stuexen#endif
1159163953Srrs		}
1160163953Srrs	}
1161167598Srrs	vrf = sctp_find_vrf(vrf_id);
1162167598Srrs	if (vrf == NULL) {
1163167598Srrs		return (0);
1164167598Srrs	}
1165163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1166167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1167163953Srrs			if ((loopback_scope == 0) &&
1168167598Srrs			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
1169163953Srrs				/* Skip loopback if loopback_scope not set */
1170163953Srrs				continue;
1171163953Srrs			}
1172167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1173163953Srrs				if (stcb) {
1174163953Srrs					/*
1175163953Srrs					 * For the BOUND-ALL case, the list
1176163953Srrs					 * associated with a TCB is Always
1177163953Srrs					 * considered a reverse list.. i.e.
1178163953Srrs					 * it lists addresses that are NOT
1179163953Srrs					 * part of the association. If this
1180163953Srrs					 * is one of those we must skip it.
1181163953Srrs					 */
1182163953Srrs					if (sctp_is_addr_restricted(stcb,
1183167598Srrs					    sctp_ifa)) {
1184163953Srrs						continue;
1185163953Srrs					}
1186163953Srrs				}
1187178251Srrs				switch (sctp_ifa->address.sa.sa_family) {
1188221249Stuexen#ifdef INET
1189178251Srrs				case AF_INET:
1190178251Srrs					if (ipv4_addr_legal) {
1191178251Srrs						struct sockaddr_in *sin;
1192163953Srrs
1193271746Stuexen						sin = &sctp_ifa->address.sin;
1194178251Srrs						if (sin->sin_addr.s_addr == 0) {
1195178251Srrs							/*
1196178251Srrs							 * we skip
1197178251Srrs							 * unspecifed
1198178251Srrs							 * addresses
1199178251Srrs							 */
1200178251Srrs							continue;
1201178251Srrs						}
1202267769Stuexen						if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
1203267769Stuexen						    &sin->sin_addr) != 0) {
1204267769Stuexen							continue;
1205267769Stuexen						}
1206178251Srrs						if ((ipv4_local_scope == 0) &&
1207178251Srrs						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
1208178251Srrs							continue;
1209178251Srrs						}
1210178251Srrs#ifdef INET6
1211178251Srrs						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
1212178251Srrs							in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
1213178251Srrs							((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1214178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
1215178251Srrs							actual += sizeof(struct sockaddr_in6);
1216178251Srrs						} else {
1217178251Srrs#endif
1218178251Srrs							memcpy(sas, sin, sizeof(*sin));
1219178251Srrs							((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1220178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
1221178251Srrs							actual += sizeof(*sin);
1222178251Srrs#ifdef INET6
1223178251Srrs						}
1224178251Srrs#endif
1225178251Srrs						if (actual >= limit) {
1226178251Srrs							return (actual);
1227178251Srrs						}
1228178251Srrs					} else {
1229163953Srrs						continue;
1230163953Srrs					}
1231178251Srrs					break;
1232221249Stuexen#endif
1233178251Srrs#ifdef INET6
1234178251Srrs				case AF_INET6:
1235178251Srrs					if (ipv6_addr_legal) {
1236178251Srrs						struct sockaddr_in6 *sin6;
1237163953Srrs
1238271746Stuexen						sin6 = &sctp_ifa->address.sin6;
1239178251Srrs						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1240178251Srrs							/*
1241178251Srrs							 * we skip
1242178251Srrs							 * unspecifed
1243178251Srrs							 * addresses
1244178251Srrs							 */
1245163953Srrs							continue;
1246178251Srrs						}
1247267769Stuexen						if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
1248267769Stuexen						    &sin6->sin6_addr) != 0) {
1249267769Stuexen							continue;
1250267769Stuexen						}
1251178251Srrs						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1252178251Srrs							if (local_scope == 0)
1253163953Srrs								continue;
1254178251Srrs							if (sin6->sin6_scope_id == 0) {
1255178251Srrs								if (sa6_recoverscope(sin6) != 0)
1256178251Srrs									/*
1257178251Srrs									 *
1258178251Srrs									 * bad
1259178251Srrs									 *
1260178251Srrs									 * li
1261178251Srrs									 * nk
1262178251Srrs									 *
1263178251Srrs									 * loc
1264178251Srrs									 * al
1265178251Srrs									 *
1266178251Srrs									 * add
1267178251Srrs									 * re
1268178251Srrs									 * ss
1269178251Srrs									 * */
1270178251Srrs									continue;
1271178251Srrs							}
1272163953Srrs						}
1273178251Srrs						if ((site_scope == 0) &&
1274178251Srrs						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
1275178251Srrs							continue;
1276178251Srrs						}
1277178251Srrs						memcpy(sas, sin6, sizeof(*sin6));
1278178251Srrs						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1279178251Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
1280178251Srrs						actual += sizeof(*sin6);
1281178251Srrs						if (actual >= limit) {
1282178251Srrs							return (actual);
1283178251Srrs						}
1284178251Srrs					} else {
1285163953Srrs						continue;
1286163953Srrs					}
1287178251Srrs					break;
1288178251Srrs#endif
1289178251Srrs				default:
1290178251Srrs					/* TSNH */
1291178251Srrs					break;
1292163953Srrs				}
1293163953Srrs			}
1294163953Srrs		}
1295163953Srrs	} else {
1296163953Srrs		struct sctp_laddr *laddr;
1297163953Srrs
1298167598Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1299167598Srrs			if (stcb) {
1300167598Srrs				if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
1301163953Srrs					continue;
1302163953Srrs				}
1303163953Srrs			}
1304167598Srrs			if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
1305167598Srrs				continue;
1306246595Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1307246595Stuexen#ifdef INET
1308246595Stuexen			case AF_INET:
1309246595Stuexen				((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1310246595Stuexen				break;
1311246595Stuexen#endif
1312246595Stuexen#ifdef INET6
1313246595Stuexen			case AF_INET6:
1314246595Stuexen				((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1315246595Stuexen				break;
1316246595Stuexen#endif
1317246595Stuexen			default:
1318246595Stuexen				/* TSNH */
1319246595Stuexen				break;
1320246595Stuexen			}
1321167598Srrs			sas = (struct sockaddr_storage *)((caddr_t)sas +
1322167598Srrs			    laddr->ifa->address.sa.sa_len);
1323167598Srrs			actual += laddr->ifa->address.sa.sa_len;
1324167598Srrs			if (actual >= limit) {
1325167598Srrs				return (actual);
1326163953Srrs			}
1327163953Srrs		}
1328163953Srrs	}
1329163953Srrs	return (actual);
1330163953Srrs}
1331163953Srrs
1332168124Srrsstatic size_t
1333168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp,
1334168124Srrs    struct sctp_tcb *stcb,
1335168124Srrs    size_t limit,
1336168124Srrs    struct sockaddr_storage *sas)
1337168124Srrs{
1338168124Srrs	size_t size = 0;
1339168124Srrs
1340172218Srrs	SCTP_IPI_ADDR_RLOCK();
1341168124Srrs	/* fill up addresses for the endpoint's default vrf */
1342168124Srrs	size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
1343168124Srrs	    inp->def_vrf_id);
1344172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1345168124Srrs	return (size);
1346168124Srrs}
1347168124Srrs
1348172091Srrs/*
1349172091Srrs * NOTE: assumes addr lock is held
1350172091Srrs */
1351163953Srrsstatic int
1352168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
1353163953Srrs{
1354163953Srrs	int cnt = 0;
1355167598Srrs	struct sctp_vrf *vrf = NULL;
1356163953Srrs
1357163953Srrs	/*
1358163953Srrs	 * In both sub-set bound an bound_all cases we return the MAXIMUM
1359163953Srrs	 * number of addresses that you COULD get. In reality the sub-set
1360163953Srrs	 * bound may have an exclusion list for a given TCB OR in the
1361163953Srrs	 * bound-all case a TCB may NOT include the loopback or other
1362163953Srrs	 * addresses as well.
1363163953Srrs	 */
1364167598Srrs	vrf = sctp_find_vrf(vrf_id);
1365167598Srrs	if (vrf == NULL) {
1366167598Srrs		return (0);
1367167598Srrs	}
1368163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1369167598Srrs		struct sctp_ifn *sctp_ifn;
1370167598Srrs		struct sctp_ifa *sctp_ifa;
1371163953Srrs
1372167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1373167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1374163953Srrs				/* Count them if they are the right type */
1375221249Stuexen				switch (sctp_ifa->address.sa.sa_family) {
1376221249Stuexen#ifdef INET
1377221249Stuexen				case AF_INET:
1378283699Stuexen#ifdef INET6
1379178251Srrs					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1380163953Srrs						cnt += sizeof(struct sockaddr_in6);
1381163953Srrs					else
1382163953Srrs						cnt += sizeof(struct sockaddr_in);
1383283699Stuexen#else
1384283699Stuexen					cnt += sizeof(struct sockaddr_in);
1385283699Stuexen#endif
1386221249Stuexen					break;
1387221249Stuexen#endif
1388221249Stuexen#ifdef INET6
1389221249Stuexen				case AF_INET6:
1390163953Srrs					cnt += sizeof(struct sockaddr_in6);
1391221249Stuexen					break;
1392221249Stuexen#endif
1393221249Stuexen				default:
1394221249Stuexen					break;
1395221249Stuexen				}
1396163953Srrs			}
1397163953Srrs		}
1398163953Srrs	} else {
1399163953Srrs		struct sctp_laddr *laddr;
1400163953Srrs
1401163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1402221249Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1403221249Stuexen#ifdef INET
1404221249Stuexen			case AF_INET:
1405283699Stuexen#ifdef INET6
1406178251Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1407163953Srrs					cnt += sizeof(struct sockaddr_in6);
1408163953Srrs				else
1409163953Srrs					cnt += sizeof(struct sockaddr_in);
1410283699Stuexen#else
1411283699Stuexen				cnt += sizeof(struct sockaddr_in);
1412283699Stuexen#endif
1413221249Stuexen				break;
1414221249Stuexen#endif
1415221249Stuexen#ifdef INET6
1416221249Stuexen			case AF_INET6:
1417163953Srrs				cnt += sizeof(struct sockaddr_in6);
1418221249Stuexen				break;
1419221249Stuexen#endif
1420221249Stuexen			default:
1421221249Stuexen				break;
1422221249Stuexen			}
1423163953Srrs		}
1424163953Srrs	}
1425163953Srrs	return (cnt);
1426163953Srrs}
1427163953Srrs
1428168124Srrsstatic int
1429168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp)
1430168124Srrs{
1431168124Srrs	int cnt = 0;
1432166675Srrs
1433172218Srrs	SCTP_IPI_ADDR_RLOCK();
1434168124Srrs	/* count addresses for the endpoint's default VRF */
1435168124Srrs	cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
1436172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1437168124Srrs	return (cnt);
1438168124Srrs}
1439168124Srrs
1440163953Srrsstatic int
1441166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
1442166675Srrs    size_t optsize, void *p, int delay)
1443163953Srrs{
1444163953Srrs	int error = 0;
1445163953Srrs	int creat_lock_on = 0;
1446163953Srrs	struct sctp_tcb *stcb = NULL;
1447163953Srrs	struct sockaddr *sa;
1448169352Srrs	int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
1449167598Srrs	uint32_t vrf_id;
1450170056Srrs	int bad_addresses = 0;
1451167598Srrs	sctp_assoc_t *a_id;
1452163953Srrs
1453169420Srrs	SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
1454163953Srrs
1455163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1456163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1457163953Srrs		/* We are already connected AND the TCP model */
1458171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
1459163953Srrs		return (EADDRINUSE);
1460163953Srrs	}
1461181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
1462181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
1463171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1464163953Srrs		return (EINVAL);
1465163953Srrs	}
1466163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1467163953Srrs		SCTP_INP_RLOCK(inp);
1468163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1469163953Srrs		SCTP_INP_RUNLOCK(inp);
1470163953Srrs	}
1471163953Srrs	if (stcb) {
1472171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1473163953Srrs		return (EALREADY);
1474163953Srrs	}
1475163953Srrs	SCTP_INP_INCR_REF(inp);
1476163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
1477163953Srrs	creat_lock_on = 1;
1478163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1479163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
1480171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
1481163953Srrs		error = EFAULT;
1482163953Srrs		goto out_now;
1483163953Srrs	}
1484166675Srrs	totaddrp = (int *)optval;
1485163953Srrs	totaddr = *totaddrp;
1486163953Srrs	sa = (struct sockaddr *)(totaddrp + 1);
1487170056Srrs	stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
1488170056Srrs	if ((stcb != NULL) || bad_addresses) {
1489169352Srrs		/* Already have or am bring up an association */
1490169352Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1491169352Srrs		creat_lock_on = 0;
1492170931Srrs		if (stcb)
1493170931Srrs			SCTP_TCB_UNLOCK(stcb);
1494171943Srrs		if (bad_addresses == 0) {
1495171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1496170056Srrs			error = EALREADY;
1497171943Srrs		}
1498169352Srrs		goto out_now;
1499163953Srrs	}
1500163953Srrs#ifdef INET6
1501163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
1502163953Srrs	    (num_v6 > 0)) {
1503163953Srrs		error = EINVAL;
1504163953Srrs		goto out_now;
1505163953Srrs	}
1506163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1507163953Srrs	    (num_v4 > 0)) {
1508163953Srrs		struct in6pcb *inp6;
1509163953Srrs
1510163953Srrs		inp6 = (struct in6pcb *)inp;
1511166023Srrs		if (SCTP_IPV6_V6ONLY(inp6)) {
1512163953Srrs			/*
1513163953Srrs			 * if IPV6_V6ONLY flag, ignore connections destined
1514163953Srrs			 * to a v4 addr or v4-mapped addr
1515163953Srrs			 */
1516171943Srrs			SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1517163953Srrs			error = EINVAL;
1518163953Srrs			goto out_now;
1519163953Srrs		}
1520163953Srrs	}
1521163953Srrs#endif				/* INET6 */
1522163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1523163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
1524163953Srrs		/* Bind a ephemeral port */
1525171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
1526163953Srrs		if (error) {
1527163953Srrs			goto out_now;
1528163953Srrs		}
1529163953Srrs	}
1530167695Srrs	/* FIX ME: do we want to pass in a vrf on the connect call? */
1531167695Srrs	vrf_id = inp->def_vrf_id;
1532167695Srrs
1533181054Srrs
1534163953Srrs	/* We are GOOD to go */
1535206137Stuexen	stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id,
1536171531Srrs	    (struct thread *)p
1537171531Srrs	    );
1538163953Srrs	if (stcb == NULL) {
1539163953Srrs		/* Gak! no memory */
1540163953Srrs		goto out_now;
1541163953Srrs	}
1542225559Stuexen	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1543225559Stuexen		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1544225559Stuexen		/* Set the connected flag so we can queue data */
1545225559Stuexen		soisconnecting(so);
1546225559Stuexen	}
1547171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
1548163953Srrs	/* move to second address */
1549221249Stuexen	switch (sa->sa_family) {
1550221249Stuexen#ifdef INET
1551221249Stuexen	case AF_INET:
1552163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
1553221249Stuexen		break;
1554221249Stuexen#endif
1555221249Stuexen#ifdef INET6
1556221249Stuexen	case AF_INET6:
1557163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
1558221249Stuexen		break;
1559221249Stuexen#endif
1560221249Stuexen	default:
1561221249Stuexen		break;
1562221249Stuexen	}
1563163953Srrs
1564170056Srrs	error = 0;
1565223132Stuexen	sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
1566167598Srrs	/* Fill in the return id */
1567170056Srrs	if (error) {
1568283822Stuexen		(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE,
1569283822Stuexen		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
1570170056Srrs		goto out_now;
1571170056Srrs	}
1572167598Srrs	a_id = (sctp_assoc_t *) optval;
1573167598Srrs	*a_id = sctp_get_associd(stcb);
1574163953Srrs
1575163953Srrs	/* initialize authentication parameters for the assoc */
1576163953Srrs	sctp_initialize_auth_params(inp, stcb);
1577163953Srrs
1578163953Srrs	if (delay) {
1579163953Srrs		/* doing delayed connection */
1580163953Srrs		stcb->asoc.delayed_connection = 1;
1581163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
1582163953Srrs	} else {
1583169378Srrs		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1584172090Srrs		sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
1585163953Srrs	}
1586163953Srrs	SCTP_TCB_UNLOCK(stcb);
1587163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1588163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1589163953Srrs		/* Set the connected flag so we can queue data */
1590163953Srrs		soisconnecting(so);
1591163953Srrs	}
1592163953Srrsout_now:
1593169655Srrs	if (creat_lock_on) {
1594163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1595169655Srrs	}
1596163953Srrs	SCTP_INP_DECR_REF(inp);
1597228907Stuexen	return (error);
1598163953Srrs}
1599163953Srrs
1600169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
1601169655Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\
1602169655Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \
1603166675Srrs		SCTP_INP_RLOCK(inp); \
1604166675Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list); \
1605169655Srrs		if (stcb) { \
1606166675Srrs			SCTP_TCB_LOCK(stcb); \
1607169655Srrs                } \
1608166675Srrs		SCTP_INP_RUNLOCK(inp); \
1609223132Stuexen	} else if (assoc_id > SCTP_ALL_ASSOC) { \
1610166675Srrs		stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
1611166675Srrs		if (stcb == NULL) { \
1612171943Srrs		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
1613166675Srrs			error = ENOENT; \
1614166675Srrs			break; \
1615166675Srrs		} \
1616166675Srrs	} else { \
1617166675Srrs		stcb = NULL; \
1618169420Srrs        } \
1619169420Srrs  }
1620163953Srrs
1621169420Srrs
1622234464Stuexen#define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
1623166675Srrs	if (size < sizeof(type)) { \
1624171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
1625166675Srrs		error = EINVAL; \
1626166675Srrs		break; \
1627166675Srrs	} else { \
1628166675Srrs		destp = (type *)srcp; \
1629169420Srrs	} \
1630169420Srrs      }
1631163953Srrs
1632163953Srrsstatic int
1633166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
1634166675Srrs    void *p)
1635163953Srrs{
1636171943Srrs	struct sctp_inpcb *inp = NULL;
1637166675Srrs	int error, val = 0;
1638163953Srrs	struct sctp_tcb *stcb = NULL;
1639163953Srrs
1640166675Srrs	if (optval == NULL) {
1641171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1642166675Srrs		return (EINVAL);
1643166675Srrs	}
1644163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1645233005Stuexen	if (inp == NULL) {
1646171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1647163953Srrs		return EINVAL;
1648171943Srrs	}
1649163953Srrs	error = 0;
1650163953Srrs
1651166675Srrs	switch (optname) {
1652163953Srrs	case SCTP_NODELAY:
1653163953Srrs	case SCTP_AUTOCLOSE:
1654163953Srrs	case SCTP_EXPLICIT_EOR:
1655163953Srrs	case SCTP_AUTO_ASCONF:
1656163953Srrs	case SCTP_DISABLE_FRAGMENTS:
1657163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
1658163953Srrs	case SCTP_USE_EXT_RCVINFO:
1659163953Srrs		SCTP_INP_RLOCK(inp);
1660166675Srrs		switch (optname) {
1661163953Srrs		case SCTP_DISABLE_FRAGMENTS:
1662166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
1663163953Srrs			break;
1664163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
1665166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
1666163953Srrs			break;
1667163953Srrs		case SCTP_AUTO_ASCONF:
1668171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1669171943Srrs				/* only valid for bound all sockets */
1670171943Srrs				val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
1671171943Srrs			} else {
1672171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1673171943Srrs				error = EINVAL;
1674171943Srrs				goto flags_out;
1675171943Srrs			}
1676163953Srrs			break;
1677163953Srrs		case SCTP_EXPLICIT_EOR:
1678166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
1679163953Srrs			break;
1680163953Srrs		case SCTP_NODELAY:
1681166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
1682163953Srrs			break;
1683163953Srrs		case SCTP_USE_EXT_RCVINFO:
1684166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
1685163953Srrs			break;
1686163953Srrs		case SCTP_AUTOCLOSE:
1687163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
1688166675Srrs				val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
1689163953Srrs			else
1690166675Srrs				val = 0;
1691163953Srrs			break;
1692163953Srrs
1693163953Srrs		default:
1694171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
1695163953Srrs			error = ENOPROTOOPT;
1696163953Srrs		}		/* end switch (sopt->sopt_name) */
1697166675Srrs		if (*optsize < sizeof(val)) {
1698171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1699163953Srrs			error = EINVAL;
1700163953Srrs		}
1701171943Srrsflags_out:
1702163953Srrs		SCTP_INP_RUNLOCK(inp);
1703163953Srrs		if (error == 0) {
1704163953Srrs			/* return the option value */
1705166675Srrs			*(int *)optval = val;
1706166675Srrs			*optsize = sizeof(val);
1707163953Srrs		}
1708163953Srrs		break;
1709170091Srrs	case SCTP_GET_PACKET_LOG:
1710170091Srrs		{
1711170091Srrs#ifdef  SCTP_PACKET_LOGGING
1712170091Srrs			uint8_t *target;
1713170091Srrs			int ret;
1714167598Srrs
1715170091Srrs			SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize);
1716170091Srrs			ret = sctp_copy_out_packet_log(target, (int)*optsize);
1717170091Srrs			*optsize = ret;
1718170091Srrs#else
1719171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1720170091Srrs			error = EOPNOTSUPP;
1721170091Srrs#endif
1722170091Srrs			break;
1723170091Srrs		}
1724181054Srrs	case SCTP_REUSE_PORT:
1725181054Srrs		{
1726181054Srrs			uint32_t *value;
1727181054Srrs
1728181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
1729181054Srrs				/* Can't do this for a 1-m socket */
1730181054Srrs				error = EINVAL;
1731181054Srrs				break;
1732181054Srrs			}
1733181054Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1734181054Srrs			*value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
1735181054Srrs			*optsize = sizeof(uint32_t);
1736223132Stuexen			break;
1737181054Srrs		}
1738163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
1739163953Srrs		{
1740166675Srrs			uint32_t *value;
1741166675Srrs
1742166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1743166675Srrs			*value = inp->partial_delivery_point;
1744166675Srrs			*optsize = sizeof(uint32_t);
1745223132Stuexen			break;
1746163953Srrs		}
1747163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
1748163953Srrs		{
1749166675Srrs			uint32_t *value;
1750166675Srrs
1751166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1752168943Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
1753168943Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
1754168943Srrs					*value = SCTP_FRAG_LEVEL_2;
1755168943Srrs				} else {
1756168943Srrs					*value = SCTP_FRAG_LEVEL_1;
1757168943Srrs				}
1758168943Srrs			} else {
1759168943Srrs				*value = SCTP_FRAG_LEVEL_0;
1760168943Srrs			}
1761166675Srrs			*optsize = sizeof(uint32_t);
1762223132Stuexen			break;
1763163953Srrs		}
1764163953Srrs	case SCTP_CMT_ON_OFF:
1765163953Srrs		{
1766166675Srrs			struct sctp_assoc_value *av;
1767166675Srrs
1768166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1769211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1770211944Stuexen			if (stcb) {
1771211944Stuexen				av->assoc_value = stcb->asoc.sctp_cmt_on_off;
1772211944Stuexen				SCTP_TCB_UNLOCK(stcb);
1773166675Srrs			} else {
1774224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1775224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1776224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1777223132Stuexen					SCTP_INP_RLOCK(inp);
1778223132Stuexen					av->assoc_value = inp->sctp_cmt_on_off;
1779223132Stuexen					SCTP_INP_RUNLOCK(inp);
1780223132Stuexen				} else {
1781223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1782223132Stuexen					error = EINVAL;
1783223132Stuexen				}
1784163953Srrs			}
1785223132Stuexen			if (error == 0) {
1786223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1787223132Stuexen			}
1788223132Stuexen			break;
1789163953Srrs		}
1790171440Srrs	case SCTP_PLUGGABLE_CC:
1791171440Srrs		{
1792171440Srrs			struct sctp_assoc_value *av;
1793171440Srrs
1794171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1795171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1796171440Srrs			if (stcb) {
1797171440Srrs				av->assoc_value = stcb->asoc.congestion_control_module;
1798171440Srrs				SCTP_TCB_UNLOCK(stcb);
1799171440Srrs			} else {
1800224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1801224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1802224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1803223132Stuexen					SCTP_INP_RLOCK(inp);
1804223132Stuexen					av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
1805223132Stuexen					SCTP_INP_RUNLOCK(inp);
1806223132Stuexen				} else {
1807223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1808223132Stuexen					error = EINVAL;
1809223132Stuexen				}
1810171440Srrs			}
1811223132Stuexen			if (error == 0) {
1812223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1813223132Stuexen			}
1814223132Stuexen			break;
1815171440Srrs		}
1816219057Srrs	case SCTP_CC_OPTION:
1817219057Srrs		{
1818219057Srrs			struct sctp_cc_option *cc_opt;
1819219057Srrs
1820219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize);
1821219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
1822219057Srrs			if (stcb == NULL) {
1823219057Srrs				error = EINVAL;
1824219057Srrs			} else {
1825219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
1826219057Srrs					error = ENOTSUP;
1827219057Srrs				} else {
1828223132Stuexen					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt);
1829223132Stuexen					*optsize = sizeof(struct sctp_cc_option);
1830219057Srrs				}
1831219057Srrs				SCTP_TCB_UNLOCK(stcb);
1832219057Srrs			}
1833223132Stuexen			break;
1834219057Srrs		}
1835217760Stuexen	case SCTP_PLUGGABLE_SS:
1836217760Stuexen		{
1837217760Stuexen			struct sctp_assoc_value *av;
1838217760Stuexen
1839217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1840217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1841217760Stuexen			if (stcb) {
1842217760Stuexen				av->assoc_value = stcb->asoc.stream_scheduling_module;
1843217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1844217760Stuexen			} else {
1845224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1846224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1847224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1848223132Stuexen					SCTP_INP_RLOCK(inp);
1849223132Stuexen					av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
1850223132Stuexen					SCTP_INP_RUNLOCK(inp);
1851223132Stuexen				} else {
1852223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1853223132Stuexen					error = EINVAL;
1854223132Stuexen				}
1855217760Stuexen			}
1856223132Stuexen			if (error == 0) {
1857223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1858223132Stuexen			}
1859223132Stuexen			break;
1860217760Stuexen		}
1861217760Stuexen	case SCTP_SS_VALUE:
1862217760Stuexen		{
1863217760Stuexen			struct sctp_stream_value *av;
1864217760Stuexen
1865217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
1866217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1867217760Stuexen			if (stcb) {
1868277807Sdelphij				if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
1869277807Sdelphij				    (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
1870277807Sdelphij				    &av->stream_value) < 0)) {
1871217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1872217760Stuexen					error = EINVAL;
1873217760Stuexen				} else {
1874223132Stuexen					*optsize = sizeof(struct sctp_stream_value);
1875217760Stuexen				}
1876217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1877217760Stuexen			} else {
1878217760Stuexen				/*
1879217760Stuexen				 * Can't get stream value without
1880217760Stuexen				 * association
1881217760Stuexen				 */
1882217760Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1883217760Stuexen				error = EINVAL;
1884217760Stuexen			}
1885223132Stuexen			break;
1886217760Stuexen		}
1887163953Srrs	case SCTP_GET_ADDR_LEN:
1888163953Srrs		{
1889163953Srrs			struct sctp_assoc_value *av;
1890163953Srrs
1891166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1892163953Srrs			error = EINVAL;
1893167598Srrs#ifdef INET
1894163953Srrs			if (av->assoc_value == AF_INET) {
1895163953Srrs				av->assoc_value = sizeof(struct sockaddr_in);
1896163953Srrs				error = 0;
1897163953Srrs			}
1898163953Srrs#endif
1899167598Srrs#ifdef INET6
1900163953Srrs			if (av->assoc_value == AF_INET6) {
1901163953Srrs				av->assoc_value = sizeof(struct sockaddr_in6);
1902163953Srrs				error = 0;
1903163953Srrs			}
1904163953Srrs#endif
1905172091Srrs			if (error) {
1906171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1907223132Stuexen			} else {
1908223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1909172091Srrs			}
1910223132Stuexen			break;
1911163953Srrs		}
1912169655Srrs	case SCTP_GET_ASSOC_NUMBER:
1913163953Srrs		{
1914169655Srrs			uint32_t *value, cnt;
1915163953Srrs
1916169655Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1917163953Srrs			cnt = 0;
1918163953Srrs			SCTP_INP_RLOCK(inp);
1919169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1920169655Srrs				cnt++;
1921163953Srrs			}
1922169655Srrs			SCTP_INP_RUNLOCK(inp);
1923169655Srrs			*value = cnt;
1924169655Srrs			*optsize = sizeof(uint32_t);
1925223132Stuexen			break;
1926169655Srrs		}
1927169655Srrs	case SCTP_GET_ASSOC_ID_LIST:
1928169655Srrs		{
1929169655Srrs			struct sctp_assoc_ids *ids;
1930169655Srrs			unsigned int at, limit;
1931169655Srrs
1932169655Srrs			SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
1933163953Srrs			at = 0;
1934185694Srrs			limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t);
1935169655Srrs			SCTP_INP_RLOCK(inp);
1936169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1937169655Srrs				if (at < limit) {
1938169655Srrs					ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
1939169655Srrs				} else {
1940169655Srrs					error = EINVAL;
1941171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1942163953Srrs					break;
1943163953Srrs				}
1944163953Srrs			}
1945163953Srrs			SCTP_INP_RUNLOCK(inp);
1946223132Stuexen			if (error == 0) {
1947223132Stuexen				ids->gaids_number_of_ids = at;
1948223132Stuexen				*optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
1949223132Stuexen			}
1950223132Stuexen			break;
1951163953Srrs		}
1952163953Srrs	case SCTP_CONTEXT:
1953163953Srrs		{
1954163953Srrs			struct sctp_assoc_value *av;
1955163953Srrs
1956166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1957166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1958166675Srrs
1959166675Srrs			if (stcb) {
1960166675Srrs				av->assoc_value = stcb->asoc.context;
1961166675Srrs				SCTP_TCB_UNLOCK(stcb);
1962163953Srrs			} else {
1963224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
1964224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
1965224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
1966223132Stuexen					SCTP_INP_RLOCK(inp);
1967223132Stuexen					av->assoc_value = inp->sctp_context;
1968223132Stuexen					SCTP_INP_RUNLOCK(inp);
1969223132Stuexen				} else {
1970223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1971223132Stuexen					error = EINVAL;
1972223132Stuexen				}
1973163953Srrs			}
1974223132Stuexen			if (error == 0) {
1975223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
1976223132Stuexen			}
1977223132Stuexen			break;
1978163953Srrs		}
1979167598Srrs	case SCTP_VRF_ID:
1980167598Srrs		{
1981170056Srrs			uint32_t *default_vrfid;
1982167598Srrs
1983170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
1984170056Srrs			*default_vrfid = inp->def_vrf_id;
1985223132Stuexen			*optsize = sizeof(uint32_t);
1986167598Srrs			break;
1987167598Srrs		}
1988167598Srrs	case SCTP_GET_ASOC_VRF:
1989167598Srrs		{
1990167598Srrs			struct sctp_assoc_value *id;
1991167598Srrs
1992167598Srrs			SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
1993167598Srrs			SCTP_FIND_STCB(inp, stcb, id->assoc_id);
1994167598Srrs			if (stcb == NULL) {
1995167598Srrs				error = EINVAL;
1996171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1997223132Stuexen			} else {
1998223132Stuexen				id->assoc_value = stcb->asoc.vrf_id;
1999223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2000167598Srrs			}
2001167598Srrs			break;
2002167598Srrs		}
2003167598Srrs	case SCTP_GET_VRF_IDS:
2004167598Srrs		{
2005171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
2006167598Srrs			error = EOPNOTSUPP;
2007167598Srrs			break;
2008167598Srrs		}
2009163953Srrs	case SCTP_GET_NONCE_VALUES:
2010163953Srrs		{
2011163953Srrs			struct sctp_get_nonce_values *gnv;
2012163953Srrs
2013166675Srrs			SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
2014166675Srrs			SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
2015166675Srrs
2016166675Srrs			if (stcb) {
2017163953Srrs				gnv->gn_peers_tag = stcb->asoc.peer_vtag;
2018163953Srrs				gnv->gn_local_tag = stcb->asoc.my_vtag;
2019163953Srrs				SCTP_TCB_UNLOCK(stcb);
2020223132Stuexen				*optsize = sizeof(struct sctp_get_nonce_values);
2021166675Srrs			} else {
2022171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2023166675Srrs				error = ENOTCONN;
2024163953Srrs			}
2025223132Stuexen			break;
2026163953Srrs		}
2027170056Srrs	case SCTP_DELAYED_SACK:
2028163953Srrs		{
2029170056Srrs			struct sctp_sack_info *sack;
2030163953Srrs
2031170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
2032170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
2033166675Srrs			if (stcb) {
2034170056Srrs				sack->sack_delay = stcb->asoc.delayed_ack;
2035170056Srrs				sack->sack_freq = stcb->asoc.sack_freq;
2036166675Srrs				SCTP_TCB_UNLOCK(stcb);
2037166675Srrs			} else {
2038224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2039224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2040224918Stuexen				    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) {
2041223132Stuexen					SCTP_INP_RLOCK(inp);
2042223132Stuexen					sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
2043223132Stuexen					sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
2044223132Stuexen					SCTP_INP_RUNLOCK(inp);
2045223132Stuexen				} else {
2046223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2047223132Stuexen					error = EINVAL;
2048223132Stuexen				}
2049163953Srrs			}
2050223132Stuexen			if (error == 0) {
2051223132Stuexen				*optsize = sizeof(struct sctp_sack_info);
2052223132Stuexen			}
2053223132Stuexen			break;
2054163953Srrs		}
2055163953Srrs	case SCTP_GET_SNDBUF_USE:
2056166675Srrs		{
2057163953Srrs			struct sctp_sockstat *ss;
2058163953Srrs
2059166675Srrs			SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
2060166675Srrs			SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
2061166675Srrs
2062166675Srrs			if (stcb) {
2063166675Srrs				ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
2064166675Srrs				ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
2065166675Srrs				    stcb->asoc.size_on_all_streams);
2066166675Srrs				SCTP_TCB_UNLOCK(stcb);
2067223132Stuexen				*optsize = sizeof(struct sctp_sockstat);
2068166675Srrs			} else {
2069171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2070163953Srrs				error = ENOTCONN;
2071163953Srrs			}
2072223132Stuexen			break;
2073163953Srrs		}
2074170056Srrs	case SCTP_MAX_BURST:
2075163953Srrs		{
2076217895Stuexen			struct sctp_assoc_value *av;
2077163953Srrs
2078217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2079217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2080166675Srrs
2081217895Stuexen			if (stcb) {
2082217895Stuexen				av->assoc_value = stcb->asoc.max_burst;
2083217895Stuexen				SCTP_TCB_UNLOCK(stcb);
2084217894Stuexen			} else {
2085224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2086224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2087224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2088223132Stuexen					SCTP_INP_RLOCK(inp);
2089223132Stuexen					av->assoc_value = inp->sctp_ep.max_burst;
2090223132Stuexen					SCTP_INP_RUNLOCK(inp);
2091223132Stuexen				} else {
2092223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2093223132Stuexen					error = EINVAL;
2094223132Stuexen				}
2095217894Stuexen			}
2096223132Stuexen			if (error == 0) {
2097223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2098223132Stuexen			}
2099223132Stuexen			break;
2100163953Srrs		}
2101163953Srrs	case SCTP_MAXSEG:
2102163953Srrs		{
2103167598Srrs			struct sctp_assoc_value *av;
2104163953Srrs			int ovh;
2105163953Srrs
2106167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2107170056Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2108163953Srrs
2109167598Srrs			if (stcb) {
2110167598Srrs				av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
2111167598Srrs				SCTP_TCB_UNLOCK(stcb);
2112163953Srrs			} else {
2113224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2114224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2115224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
2116223132Stuexen					SCTP_INP_RLOCK(inp);
2117223132Stuexen					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2118223132Stuexen						ovh = SCTP_MED_OVERHEAD;
2119223132Stuexen					} else {
2120223132Stuexen						ovh = SCTP_MED_V4_OVERHEAD;
2121223132Stuexen					}
2122223132Stuexen					if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
2123223132Stuexen						av->assoc_value = 0;
2124223132Stuexen					else
2125223132Stuexen						av->assoc_value = inp->sctp_frag_point - ovh;
2126223132Stuexen					SCTP_INP_RUNLOCK(inp);
2127167598Srrs				} else {
2128223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2129223132Stuexen					error = EINVAL;
2130167598Srrs				}
2131163953Srrs			}
2132223132Stuexen			if (error == 0) {
2133223132Stuexen				*optsize = sizeof(struct sctp_assoc_value);
2134223132Stuexen			}
2135223132Stuexen			break;
2136163953Srrs		}
2137163953Srrs	case SCTP_GET_STAT_LOG:
2138167598Srrs		error = sctp_fill_stat_log(optval, optsize);
2139163953Srrs		break;
2140163953Srrs	case SCTP_EVENTS:
2141163953Srrs		{
2142163953Srrs			struct sctp_event_subscribe *events;
2143163953Srrs
2144166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
2145223132Stuexen			memset(events, 0, sizeof(struct sctp_event_subscribe));
2146163953Srrs			SCTP_INP_RLOCK(inp);
2147163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
2148163953Srrs				events->sctp_data_io_event = 1;
2149163953Srrs
2150163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
2151163953Srrs				events->sctp_association_event = 1;
2152163953Srrs
2153163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
2154163953Srrs				events->sctp_address_event = 1;
2155163953Srrs
2156163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
2157163953Srrs				events->sctp_send_failure_event = 1;
2158163953Srrs
2159163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
2160163953Srrs				events->sctp_peer_error_event = 1;
2161163953Srrs
2162163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
2163163953Srrs				events->sctp_shutdown_event = 1;
2164163953Srrs
2165163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
2166163953Srrs				events->sctp_partial_delivery_event = 1;
2167163953Srrs
2168163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
2169163953Srrs				events->sctp_adaptation_layer_event = 1;
2170163953Srrs
2171163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
2172163953Srrs				events->sctp_authentication_event = 1;
2173163953Srrs
2174185694Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
2175185694Srrs				events->sctp_sender_dry_event = 1;
2176185694Srrs
2177163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
2178202520Srrs				events->sctp_stream_reset_event = 1;
2179163953Srrs			SCTP_INP_RUNLOCK(inp);
2180166675Srrs			*optsize = sizeof(struct sctp_event_subscribe);
2181223132Stuexen			break;
2182163953Srrs		}
2183163953Srrs	case SCTP_ADAPTATION_LAYER:
2184166675Srrs		{
2185166675Srrs			uint32_t *value;
2186166675Srrs
2187166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2188166675Srrs
2189166675Srrs			SCTP_INP_RLOCK(inp);
2190166675Srrs			*value = inp->sctp_ep.adaptation_layer_indicator;
2191166675Srrs			SCTP_INP_RUNLOCK(inp);
2192166675Srrs			*optsize = sizeof(uint32_t);
2193223132Stuexen			break;
2194163953Srrs		}
2195163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
2196166675Srrs		{
2197166675Srrs			uint32_t *value;
2198166675Srrs
2199166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2200166675Srrs			SCTP_INP_RLOCK(inp);
2201166675Srrs			*value = inp->sctp_ep.initial_sequence_debug;
2202166675Srrs			SCTP_INP_RUNLOCK(inp);
2203166675Srrs			*optsize = sizeof(uint32_t);
2204223132Stuexen			break;
2205163953Srrs		}
2206163953Srrs	case SCTP_GET_LOCAL_ADDR_SIZE:
2207166675Srrs		{
2208166675Srrs			uint32_t *value;
2209166675Srrs
2210166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2211166675Srrs			SCTP_INP_RLOCK(inp);
2212168124Srrs			*value = sctp_count_max_addresses(inp);
2213166675Srrs			SCTP_INP_RUNLOCK(inp);
2214166675Srrs			*optsize = sizeof(uint32_t);
2215223132Stuexen			break;
2216163953Srrs		}
2217163953Srrs	case SCTP_GET_REMOTE_ADDR_SIZE:
2218163953Srrs		{
2219166675Srrs			uint32_t *value;
2220166675Srrs			size_t size;
2221163953Srrs			struct sctp_nets *net;
2222163953Srrs
2223166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2224166675Srrs			/* FIXME MT: change to sctp_assoc_value? */
2225166675Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
2226166675Srrs
2227166675Srrs			if (stcb) {
2228166675Srrs				size = 0;
2229166675Srrs				/* Count the sizes */
2230166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2231283699Stuexen					switch (net->ro._l_addr.sa.sa_family) {
2232221249Stuexen#ifdef INET
2233283699Stuexen					case AF_INET:
2234283699Stuexen#ifdef INET6
2235283699Stuexen						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2236283699Stuexen							size += sizeof(struct sockaddr_in6);
2237283699Stuexen						} else {
2238221249Stuexen							size += sizeof(struct sockaddr_in);
2239283699Stuexen						}
2240283699Stuexen#else
2241283699Stuexen						size += sizeof(struct sockaddr_in);
2242221249Stuexen#endif
2243283699Stuexen						break;
2244283699Stuexen#endif
2245221249Stuexen#ifdef INET6
2246283699Stuexen					case AF_INET6:
2247283699Stuexen						size += sizeof(struct sockaddr_in6);
2248283699Stuexen						break;
2249221249Stuexen#endif
2250283699Stuexen					default:
2251283699Stuexen						break;
2252166675Srrs					}
2253163953Srrs				}
2254166675Srrs				SCTP_TCB_UNLOCK(stcb);
2255166675Srrs				*value = (uint32_t) size;
2256223132Stuexen				*optsize = sizeof(uint32_t);
2257166675Srrs			} else {
2258171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2259166675Srrs				error = ENOTCONN;
2260163953Srrs			}
2261223132Stuexen			break;
2262163953Srrs		}
2263163953Srrs	case SCTP_GET_PEER_ADDRESSES:
2264163953Srrs		/*
2265163953Srrs		 * Get the address information, an array is passed in to
2266163953Srrs		 * fill up we pack it.
2267163953Srrs		 */
2268163953Srrs		{
2269166675Srrs			size_t cpsz, left;
2270163953Srrs			struct sockaddr_storage *sas;
2271163953Srrs			struct sctp_nets *net;
2272163953Srrs			struct sctp_getaddresses *saddr;
2273163953Srrs
2274166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2275166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2276163953Srrs
2277166675Srrs			if (stcb) {
2278166675Srrs				left = (*optsize) - sizeof(struct sctp_getaddresses);
2279166675Srrs				*optsize = sizeof(struct sctp_getaddresses);
2280166675Srrs				sas = (struct sockaddr_storage *)&saddr->addr[0];
2281166675Srrs
2282166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2283283699Stuexen					switch (net->ro._l_addr.sa.sa_family) {
2284221249Stuexen#ifdef INET
2285283699Stuexen					case AF_INET:
2286283699Stuexen#ifdef INET6
2287283699Stuexen						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2288283699Stuexen							cpsz = sizeof(struct sockaddr_in6);
2289283699Stuexen						} else {
2290221249Stuexen							cpsz = sizeof(struct sockaddr_in);
2291283699Stuexen						}
2292283699Stuexen#else
2293283699Stuexen						cpsz = sizeof(struct sockaddr_in);
2294221249Stuexen#endif
2295283699Stuexen						break;
2296283699Stuexen#endif
2297221249Stuexen#ifdef INET6
2298283699Stuexen					case AF_INET6:
2299283699Stuexen						cpsz = sizeof(struct sockaddr_in6);
2300283699Stuexen						break;
2301221249Stuexen#endif
2302283699Stuexen					default:
2303283699Stuexen						cpsz = 0;
2304283699Stuexen						break;
2305221249Stuexen					}
2306221249Stuexen					if (cpsz == 0) {
2307166675Srrs						break;
2308166675Srrs					}
2309166675Srrs					if (left < cpsz) {
2310166675Srrs						/* not enough room. */
2311166675Srrs						break;
2312166675Srrs					}
2313221249Stuexen#if defined(INET) && defined(INET6)
2314178251Srrs					if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
2315283699Stuexen					    (net->ro._l_addr.sa.sa_family == AF_INET)) {
2316166675Srrs						/* Must map the address */
2317283699Stuexen						in6_sin_2_v4mapsin6(&net->ro._l_addr.sin,
2318166675Srrs						    (struct sockaddr_in6 *)sas);
2319166675Srrs					} else {
2320166675Srrs						memcpy(sas, &net->ro._l_addr, cpsz);
2321166675Srrs					}
2322283699Stuexen#else
2323283699Stuexen					memcpy(sas, &net->ro._l_addr, cpsz);
2324178251Srrs#endif
2325166675Srrs					((struct sockaddr_in *)sas)->sin_port = stcb->rport;
2326166675Srrs
2327166675Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
2328166675Srrs					left -= cpsz;
2329166675Srrs					*optsize += cpsz;
2330163953Srrs				}
2331166675Srrs				SCTP_TCB_UNLOCK(stcb);
2332166675Srrs			} else {
2333171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2334166675Srrs				error = ENOENT;
2335163953Srrs			}
2336223132Stuexen			break;
2337163953Srrs		}
2338163953Srrs	case SCTP_GET_LOCAL_ADDRESSES:
2339163953Srrs		{
2340166675Srrs			size_t limit, actual;
2341163953Srrs			struct sockaddr_storage *sas;
2342163953Srrs			struct sctp_getaddresses *saddr;
2343163953Srrs
2344166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2345166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2346163953Srrs
2347163953Srrs			sas = (struct sockaddr_storage *)&saddr->addr[0];
2348166675Srrs			limit = *optsize - sizeof(sctp_assoc_t);
2349168124Srrs			actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
2350169655Srrs			if (stcb) {
2351163953Srrs				SCTP_TCB_UNLOCK(stcb);
2352169655Srrs			}
2353166675Srrs			*optsize = sizeof(struct sockaddr_storage) + actual;
2354223132Stuexen			break;
2355163953Srrs		}
2356163953Srrs	case SCTP_PEER_ADDR_PARAMS:
2357163953Srrs		{
2358163953Srrs			struct sctp_paddrparams *paddrp;
2359163953Srrs			struct sctp_nets *net;
2360283699Stuexen			struct sockaddr *addr;
2361163953Srrs
2362283699Stuexen#if defined(INET) && defined(INET6)
2363283699Stuexen			struct sockaddr_in sin_store;
2364283699Stuexen
2365283699Stuexen#endif
2366283699Stuexen
2367166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
2368166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
2369163953Srrs
2370283699Stuexen#if defined(INET) && defined(INET6)
2371283699Stuexen			if (paddrp->spp_address.ss_family == AF_INET6) {
2372283699Stuexen				struct sockaddr_in6 *sin6;
2373283699Stuexen
2374283699Stuexen				sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
2375283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
2376283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
2377283699Stuexen					addr = (struct sockaddr *)&sin_store;
2378283699Stuexen				} else {
2379283699Stuexen					addr = (struct sockaddr *)&paddrp->spp_address;
2380283699Stuexen				}
2381166675Srrs			} else {
2382283699Stuexen				addr = (struct sockaddr *)&paddrp->spp_address;
2383283699Stuexen			}
2384283699Stuexen#else
2385283699Stuexen			addr = (struct sockaddr *)&paddrp->spp_address;
2386283699Stuexen#endif
2387283699Stuexen			if (stcb != NULL) {
2388283699Stuexen				net = sctp_findnet(stcb, addr);
2389283699Stuexen			} else {
2390166675Srrs				/*
2391166675Srrs				 * We increment here since
2392166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2393166675Srrs				 * decrement if it finds the stcb as long as
2394166675Srrs				 * the locked tcb (last argument) is NOT a
2395166675Srrs				 * TCB.. aka NULL.
2396166675Srrs				 */
2397283699Stuexen				net = NULL;
2398166675Srrs				SCTP_INP_INCR_REF(inp);
2399283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
2400163953Srrs				if (stcb == NULL) {
2401166675Srrs					SCTP_INP_DECR_REF(inp);
2402163953Srrs				}
2403163953Srrs			}
2404283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
2405221249Stuexen#ifdef INET
2406283699Stuexen				if (addr->sa_family == AF_INET) {
2407171943Srrs					struct sockaddr_in *sin;
2408171943Srrs
2409283699Stuexen					sin = (struct sockaddr_in *)addr;
2410283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
2411171943Srrs						error = EINVAL;
2412171943Srrs						SCTP_TCB_UNLOCK(stcb);
2413171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2414171943Srrs						break;
2415171943Srrs					}
2416221249Stuexen				} else
2417221249Stuexen#endif
2418221249Stuexen#ifdef INET6
2419283699Stuexen				if (addr->sa_family == AF_INET6) {
2420171943Srrs					struct sockaddr_in6 *sin6;
2421171943Srrs
2422283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
2423171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
2424171943Srrs						error = EINVAL;
2425171943Srrs						SCTP_TCB_UNLOCK(stcb);
2426171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2427171943Srrs						break;
2428171943Srrs					}
2429221249Stuexen				} else
2430221249Stuexen#endif
2431221249Stuexen				{
2432171943Srrs					error = EAFNOSUPPORT;
2433171943Srrs					SCTP_TCB_UNLOCK(stcb);
2434171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2435171943Srrs					break;
2436171943Srrs				}
2437171943Srrs			}
2438283699Stuexen			if (stcb != NULL) {
2439224641Stuexen				/* Applies to the specific association */
2440163953Srrs				paddrp->spp_flags = 0;
2441283699Stuexen				if (net != NULL) {
2442224641Stuexen					paddrp->spp_hbinterval = net->heart_beat_delay;
2443163953Srrs					paddrp->spp_pathmaxrxt = net->failure_threshold;
2444283829Stuexen					paddrp->spp_pathmtu = net->mtu;
2445283829Stuexen					switch (net->ro._l_addr.sa.sa_family) {
2446283829Stuexen#ifdef INET
2447283829Stuexen					case AF_INET:
2448283829Stuexen						paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD;
2449283829Stuexen						break;
2450283829Stuexen#endif
2451283829Stuexen#ifdef INET6
2452283829Stuexen					case AF_INET6:
2453283829Stuexen						paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD;
2454283829Stuexen						break;
2455283829Stuexen#endif
2456283829Stuexen					default:
2457283829Stuexen						break;
2458283829Stuexen					}
2459163953Srrs					/* get flags for HB */
2460225635Stuexen					if (net->dest_state & SCTP_ADDR_NOHB) {
2461163953Srrs						paddrp->spp_flags |= SPP_HB_DISABLE;
2462225635Stuexen					} else {
2463163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2464225635Stuexen					}
2465163953Srrs					/* get flags for PMTU */
2466225635Stuexen					if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
2467284440Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2468284440Stuexen					} else {
2469163953Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2470163953Srrs					}
2471225549Stuexen					if (net->dscp & 0x01) {
2472226252Stuexen						paddrp->spp_dscp = net->dscp & 0xfc;
2473224870Stuexen						paddrp->spp_flags |= SPP_DSCP;
2474163953Srrs					}
2475167598Srrs#ifdef INET6
2476225549Stuexen					if ((net->ro._l_addr.sa.sa_family == AF_INET6) &&
2477225549Stuexen					    (net->flowlabel & 0x80000000)) {
2478225549Stuexen						paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff;
2479163953Srrs						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2480163953Srrs					}
2481163953Srrs#endif
2482163953Srrs				} else {
2483163953Srrs					/*
2484163953Srrs					 * No destination so return default
2485163953Srrs					 * value
2486163953Srrs					 */
2487163953Srrs					paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
2488283829Stuexen					paddrp->spp_pathmtu = 0;
2489225549Stuexen					if (stcb->asoc.default_dscp & 0x01) {
2490226252Stuexen						paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
2491225549Stuexen						paddrp->spp_flags |= SPP_DSCP;
2492225549Stuexen					}
2493167598Srrs#ifdef INET6
2494225549Stuexen					if (stcb->asoc.default_flowlabel & 0x80000000) {
2495225549Stuexen						paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff;
2496225549Stuexen						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2497225549Stuexen					}
2498163953Srrs#endif
2499163953Srrs					/* default settings should be these */
2500225635Stuexen					if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2501224641Stuexen						paddrp->spp_flags |= SPP_HB_DISABLE;
2502224641Stuexen					} else {
2503163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2504163953Srrs					}
2505225635Stuexen					if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
2506225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2507225635Stuexen					} else {
2508170056Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2509170056Srrs					}
2510225635Stuexen					paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
2511163953Srrs				}
2512163953Srrs				paddrp->spp_assoc_id = sctp_get_associd(stcb);
2513163953Srrs				SCTP_TCB_UNLOCK(stcb);
2514163953Srrs			} else {
2515224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2516224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2517224918Stuexen				    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
2518223132Stuexen					/* Use endpoint defaults */
2519223132Stuexen					SCTP_INP_RLOCK(inp);
2520223132Stuexen					paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
2521223132Stuexen					paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
2522223132Stuexen					paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
2523223132Stuexen					/* get inp's default */
2524225549Stuexen					if (inp->sctp_ep.default_dscp & 0x01) {
2525226252Stuexen						paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc;
2526225549Stuexen						paddrp->spp_flags |= SPP_DSCP;
2527225549Stuexen					}
2528167598Srrs#ifdef INET6
2529225549Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
2530225549Stuexen					    (inp->sctp_ep.default_flowlabel & 0x80000000)) {
2531225549Stuexen						paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff;
2532223132Stuexen						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2533223132Stuexen					}
2534163953Srrs#endif
2535223132Stuexen					/* can't return this */
2536223132Stuexen					paddrp->spp_pathmtu = 0;
2537170056Srrs
2538223132Stuexen					if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2539223132Stuexen						paddrp->spp_flags |= SPP_HB_ENABLE;
2540223132Stuexen					} else {
2541223132Stuexen						paddrp->spp_flags |= SPP_HB_DISABLE;
2542223132Stuexen					}
2543225635Stuexen					if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
2544225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2545225635Stuexen					} else {
2546225635Stuexen						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2547225635Stuexen					}
2548223132Stuexen					SCTP_INP_RUNLOCK(inp);
2549170056Srrs				} else {
2550223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2551223132Stuexen					error = EINVAL;
2552170056Srrs				}
2553163953Srrs			}
2554223132Stuexen			if (error == 0) {
2555223132Stuexen				*optsize = sizeof(struct sctp_paddrparams);
2556223132Stuexen			}
2557223132Stuexen			break;
2558163953Srrs		}
2559163953Srrs	case SCTP_GET_PEER_ADDR_INFO:
2560163953Srrs		{
2561163953Srrs			struct sctp_paddrinfo *paddri;
2562163953Srrs			struct sctp_nets *net;
2563283699Stuexen			struct sockaddr *addr;
2564163953Srrs
2565283699Stuexen#if defined(INET) && defined(INET6)
2566283699Stuexen			struct sockaddr_in sin_store;
2567283699Stuexen
2568283699Stuexen#endif
2569283699Stuexen
2570166675Srrs			SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
2571166675Srrs			SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
2572166675Srrs
2573283699Stuexen#if defined(INET) && defined(INET6)
2574283699Stuexen			if (paddri->spinfo_address.ss_family == AF_INET6) {
2575283699Stuexen				struct sockaddr_in6 *sin6;
2576283699Stuexen
2577283699Stuexen				sin6 = (struct sockaddr_in6 *)&paddri->spinfo_address;
2578283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
2579283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
2580283699Stuexen					addr = (struct sockaddr *)&sin_store;
2581283699Stuexen				} else {
2582283699Stuexen					addr = (struct sockaddr *)&paddri->spinfo_address;
2583283699Stuexen				}
2584166675Srrs			} else {
2585283699Stuexen				addr = (struct sockaddr *)&paddri->spinfo_address;
2586283699Stuexen			}
2587283699Stuexen#else
2588283699Stuexen			addr = (struct sockaddr *)&paddri->spinfo_address;
2589283699Stuexen#endif
2590283699Stuexen			if (stcb != NULL) {
2591283699Stuexen				net = sctp_findnet(stcb, addr);
2592283699Stuexen			} else {
2593166675Srrs				/*
2594166675Srrs				 * We increment here since
2595166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2596166675Srrs				 * decrement if it finds the stcb as long as
2597166675Srrs				 * the locked tcb (last argument) is NOT a
2598166675Srrs				 * TCB.. aka NULL.
2599166675Srrs				 */
2600283699Stuexen				net = NULL;
2601166675Srrs				SCTP_INP_INCR_REF(inp);
2602283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
2603166675Srrs				if (stcb == NULL) {
2604166675Srrs					SCTP_INP_DECR_REF(inp);
2605163953Srrs				}
2606166675Srrs			}
2607163953Srrs
2608283699Stuexen			if ((stcb != NULL) && (net != NULL)) {
2609217635Srrs				if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2610217638Stuexen					/* It's unconfirmed */
2611217635Srrs					paddri->spinfo_state = SCTP_UNCONFIRMED;
2612217635Srrs				} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2613217638Stuexen					/* It's active */
2614217635Srrs					paddri->spinfo_state = SCTP_ACTIVE;
2615217635Srrs				} else {
2616217638Stuexen					/* It's inactive */
2617217635Srrs					paddri->spinfo_state = SCTP_INACTIVE;
2618217635Srrs				}
2619166675Srrs				paddri->spinfo_cwnd = net->cwnd;
2620219014Stuexen				paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2621166675Srrs				paddri->spinfo_rto = net->RTO;
2622166675Srrs				paddri->spinfo_assoc_id = sctp_get_associd(stcb);
2623222029Stuexen				paddri->spinfo_mtu = net->mtu;
2624283829Stuexen				switch (addr->sa_family) {
2625283829Stuexen#if defined(INET)
2626283829Stuexen				case AF_INET:
2627283829Stuexen					paddri->spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
2628283829Stuexen					break;
2629283829Stuexen#endif
2630283829Stuexen#if defined(INET6)
2631283829Stuexen				case AF_INET6:
2632283829Stuexen					paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD;
2633283829Stuexen					break;
2634283829Stuexen#endif
2635283829Stuexen				default:
2636283829Stuexen					break;
2637283829Stuexen				}
2638166675Srrs				SCTP_TCB_UNLOCK(stcb);
2639223132Stuexen				*optsize = sizeof(struct sctp_paddrinfo);
2640163953Srrs			} else {
2641283699Stuexen				if (stcb != NULL) {
2642163953Srrs					SCTP_TCB_UNLOCK(stcb);
2643163953Srrs				}
2644171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2645163953Srrs				error = ENOENT;
2646163953Srrs			}
2647223132Stuexen			break;
2648163953Srrs		}
2649163953Srrs	case SCTP_PCB_STATUS:
2650163953Srrs		{
2651163953Srrs			struct sctp_pcbinfo *spcb;
2652163953Srrs
2653166675Srrs			SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
2654163953Srrs			sctp_fill_pcbinfo(spcb);
2655166675Srrs			*optsize = sizeof(struct sctp_pcbinfo);
2656223132Stuexen			break;
2657163953Srrs		}
2658163953Srrs	case SCTP_STATUS:
2659163953Srrs		{
2660163953Srrs			struct sctp_nets *net;
2661163953Srrs			struct sctp_status *sstat;
2662163953Srrs
2663166675Srrs			SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
2664166675Srrs			SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
2665163953Srrs
2666163953Srrs			if (stcb == NULL) {
2667223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2668163953Srrs				error = EINVAL;
2669163953Srrs				break;
2670163953Srrs			}
2671294149Stuexen			sstat->sstat_state = sctp_map_assoc_state(stcb->asoc.state);
2672173179Srrs			sstat->sstat_assoc_id = sctp_get_associd(stcb);
2673163953Srrs			sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
2674163953Srrs			sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
2675163953Srrs			/*
2676163953Srrs			 * We can't include chunks that have been passed to
2677163953Srrs			 * the socket layer. Only things in queue.
2678163953Srrs			 */
2679163953Srrs			sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
2680163953Srrs			    stcb->asoc.cnt_on_all_streams);
2681163953Srrs
2682163953Srrs
2683163953Srrs			sstat->sstat_instrms = stcb->asoc.streamincnt;
2684163953Srrs			sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
2685163953Srrs			sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
2686163953Srrs			memcpy(&sstat->sstat_primary.spinfo_address,
2687163953Srrs			    &stcb->asoc.primary_destination->ro._l_addr,
2688163953Srrs			    ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
2689163953Srrs			net = stcb->asoc.primary_destination;
2690163953Srrs			((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
2691163953Srrs			/*
2692163953Srrs			 * Again the user can get info from sctp_constants.h
2693163953Srrs			 * for what the state of the network is.
2694163953Srrs			 */
2695217635Srrs			if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2696217635Srrs				/* It's unconfirmed */
2697217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
2698217635Srrs			} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2699217638Stuexen				/* It's active */
2700217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
2701217635Srrs			} else {
2702217638Stuexen				/* It's inactive */
2703217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
2704217635Srrs			}
2705163953Srrs			sstat->sstat_primary.spinfo_cwnd = net->cwnd;
2706219014Stuexen			sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2707163953Srrs			sstat->sstat_primary.spinfo_rto = net->RTO;
2708163953Srrs			sstat->sstat_primary.spinfo_mtu = net->mtu;
2709283829Stuexen			switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) {
2710283829Stuexen#if defined(INET)
2711283829Stuexen			case AF_INET:
2712283829Stuexen				sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
2713283829Stuexen				break;
2714283829Stuexen#endif
2715283829Stuexen#if defined(INET6)
2716283829Stuexen			case AF_INET6:
2717283829Stuexen				sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD;
2718283829Stuexen				break;
2719283829Stuexen#endif
2720283829Stuexen			default:
2721283829Stuexen				break;
2722283829Stuexen			}
2723163953Srrs			sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
2724163953Srrs			SCTP_TCB_UNLOCK(stcb);
2725223132Stuexen			*optsize = sizeof(struct sctp_status);
2726223132Stuexen			break;
2727163953Srrs		}
2728163953Srrs	case SCTP_RTOINFO:
2729163953Srrs		{
2730163953Srrs			struct sctp_rtoinfo *srto;
2731163953Srrs
2732166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
2733166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
2734166675Srrs
2735166675Srrs			if (stcb) {
2736166675Srrs				srto->srto_initial = stcb->asoc.initial_rto;
2737166675Srrs				srto->srto_max = stcb->asoc.maxrto;
2738166675Srrs				srto->srto_min = stcb->asoc.minrto;
2739166675Srrs				SCTP_TCB_UNLOCK(stcb);
2740166675Srrs			} else {
2741224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2742224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2743224918Stuexen				    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
2744223132Stuexen					SCTP_INP_RLOCK(inp);
2745223132Stuexen					srto->srto_initial = inp->sctp_ep.initial_rto;
2746223132Stuexen					srto->srto_max = inp->sctp_ep.sctp_maxrto;
2747223132Stuexen					srto->srto_min = inp->sctp_ep.sctp_minrto;
2748223132Stuexen					SCTP_INP_RUNLOCK(inp);
2749223132Stuexen				} else {
2750223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2751223132Stuexen					error = EINVAL;
2752223132Stuexen				}
2753163953Srrs			}
2754223132Stuexen			if (error == 0) {
2755223132Stuexen				*optsize = sizeof(struct sctp_rtoinfo);
2756223132Stuexen			}
2757223132Stuexen			break;
2758163953Srrs		}
2759215410Stuexen	case SCTP_TIMEOUTS:
2760215410Stuexen		{
2761215410Stuexen			struct sctp_timeouts *stimo;
2762215410Stuexen
2763215410Stuexen			SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize);
2764215410Stuexen			SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id);
2765215410Stuexen
2766215410Stuexen			if (stcb) {
2767215410Stuexen				stimo->stimo_init = stcb->asoc.timoinit;
2768215410Stuexen				stimo->stimo_data = stcb->asoc.timodata;
2769215410Stuexen				stimo->stimo_sack = stcb->asoc.timosack;
2770215410Stuexen				stimo->stimo_shutdown = stcb->asoc.timoshutdown;
2771215410Stuexen				stimo->stimo_heartbeat = stcb->asoc.timoheartbeat;
2772215410Stuexen				stimo->stimo_cookie = stcb->asoc.timocookie;
2773215410Stuexen				stimo->stimo_shutdownack = stcb->asoc.timoshutdownack;
2774215410Stuexen				SCTP_TCB_UNLOCK(stcb);
2775223132Stuexen				*optsize = sizeof(struct sctp_timeouts);
2776215410Stuexen			} else {
2777223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2778215410Stuexen				error = EINVAL;
2779215410Stuexen			}
2780223132Stuexen			break;
2781215410Stuexen		}
2782163953Srrs	case SCTP_ASSOCINFO:
2783163953Srrs		{
2784163953Srrs			struct sctp_assocparams *sasoc;
2785163953Srrs
2786166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
2787166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
2788163953Srrs
2789163953Srrs			if (stcb) {
2790171477Srrs				sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
2791163953Srrs				sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
2792163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
2793163953Srrs				sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
2794163953Srrs				sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
2795163953Srrs				SCTP_TCB_UNLOCK(stcb);
2796163953Srrs			} else {
2797224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2798224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2799224918Stuexen				    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
2800223132Stuexen					SCTP_INP_RLOCK(inp);
2801223132Stuexen					sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
2802223132Stuexen					sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
2803223132Stuexen					sasoc->sasoc_number_peer_destinations = 0;
2804223132Stuexen					sasoc->sasoc_peer_rwnd = 0;
2805223132Stuexen					sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
2806223132Stuexen					SCTP_INP_RUNLOCK(inp);
2807223132Stuexen				} else {
2808223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2809223132Stuexen					error = EINVAL;
2810223132Stuexen				}
2811163953Srrs			}
2812223132Stuexen			if (error == 0) {
2813223132Stuexen				*optsize = sizeof(struct sctp_assocparams);
2814223132Stuexen			}
2815223132Stuexen			break;
2816163953Srrs		}
2817163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
2818163953Srrs		{
2819163953Srrs			struct sctp_sndrcvinfo *s_info;
2820163953Srrs
2821166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
2822166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
2823166675Srrs
2824166675Srrs			if (stcb) {
2825170056Srrs				memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
2826166675Srrs				SCTP_TCB_UNLOCK(stcb);
2827166675Srrs			} else {
2828224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2829224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2830224918Stuexen				    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) {
2831223132Stuexen					SCTP_INP_RLOCK(inp);
2832223132Stuexen					memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
2833223132Stuexen					SCTP_INP_RUNLOCK(inp);
2834223132Stuexen				} else {
2835223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2836223132Stuexen					error = EINVAL;
2837223132Stuexen				}
2838163953Srrs			}
2839223132Stuexen			if (error == 0) {
2840223132Stuexen				*optsize = sizeof(struct sctp_sndrcvinfo);
2841223132Stuexen			}
2842223132Stuexen			break;
2843163953Srrs		}
2844163953Srrs	case SCTP_INITMSG:
2845163953Srrs		{
2846163953Srrs			struct sctp_initmsg *sinit;
2847163953Srrs
2848166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
2849163953Srrs			SCTP_INP_RLOCK(inp);
2850163953Srrs			sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
2851163953Srrs			sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
2852163953Srrs			sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
2853163953Srrs			sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
2854163953Srrs			SCTP_INP_RUNLOCK(inp);
2855223132Stuexen			*optsize = sizeof(struct sctp_initmsg);
2856223132Stuexen			break;
2857163953Srrs		}
2858163953Srrs	case SCTP_PRIMARY_ADDR:
2859163953Srrs		/* we allow a "get" operation on this */
2860163953Srrs		{
2861163953Srrs			struct sctp_setprim *ssp;
2862163953Srrs
2863166675Srrs			SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
2864166675Srrs			SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
2865166675Srrs
2866166675Srrs			if (stcb) {
2867283699Stuexen				union sctp_sockstore *addr;
2868170056Srrs
2869283699Stuexen				addr = &stcb->asoc.primary_destination->ro._l_addr;
2870283699Stuexen				switch (addr->sa.sa_family) {
2871283699Stuexen#ifdef INET
2872283699Stuexen				case AF_INET:
2873283699Stuexen#ifdef INET6
2874283699Stuexen					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2875283699Stuexen						in6_sin_2_v4mapsin6(&addr->sin,
2876283699Stuexen						    (struct sockaddr_in6 *)&ssp->ssp_addr);
2877283699Stuexen					} else {
2878283699Stuexen						memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
2879283699Stuexen					}
2880283699Stuexen#else
2881283699Stuexen					memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
2882283699Stuexen#endif
2883283699Stuexen					break;
2884283699Stuexen#endif
2885283699Stuexen#ifdef INET6
2886283699Stuexen				case AF_INET6:
2887283699Stuexen					memcpy(&ssp->ssp_addr, &addr->sin6, sizeof(struct sockaddr_in6));
2888283699Stuexen					break;
2889283699Stuexen#endif
2890283699Stuexen				default:
2891283699Stuexen					break;
2892283699Stuexen				}
2893166675Srrs				SCTP_TCB_UNLOCK(stcb);
2894223132Stuexen				*optsize = sizeof(struct sctp_setprim);
2895166675Srrs			} else {
2896223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2897163953Srrs				error = EINVAL;
2898163953Srrs			}
2899223132Stuexen			break;
2900163953Srrs		}
2901163953Srrs	case SCTP_HMAC_IDENT:
2902163953Srrs		{
2903163953Srrs			struct sctp_hmacalgo *shmac;
2904163953Srrs			sctp_hmaclist_t *hmaclist;
2905163953Srrs			uint32_t size;
2906163953Srrs			int i;
2907163953Srrs
2908166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
2909166675Srrs
2910163953Srrs			SCTP_INP_RLOCK(inp);
2911163953Srrs			hmaclist = inp->sctp_ep.local_hmacs;
2912163953Srrs			if (hmaclist == NULL) {
2913163953Srrs				/* no HMACs to return */
2914166675Srrs				*optsize = sizeof(*shmac);
2915168299Srrs				SCTP_INP_RUNLOCK(inp);
2916163953Srrs				break;
2917163953Srrs			}
2918163953Srrs			/* is there room for all of the hmac ids? */
2919163953Srrs			size = sizeof(*shmac) + (hmaclist->num_algo *
2920163953Srrs			    sizeof(shmac->shmac_idents[0]));
2921166675Srrs			if ((size_t)(*optsize) < size) {
2922223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2923163953Srrs				error = EINVAL;
2924163953Srrs				SCTP_INP_RUNLOCK(inp);
2925163953Srrs				break;
2926163953Srrs			}
2927163953Srrs			/* copy in the list */
2928181054Srrs			shmac->shmac_number_of_idents = hmaclist->num_algo;
2929181054Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
2930163953Srrs				shmac->shmac_idents[i] = hmaclist->hmac[i];
2931181054Srrs			}
2932163953Srrs			SCTP_INP_RUNLOCK(inp);
2933166675Srrs			*optsize = size;
2934163953Srrs			break;
2935163953Srrs		}
2936163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
2937163953Srrs		{
2938163953Srrs			struct sctp_authkeyid *scact;
2939163953Srrs
2940166675Srrs			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
2941166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
2942166675Srrs
2943166675Srrs			if (stcb) {
2944163953Srrs				/* get the active key on the assoc */
2945185694Srrs				scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
2946163953Srrs				SCTP_TCB_UNLOCK(stcb);
2947163953Srrs			} else {
2948224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2949224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2950224918Stuexen				    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) {
2951223132Stuexen					/* get the endpoint active key */
2952223132Stuexen					SCTP_INP_RLOCK(inp);
2953223132Stuexen					scact->scact_keynumber = inp->sctp_ep.default_keyid;
2954223132Stuexen					SCTP_INP_RUNLOCK(inp);
2955223132Stuexen				} else {
2956223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2957223132Stuexen					error = EINVAL;
2958223132Stuexen				}
2959163953Srrs			}
2960223132Stuexen			if (error == 0) {
2961223132Stuexen				*optsize = sizeof(struct sctp_authkeyid);
2962223132Stuexen			}
2963163953Srrs			break;
2964163953Srrs		}
2965163953Srrs	case SCTP_LOCAL_AUTH_CHUNKS:
2966163953Srrs		{
2967163953Srrs			struct sctp_authchunks *sac;
2968163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2969166675Srrs			size_t size = 0;
2970163953Srrs
2971166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2972166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2973166675Srrs
2974166675Srrs			if (stcb) {
2975163953Srrs				/* get off the assoc */
2976163953Srrs				chklist = stcb->asoc.local_auth_chunks;
2977163953Srrs				/* is there enough space? */
2978163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2979166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2980163953Srrs					error = EINVAL;
2981171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2982166675Srrs				} else {
2983166675Srrs					/* copy in the chunks */
2984169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2985234832Stuexen					sac->gauth_number_of_chunks = (uint32_t) size;
2986223132Stuexen					*optsize = sizeof(struct sctp_authchunks) + size;
2987163953Srrs				}
2988163953Srrs				SCTP_TCB_UNLOCK(stcb);
2989163953Srrs			} else {
2990224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2991224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
2992224918Stuexen				    (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) {
2993223132Stuexen					/* get off the endpoint */
2994223132Stuexen					SCTP_INP_RLOCK(inp);
2995223132Stuexen					chklist = inp->sctp_ep.local_auth_chunks;
2996223132Stuexen					/* is there enough space? */
2997223132Stuexen					size = sctp_auth_get_chklist_size(chklist);
2998223132Stuexen					if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2999223132Stuexen						error = EINVAL;
3000223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3001223132Stuexen					} else {
3002223132Stuexen						/* copy in the chunks */
3003223132Stuexen						(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
3004234832Stuexen						sac->gauth_number_of_chunks = (uint32_t) size;
3005223132Stuexen						*optsize = sizeof(struct sctp_authchunks) + size;
3006223132Stuexen					}
3007223132Stuexen					SCTP_INP_RUNLOCK(inp);
3008223132Stuexen				} else {
3009223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3010163953Srrs					error = EINVAL;
3011163953Srrs				}
3012163953Srrs			}
3013163953Srrs			break;
3014163953Srrs		}
3015163953Srrs	case SCTP_PEER_AUTH_CHUNKS:
3016163953Srrs		{
3017163953Srrs			struct sctp_authchunks *sac;
3018163953Srrs			sctp_auth_chklist_t *chklist = NULL;
3019166675Srrs			size_t size = 0;
3020163953Srrs
3021166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
3022166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
3023166675Srrs
3024166675Srrs			if (stcb) {
3025166675Srrs				/* get off the assoc */
3026166675Srrs				chklist = stcb->asoc.peer_auth_chunks;
3027166675Srrs				/* is there enough space? */
3028166675Srrs				size = sctp_auth_get_chklist_size(chklist);
3029166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
3030166675Srrs					error = EINVAL;
3031171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3032166675Srrs				} else {
3033166675Srrs					/* copy in the chunks */
3034169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
3035234832Stuexen					sac->gauth_number_of_chunks = (uint32_t) size;
3036223132Stuexen					*optsize = sizeof(struct sctp_authchunks) + size;
3037166675Srrs				}
3038166675Srrs				SCTP_TCB_UNLOCK(stcb);
3039166675Srrs			} else {
3040171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
3041163953Srrs				error = ENOENT;
3042163953Srrs			}
3043163953Srrs			break;
3044163953Srrs		}
3045223132Stuexen	case SCTP_EVENT:
3046223132Stuexen		{
3047223132Stuexen			struct sctp_event *event;
3048223132Stuexen			uint32_t event_type;
3049163953Srrs
3050223132Stuexen			SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize);
3051223132Stuexen			SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
3052163953Srrs
3053223132Stuexen			switch (event->se_type) {
3054223132Stuexen			case SCTP_ASSOC_CHANGE:
3055223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
3056223132Stuexen				break;
3057223132Stuexen			case SCTP_PEER_ADDR_CHANGE:
3058223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
3059223132Stuexen				break;
3060223132Stuexen			case SCTP_REMOTE_ERROR:
3061223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPEERERR;
3062223132Stuexen				break;
3063223132Stuexen			case SCTP_SEND_FAILED:
3064223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
3065223132Stuexen				break;
3066223132Stuexen			case SCTP_SHUTDOWN_EVENT:
3067223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
3068223132Stuexen				break;
3069223132Stuexen			case SCTP_ADAPTATION_INDICATION:
3070223132Stuexen				event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
3071223132Stuexen				break;
3072223132Stuexen			case SCTP_PARTIAL_DELIVERY_EVENT:
3073223132Stuexen				event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
3074223132Stuexen				break;
3075223132Stuexen			case SCTP_AUTHENTICATION_EVENT:
3076223132Stuexen				event_type = SCTP_PCB_FLAGS_AUTHEVNT;
3077223132Stuexen				break;
3078223132Stuexen			case SCTP_STREAM_RESET_EVENT:
3079223132Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
3080223132Stuexen				break;
3081223132Stuexen			case SCTP_SENDER_DRY_EVENT:
3082223132Stuexen				event_type = SCTP_PCB_FLAGS_DRYEVNT;
3083223132Stuexen				break;
3084223132Stuexen			case SCTP_NOTIFICATIONS_STOPPED_EVENT:
3085223132Stuexen				event_type = 0;
3086223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
3087223132Stuexen				error = ENOTSUP;
3088223132Stuexen				break;
3089235009Stuexen			case SCTP_ASSOC_RESET_EVENT:
3090235009Stuexen				event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
3091235009Stuexen				break;
3092235009Stuexen			case SCTP_STREAM_CHANGE_EVENT:
3093235009Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
3094235009Stuexen				break;
3095235075Stuexen			case SCTP_SEND_FAILED_EVENT:
3096235075Stuexen				event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
3097235075Stuexen				break;
3098223132Stuexen			default:
3099223132Stuexen				event_type = 0;
3100223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3101223132Stuexen				error = EINVAL;
3102223132Stuexen				break;
3103223132Stuexen			}
3104223132Stuexen			if (event_type > 0) {
3105223132Stuexen				if (stcb) {
3106223132Stuexen					event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
3107223132Stuexen					SCTP_TCB_UNLOCK(stcb);
3108223132Stuexen				} else {
3109224918Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3110224918Stuexen					    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3111224918Stuexen					    (event->se_assoc_id == SCTP_FUTURE_ASSOC)) {
3112223132Stuexen						SCTP_INP_RLOCK(inp);
3113223132Stuexen						event->se_on = sctp_is_feature_on(inp, event_type);
3114223132Stuexen						SCTP_INP_RUNLOCK(inp);
3115223132Stuexen					} else {
3116223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3117223132Stuexen						error = EINVAL;
3118223132Stuexen					}
3119223132Stuexen				}
3120223132Stuexen			}
3121223132Stuexen			if (error == 0) {
3122223132Stuexen				*optsize = sizeof(struct sctp_event);
3123223132Stuexen			}
3124223132Stuexen			break;
3125223132Stuexen		}
3126223132Stuexen	case SCTP_RECVRCVINFO:
3127223132Stuexen		{
3128223132Stuexen			int onoff;
3129223132Stuexen
3130223132Stuexen			if (*optsize < sizeof(int)) {
3131223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3132223132Stuexen				error = EINVAL;
3133223132Stuexen			} else {
3134230104Stuexen				SCTP_INP_RLOCK(inp);
3135223132Stuexen				onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
3136223132Stuexen				SCTP_INP_RUNLOCK(inp);
3137223132Stuexen			}
3138223132Stuexen			if (error == 0) {
3139223132Stuexen				/* return the option value */
3140223132Stuexen				*(int *)optval = onoff;
3141223132Stuexen				*optsize = sizeof(int);
3142223132Stuexen			}
3143223132Stuexen			break;
3144223132Stuexen		}
3145223132Stuexen	case SCTP_RECVNXTINFO:
3146223132Stuexen		{
3147223132Stuexen			int onoff;
3148223132Stuexen
3149223132Stuexen			if (*optsize < sizeof(int)) {
3150223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3151223132Stuexen				error = EINVAL;
3152223132Stuexen			} else {
3153230104Stuexen				SCTP_INP_RLOCK(inp);
3154223132Stuexen				onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
3155223132Stuexen				SCTP_INP_RUNLOCK(inp);
3156223132Stuexen			}
3157223132Stuexen			if (error == 0) {
3158223132Stuexen				/* return the option value */
3159223132Stuexen				*(int *)optval = onoff;
3160223132Stuexen				*optsize = sizeof(int);
3161223132Stuexen			}
3162223132Stuexen			break;
3163223132Stuexen		}
3164223132Stuexen	case SCTP_DEFAULT_SNDINFO:
3165223132Stuexen		{
3166223132Stuexen			struct sctp_sndinfo *info;
3167223132Stuexen
3168223132Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize);
3169223132Stuexen			SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
3170223132Stuexen
3171223132Stuexen			if (stcb) {
3172223132Stuexen				info->snd_sid = stcb->asoc.def_send.sinfo_stream;
3173223132Stuexen				info->snd_flags = stcb->asoc.def_send.sinfo_flags;
3174223162Stuexen				info->snd_flags &= 0xfff0;
3175223132Stuexen				info->snd_ppid = stcb->asoc.def_send.sinfo_ppid;
3176223132Stuexen				info->snd_context = stcb->asoc.def_send.sinfo_context;
3177223132Stuexen				SCTP_TCB_UNLOCK(stcb);
3178223132Stuexen			} else {
3179224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3180224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3181224918Stuexen				    (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) {
3182223132Stuexen					SCTP_INP_RLOCK(inp);
3183223132Stuexen					info->snd_sid = inp->def_send.sinfo_stream;
3184223132Stuexen					info->snd_flags = inp->def_send.sinfo_flags;
3185223162Stuexen					info->snd_flags &= 0xfff0;
3186223132Stuexen					info->snd_ppid = inp->def_send.sinfo_ppid;
3187223132Stuexen					info->snd_context = inp->def_send.sinfo_context;
3188223132Stuexen					SCTP_INP_RUNLOCK(inp);
3189223132Stuexen				} else {
3190223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3191223132Stuexen					error = EINVAL;
3192223132Stuexen				}
3193223132Stuexen			}
3194223132Stuexen			if (error == 0) {
3195223132Stuexen				*optsize = sizeof(struct sctp_sndinfo);
3196223132Stuexen			}
3197223132Stuexen			break;
3198223132Stuexen		}
3199223162Stuexen	case SCTP_DEFAULT_PRINFO:
3200223162Stuexen		{
3201223162Stuexen			struct sctp_default_prinfo *info;
3202223162Stuexen
3203223162Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize);
3204223162Stuexen			SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
3205223162Stuexen
3206223162Stuexen			if (stcb) {
3207223162Stuexen				info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
3208223162Stuexen				info->pr_value = stcb->asoc.def_send.sinfo_timetolive;
3209223162Stuexen				SCTP_TCB_UNLOCK(stcb);
3210223162Stuexen			} else {
3211224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3212224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3213224918Stuexen				    (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) {
3214223162Stuexen					SCTP_INP_RLOCK(inp);
3215223162Stuexen					info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
3216223162Stuexen					info->pr_value = inp->def_send.sinfo_timetolive;
3217223162Stuexen					SCTP_INP_RUNLOCK(inp);
3218223162Stuexen				} else {
3219223162Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3220223162Stuexen					error = EINVAL;
3221223162Stuexen				}
3222223162Stuexen			}
3223223162Stuexen			if (error == 0) {
3224223162Stuexen				*optsize = sizeof(struct sctp_default_prinfo);
3225223162Stuexen			}
3226223162Stuexen			break;
3227223162Stuexen		}
3228224641Stuexen	case SCTP_PEER_ADDR_THLDS:
3229224641Stuexen		{
3230224641Stuexen			struct sctp_paddrthlds *thlds;
3231224641Stuexen			struct sctp_nets *net;
3232283699Stuexen			struct sockaddr *addr;
3233224641Stuexen
3234283699Stuexen#if defined(INET) && defined(INET6)
3235283699Stuexen			struct sockaddr_in sin_store;
3236283699Stuexen
3237283699Stuexen#endif
3238283699Stuexen
3239224641Stuexen			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
3240224641Stuexen			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
3241224641Stuexen
3242283699Stuexen#if defined(INET) && defined(INET6)
3243283699Stuexen			if (thlds->spt_address.ss_family == AF_INET6) {
3244283699Stuexen				struct sockaddr_in6 *sin6;
3245283699Stuexen
3246283699Stuexen				sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
3247283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3248283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
3249283699Stuexen					addr = (struct sockaddr *)&sin_store;
3250283699Stuexen				} else {
3251283699Stuexen					addr = (struct sockaddr *)&thlds->spt_address;
3252283699Stuexen				}
3253224641Stuexen			} else {
3254283699Stuexen				addr = (struct sockaddr *)&thlds->spt_address;
3255283699Stuexen			}
3256283699Stuexen#else
3257283699Stuexen			addr = (struct sockaddr *)&thlds->spt_address;
3258283699Stuexen#endif
3259283699Stuexen			if (stcb != NULL) {
3260283699Stuexen				net = sctp_findnet(stcb, addr);
3261283699Stuexen			} else {
3262224641Stuexen				/*
3263224641Stuexen				 * We increment here since
3264224641Stuexen				 * sctp_findassociation_ep_addr() wil do a
3265224641Stuexen				 * decrement if it finds the stcb as long as
3266224641Stuexen				 * the locked tcb (last argument) is NOT a
3267224641Stuexen				 * TCB.. aka NULL.
3268224641Stuexen				 */
3269283699Stuexen				net = NULL;
3270224641Stuexen				SCTP_INP_INCR_REF(inp);
3271283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
3272224641Stuexen				if (stcb == NULL) {
3273224641Stuexen					SCTP_INP_DECR_REF(inp);
3274224641Stuexen				}
3275224641Stuexen			}
3276283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
3277224641Stuexen#ifdef INET
3278283699Stuexen				if (addr->sa_family == AF_INET) {
3279224641Stuexen					struct sockaddr_in *sin;
3280224641Stuexen
3281283699Stuexen					sin = (struct sockaddr_in *)addr;
3282283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
3283224641Stuexen						error = EINVAL;
3284224641Stuexen						SCTP_TCB_UNLOCK(stcb);
3285224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3286224641Stuexen						break;
3287224641Stuexen					}
3288224641Stuexen				} else
3289224641Stuexen#endif
3290224641Stuexen#ifdef INET6
3291283699Stuexen				if (addr->sa_family == AF_INET6) {
3292224641Stuexen					struct sockaddr_in6 *sin6;
3293224641Stuexen
3294283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
3295224641Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3296224641Stuexen						error = EINVAL;
3297224641Stuexen						SCTP_TCB_UNLOCK(stcb);
3298224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3299224641Stuexen						break;
3300224641Stuexen					}
3301224641Stuexen				} else
3302224641Stuexen#endif
3303224641Stuexen				{
3304224641Stuexen					error = EAFNOSUPPORT;
3305224641Stuexen					SCTP_TCB_UNLOCK(stcb);
3306224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3307224641Stuexen					break;
3308224641Stuexen				}
3309224641Stuexen			}
3310283699Stuexen			if (stcb != NULL) {
3311283699Stuexen				if (net != NULL) {
3312224641Stuexen					thlds->spt_pathmaxrxt = net->failure_threshold;
3313224641Stuexen					thlds->spt_pathpfthld = net->pf_threshold;
3314224641Stuexen				} else {
3315224641Stuexen					thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
3316224641Stuexen					thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
3317224641Stuexen				}
3318224641Stuexen				thlds->spt_assoc_id = sctp_get_associd(stcb);
3319224641Stuexen				SCTP_TCB_UNLOCK(stcb);
3320224641Stuexen			} else {
3321224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3322224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3323224918Stuexen				    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
3324224641Stuexen					/* Use endpoint defaults */
3325224641Stuexen					SCTP_INP_RLOCK(inp);
3326224641Stuexen					thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
3327224641Stuexen					thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
3328224641Stuexen					SCTP_INP_RUNLOCK(inp);
3329224641Stuexen				} else {
3330224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3331224641Stuexen					error = EINVAL;
3332224641Stuexen				}
3333224641Stuexen			}
3334224641Stuexen			if (error == 0) {
3335224641Stuexen				*optsize = sizeof(struct sctp_paddrthlds);
3336224641Stuexen			}
3337224641Stuexen			break;
3338224641Stuexen		}
3339227755Stuexen	case SCTP_REMOTE_UDP_ENCAPS_PORT:
3340227755Stuexen		{
3341227755Stuexen			struct sctp_udpencaps *encaps;
3342227755Stuexen			struct sctp_nets *net;
3343283699Stuexen			struct sockaddr *addr;
3344227755Stuexen
3345283699Stuexen#if defined(INET) && defined(INET6)
3346283699Stuexen			struct sockaddr_in sin_store;
3347283699Stuexen
3348283699Stuexen#endif
3349283699Stuexen
3350227755Stuexen			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize);
3351227755Stuexen			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
3352227755Stuexen
3353283699Stuexen#if defined(INET) && defined(INET6)
3354283699Stuexen			if (encaps->sue_address.ss_family == AF_INET6) {
3355283699Stuexen				struct sockaddr_in6 *sin6;
3356283699Stuexen
3357283699Stuexen				sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
3358283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3359283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
3360283699Stuexen					addr = (struct sockaddr *)&sin_store;
3361283699Stuexen				} else {
3362283699Stuexen					addr = (struct sockaddr *)&encaps->sue_address;
3363283699Stuexen				}
3364283699Stuexen			} else {
3365283699Stuexen				addr = (struct sockaddr *)&encaps->sue_address;
3366283699Stuexen			}
3367283699Stuexen#else
3368283699Stuexen			addr = (struct sockaddr *)&encaps->sue_address;
3369283699Stuexen#endif
3370227755Stuexen			if (stcb) {
3371283699Stuexen				net = sctp_findnet(stcb, addr);
3372227755Stuexen			} else {
3373227755Stuexen				/*
3374227755Stuexen				 * We increment here since
3375227755Stuexen				 * sctp_findassociation_ep_addr() wil do a
3376227755Stuexen				 * decrement if it finds the stcb as long as
3377227755Stuexen				 * the locked tcb (last argument) is NOT a
3378227755Stuexen				 * TCB.. aka NULL.
3379227755Stuexen				 */
3380227755Stuexen				net = NULL;
3381227755Stuexen				SCTP_INP_INCR_REF(inp);
3382283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
3383227755Stuexen				if (stcb == NULL) {
3384227755Stuexen					SCTP_INP_DECR_REF(inp);
3385227755Stuexen				}
3386227755Stuexen			}
3387283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
3388227755Stuexen#ifdef INET
3389283699Stuexen				if (addr->sa_family == AF_INET) {
3390227755Stuexen					struct sockaddr_in *sin;
3391227755Stuexen
3392283699Stuexen					sin = (struct sockaddr_in *)addr;
3393283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
3394227755Stuexen						error = EINVAL;
3395227755Stuexen						SCTP_TCB_UNLOCK(stcb);
3396227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3397227755Stuexen						break;
3398227755Stuexen					}
3399227755Stuexen				} else
3400227755Stuexen#endif
3401227755Stuexen#ifdef INET6
3402283699Stuexen				if (addr->sa_family == AF_INET6) {
3403227755Stuexen					struct sockaddr_in6 *sin6;
3404227755Stuexen
3405283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
3406227755Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3407227755Stuexen						error = EINVAL;
3408227755Stuexen						SCTP_TCB_UNLOCK(stcb);
3409227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3410227755Stuexen						break;
3411227755Stuexen					}
3412227755Stuexen				} else
3413227755Stuexen#endif
3414227755Stuexen				{
3415227755Stuexen					error = EAFNOSUPPORT;
3416227755Stuexen					SCTP_TCB_UNLOCK(stcb);
3417227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3418227755Stuexen					break;
3419227755Stuexen				}
3420227755Stuexen			}
3421283699Stuexen			if (stcb != NULL) {
3422227755Stuexen				if (net) {
3423227755Stuexen					encaps->sue_port = net->port;
3424227755Stuexen				} else {
3425227755Stuexen					encaps->sue_port = stcb->asoc.port;
3426227755Stuexen				}
3427227755Stuexen				SCTP_TCB_UNLOCK(stcb);
3428227755Stuexen			} else {
3429227755Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3430227755Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3431227755Stuexen				    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
3432227755Stuexen					SCTP_INP_RLOCK(inp);
3433227755Stuexen					encaps->sue_port = inp->sctp_ep.port;
3434227755Stuexen					SCTP_INP_RUNLOCK(inp);
3435227755Stuexen				} else {
3436227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3437227755Stuexen					error = EINVAL;
3438227755Stuexen				}
3439227755Stuexen			}
3440227755Stuexen			if (error == 0) {
3441258454Stuexen				*optsize = sizeof(struct sctp_udpencaps);
3442227755Stuexen			}
3443227755Stuexen			break;
3444227755Stuexen		}
3445270356Stuexen	case SCTP_ECN_SUPPORTED:
3446270356Stuexen		{
3447270356Stuexen			struct sctp_assoc_value *av;
3448270356Stuexen
3449270356Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3450270356Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3451270356Stuexen
3452270356Stuexen			if (stcb) {
3453270356Stuexen				av->assoc_value = stcb->asoc.ecn_supported;
3454270356Stuexen				SCTP_TCB_UNLOCK(stcb);
3455270356Stuexen			} else {
3456270356Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3457270356Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3458270356Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3459270356Stuexen					SCTP_INP_RLOCK(inp);
3460270356Stuexen					av->assoc_value = inp->ecn_supported;
3461270356Stuexen					SCTP_INP_RUNLOCK(inp);
3462270356Stuexen				} else {
3463270356Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3464270356Stuexen					error = EINVAL;
3465270356Stuexen				}
3466270356Stuexen			}
3467270356Stuexen			if (error == 0) {
3468270356Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3469270356Stuexen			}
3470270356Stuexen			break;
3471270356Stuexen		}
3472270357Stuexen	case SCTP_PR_SUPPORTED:
3473270357Stuexen		{
3474270357Stuexen			struct sctp_assoc_value *av;
3475270357Stuexen
3476270357Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3477270357Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3478270357Stuexen
3479270357Stuexen			if (stcb) {
3480270357Stuexen				av->assoc_value = stcb->asoc.prsctp_supported;
3481270357Stuexen				SCTP_TCB_UNLOCK(stcb);
3482270357Stuexen			} else {
3483270357Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3484270357Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3485270357Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3486270357Stuexen					SCTP_INP_RLOCK(inp);
3487270357Stuexen					av->assoc_value = inp->prsctp_supported;
3488270357Stuexen					SCTP_INP_RUNLOCK(inp);
3489270357Stuexen				} else {
3490270357Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3491270357Stuexen					error = EINVAL;
3492270357Stuexen				}
3493270357Stuexen			}
3494270357Stuexen			if (error == 0) {
3495270357Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3496270357Stuexen			}
3497270357Stuexen			break;
3498270357Stuexen		}
3499270362Stuexen	case SCTP_AUTH_SUPPORTED:
3500270362Stuexen		{
3501270362Stuexen			struct sctp_assoc_value *av;
3502270362Stuexen
3503270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3504270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3505270362Stuexen
3506270362Stuexen			if (stcb) {
3507270362Stuexen				av->assoc_value = stcb->asoc.auth_supported;
3508270362Stuexen				SCTP_TCB_UNLOCK(stcb);
3509270362Stuexen			} else {
3510270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3511270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3512270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3513270362Stuexen					SCTP_INP_RLOCK(inp);
3514270362Stuexen					av->assoc_value = inp->auth_supported;
3515270362Stuexen					SCTP_INP_RUNLOCK(inp);
3516270362Stuexen				} else {
3517270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3518270362Stuexen					error = EINVAL;
3519270362Stuexen				}
3520270362Stuexen			}
3521270362Stuexen			if (error == 0) {
3522270362Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3523270362Stuexen			}
3524270362Stuexen			break;
3525270362Stuexen		}
3526270362Stuexen	case SCTP_ASCONF_SUPPORTED:
3527270362Stuexen		{
3528270362Stuexen			struct sctp_assoc_value *av;
3529270362Stuexen
3530270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3531270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3532270362Stuexen
3533270362Stuexen			if (stcb) {
3534270362Stuexen				av->assoc_value = stcb->asoc.asconf_supported;
3535270362Stuexen				SCTP_TCB_UNLOCK(stcb);
3536270362Stuexen			} else {
3537270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3538270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3539270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3540270362Stuexen					SCTP_INP_RLOCK(inp);
3541270362Stuexen					av->assoc_value = inp->asconf_supported;
3542270362Stuexen					SCTP_INP_RUNLOCK(inp);
3543270362Stuexen				} else {
3544270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3545270362Stuexen					error = EINVAL;
3546270362Stuexen				}
3547270362Stuexen			}
3548270362Stuexen			if (error == 0) {
3549270362Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3550270362Stuexen			}
3551270362Stuexen			break;
3552270362Stuexen		}
3553270361Stuexen	case SCTP_RECONFIG_SUPPORTED:
3554270361Stuexen		{
3555270361Stuexen			struct sctp_assoc_value *av;
3556270361Stuexen
3557270361Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3558270361Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3559270361Stuexen
3560270361Stuexen			if (stcb) {
3561270361Stuexen				av->assoc_value = stcb->asoc.reconfig_supported;
3562270361Stuexen				SCTP_TCB_UNLOCK(stcb);
3563270361Stuexen			} else {
3564270361Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3565270361Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3566270361Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3567270361Stuexen					SCTP_INP_RLOCK(inp);
3568270361Stuexen					av->assoc_value = inp->reconfig_supported;
3569270361Stuexen					SCTP_INP_RUNLOCK(inp);
3570270361Stuexen				} else {
3571270361Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3572270361Stuexen					error = EINVAL;
3573270361Stuexen				}
3574270361Stuexen			}
3575270361Stuexen			if (error == 0) {
3576270361Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3577270361Stuexen			}
3578270361Stuexen			break;
3579270361Stuexen		}
3580270359Stuexen	case SCTP_NRSACK_SUPPORTED:
3581270359Stuexen		{
3582270359Stuexen			struct sctp_assoc_value *av;
3583270359Stuexen
3584270359Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3585270359Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3586270359Stuexen
3587270359Stuexen			if (stcb) {
3588270359Stuexen				av->assoc_value = stcb->asoc.nrsack_supported;
3589270359Stuexen				SCTP_TCB_UNLOCK(stcb);
3590270359Stuexen			} else {
3591270359Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3592270359Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3593270359Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3594270359Stuexen					SCTP_INP_RLOCK(inp);
3595270359Stuexen					av->assoc_value = inp->nrsack_supported;
3596270359Stuexen					SCTP_INP_RUNLOCK(inp);
3597270359Stuexen				} else {
3598270359Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3599270359Stuexen					error = EINVAL;
3600270359Stuexen				}
3601270359Stuexen			}
3602270359Stuexen			if (error == 0) {
3603270359Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3604270359Stuexen			}
3605270359Stuexen			break;
3606270359Stuexen		}
3607270360Stuexen	case SCTP_PKTDROP_SUPPORTED:
3608270360Stuexen		{
3609270360Stuexen			struct sctp_assoc_value *av;
3610270360Stuexen
3611270360Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3612270360Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3613270360Stuexen
3614270360Stuexen			if (stcb) {
3615270360Stuexen				av->assoc_value = stcb->asoc.pktdrop_supported;
3616270360Stuexen				SCTP_TCB_UNLOCK(stcb);
3617270360Stuexen			} else {
3618270360Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3619270360Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3620270360Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3621270360Stuexen					SCTP_INP_RLOCK(inp);
3622270360Stuexen					av->assoc_value = inp->pktdrop_supported;
3623270360Stuexen					SCTP_INP_RUNLOCK(inp);
3624270360Stuexen				} else {
3625270360Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3626270360Stuexen					error = EINVAL;
3627270360Stuexen				}
3628270360Stuexen			}
3629270360Stuexen			if (error == 0) {
3630270360Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3631270360Stuexen			}
3632270360Stuexen			break;
3633270360Stuexen		}
3634235021Stuexen	case SCTP_ENABLE_STREAM_RESET:
3635235021Stuexen		{
3636235021Stuexen			struct sctp_assoc_value *av;
3637235021Stuexen
3638235021Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3639235021Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3640235021Stuexen
3641235021Stuexen			if (stcb) {
3642235021Stuexen				av->assoc_value = (uint32_t) stcb->asoc.local_strreset_support;
3643235021Stuexen				SCTP_TCB_UNLOCK(stcb);
3644235021Stuexen			} else {
3645235021Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3646235021Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3647235021Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3648235021Stuexen					SCTP_INP_RLOCK(inp);
3649235021Stuexen					av->assoc_value = (uint32_t) inp->local_strreset_support;
3650235021Stuexen					SCTP_INP_RUNLOCK(inp);
3651235021Stuexen				} else {
3652235021Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3653235021Stuexen					error = EINVAL;
3654235021Stuexen				}
3655235021Stuexen			}
3656235021Stuexen			if (error == 0) {
3657235021Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3658235021Stuexen			}
3659235021Stuexen			break;
3660235021Stuexen		}
3661270363Stuexen	case SCTP_PR_STREAM_STATUS:
3662270363Stuexen		{
3663270363Stuexen			struct sctp_prstatus *sprstat;
3664270363Stuexen			uint16_t sid;
3665270363Stuexen			uint16_t policy;
3666270363Stuexen
3667270363Stuexen			SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
3668270363Stuexen			SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
3669270363Stuexen
3670270363Stuexen			sid = sprstat->sprstat_sid;
3671270363Stuexen			policy = sprstat->sprstat_policy;
3672270363Stuexen#if defined(SCTP_DETAILED_STR_STATS)
3673270363Stuexen			if ((stcb != NULL) &&
3674283706Stuexen			    (sid < stcb->asoc.streamoutcnt) &&
3675270363Stuexen			    (policy != SCTP_PR_SCTP_NONE) &&
3676283706Stuexen			    ((policy <= SCTP_PR_SCTP_MAX) ||
3677283706Stuexen			    (policy == SCTP_PR_SCTP_ALL))) {
3678270363Stuexen				if (policy == SCTP_PR_SCTP_ALL) {
3679270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
3680270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
3681270363Stuexen				} else {
3682270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[policy];
3683270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[policy];
3684270363Stuexen				}
3685283705Stuexen#else
3686283705Stuexen			if ((stcb != NULL) &&
3687283706Stuexen			    (sid < stcb->asoc.streamoutcnt) &&
3688283706Stuexen			    (policy == SCTP_PR_SCTP_ALL)) {
3689283705Stuexen				sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
3690283705Stuexen				sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
3691283705Stuexen#endif
3692270363Stuexen				SCTP_TCB_UNLOCK(stcb);
3693270363Stuexen				*optsize = sizeof(struct sctp_prstatus);
3694270363Stuexen			} else {
3695270363Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3696270363Stuexen				error = EINVAL;
3697270363Stuexen			}
3698270363Stuexen			break;
3699270363Stuexen		}
3700270363Stuexen	case SCTP_PR_ASSOC_STATUS:
3701270363Stuexen		{
3702270363Stuexen			struct sctp_prstatus *sprstat;
3703270363Stuexen			uint16_t policy;
3704270363Stuexen
3705270363Stuexen			SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
3706270363Stuexen			SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
3707270363Stuexen
3708270363Stuexen			policy = sprstat->sprstat_policy;
3709270363Stuexen			if ((stcb != NULL) &&
3710270363Stuexen			    (policy != SCTP_PR_SCTP_NONE) &&
3711283706Stuexen			    ((policy <= SCTP_PR_SCTP_MAX) ||
3712283706Stuexen			    (policy == SCTP_PR_SCTP_ALL))) {
3713270363Stuexen				if (policy == SCTP_PR_SCTP_ALL) {
3714270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[0];
3715270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[0];
3716270363Stuexen				} else {
3717270363Stuexen					sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy];
3718270363Stuexen					sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy];
3719270363Stuexen				}
3720270363Stuexen				SCTP_TCB_UNLOCK(stcb);
3721270363Stuexen				*optsize = sizeof(struct sctp_prstatus);
3722270363Stuexen			} else {
3723270363Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3724270363Stuexen				error = EINVAL;
3725270363Stuexen			}
3726270363Stuexen			break;
3727270363Stuexen		}
3728283724Stuexen	case SCTP_MAX_CWND:
3729283724Stuexen		{
3730283724Stuexen			struct sctp_assoc_value *av;
3731283724Stuexen
3732283724Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
3733283724Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3734283724Stuexen
3735283724Stuexen			if (stcb) {
3736283724Stuexen				av->assoc_value = stcb->asoc.max_cwnd;
3737283724Stuexen				SCTP_TCB_UNLOCK(stcb);
3738283724Stuexen			} else {
3739283724Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3740283724Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3741283724Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
3742283724Stuexen					SCTP_INP_RLOCK(inp);
3743283724Stuexen					av->assoc_value = inp->max_cwnd;
3744283724Stuexen					SCTP_INP_RUNLOCK(inp);
3745283724Stuexen				} else {
3746283724Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3747283724Stuexen					error = EINVAL;
3748283724Stuexen				}
3749283724Stuexen			}
3750283724Stuexen			if (error == 0) {
3751283724Stuexen				*optsize = sizeof(struct sctp_assoc_value);
3752283724Stuexen			}
3753283724Stuexen			break;
3754283724Stuexen		}
3755163953Srrs	default:
3756171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3757163953Srrs		error = ENOPROTOOPT;
3758163953Srrs		break;
3759163953Srrs	}			/* end switch (sopt->sopt_name) */
3760223132Stuexen	if (error) {
3761223132Stuexen		*optsize = 0;
3762223132Stuexen	}
3763163953Srrs	return (error);
3764163953Srrs}
3765163953Srrs
3766163953Srrsstatic int
3767166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
3768166675Srrs    void *p)
3769163953Srrs{
3770166675Srrs	int error, set_opt;
3771166675Srrs	uint32_t *mopt;
3772163953Srrs	struct sctp_tcb *stcb = NULL;
3773171943Srrs	struct sctp_inpcb *inp = NULL;
3774167598Srrs	uint32_t vrf_id;
3775163953Srrs
3776166675Srrs	if (optval == NULL) {
3777169420Srrs		SCTP_PRINTF("optval is NULL\n");
3778171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3779163953Srrs		return (EINVAL);
3780163953Srrs	}
3781163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3782233005Stuexen	if (inp == NULL) {
3783169420Srrs		SCTP_PRINTF("inp is NULL?\n");
3784171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3785228907Stuexen		return (EINVAL);
3786167598Srrs	}
3787168299Srrs	vrf_id = inp->def_vrf_id;
3788163953Srrs
3789163953Srrs	error = 0;
3790166675Srrs	switch (optname) {
3791163953Srrs	case SCTP_NODELAY:
3792163953Srrs	case SCTP_AUTOCLOSE:
3793163953Srrs	case SCTP_AUTO_ASCONF:
3794163953Srrs	case SCTP_EXPLICIT_EOR:
3795163953Srrs	case SCTP_DISABLE_FRAGMENTS:
3796163953Srrs	case SCTP_USE_EXT_RCVINFO:
3797163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
3798163953Srrs		/* copy in the option value */
3799166675Srrs		SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
3800163953Srrs		set_opt = 0;
3801163953Srrs		if (error)
3802163953Srrs			break;
3803166675Srrs		switch (optname) {
3804163953Srrs		case SCTP_DISABLE_FRAGMENTS:
3805163953Srrs			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
3806163953Srrs			break;
3807163953Srrs		case SCTP_AUTO_ASCONF:
3808171943Srrs			/*
3809171943Srrs			 * NOTE: we don't really support this flag
3810171943Srrs			 */
3811171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3812171943Srrs				/* only valid for bound all sockets */
3813224641Stuexen				if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
3814224641Stuexen				    (*mopt != 0)) {
3815224641Stuexen					/* forbidden by admin */
3816224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
3817224641Stuexen					return (EPERM);
3818224641Stuexen				}
3819171943Srrs				set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
3820171943Srrs			} else {
3821171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3822171943Srrs				return (EINVAL);
3823171943Srrs			}
3824163953Srrs			break;
3825163953Srrs		case SCTP_EXPLICIT_EOR:
3826163953Srrs			set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
3827163953Srrs			break;
3828163953Srrs		case SCTP_USE_EXT_RCVINFO:
3829163953Srrs			set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
3830163953Srrs			break;
3831163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
3832163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3833163953Srrs				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
3834163953Srrs			} else {
3835171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3836163953Srrs				return (EINVAL);
3837163953Srrs			}
3838163953Srrs			break;
3839163953Srrs		case SCTP_NODELAY:
3840163953Srrs			set_opt = SCTP_PCB_FLAGS_NODELAY;
3841163953Srrs			break;
3842163953Srrs		case SCTP_AUTOCLOSE:
3843170056Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3844170056Srrs			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3845171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3846170056Srrs				return (EINVAL);
3847170056Srrs			}
3848163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
3849163953Srrs			/*
3850163953Srrs			 * The value is in ticks. Note this does not effect
3851163953Srrs			 * old associations, only new ones.
3852163953Srrs			 */
3853163953Srrs			inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
3854163953Srrs			break;
3855163953Srrs		}
3856163953Srrs		SCTP_INP_WLOCK(inp);
3857163953Srrs		if (*mopt != 0) {
3858163953Srrs			sctp_feature_on(inp, set_opt);
3859163953Srrs		} else {
3860163953Srrs			sctp_feature_off(inp, set_opt);
3861163953Srrs		}
3862163953Srrs		SCTP_INP_WUNLOCK(inp);
3863163953Srrs		break;
3864181054Srrs	case SCTP_REUSE_PORT:
3865181054Srrs		{
3866181054Srrs			SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
3867181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
3868181054Srrs				/* Can't set it after we are bound */
3869181054Srrs				error = EINVAL;
3870181054Srrs				break;
3871181054Srrs			}
3872181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
3873181054Srrs				/* Can't do this for a 1-m socket */
3874181054Srrs				error = EINVAL;
3875181054Srrs				break;
3876181054Srrs			}
3877181054Srrs			if (optval)
3878181054Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
3879181054Srrs			else
3880181054Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
3881223132Stuexen			break;
3882181054Srrs		}
3883163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
3884163953Srrs		{
3885166675Srrs			uint32_t *value;
3886166675Srrs
3887166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
3888167736Srrs			if (*value > SCTP_SB_LIMIT_RCV(so)) {
3889171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3890167736Srrs				error = EINVAL;
3891167736Srrs				break;
3892167736Srrs			}
3893166675Srrs			inp->partial_delivery_point = *value;
3894223132Stuexen			break;
3895163953Srrs		}
3896163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
3897163953Srrs		/* not yet until we re-write sctp_recvmsg() */
3898163953Srrs		{
3899168943Srrs			uint32_t *level;
3900163953Srrs
3901168943Srrs			SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
3902168943Srrs			if (*level == SCTP_FRAG_LEVEL_2) {
3903163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3904168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3905168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_1) {
3906168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3907168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3908168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_0) {
3909170056Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
3910168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
3911168943Srrs
3912163953Srrs			} else {
3913171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3914168943Srrs				error = EINVAL;
3915163953Srrs			}
3916223132Stuexen			break;
3917163953Srrs		}
3918163953Srrs	case SCTP_CMT_ON_OFF:
3919211944Stuexen		if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
3920163953Srrs			struct sctp_assoc_value *av;
3921163953Srrs
3922166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3923223132Stuexen			if (av->assoc_value > SCTP_CMT_MAX) {
3924223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3925223132Stuexen				error = EINVAL;
3926223132Stuexen				break;
3927223132Stuexen			}
3928211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3929211944Stuexen			if (stcb) {
3930223132Stuexen				stcb->asoc.sctp_cmt_on_off = av->assoc_value;
3931211944Stuexen				SCTP_TCB_UNLOCK(stcb);
3932166675Srrs			} else {
3933224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3934224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3935224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3936223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3937221460Stuexen					SCTP_INP_WLOCK(inp);
3938221460Stuexen					inp->sctp_cmt_on_off = av->assoc_value;
3939221460Stuexen					SCTP_INP_WUNLOCK(inp);
3940216669Stuexen				}
3941223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3942223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3943223132Stuexen					SCTP_INP_RLOCK(inp);
3944223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3945223132Stuexen						SCTP_TCB_LOCK(stcb);
3946223132Stuexen						stcb->asoc.sctp_cmt_on_off = av->assoc_value;
3947223132Stuexen						SCTP_TCB_UNLOCK(stcb);
3948223132Stuexen					}
3949224918Stuexen					SCTP_INP_RUNLOCK(inp);
3950223132Stuexen				}
3951163953Srrs			}
3952211944Stuexen		} else {
3953211944Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3954211944Stuexen			error = ENOPROTOOPT;
3955163953Srrs		}
3956163953Srrs		break;
3957171440Srrs	case SCTP_PLUGGABLE_CC:
3958171440Srrs		{
3959171440Srrs			struct sctp_assoc_value *av;
3960219057Srrs			struct sctp_nets *net;
3961171440Srrs
3962171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3963223132Stuexen			if ((av->assoc_value != SCTP_CC_RFC2581) &&
3964223132Stuexen			    (av->assoc_value != SCTP_CC_HSTCP) &&
3965223132Stuexen			    (av->assoc_value != SCTP_CC_HTCP) &&
3966223132Stuexen			    (av->assoc_value != SCTP_CC_RTCC)) {
3967223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3968223132Stuexen				error = EINVAL;
3969223132Stuexen				break;
3970223132Stuexen			}
3971171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3972171440Srrs			if (stcb) {
3973223132Stuexen				stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3974223132Stuexen				stcb->asoc.congestion_control_module = av->assoc_value;
3975223132Stuexen				if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3976223132Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3977223132Stuexen						stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
3978219057Srrs					}
3979171440Srrs				}
3980217611Stuexen				SCTP_TCB_UNLOCK(stcb);
3981171440Srrs			} else {
3982224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3983224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
3984224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
3985223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3986217611Stuexen					SCTP_INP_WLOCK(inp);
3987171440Srrs					inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
3988217611Stuexen					SCTP_INP_WUNLOCK(inp);
3989217760Stuexen				}
3990223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
3991223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
3992223132Stuexen					SCTP_INP_RLOCK(inp);
3993223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
3994223132Stuexen						SCTP_TCB_LOCK(stcb);
3995223132Stuexen						stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3996223132Stuexen						stcb->asoc.congestion_control_module = av->assoc_value;
3997223132Stuexen						if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3998223132Stuexen							TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3999223132Stuexen								stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
4000223132Stuexen							}
4001223132Stuexen						}
4002223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4003223132Stuexen					}
4004223132Stuexen					SCTP_INP_RUNLOCK(inp);
4005223132Stuexen				}
4006171440Srrs			}
4007223132Stuexen			break;
4008171440Srrs		}
4009219057Srrs	case SCTP_CC_OPTION:
4010219057Srrs		{
4011219057Srrs			struct sctp_cc_option *cc_opt;
4012219057Srrs
4013219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
4014219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
4015219057Srrs			if (stcb == NULL) {
4016223132Stuexen				if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) {
4017223132Stuexen					SCTP_INP_RLOCK(inp);
4018223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4019223132Stuexen						SCTP_TCB_LOCK(stcb);
4020223132Stuexen						if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) {
4021223132Stuexen							(*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt);
4022223132Stuexen						}
4023223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4024223132Stuexen					}
4025223132Stuexen					SCTP_INP_RUNLOCK(inp);
4026223132Stuexen				} else {
4027223132Stuexen					error = EINVAL;
4028223132Stuexen				}
4029219057Srrs			} else {
4030219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
4031219057Srrs					error = ENOTSUP;
4032219057Srrs				} else {
4033219057Srrs					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1,
4034219057Srrs					    cc_opt);
4035219057Srrs				}
4036219057Srrs				SCTP_TCB_UNLOCK(stcb);
4037219057Srrs			}
4038223132Stuexen			break;
4039219057Srrs		}
4040217760Stuexen	case SCTP_PLUGGABLE_SS:
4041217760Stuexen		{
4042217760Stuexen			struct sctp_assoc_value *av;
4043217760Stuexen
4044217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4045223132Stuexen			if ((av->assoc_value != SCTP_SS_DEFAULT) &&
4046223132Stuexen			    (av->assoc_value != SCTP_SS_ROUND_ROBIN) &&
4047223132Stuexen			    (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) &&
4048223132Stuexen			    (av->assoc_value != SCTP_SS_PRIORITY) &&
4049223132Stuexen			    (av->assoc_value != SCTP_SS_FAIR_BANDWITH) &&
4050223132Stuexen			    (av->assoc_value != SCTP_SS_FIRST_COME)) {
4051223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4052223132Stuexen				error = EINVAL;
4053223132Stuexen				break;
4054223132Stuexen			}
4055217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4056217760Stuexen			if (stcb) {
4057223132Stuexen				stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
4058223132Stuexen				stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
4059223132Stuexen				stcb->asoc.stream_scheduling_module = av->assoc_value;
4060223132Stuexen				stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
4061217760Stuexen				SCTP_TCB_UNLOCK(stcb);
4062217760Stuexen			} else {
4063224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4064224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4065224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4066223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4067217760Stuexen					SCTP_INP_WLOCK(inp);
4068217760Stuexen					inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
4069217760Stuexen					SCTP_INP_WUNLOCK(inp);
4070217760Stuexen				}
4071223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4072223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4073223132Stuexen					SCTP_INP_RLOCK(inp);
4074223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4075223132Stuexen						SCTP_TCB_LOCK(stcb);
4076223132Stuexen						stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
4077223132Stuexen						stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
4078223132Stuexen						stcb->asoc.stream_scheduling_module = av->assoc_value;
4079223132Stuexen						stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
4080223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4081223132Stuexen					}
4082223132Stuexen					SCTP_INP_RUNLOCK(inp);
4083223132Stuexen				}
4084217760Stuexen			}
4085223132Stuexen			break;
4086217760Stuexen		}
4087217760Stuexen	case SCTP_SS_VALUE:
4088217760Stuexen		{
4089217760Stuexen			struct sctp_stream_value *av;
4090217760Stuexen
4091217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
4092217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4093217760Stuexen			if (stcb) {
4094277807Sdelphij				if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
4095277807Sdelphij				    (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
4096277807Sdelphij				    av->stream_value) < 0)) {
4097217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4098217760Stuexen					error = EINVAL;
4099217760Stuexen				}
4100217760Stuexen				SCTP_TCB_UNLOCK(stcb);
4101217760Stuexen			} else {
4102223132Stuexen				if (av->assoc_id == SCTP_CURRENT_ASSOC) {
4103223132Stuexen					SCTP_INP_RLOCK(inp);
4104223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4105223132Stuexen						SCTP_TCB_LOCK(stcb);
4106277807Sdelphij						if (av->stream_id < stcb->asoc.streamoutcnt) {
4107277807Sdelphij							stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
4108277807Sdelphij							    &stcb->asoc,
4109277807Sdelphij							    &stcb->asoc.strmout[av->stream_id],
4110277807Sdelphij							    av->stream_value);
4111277807Sdelphij						}
4112223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4113223132Stuexen					}
4114223132Stuexen					SCTP_INP_RUNLOCK(inp);
4115223132Stuexen				} else {
4116223132Stuexen					/*
4117223132Stuexen					 * Can't set stream value without
4118223132Stuexen					 * association
4119223132Stuexen					 */
4120223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4121223132Stuexen					error = EINVAL;
4122223132Stuexen				}
4123217760Stuexen			}
4124223132Stuexen			break;
4125217760Stuexen		}
4126163953Srrs	case SCTP_CLR_STAT_LOG:
4127171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4128163953Srrs		error = EOPNOTSUPP;
4129163953Srrs		break;
4130163953Srrs	case SCTP_CONTEXT:
4131163953Srrs		{
4132163953Srrs			struct sctp_assoc_value *av;
4133163953Srrs
4134166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4135166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4136166675Srrs
4137166675Srrs			if (stcb) {
4138166675Srrs				stcb->asoc.context = av->assoc_value;
4139166675Srrs				SCTP_TCB_UNLOCK(stcb);
4140163953Srrs			} else {
4141224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4142224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4143224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4144223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4145223132Stuexen					SCTP_INP_WLOCK(inp);
4146223132Stuexen					inp->sctp_context = av->assoc_value;
4147223132Stuexen					SCTP_INP_WUNLOCK(inp);
4148223132Stuexen				}
4149223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4150223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4151223132Stuexen					SCTP_INP_RLOCK(inp);
4152223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4153223132Stuexen						SCTP_TCB_LOCK(stcb);
4154223132Stuexen						stcb->asoc.context = av->assoc_value;
4155223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4156223132Stuexen					}
4157223132Stuexen					SCTP_INP_RUNLOCK(inp);
4158223132Stuexen				}
4159163953Srrs			}
4160223132Stuexen			break;
4161163953Srrs		}
4162167598Srrs	case SCTP_VRF_ID:
4163167598Srrs		{
4164170056Srrs			uint32_t *default_vrfid;
4165167598Srrs
4166170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
4167170056Srrs			if (*default_vrfid > SCTP_MAX_VRF_ID) {
4168171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4169167598Srrs				error = EINVAL;
4170167598Srrs				break;
4171167598Srrs			}
4172170056Srrs			inp->def_vrf_id = *default_vrfid;
4173167598Srrs			break;
4174167598Srrs		}
4175167598Srrs	case SCTP_DEL_VRF_ID:
4176167598Srrs		{
4177171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4178167598Srrs			error = EOPNOTSUPP;
4179167598Srrs			break;
4180167598Srrs		}
4181167598Srrs	case SCTP_ADD_VRF_ID:
4182167598Srrs		{
4183171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4184167598Srrs			error = EOPNOTSUPP;
4185167598Srrs			break;
4186167598Srrs		}
4187170056Srrs	case SCTP_DELAYED_SACK:
4188163953Srrs		{
4189170056Srrs			struct sctp_sack_info *sack;
4190163953Srrs
4191170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
4192170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
4193171477Srrs			if (sack->sack_delay) {
4194171477Srrs				if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
4195171477Srrs					sack->sack_delay = SCTP_MAX_SACK_DELAY;
4196223132Stuexen				if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
4197223132Stuexen					sack->sack_delay = TICKS_TO_MSEC(1);
4198223132Stuexen				}
4199171477Srrs			}
4200166675Srrs			if (stcb) {
4201170056Srrs				if (sack->sack_delay) {
4202170056Srrs					stcb->asoc.delayed_ack = sack->sack_delay;
4203170056Srrs				}
4204170056Srrs				if (sack->sack_freq) {
4205170056Srrs					stcb->asoc.sack_freq = sack->sack_freq;
4206170056Srrs				}
4207166675Srrs				SCTP_TCB_UNLOCK(stcb);
4208166675Srrs			} else {
4209224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4210224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4211224918Stuexen				    (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
4212223132Stuexen				    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
4213223132Stuexen					SCTP_INP_WLOCK(inp);
4214223132Stuexen					if (sack->sack_delay) {
4215223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
4216170056Srrs					}
4217223132Stuexen					if (sack->sack_freq) {
4218223132Stuexen						inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
4219223132Stuexen					}
4220223132Stuexen					SCTP_INP_WUNLOCK(inp);
4221170056Srrs				}
4222223132Stuexen				if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
4223223132Stuexen				    (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
4224223132Stuexen					SCTP_INP_RLOCK(inp);
4225223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4226223132Stuexen						SCTP_TCB_LOCK(stcb);
4227223132Stuexen						if (sack->sack_delay) {
4228223132Stuexen							stcb->asoc.delayed_ack = sack->sack_delay;
4229223132Stuexen						}
4230223132Stuexen						if (sack->sack_freq) {
4231223132Stuexen							stcb->asoc.sack_freq = sack->sack_freq;
4232223132Stuexen						}
4233223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4234223132Stuexen					}
4235223132Stuexen					SCTP_INP_RUNLOCK(inp);
4236170056Srrs				}
4237163953Srrs			}
4238166675Srrs			break;
4239163953Srrs		}
4240163953Srrs	case SCTP_AUTH_CHUNK:
4241163953Srrs		{
4242163953Srrs			struct sctp_authchunk *sauth;
4243163953Srrs
4244166675Srrs			SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
4245166675Srrs
4246166675Srrs			SCTP_INP_WLOCK(inp);
4247171943Srrs			if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
4248171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4249163953Srrs				error = EINVAL;
4250171943Srrs			}
4251166675Srrs			SCTP_INP_WUNLOCK(inp);
4252163953Srrs			break;
4253163953Srrs		}
4254163953Srrs	case SCTP_AUTH_KEY:
4255163953Srrs		{
4256163953Srrs			struct sctp_authkey *sca;
4257163953Srrs			struct sctp_keyhead *shared_keys;
4258163953Srrs			sctp_sharedkey_t *shared_key;
4259163953Srrs			sctp_key_t *key = NULL;
4260166675Srrs			size_t size;
4261163953Srrs
4262166675Srrs			SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
4263223697Stuexen			if (sca->sca_keylength == 0) {
4264223697Stuexen				size = optsize - sizeof(struct sctp_authkey);
4265223697Stuexen			} else {
4266223697Stuexen				if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
4267223697Stuexen					size = sca->sca_keylength;
4268223697Stuexen				} else {
4269223697Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4270223697Stuexen					error = EINVAL;
4271223697Stuexen					break;
4272223697Stuexen				}
4273223697Stuexen			}
4274169420Srrs			SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
4275166675Srrs
4276166675Srrs			if (stcb) {
4277163953Srrs				shared_keys = &stcb->asoc.shared_keys;
4278163953Srrs				/* clear the cached keys for this key id */
4279163953Srrs				sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
4280163953Srrs				/*
4281163953Srrs				 * create the new shared key and
4282163953Srrs				 * insert/replace it
4283163953Srrs				 */
4284163953Srrs				if (size > 0) {
4285163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
4286163953Srrs					if (key == NULL) {
4287171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4288163953Srrs						error = ENOMEM;
4289163953Srrs						SCTP_TCB_UNLOCK(stcb);
4290163953Srrs						break;
4291163953Srrs					}
4292163953Srrs				}
4293163953Srrs				shared_key = sctp_alloc_sharedkey();
4294163953Srrs				if (shared_key == NULL) {
4295163953Srrs					sctp_free_key(key);
4296171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4297163953Srrs					error = ENOMEM;
4298163953Srrs					SCTP_TCB_UNLOCK(stcb);
4299163953Srrs					break;
4300163953Srrs				}
4301163953Srrs				shared_key->key = key;
4302163953Srrs				shared_key->keyid = sca->sca_keynumber;
4303185694Srrs				error = sctp_insert_sharedkey(shared_keys, shared_key);
4304163953Srrs				SCTP_TCB_UNLOCK(stcb);
4305163953Srrs			} else {
4306224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4307224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4308224918Stuexen				    (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
4309223132Stuexen				    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
4310223132Stuexen					SCTP_INP_WLOCK(inp);
4311223132Stuexen					shared_keys = &inp->sctp_ep.shared_keys;
4312223132Stuexen					/*
4313223132Stuexen					 * clear the cached keys on all
4314223132Stuexen					 * assocs for this key id
4315223132Stuexen					 */
4316223132Stuexen					sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
4317223132Stuexen					/*
4318223132Stuexen					 * create the new shared key and
4319223132Stuexen					 * insert/replace it
4320223132Stuexen					 */
4321223132Stuexen					if (size > 0) {
4322223132Stuexen						key = sctp_set_key(sca->sca_key, (uint32_t) size);
4323223132Stuexen						if (key == NULL) {
4324223132Stuexen							SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4325223132Stuexen							error = ENOMEM;
4326223132Stuexen							SCTP_INP_WUNLOCK(inp);
4327223132Stuexen							break;
4328223132Stuexen						}
4329223132Stuexen					}
4330223132Stuexen					shared_key = sctp_alloc_sharedkey();
4331223132Stuexen					if (shared_key == NULL) {
4332223132Stuexen						sctp_free_key(key);
4333171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4334163953Srrs						error = ENOMEM;
4335163953Srrs						SCTP_INP_WUNLOCK(inp);
4336163953Srrs						break;
4337163953Srrs					}
4338223132Stuexen					shared_key->key = key;
4339223132Stuexen					shared_key->keyid = sca->sca_keynumber;
4340223132Stuexen					error = sctp_insert_sharedkey(shared_keys, shared_key);
4341163953Srrs					SCTP_INP_WUNLOCK(inp);
4342163953Srrs				}
4343223132Stuexen				if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
4344223132Stuexen				    (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
4345223132Stuexen					SCTP_INP_RLOCK(inp);
4346223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4347223132Stuexen						SCTP_TCB_LOCK(stcb);
4348223132Stuexen						shared_keys = &stcb->asoc.shared_keys;
4349223132Stuexen						/*
4350223132Stuexen						 * clear the cached keys for
4351223132Stuexen						 * this key id
4352223132Stuexen						 */
4353223132Stuexen						sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
4354223132Stuexen						/*
4355223132Stuexen						 * create the new shared key
4356223132Stuexen						 * and insert/replace it
4357223132Stuexen						 */
4358223132Stuexen						if (size > 0) {
4359223132Stuexen							key = sctp_set_key(sca->sca_key, (uint32_t) size);
4360223132Stuexen							if (key == NULL) {
4361223132Stuexen								SCTP_TCB_UNLOCK(stcb);
4362223132Stuexen								continue;
4363223132Stuexen							}
4364223132Stuexen						}
4365223132Stuexen						shared_key = sctp_alloc_sharedkey();
4366223132Stuexen						if (shared_key == NULL) {
4367223132Stuexen							sctp_free_key(key);
4368223132Stuexen							SCTP_TCB_UNLOCK(stcb);
4369223132Stuexen							continue;
4370223132Stuexen						}
4371223132Stuexen						shared_key->key = key;
4372223132Stuexen						shared_key->keyid = sca->sca_keynumber;
4373223132Stuexen						error = sctp_insert_sharedkey(shared_keys, shared_key);
4374223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4375223132Stuexen					}
4376223132Stuexen					SCTP_INP_RUNLOCK(inp);
4377223132Stuexen				}
4378163953Srrs			}
4379163953Srrs			break;
4380163953Srrs		}
4381163953Srrs	case SCTP_HMAC_IDENT:
4382163953Srrs		{
4383163953Srrs			struct sctp_hmacalgo *shmac;
4384163953Srrs			sctp_hmaclist_t *hmaclist;
4385181054Srrs			uint16_t hmacid;
4386181054Srrs			uint32_t i;
4387181054Srrs
4388166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
4389271750Stuexen			if ((optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) ||
4390271750Stuexen			    (shmac->shmac_number_of_idents > 0xffff)) {
4391181054Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4392181054Srrs				error = EINVAL;
4393181054Srrs				break;
4394181054Srrs			}
4395271750Stuexen			hmaclist = sctp_alloc_hmaclist((uint16_t) shmac->shmac_number_of_idents);
4396163953Srrs			if (hmaclist == NULL) {
4397171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4398163953Srrs				error = ENOMEM;
4399163953Srrs				break;
4400163953Srrs			}
4401181054Srrs			for (i = 0; i < shmac->shmac_number_of_idents; i++) {
4402163953Srrs				hmacid = shmac->shmac_idents[i];
4403181054Srrs				if (sctp_auth_add_hmacid(hmaclist, hmacid)) {
4404163953Srrs					 /* invalid HMACs were found */ ;
4405171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4406163953Srrs					error = EINVAL;
4407164085Srrs					sctp_free_hmaclist(hmaclist);
4408163953Srrs					goto sctp_set_hmac_done;
4409163953Srrs				}
4410163953Srrs			}
4411170056Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
4412170056Srrs				if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
4413170056Srrs					/* already in list */
4414253858Stuexen					break;
4415170056Srrs				}
4416170056Srrs			}
4417253858Stuexen			if (i == hmaclist->num_algo) {
4418253858Stuexen				/* not found in list */
4419170056Srrs				sctp_free_hmaclist(hmaclist);
4420171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4421170056Srrs				error = EINVAL;
4422170056Srrs				break;
4423170056Srrs			}
4424163953Srrs			/* set it on the endpoint */
4425163953Srrs			SCTP_INP_WLOCK(inp);
4426163953Srrs			if (inp->sctp_ep.local_hmacs)
4427163953Srrs				sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
4428163953Srrs			inp->sctp_ep.local_hmacs = hmaclist;
4429163953Srrs			SCTP_INP_WUNLOCK(inp);
4430163953Srrs	sctp_set_hmac_done:
4431163953Srrs			break;
4432163953Srrs		}
4433163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
4434163953Srrs		{
4435163953Srrs			struct sctp_authkeyid *scact;
4436163953Srrs
4437223132Stuexen			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
4438166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
4439166675Srrs
4440163953Srrs			/* set the active key on the right place */
4441166675Srrs			if (stcb) {
4442163953Srrs				/* set the active key on the assoc */
4443185694Srrs				if (sctp_auth_setactivekey(stcb,
4444185694Srrs				    scact->scact_keynumber)) {
4445185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
4446185694Srrs					    SCTP_FROM_SCTP_USRREQ,
4447185694Srrs					    EINVAL);
4448163953Srrs					error = EINVAL;
4449171943Srrs				}
4450163953Srrs				SCTP_TCB_UNLOCK(stcb);
4451163953Srrs			} else {
4452224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4453224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4454224918Stuexen				    (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4455223132Stuexen				    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
4456223132Stuexen					SCTP_INP_WLOCK(inp);
4457223132Stuexen					if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
4458223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4459223132Stuexen						error = EINVAL;
4460223132Stuexen					}
4461223132Stuexen					SCTP_INP_WUNLOCK(inp);
4462171943Srrs				}
4463223132Stuexen				if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4464223132Stuexen				    (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
4465223132Stuexen					SCTP_INP_RLOCK(inp);
4466223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4467223132Stuexen						SCTP_TCB_LOCK(stcb);
4468223132Stuexen						sctp_auth_setactivekey(stcb, scact->scact_keynumber);
4469223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4470223132Stuexen					}
4471223132Stuexen					SCTP_INP_RUNLOCK(inp);
4472223132Stuexen				}
4473163953Srrs			}
4474163953Srrs			break;
4475163953Srrs		}
4476163953Srrs	case SCTP_AUTH_DELETE_KEY:
4477163953Srrs		{
4478163953Srrs			struct sctp_authkeyid *scdel;
4479163953Srrs
4480223132Stuexen			SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
4481166675Srrs			SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
4482166675Srrs
4483163953Srrs			/* delete the key from the right place */
4484166675Srrs			if (stcb) {
4485223132Stuexen				if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
4486223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4487163953Srrs					error = EINVAL;
4488171943Srrs				}
4489163953Srrs				SCTP_TCB_UNLOCK(stcb);
4490163953Srrs			} else {
4491224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4492224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4493224918Stuexen				    (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4494223132Stuexen				    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
4495223132Stuexen					SCTP_INP_WLOCK(inp);
4496223132Stuexen					if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
4497223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4498223132Stuexen						error = EINVAL;
4499223132Stuexen					}
4500223132Stuexen					SCTP_INP_WUNLOCK(inp);
4501171943Srrs				}
4502223132Stuexen				if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4503223132Stuexen				    (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
4504223132Stuexen					SCTP_INP_RLOCK(inp);
4505223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4506223132Stuexen						SCTP_TCB_LOCK(stcb);
4507223132Stuexen						sctp_delete_sharedkey(stcb, scdel->scact_keynumber);
4508223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4509223132Stuexen					}
4510223132Stuexen					SCTP_INP_RUNLOCK(inp);
4511223132Stuexen				}
4512163953Srrs			}
4513163953Srrs			break;
4514163953Srrs		}
4515185694Srrs	case SCTP_AUTH_DEACTIVATE_KEY:
4516185694Srrs		{
4517185694Srrs			struct sctp_authkeyid *keyid;
4518163953Srrs
4519223132Stuexen			SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize);
4520185694Srrs			SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
4521185694Srrs
4522185694Srrs			/* deactivate the key from the right place */
4523185694Srrs			if (stcb) {
4524223132Stuexen				if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) {
4525223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4526185694Srrs					error = EINVAL;
4527185694Srrs				}
4528185694Srrs				SCTP_TCB_UNLOCK(stcb);
4529185694Srrs			} else {
4530224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4531224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4532224918Stuexen				    (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
4533223132Stuexen				    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
4534223132Stuexen					SCTP_INP_WLOCK(inp);
4535223132Stuexen					if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
4536223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4537223132Stuexen						error = EINVAL;
4538223132Stuexen					}
4539223132Stuexen					SCTP_INP_WUNLOCK(inp);
4540185694Srrs				}
4541223132Stuexen				if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
4542223132Stuexen				    (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
4543223132Stuexen					SCTP_INP_RLOCK(inp);
4544223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4545223132Stuexen						SCTP_TCB_LOCK(stcb);
4546223132Stuexen						sctp_deact_sharedkey(stcb, keyid->scact_keynumber);
4547223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4548223132Stuexen					}
4549223132Stuexen					SCTP_INP_RUNLOCK(inp);
4550223132Stuexen				}
4551185694Srrs			}
4552185694Srrs			break;
4553185694Srrs		}
4554233660Srrs	case SCTP_ENABLE_STREAM_RESET:
4555233660Srrs		{
4556233660Srrs			struct sctp_assoc_value *av;
4557185694Srrs
4558233660Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4559233660Srrs			if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
4560233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4561233660Srrs				error = EINVAL;
4562233660Srrs				break;
4563233660Srrs			}
4564233660Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4565233660Srrs			if (stcb) {
4566235021Stuexen				stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value;
4567233660Srrs				SCTP_TCB_UNLOCK(stcb);
4568233660Srrs			} else {
4569233660Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4570233660Srrs				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4571233660Srrs				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4572233660Srrs				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4573233660Srrs					SCTP_INP_WLOCK(inp);
4574235021Stuexen					inp->local_strreset_support = (uint8_t) av->assoc_value;
4575233660Srrs					SCTP_INP_WUNLOCK(inp);
4576233660Srrs				}
4577233660Srrs				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4578233660Srrs				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4579233660Srrs					SCTP_INP_RLOCK(inp);
4580233660Srrs					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4581233660Srrs						SCTP_TCB_LOCK(stcb);
4582235021Stuexen						stcb->asoc.local_strreset_support = (uint8_t) av->assoc_value;
4583233660Srrs						SCTP_TCB_UNLOCK(stcb);
4584233660Srrs					}
4585233660Srrs					SCTP_INP_RUNLOCK(inp);
4586233660Srrs				}
4587233660Srrs			}
4588233660Srrs			break;
4589233660Srrs		}
4590163953Srrs	case SCTP_RESET_STREAMS:
4591163953Srrs		{
4592233660Srrs			struct sctp_reset_streams *strrst;
4593233660Srrs			int i, send_out = 0;
4594233660Srrs			int send_in = 0;
4595163953Srrs
4596233660Srrs			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
4597233660Srrs			SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
4598163953Srrs			if (stcb == NULL) {
4599171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4600163953Srrs				error = ENOENT;
4601163953Srrs				break;
4602163953Srrs			}
4603270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4604163953Srrs				/*
4605233660Srrs				 * Peer does not support the chunk type.
4606163953Srrs				 */
4607233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4608233660Srrs				error = EOPNOTSUPP;
4609163953Srrs				SCTP_TCB_UNLOCK(stcb);
4610163953Srrs				break;
4611163953Srrs			}
4612273000Stuexen			if (sizeof(struct sctp_reset_streams) +
4613273000Stuexen			    strrst->srs_number_streams * sizeof(uint16_t) > optsize) {
4614273000Stuexen				error = EINVAL;
4615273000Stuexen				SCTP_TCB_UNLOCK(stcb);
4616273000Stuexen				break;
4617273000Stuexen			}
4618233660Srrs			if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
4619163953Srrs				send_in = 1;
4620294140Stuexen				if (stcb->asoc.stream_reset_outstanding) {
4621294140Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4622294140Stuexen					error = EALREADY;
4623294140Stuexen					SCTP_TCB_UNLOCK(stcb);
4624294140Stuexen					break;
4625294140Stuexen				}
4626233660Srrs			}
4627233660Srrs			if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
4628163953Srrs				send_out = 1;
4629233660Srrs			}
4630294140Stuexen			if ((strrst->srs_number_streams > SCTP_MAX_STREAMS_AT_ONCE_RESET) && send_in) {
4631294140Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
4632294140Stuexen				error = ENOMEM;
4633294140Stuexen				SCTP_TCB_UNLOCK(stcb);
4634294140Stuexen				break;
4635294140Stuexen			}
4636233660Srrs			if ((send_in == 0) && (send_out == 0)) {
4637233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4638233660Srrs				error = EINVAL;
4639233660Srrs				SCTP_TCB_UNLOCK(stcb);
4640233660Srrs				break;
4641233660Srrs			}
4642233660Srrs			for (i = 0; i < strrst->srs_number_streams; i++) {
4643233660Srrs				if ((send_in) &&
4644233660Srrs				    (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
4645233660Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4646188854Srrs					error = EINVAL;
4647233660Srrs					break;
4648188854Srrs				}
4649233660Srrs				if ((send_out) &&
4650233660Srrs				    (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
4651233660Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4652233660Srrs					error = EINVAL;
4653233660Srrs					break;
4654188854Srrs				}
4655233660Srrs			}
4656233660Srrs			if (error) {
4657233660Srrs				SCTP_TCB_UNLOCK(stcb);
4658233660Srrs				break;
4659233660Srrs			}
4660294140Stuexen			if (send_out) {
4661294140Stuexen				int cnt;
4662294140Stuexen				uint16_t strm;
4663233660Srrs
4664294140Stuexen				if (strrst->srs_number_streams) {
4665294140Stuexen					for (i = 0, cnt = 0; i < strrst->srs_number_streams; i++) {
4666294140Stuexen						strm = strrst->srs_stream_list[i];
4667294140Stuexen						if (stcb->asoc.strmout[strm].state == SCTP_STREAM_OPEN) {
4668294140Stuexen							stcb->asoc.strmout[strm].state = SCTP_STREAM_RESET_PENDING;
4669294140Stuexen							cnt++;
4670294140Stuexen						}
4671294140Stuexen					}
4672294140Stuexen				} else {
4673294140Stuexen					/* Its all */
4674294140Stuexen					for (i = 0, cnt = 0; i < stcb->asoc.streamoutcnt; i++) {
4675294140Stuexen						if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN) {
4676294140Stuexen							stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING;
4677294140Stuexen							cnt++;
4678294140Stuexen						}
4679294140Stuexen					}
4680294140Stuexen				}
4681294140Stuexen			}
4682294140Stuexen			if (send_in) {
4683294140Stuexen				error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
4684294140Stuexen				    strrst->srs_stream_list,
4685294140Stuexen				    send_in, 0, 0, 0, 0, 0);
4686294140Stuexen			} else
4687294141Stuexen				error = sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_LOCKED);
4688294140Stuexen			if (!error)
4689294140Stuexen				sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4690294140Stuexen
4691233660Srrs			SCTP_TCB_UNLOCK(stcb);
4692233660Srrs			break;
4693233660Srrs		}
4694233660Srrs	case SCTP_ADD_STREAMS:
4695233660Srrs		{
4696233660Srrs			struct sctp_add_streams *stradd;
4697233660Srrs			uint8_t addstream = 0;
4698233660Srrs			uint16_t add_o_strmcnt = 0;
4699233660Srrs			uint16_t add_i_strmcnt = 0;
4700233660Srrs
4701233660Srrs			SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
4702233660Srrs			SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
4703233660Srrs			if (stcb == NULL) {
4704233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4705233660Srrs				error = ENOENT;
4706233660Srrs				break;
4707233660Srrs			}
4708270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4709235057Stuexen				/*
4710235057Stuexen				 * Peer does not support the chunk type.
4711235057Stuexen				 */
4712235057Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4713235057Stuexen				error = EOPNOTSUPP;
4714235057Stuexen				SCTP_TCB_UNLOCK(stcb);
4715235057Stuexen				break;
4716235057Stuexen			}
4717235057Stuexen			if (stcb->asoc.stream_reset_outstanding) {
4718235057Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4719235057Stuexen				error = EALREADY;
4720235057Stuexen				SCTP_TCB_UNLOCK(stcb);
4721235057Stuexen				break;
4722235057Stuexen			}
4723233660Srrs			if ((stradd->sas_outstrms == 0) &&
4724233660Srrs			    (stradd->sas_instrms == 0)) {
4725233660Srrs				error = EINVAL;
4726233660Srrs				goto skip_stuff;
4727233660Srrs			}
4728233660Srrs			if (stradd->sas_outstrms) {
4729188854Srrs				addstream = 1;
4730188854Srrs				/* We allocate here */
4731233660Srrs				add_o_strmcnt = stradd->sas_outstrms;
4732233660Srrs				if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
4733188854Srrs					/* You can't have more than 64k */
4734188854Srrs					error = EINVAL;
4735188854Srrs					goto skip_stuff;
4736188854Srrs				}
4737163953Srrs			}
4738233660Srrs			if (stradd->sas_instrms) {
4739233660Srrs				int cnt;
4740163953Srrs
4741233660Srrs				addstream |= 2;
4742233660Srrs				/*
4743233660Srrs				 * We allocate inside
4744233660Srrs				 * sctp_send_str_reset_req()
4745233660Srrs				 */
4746233660Srrs				add_i_strmcnt = stradd->sas_instrms;
4747233660Srrs				cnt = add_i_strmcnt;
4748233660Srrs				cnt += stcb->asoc.streamincnt;
4749233660Srrs				if (cnt > 0x0000ffff) {
4750233660Srrs					/* You can't have more than 64k */
4751163953Srrs					error = EINVAL;
4752233660Srrs					goto skip_stuff;
4753163953Srrs				}
4754233660Srrs				if (cnt > (int)stcb->asoc.max_inbound_streams) {
4755233660Srrs					/* More than you are allowed */
4756163953Srrs					error = EINVAL;
4757233660Srrs					goto skip_stuff;
4758163953Srrs				}
4759163953Srrs			}
4760294140Stuexen			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
4761233660Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4762188854Srrs	skip_stuff:
4763233660Srrs			SCTP_TCB_UNLOCK(stcb);
4764233660Srrs			break;
4765233660Srrs		}
4766233660Srrs	case SCTP_RESET_ASSOC:
4767233660Srrs		{
4768294140Stuexen			int i;
4769233660Srrs			uint32_t *value;
4770233660Srrs
4771233660Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
4772233660Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
4773233660Srrs			if (stcb == NULL) {
4774233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4775233660Srrs				error = ENOENT;
4776233660Srrs				break;
4777233660Srrs			}
4778270361Stuexen			if (stcb->asoc.reconfig_supported == 0) {
4779233660Srrs				/*
4780233660Srrs				 * Peer does not support the chunk type.
4781233660Srrs				 */
4782233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4783233660Srrs				error = EOPNOTSUPP;
4784163953Srrs				SCTP_TCB_UNLOCK(stcb);
4785163953Srrs				break;
4786163953Srrs			}
4787233660Srrs			if (stcb->asoc.stream_reset_outstanding) {
4788233660Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4789233660Srrs				error = EALREADY;
4790233660Srrs				SCTP_TCB_UNLOCK(stcb);
4791233660Srrs				break;
4792233660Srrs			}
4793294140Stuexen			/*
4794294140Stuexen			 * Is there any data pending in the send or sent
4795294140Stuexen			 * queues?
4796294140Stuexen			 */
4797294140Stuexen			if (!TAILQ_EMPTY(&stcb->asoc.send_queue) ||
4798294140Stuexen			    !TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
4799294140Stuexen		busy_out:
4800294140Stuexen				error = EBUSY;
4801294140Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4802294140Stuexen				SCTP_TCB_UNLOCK(stcb);
4803294140Stuexen				break;
4804294140Stuexen			}
4805294140Stuexen			/* Do any streams have data queued? */
4806294140Stuexen			for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
4807294140Stuexen				if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
4808294140Stuexen					goto busy_out;
4809294140Stuexen				}
4810294140Stuexen			}
4811294140Stuexen			error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 1, 0, 0, 0, 0);
4812172090Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
4813163953Srrs			SCTP_TCB_UNLOCK(stcb);
4814223132Stuexen			break;
4815163953Srrs		}
4816163953Srrs	case SCTP_CONNECT_X:
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, 0);
4823163953Srrs		break;
4824163953Srrs	case SCTP_CONNECT_X_DELAYED:
4825166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
4826171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4827163953Srrs			error = EINVAL;
4828163953Srrs			break;
4829163953Srrs		}
4830166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
4831163953Srrs		break;
4832163953Srrs	case SCTP_CONNECT_X_COMPLETE:
4833163953Srrs		{
4834163953Srrs			struct sockaddr *sa;
4835163953Srrs
4836166675Srrs			/* FIXME MT: check correct? */
4837166675Srrs			SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
4838166675Srrs
4839163953Srrs			/* find tcb */
4840163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4841163953Srrs				SCTP_INP_RLOCK(inp);
4842163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
4843163953Srrs				if (stcb) {
4844163953Srrs					SCTP_TCB_LOCK(stcb);
4845163953Srrs				}
4846163953Srrs				SCTP_INP_RUNLOCK(inp);
4847163953Srrs			} else {
4848166675Srrs				/*
4849166675Srrs				 * We increment here since
4850166675Srrs				 * sctp_findassociation_ep_addr() wil do a
4851166675Srrs				 * decrement if it finds the stcb as long as
4852166675Srrs				 * the locked tcb (last argument) is NOT a
4853166675Srrs				 * TCB.. aka NULL.
4854166675Srrs				 */
4855163953Srrs				SCTP_INP_INCR_REF(inp);
4856283716Stuexen				stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
4857163953Srrs				if (stcb == NULL) {
4858163953Srrs					SCTP_INP_DECR_REF(inp);
4859163953Srrs				}
4860163953Srrs			}
4861163953Srrs
4862163953Srrs			if (stcb == NULL) {
4863171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
4864163953Srrs				error = ENOENT;
4865163953Srrs				break;
4866163953Srrs			}
4867163953Srrs			if (stcb->asoc.delayed_connection == 1) {
4868163953Srrs				stcb->asoc.delayed_connection = 0;
4869169378Srrs				(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
4870165220Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
4871165220Srrs				    stcb->asoc.primary_destination,
4872283822Stuexen				    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
4873172090Srrs				sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
4874163953Srrs			} else {
4875163953Srrs				/*
4876163953Srrs				 * already expired or did not use delayed
4877163953Srrs				 * connectx
4878163953Srrs				 */
4879171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4880163953Srrs				error = EALREADY;
4881163953Srrs			}
4882163953Srrs			SCTP_TCB_UNLOCK(stcb);
4883223132Stuexen			break;
4884163953Srrs		}
4885170056Srrs	case SCTP_MAX_BURST:
4886163953Srrs		{
4887217895Stuexen			struct sctp_assoc_value *av;
4888163953Srrs
4889217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4890217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4891166675Srrs
4892217895Stuexen			if (stcb) {
4893217895Stuexen				stcb->asoc.max_burst = av->assoc_value;
4894217895Stuexen				SCTP_TCB_UNLOCK(stcb);
4895217895Stuexen			} else {
4896224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4897224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4898224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC) ||
4899223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4900223132Stuexen					SCTP_INP_WLOCK(inp);
4901223132Stuexen					inp->sctp_ep.max_burst = av->assoc_value;
4902223132Stuexen					SCTP_INP_WUNLOCK(inp);
4903223132Stuexen				}
4904223132Stuexen				if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
4905223132Stuexen				    (av->assoc_id == SCTP_ALL_ASSOC)) {
4906223132Stuexen					SCTP_INP_RLOCK(inp);
4907223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
4908223132Stuexen						SCTP_TCB_LOCK(stcb);
4909223132Stuexen						stcb->asoc.max_burst = av->assoc_value;
4910223132Stuexen						SCTP_TCB_UNLOCK(stcb);
4911223132Stuexen					}
4912223132Stuexen					SCTP_INP_RUNLOCK(inp);
4913223132Stuexen				}
4914217895Stuexen			}
4915223132Stuexen			break;
4916163953Srrs		}
4917163953Srrs	case SCTP_MAXSEG:
4918163953Srrs		{
4919167598Srrs			struct sctp_assoc_value *av;
4920163953Srrs			int ovh;
4921163953Srrs
4922167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
4923167598Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
4924166675Srrs
4925170056Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
4926170056Srrs				ovh = SCTP_MED_OVERHEAD;
4927170056Srrs			} else {
4928170056Srrs				ovh = SCTP_MED_V4_OVERHEAD;
4929170056Srrs			}
4930167598Srrs			if (stcb) {
4931170056Srrs				if (av->assoc_value) {
4932170056Srrs					stcb->asoc.sctp_frag_point = (av->assoc_value + ovh);
4933170056Srrs				} else {
4934170056Srrs					stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
4935170056Srrs				}
4936167598Srrs				SCTP_TCB_UNLOCK(stcb);
4937163953Srrs			} else {
4938224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
4939224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
4940224918Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
4941223132Stuexen					SCTP_INP_WLOCK(inp);
4942223132Stuexen					/*
4943223132Stuexen					 * FIXME MT: I think this is not in
4944223132Stuexen					 * tune with the API ID
4945223132Stuexen					 */
4946223132Stuexen					if (av->assoc_value) {
4947223132Stuexen						inp->sctp_frag_point = (av->assoc_value + ovh);
4948223132Stuexen					} else {
4949223132Stuexen						inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
4950223132Stuexen					}
4951223132Stuexen					SCTP_INP_WUNLOCK(inp);
4952167598Srrs				} else {
4953223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4954223132Stuexen					error = EINVAL;
4955167598Srrs				}
4956163953Srrs			}
4957223132Stuexen			break;
4958163953Srrs		}
4959163953Srrs	case SCTP_EVENTS:
4960163953Srrs		{
4961163953Srrs			struct sctp_event_subscribe *events;
4962163953Srrs
4963166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
4964166675Srrs
4965163953Srrs			SCTP_INP_WLOCK(inp);
4966163953Srrs			if (events->sctp_data_io_event) {
4967163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
4968163953Srrs			} else {
4969163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
4970163953Srrs			}
4971163953Srrs
4972163953Srrs			if (events->sctp_association_event) {
4973163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4974163953Srrs			} else {
4975163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
4976163953Srrs			}
4977163953Srrs
4978163953Srrs			if (events->sctp_address_event) {
4979163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
4980163953Srrs			} else {
4981163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
4982163953Srrs			}
4983163953Srrs
4984163953Srrs			if (events->sctp_send_failure_event) {
4985163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4986163953Srrs			} else {
4987163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
4988163953Srrs			}
4989163953Srrs
4990163953Srrs			if (events->sctp_peer_error_event) {
4991163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
4992163953Srrs			} else {
4993163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
4994163953Srrs			}
4995163953Srrs
4996163953Srrs			if (events->sctp_shutdown_event) {
4997163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
4998163953Srrs			} else {
4999163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5000163953Srrs			}
5001163953Srrs
5002163953Srrs			if (events->sctp_partial_delivery_event) {
5003163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
5004163953Srrs			} else {
5005163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
5006163953Srrs			}
5007163953Srrs
5008163953Srrs			if (events->sctp_adaptation_layer_event) {
5009163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5010163953Srrs			} else {
5011163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5012163953Srrs			}
5013163953Srrs
5014163953Srrs			if (events->sctp_authentication_event) {
5015163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
5016163953Srrs			} else {
5017163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
5018163953Srrs			}
5019163953Srrs
5020185694Srrs			if (events->sctp_sender_dry_event) {
5021185694Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
5022185694Srrs			} else {
5023185694Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
5024185694Srrs			}
5025185694Srrs
5026202520Srrs			if (events->sctp_stream_reset_event) {
5027163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5028163953Srrs			} else {
5029163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5030163953Srrs			}
5031163953Srrs			SCTP_INP_WUNLOCK(inp);
5032223132Stuexen
5033223132Stuexen			SCTP_INP_RLOCK(inp);
5034223132Stuexen			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5035223132Stuexen				SCTP_TCB_LOCK(stcb);
5036223132Stuexen				if (events->sctp_association_event) {
5037223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
5038223132Stuexen				} else {
5039223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
5040223132Stuexen				}
5041223132Stuexen				if (events->sctp_address_event) {
5042223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
5043223132Stuexen				} else {
5044223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
5045223132Stuexen				}
5046223132Stuexen				if (events->sctp_send_failure_event) {
5047223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
5048223132Stuexen				} else {
5049223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
5050223132Stuexen				}
5051223132Stuexen				if (events->sctp_peer_error_event) {
5052223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
5053223132Stuexen				} else {
5054223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
5055223132Stuexen				}
5056223132Stuexen				if (events->sctp_shutdown_event) {
5057223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5058223132Stuexen				} else {
5059223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
5060223132Stuexen				}
5061223132Stuexen				if (events->sctp_partial_delivery_event) {
5062223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
5063223132Stuexen				} else {
5064223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
5065223132Stuexen				}
5066223132Stuexen				if (events->sctp_adaptation_layer_event) {
5067223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5068223132Stuexen				} else {
5069223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
5070223132Stuexen				}
5071223132Stuexen				if (events->sctp_authentication_event) {
5072223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
5073223132Stuexen				} else {
5074223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
5075223132Stuexen				}
5076223132Stuexen				if (events->sctp_sender_dry_event) {
5077223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
5078223132Stuexen				} else {
5079223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
5080223132Stuexen				}
5081223132Stuexen				if (events->sctp_stream_reset_event) {
5082223132Stuexen					sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5083223132Stuexen				} else {
5084223132Stuexen					sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
5085223132Stuexen				}
5086223132Stuexen				SCTP_TCB_UNLOCK(stcb);
5087223132Stuexen			}
5088223132Stuexen			/*
5089223132Stuexen			 * Send up the sender dry event only for 1-to-1
5090223132Stuexen			 * style sockets.
5091223132Stuexen			 */
5092223132Stuexen			if (events->sctp_sender_dry_event) {
5093223132Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5094223132Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
5095223132Stuexen					stcb = LIST_FIRST(&inp->sctp_asoc_list);
5096223132Stuexen					if (stcb) {
5097223132Stuexen						SCTP_TCB_LOCK(stcb);
5098223132Stuexen						if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
5099223132Stuexen						    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
5100223132Stuexen						    (stcb->asoc.stream_queue_cnt == 0)) {
5101223132Stuexen							sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
5102223132Stuexen						}
5103223132Stuexen						SCTP_TCB_UNLOCK(stcb);
5104223132Stuexen					}
5105223132Stuexen				}
5106223132Stuexen			}
5107223132Stuexen			SCTP_INP_RUNLOCK(inp);
5108223132Stuexen			break;
5109163953Srrs		}
5110163953Srrs	case SCTP_ADAPTATION_LAYER:
5111163953Srrs		{
5112163953Srrs			struct sctp_setadaptation *adap_bits;
5113163953Srrs
5114166675Srrs			SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
5115163953Srrs			SCTP_INP_WLOCK(inp);
5116163953Srrs			inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
5117246687Stuexen			inp->sctp_ep.adaptation_layer_indicator_provided = 1;
5118163953Srrs			SCTP_INP_WUNLOCK(inp);
5119223132Stuexen			break;
5120163953Srrs		}
5121166675Srrs#ifdef SCTP_DEBUG
5122163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
5123163953Srrs		{
5124163953Srrs			uint32_t *vvv;
5125163953Srrs
5126166675Srrs			SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
5127163953Srrs			SCTP_INP_WLOCK(inp);
5128163953Srrs			inp->sctp_ep.initial_sequence_debug = *vvv;
5129163953Srrs			SCTP_INP_WUNLOCK(inp);
5130223132Stuexen			break;
5131163953Srrs		}
5132166675Srrs#endif
5133163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
5134163953Srrs		{
5135163953Srrs			struct sctp_sndrcvinfo *s_info;
5136163953Srrs
5137166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
5138166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
5139163953Srrs
5140166675Srrs			if (stcb) {
5141223132Stuexen				if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
5142170056Srrs					memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
5143163953Srrs				} else {
5144171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5145166675Srrs					error = EINVAL;
5146163953Srrs				}
5147166675Srrs				SCTP_TCB_UNLOCK(stcb);
5148166675Srrs			} else {
5149224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5150224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5151224918Stuexen				    (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
5152223132Stuexen				    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
5153223132Stuexen					SCTP_INP_WLOCK(inp);
5154223132Stuexen					memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
5155223132Stuexen					SCTP_INP_WUNLOCK(inp);
5156223132Stuexen				}
5157223132Stuexen				if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
5158223132Stuexen				    (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
5159223132Stuexen					SCTP_INP_RLOCK(inp);
5160223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
5161223132Stuexen						SCTP_TCB_LOCK(stcb);
5162223132Stuexen						if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
5163223132Stuexen							memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
5164223132Stuexen						}
5165223132Stuexen						SCTP_TCB_UNLOCK(stcb);
5166223132Stuexen					}
5167223132Stuexen					SCTP_INP_RUNLOCK(inp);
5168223132Stuexen				}
5169163953Srrs			}
5170223132Stuexen			break;
5171163953Srrs		}
5172163953Srrs	case SCTP_PEER_ADDR_PARAMS:
5173163953Srrs		{
5174163953Srrs			struct sctp_paddrparams *paddrp;
5175163953Srrs			struct sctp_nets *net;
5176283699Stuexen			struct sockaddr *addr;
5177163953Srrs
5178283699Stuexen#if defined(INET) && defined(INET6)
5179283699Stuexen			struct sockaddr_in sin_store;
5180283699Stuexen
5181283699Stuexen#endif
5182283699Stuexen
5183166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
5184166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
5185283699Stuexen
5186283699Stuexen#if defined(INET) && defined(INET6)
5187283699Stuexen			if (paddrp->spp_address.ss_family == AF_INET6) {
5188283699Stuexen				struct sockaddr_in6 *sin6;
5189283699Stuexen
5190283699Stuexen				sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
5191283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5192283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
5193283699Stuexen					addr = (struct sockaddr *)&sin_store;
5194283699Stuexen				} else {
5195283699Stuexen					addr = (struct sockaddr *)&paddrp->spp_address;
5196283699Stuexen				}
5197166675Srrs			} else {
5198283699Stuexen				addr = (struct sockaddr *)&paddrp->spp_address;
5199283699Stuexen			}
5200283699Stuexen#else
5201283699Stuexen			addr = (struct sockaddr *)&paddrp->spp_address;
5202283699Stuexen#endif
5203283699Stuexen			if (stcb != NULL) {
5204283699Stuexen				net = sctp_findnet(stcb, addr);
5205283699Stuexen			} else {
5206166675Srrs				/*
5207166675Srrs				 * We increment here since
5208166675Srrs				 * sctp_findassociation_ep_addr() wil do a
5209166675Srrs				 * decrement if it finds the stcb as long as
5210166675Srrs				 * the locked tcb (last argument) is NOT a
5211166675Srrs				 * TCB.. aka NULL.
5212166675Srrs				 */
5213283699Stuexen				net = NULL;
5214166675Srrs				SCTP_INP_INCR_REF(inp);
5215283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr,
5216166675Srrs				    &net, NULL, NULL);
5217163953Srrs				if (stcb == NULL) {
5218166675Srrs					SCTP_INP_DECR_REF(inp);
5219163953Srrs				}
5220163953Srrs			}
5221283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
5222221249Stuexen#ifdef INET
5223283699Stuexen				if (addr->sa_family == AF_INET) {
5224221249Stuexen
5225171943Srrs					struct sockaddr_in *sin;
5226171943Srrs
5227283699Stuexen					sin = (struct sockaddr_in *)addr;
5228283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
5229171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5230171943Srrs						SCTP_TCB_UNLOCK(stcb);
5231171943Srrs						error = EINVAL;
5232171943Srrs						break;
5233171943Srrs					}
5234221249Stuexen				} else
5235221249Stuexen#endif
5236221249Stuexen#ifdef INET6
5237283699Stuexen				if (addr->sa_family == AF_INET6) {
5238171943Srrs					struct sockaddr_in6 *sin6;
5239171943Srrs
5240283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
5241171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
5242171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5243171943Srrs						SCTP_TCB_UNLOCK(stcb);
5244171943Srrs						error = EINVAL;
5245171943Srrs						break;
5246171943Srrs					}
5247221249Stuexen				} else
5248221249Stuexen#endif
5249221249Stuexen				{
5250171943Srrs					error = EAFNOSUPPORT;
5251171943Srrs					SCTP_TCB_UNLOCK(stcb);
5252171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
5253171943Srrs					break;
5254171943Srrs				}
5255171943Srrs			}
5256170056Srrs			/* sanity checks */
5257170056Srrs			if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
5258170056Srrs				if (stcb)
5259170056Srrs					SCTP_TCB_UNLOCK(stcb);
5260171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5261170056Srrs				return (EINVAL);
5262170056Srrs			}
5263170056Srrs			if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
5264170056Srrs				if (stcb)
5265170056Srrs					SCTP_TCB_UNLOCK(stcb);
5266171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5267170056Srrs				return (EINVAL);
5268170056Srrs			}
5269283699Stuexen			if (stcb != NULL) {
5270163953Srrs				/************************TCB SPECIFIC SET ******************/
5271283699Stuexen				if (net != NULL) {
5272163953Srrs					/************************NET SPECIFIC SET ******************/
5273224641Stuexen					if (paddrp->spp_flags & SPP_HB_DISABLE) {
5274224641Stuexen						if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
5275224641Stuexen						    !(net->dest_state & SCTP_ADDR_NOHB)) {
5276224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5277283822Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
5278171440Srrs						}
5279163953Srrs						net->dest_state |= SCTP_ADDR_NOHB;
5280163953Srrs					}
5281163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5282224641Stuexen						if (paddrp->spp_hbinterval) {
5283224641Stuexen							net->heart_beat_delay = paddrp->spp_hbinterval;
5284224641Stuexen						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5285224641Stuexen							net->heart_beat_delay = 0;
5286224641Stuexen						}
5287224641Stuexen						sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5288224641Stuexen						    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
5289224641Stuexen						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5290163953Srrs						net->dest_state &= ~SCTP_ADDR_NOHB;
5291163953Srrs					}
5292224641Stuexen					if (paddrp->spp_flags & SPP_HB_DEMAND) {
5293224641Stuexen						/* on demand HB */
5294224641Stuexen						sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5295228391Stuexen						sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
5296224641Stuexen						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5297224641Stuexen					}
5298170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
5299165647Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5300165220Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
5301283822Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
5302163953Srrs						}
5303225635Stuexen						net->dest_state |= SCTP_ADDR_NO_PMTUD;
5304283829Stuexen						net->mtu = paddrp->spp_pathmtu;
5305283829Stuexen						switch (net->ro._l_addr.sa.sa_family) {
5306283829Stuexen#ifdef INET
5307283829Stuexen						case AF_INET:
5308283829Stuexen							net->mtu += SCTP_MIN_V4_OVERHEAD;
5309283829Stuexen							break;
5310283829Stuexen#endif
5311283829Stuexen#ifdef INET6
5312283829Stuexen						case AF_INET6:
5313283829Stuexen							net->mtu += SCTP_MIN_OVERHEAD;
5314283829Stuexen							break;
5315283829Stuexen#endif
5316283829Stuexen						default:
5317283829Stuexen							break;
5318283829Stuexen						}
5319258454Stuexen						if (net->mtu < stcb->asoc.smallest_mtu) {
5320258454Stuexen							sctp_pathmtu_adjustment(stcb, net->mtu);
5321163953Srrs						}
5322163953Srrs					}
5323163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5324225635Stuexen						if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5325163953Srrs							sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
5326163953Srrs						}
5327225635Stuexen						net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
5328163953Srrs					}
5329224641Stuexen					if (paddrp->spp_pathmaxrxt) {
5330224641Stuexen						if (net->dest_state & SCTP_ADDR_PF) {
5331224641Stuexen							if (net->error_count > paddrp->spp_pathmaxrxt) {
5332224641Stuexen								net->dest_state &= ~SCTP_ADDR_PF;
5333224641Stuexen							}
5334224641Stuexen						} else {
5335224641Stuexen							if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
5336224641Stuexen							    (net->error_count > net->pf_threshold)) {
5337224641Stuexen								net->dest_state |= SCTP_ADDR_PF;
5338224641Stuexen								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5339283822Stuexen								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
5340283822Stuexen								    stcb->sctp_ep, stcb, net,
5341283822Stuexen								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12);
5342224641Stuexen								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5343224641Stuexen							}
5344224641Stuexen						}
5345224641Stuexen						if (net->dest_state & SCTP_ADDR_REACHABLE) {
5346224641Stuexen							if (net->error_count > paddrp->spp_pathmaxrxt) {
5347224641Stuexen								net->dest_state &= ~SCTP_ADDR_REACHABLE;
5348235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5349224641Stuexen							}
5350224641Stuexen						} else {
5351224641Stuexen							if (net->error_count <= paddrp->spp_pathmaxrxt) {
5352224641Stuexen								net->dest_state |= SCTP_ADDR_REACHABLE;
5353235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5354224641Stuexen							}
5355224641Stuexen						}
5356163953Srrs						net->failure_threshold = paddrp->spp_pathmaxrxt;
5357224641Stuexen					}
5358224870Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5359226252Stuexen						net->dscp = paddrp->spp_dscp & 0xfc;
5360225549Stuexen						net->dscp |= 0x01;
5361163953Srrs					}
5362167598Srrs#ifdef INET6
5363163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5364225549Stuexen						if (net->ro._l_addr.sa.sa_family == AF_INET6) {
5365224870Stuexen							net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5366225549Stuexen							net->flowlabel |= 0x80000000;
5367163953Srrs						}
5368163953Srrs					}
5369163953Srrs#endif
5370163953Srrs				} else {
5371163953Srrs					/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
5372283699Stuexen					if (paddrp->spp_pathmaxrxt != 0) {
5373163953Srrs						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
5374224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5375224641Stuexen							if (net->dest_state & SCTP_ADDR_PF) {
5376224641Stuexen								if (net->error_count > paddrp->spp_pathmaxrxt) {
5377224641Stuexen									net->dest_state &= ~SCTP_ADDR_PF;
5378224641Stuexen								}
5379224641Stuexen							} else {
5380224641Stuexen								if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
5381224641Stuexen								    (net->error_count > net->pf_threshold)) {
5382224641Stuexen									net->dest_state |= SCTP_ADDR_PF;
5383224641Stuexen									sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
5384283822Stuexen									sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
5385283822Stuexen									    stcb->sctp_ep, stcb, net,
5386283822Stuexen									    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_13);
5387224641Stuexen									sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
5388224641Stuexen								}
5389224641Stuexen							}
5390224641Stuexen							if (net->dest_state & SCTP_ADDR_REACHABLE) {
5391224641Stuexen								if (net->error_count > paddrp->spp_pathmaxrxt) {
5392224641Stuexen									net->dest_state &= ~SCTP_ADDR_REACHABLE;
5393235414Stuexen									sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
5394224641Stuexen								}
5395224641Stuexen							} else {
5396224641Stuexen								if (net->error_count <= paddrp->spp_pathmaxrxt) {
5397224641Stuexen									net->dest_state |= SCTP_ADDR_REACHABLE;
5398235414Stuexen									sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
5399224641Stuexen								}
5400224641Stuexen							}
5401224641Stuexen							net->failure_threshold = paddrp->spp_pathmaxrxt;
5402224641Stuexen						}
5403224641Stuexen					}
5404163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5405283699Stuexen						if (paddrp->spp_hbinterval != 0) {
5406224641Stuexen							stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
5407224641Stuexen						} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5408224641Stuexen							stcb->asoc.heart_beat_delay = 0;
5409224641Stuexen						}
5410163953Srrs						/* Turn back on the timer */
5411224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5412283699Stuexen							if (paddrp->spp_hbinterval != 0) {
5413224641Stuexen								net->heart_beat_delay = paddrp->spp_hbinterval;
5414224641Stuexen							} else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5415224641Stuexen								net->heart_beat_delay = 0;
5416224641Stuexen							}
5417224641Stuexen							if (net->dest_state & SCTP_ADDR_NOHB) {
5418224641Stuexen								net->dest_state &= ~SCTP_ADDR_NOHB;
5419224641Stuexen							}
5420224641Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
5421283822Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_14);
5422224641Stuexen							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
5423224641Stuexen						}
5424225635Stuexen						sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5425163953Srrs					}
5426224641Stuexen					if (paddrp->spp_flags & SPP_HB_DISABLE) {
5427224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5428224641Stuexen							if (!(net->dest_state & SCTP_ADDR_NOHB)) {
5429224641Stuexen								net->dest_state |= SCTP_ADDR_NOHB;
5430224641Stuexen								if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
5431283822Stuexen									sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
5432283822Stuexen									    inp, stcb, net,
5433283822Stuexen									    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15);
5434224641Stuexen								}
5435224641Stuexen							}
5436224641Stuexen						}
5437225635Stuexen						sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5438224641Stuexen					}
5439170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
5440170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5441170056Srrs							if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5442170056Srrs								sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
5443283822Stuexen								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16);
5444170056Srrs							}
5445225635Stuexen							net->dest_state |= SCTP_ADDR_NO_PMTUD;
5446283829Stuexen							net->mtu = paddrp->spp_pathmtu;
5447283829Stuexen							switch (net->ro._l_addr.sa.sa_family) {
5448283829Stuexen#ifdef INET
5449283829Stuexen							case AF_INET:
5450283829Stuexen								net->mtu += SCTP_MIN_V4_OVERHEAD;
5451283829Stuexen								break;
5452283829Stuexen#endif
5453283829Stuexen#ifdef INET6
5454283829Stuexen							case AF_INET6:
5455283829Stuexen								net->mtu += SCTP_MIN_OVERHEAD;
5456283829Stuexen								break;
5457283829Stuexen#endif
5458283829Stuexen							default:
5459283829Stuexen								break;
5460283829Stuexen							}
5461258454Stuexen							if (net->mtu < stcb->asoc.smallest_mtu) {
5462258454Stuexen								sctp_pathmtu_adjustment(stcb, net->mtu);
5463170056Srrs							}
5464170056Srrs						}
5465225635Stuexen						sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5466170056Srrs					}
5467170056Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5468170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5469225635Stuexen							if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
5470170056Srrs								sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
5471170056Srrs							}
5472225635Stuexen							net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
5473170056Srrs						}
5474225635Stuexen						sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5475170056Srrs					}
5476224870Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5477224641Stuexen						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5478226252Stuexen							net->dscp = paddrp->spp_dscp & 0xfc;
5479225549Stuexen							net->dscp |= 0x01;
5480163953Srrs						}
5481226252Stuexen						stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc;
5482225549Stuexen						stcb->asoc.default_dscp |= 0x01;
5483163953Srrs					}
5484225549Stuexen#ifdef INET6
5485224641Stuexen					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5486170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5487225549Stuexen							if (net->ro._l_addr.sa.sa_family == AF_INET6) {
5488225549Stuexen								net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5489225549Stuexen								net->flowlabel |= 0x80000000;
5490225549Stuexen							}
5491170056Srrs						}
5492225549Stuexen						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5493225549Stuexen						stcb->asoc.default_flowlabel |= 0x80000000;
5494163953Srrs					}
5495225549Stuexen#endif
5496163953Srrs				}
5497163953Srrs				SCTP_TCB_UNLOCK(stcb);
5498163953Srrs			} else {
5499163953Srrs				/************************NO TCB, SET TO default stuff ******************/
5500224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5501224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5502224918Stuexen				    (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) {
5503223132Stuexen					SCTP_INP_WLOCK(inp);
5504223132Stuexen					/*
5505223132Stuexen					 * For the TOS/FLOWLABEL stuff you
5506223132Stuexen					 * set it with the options on the
5507223132Stuexen					 * socket
5508223132Stuexen					 */
5509283699Stuexen					if (paddrp->spp_pathmaxrxt != 0) {
5510223132Stuexen						inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
5511223132Stuexen					}
5512223132Stuexen					if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
5513223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
5514283699Stuexen					else if (paddrp->spp_hbinterval != 0) {
5515223132Stuexen						if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
5516223132Stuexen							paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL;
5517223132Stuexen						inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
5518223132Stuexen					}
5519223132Stuexen					if (paddrp->spp_flags & SPP_HB_ENABLE) {
5520224641Stuexen						if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
5521224641Stuexen							inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
5522224641Stuexen						} else if (paddrp->spp_hbinterval) {
5523224641Stuexen							inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
5524224641Stuexen						}
5525223132Stuexen						sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5526223132Stuexen					} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
5527223132Stuexen						sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
5528223132Stuexen					}
5529225635Stuexen					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
5530225635Stuexen						sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5531225635Stuexen					} else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
5532225635Stuexen						sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
5533225635Stuexen					}
5534225549Stuexen					if (paddrp->spp_flags & SPP_DSCP) {
5535226252Stuexen						inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc;
5536225549Stuexen						inp->sctp_ep.default_dscp |= 0x01;
5537225549Stuexen					}
5538225549Stuexen#ifdef INET6
5539225549Stuexen					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
5540225549Stuexen						if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
5541225549Stuexen							inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
5542225549Stuexen							inp->sctp_ep.default_flowlabel |= 0x80000000;
5543225549Stuexen						}
5544225549Stuexen					}
5545225549Stuexen#endif
5546223132Stuexen					SCTP_INP_WUNLOCK(inp);
5547223132Stuexen				} else {
5548223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5549223132Stuexen					error = EINVAL;
5550163953Srrs				}
5551163953Srrs			}
5552223132Stuexen			break;
5553163953Srrs		}
5554163953Srrs	case SCTP_RTOINFO:
5555163953Srrs		{
5556163953Srrs			struct sctp_rtoinfo *srto;
5557169655Srrs			uint32_t new_init, new_min, new_max;
5558163953Srrs
5559166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
5560166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
5561166675Srrs
5562166675Srrs			if (stcb) {
5563167598Srrs				if (srto->srto_initial)
5564169655Srrs					new_init = srto->srto_initial;
5565169655Srrs				else
5566169655Srrs					new_init = stcb->asoc.initial_rto;
5567167598Srrs				if (srto->srto_max)
5568169655Srrs					new_max = srto->srto_max;
5569169655Srrs				else
5570169655Srrs					new_max = stcb->asoc.maxrto;
5571167598Srrs				if (srto->srto_min)
5572169655Srrs					new_min = srto->srto_min;
5573169655Srrs				else
5574169655Srrs					new_min = stcb->asoc.minrto;
5575169655Srrs				if ((new_min <= new_init) && (new_init <= new_max)) {
5576169655Srrs					stcb->asoc.initial_rto = new_init;
5577169655Srrs					stcb->asoc.maxrto = new_max;
5578169655Srrs					stcb->asoc.minrto = new_min;
5579169655Srrs				} else {
5580179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5581179783Srrs					error = EINVAL;
5582169655Srrs				}
5583166675Srrs				SCTP_TCB_UNLOCK(stcb);
5584166675Srrs			} else {
5585224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5586224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5587224918Stuexen				    (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) {
5588223132Stuexen					SCTP_INP_WLOCK(inp);
5589223132Stuexen					if (srto->srto_initial)
5590223132Stuexen						new_init = srto->srto_initial;
5591223132Stuexen					else
5592223132Stuexen						new_init = inp->sctp_ep.initial_rto;
5593223132Stuexen					if (srto->srto_max)
5594223132Stuexen						new_max = srto->srto_max;
5595223132Stuexen					else
5596223132Stuexen						new_max = inp->sctp_ep.sctp_maxrto;
5597223132Stuexen					if (srto->srto_min)
5598223132Stuexen						new_min = srto->srto_min;
5599223132Stuexen					else
5600223132Stuexen						new_min = inp->sctp_ep.sctp_minrto;
5601223132Stuexen					if ((new_min <= new_init) && (new_init <= new_max)) {
5602223132Stuexen						inp->sctp_ep.initial_rto = new_init;
5603223132Stuexen						inp->sctp_ep.sctp_maxrto = new_max;
5604223132Stuexen						inp->sctp_ep.sctp_minrto = new_min;
5605223132Stuexen					} else {
5606223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5607223132Stuexen						error = EINVAL;
5608223132Stuexen					}
5609223132Stuexen					SCTP_INP_WUNLOCK(inp);
5610169655Srrs				} else {
5611179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5612179783Srrs					error = EINVAL;
5613169655Srrs				}
5614163953Srrs			}
5615223132Stuexen			break;
5616163953Srrs		}
5617163953Srrs	case SCTP_ASSOCINFO:
5618163953Srrs		{
5619163953Srrs			struct sctp_assocparams *sasoc;
5620163953Srrs
5621166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
5622166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
5623171477Srrs			if (sasoc->sasoc_cookie_life) {
5624171477Srrs				/* boundary check the cookie life */
5625171477Srrs				if (sasoc->sasoc_cookie_life < 1000)
5626171477Srrs					sasoc->sasoc_cookie_life = 1000;
5627171477Srrs				if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
5628171477Srrs					sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
5629171477Srrs				}
5630171477Srrs			}
5631163953Srrs			if (stcb) {
5632163953Srrs				if (sasoc->sasoc_asocmaxrxt)
5633163953Srrs					stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
5634170056Srrs				if (sasoc->sasoc_cookie_life) {
5635171572Srrs					stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
5636167598Srrs				}
5637163953Srrs				SCTP_TCB_UNLOCK(stcb);
5638163953Srrs			} else {
5639224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
5640224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
5641224918Stuexen				    (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) {
5642223132Stuexen					SCTP_INP_WLOCK(inp);
5643223132Stuexen					if (sasoc->sasoc_asocmaxrxt)
5644223132Stuexen						inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
5645223132Stuexen					if (sasoc->sasoc_cookie_life) {
5646223132Stuexen						inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
5647223132Stuexen					}
5648223132Stuexen					SCTP_INP_WUNLOCK(inp);
5649223132Stuexen				} else {
5650223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5651223132Stuexen					error = EINVAL;
5652167598Srrs				}
5653163953Srrs			}
5654223132Stuexen			break;
5655163953Srrs		}
5656163953Srrs	case SCTP_INITMSG:
5657163953Srrs		{
5658163953Srrs			struct sctp_initmsg *sinit;
5659163953Srrs
5660166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
5661163953Srrs			SCTP_INP_WLOCK(inp);
5662163953Srrs			if (sinit->sinit_num_ostreams)
5663163953Srrs				inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
5664163953Srrs
5665163953Srrs			if (sinit->sinit_max_instreams)
5666163953Srrs				inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
5667163953Srrs
5668163953Srrs			if (sinit->sinit_max_attempts)
5669163953Srrs				inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
5670163953Srrs
5671167598Srrs			if (sinit->sinit_max_init_timeo)
5672163953Srrs				inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
5673163953Srrs			SCTP_INP_WUNLOCK(inp);
5674223132Stuexen			break;
5675163953Srrs		}
5676163953Srrs	case SCTP_PRIMARY_ADDR:
5677163953Srrs		{
5678163953Srrs			struct sctp_setprim *spa;
5679223132Stuexen			struct sctp_nets *net;
5680283699Stuexen			struct sockaddr *addr;
5681163953Srrs
5682283699Stuexen#if defined(INET) && defined(INET6)
5683283699Stuexen			struct sockaddr_in sin_store;
5684283699Stuexen
5685283699Stuexen#endif
5686283699Stuexen
5687166675Srrs			SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
5688166675Srrs			SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
5689163953Srrs
5690283699Stuexen#if defined(INET) && defined(INET6)
5691283699Stuexen			if (spa->ssp_addr.ss_family == AF_INET6) {
5692283699Stuexen				struct sockaddr_in6 *sin6;
5693283699Stuexen
5694283699Stuexen				sin6 = (struct sockaddr_in6 *)&spa->ssp_addr;
5695283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5696283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
5697283699Stuexen					addr = (struct sockaddr *)&sin_store;
5698283699Stuexen				} else {
5699283699Stuexen					addr = (struct sockaddr *)&spa->ssp_addr;
5700283699Stuexen				}
5701166675Srrs			} else {
5702283699Stuexen				addr = (struct sockaddr *)&spa->ssp_addr;
5703283699Stuexen			}
5704283699Stuexen#else
5705283699Stuexen			addr = (struct sockaddr *)&spa->ssp_addr;
5706283699Stuexen#endif
5707283699Stuexen			if (stcb != NULL) {
5708283699Stuexen				net = sctp_findnet(stcb, addr);
5709283699Stuexen			} else {
5710166675Srrs				/*
5711166675Srrs				 * We increment here since
5712166675Srrs				 * sctp_findassociation_ep_addr() wil do a
5713166675Srrs				 * decrement if it finds the stcb as long as
5714166675Srrs				 * the locked tcb (last argument) is NOT a
5715166675Srrs				 * TCB.. aka NULL.
5716166675Srrs				 */
5717283699Stuexen				net = NULL;
5718163953Srrs				SCTP_INP_INCR_REF(inp);
5719283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr,
5720163953Srrs				    &net, NULL, NULL);
5721163953Srrs				if (stcb == NULL) {
5722163953Srrs					SCTP_INP_DECR_REF(inp);
5723163953Srrs				}
5724163953Srrs			}
5725166675Srrs
5726283699Stuexen			if ((stcb != NULL) && (net != NULL)) {
5727284693Stuexen				if (net != stcb->asoc.primary_destination) {
5728284693Stuexen					if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
5729284693Stuexen						/* Ok we need to set it */
5730284693Stuexen						if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
5731284693Stuexen							if ((stcb->asoc.alternate) &&
5732284693Stuexen							    (!(net->dest_state & SCTP_ADDR_PF)) &&
5733284693Stuexen							    (net->dest_state & SCTP_ADDR_REACHABLE)) {
5734284693Stuexen								sctp_free_remote_addr(stcb->asoc.alternate);
5735284693Stuexen								stcb->asoc.alternate = NULL;
5736284693Stuexen							}
5737284693Stuexen						} else {
5738284693Stuexen							SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5739284693Stuexen							error = EINVAL;
5740166675Srrs						}
5741284693Stuexen					} else {
5742284693Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5743284693Stuexen						error = EINVAL;
5744163953Srrs					}
5745163953Srrs				}
5746166675Srrs			} else {
5747171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5748166675Srrs				error = EINVAL;
5749163953Srrs			}
5750283699Stuexen			if (stcb != NULL) {
5751166675Srrs				SCTP_TCB_UNLOCK(stcb);
5752166675Srrs			}
5753223132Stuexen			break;
5754163953Srrs		}
5755167598Srrs	case SCTP_SET_DYNAMIC_PRIMARY:
5756167598Srrs		{
5757167598Srrs			union sctp_sockstore *ss;
5758163953Srrs
5759170587Srwatson			error = priv_check(curthread,
5760170587Srwatson			    PRIV_NETINET_RESERVEDPORT);
5761167598Srrs			if (error)
5762167598Srrs				break;
5763167598Srrs
5764167598Srrs			SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
5765167598Srrs			/* SUPER USER CHECK? */
5766167598Srrs			error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
5767223132Stuexen			break;
5768167598Srrs		}
5769163953Srrs	case SCTP_SET_PEER_PRIMARY_ADDR:
5770163953Srrs		{
5771163953Srrs			struct sctp_setpeerprim *sspp;
5772283699Stuexen			struct sockaddr *addr;
5773163953Srrs
5774283699Stuexen#if defined(INET) && defined(INET6)
5775283699Stuexen			struct sockaddr_in sin_store;
5776283699Stuexen
5777283699Stuexen#endif
5778283699Stuexen
5779166675Srrs			SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
5780166675Srrs			SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
5781169208Srrs			if (stcb != NULL) {
5782170056Srrs				struct sctp_ifa *ifa;
5783170056Srrs
5784283699Stuexen#if defined(INET) && defined(INET6)
5785283699Stuexen				if (sspp->sspp_addr.ss_family == AF_INET6) {
5786283699Stuexen					struct sockaddr_in6 *sin6;
5787283699Stuexen
5788283699Stuexen					sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr;
5789283699Stuexen					if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
5790283699Stuexen						in6_sin6_2_sin(&sin_store, sin6);
5791283699Stuexen						addr = (struct sockaddr *)&sin_store;
5792283699Stuexen					} else {
5793283699Stuexen						addr = (struct sockaddr *)&sspp->sspp_addr;
5794283699Stuexen					}
5795283699Stuexen				} else {
5796283699Stuexen					addr = (struct sockaddr *)&sspp->sspp_addr;
5797283699Stuexen				}
5798283699Stuexen#else
5799283699Stuexen				addr = (struct sockaddr *)&sspp->sspp_addr;
5800283699Stuexen#endif
5801283699Stuexen				ifa = sctp_find_ifa_by_addr(addr, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
5802170056Srrs				if (ifa == NULL) {
5803171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5804166675Srrs					error = EINVAL;
5805170056Srrs					goto out_of_it;
5806166675Srrs				}
5807170056Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
5808170056Srrs					/*
5809170056Srrs					 * Must validate the ifa found is in
5810170056Srrs					 * our ep
5811170056Srrs					 */
5812170056Srrs					struct sctp_laddr *laddr;
5813170056Srrs					int found = 0;
5814170056Srrs
5815170056Srrs					LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
5816170056Srrs						if (laddr->ifa == NULL) {
5817170056Srrs							SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
5818294174Stuexen							    __func__);
5819170056Srrs							continue;
5820170056Srrs						}
5821170056Srrs						if (laddr->ifa == ifa) {
5822170056Srrs							found = 1;
5823170056Srrs							break;
5824170056Srrs						}
5825170056Srrs					}
5826170056Srrs					if (!found) {
5827171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5828170056Srrs						error = EINVAL;
5829170056Srrs						goto out_of_it;
5830170056Srrs					}
5831267769Stuexen				} else {
5832283699Stuexen					switch (addr->sa_family) {
5833267769Stuexen#ifdef INET
5834267769Stuexen					case AF_INET:
5835267769Stuexen						{
5836267769Stuexen							struct sockaddr_in *sin;
5837267769Stuexen
5838283699Stuexen							sin = (struct sockaddr_in *)addr;
5839267769Stuexen							if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
5840267769Stuexen							    &sin->sin_addr) != 0) {
5841267769Stuexen								SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5842267769Stuexen								error = EINVAL;
5843267769Stuexen								goto out_of_it;
5844267769Stuexen							}
5845267769Stuexen							break;
5846267769Stuexen						}
5847267769Stuexen#endif
5848267769Stuexen#ifdef INET6
5849267769Stuexen					case AF_INET6:
5850267769Stuexen						{
5851267769Stuexen							struct sockaddr_in6 *sin6;
5852267769Stuexen
5853283699Stuexen							sin6 = (struct sockaddr_in6 *)addr;
5854267769Stuexen							if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
5855267769Stuexen							    &sin6->sin6_addr) != 0) {
5856267769Stuexen								SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5857267769Stuexen								error = EINVAL;
5858267769Stuexen								goto out_of_it;
5859267769Stuexen							}
5860267769Stuexen							break;
5861267769Stuexen						}
5862267769Stuexen#endif
5863267769Stuexen					default:
5864267769Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5865267769Stuexen						error = EINVAL;
5866267769Stuexen						goto out_of_it;
5867267769Stuexen					}
5868170056Srrs				}
5869283699Stuexen				if (sctp_set_primary_ip_address_sa(stcb, addr) != 0) {
5870171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5871170056Srrs					error = EINVAL;
5872170056Srrs				}
5873170056Srrs		out_of_it:
5874169208Srrs				SCTP_TCB_UNLOCK(stcb);
5875166675Srrs			} else {
5876171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5877163953Srrs				error = EINVAL;
5878163953Srrs			}
5879223132Stuexen			break;
5880163953Srrs		}
5881163953Srrs	case SCTP_BINDX_ADD_ADDR:
5882163953Srrs		{
5883163953Srrs			struct sctp_getaddresses *addrs;
5884171477Srrs			struct thread *td;
5885163953Srrs
5886171477Srrs			td = (struct thread *)p;
5887170606Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
5888170606Srrs			    optsize);
5889221249Stuexen#ifdef INET
5890171477Srrs			if (addrs->addr->sa_family == AF_INET) {
5891238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
5892171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5893171477Srrs					error = EINVAL;
5894171477Srrs					break;
5895171477Srrs				}
5896188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
5897188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5898185435Sbz					break;
5899171477Srrs				}
5900221249Stuexen			} else
5901221249Stuexen#endif
5902185435Sbz#ifdef INET6
5903221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
5904238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
5905171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5906171477Srrs					error = EINVAL;
5907171477Srrs					break;
5908171477Srrs				}
5909188590Srrs				if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
5910188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
5911188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5912185435Sbz					break;
5913185435Sbz				}
5914221249Stuexen			} else
5915185435Sbz#endif
5916221249Stuexen			{
5917185435Sbz				error = EAFNOSUPPORT;
5918185435Sbz				break;
5919171477Srrs			}
5920170606Srrs			sctp_bindx_add_address(so, inp, addrs->addr,
5921170606Srrs			    addrs->sget_assoc_id, vrf_id,
5922170606Srrs			    &error, p);
5923223132Stuexen			break;
5924163953Srrs		}
5925163953Srrs	case SCTP_BINDX_REM_ADDR:
5926163953Srrs		{
5927163953Srrs			struct sctp_getaddresses *addrs;
5928171477Srrs			struct thread *td;
5929163953Srrs
5930171477Srrs			td = (struct thread *)p;
5931185435Sbz
5932166675Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
5933221249Stuexen#ifdef INET
5934171477Srrs			if (addrs->addr->sa_family == AF_INET) {
5935238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) {
5936171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5937171477Srrs					error = EINVAL;
5938171477Srrs					break;
5939171477Srrs				}
5940188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
5941188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5942185435Sbz					break;
5943171477Srrs				}
5944221249Stuexen			} else
5945221249Stuexen#endif
5946185435Sbz#ifdef INET6
5947221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
5948238501Stuexen				if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) {
5949171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5950171477Srrs					error = EINVAL;
5951171477Srrs					break;
5952171477Srrs				}
5953224641Stuexen				if (td != NULL &&
5954224641Stuexen				    (error = prison_local_ip6(td->td_ucred,
5955224641Stuexen				    &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
5956188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
5957188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
5958185435Sbz					break;
5959185435Sbz				}
5960221249Stuexen			} else
5961185435Sbz#endif
5962221249Stuexen			{
5963185435Sbz				error = EAFNOSUPPORT;
5964185435Sbz				break;
5965171477Srrs			}
5966228653Stuexen			sctp_bindx_delete_address(inp, addrs->addr,
5967170606Srrs			    addrs->sget_assoc_id, vrf_id,
5968170606Srrs			    &error);
5969223132Stuexen			break;
5970163953Srrs		}
5971223132Stuexen	case SCTP_EVENT:
5972223132Stuexen		{
5973223132Stuexen			struct sctp_event *event;
5974223132Stuexen			uint32_t event_type;
5975223132Stuexen
5976223132Stuexen			SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize);
5977223132Stuexen			SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
5978223132Stuexen			switch (event->se_type) {
5979223132Stuexen			case SCTP_ASSOC_CHANGE:
5980223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
5981223132Stuexen				break;
5982223132Stuexen			case SCTP_PEER_ADDR_CHANGE:
5983223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
5984223132Stuexen				break;
5985223132Stuexen			case SCTP_REMOTE_ERROR:
5986223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVPEERERR;
5987223132Stuexen				break;
5988223132Stuexen			case SCTP_SEND_FAILED:
5989223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
5990223132Stuexen				break;
5991223132Stuexen			case SCTP_SHUTDOWN_EVENT:
5992223132Stuexen				event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
5993223132Stuexen				break;
5994223132Stuexen			case SCTP_ADAPTATION_INDICATION:
5995223132Stuexen				event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
5996223132Stuexen				break;
5997223132Stuexen			case SCTP_PARTIAL_DELIVERY_EVENT:
5998223132Stuexen				event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
5999223132Stuexen				break;
6000223132Stuexen			case SCTP_AUTHENTICATION_EVENT:
6001223132Stuexen				event_type = SCTP_PCB_FLAGS_AUTHEVNT;
6002223132Stuexen				break;
6003223132Stuexen			case SCTP_STREAM_RESET_EVENT:
6004223132Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
6005223132Stuexen				break;
6006223132Stuexen			case SCTP_SENDER_DRY_EVENT:
6007223132Stuexen				event_type = SCTP_PCB_FLAGS_DRYEVNT;
6008223132Stuexen				break;
6009223132Stuexen			case SCTP_NOTIFICATIONS_STOPPED_EVENT:
6010223132Stuexen				event_type = 0;
6011223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
6012223132Stuexen				error = ENOTSUP;
6013223132Stuexen				break;
6014235009Stuexen			case SCTP_ASSOC_RESET_EVENT:
6015235009Stuexen				event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
6016235009Stuexen				break;
6017235009Stuexen			case SCTP_STREAM_CHANGE_EVENT:
6018235009Stuexen				event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
6019235009Stuexen				break;
6020235075Stuexen			case SCTP_SEND_FAILED_EVENT:
6021235075Stuexen				event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
6022235075Stuexen				break;
6023223132Stuexen			default:
6024223132Stuexen				event_type = 0;
6025223132Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6026223132Stuexen				error = EINVAL;
6027223132Stuexen				break;
6028223132Stuexen			}
6029223132Stuexen			if (event_type > 0) {
6030223132Stuexen				if (stcb) {
6031223132Stuexen					if (event->se_on) {
6032223132Stuexen						sctp_stcb_feature_on(inp, stcb, event_type);
6033223132Stuexen						if (event_type == SCTP_PCB_FLAGS_DRYEVNT) {
6034223132Stuexen							if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
6035223132Stuexen							    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
6036223132Stuexen							    (stcb->asoc.stream_queue_cnt == 0)) {
6037223132Stuexen								sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
6038223132Stuexen							}
6039223132Stuexen						}
6040223132Stuexen					} else {
6041223132Stuexen						sctp_stcb_feature_off(inp, stcb, event_type);
6042223132Stuexen					}
6043223132Stuexen					SCTP_TCB_UNLOCK(stcb);
6044223132Stuexen				} else {
6045223132Stuexen					/*
6046223132Stuexen					 * We don't want to send up a storm
6047223132Stuexen					 * of events, so return an error for
6048223132Stuexen					 * sender dry events
6049223132Stuexen					 */
6050223132Stuexen					if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
6051224918Stuexen					    ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) &&
6052224918Stuexen					    ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) &&
6053223132Stuexen					    ((event->se_assoc_id == SCTP_ALL_ASSOC) ||
6054223132Stuexen					    (event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
6055223132Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
6056223132Stuexen						error = ENOTSUP;
6057223132Stuexen						break;
6058223132Stuexen					}
6059224918Stuexen					if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6060224918Stuexen					    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6061224918Stuexen					    (event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
6062223132Stuexen					    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
6063223132Stuexen						SCTP_INP_WLOCK(inp);
6064223132Stuexen						if (event->se_on) {
6065223132Stuexen							sctp_feature_on(inp, event_type);
6066223132Stuexen						} else {
6067223132Stuexen							sctp_feature_off(inp, event_type);
6068223132Stuexen						}
6069223132Stuexen						SCTP_INP_WUNLOCK(inp);
6070223132Stuexen					}
6071223132Stuexen					if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
6072223132Stuexen					    (event->se_assoc_id == SCTP_ALL_ASSOC)) {
6073223132Stuexen						SCTP_INP_RLOCK(inp);
6074223132Stuexen						LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6075223132Stuexen							SCTP_TCB_LOCK(stcb);
6076223132Stuexen							if (event->se_on) {
6077223132Stuexen								sctp_stcb_feature_on(inp, stcb, event_type);
6078223132Stuexen							} else {
6079223132Stuexen								sctp_stcb_feature_off(inp, stcb, event_type);
6080223132Stuexen							}
6081223132Stuexen							SCTP_TCB_UNLOCK(stcb);
6082223132Stuexen						}
6083223132Stuexen						SCTP_INP_RUNLOCK(inp);
6084223132Stuexen					}
6085223132Stuexen				}
6086223132Stuexen			}
6087223132Stuexen			break;
6088223132Stuexen		}
6089223132Stuexen	case SCTP_RECVRCVINFO:
6090223132Stuexen		{
6091223132Stuexen			int *onoff;
6092223132Stuexen
6093223132Stuexen			SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
6094223132Stuexen			SCTP_INP_WLOCK(inp);
6095223132Stuexen			if (*onoff != 0) {
6096223132Stuexen				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
6097223132Stuexen			} else {
6098223132Stuexen				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
6099223132Stuexen			}
6100223132Stuexen			SCTP_INP_WUNLOCK(inp);
6101223132Stuexen			break;
6102223132Stuexen		}
6103223132Stuexen	case SCTP_RECVNXTINFO:
6104223132Stuexen		{
6105223132Stuexen			int *onoff;
6106223132Stuexen
6107223132Stuexen			SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
6108223132Stuexen			SCTP_INP_WLOCK(inp);
6109223132Stuexen			if (*onoff != 0) {
6110223132Stuexen				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
6111223132Stuexen			} else {
6112223132Stuexen				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
6113223132Stuexen			}
6114223132Stuexen			SCTP_INP_WUNLOCK(inp);
6115223132Stuexen			break;
6116223132Stuexen		}
6117223132Stuexen	case SCTP_DEFAULT_SNDINFO:
6118223132Stuexen		{
6119223132Stuexen			struct sctp_sndinfo *info;
6120223162Stuexen			uint16_t policy;
6121223132Stuexen
6122223132Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize);
6123223132Stuexen			SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
6124223132Stuexen
6125223132Stuexen			if (stcb) {
6126223132Stuexen				if (info->snd_sid < stcb->asoc.streamoutcnt) {
6127223132Stuexen					stcb->asoc.def_send.sinfo_stream = info->snd_sid;
6128223162Stuexen					policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
6129223132Stuexen					stcb->asoc.def_send.sinfo_flags = info->snd_flags;
6130223162Stuexen					stcb->asoc.def_send.sinfo_flags |= policy;
6131223132Stuexen					stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
6132223132Stuexen					stcb->asoc.def_send.sinfo_context = info->snd_context;
6133223132Stuexen				} else {
6134223132Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6135223132Stuexen					error = EINVAL;
6136223132Stuexen				}
6137223132Stuexen				SCTP_TCB_UNLOCK(stcb);
6138223132Stuexen			} else {
6139224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6140224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6141224918Stuexen				    (info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
6142223132Stuexen				    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
6143223132Stuexen					SCTP_INP_WLOCK(inp);
6144223132Stuexen					inp->def_send.sinfo_stream = info->snd_sid;
6145223162Stuexen					policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
6146223132Stuexen					inp->def_send.sinfo_flags = info->snd_flags;
6147223162Stuexen					inp->def_send.sinfo_flags |= policy;
6148223132Stuexen					inp->def_send.sinfo_ppid = info->snd_ppid;
6149223132Stuexen					inp->def_send.sinfo_context = info->snd_context;
6150223132Stuexen					SCTP_INP_WUNLOCK(inp);
6151223132Stuexen				}
6152223132Stuexen				if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
6153223132Stuexen				    (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
6154223132Stuexen					SCTP_INP_RLOCK(inp);
6155223132Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6156223132Stuexen						SCTP_TCB_LOCK(stcb);
6157223132Stuexen						if (info->snd_sid < stcb->asoc.streamoutcnt) {
6158223132Stuexen							stcb->asoc.def_send.sinfo_stream = info->snd_sid;
6159223162Stuexen							policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
6160223132Stuexen							stcb->asoc.def_send.sinfo_flags = info->snd_flags;
6161223162Stuexen							stcb->asoc.def_send.sinfo_flags |= policy;
6162223132Stuexen							stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
6163223132Stuexen							stcb->asoc.def_send.sinfo_context = info->snd_context;
6164223132Stuexen						}
6165223132Stuexen						SCTP_TCB_UNLOCK(stcb);
6166223132Stuexen					}
6167223132Stuexen					SCTP_INP_RUNLOCK(inp);
6168223132Stuexen				}
6169223132Stuexen			}
6170223132Stuexen			break;
6171223132Stuexen		}
6172223162Stuexen	case SCTP_DEFAULT_PRINFO:
6173223162Stuexen		{
6174223162Stuexen			struct sctp_default_prinfo *info;
6175223162Stuexen
6176223162Stuexen			SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize);
6177223162Stuexen			SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
6178223162Stuexen
6179283706Stuexen			if (info->pr_policy > SCTP_PR_SCTP_MAX) {
6180223162Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6181223162Stuexen				error = EINVAL;
6182223162Stuexen				break;
6183223162Stuexen			}
6184223162Stuexen			if (stcb) {
6185223162Stuexen				stcb->asoc.def_send.sinfo_flags &= 0xfff0;
6186223162Stuexen				stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
6187224918Stuexen				stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
6188223162Stuexen				SCTP_TCB_UNLOCK(stcb);
6189223162Stuexen			} else {
6190224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6191224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6192224918Stuexen				    (info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
6193223162Stuexen				    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
6194223162Stuexen					SCTP_INP_WLOCK(inp);
6195223162Stuexen					inp->def_send.sinfo_flags &= 0xfff0;
6196223162Stuexen					inp->def_send.sinfo_flags |= info->pr_policy;
6197224918Stuexen					inp->def_send.sinfo_timetolive = info->pr_value;
6198223162Stuexen					SCTP_INP_WUNLOCK(inp);
6199223162Stuexen				}
6200223162Stuexen				if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
6201223162Stuexen				    (info->pr_assoc_id == SCTP_ALL_ASSOC)) {
6202223162Stuexen					SCTP_INP_RLOCK(inp);
6203223162Stuexen					LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
6204223162Stuexen						SCTP_TCB_LOCK(stcb);
6205223162Stuexen						stcb->asoc.def_send.sinfo_flags &= 0xfff0;
6206223162Stuexen						stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
6207224918Stuexen						stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
6208223162Stuexen						SCTP_TCB_UNLOCK(stcb);
6209223162Stuexen					}
6210223162Stuexen					SCTP_INP_RUNLOCK(inp);
6211223162Stuexen				}
6212223162Stuexen			}
6213223162Stuexen			break;
6214223162Stuexen		}
6215224641Stuexen	case SCTP_PEER_ADDR_THLDS:
6216224641Stuexen		/* Applies to the specific association */
6217224641Stuexen		{
6218224641Stuexen			struct sctp_paddrthlds *thlds;
6219224641Stuexen			struct sctp_nets *net;
6220283699Stuexen			struct sockaddr *addr;
6221224641Stuexen
6222283699Stuexen#if defined(INET) && defined(INET6)
6223283699Stuexen			struct sockaddr_in sin_store;
6224283699Stuexen
6225283699Stuexen#endif
6226283699Stuexen
6227224641Stuexen			SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
6228224641Stuexen			SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
6229283699Stuexen
6230283699Stuexen#if defined(INET) && defined(INET6)
6231283699Stuexen			if (thlds->spt_address.ss_family == AF_INET6) {
6232283699Stuexen				struct sockaddr_in6 *sin6;
6233283699Stuexen
6234283699Stuexen				sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
6235283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6236283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
6237283699Stuexen					addr = (struct sockaddr *)&sin_store;
6238283699Stuexen				} else {
6239283699Stuexen					addr = (struct sockaddr *)&thlds->spt_address;
6240283699Stuexen				}
6241224641Stuexen			} else {
6242283699Stuexen				addr = (struct sockaddr *)&thlds->spt_address;
6243283699Stuexen			}
6244283699Stuexen#else
6245283699Stuexen			addr = (struct sockaddr *)&thlds->spt_address;
6246283699Stuexen#endif
6247283699Stuexen			if (stcb != NULL) {
6248283699Stuexen				net = sctp_findnet(stcb, addr);
6249283699Stuexen			} else {
6250224641Stuexen				/*
6251224641Stuexen				 * We increment here since
6252224641Stuexen				 * sctp_findassociation_ep_addr() wil do a
6253224641Stuexen				 * decrement if it finds the stcb as long as
6254224641Stuexen				 * the locked tcb (last argument) is NOT a
6255224641Stuexen				 * TCB.. aka NULL.
6256224641Stuexen				 */
6257283699Stuexen				net = NULL;
6258224641Stuexen				SCTP_INP_INCR_REF(inp);
6259283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr,
6260224641Stuexen				    &net, NULL, NULL);
6261224641Stuexen				if (stcb == NULL) {
6262224641Stuexen					SCTP_INP_DECR_REF(inp);
6263224641Stuexen				}
6264224641Stuexen			}
6265283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
6266224641Stuexen#ifdef INET
6267283699Stuexen				if (addr->sa_family == AF_INET) {
6268224641Stuexen
6269224641Stuexen					struct sockaddr_in *sin;
6270224641Stuexen
6271283699Stuexen					sin = (struct sockaddr_in *)addr;
6272283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
6273224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6274224641Stuexen						SCTP_TCB_UNLOCK(stcb);
6275224641Stuexen						error = EINVAL;
6276224641Stuexen						break;
6277224641Stuexen					}
6278224641Stuexen				} else
6279224641Stuexen#endif
6280224641Stuexen#ifdef INET6
6281283699Stuexen				if (addr->sa_family == AF_INET6) {
6282224641Stuexen					struct sockaddr_in6 *sin6;
6283224641Stuexen
6284283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
6285224641Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
6286224641Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6287224641Stuexen						SCTP_TCB_UNLOCK(stcb);
6288224641Stuexen						error = EINVAL;
6289224641Stuexen						break;
6290224641Stuexen					}
6291224641Stuexen				} else
6292224641Stuexen#endif
6293224641Stuexen				{
6294224641Stuexen					error = EAFNOSUPPORT;
6295224641Stuexen					SCTP_TCB_UNLOCK(stcb);
6296224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6297224641Stuexen					break;
6298224641Stuexen				}
6299224641Stuexen			}
6300283699Stuexen			if (stcb != NULL) {
6301283699Stuexen				if (net != NULL) {
6302283727Stuexen					net->failure_threshold = thlds->spt_pathmaxrxt;
6303283727Stuexen					net->pf_threshold = thlds->spt_pathpfthld;
6304224641Stuexen					if (net->dest_state & SCTP_ADDR_PF) {
6305283727Stuexen						if ((net->error_count > net->failure_threshold) ||
6306283727Stuexen						    (net->error_count <= net->pf_threshold)) {
6307224641Stuexen							net->dest_state &= ~SCTP_ADDR_PF;
6308224641Stuexen						}
6309224641Stuexen					} else {
6310283727Stuexen						if ((net->error_count > net->pf_threshold) &&
6311283727Stuexen						    (net->error_count <= net->failure_threshold)) {
6312224641Stuexen							net->dest_state |= SCTP_ADDR_PF;
6313224641Stuexen							sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
6314283822Stuexen							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
6315283822Stuexen							    stcb->sctp_ep, stcb, net,
6316283822Stuexen							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_17);
6317224641Stuexen							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
6318224641Stuexen						}
6319224641Stuexen					}
6320224641Stuexen					if (net->dest_state & SCTP_ADDR_REACHABLE) {
6321283727Stuexen						if (net->error_count > net->failure_threshold) {
6322224641Stuexen							net->dest_state &= ~SCTP_ADDR_REACHABLE;
6323235414Stuexen							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
6324224641Stuexen						}
6325224641Stuexen					} else {
6326283727Stuexen						if (net->error_count <= net->failure_threshold) {
6327224641Stuexen							net->dest_state |= SCTP_ADDR_REACHABLE;
6328235414Stuexen							sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
6329224641Stuexen						}
6330224641Stuexen					}
6331224641Stuexen				} else {
6332224641Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6333283727Stuexen						net->failure_threshold = thlds->spt_pathmaxrxt;
6334283727Stuexen						net->pf_threshold = thlds->spt_pathpfthld;
6335224641Stuexen						if (net->dest_state & SCTP_ADDR_PF) {
6336283727Stuexen							if ((net->error_count > net->failure_threshold) ||
6337283727Stuexen							    (net->error_count <= net->pf_threshold)) {
6338224641Stuexen								net->dest_state &= ~SCTP_ADDR_PF;
6339224641Stuexen							}
6340224641Stuexen						} else {
6341283727Stuexen							if ((net->error_count > net->pf_threshold) &&
6342283727Stuexen							    (net->error_count <= net->failure_threshold)) {
6343224641Stuexen								net->dest_state |= SCTP_ADDR_PF;
6344224641Stuexen								sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
6345283822Stuexen								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
6346283822Stuexen								    stcb->sctp_ep, stcb, net,
6347283822Stuexen								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_18);
6348224641Stuexen								sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
6349224641Stuexen							}
6350224641Stuexen						}
6351224641Stuexen						if (net->dest_state & SCTP_ADDR_REACHABLE) {
6352283727Stuexen							if (net->error_count > net->failure_threshold) {
6353224641Stuexen								net->dest_state &= ~SCTP_ADDR_REACHABLE;
6354235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
6355224641Stuexen							}
6356224641Stuexen						} else {
6357283727Stuexen							if (net->error_count <= net->failure_threshold) {
6358224641Stuexen								net->dest_state |= SCTP_ADDR_REACHABLE;
6359235414Stuexen								sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
6360224641Stuexen							}
6361224641Stuexen						}
6362224641Stuexen					}
6363224641Stuexen					stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
6364224641Stuexen					stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
6365224641Stuexen				}
6366283725Stuexen				SCTP_TCB_UNLOCK(stcb);
6367224641Stuexen			} else {
6368224918Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6369224918Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6370224918Stuexen				    (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) {
6371224641Stuexen					SCTP_INP_WLOCK(inp);
6372224641Stuexen					inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
6373224641Stuexen					inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
6374224641Stuexen					SCTP_INP_WUNLOCK(inp);
6375224641Stuexen				} else {
6376224641Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6377224641Stuexen					error = EINVAL;
6378224641Stuexen				}
6379224641Stuexen			}
6380224641Stuexen			break;
6381224641Stuexen		}
6382227755Stuexen	case SCTP_REMOTE_UDP_ENCAPS_PORT:
6383227755Stuexen		{
6384227755Stuexen			struct sctp_udpencaps *encaps;
6385227755Stuexen			struct sctp_nets *net;
6386283699Stuexen			struct sockaddr *addr;
6387227755Stuexen
6388283699Stuexen#if defined(INET) && defined(INET6)
6389283699Stuexen			struct sockaddr_in sin_store;
6390283699Stuexen
6391283699Stuexen#endif
6392283699Stuexen
6393227755Stuexen			SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize);
6394227755Stuexen			SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
6395283699Stuexen
6396283699Stuexen#if defined(INET) && defined(INET6)
6397283699Stuexen			if (encaps->sue_address.ss_family == AF_INET6) {
6398283699Stuexen				struct sockaddr_in6 *sin6;
6399283699Stuexen
6400283699Stuexen				sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
6401283699Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
6402283699Stuexen					in6_sin6_2_sin(&sin_store, sin6);
6403283699Stuexen					addr = (struct sockaddr *)&sin_store;
6404283699Stuexen				} else {
6405283699Stuexen					addr = (struct sockaddr *)&encaps->sue_address;
6406283699Stuexen				}
6407227755Stuexen			} else {
6408283699Stuexen				addr = (struct sockaddr *)&encaps->sue_address;
6409283699Stuexen			}
6410283699Stuexen#else
6411283699Stuexen			addr = (struct sockaddr *)&encaps->sue_address;
6412283699Stuexen#endif
6413283699Stuexen			if (stcb != NULL) {
6414283699Stuexen				net = sctp_findnet(stcb, addr);
6415283699Stuexen			} else {
6416227755Stuexen				/*
6417227755Stuexen				 * We increment here since
6418227755Stuexen				 * sctp_findassociation_ep_addr() wil do a
6419227755Stuexen				 * decrement if it finds the stcb as long as
6420227755Stuexen				 * the locked tcb (last argument) is NOT a
6421227755Stuexen				 * TCB.. aka NULL.
6422227755Stuexen				 */
6423227755Stuexen				net = NULL;
6424227755Stuexen				SCTP_INP_INCR_REF(inp);
6425283699Stuexen				stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
6426227755Stuexen				if (stcb == NULL) {
6427227755Stuexen					SCTP_INP_DECR_REF(inp);
6428227755Stuexen				}
6429227755Stuexen			}
6430283699Stuexen			if ((stcb != NULL) && (net == NULL)) {
6431227755Stuexen#ifdef INET
6432283699Stuexen				if (addr->sa_family == AF_INET) {
6433227755Stuexen
6434227755Stuexen					struct sockaddr_in *sin;
6435227755Stuexen
6436283699Stuexen					sin = (struct sockaddr_in *)addr;
6437283699Stuexen					if (sin->sin_addr.s_addr != INADDR_ANY) {
6438227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6439227755Stuexen						SCTP_TCB_UNLOCK(stcb);
6440227755Stuexen						error = EINVAL;
6441227755Stuexen						break;
6442227755Stuexen					}
6443227755Stuexen				} else
6444227755Stuexen#endif
6445227755Stuexen#ifdef INET6
6446283699Stuexen				if (addr->sa_family == AF_INET6) {
6447227755Stuexen					struct sockaddr_in6 *sin6;
6448227755Stuexen
6449283699Stuexen					sin6 = (struct sockaddr_in6 *)addr;
6450227755Stuexen					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
6451227755Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6452227755Stuexen						SCTP_TCB_UNLOCK(stcb);
6453227755Stuexen						error = EINVAL;
6454227755Stuexen						break;
6455227755Stuexen					}
6456227755Stuexen				} else
6457227755Stuexen#endif
6458227755Stuexen				{
6459227755Stuexen					error = EAFNOSUPPORT;
6460227755Stuexen					SCTP_TCB_UNLOCK(stcb);
6461227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6462227755Stuexen					break;
6463227755Stuexen				}
6464227755Stuexen			}
6465283699Stuexen			if (stcb != NULL) {
6466283699Stuexen				if (net != NULL) {
6467227755Stuexen					net->port = encaps->sue_port;
6468227755Stuexen				} else {
6469227755Stuexen					stcb->asoc.port = encaps->sue_port;
6470227755Stuexen				}
6471227755Stuexen				SCTP_TCB_UNLOCK(stcb);
6472227755Stuexen			} else {
6473227755Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6474227755Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6475227755Stuexen				    (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) {
6476227755Stuexen					SCTP_INP_WLOCK(inp);
6477227755Stuexen					inp->sctp_ep.port = encaps->sue_port;
6478227755Stuexen					SCTP_INP_WUNLOCK(inp);
6479227755Stuexen				} else {
6480227755Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6481227755Stuexen					error = EINVAL;
6482227755Stuexen				}
6483227755Stuexen			}
6484227755Stuexen			break;
6485227755Stuexen		}
6486270356Stuexen	case SCTP_ECN_SUPPORTED:
6487270356Stuexen		{
6488270356Stuexen			struct sctp_assoc_value *av;
6489270356Stuexen
6490270356Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6491270356Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6492270356Stuexen
6493270356Stuexen			if (stcb) {
6494270356Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6495270356Stuexen				error = EINVAL;
6496270356Stuexen				SCTP_TCB_UNLOCK(stcb);
6497270356Stuexen			} else {
6498270356Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6499270356Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6500270356Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6501270356Stuexen					SCTP_INP_WLOCK(inp);
6502270356Stuexen					if (av->assoc_value == 0) {
6503270356Stuexen						inp->ecn_supported = 0;
6504270356Stuexen					} else {
6505270356Stuexen						inp->ecn_supported = 1;
6506270356Stuexen					}
6507270356Stuexen					SCTP_INP_WUNLOCK(inp);
6508270356Stuexen				} else {
6509270356Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6510270356Stuexen					error = EINVAL;
6511270356Stuexen				}
6512270356Stuexen			}
6513270356Stuexen			break;
6514270356Stuexen		}
6515270357Stuexen	case SCTP_PR_SUPPORTED:
6516270357Stuexen		{
6517270357Stuexen			struct sctp_assoc_value *av;
6518270357Stuexen
6519270357Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6520270357Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6521270357Stuexen
6522270357Stuexen			if (stcb) {
6523270357Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6524270357Stuexen				error = EINVAL;
6525270357Stuexen				SCTP_TCB_UNLOCK(stcb);
6526270357Stuexen			} else {
6527270357Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6528270357Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6529270357Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6530270357Stuexen					SCTP_INP_WLOCK(inp);
6531270357Stuexen					if (av->assoc_value == 0) {
6532270357Stuexen						inp->prsctp_supported = 0;
6533270357Stuexen					} else {
6534270357Stuexen						inp->prsctp_supported = 1;
6535270357Stuexen					}
6536270357Stuexen					SCTP_INP_WUNLOCK(inp);
6537270357Stuexen				} else {
6538270357Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6539270357Stuexen					error = EINVAL;
6540270357Stuexen				}
6541270357Stuexen			}
6542270357Stuexen			break;
6543270357Stuexen		}
6544270362Stuexen	case SCTP_AUTH_SUPPORTED:
6545270362Stuexen		{
6546270362Stuexen			struct sctp_assoc_value *av;
6547270362Stuexen
6548270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6549270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6550270362Stuexen
6551270362Stuexen			if (stcb) {
6552270362Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6553270362Stuexen				error = EINVAL;
6554270362Stuexen				SCTP_TCB_UNLOCK(stcb);
6555270362Stuexen			} else {
6556270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6557270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6558270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6559270362Stuexen					if ((av->assoc_value == 0) &&
6560270362Stuexen					    (inp->asconf_supported == 1)) {
6561270362Stuexen						/*
6562270362Stuexen						 * AUTH is required for
6563270362Stuexen						 * ASCONF
6564270362Stuexen						 */
6565270362Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6566270362Stuexen						error = EINVAL;
6567270362Stuexen					} else {
6568270362Stuexen						SCTP_INP_WLOCK(inp);
6569270362Stuexen						if (av->assoc_value == 0) {
6570270362Stuexen							inp->auth_supported = 0;
6571270362Stuexen						} else {
6572270362Stuexen							inp->auth_supported = 1;
6573270362Stuexen						}
6574270362Stuexen						SCTP_INP_WUNLOCK(inp);
6575270362Stuexen					}
6576270362Stuexen				} else {
6577270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6578270362Stuexen					error = EINVAL;
6579270362Stuexen				}
6580270362Stuexen			}
6581270362Stuexen			break;
6582270362Stuexen		}
6583270362Stuexen	case SCTP_ASCONF_SUPPORTED:
6584270362Stuexen		{
6585270362Stuexen			struct sctp_assoc_value *av;
6586270362Stuexen
6587270362Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6588270362Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6589270362Stuexen
6590270362Stuexen			if (stcb) {
6591270362Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6592270362Stuexen				error = EINVAL;
6593270362Stuexen				SCTP_TCB_UNLOCK(stcb);
6594270362Stuexen			} else {
6595270362Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6596270362Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6597270362Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6598270362Stuexen					if ((av->assoc_value != 0) &&
6599270362Stuexen					    (inp->auth_supported == 0)) {
6600270362Stuexen						/*
6601270362Stuexen						 * AUTH is required for
6602270362Stuexen						 * ASCONF
6603270362Stuexen						 */
6604270362Stuexen						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6605270362Stuexen						error = EINVAL;
6606270362Stuexen					} else {
6607270362Stuexen						SCTP_INP_WLOCK(inp);
6608270362Stuexen						if (av->assoc_value == 0) {
6609270362Stuexen							inp->asconf_supported = 0;
6610270362Stuexen							sctp_auth_delete_chunk(SCTP_ASCONF,
6611270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6612270362Stuexen							sctp_auth_delete_chunk(SCTP_ASCONF_ACK,
6613270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6614270362Stuexen						} else {
6615270362Stuexen							inp->asconf_supported = 1;
6616270362Stuexen							sctp_auth_add_chunk(SCTP_ASCONF,
6617270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6618270362Stuexen							sctp_auth_add_chunk(SCTP_ASCONF_ACK,
6619270362Stuexen							    inp->sctp_ep.local_auth_chunks);
6620270362Stuexen						}
6621270362Stuexen						SCTP_INP_WUNLOCK(inp);
6622270362Stuexen					}
6623270362Stuexen				} else {
6624270362Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6625270362Stuexen					error = EINVAL;
6626270362Stuexen				}
6627270362Stuexen			}
6628270362Stuexen			break;
6629270362Stuexen		}
6630270361Stuexen	case SCTP_RECONFIG_SUPPORTED:
6631270361Stuexen		{
6632270361Stuexen			struct sctp_assoc_value *av;
6633270361Stuexen
6634270361Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6635270361Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6636270361Stuexen
6637270361Stuexen			if (stcb) {
6638270361Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6639270361Stuexen				error = EINVAL;
6640270361Stuexen				SCTP_TCB_UNLOCK(stcb);
6641270361Stuexen			} else {
6642270361Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6643270361Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6644270361Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6645270361Stuexen					SCTP_INP_WLOCK(inp);
6646270361Stuexen					if (av->assoc_value == 0) {
6647270361Stuexen						inp->reconfig_supported = 0;
6648270361Stuexen					} else {
6649270361Stuexen						inp->reconfig_supported = 1;
6650270361Stuexen					}
6651270361Stuexen					SCTP_INP_WUNLOCK(inp);
6652270361Stuexen				} else {
6653270361Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6654270361Stuexen					error = EINVAL;
6655270361Stuexen				}
6656270361Stuexen			}
6657270361Stuexen			break;
6658270361Stuexen		}
6659270359Stuexen	case SCTP_NRSACK_SUPPORTED:
6660270359Stuexen		{
6661270359Stuexen			struct sctp_assoc_value *av;
6662270359Stuexen
6663270359Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6664270359Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6665270359Stuexen
6666270359Stuexen			if (stcb) {
6667270359Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6668270359Stuexen				error = EINVAL;
6669270359Stuexen				SCTP_TCB_UNLOCK(stcb);
6670270359Stuexen			} else {
6671270359Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6672270359Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6673270359Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6674270359Stuexen					SCTP_INP_WLOCK(inp);
6675270359Stuexen					if (av->assoc_value == 0) {
6676270359Stuexen						inp->nrsack_supported = 0;
6677270359Stuexen					} else {
6678270359Stuexen						inp->nrsack_supported = 1;
6679270359Stuexen					}
6680270359Stuexen					SCTP_INP_WUNLOCK(inp);
6681270359Stuexen				} else {
6682270359Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6683270359Stuexen					error = EINVAL;
6684270359Stuexen				}
6685270359Stuexen			}
6686270359Stuexen			break;
6687270359Stuexen		}
6688270360Stuexen	case SCTP_PKTDROP_SUPPORTED:
6689270360Stuexen		{
6690270360Stuexen			struct sctp_assoc_value *av;
6691270360Stuexen
6692270360Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6693270360Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6694270360Stuexen
6695270360Stuexen			if (stcb) {
6696270360Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6697270360Stuexen				error = EINVAL;
6698270360Stuexen				SCTP_TCB_UNLOCK(stcb);
6699270360Stuexen			} else {
6700270360Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6701270360Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6702270360Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6703270360Stuexen					SCTP_INP_WLOCK(inp);
6704270360Stuexen					if (av->assoc_value == 0) {
6705270360Stuexen						inp->pktdrop_supported = 0;
6706270360Stuexen					} else {
6707270360Stuexen						inp->pktdrop_supported = 1;
6708270360Stuexen					}
6709270360Stuexen					SCTP_INP_WUNLOCK(inp);
6710270360Stuexen				} else {
6711270360Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6712270360Stuexen					error = EINVAL;
6713270360Stuexen				}
6714270360Stuexen			}
6715270360Stuexen			break;
6716270360Stuexen		}
6717283724Stuexen	case SCTP_MAX_CWND:
6718283724Stuexen		{
6719283724Stuexen			struct sctp_assoc_value *av;
6720283724Stuexen			struct sctp_nets *net;
6721283724Stuexen
6722283724Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
6723283724Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
6724283724Stuexen
6725283724Stuexen			if (stcb) {
6726283724Stuexen				stcb->asoc.max_cwnd = av->assoc_value;
6727283724Stuexen				if (stcb->asoc.max_cwnd > 0) {
6728283724Stuexen					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
6729283724Stuexen						if ((net->cwnd > stcb->asoc.max_cwnd) &&
6730283724Stuexen						    (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
6731283724Stuexen							net->cwnd = stcb->asoc.max_cwnd;
6732283724Stuexen							if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
6733283724Stuexen								net->cwnd = net->mtu - sizeof(struct sctphdr);
6734283724Stuexen							}
6735283724Stuexen						}
6736283724Stuexen					}
6737283724Stuexen				}
6738283724Stuexen				SCTP_TCB_UNLOCK(stcb);
6739283724Stuexen			} else {
6740283724Stuexen				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
6741283724Stuexen				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
6742283724Stuexen				    (av->assoc_id == SCTP_FUTURE_ASSOC)) {
6743283724Stuexen					SCTP_INP_WLOCK(inp);
6744283724Stuexen					inp->max_cwnd = av->assoc_value;
6745283724Stuexen					SCTP_INP_WUNLOCK(inp);
6746283724Stuexen				} else {
6747283724Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6748283724Stuexen					error = EINVAL;
6749283724Stuexen				}
6750283724Stuexen			}
6751283724Stuexen			break;
6752283724Stuexen		}
6753163953Srrs	default:
6754171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
6755163953Srrs		error = ENOPROTOOPT;
6756163953Srrs		break;
6757163953Srrs	}			/* end switch (opt) */
6758163953Srrs	return (error);
6759163953Srrs}
6760163953Srrs
6761163953Srrsint
6762163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt)
6763163953Srrs{
6764166675Srrs	void *optval = NULL;
6765166675Srrs	size_t optsize = 0;
6766166675Srrs	void *p;
6767166675Srrs	int error = 0;
6768284633Stuexen	struct sctp_inpcb *inp;
6769163953Srrs
6770284633Stuexen	if ((sopt->sopt_level == SOL_SOCKET) &&
6771284633Stuexen	    (sopt->sopt_name == SO_SETFIB)) {
6772284633Stuexen		inp = (struct sctp_inpcb *)so->so_pcb;
6773284633Stuexen		if (inp == NULL) {
6774284633Stuexen			SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
6775284633Stuexen			return (EINVAL);
6776284633Stuexen		}
6777284633Stuexen		SCTP_INP_WLOCK(inp);
6778284633Stuexen		inp->fibnum = so->so_fibnum;
6779284633Stuexen		SCTP_INP_WUNLOCK(inp);
6780284633Stuexen		return (0);
6781284633Stuexen	}
6782163953Srrs	if (sopt->sopt_level != IPPROTO_SCTP) {
6783163953Srrs		/* wrong proto level... send back up to IP */
6784163953Srrs#ifdef INET6
6785163953Srrs		if (INP_CHECK_SOCKAF(so, AF_INET6))
6786163953Srrs			error = ip6_ctloutput(so, sopt);
6787221249Stuexen#endif				/* INET6 */
6788237565Stuexen#if defined(INET) && defined(INET6)
6789163953Srrs		else
6790221249Stuexen#endif
6791221249Stuexen#ifdef INET
6792163953Srrs			error = ip_ctloutput(so, sopt);
6793221249Stuexen#endif
6794163953Srrs		return (error);
6795163953Srrs	}
6796166675Srrs	optsize = sopt->sopt_valsize;
6797166675Srrs	if (optsize) {
6798170091Srrs		SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
6799166675Srrs		if (optval == NULL) {
6800235091Stuexen			SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
6801163953Srrs			return (ENOBUFS);
6802163953Srrs		}
6803166675Srrs		error = sooptcopyin(sopt, optval, optsize, optsize);
6804163953Srrs		if (error) {
6805170091Srrs			SCTP_FREE(optval, SCTP_M_SOCKOPT);
6806163953Srrs			goto out;
6807163953Srrs		}
6808163953Srrs	}
6809166675Srrs	p = (void *)sopt->sopt_td;
6810163953Srrs	if (sopt->sopt_dir == SOPT_SET) {
6811166675Srrs		error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
6812163953Srrs	} else if (sopt->sopt_dir == SOPT_GET) {
6813166675Srrs		error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
6814163953Srrs	} else {
6815235091Stuexen		SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6816163953Srrs		error = EINVAL;
6817163953Srrs	}
6818166675Srrs	if ((error == 0) && (optval != NULL)) {
6819166675Srrs		error = sooptcopyout(sopt, optval, optsize);
6820170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
6821166675Srrs	} else if (optval != NULL) {
6822170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
6823163953Srrs	}
6824163953Srrsout:
6825163953Srrs	return (error);
6826163953Srrs}
6827163953Srrs
6828221249Stuexen#ifdef INET
6829163953Srrsstatic int
6830163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
6831163953Srrs{
6832163953Srrs	int error = 0;
6833163953Srrs	int create_lock_on = 0;
6834167598Srrs	uint32_t vrf_id;
6835163953Srrs	struct sctp_inpcb *inp;
6836163953Srrs	struct sctp_tcb *stcb = NULL;
6837163953Srrs
6838163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6839233005Stuexen	if (inp == NULL) {
6840163953Srrs		/* I made the same as TCP since we are not setup? */
6841171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6842163953Srrs		return (ECONNRESET);
6843163953Srrs	}
6844171943Srrs	if (addr == NULL) {
6845171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6846170056Srrs		return EINVAL;
6847171943Srrs	}
6848221249Stuexen	switch (addr->sa_family) {
6849185435Sbz#ifdef INET6
6850221249Stuexen	case AF_INET6:
6851221249Stuexen		{
6852221249Stuexen			struct sockaddr_in6 *sin6p;
6853185694Srrs
6854221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
6855221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6856221249Stuexen				return (EINVAL);
6857221249Stuexen			}
6858221249Stuexen			sin6p = (struct sockaddr_in6 *)addr;
6859221249Stuexen			if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
6860221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6861221249Stuexen				return (error);
6862221249Stuexen			}
6863221249Stuexen			break;
6864185435Sbz		}
6865185435Sbz#endif
6866221249Stuexen#ifdef INET
6867221249Stuexen	case AF_INET:
6868221249Stuexen		{
6869221249Stuexen			struct sockaddr_in *sinp;
6870185694Srrs
6871221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
6872221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6873221249Stuexen				return (EINVAL);
6874221249Stuexen			}
6875221249Stuexen			sinp = (struct sockaddr_in *)addr;
6876221249Stuexen			if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) {
6877221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
6878221249Stuexen				return (error);
6879221249Stuexen			}
6880221249Stuexen			break;
6881185435Sbz		}
6882221249Stuexen#endif
6883221249Stuexen	default:
6884185435Sbz		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
6885185435Sbz		return (EAFNOSUPPORT);
6886170056Srrs	}
6887178202Srrs	SCTP_INP_INCR_REF(inp);
6888163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
6889163953Srrs	create_lock_on = 1;
6890163953Srrs
6891178202Srrs
6892163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
6893163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
6894163953Srrs		/* Should I really unlock ? */
6895171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
6896163953Srrs		error = EFAULT;
6897163953Srrs		goto out_now;
6898163953Srrs	}
6899163953Srrs#ifdef INET6
6900163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
6901163953Srrs	    (addr->sa_family == AF_INET6)) {
6902171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6903163953Srrs		error = EINVAL;
6904163953Srrs		goto out_now;
6905163953Srrs	}
6906246595Stuexen#endif
6907163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
6908163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
6909163953Srrs		/* Bind a ephemeral port */
6910171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
6911163953Srrs		if (error) {
6912163953Srrs			goto out_now;
6913163953Srrs		}
6914163953Srrs	}
6915163953Srrs	/* Now do we connect? */
6916181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
6917181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
6918171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
6919163953Srrs		error = EINVAL;
6920163953Srrs		goto out_now;
6921163953Srrs	}
6922163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
6923163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
6924163953Srrs		/* We are already connected AND the TCP model */
6925171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
6926163953Srrs		error = EADDRINUSE;
6927163953Srrs		goto out_now;
6928163953Srrs	}
6929163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
6930163953Srrs		SCTP_INP_RLOCK(inp);
6931163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
6932163953Srrs		SCTP_INP_RUNLOCK(inp);
6933163953Srrs	} else {
6934163953Srrs		/*
6935166675Srrs		 * We increment here since sctp_findassociation_ep_addr()
6936181054Srrs		 * will do a decrement if it finds the stcb as long as the
6937166675Srrs		 * locked tcb (last argument) is NOT a TCB.. aka NULL.
6938163953Srrs		 */
6939163953Srrs		SCTP_INP_INCR_REF(inp);
6940163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
6941163953Srrs		if (stcb == NULL) {
6942163953Srrs			SCTP_INP_DECR_REF(inp);
6943168299Srrs		} else {
6944178202Srrs			SCTP_TCB_UNLOCK(stcb);
6945163953Srrs		}
6946163953Srrs	}
6947163953Srrs	if (stcb != NULL) {
6948163953Srrs		/* Already have or am bring up an association */
6949171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
6950163953Srrs		error = EALREADY;
6951163953Srrs		goto out_now;
6952163953Srrs	}
6953168299Srrs	vrf_id = inp->def_vrf_id;
6954163953Srrs	/* We are GOOD to go */
6955206137Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
6956163953Srrs	if (stcb == NULL) {
6957163953Srrs		/* Gak! no memory */
6958167598Srrs		goto out_now;
6959163953Srrs	}
6960163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
6961163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
6962163953Srrs		/* Set the connected flag so we can queue data */
6963163953Srrs		soisconnecting(so);
6964163953Srrs	}
6965171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
6966169378Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
6967163953Srrs
6968163953Srrs	/* initialize authentication parameters for the assoc */
6969163953Srrs	sctp_initialize_auth_params(inp, stcb);
6970163953Srrs
6971172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
6972168299Srrs	SCTP_TCB_UNLOCK(stcb);
6973163953Srrsout_now:
6974169420Srrs	if (create_lock_on) {
6975163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
6976169420Srrs	}
6977163953Srrs	SCTP_INP_DECR_REF(inp);
6978228907Stuexen	return (error);
6979163953Srrs}
6980163953Srrs
6981221249Stuexen#endif
6982221249Stuexen
6983163953Srrsint
6984163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p)
6985163953Srrs{
6986163953Srrs	/*
6987163953Srrs	 * Note this module depends on the protocol processing being called
6988163953Srrs	 * AFTER any socket level flags and backlog are applied to the
6989163953Srrs	 * socket. The traditional way that the socket flags are applied is
6990163953Srrs	 * AFTER protocol processing. We have made a change to the
6991163953Srrs	 * sys/kern/uipc_socket.c module to reverse this but this MUST be in
6992163953Srrs	 * place if the socket API for SCTP is to work properly.
6993163953Srrs	 */
6994163953Srrs
6995163953Srrs	int error = 0;
6996163953Srrs	struct sctp_inpcb *inp;
6997163953Srrs
6998163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
6999233005Stuexen	if (inp == NULL) {
7000163953Srrs		/* I made the same as TCP since we are not setup? */
7001171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7002163953Srrs		return (ECONNRESET);
7003163953Srrs	}
7004181054Srrs	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
7005181054Srrs		/* See if we have a listener */
7006181054Srrs		struct sctp_inpcb *tinp;
7007267771Stuexen		union sctp_sockstore store;
7008181054Srrs
7009181054Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
7010181054Srrs			/* not bound all */
7011181054Srrs			struct sctp_laddr *laddr;
7012181054Srrs
7013181054Srrs			LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
7014181054Srrs				memcpy(&store, &laddr->ifa->address, sizeof(store));
7015267771Stuexen				switch (store.sa.sa_family) {
7016221249Stuexen#ifdef INET
7017221249Stuexen				case AF_INET:
7018267771Stuexen					store.sin.sin_port = inp->sctp_lport;
7019221249Stuexen					break;
7020221249Stuexen#endif
7021221249Stuexen#ifdef INET6
7022221249Stuexen				case AF_INET6:
7023267771Stuexen					store.sin6.sin6_port = inp->sctp_lport;
7024221249Stuexen					break;
7025221249Stuexen#endif
7026221249Stuexen				default:
7027221249Stuexen					break;
7028221249Stuexen				}
7029267771Stuexen				tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
7030181054Srrs				if (tinp && (tinp != inp) &&
7031181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
7032181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
7033181054Srrs				    (tinp->sctp_socket->so_qlimit)) {
7034181054Srrs					/*
7035181054Srrs					 * we have a listener already and
7036181054Srrs					 * its not this inp.
7037181054Srrs					 */
7038181054Srrs					SCTP_INP_DECR_REF(tinp);
7039181054Srrs					return (EADDRINUSE);
7040181054Srrs				} else if (tinp) {
7041181054Srrs					SCTP_INP_DECR_REF(tinp);
7042181054Srrs				}
7043181054Srrs			}
7044181054Srrs		} else {
7045181054Srrs			/* Setup a local addr bound all */
7046181054Srrs			memset(&store, 0, sizeof(store));
7047267771Stuexen#ifdef INET6
7048267771Stuexen			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
7049267771Stuexen				store.sa.sa_family = AF_INET6;
7050267771Stuexen				store.sa.sa_len = sizeof(struct sockaddr_in6);
7051267771Stuexen			}
7052267771Stuexen#endif
7053221249Stuexen#ifdef INET
7054267771Stuexen			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
7055267771Stuexen				store.sa.sa_family = AF_INET;
7056267771Stuexen				store.sa.sa_len = sizeof(struct sockaddr_in);
7057267771Stuexen			}
7058267771Stuexen#endif
7059267771Stuexen			switch (store.sa.sa_family) {
7060267771Stuexen#ifdef INET
7061221249Stuexen			case AF_INET:
7062221249Stuexen				store.sin.sin_port = inp->sctp_lport;
7063221249Stuexen				break;
7064221249Stuexen#endif
7065181054Srrs#ifdef INET6
7066221249Stuexen			case AF_INET6:
7067267771Stuexen				store.sin6.sin6_port = inp->sctp_lport;
7068221249Stuexen				break;
7069221249Stuexen#endif
7070221249Stuexen			default:
7071221249Stuexen				break;
7072221249Stuexen			}
7073267771Stuexen			tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
7074181054Srrs			if (tinp && (tinp != inp) &&
7075181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
7076181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
7077181054Srrs			    (tinp->sctp_socket->so_qlimit)) {
7078181054Srrs				/*
7079181054Srrs				 * we have a listener already and its not
7080181054Srrs				 * this inp.
7081181054Srrs				 */
7082181054Srrs				SCTP_INP_DECR_REF(tinp);
7083181054Srrs				return (EADDRINUSE);
7084181054Srrs			} else if (tinp) {
7085283733Stuexen				SCTP_INP_DECR_REF(tinp);
7086181054Srrs			}
7087181054Srrs		}
7088181054Srrs	}
7089163953Srrs	SCTP_INP_RLOCK(inp);
7090163953Srrs#ifdef SCTP_LOCK_LOGGING
7091179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
7092170744Srrs		sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
7093170744Srrs	}
7094163953Srrs#endif
7095163953Srrs	SOCK_LOCK(so);
7096163953Srrs	error = solisten_proto_check(so);
7097283732Stuexen	SOCK_UNLOCK(so);
7098163953Srrs	if (error) {
7099169208Srrs		SCTP_INP_RUNLOCK(inp);
7100163953Srrs		return (error);
7101163953Srrs	}
7102181054Srrs	if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
7103181054Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
7104181054Srrs		/*
7105181054Srrs		 * The unlucky case - We are in the tcp pool with this guy.
7106181054Srrs		 * - Someone else is in the main inp slot. - We must move
7107181054Srrs		 * this guy (the listener) to the main slot - We must then
7108181054Srrs		 * move the guy that was listener to the TCP Pool.
7109181054Srrs		 */
7110181054Srrs		if (sctp_swap_inpcb_for_listen(inp)) {
7111283732Stuexen			SCTP_INP_RUNLOCK(inp);
7112283732Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
7113283732Stuexen			return (EADDRINUSE);
7114181054Srrs		}
7115181054Srrs	}
7116163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
7117163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
7118163953Srrs		/* We are already connected AND the TCP model */
7119163953Srrs		SCTP_INP_RUNLOCK(inp);
7120171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
7121163953Srrs		return (EADDRINUSE);
7122163953Srrs	}
7123181054Srrs	SCTP_INP_RUNLOCK(inp);
7124163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
7125163953Srrs		/* We must do a bind. */
7126171572Srrs		if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
7127163953Srrs			/* bind error, probably perm */
7128163953Srrs			return (error);
7129163953Srrs		}
7130163953Srrs	}
7131283732Stuexen	SOCK_LOCK(so);
7132163953Srrs	/* It appears for 7.0 and on, we must always call this. */
7133163953Srrs	solisten_proto(so, backlog);
7134163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
7135163953Srrs		/* remove the ACCEPTCONN flag for one-to-many sockets */
7136163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
7137163953Srrs	}
7138163953Srrs	if (backlog == 0) {
7139163953Srrs		/* turning off listen */
7140163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
7141163953Srrs	}
7142163953Srrs	SOCK_UNLOCK(so);
7143163953Srrs	return (error);
7144163953Srrs}
7145163953Srrs
7146163953Srrsstatic int sctp_defered_wakeup_cnt = 0;
7147163953Srrs
7148163953Srrsint
7149163953Srrssctp_accept(struct socket *so, struct sockaddr **addr)
7150163953Srrs{
7151163953Srrs	struct sctp_tcb *stcb;
7152163953Srrs	struct sctp_inpcb *inp;
7153163953Srrs	union sctp_sockstore store;
7154163953Srrs
7155178251Srrs#ifdef INET6
7156163953Srrs	int error;
7157163953Srrs
7158178251Srrs#endif
7159163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
7160163953Srrs
7161233005Stuexen	if (inp == NULL) {
7162171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7163163953Srrs		return (ECONNRESET);
7164163953Srrs	}
7165163953Srrs	SCTP_INP_RLOCK(inp);
7166163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
7167168299Srrs		SCTP_INP_RUNLOCK(inp);
7168171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
7169171943Srrs		return (EOPNOTSUPP);
7170163953Srrs	}
7171163953Srrs	if (so->so_state & SS_ISDISCONNECTED) {
7172163953Srrs		SCTP_INP_RUNLOCK(inp);
7173171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
7174163953Srrs		return (ECONNABORTED);
7175163953Srrs	}
7176163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
7177163953Srrs	if (stcb == NULL) {
7178163953Srrs		SCTP_INP_RUNLOCK(inp);
7179171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7180163953Srrs		return (ECONNRESET);
7181163953Srrs	}
7182163953Srrs	SCTP_TCB_LOCK(stcb);
7183163953Srrs	SCTP_INP_RUNLOCK(inp);
7184163953Srrs	store = stcb->asoc.primary_destination->ro._l_addr;
7185207924Srrs	stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
7186163953Srrs	SCTP_TCB_UNLOCK(stcb);
7187178251Srrs	switch (store.sa.sa_family) {
7188221249Stuexen#ifdef INET
7189178251Srrs	case AF_INET:
7190178251Srrs		{
7191178251Srrs			struct sockaddr_in *sin;
7192163953Srrs
7193178251Srrs			SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
7194208863Srrs			if (sin == NULL)
7195208863Srrs				return (ENOMEM);
7196178251Srrs			sin->sin_family = AF_INET;
7197178251Srrs			sin->sin_len = sizeof(*sin);
7198246595Stuexen			sin->sin_port = store.sin.sin_port;
7199246595Stuexen			sin->sin_addr = store.sin.sin_addr;
7200178251Srrs			*addr = (struct sockaddr *)sin;
7201178251Srrs			break;
7202178251Srrs		}
7203221249Stuexen#endif
7204178251Srrs#ifdef INET6
7205178251Srrs	case AF_INET6:
7206178251Srrs		{
7207178251Srrs			struct sockaddr_in6 *sin6;
7208163953Srrs
7209178251Srrs			SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
7210208863Srrs			if (sin6 == NULL)
7211208863Srrs				return (ENOMEM);
7212178251Srrs			sin6->sin6_family = AF_INET6;
7213178251Srrs			sin6->sin6_len = sizeof(*sin6);
7214246595Stuexen			sin6->sin6_port = store.sin6.sin6_port;
7215246595Stuexen			sin6->sin6_addr = store.sin6.sin6_addr;
7216178251Srrs			if ((error = sa6_recoverscope(sin6)) != 0) {
7217178251Srrs				SCTP_FREE_SONAME(sin6);
7218178251Srrs				return (error);
7219178251Srrs			}
7220178251Srrs			*addr = (struct sockaddr *)sin6;
7221178251Srrs			break;
7222164085Srrs		}
7223178251Srrs#endif
7224178251Srrs	default:
7225178251Srrs		/* TSNH */
7226178251Srrs		break;
7227163953Srrs	}
7228163953Srrs	/* Wake any delayed sleep action */
7229163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
7230166086Srrs		SCTP_INP_WLOCK(inp);
7231163953Srrs		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
7232163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
7233163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
7234166086Srrs			SCTP_INP_WUNLOCK(inp);
7235163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
7236163953Srrs			if (sowriteable(inp->sctp_socket)) {
7237163953Srrs				sowwakeup_locked(inp->sctp_socket);
7238163953Srrs			} else {
7239163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
7240163953Srrs			}
7241166086Srrs			SCTP_INP_WLOCK(inp);
7242163953Srrs		}
7243163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
7244163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
7245166086Srrs			SCTP_INP_WUNLOCK(inp);
7246163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
7247163953Srrs			if (soreadable(inp->sctp_socket)) {
7248163953Srrs				sctp_defered_wakeup_cnt++;
7249163953Srrs				sorwakeup_locked(inp->sctp_socket);
7250163953Srrs			} else {
7251163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
7252163953Srrs			}
7253166086Srrs			SCTP_INP_WLOCK(inp);
7254163953Srrs		}
7255166086Srrs		SCTP_INP_WUNLOCK(inp);
7256163953Srrs	}
7257207924Srrs	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
7258207924Srrs		SCTP_TCB_LOCK(stcb);
7259283822Stuexen		sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
7260283822Stuexen		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19);
7261207924Srrs	}
7262163953Srrs	return (0);
7263163953Srrs}
7264163953Srrs
7265221249Stuexen#ifdef INET
7266163953Srrsint
7267163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr)
7268163953Srrs{
7269163953Srrs	struct sockaddr_in *sin;
7270167598Srrs	uint32_t vrf_id;
7271163953Srrs	struct sctp_inpcb *inp;
7272167695Srrs	struct sctp_ifa *sctp_ifa;
7273163953Srrs
7274163953Srrs	/*
7275163953Srrs	 * Do the malloc first in case it blocks.
7276163953Srrs	 */
7277163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
7278208863Srrs	if (sin == NULL)
7279208863Srrs		return (ENOMEM);
7280163953Srrs	sin->sin_family = AF_INET;
7281163953Srrs	sin->sin_len = sizeof(*sin);
7282163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
7283163953Srrs	if (!inp) {
7284163953Srrs		SCTP_FREE_SONAME(sin);
7285171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7286228907Stuexen		return (ECONNRESET);
7287163953Srrs	}
7288163953Srrs	SCTP_INP_RLOCK(inp);
7289163953Srrs	sin->sin_port = inp->sctp_lport;
7290163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
7291163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
7292163953Srrs			struct sctp_tcb *stcb;
7293163953Srrs			struct sockaddr_in *sin_a;
7294163953Srrs			struct sctp_nets *net;
7295163953Srrs			int fnd;
7296163953Srrs
7297163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
7298163953Srrs			if (stcb == NULL) {
7299163953Srrs				goto notConn;
7300163953Srrs			}
7301163953Srrs			fnd = 0;
7302163953Srrs			sin_a = NULL;
7303163953Srrs			SCTP_TCB_LOCK(stcb);
7304163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
7305163953Srrs				sin_a = (struct sockaddr_in *)&net->ro._l_addr;
7306164085Srrs				if (sin_a == NULL)
7307164085Srrs					/* this will make coverity happy */
7308164085Srrs					continue;
7309164085Srrs
7310163953Srrs				if (sin_a->sin_family == AF_INET) {
7311163953Srrs					fnd = 1;
7312163953Srrs					break;
7313163953Srrs				}
7314163953Srrs			}
7315163953Srrs			if ((!fnd) || (sin_a == NULL)) {
7316163953Srrs				/* punt */
7317163953Srrs				SCTP_TCB_UNLOCK(stcb);
7318163953Srrs				goto notConn;
7319163953Srrs			}
7320168299Srrs			vrf_id = inp->def_vrf_id;
7321167598Srrs			sctp_ifa = sctp_source_address_selection(inp,
7322167598Srrs			    stcb,
7323168299Srrs			    (sctp_route_t *) & net->ro,
7324167598Srrs			    net, 0, vrf_id);
7325167598Srrs			if (sctp_ifa) {
7326167598Srrs				sin->sin_addr = sctp_ifa->address.sin.sin_addr;
7327167598Srrs				sctp_free_ifa(sctp_ifa);
7328167598Srrs			}
7329163953Srrs			SCTP_TCB_UNLOCK(stcb);
7330163953Srrs		} else {
7331163953Srrs			/* For the bound all case you get back 0 */
7332163953Srrs	notConn:
7333163953Srrs			sin->sin_addr.s_addr = 0;
7334163953Srrs		}
7335163953Srrs
7336163953Srrs	} else {
7337163953Srrs		/* Take the first IPv4 address in the list */
7338163953Srrs		struct sctp_laddr *laddr;
7339163953Srrs		int fnd = 0;
7340163953Srrs
7341163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
7342167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET) {
7343163953Srrs				struct sockaddr_in *sin_a;
7344163953Srrs
7345271746Stuexen				sin_a = &laddr->ifa->address.sin;
7346163953Srrs				sin->sin_addr = sin_a->sin_addr;
7347163953Srrs				fnd = 1;
7348163953Srrs				break;
7349163953Srrs			}
7350163953Srrs		}
7351163953Srrs		if (!fnd) {
7352163953Srrs			SCTP_FREE_SONAME(sin);
7353163953Srrs			SCTP_INP_RUNLOCK(inp);
7354171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
7355228907Stuexen			return (ENOENT);
7356163953Srrs		}
7357163953Srrs	}
7358163953Srrs	SCTP_INP_RUNLOCK(inp);
7359163953Srrs	(*addr) = (struct sockaddr *)sin;
7360163953Srrs	return (0);
7361163953Srrs}
7362163953Srrs
7363163953Srrsint
7364163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr)
7365163953Srrs{
7366231895Stuexen	struct sockaddr_in *sin;
7367166086Srrs	int fnd;
7368163953Srrs	struct sockaddr_in *sin_a;
7369163953Srrs	struct sctp_inpcb *inp;
7370163953Srrs	struct sctp_tcb *stcb;
7371163953Srrs	struct sctp_nets *net;
7372163953Srrs
7373163953Srrs	/* Do the malloc first in case it blocks. */
7374163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
7375208863Srrs	if (sin == NULL)
7376208863Srrs		return (ENOMEM);
7377163953Srrs	sin->sin_family = AF_INET;
7378163953Srrs	sin->sin_len = sizeof(*sin);
7379163953Srrs
7380163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
7381228907Stuexen	if ((inp == NULL) ||
7382228907Stuexen	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
7383228907Stuexen		/* UDP type and listeners will drop out here */
7384163953Srrs		SCTP_FREE_SONAME(sin);
7385228907Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
7386228907Stuexen		return (ENOTCONN);
7387163953Srrs	}
7388163953Srrs	SCTP_INP_RLOCK(inp);
7389163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
7390169420Srrs	if (stcb) {
7391163953Srrs		SCTP_TCB_LOCK(stcb);
7392169420Srrs	}
7393163953Srrs	SCTP_INP_RUNLOCK(inp);
7394163953Srrs	if (stcb == NULL) {
7395163953Srrs		SCTP_FREE_SONAME(sin);
7396171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
7397228907Stuexen		return (ECONNRESET);
7398163953Srrs	}
7399163953Srrs	fnd = 0;
7400163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
7401163953Srrs		sin_a = (struct sockaddr_in *)&net->ro._l_addr;
7402163953Srrs		if (sin_a->sin_family == AF_INET) {
7403163953Srrs			fnd = 1;
7404163953Srrs			sin->sin_port = stcb->rport;
7405163953Srrs			sin->sin_addr = sin_a->sin_addr;
7406163953Srrs			break;
7407163953Srrs		}
7408163953Srrs	}
7409163953Srrs	SCTP_TCB_UNLOCK(stcb);
7410163953Srrs	if (!fnd) {
7411163953Srrs		/* No IPv4 address */
7412163953Srrs		SCTP_FREE_SONAME(sin);
7413171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
7414228907Stuexen		return (ENOENT);
7415163953Srrs	}
7416163953Srrs	(*addr) = (struct sockaddr *)sin;
7417163953Srrs	return (0);
7418163953Srrs}
7419163953Srrs
7420163953Srrsstruct pr_usrreqs sctp_usrreqs = {
7421163953Srrs	.pru_abort = sctp_abort,
7422163953Srrs	.pru_accept = sctp_accept,
7423163953Srrs	.pru_attach = sctp_attach,
7424163953Srrs	.pru_bind = sctp_bind,
7425163953Srrs	.pru_connect = sctp_connect,
7426163953Srrs	.pru_control = in_control,
7427163953Srrs	.pru_close = sctp_close,
7428163953Srrs	.pru_detach = sctp_close,
7429163953Srrs	.pru_sopoll = sopoll_generic,
7430178202Srrs	.pru_flush = sctp_flush,
7431163953Srrs	.pru_disconnect = sctp_disconnect,
7432163953Srrs	.pru_listen = sctp_listen,
7433163953Srrs	.pru_peeraddr = sctp_peeraddr,
7434163953Srrs	.pru_send = sctp_sendm,
7435163953Srrs	.pru_shutdown = sctp_shutdown,
7436163953Srrs	.pru_sockaddr = sctp_ingetaddr,
7437163953Srrs	.pru_sosend = sctp_sosend,
7438163953Srrs	.pru_soreceive = sctp_soreceive
7439163953Srrs};
7440221249Stuexen
7441221249Stuexen#endif
7442