sctp_usrreq.c revision 221249
1163953Srrs/*-
2185694Srrs * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
3218319Srrs * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
4218319Srrs * Copyright (c) 2008-2011, 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,
10163953Srrs *   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
14163953Srrs *   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/* $KAME: sctp_usrreq.c,v 1.48 2005/03/07 23:26:08 itojun Exp $	 */
34163953Srrs
35163953Srrs#include <sys/cdefs.h>
36163953Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 221249 2011-04-30 11:18:16Z tuexen $");
37166086Srrs#include <netinet/sctp_os.h>
38163953Srrs#include <sys/proc.h>
39163953Srrs#include <netinet/sctp_pcb.h>
40163953Srrs#include <netinet/sctp_header.h>
41163953Srrs#include <netinet/sctp_var.h>
42167695Srrs#if defined(INET6)
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);
82163953Srrs
83179783Srrs	SCTP_BASE_VAR(first_time) = 0;
84179783Srrs	SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
85179783Srrs	sctp_pcb_init();
86179783Srrs#if defined(SCTP_PACKET_LOGGING)
87179783Srrs	SCTP_BASE_VAR(packet_log_writers) = 0;
88179783Srrs	SCTP_BASE_VAR(packet_log_end) = 0;
89179783Srrs	bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE);
90179783Srrs#endif
91179783Srrs
92179783Srrs
93163953Srrs}
94163953Srrs
95179783Srrsvoid
96179783Srrssctp_finish(void)
97179783Srrs{
98179783Srrs	sctp_pcb_finish();
99179783Srrs}
100163953Srrs
101166023Srrs
102163953Srrs
103179157Srrsvoid
104167695Srrssctp_pathmtu_adjustment(struct sctp_inpcb *inp,
105163953Srrs    struct sctp_tcb *stcb,
106163953Srrs    struct sctp_nets *net,
107163953Srrs    uint16_t nxtsz)
108163953Srrs{
109163953Srrs	struct sctp_tmit_chunk *chk;
110197257Stuexen	uint16_t overhead;
111163953Srrs
112163953Srrs	/* Adjust that too */
113163953Srrs	stcb->asoc.smallest_mtu = nxtsz;
114163953Srrs	/* now off to subtract IP_DF flag if needed */
115197257Stuexen	overhead = IP_HDR_SIZE;
116197257Stuexen	if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
117197257Stuexen		overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id);
118197257Stuexen	}
119163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
120197257Stuexen		if ((chk->send_size + overhead) > nxtsz) {
121163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
122163953Srrs		}
123163953Srrs	}
124163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
125197257Stuexen		if ((chk->send_size + overhead) > nxtsz) {
126163953Srrs			/*
127163953Srrs			 * For this guy we also mark for immediate resend
128163953Srrs			 * since we sent to big of chunk
129163953Srrs			 */
130163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
131190689Srrs			if (chk->sent < SCTP_DATAGRAM_RESEND) {
132190689Srrs				sctp_flight_size_decrease(chk);
133190689Srrs				sctp_total_flight_decrease(stcb, chk);
134190689Srrs			}
135163953Srrs			if (chk->sent != SCTP_DATAGRAM_RESEND) {
136163953Srrs				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
137163953Srrs			}
138163953Srrs			chk->sent = SCTP_DATAGRAM_RESEND;
139163953Srrs			chk->rec.data.doing_fast_retransmit = 0;
140179783Srrs			if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
141170744Srrs				sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
142170744Srrs				    chk->whoTo->flight_size,
143170744Srrs				    chk->book_size,
144170744Srrs				    (uintptr_t) chk->whoTo,
145170744Srrs				    chk->rec.data.TSN_seq);
146170744Srrs			}
147163953Srrs			/* Clear any time so NO RTT is being done */
148163953Srrs			chk->do_rtt = 0;
149163953Srrs		}
150163953Srrs	}
151163953Srrs}
152163953Srrs
153221249Stuexen#ifdef INET
154163953Srrsstatic void
155163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp,
156163953Srrs    struct sctp_tcb *stcb,
157163953Srrs    struct sctp_nets *net,
158163953Srrs    struct ip *ip,
159163953Srrs    struct sctphdr *sh)
160163953Srrs{
161163953Srrs	struct icmp *icmph;
162163953Srrs	int totsz, tmr_stopped = 0;
163163953Srrs	uint16_t nxtsz;
164163953Srrs
165163953Srrs	/* protection */
166163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
167163953Srrs	    (ip == NULL) || (sh == NULL)) {
168169420Srrs		if (stcb != NULL) {
169163953Srrs			SCTP_TCB_UNLOCK(stcb);
170169420Srrs		}
171163953Srrs		return;
172163953Srrs	}
173163953Srrs	/* First job is to verify the vtag matches what I would send */
174163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
175163953Srrs		SCTP_TCB_UNLOCK(stcb);
176163953Srrs		return;
177163953Srrs	}
178163953Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
179163953Srrs	    sizeof(struct ip)));
180163953Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
181163953Srrs		/* We only care about unreachable */
182163953Srrs		SCTP_TCB_UNLOCK(stcb);
183163953Srrs		return;
184163953Srrs	}
185163953Srrs	if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
186163953Srrs		/* not a unreachable message due to frag. */
187163953Srrs		SCTP_TCB_UNLOCK(stcb);
188163953Srrs		return;
189163953Srrs	}
190163953Srrs	totsz = ip->ip_len;
191163953Srrs
192171943Srrs	nxtsz = ntohs(icmph->icmp_nextmtu);
193163953Srrs	if (nxtsz == 0) {
194163953Srrs		/*
195163953Srrs		 * old type router that does not tell us what the next size
196163953Srrs		 * mtu is. Rats we will have to guess (in a educated fashion
197163953Srrs		 * of course)
198163953Srrs		 */
199214939Stuexen		nxtsz = sctp_get_prev_mtu(totsz);
200163953Srrs	}
201163953Srrs	/* Stop any PMTU timer */
202165647Srrs	if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
203163953Srrs		tmr_stopped = 1;
204165220Srrs		sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
205165220Srrs		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
206163953Srrs	}
207163953Srrs	/* Adjust destination size limit */
208163953Srrs	if (net->mtu > nxtsz) {
209163953Srrs		net->mtu = nxtsz;
210185694Srrs		if (net->port) {
211185694Srrs			net->mtu -= sizeof(struct udphdr);
212185694Srrs		}
213163953Srrs	}
214163953Srrs	/* now what about the ep? */
215163953Srrs	if (stcb->asoc.smallest_mtu > nxtsz) {
216167695Srrs		sctp_pathmtu_adjustment(inp, stcb, net, nxtsz);
217163953Srrs	}
218163953Srrs	if (tmr_stopped)
219163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
220163953Srrs
221163953Srrs	SCTP_TCB_UNLOCK(stcb);
222163953Srrs}
223163953Srrs
224221249Stuexen#endif
225163953Srrs
226163953Srrsvoid
227163953Srrssctp_notify(struct sctp_inpcb *inp,
228172091Srrs    struct ip *ip,
229163953Srrs    struct sctphdr *sh,
230163953Srrs    struct sockaddr *to,
231163953Srrs    struct sctp_tcb *stcb,
232163953Srrs    struct sctp_nets *net)
233163953Srrs{
234172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
235172090Srrs	struct socket *so;
236172090Srrs
237172090Srrs#endif
238163953Srrs	/* protection */
239172091Srrs	int reason;
240172091Srrs	struct icmp *icmph;
241172091Srrs
242172091Srrs
243163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
244163953Srrs	    (sh == NULL) || (to == NULL)) {
245172091Srrs		if (stcb)
246172091Srrs			SCTP_TCB_UNLOCK(stcb);
247163953Srrs		return;
248163953Srrs	}
249163953Srrs	/* First job is to verify the vtag matches what I would send */
250163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
251172091Srrs		SCTP_TCB_UNLOCK(stcb);
252163953Srrs		return;
253163953Srrs	}
254172091Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
255172091Srrs	    sizeof(struct ip)));
256172091Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
257172091Srrs		/* We only care about unreachable */
258172091Srrs		SCTP_TCB_UNLOCK(stcb);
259172091Srrs		return;
260172091Srrs	}
261172091Srrs	if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
262172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST) ||
263172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
264172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
265172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
266172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
267172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
268172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
269163953Srrs
270163953Srrs		/*
271163953Srrs		 * Hmm reachablity problems we must examine closely. If its
272163953Srrs		 * not reachable, we may have lost a network. Or if there is
273163953Srrs		 * NO protocol at the other end named SCTP. well we consider
274163953Srrs		 * it a OOTB abort.
275163953Srrs		 */
276172091Srrs		if (net->dest_state & SCTP_ADDR_REACHABLE) {
277172091Srrs			/* Ok that destination is NOT reachable */
278172091Srrs			SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
279172091Srrs			    net->error_count,
280172091Srrs			    net->failure_threshold,
281172091Srrs			    net);
282167598Srrs
283172091Srrs			net->dest_state &= ~SCTP_ADDR_REACHABLE;
284172091Srrs			net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
285163953Srrs			/*
286172091Srrs			 * JRS 5/14/07 - If a destination is unreachable,
287172091Srrs			 * the PF bit is turned off.  This allows an
288172091Srrs			 * unambiguous use of the PF bit for destinations
289172091Srrs			 * that are reachable but potentially failed. If the
290172091Srrs			 * destination is set to the unreachable state, also
291172091Srrs			 * set the destination to the PF state.
292163953Srrs			 */
293172091Srrs			/*
294172091Srrs			 * Add debug message here if destination is not in
295172091Srrs			 * PF state.
296172091Srrs			 */
297172091Srrs			/* Stop any running T3 timers here? */
298216669Stuexen			if ((stcb->asoc.sctp_cmt_on_off > 0) &&
299211944Stuexen			    (stcb->asoc.sctp_cmt_pf > 0)) {
300172091Srrs				net->dest_state &= ~SCTP_ADDR_PF;
301172091Srrs				SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
302172091Srrs				    net);
303172091Srrs			}
304172091Srrs			net->error_count = net->failure_threshold + 1;
305172091Srrs			sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
306172091Srrs			    stcb, SCTP_FAILED_THRESHOLD,
307172091Srrs			    (void *)net, SCTP_SO_NOT_LOCKED);
308172091Srrs		}
309172091Srrs		SCTP_TCB_UNLOCK(stcb);
310172091Srrs	} else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
311172091Srrs	    (icmph->icmp_code == ICMP_UNREACH_PORT)) {
312172091Srrs		/*
313172091Srrs		 * Here the peer is either playing tricks on us, including
314172091Srrs		 * an address that belongs to someone who does not support
315172091Srrs		 * SCTP OR was a userland implementation that shutdown and
316172091Srrs		 * now is dead. In either case treat it like a OOTB abort
317172091Srrs		 * with no TCB
318172091Srrs		 */
319172091Srrs		reason = SCTP_PEER_FAULTY;
320172091Srrs		sctp_abort_notification(stcb, reason, SCTP_SO_NOT_LOCKED);
321172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
322172091Srrs		so = SCTP_INP_SO(inp);
323172091Srrs		atomic_add_int(&stcb->asoc.refcnt, 1);
324172091Srrs		SCTP_TCB_UNLOCK(stcb);
325172091Srrs		SCTP_SOCKET_LOCK(so, 1);
326172091Srrs		SCTP_TCB_LOCK(stcb);
327172091Srrs		atomic_subtract_int(&stcb->asoc.refcnt, 1);
328172090Srrs#endif
329172091Srrs		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
330172090Srrs#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
331172091Srrs		SCTP_SOCKET_UNLOCK(so, 1);
332172091Srrs		/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
333172090Srrs#endif
334172091Srrs		/* no need to unlock here, since the TCB is gone */
335163953Srrs	} else {
336172091Srrs		SCTP_TCB_UNLOCK(stcb);
337163953Srrs	}
338163953Srrs}
339163953Srrs
340221249Stuexen#ifdef INET
341163953Srrsvoid
342163953Srrssctp_ctlinput(cmd, sa, vip)
343163953Srrs	int cmd;
344163953Srrs	struct sockaddr *sa;
345163953Srrs	void *vip;
346163953Srrs{
347163953Srrs	struct ip *ip = vip;
348163953Srrs	struct sctphdr *sh;
349167598Srrs	uint32_t vrf_id;
350163953Srrs
351168299Srrs	/* FIX, for non-bsd is this right? */
352167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
353163953Srrs	if (sa->sa_family != AF_INET ||
354163953Srrs	    ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
355163953Srrs		return;
356163953Srrs	}
357163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
358163953Srrs		ip = 0;
359163953Srrs	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
360163953Srrs		return;
361163953Srrs	}
362163953Srrs	if (ip) {
363163953Srrs		struct sctp_inpcb *inp = NULL;
364163953Srrs		struct sctp_tcb *stcb = NULL;
365163953Srrs		struct sctp_nets *net = NULL;
366163953Srrs		struct sockaddr_in to, from;
367163953Srrs
368163953Srrs		sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
369163953Srrs		bzero(&to, sizeof(to));
370163953Srrs		bzero(&from, sizeof(from));
371163953Srrs		from.sin_family = to.sin_family = AF_INET;
372163953Srrs		from.sin_len = to.sin_len = sizeof(to);
373163953Srrs		from.sin_port = sh->src_port;
374163953Srrs		from.sin_addr = ip->ip_src;
375163953Srrs		to.sin_port = sh->dest_port;
376163953Srrs		to.sin_addr = ip->ip_dst;
377163953Srrs
378163953Srrs		/*
379163953Srrs		 * 'to' holds the dest of the packet that failed to be sent.
380163953Srrs		 * 'from' holds our local endpoint address. Thus we reverse
381163953Srrs		 * the to and the from in the lookup.
382163953Srrs		 */
383163953Srrs		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from,
384163953Srrs		    (struct sockaddr *)&to,
385167598Srrs		    &inp, &net, 1, vrf_id);
386163953Srrs		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
387163953Srrs			if (cmd != PRC_MSGSIZE) {
388172091Srrs				sctp_notify(inp, ip, sh,
389163953Srrs				    (struct sockaddr *)&to, stcb,
390163953Srrs				    net);
391163953Srrs			} else {
392163953Srrs				/* handle possible ICMP size messages */
393163953Srrs				sctp_notify_mbuf(inp, stcb, net, ip, sh);
394163953Srrs			}
395163953Srrs		} else {
396163953Srrs			if ((stcb == NULL) && (inp != NULL)) {
397163953Srrs				/* reduce ref-count */
398163953Srrs				SCTP_INP_WLOCK(inp);
399163953Srrs				SCTP_INP_DECR_REF(inp);
400163953Srrs				SCTP_INP_WUNLOCK(inp);
401163953Srrs			}
402209029Srrs			if (stcb) {
403209029Srrs				SCTP_TCB_UNLOCK(stcb);
404209029Srrs			}
405163953Srrs		}
406163953Srrs	}
407163953Srrs	return;
408163953Srrs}
409163953Srrs
410221249Stuexen#endif
411221249Stuexen
412163953Srrsstatic int
413163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS)
414163953Srrs{
415164085Srrs	struct xucred xuc;
416163953Srrs	struct sockaddr_in addrs[2];
417163953Srrs	struct sctp_inpcb *inp;
418163953Srrs	struct sctp_nets *net;
419163953Srrs	struct sctp_tcb *stcb;
420164085Srrs	int error;
421167598Srrs	uint32_t vrf_id;
422163953Srrs
423168299Srrs	/* FIX, for non-bsd is this right? */
424167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
425168299Srrs
426170587Srwatson	error = priv_check(req->td, PRIV_NETINET_GETCRED);
427170587Srwatson
428163953Srrs	if (error)
429163953Srrs		return (error);
430164039Srwatson
431163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
432163953Srrs	if (error)
433163953Srrs		return (error);
434163953Srrs
435163953Srrs	stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]),
436163953Srrs	    sintosa(&addrs[1]),
437167598Srrs	    &inp, &net, 1, vrf_id);
438163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
439163953Srrs		if ((inp != NULL) && (stcb == NULL)) {
440163953Srrs			/* reduce ref-count */
441163953Srrs			SCTP_INP_WLOCK(inp);
442163953Srrs			SCTP_INP_DECR_REF(inp);
443164085Srrs			goto cred_can_cont;
444163953Srrs		}
445171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
446163953Srrs		error = ENOENT;
447163953Srrs		goto out;
448163953Srrs	}
449163953Srrs	SCTP_TCB_UNLOCK(stcb);
450164085Srrs	/*
451164085Srrs	 * We use the write lock here, only since in the error leg we need
452164085Srrs	 * it. If we used RLOCK, then we would have to
453164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
454164085Srrs	 * Better to use higher wlock.
455164085Srrs	 */
456164085Srrs	SCTP_INP_WLOCK(inp);
457164085Srrscred_can_cont:
458164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
459164085Srrs	if (error) {
460164085Srrs		SCTP_INP_WUNLOCK(inp);
461164085Srrs		goto out;
462164085Srrs	}
463164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
464164085Srrs	SCTP_INP_WUNLOCK(inp);
465164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
466163953Srrsout:
467163953Srrs	return (error);
468163953Srrs}
469163953Srrs
470163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
471163953Srrs    0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
472163953Srrs
473163953Srrs
474221249Stuexen#ifdef INET
475163953Srrsstatic void
476163953Srrssctp_abort(struct socket *so)
477163953Srrs{
478163953Srrs	struct sctp_inpcb *inp;
479163953Srrs	uint32_t flags;
480163953Srrs
481163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
482171943Srrs	if (inp == 0) {
483163953Srrs		return;
484171943Srrs	}
485163953Srrssctp_must_try_again:
486163953Srrs	flags = inp->sctp_flags;
487163953Srrs#ifdef SCTP_LOG_CLOSING
488163953Srrs	sctp_log_closing(inp, NULL, 17);
489163953Srrs#endif
490163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
491163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
492163953Srrs#ifdef SCTP_LOG_CLOSING
493163953Srrs		sctp_log_closing(inp, NULL, 16);
494163953Srrs#endif
495169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
496169380Srrs		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
497163953Srrs		SOCK_LOCK(so);
498167695Srrs		SCTP_SB_CLEAR(so->so_snd);
499163953Srrs		/*
500163953Srrs		 * same for the rcv ones, they are only here for the
501163953Srrs		 * accounting/select.
502163953Srrs		 */
503167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
504167695Srrs
505167695Srrs		/* Now null out the reference, we are completely detached. */
506163953Srrs		so->so_pcb = NULL;
507163953Srrs		SOCK_UNLOCK(so);
508163953Srrs	} else {
509163953Srrs		flags = inp->sctp_flags;
510163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
511163953Srrs			goto sctp_must_try_again;
512163953Srrs		}
513163953Srrs	}
514163953Srrs	return;
515163953Srrs}
516163953Srrs
517163953Srrsstatic int
518163953Srrssctp_attach(struct socket *so, int proto, struct thread *p)
519163953Srrs{
520163953Srrs	struct sctp_inpcb *inp;
521163953Srrs	struct inpcb *ip_inp;
522166086Srrs	int error;
523170205Srrs	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
524185694Srrs
525171167Sgnn#ifdef IPSEC
526163953Srrs	uint32_t flags;
527185694Srrs
528185435Sbz#endif
529171440Srrs
530163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
531163953Srrs	if (inp != 0) {
532171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
533163953Srrs		return EINVAL;
534163953Srrs	}
535184030Srrs	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
536184030Srrs		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
537184030Srrs		if (error) {
538184030Srrs			return error;
539184030Srrs		}
540163953Srrs	}
541170205Srrs	error = sctp_inpcb_alloc(so, vrf_id);
542163953Srrs	if (error) {
543163953Srrs		return error;
544163953Srrs	}
545163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
546163953Srrs	SCTP_INP_WLOCK(inp);
547163953Srrs	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;	/* I'm not v6! */
548163953Srrs	ip_inp = &inp->ip_inp.inp;
549163953Srrs	ip_inp->inp_vflag |= INP_IPV4;
550197288Srrs	ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
551171167Sgnn#ifdef IPSEC
552171133Sgnn	error = ipsec_init_policy(so, &ip_inp->inp_sp);
553163953Srrs#ifdef SCTP_LOG_CLOSING
554163953Srrs	sctp_log_closing(inp, NULL, 17);
555163953Srrs#endif
556163953Srrs	if (error != 0) {
557202523Srrstry_again:
558163953Srrs		flags = inp->sctp_flags;
559163953Srrs		if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
560163953Srrs		    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
561163953Srrs#ifdef SCTP_LOG_CLOSING
562163953Srrs			sctp_log_closing(inp, NULL, 15);
563163953Srrs#endif
564169352Srrs			SCTP_INP_WUNLOCK(inp);
565169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
566169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
567169254Srrs		} else {
568202523Srrs			flags = inp->sctp_flags;
569202523Srrs			if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
570202523Srrs				goto try_again;
571202523Srrs			} else {
572202523Srrs				SCTP_INP_WUNLOCK(inp);
573202523Srrs			}
574163953Srrs		}
575163953Srrs		return error;
576163953Srrs	}
577171167Sgnn#endif				/* IPSEC */
578163953Srrs	SCTP_INP_WUNLOCK(inp);
579163953Srrs	return 0;
580163953Srrs}
581163953Srrs
582163953Srrsstatic int
583163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
584163953Srrs{
585171943Srrs	struct sctp_inpcb *inp = NULL;
586166086Srrs	int error;
587163953Srrs
588163953Srrs#ifdef INET6
589171943Srrs	if (addr && addr->sa_family != AF_INET) {
590163953Srrs		/* must be a v4 address! */
591171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
592163953Srrs		return EINVAL;
593171943Srrs	}
594163953Srrs#endif				/* INET6 */
595170056Srrs	if (addr && (addr->sa_len != sizeof(struct sockaddr_in))) {
596171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
597170056Srrs		return EINVAL;
598170056Srrs	}
599163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
600171943Srrs	if (inp == 0) {
601171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
602163953Srrs		return EINVAL;
603171943Srrs	}
604171572Srrs	error = sctp_inpcb_bind(so, addr, NULL, p);
605163953Srrs	return error;
606163953Srrs}
607163953Srrs
608221249Stuexen#endif
609171990Srrsvoid
610163953Srrssctp_close(struct socket *so)
611163953Srrs{
612163953Srrs	struct sctp_inpcb *inp;
613163953Srrs	uint32_t flags;
614163953Srrs
615163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
616163953Srrs	if (inp == 0)
617163953Srrs		return;
618163953Srrs
619163953Srrs	/*
620163953Srrs	 * Inform all the lower layer assoc that we are done.
621163953Srrs	 */
622163953Srrssctp_must_try_again:
623163953Srrs	flags = inp->sctp_flags;
624163953Srrs#ifdef SCTP_LOG_CLOSING
625163953Srrs	sctp_log_closing(inp, NULL, 17);
626163953Srrs#endif
627163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
628163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
629163953Srrs		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
630163953Srrs		    (so->so_rcv.sb_cc > 0)) {
631163953Srrs#ifdef SCTP_LOG_CLOSING
632163953Srrs			sctp_log_closing(inp, NULL, 13);
633163953Srrs#endif
634169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
635169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
636163953Srrs		} else {
637163953Srrs#ifdef SCTP_LOG_CLOSING
638163953Srrs			sctp_log_closing(inp, NULL, 14);
639163953Srrs#endif
640169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
641169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
642163953Srrs		}
643163953Srrs		/*
644163953Srrs		 * The socket is now detached, no matter what the state of
645163953Srrs		 * the SCTP association.
646163953Srrs		 */
647163953Srrs		SOCK_LOCK(so);
648167695Srrs		SCTP_SB_CLEAR(so->so_snd);
649163953Srrs		/*
650163953Srrs		 * same for the rcv ones, they are only here for the
651163953Srrs		 * accounting/select.
652163953Srrs		 */
653167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
654167695Srrs
655167695Srrs		/* Now null out the reference, we are completely detached. */
656163953Srrs		so->so_pcb = NULL;
657163953Srrs		SOCK_UNLOCK(so);
658163953Srrs	} else {
659163953Srrs		flags = inp->sctp_flags;
660163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
661163953Srrs			goto sctp_must_try_again;
662163953Srrs		}
663163953Srrs	}
664163953Srrs	return;
665163953Srrs}
666163953Srrs
667163953Srrs
668163953Srrsint
669163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
670163953Srrs    struct mbuf *control, struct thread *p);
671163953Srrs
672163953Srrs
673163953Srrsint
674163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
675163953Srrs    struct mbuf *control, struct thread *p)
676163953Srrs{
677163953Srrs	struct sctp_inpcb *inp;
678163953Srrs	int error;
679163953Srrs
680163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
681163953Srrs	if (inp == 0) {
682163953Srrs		if (control) {
683163953Srrs			sctp_m_freem(control);
684163953Srrs			control = NULL;
685163953Srrs		}
686171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
687163953Srrs		sctp_m_freem(m);
688163953Srrs		return EINVAL;
689163953Srrs	}
690163953Srrs	/* Got to have an to address if we are NOT a connected socket */
691163953Srrs	if ((addr == NULL) &&
692163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
693163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))
694163953Srrs	    ) {
695163953Srrs		goto connected_type;
696163953Srrs	} else if (addr == NULL) {
697171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
698163953Srrs		error = EDESTADDRREQ;
699163953Srrs		sctp_m_freem(m);
700163953Srrs		if (control) {
701163953Srrs			sctp_m_freem(control);
702163953Srrs			control = NULL;
703163953Srrs		}
704163953Srrs		return (error);
705163953Srrs	}
706163953Srrs#ifdef INET6
707163953Srrs	if (addr->sa_family != AF_INET) {
708163953Srrs		/* must be a v4 address! */
709171943Srrs		SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
710163953Srrs		sctp_m_freem(m);
711163953Srrs		if (control) {
712163953Srrs			sctp_m_freem(control);
713163953Srrs			control = NULL;
714163953Srrs		}
715163953Srrs		error = EDESTADDRREQ;
716171943Srrs		return EDESTADDRREQ;
717163953Srrs	}
718163953Srrs#endif				/* INET6 */
719163953Srrsconnected_type:
720163953Srrs	/* now what about control */
721163953Srrs	if (control) {
722163953Srrs		if (inp->control) {
723169420Srrs			SCTP_PRINTF("huh? control set?\n");
724163953Srrs			sctp_m_freem(inp->control);
725163953Srrs			inp->control = NULL;
726163953Srrs		}
727163953Srrs		inp->control = control;
728163953Srrs	}
729163953Srrs	/* Place the data */
730163953Srrs	if (inp->pkt) {
731165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
732163953Srrs		inp->pkt_last = m;
733163953Srrs	} else {
734163953Srrs		inp->pkt_last = inp->pkt = m;
735163953Srrs	}
736163953Srrs	if (
737163953Srrs	/* FreeBSD uses a flag passed */
738163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
739163953Srrs	    ) {
740163953Srrs		/*
741163953Srrs		 * note with the current version this code will only be used
742163953Srrs		 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
743163953Srrs		 * re-defining sosend to use the sctp_sosend. One can
744163953Srrs		 * optionally switch back to this code (by changing back the
745163953Srrs		 * definitions) but this is not advisable. This code is used
746163953Srrs		 * by FreeBSD when sending a file with sendfile() though.
747163953Srrs		 */
748163953Srrs		int ret;
749163953Srrs
750163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
751163953Srrs		inp->pkt = NULL;
752163953Srrs		inp->control = NULL;
753163953Srrs		return (ret);
754163953Srrs	} else {
755163953Srrs		return (0);
756163953Srrs	}
757163953Srrs}
758163953Srrs
759171990Srrsint
760163953Srrssctp_disconnect(struct socket *so)
761163953Srrs{
762163953Srrs	struct sctp_inpcb *inp;
763163953Srrs
764163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
765163953Srrs	if (inp == NULL) {
766171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
767163953Srrs		return (ENOTCONN);
768163953Srrs	}
769163953Srrs	SCTP_INP_RLOCK(inp);
770171745Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
771171745Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
772199437Stuexen		if (LIST_EMPTY(&inp->sctp_asoc_list)) {
773163953Srrs			/* No connection */
774163953Srrs			SCTP_INP_RUNLOCK(inp);
775163953Srrs			return (0);
776163953Srrs		} else {
777163953Srrs			struct sctp_association *asoc;
778163953Srrs			struct sctp_tcb *stcb;
779163953Srrs
780163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
781163953Srrs			if (stcb == NULL) {
782163953Srrs				SCTP_INP_RUNLOCK(inp);
783171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
784163953Srrs				return (EINVAL);
785163953Srrs			}
786163953Srrs			SCTP_TCB_LOCK(stcb);
787163953Srrs			asoc = &stcb->asoc;
788163953Srrs			if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
789163953Srrs				/* We are about to be freed, out of here */
790163953Srrs				SCTP_TCB_UNLOCK(stcb);
791163953Srrs				SCTP_INP_RUNLOCK(inp);
792163953Srrs				return (0);
793163953Srrs			}
794163953Srrs			if (((so->so_options & SO_LINGER) &&
795163953Srrs			    (so->so_linger == 0)) ||
796163953Srrs			    (so->so_rcv.sb_cc > 0)) {
797163953Srrs				if (SCTP_GET_STATE(asoc) !=
798163953Srrs				    SCTP_STATE_COOKIE_WAIT) {
799163953Srrs					/* Left with Data unread */
800163953Srrs					struct mbuf *err;
801163953Srrs
802163953Srrs					err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA);
803163953Srrs					if (err) {
804163953Srrs						/*
805163953Srrs						 * Fill in the user
806163953Srrs						 * initiated abort
807163953Srrs						 */
808163953Srrs						struct sctp_paramhdr *ph;
809163953Srrs
810163953Srrs						ph = mtod(err, struct sctp_paramhdr *);
811165647Srrs						SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr);
812163953Srrs						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
813165647Srrs						ph->param_length = htons(SCTP_BUF_LEN(err));
814163953Srrs					}
815172396Srrs#if defined(SCTP_PANIC_ON_ABORT)
816172396Srrs					panic("disconnect does an abort");
817172396Srrs#endif
818172090Srrs					sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
819163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
820163953Srrs				}
821163953Srrs				SCTP_INP_RUNLOCK(inp);
822163953Srrs				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
823163953Srrs				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
824163953Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
825163953Srrs				}
826171943Srrs				(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
827163953Srrs				/* No unlock tcb assoc is gone */
828163953Srrs				return (0);
829163953Srrs			}
830163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
831163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
832163953Srrs			    (asoc->stream_queue_cnt == 0)) {
833163953Srrs				/* there is nothing queued to send, so done */
834163953Srrs				if (asoc->locked_on_sending) {
835163953Srrs					goto abort_anyway;
836163953Srrs				}
837166675Srrs				if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
838166675Srrs				    (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
839163953Srrs					/* only send SHUTDOWN 1st time thru */
840163953Srrs					sctp_stop_timers_for_shutdown(stcb);
841163953Srrs					sctp_send_shutdown(stcb,
842163953Srrs					    stcb->asoc.primary_destination);
843172090Srrs					sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
844166675Srrs					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
845166675Srrs					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
846166675Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
847166675Srrs					}
848171943Srrs					SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
849172703Srrs					SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
850163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
851163953Srrs					    stcb->sctp_ep, stcb,
852163953Srrs					    asoc->primary_destination);
853163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
854163953Srrs					    stcb->sctp_ep, stcb,
855163953Srrs					    asoc->primary_destination);
856163953Srrs				}
857163953Srrs			} else {
858163953Srrs				/*
859163953Srrs				 * we still got (or just got) data to send,
860163953Srrs				 * so set SHUTDOWN_PENDING
861163953Srrs				 */
862163953Srrs				/*
863163953Srrs				 * XXX sockets draft says that SCTP_EOF
864163953Srrs				 * should be sent with no data. currently,
865163953Srrs				 * we will allow user data to be sent first
866163953Srrs				 * and move to SHUTDOWN-PENDING
867163953Srrs				 */
868163953Srrs				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
869163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
870163953Srrs				    asoc->primary_destination);
871163953Srrs				if (asoc->locked_on_sending) {
872163953Srrs					/* Locked to send out the data */
873163953Srrs					struct sctp_stream_queue_pending *sp;
874163953Srrs
875163953Srrs					sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
876163953Srrs					if (sp == NULL) {
877169420Srrs						SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
878163953Srrs						    asoc->locked_on_sending->stream_no);
879163953Srrs					} else {
880163953Srrs						if ((sp->length == 0) && (sp->msg_is_complete == 0))
881163953Srrs							asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
882163953Srrs					}
883163953Srrs				}
884163953Srrs				if (TAILQ_EMPTY(&asoc->send_queue) &&
885163953Srrs				    TAILQ_EMPTY(&asoc->sent_queue) &&
886163953Srrs				    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
887163953Srrs					struct mbuf *op_err;
888163953Srrs
889163953Srrs			abort_anyway:
890163953Srrs					op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
891163953Srrs					    0, M_DONTWAIT, 1, MT_DATA);
892163953Srrs					if (op_err) {
893163953Srrs						/*
894163953Srrs						 * Fill in the user
895163953Srrs						 * initiated abort
896163953Srrs						 */
897163953Srrs						struct sctp_paramhdr *ph;
898163953Srrs						uint32_t *ippp;
899163953Srrs
900165647Srrs						SCTP_BUF_LEN(op_err) =
901163953Srrs						    (sizeof(struct sctp_paramhdr) + sizeof(uint32_t));
902163953Srrs						ph = mtod(op_err,
903163953Srrs						    struct sctp_paramhdr *);
904163953Srrs						ph->param_type = htons(
905163953Srrs						    SCTP_CAUSE_USER_INITIATED_ABT);
906165647Srrs						ph->param_length = htons(SCTP_BUF_LEN(op_err));
907163953Srrs						ippp = (uint32_t *) (ph + 1);
908165220Srrs						*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4);
909163953Srrs					}
910172396Srrs#if defined(SCTP_PANIC_ON_ABORT)
911172396Srrs					panic("disconnect does an abort");
912172396Srrs#endif
913172396Srrs
914165220Srrs					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
915172090Srrs					sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
916163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
917163953Srrs					if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
918163953Srrs					    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
919163953Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
920163953Srrs					}
921163953Srrs					SCTP_INP_RUNLOCK(inp);
922171943Srrs					(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
923163953Srrs					return (0);
924171990Srrs				} else {
925172090Srrs					sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
926163953Srrs				}
927163953Srrs			}
928188067Srrs			soisdisconnecting(so);
929163953Srrs			SCTP_TCB_UNLOCK(stcb);
930163953Srrs			SCTP_INP_RUNLOCK(inp);
931163953Srrs			return (0);
932163953Srrs		}
933163953Srrs		/* not reached */
934163953Srrs	} else {
935163953Srrs		/* UDP model does not support this */
936163953Srrs		SCTP_INP_RUNLOCK(inp);
937171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
938163953Srrs		return EOPNOTSUPP;
939163953Srrs	}
940163953Srrs}
941163953Srrs
942163953Srrsint
943178202Srrssctp_flush(struct socket *so, int how)
944178202Srrs{
945178202Srrs	/*
946178202Srrs	 * We will just clear out the values and let subsequent close clear
947178202Srrs	 * out the data, if any. Note if the user did a shutdown(SHUT_RD)
948178202Srrs	 * they will not be able to read the data, the socket will block
949178202Srrs	 * that from happening.
950178202Srrs	 */
951209289Stuexen	struct sctp_inpcb *inp;
952209289Stuexen
953209289Stuexen	inp = (struct sctp_inpcb *)so->so_pcb;
954209289Stuexen	if (inp == NULL) {
955209289Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
956209289Stuexen		return EINVAL;
957209289Stuexen	}
958209289Stuexen	SCTP_INP_RLOCK(inp);
959209289Stuexen	/* For the 1 to many model this does nothing */
960209289Stuexen	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
961209289Stuexen		SCTP_INP_RUNLOCK(inp);
962209289Stuexen		return (0);
963209289Stuexen	}
964209289Stuexen	SCTP_INP_RUNLOCK(inp);
965178202Srrs	if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
966178202Srrs		/*
967178202Srrs		 * First make sure the sb will be happy, we don't use these
968178202Srrs		 * except maybe the count
969178202Srrs		 */
970209289Stuexen		SCTP_INP_WLOCK(inp);
971209289Stuexen		SCTP_INP_READ_LOCK(inp);
972209289Stuexen		inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
973209289Stuexen		SCTP_INP_READ_UNLOCK(inp);
974209289Stuexen		SCTP_INP_WUNLOCK(inp);
975178202Srrs		so->so_rcv.sb_cc = 0;
976178202Srrs		so->so_rcv.sb_mbcnt = 0;
977178202Srrs		so->so_rcv.sb_mb = NULL;
978178202Srrs	}
979178202Srrs	if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
980178202Srrs		/*
981178202Srrs		 * First make sure the sb will be happy, we don't use these
982178202Srrs		 * except maybe the count
983178202Srrs		 */
984178202Srrs		so->so_snd.sb_cc = 0;
985178202Srrs		so->so_snd.sb_mbcnt = 0;
986178202Srrs		so->so_snd.sb_mb = NULL;
987178202Srrs
988178202Srrs	}
989178202Srrs	return (0);
990178202Srrs}
991178202Srrs
992178202Srrsint
993163953Srrssctp_shutdown(struct socket *so)
994163953Srrs{
995163953Srrs	struct sctp_inpcb *inp;
996163953Srrs
997163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
998163953Srrs	if (inp == 0) {
999171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1000163953Srrs		return EINVAL;
1001163953Srrs	}
1002163953Srrs	SCTP_INP_RLOCK(inp);
1003163953Srrs	/* For UDP model this is a invalid call */
1004163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
1005163953Srrs		/* Restore the flags that the soshutdown took away. */
1006204096Stuexen		SOCKBUF_LOCK(&so->so_rcv);
1007163953Srrs		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
1008204096Stuexen		SOCKBUF_UNLOCK(&so->so_rcv);
1009163953Srrs		/* This proc will wakeup for read and do nothing (I hope) */
1010163953Srrs		SCTP_INP_RUNLOCK(inp);
1011171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1012163953Srrs		return (EOPNOTSUPP);
1013163953Srrs	}
1014163953Srrs	/*
1015163953Srrs	 * Ok if we reach here its the TCP model and it is either a SHUT_WR
1016163953Srrs	 * or SHUT_RDWR. This means we put the shutdown flag against it.
1017163953Srrs	 */
1018163953Srrs	{
1019163953Srrs		struct sctp_tcb *stcb;
1020163953Srrs		struct sctp_association *asoc;
1021163953Srrs
1022188067Srrs		if ((so->so_state &
1023188067Srrs		    (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
1024188067Srrs			SCTP_INP_RUNLOCK(inp);
1025188067Srrs			return (ENOTCONN);
1026188067Srrs		}
1027163953Srrs		socantsendmore(so);
1028163953Srrs
1029163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1030163953Srrs		if (stcb == NULL) {
1031163953Srrs			/*
1032163953Srrs			 * Ok we hit the case that the shutdown call was
1033163953Srrs			 * made after an abort or something. Nothing to do
1034163953Srrs			 * now.
1035163953Srrs			 */
1036168299Srrs			SCTP_INP_RUNLOCK(inp);
1037163953Srrs			return (0);
1038163953Srrs		}
1039163953Srrs		SCTP_TCB_LOCK(stcb);
1040163953Srrs		asoc = &stcb->asoc;
1041163953Srrs		if (TAILQ_EMPTY(&asoc->send_queue) &&
1042163953Srrs		    TAILQ_EMPTY(&asoc->sent_queue) &&
1043163953Srrs		    (asoc->stream_queue_cnt == 0)) {
1044163953Srrs			if (asoc->locked_on_sending) {
1045163953Srrs				goto abort_anyway;
1046163953Srrs			}
1047163953Srrs			/* there is nothing queued to send, so I'm done... */
1048163953Srrs			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
1049163953Srrs				/* only send SHUTDOWN the first time through */
1050163953Srrs				sctp_stop_timers_for_shutdown(stcb);
1051163953Srrs				sctp_send_shutdown(stcb,
1052163953Srrs				    stcb->asoc.primary_destination);
1053172218Srrs				sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
1054166675Srrs				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
1055166675Srrs				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
1056166675Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
1057166675Srrs				}
1058171943Srrs				SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT);
1059172703Srrs				SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING);
1060163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
1061163953Srrs				    stcb->sctp_ep, stcb,
1062163953Srrs				    asoc->primary_destination);
1063163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
1064163953Srrs				    stcb->sctp_ep, stcb,
1065163953Srrs				    asoc->primary_destination);
1066163953Srrs			}
1067163953Srrs		} else {
1068163953Srrs			/*
1069163953Srrs			 * we still got (or just got) data to send, so set
1070163953Srrs			 * SHUTDOWN_PENDING
1071163953Srrs			 */
1072163953Srrs			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
1073163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
1074163953Srrs			    asoc->primary_destination);
1075163953Srrs
1076163953Srrs			if (asoc->locked_on_sending) {
1077163953Srrs				/* Locked to send out the data */
1078163953Srrs				struct sctp_stream_queue_pending *sp;
1079163953Srrs
1080163953Srrs				sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
1081163953Srrs				if (sp == NULL) {
1082169420Srrs					SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
1083163953Srrs					    asoc->locked_on_sending->stream_no);
1084163953Srrs				} else {
1085163953Srrs					if ((sp->length == 0) && (sp->msg_is_complete == 0)) {
1086163953Srrs						asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
1087163953Srrs					}
1088163953Srrs				}
1089163953Srrs			}
1090163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
1091163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
1092163953Srrs			    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
1093163953Srrs				struct mbuf *op_err;
1094163953Srrs
1095163953Srrs		abort_anyway:
1096163953Srrs				op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
1097163953Srrs				    0, M_DONTWAIT, 1, MT_DATA);
1098163953Srrs				if (op_err) {
1099163953Srrs					/* Fill in the user initiated abort */
1100163953Srrs					struct sctp_paramhdr *ph;
1101163953Srrs					uint32_t *ippp;
1102163953Srrs
1103165647Srrs					SCTP_BUF_LEN(op_err) =
1104163953Srrs					    sizeof(struct sctp_paramhdr) + sizeof(uint32_t);
1105163953Srrs					ph = mtod(op_err,
1106163953Srrs					    struct sctp_paramhdr *);
1107163953Srrs					ph->param_type = htons(
1108163953Srrs					    SCTP_CAUSE_USER_INITIATED_ABT);
1109165647Srrs					ph->param_length = htons(SCTP_BUF_LEN(op_err));
1110163953Srrs					ippp = (uint32_t *) (ph + 1);
1111165220Srrs					*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
1112163953Srrs				}
1113172396Srrs#if defined(SCTP_PANIC_ON_ABORT)
1114172396Srrs				panic("shutdown does an abort");
1115172396Srrs#endif
1116165220Srrs				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
1117163953Srrs				sctp_abort_an_association(stcb->sctp_ep, stcb,
1118163953Srrs				    SCTP_RESPONSE_TO_USER_REQ,
1119172090Srrs				    op_err, SCTP_SO_LOCKED);
1120163953Srrs				goto skip_unlock;
1121171990Srrs			} else {
1122172090Srrs				sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
1123163953Srrs			}
1124163953Srrs		}
1125163953Srrs		SCTP_TCB_UNLOCK(stcb);
1126163953Srrs	}
1127163953Srrsskip_unlock:
1128163953Srrs	SCTP_INP_RUNLOCK(inp);
1129163953Srrs	return 0;
1130163953Srrs}
1131163953Srrs
1132163953Srrs/*
1133163953Srrs * copies a "user" presentable address and removes embedded scope, etc.
1134163953Srrs * returns 0 on success, 1 on error
1135163953Srrs */
1136163953Srrsstatic uint32_t
1137163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
1138163953Srrs{
1139178251Srrs#ifdef INET6
1140163953Srrs	struct sockaddr_in6 lsa6;
1141163953Srrs
1142163953Srrs	sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
1143163953Srrs	    &lsa6);
1144178251Srrs#endif
1145163953Srrs	memcpy(ss, sa, sa->sa_len);
1146163953Srrs	return (0);
1147163953Srrs}
1148163953Srrs
1149163953Srrs
1150163953Srrs
1151172091Srrs/*
1152172091Srrs * NOTE: assumes addr lock is held
1153172091Srrs */
1154166675Srrsstatic size_t
1155168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
1156163953Srrs    struct sctp_tcb *stcb,
1157166675Srrs    size_t limit,
1158167598Srrs    struct sockaddr_storage *sas,
1159167598Srrs    uint32_t vrf_id)
1160163953Srrs{
1161167598Srrs	struct sctp_ifn *sctp_ifn;
1162167598Srrs	struct sctp_ifa *sctp_ifa;
1163166675Srrs	int loopback_scope, ipv4_local_scope, local_scope, site_scope;
1164166675Srrs	size_t actual;
1165163953Srrs	int ipv4_addr_legal, ipv6_addr_legal;
1166167598Srrs	struct sctp_vrf *vrf;
1167163953Srrs
1168163953Srrs	actual = 0;
1169163953Srrs	if (limit <= 0)
1170163953Srrs		return (actual);
1171163953Srrs
1172163953Srrs	if (stcb) {
1173163953Srrs		/* Turn on all the appropriate scope */
1174163953Srrs		loopback_scope = stcb->asoc.loopback_scope;
1175163953Srrs		ipv4_local_scope = stcb->asoc.ipv4_local_scope;
1176163953Srrs		local_scope = stcb->asoc.local_scope;
1177163953Srrs		site_scope = stcb->asoc.site_scope;
1178163953Srrs	} else {
1179163953Srrs		/* Turn on ALL scope, since we look at the EP */
1180163953Srrs		loopback_scope = ipv4_local_scope = local_scope =
1181163953Srrs		    site_scope = 1;
1182163953Srrs	}
1183163953Srrs	ipv4_addr_legal = ipv6_addr_legal = 0;
1184163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1185163953Srrs		ipv6_addr_legal = 1;
1186166023Srrs		if (SCTP_IPV6_V6ONLY(inp) == 0) {
1187163953Srrs			ipv4_addr_legal = 1;
1188163953Srrs		}
1189163953Srrs	} else {
1190163953Srrs		ipv4_addr_legal = 1;
1191163953Srrs	}
1192167598Srrs	vrf = sctp_find_vrf(vrf_id);
1193167598Srrs	if (vrf == NULL) {
1194167598Srrs		return (0);
1195167598Srrs	}
1196163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1197167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1198163953Srrs			if ((loopback_scope == 0) &&
1199167598Srrs			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
1200163953Srrs				/* Skip loopback if loopback_scope not set */
1201163953Srrs				continue;
1202163953Srrs			}
1203167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1204163953Srrs				if (stcb) {
1205163953Srrs					/*
1206163953Srrs					 * For the BOUND-ALL case, the list
1207163953Srrs					 * associated with a TCB is Always
1208163953Srrs					 * considered a reverse list.. i.e.
1209163953Srrs					 * it lists addresses that are NOT
1210163953Srrs					 * part of the association. If this
1211163953Srrs					 * is one of those we must skip it.
1212163953Srrs					 */
1213163953Srrs					if (sctp_is_addr_restricted(stcb,
1214167598Srrs					    sctp_ifa)) {
1215163953Srrs						continue;
1216163953Srrs					}
1217163953Srrs				}
1218178251Srrs				switch (sctp_ifa->address.sa.sa_family) {
1219221249Stuexen#ifdef INET
1220178251Srrs				case AF_INET:
1221178251Srrs					if (ipv4_addr_legal) {
1222178251Srrs						struct sockaddr_in *sin;
1223163953Srrs
1224178251Srrs						sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
1225178251Srrs						if (sin->sin_addr.s_addr == 0) {
1226178251Srrs							/*
1227178251Srrs							 * we skip
1228178251Srrs							 * unspecifed
1229178251Srrs							 * addresses
1230178251Srrs							 */
1231178251Srrs							continue;
1232178251Srrs						}
1233178251Srrs						if ((ipv4_local_scope == 0) &&
1234178251Srrs						    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
1235178251Srrs							continue;
1236178251Srrs						}
1237178251Srrs#ifdef INET6
1238178251Srrs						if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
1239178251Srrs							in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
1240178251Srrs							((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1241178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
1242178251Srrs							actual += sizeof(struct sockaddr_in6);
1243178251Srrs						} else {
1244178251Srrs#endif
1245178251Srrs							memcpy(sas, sin, sizeof(*sin));
1246178251Srrs							((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1247178251Srrs							sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
1248178251Srrs							actual += sizeof(*sin);
1249178251Srrs#ifdef INET6
1250178251Srrs						}
1251178251Srrs#endif
1252178251Srrs						if (actual >= limit) {
1253178251Srrs							return (actual);
1254178251Srrs						}
1255178251Srrs					} else {
1256163953Srrs						continue;
1257163953Srrs					}
1258178251Srrs					break;
1259221249Stuexen#endif
1260178251Srrs#ifdef INET6
1261178251Srrs				case AF_INET6:
1262178251Srrs					if (ipv6_addr_legal) {
1263178251Srrs						struct sockaddr_in6 *sin6;
1264163953Srrs
1265178251Srrs						sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
1266178251Srrs						if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1267178251Srrs							/*
1268178251Srrs							 * we skip
1269178251Srrs							 * unspecifed
1270178251Srrs							 * addresses
1271178251Srrs							 */
1272163953Srrs							continue;
1273178251Srrs						}
1274178251Srrs						if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1275178251Srrs							if (local_scope == 0)
1276163953Srrs								continue;
1277178251Srrs							if (sin6->sin6_scope_id == 0) {
1278178251Srrs								if (sa6_recoverscope(sin6) != 0)
1279178251Srrs									/*
1280178251Srrs									 *
1281178251Srrs									 * bad
1282178251Srrs									 *
1283178251Srrs									 * li
1284178251Srrs									 * nk
1285178251Srrs									 *
1286178251Srrs									 * loc
1287178251Srrs									 * al
1288178251Srrs									 *
1289178251Srrs									 * add
1290178251Srrs									 * re
1291178251Srrs									 * ss
1292178251Srrs									 * */
1293178251Srrs									continue;
1294178251Srrs							}
1295163953Srrs						}
1296178251Srrs						if ((site_scope == 0) &&
1297178251Srrs						    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
1298178251Srrs							continue;
1299178251Srrs						}
1300178251Srrs						memcpy(sas, sin6, sizeof(*sin6));
1301178251Srrs						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1302178251Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
1303178251Srrs						actual += sizeof(*sin6);
1304178251Srrs						if (actual >= limit) {
1305178251Srrs							return (actual);
1306178251Srrs						}
1307178251Srrs					} else {
1308163953Srrs						continue;
1309163953Srrs					}
1310178251Srrs					break;
1311178251Srrs#endif
1312178251Srrs				default:
1313178251Srrs					/* TSNH */
1314178251Srrs					break;
1315163953Srrs				}
1316163953Srrs			}
1317163953Srrs		}
1318163953Srrs	} else {
1319163953Srrs		struct sctp_laddr *laddr;
1320163953Srrs
1321167598Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1322167598Srrs			if (stcb) {
1323167598Srrs				if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
1324163953Srrs					continue;
1325163953Srrs				}
1326163953Srrs			}
1327167598Srrs			if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
1328167598Srrs				continue;
1329167598Srrs
1330167598Srrs			((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1331167598Srrs			sas = (struct sockaddr_storage *)((caddr_t)sas +
1332167598Srrs			    laddr->ifa->address.sa.sa_len);
1333167598Srrs			actual += laddr->ifa->address.sa.sa_len;
1334167598Srrs			if (actual >= limit) {
1335167598Srrs				return (actual);
1336163953Srrs			}
1337163953Srrs		}
1338163953Srrs	}
1339163953Srrs	return (actual);
1340163953Srrs}
1341163953Srrs
1342168124Srrsstatic size_t
1343168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp,
1344168124Srrs    struct sctp_tcb *stcb,
1345168124Srrs    size_t limit,
1346168124Srrs    struct sockaddr_storage *sas)
1347168124Srrs{
1348168124Srrs	size_t size = 0;
1349168124Srrs
1350172218Srrs	SCTP_IPI_ADDR_RLOCK();
1351168124Srrs	/* fill up addresses for the endpoint's default vrf */
1352168124Srrs	size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
1353168124Srrs	    inp->def_vrf_id);
1354172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1355168124Srrs	return (size);
1356168124Srrs}
1357168124Srrs
1358172091Srrs/*
1359172091Srrs * NOTE: assumes addr lock is held
1360172091Srrs */
1361163953Srrsstatic int
1362168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
1363163953Srrs{
1364163953Srrs	int cnt = 0;
1365167598Srrs	struct sctp_vrf *vrf = NULL;
1366163953Srrs
1367163953Srrs	/*
1368163953Srrs	 * In both sub-set bound an bound_all cases we return the MAXIMUM
1369163953Srrs	 * number of addresses that you COULD get. In reality the sub-set
1370163953Srrs	 * bound may have an exclusion list for a given TCB OR in the
1371163953Srrs	 * bound-all case a TCB may NOT include the loopback or other
1372163953Srrs	 * addresses as well.
1373163953Srrs	 */
1374167598Srrs	vrf = sctp_find_vrf(vrf_id);
1375167598Srrs	if (vrf == NULL) {
1376167598Srrs		return (0);
1377167598Srrs	}
1378163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1379167598Srrs		struct sctp_ifn *sctp_ifn;
1380167598Srrs		struct sctp_ifa *sctp_ifa;
1381163953Srrs
1382167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1383167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1384163953Srrs				/* Count them if they are the right type */
1385221249Stuexen				switch (sctp_ifa->address.sa.sa_family) {
1386221249Stuexen#ifdef INET
1387221249Stuexen				case AF_INET:
1388178251Srrs					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1389163953Srrs						cnt += sizeof(struct sockaddr_in6);
1390163953Srrs					else
1391163953Srrs						cnt += sizeof(struct sockaddr_in);
1392221249Stuexen					break;
1393221249Stuexen#endif
1394221249Stuexen#ifdef INET6
1395221249Stuexen				case AF_INET6:
1396163953Srrs					cnt += sizeof(struct sockaddr_in6);
1397221249Stuexen					break;
1398221249Stuexen#endif
1399221249Stuexen				default:
1400221249Stuexen					break;
1401221249Stuexen				}
1402163953Srrs			}
1403163953Srrs		}
1404163953Srrs	} else {
1405163953Srrs		struct sctp_laddr *laddr;
1406163953Srrs
1407163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1408221249Stuexen			switch (laddr->ifa->address.sa.sa_family) {
1409221249Stuexen#ifdef INET
1410221249Stuexen			case AF_INET:
1411178251Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
1412163953Srrs					cnt += sizeof(struct sockaddr_in6);
1413163953Srrs				else
1414163953Srrs					cnt += sizeof(struct sockaddr_in);
1415221249Stuexen				break;
1416221249Stuexen#endif
1417221249Stuexen#ifdef INET6
1418221249Stuexen			case AF_INET6:
1419163953Srrs				cnt += sizeof(struct sockaddr_in6);
1420221249Stuexen				break;
1421221249Stuexen#endif
1422221249Stuexen			default:
1423221249Stuexen				break;
1424221249Stuexen			}
1425163953Srrs		}
1426163953Srrs	}
1427163953Srrs	return (cnt);
1428163953Srrs}
1429163953Srrs
1430168124Srrsstatic int
1431168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp)
1432168124Srrs{
1433168124Srrs	int cnt = 0;
1434166675Srrs
1435172218Srrs	SCTP_IPI_ADDR_RLOCK();
1436168124Srrs	/* count addresses for the endpoint's default VRF */
1437168124Srrs	cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
1438172218Srrs	SCTP_IPI_ADDR_RUNLOCK();
1439168124Srrs	return (cnt);
1440168124Srrs}
1441168124Srrs
1442163953Srrsstatic int
1443166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
1444166675Srrs    size_t optsize, void *p, int delay)
1445163953Srrs{
1446163953Srrs	int error = 0;
1447163953Srrs	int creat_lock_on = 0;
1448163953Srrs	struct sctp_tcb *stcb = NULL;
1449163953Srrs	struct sockaddr *sa;
1450169352Srrs	int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
1451169352Srrs	int added = 0;
1452167598Srrs	uint32_t vrf_id;
1453170056Srrs	int bad_addresses = 0;
1454167598Srrs	sctp_assoc_t *a_id;
1455163953Srrs
1456169420Srrs	SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
1457163953Srrs
1458163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1459163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1460163953Srrs		/* We are already connected AND the TCP model */
1461171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
1462163953Srrs		return (EADDRINUSE);
1463163953Srrs	}
1464181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
1465181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
1466171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1467163953Srrs		return (EINVAL);
1468163953Srrs	}
1469163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1470163953Srrs		SCTP_INP_RLOCK(inp);
1471163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1472163953Srrs		SCTP_INP_RUNLOCK(inp);
1473163953Srrs	}
1474163953Srrs	if (stcb) {
1475171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1476163953Srrs		return (EALREADY);
1477163953Srrs	}
1478163953Srrs	SCTP_INP_INCR_REF(inp);
1479163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
1480163953Srrs	creat_lock_on = 1;
1481163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1482163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
1483171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
1484163953Srrs		error = EFAULT;
1485163953Srrs		goto out_now;
1486163953Srrs	}
1487166675Srrs	totaddrp = (int *)optval;
1488163953Srrs	totaddr = *totaddrp;
1489163953Srrs	sa = (struct sockaddr *)(totaddrp + 1);
1490170056Srrs	stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses);
1491170056Srrs	if ((stcb != NULL) || bad_addresses) {
1492169352Srrs		/* Already have or am bring up an association */
1493169352Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1494169352Srrs		creat_lock_on = 0;
1495170931Srrs		if (stcb)
1496170931Srrs			SCTP_TCB_UNLOCK(stcb);
1497171943Srrs		if (bad_addresses == 0) {
1498171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
1499170056Srrs			error = EALREADY;
1500171943Srrs		}
1501169352Srrs		goto out_now;
1502163953Srrs	}
1503163953Srrs#ifdef INET6
1504163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
1505163953Srrs	    (num_v6 > 0)) {
1506163953Srrs		error = EINVAL;
1507163953Srrs		goto out_now;
1508163953Srrs	}
1509163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1510163953Srrs	    (num_v4 > 0)) {
1511163953Srrs		struct in6pcb *inp6;
1512163953Srrs
1513163953Srrs		inp6 = (struct in6pcb *)inp;
1514166023Srrs		if (SCTP_IPV6_V6ONLY(inp6)) {
1515163953Srrs			/*
1516163953Srrs			 * if IPV6_V6ONLY flag, ignore connections destined
1517163953Srrs			 * to a v4 addr or v4-mapped addr
1518163953Srrs			 */
1519171943Srrs			SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1520163953Srrs			error = EINVAL;
1521163953Srrs			goto out_now;
1522163953Srrs		}
1523163953Srrs	}
1524163953Srrs#endif				/* INET6 */
1525163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1526163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
1527163953Srrs		/* Bind a ephemeral port */
1528171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
1529163953Srrs		if (error) {
1530163953Srrs			goto out_now;
1531163953Srrs		}
1532163953Srrs	}
1533167695Srrs	/* FIX ME: do we want to pass in a vrf on the connect call? */
1534167695Srrs	vrf_id = inp->def_vrf_id;
1535167695Srrs
1536181054Srrs
1537163953Srrs	/* We are GOOD to go */
1538206137Stuexen	stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id,
1539171531Srrs	    (struct thread *)p
1540171531Srrs	    );
1541163953Srrs	if (stcb == NULL) {
1542163953Srrs		/* Gak! no memory */
1543163953Srrs		goto out_now;
1544163953Srrs	}
1545171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
1546163953Srrs	/* move to second address */
1547221249Stuexen	switch (sa->sa_family) {
1548221249Stuexen#ifdef INET
1549221249Stuexen	case AF_INET:
1550163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
1551221249Stuexen		break;
1552221249Stuexen#endif
1553221249Stuexen#ifdef INET6
1554221249Stuexen	case AF_INET6:
1555163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
1556221249Stuexen		break;
1557221249Stuexen#endif
1558221249Stuexen	default:
1559221249Stuexen		break;
1560221249Stuexen	}
1561163953Srrs
1562170056Srrs	error = 0;
1563169352Srrs	added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
1564167598Srrs	/* Fill in the return id */
1565170056Srrs	if (error) {
1566207924Srrs		(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
1567170056Srrs		goto out_now;
1568170056Srrs	}
1569167598Srrs	a_id = (sctp_assoc_t *) optval;
1570167598Srrs	*a_id = sctp_get_associd(stcb);
1571163953Srrs
1572163953Srrs	/* initialize authentication parameters for the assoc */
1573163953Srrs	sctp_initialize_auth_params(inp, stcb);
1574163953Srrs
1575163953Srrs	if (delay) {
1576163953Srrs		/* doing delayed connection */
1577163953Srrs		stcb->asoc.delayed_connection = 1;
1578163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
1579163953Srrs	} else {
1580169378Srrs		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1581172090Srrs		sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
1582163953Srrs	}
1583163953Srrs	SCTP_TCB_UNLOCK(stcb);
1584163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1585163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1586163953Srrs		/* Set the connected flag so we can queue data */
1587163953Srrs		soisconnecting(so);
1588163953Srrs	}
1589163953Srrsout_now:
1590169655Srrs	if (creat_lock_on) {
1591163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1592169655Srrs	}
1593163953Srrs	SCTP_INP_DECR_REF(inp);
1594163953Srrs	return error;
1595163953Srrs}
1596163953Srrs
1597169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
1598169655Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\
1599169655Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \
1600166675Srrs		SCTP_INP_RLOCK(inp); \
1601166675Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list); \
1602169655Srrs		if (stcb) { \
1603166675Srrs			SCTP_TCB_LOCK(stcb); \
1604169655Srrs                } \
1605166675Srrs		SCTP_INP_RUNLOCK(inp); \
1606166675Srrs	} else if (assoc_id != 0) { \
1607166675Srrs		stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
1608166675Srrs		if (stcb == NULL) { \
1609171943Srrs		        SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
1610166675Srrs			error = ENOENT; \
1611166675Srrs			break; \
1612166675Srrs		} \
1613166675Srrs	} else { \
1614166675Srrs		stcb = NULL; \
1615169420Srrs        } \
1616169420Srrs  }
1617163953Srrs
1618169420Srrs
1619169420Srrs#define SCTP_CHECK_AND_CAST(destp, srcp, type, size)  {\
1620166675Srrs	if (size < sizeof(type)) { \
1621171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
1622166675Srrs		error = EINVAL; \
1623166675Srrs		break; \
1624166675Srrs	} else { \
1625166675Srrs		destp = (type *)srcp; \
1626169420Srrs	} \
1627169420Srrs      }
1628163953Srrs
1629163953Srrsstatic int
1630166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
1631166675Srrs    void *p)
1632163953Srrs{
1633171943Srrs	struct sctp_inpcb *inp = NULL;
1634166675Srrs	int error, val = 0;
1635163953Srrs	struct sctp_tcb *stcb = NULL;
1636163953Srrs
1637166675Srrs	if (optval == NULL) {
1638171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1639166675Srrs		return (EINVAL);
1640166675Srrs	}
1641163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1642171943Srrs	if (inp == 0) {
1643171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1644163953Srrs		return EINVAL;
1645171943Srrs	}
1646163953Srrs	error = 0;
1647163953Srrs
1648166675Srrs	switch (optname) {
1649163953Srrs	case SCTP_NODELAY:
1650163953Srrs	case SCTP_AUTOCLOSE:
1651163953Srrs	case SCTP_EXPLICIT_EOR:
1652163953Srrs	case SCTP_AUTO_ASCONF:
1653163953Srrs	case SCTP_DISABLE_FRAGMENTS:
1654163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
1655163953Srrs	case SCTP_USE_EXT_RCVINFO:
1656163953Srrs		SCTP_INP_RLOCK(inp);
1657166675Srrs		switch (optname) {
1658163953Srrs		case SCTP_DISABLE_FRAGMENTS:
1659166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
1660163953Srrs			break;
1661163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
1662166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
1663163953Srrs			break;
1664163953Srrs		case SCTP_AUTO_ASCONF:
1665171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1666171943Srrs				/* only valid for bound all sockets */
1667171943Srrs				val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
1668171943Srrs			} else {
1669171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1670171943Srrs				error = EINVAL;
1671171943Srrs				goto flags_out;
1672171943Srrs			}
1673163953Srrs			break;
1674163953Srrs		case SCTP_EXPLICIT_EOR:
1675166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
1676163953Srrs			break;
1677163953Srrs		case SCTP_NODELAY:
1678166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
1679163953Srrs			break;
1680163953Srrs		case SCTP_USE_EXT_RCVINFO:
1681166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
1682163953Srrs			break;
1683163953Srrs		case SCTP_AUTOCLOSE:
1684163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
1685166675Srrs				val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
1686163953Srrs			else
1687166675Srrs				val = 0;
1688163953Srrs			break;
1689163953Srrs
1690163953Srrs		default:
1691171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
1692163953Srrs			error = ENOPROTOOPT;
1693163953Srrs		}		/* end switch (sopt->sopt_name) */
1694166675Srrs		if (optname != SCTP_AUTOCLOSE) {
1695163953Srrs			/* make it an "on/off" value */
1696166675Srrs			val = (val != 0);
1697163953Srrs		}
1698166675Srrs		if (*optsize < sizeof(val)) {
1699171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1700163953Srrs			error = EINVAL;
1701163953Srrs		}
1702171943Srrsflags_out:
1703163953Srrs		SCTP_INP_RUNLOCK(inp);
1704163953Srrs		if (error == 0) {
1705163953Srrs			/* return the option value */
1706166675Srrs			*(int *)optval = val;
1707166675Srrs			*optsize = sizeof(val);
1708163953Srrs		}
1709163953Srrs		break;
1710170091Srrs	case SCTP_GET_PACKET_LOG:
1711170091Srrs		{
1712170091Srrs#ifdef  SCTP_PACKET_LOGGING
1713170091Srrs			uint8_t *target;
1714170091Srrs			int ret;
1715167598Srrs
1716170091Srrs			SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize);
1717170091Srrs			ret = sctp_copy_out_packet_log(target, (int)*optsize);
1718170091Srrs			*optsize = ret;
1719170091Srrs#else
1720171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1721170091Srrs			error = EOPNOTSUPP;
1722170091Srrs#endif
1723170091Srrs			break;
1724170091Srrs		}
1725181054Srrs	case SCTP_REUSE_PORT:
1726181054Srrs		{
1727181054Srrs			uint32_t *value;
1728181054Srrs
1729181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
1730181054Srrs				/* Can't do this for a 1-m socket */
1731181054Srrs				error = EINVAL;
1732181054Srrs				break;
1733181054Srrs			}
1734181054Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1735181054Srrs			*value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
1736181054Srrs			*optsize = sizeof(uint32_t);
1737181054Srrs		}
1738181054Srrs		break;
1739163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
1740163953Srrs		{
1741166675Srrs			uint32_t *value;
1742166675Srrs
1743166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1744166675Srrs			*value = inp->partial_delivery_point;
1745166675Srrs			*optsize = sizeof(uint32_t);
1746163953Srrs		}
1747163953Srrs		break;
1748163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
1749163953Srrs		{
1750166675Srrs			uint32_t *value;
1751166675Srrs
1752166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1753168943Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
1754168943Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
1755168943Srrs					*value = SCTP_FRAG_LEVEL_2;
1756168943Srrs				} else {
1757168943Srrs					*value = SCTP_FRAG_LEVEL_1;
1758168943Srrs				}
1759168943Srrs			} else {
1760168943Srrs				*value = SCTP_FRAG_LEVEL_0;
1761168943Srrs			}
1762166675Srrs			*optsize = sizeof(uint32_t);
1763163953Srrs		}
1764163953Srrs		break;
1765163953Srrs	case SCTP_CMT_ON_OFF:
1766163953Srrs		{
1767166675Srrs			struct sctp_assoc_value *av;
1768166675Srrs
1769166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1770211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1771211944Stuexen			if (stcb) {
1772211944Stuexen				av->assoc_value = stcb->asoc.sctp_cmt_on_off;
1773211944Stuexen				SCTP_TCB_UNLOCK(stcb);
1774166675Srrs			} else {
1775211944Stuexen				SCTP_INP_RLOCK(inp);
1776211944Stuexen				av->assoc_value = inp->sctp_cmt_on_off;
1777211944Stuexen				SCTP_INP_RUNLOCK(inp);
1778163953Srrs			}
1779166675Srrs			*optsize = sizeof(*av);
1780163953Srrs		}
1781163953Srrs		break;
1782171440Srrs		/* JRS - Get socket option for pluggable congestion control */
1783171440Srrs	case SCTP_PLUGGABLE_CC:
1784171440Srrs		{
1785171440Srrs			struct sctp_assoc_value *av;
1786171440Srrs
1787171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1788171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1789171440Srrs			if (stcb) {
1790171440Srrs				av->assoc_value = stcb->asoc.congestion_control_module;
1791171440Srrs				SCTP_TCB_UNLOCK(stcb);
1792171440Srrs			} else {
1793171440Srrs				av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
1794171440Srrs			}
1795171440Srrs			*optsize = sizeof(*av);
1796171440Srrs		}
1797171440Srrs		break;
1798219057Srrs	case SCTP_CC_OPTION:
1799219057Srrs		{
1800219057Srrs			struct sctp_cc_option *cc_opt;
1801219057Srrs
1802219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize);
1803219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
1804219057Srrs			if (stcb == NULL) {
1805219057Srrs				error = EINVAL;
1806219057Srrs			} else {
1807219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
1808219057Srrs					error = ENOTSUP;
1809219057Srrs				} else {
1810219057Srrs					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0,
1811219057Srrs					    cc_opt);
1812219057Srrs					*optsize = sizeof(*cc_opt);
1813219057Srrs				}
1814219057Srrs				SCTP_TCB_UNLOCK(stcb);
1815219057Srrs			}
1816219057Srrs		}
1817219120Srrs		break;
1818217760Stuexen		/* RS - Get socket option for pluggable stream scheduling */
1819217760Stuexen	case SCTP_PLUGGABLE_SS:
1820217760Stuexen		{
1821217760Stuexen			struct sctp_assoc_value *av;
1822217760Stuexen
1823217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1824217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1825217760Stuexen			if (stcb) {
1826217760Stuexen				av->assoc_value = stcb->asoc.stream_scheduling_module;
1827217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1828217760Stuexen			} else {
1829217760Stuexen				av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
1830217760Stuexen			}
1831217760Stuexen			*optsize = sizeof(*av);
1832217760Stuexen		}
1833217760Stuexen		break;
1834217760Stuexen	case SCTP_SS_VALUE:
1835217760Stuexen		{
1836217760Stuexen			struct sctp_stream_value *av;
1837217760Stuexen
1838217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
1839217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1840217760Stuexen			if (stcb) {
1841217760Stuexen				if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
1842217760Stuexen				    &av->stream_value) < 0) {
1843217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1844217760Stuexen					error = EINVAL;
1845217760Stuexen				} else {
1846217760Stuexen					*optsize = sizeof(*av);
1847217760Stuexen				}
1848217760Stuexen				SCTP_TCB_UNLOCK(stcb);
1849217760Stuexen			} else {
1850217760Stuexen				/*
1851217760Stuexen				 * Can't get stream value without
1852217760Stuexen				 * association
1853217760Stuexen				 */
1854217760Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
1855217760Stuexen				error = EINVAL;
1856217760Stuexen			}
1857217760Stuexen		}
1858217760Stuexen		break;
1859163953Srrs	case SCTP_GET_ADDR_LEN:
1860163953Srrs		{
1861163953Srrs			struct sctp_assoc_value *av;
1862163953Srrs
1863166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1864163953Srrs			error = EINVAL;
1865167598Srrs#ifdef INET
1866163953Srrs			if (av->assoc_value == AF_INET) {
1867163953Srrs				av->assoc_value = sizeof(struct sockaddr_in);
1868163953Srrs				error = 0;
1869163953Srrs			}
1870163953Srrs#endif
1871167598Srrs#ifdef INET6
1872163953Srrs			if (av->assoc_value == AF_INET6) {
1873163953Srrs				av->assoc_value = sizeof(struct sockaddr_in6);
1874163953Srrs				error = 0;
1875163953Srrs			}
1876163953Srrs#endif
1877172091Srrs			if (error) {
1878171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1879172091Srrs			}
1880166675Srrs			*optsize = sizeof(*av);
1881163953Srrs		}
1882163953Srrs		break;
1883169655Srrs	case SCTP_GET_ASSOC_NUMBER:
1884163953Srrs		{
1885169655Srrs			uint32_t *value, cnt;
1886163953Srrs
1887169655Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1888163953Srrs			cnt = 0;
1889163953Srrs			SCTP_INP_RLOCK(inp);
1890169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1891169655Srrs				cnt++;
1892163953Srrs			}
1893169655Srrs			SCTP_INP_RUNLOCK(inp);
1894169655Srrs			*value = cnt;
1895169655Srrs			*optsize = sizeof(uint32_t);
1896169655Srrs		}
1897169655Srrs		break;
1898163953Srrs
1899169655Srrs	case SCTP_GET_ASSOC_ID_LIST:
1900169655Srrs		{
1901169655Srrs			struct sctp_assoc_ids *ids;
1902169655Srrs			unsigned int at, limit;
1903169655Srrs
1904169655Srrs			SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
1905163953Srrs			at = 0;
1906185694Srrs			limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t);
1907169655Srrs			SCTP_INP_RLOCK(inp);
1908169655Srrs			LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
1909169655Srrs				if (at < limit) {
1910169655Srrs					ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
1911169655Srrs				} else {
1912169655Srrs					error = EINVAL;
1913171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1914163953Srrs					break;
1915163953Srrs				}
1916163953Srrs			}
1917163953Srrs			SCTP_INP_RUNLOCK(inp);
1918185694Srrs			ids->gaids_number_of_ids = at;
1919185694Srrs			*optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
1920163953Srrs		}
1921163953Srrs		break;
1922163953Srrs	case SCTP_CONTEXT:
1923163953Srrs		{
1924163953Srrs			struct sctp_assoc_value *av;
1925163953Srrs
1926166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1927166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1928166675Srrs
1929166675Srrs			if (stcb) {
1930166675Srrs				av->assoc_value = stcb->asoc.context;
1931166675Srrs				SCTP_TCB_UNLOCK(stcb);
1932163953Srrs			} else {
1933166675Srrs				SCTP_INP_RLOCK(inp);
1934163953Srrs				av->assoc_value = inp->sctp_context;
1935166675Srrs				SCTP_INP_RUNLOCK(inp);
1936163953Srrs			}
1937166675Srrs			*optsize = sizeof(*av);
1938163953Srrs		}
1939163953Srrs		break;
1940167598Srrs	case SCTP_VRF_ID:
1941167598Srrs		{
1942170056Srrs			uint32_t *default_vrfid;
1943167598Srrs
1944170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
1945170056Srrs			*default_vrfid = inp->def_vrf_id;
1946167598Srrs			break;
1947167598Srrs		}
1948167598Srrs	case SCTP_GET_ASOC_VRF:
1949167598Srrs		{
1950167598Srrs			struct sctp_assoc_value *id;
1951167598Srrs
1952167598Srrs			SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
1953167598Srrs			SCTP_FIND_STCB(inp, stcb, id->assoc_id);
1954167598Srrs			if (stcb == NULL) {
1955167598Srrs				error = EINVAL;
1956171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
1957167598Srrs				break;
1958167598Srrs			}
1959167598Srrs			id->assoc_value = stcb->asoc.vrf_id;
1960167598Srrs			break;
1961167598Srrs		}
1962167598Srrs	case SCTP_GET_VRF_IDS:
1963167598Srrs		{
1964171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
1965167598Srrs			error = EOPNOTSUPP;
1966167598Srrs			break;
1967167598Srrs		}
1968163953Srrs	case SCTP_GET_NONCE_VALUES:
1969163953Srrs		{
1970163953Srrs			struct sctp_get_nonce_values *gnv;
1971163953Srrs
1972166675Srrs			SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
1973166675Srrs			SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
1974166675Srrs
1975166675Srrs			if (stcb) {
1976163953Srrs				gnv->gn_peers_tag = stcb->asoc.peer_vtag;
1977163953Srrs				gnv->gn_local_tag = stcb->asoc.my_vtag;
1978163953Srrs				SCTP_TCB_UNLOCK(stcb);
1979166675Srrs			} else {
1980171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
1981166675Srrs				error = ENOTCONN;
1982163953Srrs			}
1983166675Srrs			*optsize = sizeof(*gnv);
1984163953Srrs		}
1985163953Srrs		break;
1986170056Srrs	case SCTP_DELAYED_SACK:
1987163953Srrs		{
1988170056Srrs			struct sctp_sack_info *sack;
1989163953Srrs
1990170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
1991170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
1992166675Srrs			if (stcb) {
1993170056Srrs				sack->sack_delay = stcb->asoc.delayed_ack;
1994170056Srrs				sack->sack_freq = stcb->asoc.sack_freq;
1995166675Srrs				SCTP_TCB_UNLOCK(stcb);
1996166675Srrs			} else {
1997163953Srrs				SCTP_INP_RLOCK(inp);
1998170056Srrs				sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
1999170056Srrs				sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
2000163953Srrs				SCTP_INP_RUNLOCK(inp);
2001163953Srrs			}
2002170056Srrs			*optsize = sizeof(*sack);
2003163953Srrs		}
2004163953Srrs		break;
2005163953Srrs
2006163953Srrs	case SCTP_GET_SNDBUF_USE:
2007166675Srrs		{
2008163953Srrs			struct sctp_sockstat *ss;
2009163953Srrs
2010166675Srrs			SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
2011166675Srrs			SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
2012166675Srrs
2013166675Srrs			if (stcb) {
2014166675Srrs				ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
2015166675Srrs				ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
2016166675Srrs				    stcb->asoc.size_on_all_streams);
2017166675Srrs				SCTP_TCB_UNLOCK(stcb);
2018166675Srrs			} else {
2019171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2020163953Srrs				error = ENOTCONN;
2021163953Srrs			}
2022166675Srrs			*optsize = sizeof(struct sctp_sockstat);
2023163953Srrs		}
2024163953Srrs		break;
2025170056Srrs	case SCTP_MAX_BURST:
2026163953Srrs		{
2027217895Stuexen			struct sctp_assoc_value *av;
2028163953Srrs
2029217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2030217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2031166675Srrs
2032217895Stuexen			if (stcb) {
2033217895Stuexen				av->assoc_value = stcb->asoc.max_burst;
2034217895Stuexen				SCTP_TCB_UNLOCK(stcb);
2035217894Stuexen			} else {
2036217895Stuexen				SCTP_INP_RLOCK(inp);
2037217895Stuexen				av->assoc_value = inp->sctp_ep.max_burst;
2038217895Stuexen				SCTP_INP_RUNLOCK(inp);
2039217894Stuexen			}
2040217895Stuexen			*optsize = sizeof(struct sctp_assoc_value);
2041217895Stuexen
2042163953Srrs		}
2043163953Srrs		break;
2044163953Srrs	case SCTP_MAXSEG:
2045163953Srrs		{
2046167598Srrs			struct sctp_assoc_value *av;
2047163953Srrs			int ovh;
2048163953Srrs
2049167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
2050170056Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2051163953Srrs
2052167598Srrs			if (stcb) {
2053167598Srrs				av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
2054167598Srrs				SCTP_TCB_UNLOCK(stcb);
2055163953Srrs			} else {
2056167598Srrs				SCTP_INP_RLOCK(inp);
2057167598Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2058167598Srrs					ovh = SCTP_MED_OVERHEAD;
2059167598Srrs				} else {
2060167598Srrs					ovh = SCTP_MED_V4_OVERHEAD;
2061167598Srrs				}
2062170056Srrs				if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
2063170056Srrs					av->assoc_value = 0;
2064170056Srrs				else
2065170056Srrs					av->assoc_value = inp->sctp_frag_point - ovh;
2066167598Srrs				SCTP_INP_RUNLOCK(inp);
2067163953Srrs			}
2068167598Srrs			*optsize = sizeof(struct sctp_assoc_value);
2069163953Srrs		}
2070163953Srrs		break;
2071163953Srrs	case SCTP_GET_STAT_LOG:
2072167598Srrs		error = sctp_fill_stat_log(optval, optsize);
2073163953Srrs		break;
2074163953Srrs	case SCTP_EVENTS:
2075163953Srrs		{
2076163953Srrs			struct sctp_event_subscribe *events;
2077163953Srrs
2078166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
2079163953Srrs			memset(events, 0, sizeof(*events));
2080163953Srrs			SCTP_INP_RLOCK(inp);
2081163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
2082163953Srrs				events->sctp_data_io_event = 1;
2083163953Srrs
2084163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
2085163953Srrs				events->sctp_association_event = 1;
2086163953Srrs
2087163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
2088163953Srrs				events->sctp_address_event = 1;
2089163953Srrs
2090163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
2091163953Srrs				events->sctp_send_failure_event = 1;
2092163953Srrs
2093163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
2094163953Srrs				events->sctp_peer_error_event = 1;
2095163953Srrs
2096163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
2097163953Srrs				events->sctp_shutdown_event = 1;
2098163953Srrs
2099163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
2100163953Srrs				events->sctp_partial_delivery_event = 1;
2101163953Srrs
2102163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
2103163953Srrs				events->sctp_adaptation_layer_event = 1;
2104163953Srrs
2105163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
2106163953Srrs				events->sctp_authentication_event = 1;
2107163953Srrs
2108185694Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
2109185694Srrs				events->sctp_sender_dry_event = 1;
2110185694Srrs
2111163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
2112202520Srrs				events->sctp_stream_reset_event = 1;
2113163953Srrs			SCTP_INP_RUNLOCK(inp);
2114166675Srrs			*optsize = sizeof(struct sctp_event_subscribe);
2115163953Srrs		}
2116163953Srrs		break;
2117163953Srrs
2118163953Srrs	case SCTP_ADAPTATION_LAYER:
2119166675Srrs		{
2120166675Srrs			uint32_t *value;
2121166675Srrs
2122166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2123166675Srrs
2124166675Srrs			SCTP_INP_RLOCK(inp);
2125166675Srrs			*value = inp->sctp_ep.adaptation_layer_indicator;
2126166675Srrs			SCTP_INP_RUNLOCK(inp);
2127166675Srrs			*optsize = sizeof(uint32_t);
2128163953Srrs		}
2129163953Srrs		break;
2130163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
2131166675Srrs		{
2132166675Srrs			uint32_t *value;
2133166675Srrs
2134166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2135166675Srrs			SCTP_INP_RLOCK(inp);
2136166675Srrs			*value = inp->sctp_ep.initial_sequence_debug;
2137166675Srrs			SCTP_INP_RUNLOCK(inp);
2138166675Srrs			*optsize = sizeof(uint32_t);
2139163953Srrs		}
2140163953Srrs		break;
2141163953Srrs	case SCTP_GET_LOCAL_ADDR_SIZE:
2142166675Srrs		{
2143166675Srrs			uint32_t *value;
2144166675Srrs
2145166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2146166675Srrs			SCTP_INP_RLOCK(inp);
2147168124Srrs			*value = sctp_count_max_addresses(inp);
2148166675Srrs			SCTP_INP_RUNLOCK(inp);
2149166675Srrs			*optsize = sizeof(uint32_t);
2150163953Srrs		}
2151163953Srrs		break;
2152163953Srrs	case SCTP_GET_REMOTE_ADDR_SIZE:
2153163953Srrs		{
2154166675Srrs			uint32_t *value;
2155166675Srrs			size_t size;
2156163953Srrs			struct sctp_nets *net;
2157163953Srrs
2158166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
2159166675Srrs			/* FIXME MT: change to sctp_assoc_value? */
2160166675Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
2161166675Srrs
2162166675Srrs			if (stcb) {
2163166675Srrs				size = 0;
2164166675Srrs				/* Count the sizes */
2165166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2166221249Stuexen					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2167166675Srrs						size += sizeof(struct sockaddr_in6);
2168166675Srrs					} else {
2169221249Stuexen						switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
2170221249Stuexen#ifdef INET
2171221249Stuexen						case AF_INET:
2172221249Stuexen							size += sizeof(struct sockaddr_in);
2173221249Stuexen							break;
2174221249Stuexen#endif
2175221249Stuexen#ifdef INET6
2176221249Stuexen						case AF_INET6:
2177221249Stuexen							size += sizeof(struct sockaddr_in6);
2178221249Stuexen							break;
2179221249Stuexen#endif
2180221249Stuexen						default:
2181221249Stuexen							break;
2182221249Stuexen						}
2183166675Srrs					}
2184163953Srrs				}
2185166675Srrs				SCTP_TCB_UNLOCK(stcb);
2186166675Srrs				*value = (uint32_t) size;
2187166675Srrs			} else {
2188171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
2189166675Srrs				error = ENOTCONN;
2190163953Srrs			}
2191166675Srrs			*optsize = sizeof(uint32_t);
2192163953Srrs		}
2193163953Srrs		break;
2194163953Srrs	case SCTP_GET_PEER_ADDRESSES:
2195163953Srrs		/*
2196163953Srrs		 * Get the address information, an array is passed in to
2197163953Srrs		 * fill up we pack it.
2198163953Srrs		 */
2199163953Srrs		{
2200166675Srrs			size_t cpsz, left;
2201163953Srrs			struct sockaddr_storage *sas;
2202163953Srrs			struct sctp_nets *net;
2203163953Srrs			struct sctp_getaddresses *saddr;
2204163953Srrs
2205166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2206166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2207163953Srrs
2208166675Srrs			if (stcb) {
2209166675Srrs				left = (*optsize) - sizeof(struct sctp_getaddresses);
2210166675Srrs				*optsize = sizeof(struct sctp_getaddresses);
2211166675Srrs				sas = (struct sockaddr_storage *)&saddr->addr[0];
2212166675Srrs
2213166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2214221249Stuexen					if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
2215166675Srrs						cpsz = sizeof(struct sockaddr_in6);
2216166675Srrs					} else {
2217221249Stuexen						switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) {
2218221249Stuexen#ifdef INET
2219221249Stuexen						case AF_INET:
2220221249Stuexen							cpsz = sizeof(struct sockaddr_in);
2221221249Stuexen							break;
2222221249Stuexen#endif
2223221249Stuexen#ifdef INET6
2224221249Stuexen						case AF_INET6:
2225221249Stuexen							cpsz = sizeof(struct sockaddr_in6);
2226221249Stuexen							break;
2227221249Stuexen#endif
2228221249Stuexen						default:
2229221249Stuexen							cpsz = 0;
2230221249Stuexen							break;
2231221249Stuexen						}
2232221249Stuexen					}
2233221249Stuexen					if (cpsz == 0) {
2234166675Srrs						break;
2235166675Srrs					}
2236166675Srrs					if (left < cpsz) {
2237166675Srrs						/* not enough room. */
2238166675Srrs						break;
2239166675Srrs					}
2240221249Stuexen#if defined(INET) && defined(INET6)
2241178251Srrs					if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
2242166675Srrs					    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
2243166675Srrs						/* Must map the address */
2244166675Srrs						in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
2245166675Srrs						    (struct sockaddr_in6 *)sas);
2246166675Srrs					} else {
2247178251Srrs#endif
2248166675Srrs						memcpy(sas, &net->ro._l_addr, cpsz);
2249221249Stuexen#if defined(INET) && defined(INET6)
2250166675Srrs					}
2251178251Srrs#endif
2252166675Srrs					((struct sockaddr_in *)sas)->sin_port = stcb->rport;
2253166675Srrs
2254166675Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
2255166675Srrs					left -= cpsz;
2256166675Srrs					*optsize += cpsz;
2257163953Srrs				}
2258166675Srrs				SCTP_TCB_UNLOCK(stcb);
2259166675Srrs			} else {
2260171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2261166675Srrs				error = ENOENT;
2262163953Srrs			}
2263163953Srrs		}
2264163953Srrs		break;
2265163953Srrs	case SCTP_GET_LOCAL_ADDRESSES:
2266163953Srrs		{
2267166675Srrs			size_t limit, actual;
2268163953Srrs			struct sockaddr_storage *sas;
2269163953Srrs			struct sctp_getaddresses *saddr;
2270163953Srrs
2271166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
2272166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
2273163953Srrs
2274163953Srrs			sas = (struct sockaddr_storage *)&saddr->addr[0];
2275166675Srrs			limit = *optsize - sizeof(sctp_assoc_t);
2276168124Srrs			actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
2277169655Srrs			if (stcb) {
2278163953Srrs				SCTP_TCB_UNLOCK(stcb);
2279169655Srrs			}
2280166675Srrs			*optsize = sizeof(struct sockaddr_storage) + actual;
2281163953Srrs		}
2282163953Srrs		break;
2283163953Srrs	case SCTP_PEER_ADDR_PARAMS:
2284163953Srrs		{
2285163953Srrs			struct sctp_paddrparams *paddrp;
2286163953Srrs			struct sctp_nets *net;
2287163953Srrs
2288166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
2289166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
2290163953Srrs
2291163953Srrs			net = NULL;
2292166675Srrs			if (stcb) {
2293166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
2294166675Srrs			} else {
2295166675Srrs				/*
2296166675Srrs				 * We increment here since
2297166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2298166675Srrs				 * decrement if it finds the stcb as long as
2299166675Srrs				 * the locked tcb (last argument) is NOT a
2300166675Srrs				 * TCB.. aka NULL.
2301166675Srrs				 */
2302166675Srrs				SCTP_INP_INCR_REF(inp);
2303166675Srrs				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL);
2304163953Srrs				if (stcb == NULL) {
2305166675Srrs					SCTP_INP_DECR_REF(inp);
2306163953Srrs				}
2307163953Srrs			}
2308171943Srrs			if (stcb && (net == NULL)) {
2309171943Srrs				struct sockaddr *sa;
2310163953Srrs
2311171943Srrs				sa = (struct sockaddr *)&paddrp->spp_address;
2312221249Stuexen#ifdef INET
2313171943Srrs				if (sa->sa_family == AF_INET) {
2314171943Srrs					struct sockaddr_in *sin;
2315171943Srrs
2316171943Srrs					sin = (struct sockaddr_in *)sa;
2317171943Srrs					if (sin->sin_addr.s_addr) {
2318171943Srrs						error = EINVAL;
2319171943Srrs						SCTP_TCB_UNLOCK(stcb);
2320171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2321171943Srrs						break;
2322171943Srrs					}
2323221249Stuexen				} else
2324221249Stuexen#endif
2325221249Stuexen#ifdef INET6
2326221249Stuexen				if (sa->sa_family == AF_INET6) {
2327171943Srrs					struct sockaddr_in6 *sin6;
2328171943Srrs
2329171943Srrs					sin6 = (struct sockaddr_in6 *)sa;
2330171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
2331171943Srrs						error = EINVAL;
2332171943Srrs						SCTP_TCB_UNLOCK(stcb);
2333171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2334171943Srrs						break;
2335171943Srrs					}
2336221249Stuexen				} else
2337221249Stuexen#endif
2338221249Stuexen				{
2339171943Srrs					error = EAFNOSUPPORT;
2340171943Srrs					SCTP_TCB_UNLOCK(stcb);
2341171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2342171943Srrs					break;
2343171943Srrs				}
2344171943Srrs			}
2345163953Srrs			if (stcb) {
2346163953Srrs				/* Applys to the specific association */
2347163953Srrs				paddrp->spp_flags = 0;
2348163953Srrs				if (net) {
2349170056Srrs					int ovh;
2350170056Srrs
2351170056Srrs					if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2352170056Srrs						ovh = SCTP_MED_OVERHEAD;
2353170056Srrs					} else {
2354170056Srrs						ovh = SCTP_MED_V4_OVERHEAD;
2355170056Srrs					}
2356170056Srrs
2357170056Srrs
2358163953Srrs					paddrp->spp_pathmaxrxt = net->failure_threshold;
2359170056Srrs					paddrp->spp_pathmtu = net->mtu - ovh;
2360163953Srrs					/* get flags for HB */
2361163953Srrs					if (net->dest_state & SCTP_ADDR_NOHB)
2362163953Srrs						paddrp->spp_flags |= SPP_HB_DISABLE;
2363163953Srrs					else
2364163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2365163953Srrs					/* get flags for PMTU */
2366165647Srrs					if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
2367163953Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2368163953Srrs					} else {
2369163953Srrs						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
2370163953Srrs					}
2371167598Srrs#ifdef INET
2372163953Srrs					if (net->ro._l_addr.sin.sin_family == AF_INET) {
2373163953Srrs						paddrp->spp_ipv4_tos = net->tos_flowlabel & 0x000000fc;
2374163953Srrs						paddrp->spp_flags |= SPP_IPV4_TOS;
2375163953Srrs					}
2376163953Srrs#endif
2377167598Srrs#ifdef INET6
2378163953Srrs					if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
2379163953Srrs						paddrp->spp_ipv6_flowlabel = net->tos_flowlabel;
2380163953Srrs						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2381163953Srrs					}
2382163953Srrs#endif
2383163953Srrs				} else {
2384163953Srrs					/*
2385163953Srrs					 * No destination so return default
2386163953Srrs					 * value
2387163953Srrs					 */
2388170056Srrs					int cnt = 0;
2389170056Srrs
2390163953Srrs					paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
2391163953Srrs					paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
2392167598Srrs#ifdef INET
2393163953Srrs					paddrp->spp_ipv4_tos = stcb->asoc.default_tos & 0x000000fc;
2394163953Srrs					paddrp->spp_flags |= SPP_IPV4_TOS;
2395163953Srrs#endif
2396167598Srrs#ifdef INET6
2397163953Srrs					paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel;
2398163953Srrs					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2399163953Srrs#endif
2400163953Srrs					/* default settings should be these */
2401170056Srrs					if (stcb->asoc.hb_is_disabled == 0) {
2402163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
2403170056Srrs					} else {
2404170056Srrs						paddrp->spp_flags |= SPP_HB_DISABLE;
2405163953Srrs					}
2406170056Srrs					TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
2407170056Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
2408170056Srrs							cnt++;
2409170056Srrs						}
2410170056Srrs					}
2411170056Srrs					if (cnt) {
2412170056Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
2413170056Srrs					}
2414163953Srrs				}
2415163953Srrs				paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
2416163953Srrs				paddrp->spp_assoc_id = sctp_get_associd(stcb);
2417163953Srrs				SCTP_TCB_UNLOCK(stcb);
2418163953Srrs			} else {
2419163953Srrs				/* Use endpoint defaults */
2420163953Srrs				SCTP_INP_RLOCK(inp);
2421163953Srrs				paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
2422163953Srrs				paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
2423163953Srrs				paddrp->spp_assoc_id = (sctp_assoc_t) 0;
2424163953Srrs				/* get inp's default */
2425167598Srrs#ifdef INET
2426163953Srrs				paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos;
2427163953Srrs				paddrp->spp_flags |= SPP_IPV4_TOS;
2428163953Srrs#endif
2429167598Srrs#ifdef INET6
2430163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2431163953Srrs					paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
2432163953Srrs					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
2433163953Srrs				}
2434163953Srrs#endif
2435163953Srrs				/* can't return this */
2436163953Srrs				paddrp->spp_pathmtu = 0;
2437170056Srrs
2438163953Srrs				/* default behavior, no stcb */
2439170056Srrs				paddrp->spp_flags = SPP_PMTUD_ENABLE;
2440163953Srrs
2441170056Srrs				if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
2442170056Srrs					paddrp->spp_flags |= SPP_HB_ENABLE;
2443170056Srrs				} else {
2444170056Srrs					paddrp->spp_flags |= SPP_HB_DISABLE;
2445170056Srrs				}
2446163953Srrs				SCTP_INP_RUNLOCK(inp);
2447163953Srrs			}
2448166675Srrs			*optsize = sizeof(struct sctp_paddrparams);
2449163953Srrs		}
2450163953Srrs		break;
2451163953Srrs	case SCTP_GET_PEER_ADDR_INFO:
2452163953Srrs		{
2453163953Srrs			struct sctp_paddrinfo *paddri;
2454163953Srrs			struct sctp_nets *net;
2455163953Srrs
2456166675Srrs			SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
2457166675Srrs			SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
2458166675Srrs
2459163953Srrs			net = NULL;
2460166675Srrs			if (stcb) {
2461166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address);
2462166675Srrs			} else {
2463166675Srrs				/*
2464166675Srrs				 * We increment here since
2465166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2466166675Srrs				 * decrement if it finds the stcb as long as
2467166675Srrs				 * the locked tcb (last argument) is NOT a
2468166675Srrs				 * TCB.. aka NULL.
2469166675Srrs				 */
2470166675Srrs				SCTP_INP_INCR_REF(inp);
2471166675Srrs				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL);
2472166675Srrs				if (stcb == NULL) {
2473166675Srrs					SCTP_INP_DECR_REF(inp);
2474163953Srrs				}
2475166675Srrs			}
2476163953Srrs
2477166675Srrs			if ((stcb) && (net)) {
2478217635Srrs				if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2479217638Stuexen					/* It's unconfirmed */
2480217635Srrs					paddri->spinfo_state = SCTP_UNCONFIRMED;
2481217635Srrs				} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2482217638Stuexen					/* It's active */
2483217635Srrs					paddri->spinfo_state = SCTP_ACTIVE;
2484217635Srrs				} else {
2485217638Stuexen					/* It's inactive */
2486217635Srrs					paddri->spinfo_state = SCTP_INACTIVE;
2487217635Srrs				}
2488166675Srrs				paddri->spinfo_cwnd = net->cwnd;
2489219014Stuexen				paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2490166675Srrs				paddri->spinfo_rto = net->RTO;
2491166675Srrs				paddri->spinfo_assoc_id = sctp_get_associd(stcb);
2492166675Srrs				SCTP_TCB_UNLOCK(stcb);
2493163953Srrs			} else {
2494163953Srrs				if (stcb) {
2495163953Srrs					SCTP_TCB_UNLOCK(stcb);
2496163953Srrs				}
2497171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2498163953Srrs				error = ENOENT;
2499163953Srrs			}
2500166675Srrs			*optsize = sizeof(struct sctp_paddrinfo);
2501163953Srrs		}
2502163953Srrs		break;
2503163953Srrs	case SCTP_PCB_STATUS:
2504163953Srrs		{
2505163953Srrs			struct sctp_pcbinfo *spcb;
2506163953Srrs
2507166675Srrs			SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
2508163953Srrs			sctp_fill_pcbinfo(spcb);
2509166675Srrs			*optsize = sizeof(struct sctp_pcbinfo);
2510163953Srrs		}
2511163953Srrs		break;
2512167598Srrs
2513163953Srrs	case SCTP_STATUS:
2514163953Srrs		{
2515163953Srrs			struct sctp_nets *net;
2516163953Srrs			struct sctp_status *sstat;
2517163953Srrs
2518166675Srrs			SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
2519166675Srrs			SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
2520163953Srrs
2521163953Srrs			if (stcb == NULL) {
2522171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2523163953Srrs				error = EINVAL;
2524163953Srrs				break;
2525163953Srrs			}
2526163953Srrs			/*
2527163953Srrs			 * I think passing the state is fine since
2528163953Srrs			 * sctp_constants.h will be available to the user
2529163953Srrs			 * land.
2530163953Srrs			 */
2531163953Srrs			sstat->sstat_state = stcb->asoc.state;
2532173179Srrs			sstat->sstat_assoc_id = sctp_get_associd(stcb);
2533163953Srrs			sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
2534163953Srrs			sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
2535163953Srrs			/*
2536163953Srrs			 * We can't include chunks that have been passed to
2537163953Srrs			 * the socket layer. Only things in queue.
2538163953Srrs			 */
2539163953Srrs			sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
2540163953Srrs			    stcb->asoc.cnt_on_all_streams);
2541163953Srrs
2542163953Srrs
2543163953Srrs			sstat->sstat_instrms = stcb->asoc.streamincnt;
2544163953Srrs			sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
2545163953Srrs			sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
2546163953Srrs			memcpy(&sstat->sstat_primary.spinfo_address,
2547163953Srrs			    &stcb->asoc.primary_destination->ro._l_addr,
2548163953Srrs			    ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
2549163953Srrs			net = stcb->asoc.primary_destination;
2550163953Srrs			((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
2551163953Srrs			/*
2552163953Srrs			 * Again the user can get info from sctp_constants.h
2553163953Srrs			 * for what the state of the network is.
2554163953Srrs			 */
2555217635Srrs			if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
2556217635Srrs				/* It's unconfirmed */
2557217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
2558217635Srrs			} else if (net->dest_state & SCTP_ADDR_REACHABLE) {
2559217638Stuexen				/* It's active */
2560217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
2561217635Srrs			} else {
2562217638Stuexen				/* It's inactive */
2563217635Srrs				sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
2564217635Srrs			}
2565163953Srrs			sstat->sstat_primary.spinfo_cwnd = net->cwnd;
2566219014Stuexen			sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
2567163953Srrs			sstat->sstat_primary.spinfo_rto = net->RTO;
2568163953Srrs			sstat->sstat_primary.spinfo_mtu = net->mtu;
2569163953Srrs			sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
2570163953Srrs			SCTP_TCB_UNLOCK(stcb);
2571166675Srrs			*optsize = sizeof(*sstat);
2572163953Srrs		}
2573163953Srrs		break;
2574163953Srrs	case SCTP_RTOINFO:
2575163953Srrs		{
2576163953Srrs			struct sctp_rtoinfo *srto;
2577163953Srrs
2578166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
2579166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
2580166675Srrs
2581166675Srrs			if (stcb) {
2582166675Srrs				srto->srto_initial = stcb->asoc.initial_rto;
2583166675Srrs				srto->srto_max = stcb->asoc.maxrto;
2584166675Srrs				srto->srto_min = stcb->asoc.minrto;
2585166675Srrs				SCTP_TCB_UNLOCK(stcb);
2586166675Srrs			} else {
2587163953Srrs				SCTP_INP_RLOCK(inp);
2588163953Srrs				srto->srto_initial = inp->sctp_ep.initial_rto;
2589163953Srrs				srto->srto_max = inp->sctp_ep.sctp_maxrto;
2590163953Srrs				srto->srto_min = inp->sctp_ep.sctp_minrto;
2591163953Srrs				SCTP_INP_RUNLOCK(inp);
2592163953Srrs			}
2593166675Srrs			*optsize = sizeof(*srto);
2594163953Srrs		}
2595163953Srrs		break;
2596215410Stuexen	case SCTP_TIMEOUTS:
2597215410Stuexen		{
2598215410Stuexen			struct sctp_timeouts *stimo;
2599215410Stuexen
2600215410Stuexen			SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize);
2601215410Stuexen			SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id);
2602215410Stuexen
2603215410Stuexen			if (stcb) {
2604215410Stuexen				stimo->stimo_init = stcb->asoc.timoinit;
2605215410Stuexen				stimo->stimo_data = stcb->asoc.timodata;
2606215410Stuexen				stimo->stimo_sack = stcb->asoc.timosack;
2607215410Stuexen				stimo->stimo_shutdown = stcb->asoc.timoshutdown;
2608215410Stuexen				stimo->stimo_heartbeat = stcb->asoc.timoheartbeat;
2609215410Stuexen				stimo->stimo_cookie = stcb->asoc.timocookie;
2610215410Stuexen				stimo->stimo_shutdownack = stcb->asoc.timoshutdownack;
2611215410Stuexen				SCTP_TCB_UNLOCK(stcb);
2612215410Stuexen			} else {
2613215410Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2614215410Stuexen				error = EINVAL;
2615215410Stuexen			}
2616215410Stuexen			*optsize = sizeof(*stimo);
2617215410Stuexen		}
2618215410Stuexen		break;
2619163953Srrs	case SCTP_ASSOCINFO:
2620163953Srrs		{
2621163953Srrs			struct sctp_assocparams *sasoc;
2622171477Srrs			uint32_t oldval;
2623163953Srrs
2624166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
2625166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
2626163953Srrs
2627163953Srrs			if (stcb) {
2628171477Srrs				oldval = sasoc->sasoc_cookie_life;
2629171477Srrs				sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
2630163953Srrs				sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
2631163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
2632163953Srrs				sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
2633163953Srrs				sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
2634163953Srrs				SCTP_TCB_UNLOCK(stcb);
2635163953Srrs			} else {
2636163953Srrs				SCTP_INP_RLOCK(inp);
2637171477Srrs				sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
2638163953Srrs				sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
2639163953Srrs				sasoc->sasoc_number_peer_destinations = 0;
2640163953Srrs				sasoc->sasoc_peer_rwnd = 0;
2641163953Srrs				sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
2642163953Srrs				SCTP_INP_RUNLOCK(inp);
2643163953Srrs			}
2644166675Srrs			*optsize = sizeof(*sasoc);
2645163953Srrs		}
2646163953Srrs		break;
2647163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
2648163953Srrs		{
2649163953Srrs			struct sctp_sndrcvinfo *s_info;
2650163953Srrs
2651166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
2652166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
2653166675Srrs
2654166675Srrs			if (stcb) {
2655170056Srrs				memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
2656166675Srrs				SCTP_TCB_UNLOCK(stcb);
2657166675Srrs			} else {
2658163953Srrs				SCTP_INP_RLOCK(inp);
2659170056Srrs				memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
2660163953Srrs				SCTP_INP_RUNLOCK(inp);
2661163953Srrs			}
2662166675Srrs			*optsize = sizeof(*s_info);
2663163953Srrs		}
2664163953Srrs		break;
2665163953Srrs	case SCTP_INITMSG:
2666163953Srrs		{
2667163953Srrs			struct sctp_initmsg *sinit;
2668163953Srrs
2669166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
2670163953Srrs			SCTP_INP_RLOCK(inp);
2671163953Srrs			sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
2672163953Srrs			sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
2673163953Srrs			sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
2674163953Srrs			sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
2675163953Srrs			SCTP_INP_RUNLOCK(inp);
2676166675Srrs			*optsize = sizeof(*sinit);
2677163953Srrs		}
2678163953Srrs		break;
2679163953Srrs	case SCTP_PRIMARY_ADDR:
2680163953Srrs		/* we allow a "get" operation on this */
2681163953Srrs		{
2682163953Srrs			struct sctp_setprim *ssp;
2683163953Srrs
2684166675Srrs			SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
2685166675Srrs			SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
2686166675Srrs
2687166675Srrs			if (stcb) {
2688166675Srrs				/* simply copy out the sockaddr_storage... */
2689170056Srrs				int len;
2690170056Srrs
2691170056Srrs				len = *optsize;
2692170056Srrs				if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len)
2693170056Srrs					len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len;
2694170056Srrs
2695170056Srrs				memcpy(&ssp->ssp_addr,
2696170056Srrs				    &stcb->asoc.primary_destination->ro._l_addr,
2697170056Srrs				    len);
2698166675Srrs				SCTP_TCB_UNLOCK(stcb);
2699166675Srrs			} else {
2700171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2701163953Srrs				error = EINVAL;
2702163953Srrs			}
2703166675Srrs			*optsize = sizeof(*ssp);
2704163953Srrs		}
2705163953Srrs		break;
2706163953Srrs
2707163953Srrs	case SCTP_HMAC_IDENT:
2708163953Srrs		{
2709163953Srrs			struct sctp_hmacalgo *shmac;
2710163953Srrs			sctp_hmaclist_t *hmaclist;
2711163953Srrs			uint32_t size;
2712163953Srrs			int i;
2713163953Srrs
2714166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
2715166675Srrs
2716163953Srrs			SCTP_INP_RLOCK(inp);
2717163953Srrs			hmaclist = inp->sctp_ep.local_hmacs;
2718163953Srrs			if (hmaclist == NULL) {
2719163953Srrs				/* no HMACs to return */
2720166675Srrs				*optsize = sizeof(*shmac);
2721168299Srrs				SCTP_INP_RUNLOCK(inp);
2722163953Srrs				break;
2723163953Srrs			}
2724163953Srrs			/* is there room for all of the hmac ids? */
2725163953Srrs			size = sizeof(*shmac) + (hmaclist->num_algo *
2726163953Srrs			    sizeof(shmac->shmac_idents[0]));
2727166675Srrs			if ((size_t)(*optsize) < size) {
2728171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2729163953Srrs				error = EINVAL;
2730163953Srrs				SCTP_INP_RUNLOCK(inp);
2731163953Srrs				break;
2732163953Srrs			}
2733163953Srrs			/* copy in the list */
2734181054Srrs			shmac->shmac_number_of_idents = hmaclist->num_algo;
2735181054Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
2736163953Srrs				shmac->shmac_idents[i] = hmaclist->hmac[i];
2737181054Srrs			}
2738163953Srrs			SCTP_INP_RUNLOCK(inp);
2739166675Srrs			*optsize = size;
2740163953Srrs			break;
2741163953Srrs		}
2742163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
2743163953Srrs		{
2744163953Srrs			struct sctp_authkeyid *scact;
2745163953Srrs
2746166675Srrs			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
2747166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
2748166675Srrs
2749166675Srrs			if (stcb) {
2750163953Srrs				/* get the active key on the assoc */
2751185694Srrs				scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
2752163953Srrs				SCTP_TCB_UNLOCK(stcb);
2753163953Srrs			} else {
2754163953Srrs				/* get the endpoint active key */
2755163953Srrs				SCTP_INP_RLOCK(inp);
2756163953Srrs				scact->scact_keynumber = inp->sctp_ep.default_keyid;
2757163953Srrs				SCTP_INP_RUNLOCK(inp);
2758163953Srrs			}
2759166675Srrs			*optsize = sizeof(*scact);
2760163953Srrs			break;
2761163953Srrs		}
2762163953Srrs	case SCTP_LOCAL_AUTH_CHUNKS:
2763163953Srrs		{
2764163953Srrs			struct sctp_authchunks *sac;
2765163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2766166675Srrs			size_t size = 0;
2767163953Srrs
2768166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2769166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2770166675Srrs
2771166675Srrs			if (stcb) {
2772163953Srrs				/* get off the assoc */
2773163953Srrs				chklist = stcb->asoc.local_auth_chunks;
2774163953Srrs				/* is there enough space? */
2775163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2776166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2777163953Srrs					error = EINVAL;
2778171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2779166675Srrs				} else {
2780166675Srrs					/* copy in the chunks */
2781169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2782163953Srrs				}
2783163953Srrs				SCTP_TCB_UNLOCK(stcb);
2784163953Srrs			} else {
2785163953Srrs				/* get off the endpoint */
2786163953Srrs				SCTP_INP_RLOCK(inp);
2787163953Srrs				chklist = inp->sctp_ep.local_auth_chunks;
2788163953Srrs				/* is there enough space? */
2789163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2790166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2791163953Srrs					error = EINVAL;
2792171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2793166675Srrs				} else {
2794166675Srrs					/* copy in the chunks */
2795169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2796163953Srrs				}
2797163953Srrs				SCTP_INP_RUNLOCK(inp);
2798163953Srrs			}
2799166675Srrs			*optsize = sizeof(struct sctp_authchunks) + size;
2800163953Srrs			break;
2801163953Srrs		}
2802163953Srrs	case SCTP_PEER_AUTH_CHUNKS:
2803163953Srrs		{
2804163953Srrs			struct sctp_authchunks *sac;
2805163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2806166675Srrs			size_t size = 0;
2807163953Srrs
2808166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2809166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2810166675Srrs
2811166675Srrs			if (stcb) {
2812166675Srrs				/* get off the assoc */
2813166675Srrs				chklist = stcb->asoc.peer_auth_chunks;
2814166675Srrs				/* is there enough space? */
2815166675Srrs				size = sctp_auth_get_chklist_size(chklist);
2816166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2817166675Srrs					error = EINVAL;
2818171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
2819166675Srrs				} else {
2820166675Srrs					/* copy in the chunks */
2821169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2822166675Srrs				}
2823166675Srrs				SCTP_TCB_UNLOCK(stcb);
2824166675Srrs			} else {
2825171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
2826163953Srrs				error = ENOENT;
2827163953Srrs			}
2828166675Srrs			*optsize = sizeof(struct sctp_authchunks) + size;
2829163953Srrs			break;
2830163953Srrs		}
2831163953Srrs
2832163953Srrs
2833163953Srrs	default:
2834171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
2835163953Srrs		error = ENOPROTOOPT;
2836166675Srrs		*optsize = 0;
2837163953Srrs		break;
2838163953Srrs	}			/* end switch (sopt->sopt_name) */
2839163953Srrs	return (error);
2840163953Srrs}
2841163953Srrs
2842163953Srrsstatic int
2843166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
2844166675Srrs    void *p)
2845163953Srrs{
2846166675Srrs	int error, set_opt;
2847166675Srrs	uint32_t *mopt;
2848163953Srrs	struct sctp_tcb *stcb = NULL;
2849171943Srrs	struct sctp_inpcb *inp = NULL;
2850167598Srrs	uint32_t vrf_id;
2851163953Srrs
2852166675Srrs	if (optval == NULL) {
2853169420Srrs		SCTP_PRINTF("optval is NULL\n");
2854171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2855163953Srrs		return (EINVAL);
2856163953Srrs	}
2857163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
2858167598Srrs	if (inp == 0) {
2859169420Srrs		SCTP_PRINTF("inp is NULL?\n");
2860171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2861163953Srrs		return EINVAL;
2862167598Srrs	}
2863168299Srrs	vrf_id = inp->def_vrf_id;
2864163953Srrs
2865163953Srrs	error = 0;
2866166675Srrs	switch (optname) {
2867163953Srrs	case SCTP_NODELAY:
2868163953Srrs	case SCTP_AUTOCLOSE:
2869163953Srrs	case SCTP_AUTO_ASCONF:
2870163953Srrs	case SCTP_EXPLICIT_EOR:
2871163953Srrs	case SCTP_DISABLE_FRAGMENTS:
2872163953Srrs	case SCTP_USE_EXT_RCVINFO:
2873163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
2874163953Srrs		/* copy in the option value */
2875166675Srrs		SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
2876163953Srrs		set_opt = 0;
2877163953Srrs		if (error)
2878163953Srrs			break;
2879166675Srrs		switch (optname) {
2880163953Srrs		case SCTP_DISABLE_FRAGMENTS:
2881163953Srrs			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
2882163953Srrs			break;
2883163953Srrs		case SCTP_AUTO_ASCONF:
2884171943Srrs			/*
2885171943Srrs			 * NOTE: we don't really support this flag
2886171943Srrs			 */
2887171943Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
2888171943Srrs				/* only valid for bound all sockets */
2889171943Srrs				set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
2890171943Srrs			} else {
2891171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2892171943Srrs				return (EINVAL);
2893171943Srrs			}
2894163953Srrs			break;
2895163953Srrs		case SCTP_EXPLICIT_EOR:
2896163953Srrs			set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
2897163953Srrs			break;
2898163953Srrs		case SCTP_USE_EXT_RCVINFO:
2899163953Srrs			set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
2900163953Srrs			break;
2901163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
2902163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2903163953Srrs				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
2904163953Srrs			} else {
2905171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2906163953Srrs				return (EINVAL);
2907163953Srrs			}
2908163953Srrs			break;
2909163953Srrs		case SCTP_NODELAY:
2910163953Srrs			set_opt = SCTP_PCB_FLAGS_NODELAY;
2911163953Srrs			break;
2912163953Srrs		case SCTP_AUTOCLOSE:
2913170056Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
2914170056Srrs			    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
2915171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2916170056Srrs				return (EINVAL);
2917170056Srrs			}
2918163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
2919163953Srrs			/*
2920163953Srrs			 * The value is in ticks. Note this does not effect
2921163953Srrs			 * old associations, only new ones.
2922163953Srrs			 */
2923163953Srrs			inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
2924163953Srrs			break;
2925163953Srrs		}
2926163953Srrs		SCTP_INP_WLOCK(inp);
2927163953Srrs		if (*mopt != 0) {
2928163953Srrs			sctp_feature_on(inp, set_opt);
2929163953Srrs		} else {
2930163953Srrs			sctp_feature_off(inp, set_opt);
2931163953Srrs		}
2932163953Srrs		SCTP_INP_WUNLOCK(inp);
2933163953Srrs		break;
2934181054Srrs	case SCTP_REUSE_PORT:
2935181054Srrs		{
2936181054Srrs			SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
2937181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
2938181054Srrs				/* Can't set it after we are bound */
2939181054Srrs				error = EINVAL;
2940181054Srrs				break;
2941181054Srrs			}
2942181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
2943181054Srrs				/* Can't do this for a 1-m socket */
2944181054Srrs				error = EINVAL;
2945181054Srrs				break;
2946181054Srrs			}
2947181054Srrs			if (optval)
2948181054Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
2949181054Srrs			else
2950181054Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
2951181054Srrs		}
2952181054Srrs		break;
2953163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
2954163953Srrs		{
2955166675Srrs			uint32_t *value;
2956166675Srrs
2957166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
2958167736Srrs			if (*value > SCTP_SB_LIMIT_RCV(so)) {
2959171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2960167736Srrs				error = EINVAL;
2961167736Srrs				break;
2962167736Srrs			}
2963166675Srrs			inp->partial_delivery_point = *value;
2964163953Srrs		}
2965163953Srrs		break;
2966163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
2967163953Srrs		/* not yet until we re-write sctp_recvmsg() */
2968163953Srrs		{
2969168943Srrs			uint32_t *level;
2970163953Srrs
2971168943Srrs			SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
2972168943Srrs			if (*level == SCTP_FRAG_LEVEL_2) {
2973163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
2974168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
2975168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_1) {
2976168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
2977168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
2978168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_0) {
2979170056Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
2980168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
2981168943Srrs
2982163953Srrs			} else {
2983171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
2984168943Srrs				error = EINVAL;
2985163953Srrs			}
2986163953Srrs		}
2987163953Srrs		break;
2988163953Srrs	case SCTP_CMT_ON_OFF:
2989211944Stuexen		if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
2990163953Srrs			struct sctp_assoc_value *av;
2991163953Srrs
2992166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
2993211944Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2994211944Stuexen			if (stcb) {
2995216669Stuexen				stcb->asoc.sctp_cmt_on_off = av->assoc_value;
2996216669Stuexen				if (stcb->asoc.sctp_cmt_on_off > 2) {
2997216669Stuexen					stcb->asoc.sctp_cmt_on_off = 2;
2998216669Stuexen				}
2999211944Stuexen				SCTP_TCB_UNLOCK(stcb);
3000166675Srrs			} else {
3001211944Stuexen				SCTP_INP_WLOCK(inp);
3002216669Stuexen				inp->sctp_cmt_on_off = av->assoc_value;
3003216669Stuexen				if (inp->sctp_cmt_on_off > 2) {
3004216669Stuexen					inp->sctp_cmt_on_off = 2;
3005216669Stuexen				}
3006211944Stuexen				SCTP_INP_WUNLOCK(inp);
3007163953Srrs			}
3008211944Stuexen		} else {
3009211944Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
3010211944Stuexen			error = ENOPROTOOPT;
3011163953Srrs		}
3012163953Srrs		break;
3013171440Srrs		/* JRS - Set socket option for pluggable congestion control */
3014171440Srrs	case SCTP_PLUGGABLE_CC:
3015171440Srrs		{
3016171440Srrs			struct sctp_assoc_value *av;
3017219057Srrs			struct sctp_nets *net;
3018171440Srrs
3019171440Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3020171440Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3021171440Srrs			if (stcb) {
3022171440Srrs				switch (av->assoc_value) {
3023171440Srrs				case SCTP_CC_RFC2581:
3024171440Srrs				case SCTP_CC_HSTCP:
3025171440Srrs				case SCTP_CC_HTCP:
3026219120Srrs				case SCTP_CC_RTCC:
3027217611Stuexen					stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
3028217611Stuexen					stcb->asoc.congestion_control_module = av->assoc_value;
3029219057Srrs					if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
3030219057Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3031219057Srrs							stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
3032219057Srrs						}
3033219057Srrs					}
3034217611Stuexen					break;
3035171440Srrs				default:
3036217611Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3037217611Stuexen					error = EINVAL;
3038217611Stuexen					break;
3039171440Srrs				}
3040217611Stuexen				SCTP_TCB_UNLOCK(stcb);
3041171440Srrs			} else {
3042171440Srrs				switch (av->assoc_value) {
3043171440Srrs				case SCTP_CC_RFC2581:
3044171440Srrs				case SCTP_CC_HSTCP:
3045171440Srrs				case SCTP_CC_HTCP:
3046219120Srrs				case SCTP_CC_RTCC:
3047217611Stuexen					SCTP_INP_WLOCK(inp);
3048171440Srrs					inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
3049217611Stuexen					SCTP_INP_WUNLOCK(inp);
3050171440Srrs					break;
3051171440Srrs				default:
3052171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3053171440Srrs					error = EINVAL;
3054171440Srrs					break;
3055217760Stuexen				}
3056171440Srrs			}
3057171440Srrs		}
3058219120Srrs		break;
3059219057Srrs	case SCTP_CC_OPTION:
3060219057Srrs		{
3061219057Srrs			struct sctp_cc_option *cc_opt;
3062219057Srrs
3063219057Srrs			SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
3064219057Srrs			SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
3065219057Srrs			if (stcb == NULL) {
3066219057Srrs				error = EINVAL;
3067219057Srrs			} else {
3068219057Srrs				if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
3069219057Srrs					error = ENOTSUP;
3070219057Srrs				} else {
3071219057Srrs					error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1,
3072219057Srrs					    cc_opt);
3073219057Srrs				}
3074219057Srrs				SCTP_TCB_UNLOCK(stcb);
3075219057Srrs			}
3076219057Srrs		}
3077171440Srrs		break;
3078217760Stuexen		/* RS - Set socket option for pluggable stream scheduling */
3079217760Stuexen	case SCTP_PLUGGABLE_SS:
3080217760Stuexen		{
3081217760Stuexen			struct sctp_assoc_value *av;
3082217760Stuexen
3083217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3084217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3085217760Stuexen			if (stcb) {
3086217760Stuexen				switch (av->assoc_value) {
3087217760Stuexen				case SCTP_SS_DEFAULT:
3088217760Stuexen				case SCTP_SS_ROUND_ROBIN:
3089217760Stuexen				case SCTP_SS_ROUND_ROBIN_PACKET:
3090217760Stuexen				case SCTP_SS_PRIORITY:
3091217760Stuexen				case SCTP_SS_FAIR_BANDWITH:
3092217760Stuexen				case SCTP_SS_FIRST_COME:
3093217760Stuexen					stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
3094217760Stuexen					stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
3095217760Stuexen					stcb->asoc.stream_scheduling_module = av->assoc_value;
3096217760Stuexen					stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
3097217760Stuexen					break;
3098217760Stuexen				default:
3099217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3100217760Stuexen					error = EINVAL;
3101217760Stuexen					break;
3102217760Stuexen				}
3103217760Stuexen				SCTP_TCB_UNLOCK(stcb);
3104217760Stuexen			} else {
3105217760Stuexen				switch (av->assoc_value) {
3106217760Stuexen				case SCTP_SS_DEFAULT:
3107217760Stuexen				case SCTP_SS_ROUND_ROBIN:
3108217760Stuexen				case SCTP_SS_ROUND_ROBIN_PACKET:
3109217760Stuexen				case SCTP_SS_PRIORITY:
3110217760Stuexen				case SCTP_SS_FAIR_BANDWITH:
3111217760Stuexen				case SCTP_SS_FIRST_COME:
3112217760Stuexen					SCTP_INP_WLOCK(inp);
3113217760Stuexen					inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
3114217760Stuexen					SCTP_INP_WUNLOCK(inp);
3115217760Stuexen					break;
3116217760Stuexen				default:
3117217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3118217760Stuexen					error = EINVAL;
3119217760Stuexen					break;
3120217760Stuexen				}
3121217760Stuexen			}
3122217760Stuexen		}
3123217760Stuexen		break;
3124217760Stuexen	case SCTP_SS_VALUE:
3125217760Stuexen		{
3126217760Stuexen			struct sctp_stream_value *av;
3127217760Stuexen
3128217760Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
3129217760Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3130217760Stuexen			if (stcb) {
3131217760Stuexen				if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
3132217760Stuexen				    av->stream_value) < 0) {
3133217760Stuexen					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3134217760Stuexen					error = EINVAL;
3135217760Stuexen				}
3136217760Stuexen				SCTP_TCB_UNLOCK(stcb);
3137217760Stuexen			} else {
3138217760Stuexen				/*
3139217760Stuexen				 * Can't set stream value without
3140217760Stuexen				 * association
3141217760Stuexen				 */
3142217760Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3143217760Stuexen				error = EINVAL;
3144217760Stuexen			}
3145217760Stuexen		}
3146217760Stuexen		break;
3147163953Srrs	case SCTP_CLR_STAT_LOG:
3148171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
3149163953Srrs		error = EOPNOTSUPP;
3150163953Srrs		break;
3151163953Srrs	case SCTP_CONTEXT:
3152163953Srrs		{
3153163953Srrs			struct sctp_assoc_value *av;
3154163953Srrs
3155166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3156166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3157166675Srrs
3158166675Srrs			if (stcb) {
3159166675Srrs				stcb->asoc.context = av->assoc_value;
3160166675Srrs				SCTP_TCB_UNLOCK(stcb);
3161163953Srrs			} else {
3162166675Srrs				SCTP_INP_WLOCK(inp);
3163163953Srrs				inp->sctp_context = av->assoc_value;
3164166675Srrs				SCTP_INP_WUNLOCK(inp);
3165163953Srrs			}
3166163953Srrs		}
3167163953Srrs		break;
3168167598Srrs	case SCTP_VRF_ID:
3169167598Srrs		{
3170170056Srrs			uint32_t *default_vrfid;
3171167598Srrs
3172170056Srrs			SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
3173170056Srrs			if (*default_vrfid > SCTP_MAX_VRF_ID) {
3174171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3175167598Srrs				error = EINVAL;
3176167598Srrs				break;
3177167598Srrs			}
3178170056Srrs			inp->def_vrf_id = *default_vrfid;
3179167598Srrs			break;
3180167598Srrs		}
3181167598Srrs	case SCTP_DEL_VRF_ID:
3182167598Srrs		{
3183171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
3184167598Srrs			error = EOPNOTSUPP;
3185167598Srrs			break;
3186167598Srrs		}
3187167598Srrs	case SCTP_ADD_VRF_ID:
3188167598Srrs		{
3189171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
3190167598Srrs			error = EOPNOTSUPP;
3191167598Srrs			break;
3192167598Srrs		}
3193170056Srrs	case SCTP_DELAYED_SACK:
3194163953Srrs		{
3195170056Srrs			struct sctp_sack_info *sack;
3196163953Srrs
3197170056Srrs			SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
3198170056Srrs			SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
3199171477Srrs			if (sack->sack_delay) {
3200171477Srrs				if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
3201171477Srrs					sack->sack_delay = SCTP_MAX_SACK_DELAY;
3202171477Srrs			}
3203166675Srrs			if (stcb) {
3204170056Srrs				if (sack->sack_delay) {
3205170056Srrs					if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
3206170056Srrs						sack->sack_delay = TICKS_TO_MSEC(1);
3207170056Srrs					}
3208170056Srrs					stcb->asoc.delayed_ack = sack->sack_delay;
3209170056Srrs				}
3210170056Srrs				if (sack->sack_freq) {
3211170056Srrs					stcb->asoc.sack_freq = sack->sack_freq;
3212170056Srrs				}
3213166675Srrs				SCTP_TCB_UNLOCK(stcb);
3214166675Srrs			} else {
3215163953Srrs				SCTP_INP_WLOCK(inp);
3216170056Srrs				if (sack->sack_delay) {
3217170056Srrs					if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
3218170056Srrs						sack->sack_delay = TICKS_TO_MSEC(1);
3219170056Srrs					}
3220170056Srrs					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
3221170056Srrs				}
3222170056Srrs				if (sack->sack_freq) {
3223170056Srrs					inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
3224170056Srrs				}
3225163953Srrs				SCTP_INP_WUNLOCK(inp);
3226163953Srrs			}
3227166675Srrs			break;
3228163953Srrs		}
3229163953Srrs	case SCTP_AUTH_CHUNK:
3230163953Srrs		{
3231163953Srrs			struct sctp_authchunk *sauth;
3232163953Srrs
3233166675Srrs			SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
3234166675Srrs
3235166675Srrs			SCTP_INP_WLOCK(inp);
3236171943Srrs			if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
3237171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3238163953Srrs				error = EINVAL;
3239171943Srrs			}
3240166675Srrs			SCTP_INP_WUNLOCK(inp);
3241163953Srrs			break;
3242163953Srrs		}
3243163953Srrs	case SCTP_AUTH_KEY:
3244163953Srrs		{
3245163953Srrs			struct sctp_authkey *sca;
3246163953Srrs			struct sctp_keyhead *shared_keys;
3247163953Srrs			sctp_sharedkey_t *shared_key;
3248163953Srrs			sctp_key_t *key = NULL;
3249166675Srrs			size_t size;
3250163953Srrs
3251166675Srrs			SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
3252169420Srrs			SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
3253169420Srrs			size = optsize - sizeof(*sca);
3254166675Srrs
3255166675Srrs			if (stcb) {
3256163953Srrs				/* set it on the assoc */
3257163953Srrs				shared_keys = &stcb->asoc.shared_keys;
3258163953Srrs				/* clear the cached keys for this key id */
3259163953Srrs				sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
3260163953Srrs				/*
3261163953Srrs				 * create the new shared key and
3262163953Srrs				 * insert/replace it
3263163953Srrs				 */
3264163953Srrs				if (size > 0) {
3265163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
3266163953Srrs					if (key == NULL) {
3267171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3268163953Srrs						error = ENOMEM;
3269163953Srrs						SCTP_TCB_UNLOCK(stcb);
3270163953Srrs						break;
3271163953Srrs					}
3272163953Srrs				}
3273163953Srrs				shared_key = sctp_alloc_sharedkey();
3274163953Srrs				if (shared_key == NULL) {
3275163953Srrs					sctp_free_key(key);
3276171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3277163953Srrs					error = ENOMEM;
3278163953Srrs					SCTP_TCB_UNLOCK(stcb);
3279163953Srrs					break;
3280163953Srrs				}
3281163953Srrs				shared_key->key = key;
3282163953Srrs				shared_key->keyid = sca->sca_keynumber;
3283185694Srrs				error = sctp_insert_sharedkey(shared_keys, shared_key);
3284163953Srrs				SCTP_TCB_UNLOCK(stcb);
3285163953Srrs			} else {
3286166675Srrs				/* set it on the endpoint */
3287163953Srrs				SCTP_INP_WLOCK(inp);
3288163953Srrs				shared_keys = &inp->sctp_ep.shared_keys;
3289163953Srrs				/*
3290163953Srrs				 * clear the cached keys on all assocs for
3291163953Srrs				 * this key id
3292163953Srrs				 */
3293163953Srrs				sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
3294163953Srrs				/*
3295163953Srrs				 * create the new shared key and
3296163953Srrs				 * insert/replace it
3297163953Srrs				 */
3298163953Srrs				if (size > 0) {
3299163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
3300163953Srrs					if (key == NULL) {
3301171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3302163953Srrs						error = ENOMEM;
3303163953Srrs						SCTP_INP_WUNLOCK(inp);
3304163953Srrs						break;
3305163953Srrs					}
3306163953Srrs				}
3307163953Srrs				shared_key = sctp_alloc_sharedkey();
3308163953Srrs				if (shared_key == NULL) {
3309163953Srrs					sctp_free_key(key);
3310171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3311163953Srrs					error = ENOMEM;
3312163953Srrs					SCTP_INP_WUNLOCK(inp);
3313163953Srrs					break;
3314163953Srrs				}
3315163953Srrs				shared_key->key = key;
3316163953Srrs				shared_key->keyid = sca->sca_keynumber;
3317185694Srrs				error = sctp_insert_sharedkey(shared_keys, shared_key);
3318163953Srrs				SCTP_INP_WUNLOCK(inp);
3319163953Srrs			}
3320163953Srrs			break;
3321163953Srrs		}
3322163953Srrs	case SCTP_HMAC_IDENT:
3323163953Srrs		{
3324163953Srrs			struct sctp_hmacalgo *shmac;
3325163953Srrs			sctp_hmaclist_t *hmaclist;
3326181054Srrs			uint16_t hmacid;
3327181054Srrs			uint32_t i;
3328163953Srrs
3329181054Srrs			size_t found;
3330181054Srrs
3331166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
3332181054Srrs			if (optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) {
3333181054Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3334181054Srrs				error = EINVAL;
3335181054Srrs				break;
3336181054Srrs			}
3337181054Srrs			hmaclist = sctp_alloc_hmaclist(shmac->shmac_number_of_idents);
3338163953Srrs			if (hmaclist == NULL) {
3339171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
3340163953Srrs				error = ENOMEM;
3341163953Srrs				break;
3342163953Srrs			}
3343181054Srrs			for (i = 0; i < shmac->shmac_number_of_idents; i++) {
3344163953Srrs				hmacid = shmac->shmac_idents[i];
3345181054Srrs				if (sctp_auth_add_hmacid(hmaclist, hmacid)) {
3346163953Srrs					 /* invalid HMACs were found */ ;
3347171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3348163953Srrs					error = EINVAL;
3349164085Srrs					sctp_free_hmaclist(hmaclist);
3350163953Srrs					goto sctp_set_hmac_done;
3351163953Srrs				}
3352163953Srrs			}
3353170056Srrs			found = 0;
3354170056Srrs			for (i = 0; i < hmaclist->num_algo; i++) {
3355170056Srrs				if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
3356170056Srrs					/* already in list */
3357170056Srrs					found = 1;
3358170056Srrs				}
3359170056Srrs			}
3360170056Srrs			if (!found) {
3361170056Srrs				sctp_free_hmaclist(hmaclist);
3362171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3363170056Srrs				error = EINVAL;
3364170056Srrs				break;
3365170056Srrs			}
3366163953Srrs			/* set it on the endpoint */
3367163953Srrs			SCTP_INP_WLOCK(inp);
3368163953Srrs			if (inp->sctp_ep.local_hmacs)
3369163953Srrs				sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
3370163953Srrs			inp->sctp_ep.local_hmacs = hmaclist;
3371163953Srrs			SCTP_INP_WUNLOCK(inp);
3372163953Srrs	sctp_set_hmac_done:
3373163953Srrs			break;
3374163953Srrs		}
3375163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
3376163953Srrs		{
3377163953Srrs			struct sctp_authkeyid *scact;
3378163953Srrs
3379185694Srrs			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid,
3380185694Srrs			    optsize);
3381166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
3382166675Srrs
3383163953Srrs			/* set the active key on the right place */
3384166675Srrs			if (stcb) {
3385163953Srrs				/* set the active key on the assoc */
3386185694Srrs				if (sctp_auth_setactivekey(stcb,
3387185694Srrs				    scact->scact_keynumber)) {
3388185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
3389185694Srrs					    SCTP_FROM_SCTP_USRREQ,
3390185694Srrs					    EINVAL);
3391163953Srrs					error = EINVAL;
3392171943Srrs				}
3393163953Srrs				SCTP_TCB_UNLOCK(stcb);
3394163953Srrs			} else {
3395163953Srrs				/* set the active key on the endpoint */
3396163953Srrs				SCTP_INP_WLOCK(inp);
3397185694Srrs				if (sctp_auth_setactivekey_ep(inp,
3398185694Srrs				    scact->scact_keynumber)) {
3399185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
3400185694Srrs					    SCTP_FROM_SCTP_USRREQ,
3401185694Srrs					    EINVAL);
3402163953Srrs					error = EINVAL;
3403171943Srrs				}
3404163953Srrs				SCTP_INP_WUNLOCK(inp);
3405163953Srrs			}
3406163953Srrs			break;
3407163953Srrs		}
3408163953Srrs	case SCTP_AUTH_DELETE_KEY:
3409163953Srrs		{
3410163953Srrs			struct sctp_authkeyid *scdel;
3411163953Srrs
3412185694Srrs			SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid,
3413185694Srrs			    optsize);
3414166675Srrs			SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
3415166675Srrs
3416163953Srrs			/* delete the key from the right place */
3417166675Srrs			if (stcb) {
3418185694Srrs				if (sctp_delete_sharedkey(stcb,
3419185694Srrs				    scdel->scact_keynumber)) {
3420185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
3421185694Srrs					    SCTP_FROM_SCTP_USRREQ,
3422185694Srrs					    EINVAL);
3423163953Srrs					error = EINVAL;
3424171943Srrs				}
3425163953Srrs				SCTP_TCB_UNLOCK(stcb);
3426163953Srrs			} else {
3427163953Srrs				SCTP_INP_WLOCK(inp);
3428185694Srrs				if (sctp_delete_sharedkey_ep(inp,
3429185694Srrs				    scdel->scact_keynumber)) {
3430185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
3431185694Srrs					    SCTP_FROM_SCTP_USRREQ,
3432185694Srrs					    EINVAL);
3433163953Srrs					error = EINVAL;
3434171943Srrs				}
3435163953Srrs				SCTP_INP_WUNLOCK(inp);
3436163953Srrs			}
3437163953Srrs			break;
3438163953Srrs		}
3439185694Srrs	case SCTP_AUTH_DEACTIVATE_KEY:
3440185694Srrs		{
3441185694Srrs			struct sctp_authkeyid *keyid;
3442163953Srrs
3443185694Srrs			SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid,
3444185694Srrs			    optsize);
3445185694Srrs			SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
3446185694Srrs
3447185694Srrs			/* deactivate the key from the right place */
3448185694Srrs			if (stcb) {
3449185694Srrs				if (sctp_deact_sharedkey(stcb,
3450185694Srrs				    keyid->scact_keynumber)) {
3451185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
3452185694Srrs					    SCTP_FROM_SCTP_USRREQ,
3453185694Srrs					    EINVAL);
3454185694Srrs					error = EINVAL;
3455185694Srrs				}
3456185694Srrs				SCTP_TCB_UNLOCK(stcb);
3457185694Srrs			} else {
3458185694Srrs				SCTP_INP_WLOCK(inp);
3459185694Srrs				if (sctp_deact_sharedkey_ep(inp,
3460185694Srrs				    keyid->scact_keynumber)) {
3461185694Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
3462185694Srrs					    SCTP_FROM_SCTP_USRREQ,
3463185694Srrs					    EINVAL);
3464185694Srrs					error = EINVAL;
3465185694Srrs				}
3466185694Srrs				SCTP_INP_WUNLOCK(inp);
3467185694Srrs			}
3468185694Srrs			break;
3469185694Srrs		}
3470185694Srrs
3471163953Srrs	case SCTP_RESET_STREAMS:
3472163953Srrs		{
3473163953Srrs			struct sctp_stream_reset *strrst;
3474188854Srrs			uint8_t send_in = 0, send_tsn = 0, send_out = 0,
3475188854Srrs			        addstream = 0;
3476188854Srrs			uint16_t addstrmcnt = 0;
3477163953Srrs			int i;
3478163953Srrs
3479166675Srrs			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize);
3480166675Srrs			SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id);
3481163953Srrs
3482163953Srrs			if (stcb == NULL) {
3483171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
3484163953Srrs				error = ENOENT;
3485163953Srrs				break;
3486163953Srrs			}
3487163953Srrs			if (stcb->asoc.peer_supports_strreset == 0) {
3488163953Srrs				/*
3489163953Srrs				 * Peer does not support it, we return
3490163953Srrs				 * protocol not supported since this is true
3491163953Srrs				 * for this feature and this peer, not the
3492163953Srrs				 * socket request in general.
3493163953Srrs				 */
3494171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPROTONOSUPPORT);
3495163953Srrs				error = EPROTONOSUPPORT;
3496163953Srrs				SCTP_TCB_UNLOCK(stcb);
3497163953Srrs				break;
3498163953Srrs			}
3499163953Srrs			if (stcb->asoc.stream_reset_outstanding) {
3500171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
3501163953Srrs				error = EALREADY;
3502163953Srrs				SCTP_TCB_UNLOCK(stcb);
3503163953Srrs				break;
3504163953Srrs			}
3505163953Srrs			if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) {
3506163953Srrs				send_in = 1;
3507163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) {
3508163953Srrs				send_out = 1;
3509163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_BOTH) {
3510163953Srrs				send_in = 1;
3511163953Srrs				send_out = 1;
3512163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_TSN) {
3513163953Srrs				send_tsn = 1;
3514188854Srrs			} else if (strrst->strrst_flags == SCTP_RESET_ADD_STREAMS) {
3515188854Srrs				if (send_tsn ||
3516188854Srrs				    send_in ||
3517188854Srrs				    send_out) {
3518188854Srrs					/* We can't do that and add streams */
3519188854Srrs					error = EINVAL;
3520188854Srrs					goto skip_stuff;
3521188854Srrs				}
3522188854Srrs				if (stcb->asoc.stream_reset_outstanding) {
3523188854Srrs					error = EBUSY;
3524188854Srrs					goto skip_stuff;
3525188854Srrs				}
3526188854Srrs				addstream = 1;
3527188854Srrs				/* We allocate here */
3528188854Srrs				addstrmcnt = strrst->strrst_num_streams;
3529188854Srrs				if ((int)(addstrmcnt + stcb->asoc.streamoutcnt) > 0xffff) {
3530188854Srrs					/* You can't have more than 64k */
3531188854Srrs					error = EINVAL;
3532188854Srrs					goto skip_stuff;
3533188854Srrs				}
3534188854Srrs				if ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < addstrmcnt) {
3535188854Srrs					/* Need to allocate more */
3536188854Srrs					struct sctp_stream_out *oldstream;
3537216822Stuexen					struct sctp_stream_queue_pending *sp,
3538216822Stuexen					                         *nsp;
3539188854Srrs
3540188854Srrs					oldstream = stcb->asoc.strmout;
3541188854Srrs					/* get some more */
3542188854Srrs					SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *,
3543188854Srrs					    ((stcb->asoc.streamoutcnt + addstrmcnt) * sizeof(struct sctp_stream_out)),
3544188854Srrs					    SCTP_M_STRMO);
3545188854Srrs					if (stcb->asoc.strmout == NULL) {
3546188854Srrs						stcb->asoc.strmout = oldstream;
3547188854Srrs						error = ENOMEM;
3548188854Srrs						goto skip_stuff;
3549188854Srrs					}
3550188854Srrs					/*
3551188854Srrs					 * Ok now we proceed with copying
3552188854Srrs					 * the old out stuff and
3553188854Srrs					 * initializing the new stuff.
3554188854Srrs					 */
3555189121Srrs					SCTP_TCB_SEND_LOCK(stcb);
3556217760Stuexen					stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 0, 1);
3557189121Srrs					for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
3558189121Srrs						TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
3559189121Srrs						stcb->asoc.strmout[i].next_sequence_sent = oldstream[i].next_sequence_sent;
3560189121Srrs						stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
3561189121Srrs						stcb->asoc.strmout[i].stream_no = i;
3562218241Stuexen						stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
3563189121Srrs						/*
3564189121Srrs						 * now anything on those
3565189121Srrs						 * queues?
3566189121Srrs						 */
3567216822Stuexen						TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) {
3568189121Srrs							TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
3569189121Srrs							TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
3570189121Srrs						}
3571189121Srrs						/*
3572189121Srrs						 * Now move assoc pointers
3573189121Srrs						 * too
3574189121Srrs						 */
3575189121Srrs						if (stcb->asoc.last_out_stream == &oldstream[i]) {
3576189121Srrs							stcb->asoc.last_out_stream = &stcb->asoc.strmout[i];
3577189121Srrs						}
3578189121Srrs						if (stcb->asoc.locked_on_sending == &oldstream[i]) {
3579189121Srrs							stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i];
3580189121Srrs						}
3581189121Srrs					}
3582188854Srrs					/* now the new streams */
3583217760Stuexen					stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
3584188854Srrs					for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + addstrmcnt); i++) {
3585188854Srrs						stcb->asoc.strmout[i].next_sequence_sent = 0x0;
3586188854Srrs						TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
3587188854Srrs						stcb->asoc.strmout[i].stream_no = i;
3588188854Srrs						stcb->asoc.strmout[i].last_msg_incomplete = 0;
3589218241Stuexen						stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
3590188854Srrs					}
3591188854Srrs					stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt;
3592188854Srrs					SCTP_FREE(oldstream, SCTP_M_STRMO);
3593188854Srrs				}
3594189121Srrs				SCTP_TCB_SEND_UNLOCK(stcb);
3595188854Srrs				goto skip_stuff;
3596163953Srrs			} else {
3597171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3598163953Srrs				error = EINVAL;
3599163953Srrs				SCTP_TCB_UNLOCK(stcb);
3600163953Srrs				break;
3601163953Srrs			}
3602163953Srrs			for (i = 0; i < strrst->strrst_num_streams; i++) {
3603163953Srrs				if ((send_in) &&
3604163953Srrs
3605163953Srrs				    (strrst->strrst_list[i] > stcb->asoc.streamincnt)) {
3606171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3607163953Srrs					error = EINVAL;
3608163953Srrs					goto get_out;
3609163953Srrs				}
3610163953Srrs				if ((send_out) &&
3611163953Srrs				    (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) {
3612171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3613163953Srrs					error = EINVAL;
3614163953Srrs					goto get_out;
3615163953Srrs				}
3616163953Srrs			}
3617188854Srrs	skip_stuff:
3618163953Srrs			if (error) {
3619163953Srrs		get_out:
3620163953Srrs				SCTP_TCB_UNLOCK(stcb);
3621163953Srrs				break;
3622163953Srrs			}
3623163953Srrs			error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams,
3624163953Srrs			    strrst->strrst_list,
3625163953Srrs			    send_out, (stcb->asoc.str_reset_seq_in - 3),
3626188854Srrs			    send_in, send_tsn, addstream, addstrmcnt);
3627163953Srrs
3628172090Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
3629163953Srrs			SCTP_TCB_UNLOCK(stcb);
3630163953Srrs		}
3631163953Srrs		break;
3632166675Srrs
3633163953Srrs	case SCTP_CONNECT_X:
3634166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
3635171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3636163953Srrs			error = EINVAL;
3637163953Srrs			break;
3638163953Srrs		}
3639166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
3640163953Srrs		break;
3641163953Srrs
3642163953Srrs	case SCTP_CONNECT_X_DELAYED:
3643166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
3644171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3645163953Srrs			error = EINVAL;
3646163953Srrs			break;
3647163953Srrs		}
3648166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
3649163953Srrs		break;
3650163953Srrs
3651163953Srrs	case SCTP_CONNECT_X_COMPLETE:
3652163953Srrs		{
3653163953Srrs			struct sockaddr *sa;
3654163953Srrs			struct sctp_nets *net;
3655163953Srrs
3656166675Srrs			/* FIXME MT: check correct? */
3657166675Srrs			SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
3658166675Srrs
3659163953Srrs			/* find tcb */
3660163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3661163953Srrs				SCTP_INP_RLOCK(inp);
3662163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
3663163953Srrs				if (stcb) {
3664163953Srrs					SCTP_TCB_LOCK(stcb);
3665163953Srrs					net = sctp_findnet(stcb, sa);
3666163953Srrs				}
3667163953Srrs				SCTP_INP_RUNLOCK(inp);
3668163953Srrs			} else {
3669166675Srrs				/*
3670166675Srrs				 * We increment here since
3671166675Srrs				 * sctp_findassociation_ep_addr() wil do a
3672166675Srrs				 * decrement if it finds the stcb as long as
3673166675Srrs				 * the locked tcb (last argument) is NOT a
3674166675Srrs				 * TCB.. aka NULL.
3675166675Srrs				 */
3676163953Srrs				SCTP_INP_INCR_REF(inp);
3677163953Srrs				stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL);
3678163953Srrs				if (stcb == NULL) {
3679163953Srrs					SCTP_INP_DECR_REF(inp);
3680163953Srrs				}
3681163953Srrs			}
3682163953Srrs
3683163953Srrs			if (stcb == NULL) {
3684171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
3685163953Srrs				error = ENOENT;
3686163953Srrs				break;
3687163953Srrs			}
3688163953Srrs			if (stcb->asoc.delayed_connection == 1) {
3689163953Srrs				stcb->asoc.delayed_connection = 0;
3690169378Srrs				(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
3691165220Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
3692165220Srrs				    stcb->asoc.primary_destination,
3693165220Srrs				    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
3694172090Srrs				sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
3695163953Srrs			} else {
3696163953Srrs				/*
3697163953Srrs				 * already expired or did not use delayed
3698163953Srrs				 * connectx
3699163953Srrs				 */
3700171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
3701163953Srrs				error = EALREADY;
3702163953Srrs			}
3703163953Srrs			SCTP_TCB_UNLOCK(stcb);
3704163953Srrs		}
3705163953Srrs		break;
3706170056Srrs	case SCTP_MAX_BURST:
3707163953Srrs		{
3708217895Stuexen			struct sctp_assoc_value *av;
3709163953Srrs
3710217895Stuexen			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3711217895Stuexen			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3712166675Srrs
3713217895Stuexen			if (stcb) {
3714217895Stuexen				stcb->asoc.max_burst = av->assoc_value;
3715217895Stuexen				SCTP_TCB_UNLOCK(stcb);
3716217895Stuexen			} else {
3717217895Stuexen				SCTP_INP_WLOCK(inp);
3718217895Stuexen				inp->sctp_ep.max_burst = av->assoc_value;
3719217895Stuexen				SCTP_INP_WUNLOCK(inp);
3720217895Stuexen			}
3721163953Srrs		}
3722163953Srrs		break;
3723163953Srrs	case SCTP_MAXSEG:
3724163953Srrs		{
3725167598Srrs			struct sctp_assoc_value *av;
3726163953Srrs			int ovh;
3727163953Srrs
3728167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
3729167598Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
3730166675Srrs
3731170056Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3732170056Srrs				ovh = SCTP_MED_OVERHEAD;
3733170056Srrs			} else {
3734170056Srrs				ovh = SCTP_MED_V4_OVERHEAD;
3735170056Srrs			}
3736167598Srrs			if (stcb) {
3737170056Srrs				if (av->assoc_value) {
3738170056Srrs					stcb->asoc.sctp_frag_point = (av->assoc_value + ovh);
3739170056Srrs				} else {
3740170056Srrs					stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
3741170056Srrs				}
3742167598Srrs				SCTP_TCB_UNLOCK(stcb);
3743163953Srrs			} else {
3744167598Srrs				SCTP_INP_WLOCK(inp);
3745167598Srrs				/*
3746167598Srrs				 * FIXME MT: I think this is not in tune
3747167598Srrs				 * with the API ID
3748167598Srrs				 */
3749167598Srrs				if (av->assoc_value) {
3750167598Srrs					inp->sctp_frag_point = (av->assoc_value + ovh);
3751167598Srrs				} else {
3752170056Srrs					inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
3753167598Srrs				}
3754167598Srrs				SCTP_INP_WUNLOCK(inp);
3755163953Srrs			}
3756163953Srrs		}
3757163953Srrs		break;
3758163953Srrs	case SCTP_EVENTS:
3759163953Srrs		{
3760163953Srrs			struct sctp_event_subscribe *events;
3761163953Srrs
3762166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
3763166675Srrs
3764163953Srrs			SCTP_INP_WLOCK(inp);
3765163953Srrs			if (events->sctp_data_io_event) {
3766163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
3767163953Srrs			} else {
3768163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
3769163953Srrs			}
3770163953Srrs
3771163953Srrs			if (events->sctp_association_event) {
3772163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
3773163953Srrs			} else {
3774163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
3775163953Srrs			}
3776163953Srrs
3777163953Srrs			if (events->sctp_address_event) {
3778163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
3779163953Srrs			} else {
3780163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
3781163953Srrs			}
3782163953Srrs
3783163953Srrs			if (events->sctp_send_failure_event) {
3784163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
3785163953Srrs			} else {
3786163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
3787163953Srrs			}
3788163953Srrs
3789163953Srrs			if (events->sctp_peer_error_event) {
3790163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
3791163953Srrs			} else {
3792163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
3793163953Srrs			}
3794163953Srrs
3795163953Srrs			if (events->sctp_shutdown_event) {
3796163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
3797163953Srrs			} else {
3798163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
3799163953Srrs			}
3800163953Srrs
3801163953Srrs			if (events->sctp_partial_delivery_event) {
3802163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
3803163953Srrs			} else {
3804163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
3805163953Srrs			}
3806163953Srrs
3807163953Srrs			if (events->sctp_adaptation_layer_event) {
3808163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
3809163953Srrs			} else {
3810163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
3811163953Srrs			}
3812163953Srrs
3813163953Srrs			if (events->sctp_authentication_event) {
3814163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
3815163953Srrs			} else {
3816163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
3817163953Srrs			}
3818163953Srrs
3819185694Srrs			if (events->sctp_sender_dry_event) {
3820185694Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
3821188067Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
3822188067Srrs				    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
3823188067Srrs					stcb = LIST_FIRST(&inp->sctp_asoc_list);
3824188067Srrs					if (stcb) {
3825188067Srrs						SCTP_TCB_LOCK(stcb);
3826188067Srrs					}
3827188067Srrs					if (stcb &&
3828188067Srrs					    TAILQ_EMPTY(&stcb->asoc.send_queue) &&
3829188067Srrs					    TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
3830188067Srrs					    (stcb->asoc.stream_queue_cnt == 0)) {
3831188067Srrs						sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
3832188067Srrs					}
3833188067Srrs					if (stcb) {
3834188067Srrs						SCTP_TCB_UNLOCK(stcb);
3835188067Srrs					}
3836188067Srrs				}
3837185694Srrs			} else {
3838185694Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
3839185694Srrs			}
3840185694Srrs
3841202520Srrs			if (events->sctp_stream_reset_event) {
3842163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
3843163953Srrs			} else {
3844163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
3845163953Srrs			}
3846163953Srrs			SCTP_INP_WUNLOCK(inp);
3847163953Srrs		}
3848163953Srrs		break;
3849163953Srrs
3850163953Srrs	case SCTP_ADAPTATION_LAYER:
3851163953Srrs		{
3852163953Srrs			struct sctp_setadaptation *adap_bits;
3853163953Srrs
3854166675Srrs			SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
3855163953Srrs			SCTP_INP_WLOCK(inp);
3856163953Srrs			inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
3857163953Srrs			SCTP_INP_WUNLOCK(inp);
3858163953Srrs		}
3859163953Srrs		break;
3860166675Srrs#ifdef SCTP_DEBUG
3861163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
3862163953Srrs		{
3863163953Srrs			uint32_t *vvv;
3864163953Srrs
3865166675Srrs			SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
3866163953Srrs			SCTP_INP_WLOCK(inp);
3867163953Srrs			inp->sctp_ep.initial_sequence_debug = *vvv;
3868163953Srrs			SCTP_INP_WUNLOCK(inp);
3869163953Srrs		}
3870163953Srrs		break;
3871166675Srrs#endif
3872163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
3873163953Srrs		{
3874163953Srrs			struct sctp_sndrcvinfo *s_info;
3875163953Srrs
3876166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
3877166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
3878163953Srrs
3879166675Srrs			if (stcb) {
3880166675Srrs				if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) {
3881170056Srrs					memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
3882163953Srrs				} else {
3883171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3884166675Srrs					error = EINVAL;
3885163953Srrs				}
3886166675Srrs				SCTP_TCB_UNLOCK(stcb);
3887166675Srrs			} else {
3888166675Srrs				SCTP_INP_WLOCK(inp);
3889170056Srrs				memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
3890166675Srrs				SCTP_INP_WUNLOCK(inp);
3891163953Srrs			}
3892163953Srrs		}
3893163953Srrs		break;
3894163953Srrs	case SCTP_PEER_ADDR_PARAMS:
3895163953Srrs		/* Applys to the specific association */
3896163953Srrs		{
3897163953Srrs			struct sctp_paddrparams *paddrp;
3898163953Srrs			struct sctp_nets *net;
3899163953Srrs
3900166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
3901166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
3902163953Srrs			net = NULL;
3903166675Srrs			if (stcb) {
3904166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
3905166675Srrs			} else {
3906166675Srrs				/*
3907166675Srrs				 * We increment here since
3908166675Srrs				 * sctp_findassociation_ep_addr() wil do a
3909166675Srrs				 * decrement if it finds the stcb as long as
3910166675Srrs				 * the locked tcb (last argument) is NOT a
3911166675Srrs				 * TCB.. aka NULL.
3912166675Srrs				 */
3913166675Srrs				SCTP_INP_INCR_REF(inp);
3914166675Srrs				stcb = sctp_findassociation_ep_addr(&inp,
3915166675Srrs				    (struct sockaddr *)&paddrp->spp_address,
3916166675Srrs				    &net, NULL, NULL);
3917163953Srrs				if (stcb == NULL) {
3918166675Srrs					SCTP_INP_DECR_REF(inp);
3919163953Srrs				}
3920163953Srrs			}
3921171943Srrs			if (stcb && (net == NULL)) {
3922171943Srrs				struct sockaddr *sa;
3923171943Srrs
3924171943Srrs				sa = (struct sockaddr *)&paddrp->spp_address;
3925221249Stuexen#ifdef INET
3926171943Srrs				if (sa->sa_family == AF_INET) {
3927221249Stuexen
3928171943Srrs					struct sockaddr_in *sin;
3929171943Srrs
3930171943Srrs					sin = (struct sockaddr_in *)sa;
3931171943Srrs					if (sin->sin_addr.s_addr) {
3932171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3933171943Srrs						SCTP_TCB_UNLOCK(stcb);
3934171943Srrs						error = EINVAL;
3935171943Srrs						break;
3936171943Srrs					}
3937221249Stuexen				} else
3938221249Stuexen#endif
3939221249Stuexen#ifdef INET6
3940221249Stuexen				if (sa->sa_family == AF_INET6) {
3941171943Srrs					struct sockaddr_in6 *sin6;
3942171943Srrs
3943171943Srrs					sin6 = (struct sockaddr_in6 *)sa;
3944171943Srrs					if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
3945171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3946171943Srrs						SCTP_TCB_UNLOCK(stcb);
3947171943Srrs						error = EINVAL;
3948171943Srrs						break;
3949171943Srrs					}
3950221249Stuexen				} else
3951221249Stuexen#endif
3952221249Stuexen				{
3953171943Srrs					error = EAFNOSUPPORT;
3954171943Srrs					SCTP_TCB_UNLOCK(stcb);
3955171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
3956171943Srrs					break;
3957171943Srrs				}
3958171943Srrs			}
3959170056Srrs			/* sanity checks */
3960170056Srrs			if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
3961170056Srrs				if (stcb)
3962170056Srrs					SCTP_TCB_UNLOCK(stcb);
3963171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3964170056Srrs				return (EINVAL);
3965170056Srrs			}
3966170056Srrs			if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
3967170056Srrs				if (stcb)
3968170056Srrs					SCTP_TCB_UNLOCK(stcb);
3969171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3970170056Srrs				return (EINVAL);
3971170056Srrs			}
3972163953Srrs			if (stcb) {
3973163953Srrs				/************************TCB SPECIFIC SET ******************/
3974163953Srrs				/*
3975163953Srrs				 * do we change the timer for HB, we run
3976163953Srrs				 * only one?
3977163953Srrs				 */
3978170056Srrs				int ovh = 0;
3979170056Srrs
3980170056Srrs				if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
3981170056Srrs					ovh = SCTP_MED_OVERHEAD;
3982170056Srrs				} else {
3983170056Srrs					ovh = SCTP_MED_V4_OVERHEAD;
3984170056Srrs				}
3985170056Srrs
3986163953Srrs				if (paddrp->spp_hbinterval)
3987163953Srrs					stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
3988163953Srrs				else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
3989163953Srrs					stcb->asoc.heart_beat_delay = 0;
3990163953Srrs
3991163953Srrs				/* network sets ? */
3992163953Srrs				if (net) {
3993163953Srrs					/************************NET SPECIFIC SET ******************/
3994163953Srrs					if (paddrp->spp_flags & SPP_HB_DEMAND) {
3995163953Srrs						/* on demand HB */
3996171440Srrs						if (sctp_send_hb(stcb, 1, net) < 0) {
3997171440Srrs							/* asoc destroyed */
3998171943Srrs							SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
3999171440Srrs							error = EINVAL;
4000171440Srrs							break;
4001171440Srrs						}
4002163953Srrs					}
4003163953Srrs					if (paddrp->spp_flags & SPP_HB_DISABLE) {
4004163953Srrs						net->dest_state |= SCTP_ADDR_NOHB;
4005163953Srrs					}
4006163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
4007163953Srrs						net->dest_state &= ~SCTP_ADDR_NOHB;
4008163953Srrs					}
4009170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
4010165647Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
4011165220Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
4012165220Srrs							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
4013163953Srrs						}
4014163953Srrs						if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
4015170056Srrs							net->mtu = paddrp->spp_pathmtu + ovh;
4016169352Srrs							if (net->mtu < stcb->asoc.smallest_mtu) {
4017167695Srrs								sctp_pathmtu_adjustment(inp, stcb, net, net->mtu);
4018169352Srrs							}
4019163953Srrs						}
4020163953Srrs					}
4021163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
4022165647Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
4023163953Srrs							sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
4024163953Srrs						}
4025163953Srrs					}
4026163953Srrs					if (paddrp->spp_pathmaxrxt)
4027163953Srrs						net->failure_threshold = paddrp->spp_pathmaxrxt;
4028167598Srrs#ifdef INET
4029163953Srrs					if (paddrp->spp_flags & SPP_IPV4_TOS) {
4030163953Srrs						if (net->ro._l_addr.sin.sin_family == AF_INET) {
4031163953Srrs							net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc;
4032163953Srrs						}
4033163953Srrs					}
4034163953Srrs#endif
4035167598Srrs#ifdef INET6
4036163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
4037163953Srrs						if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
4038163953Srrs							net->tos_flowlabel = paddrp->spp_ipv6_flowlabel;
4039163953Srrs						}
4040163953Srrs					}
4041163953Srrs#endif
4042163953Srrs				} else {
4043163953Srrs					/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
4044163953Srrs					if (paddrp->spp_pathmaxrxt)
4045163953Srrs						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
4046163953Srrs
4047163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
4048163953Srrs						/* Turn back on the timer */
4049163953Srrs						stcb->asoc.hb_is_disabled = 0;
4050163953Srrs						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
4051163953Srrs					}
4052170056Srrs					if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) {
4053170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4054170056Srrs							if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
4055170056Srrs								sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
4056170056Srrs								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
4057170056Srrs							}
4058170056Srrs							if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
4059170056Srrs								net->mtu = paddrp->spp_pathmtu + ovh;
4060170056Srrs								if (net->mtu < stcb->asoc.smallest_mtu) {
4061170056Srrs									sctp_pathmtu_adjustment(inp, stcb, net, net->mtu);
4062170056Srrs								}
4063170056Srrs							}
4064170056Srrs						}
4065170056Srrs					}
4066170056Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
4067170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4068170056Srrs							if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
4069170056Srrs								sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
4070170056Srrs							}
4071170056Srrs						}
4072170056Srrs					}
4073163953Srrs					if (paddrp->spp_flags & SPP_HB_DISABLE) {
4074163953Srrs						int cnt_of_unconf = 0;
4075163953Srrs						struct sctp_nets *lnet;
4076163953Srrs
4077163953Srrs						stcb->asoc.hb_is_disabled = 1;
4078163953Srrs						TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
4079163953Srrs							if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
4080163953Srrs								cnt_of_unconf++;
4081163953Srrs							}
4082163953Srrs						}
4083163953Srrs						/*
4084163953Srrs						 * stop the timer ONLY if we
4085163953Srrs						 * have no unconfirmed
4086163953Srrs						 * addresses
4087163953Srrs						 */
4088163953Srrs						if (cnt_of_unconf == 0) {
4089170056Srrs							TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4090170056Srrs								sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
4091170056Srrs								    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
4092170056Srrs							}
4093163953Srrs						}
4094163953Srrs					}
4095163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
4096163953Srrs						/* start up the timer. */
4097170056Srrs						TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
4098170056Srrs							sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
4099170056Srrs						}
4100163953Srrs					}
4101167598Srrs#ifdef INET
4102163953Srrs					if (paddrp->spp_flags & SPP_IPV4_TOS)
4103163953Srrs						stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc;
4104163953Srrs#endif
4105167598Srrs#ifdef INET6
4106163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL)
4107163953Srrs						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel;
4108163953Srrs#endif
4109163953Srrs
4110163953Srrs				}
4111163953Srrs				SCTP_TCB_UNLOCK(stcb);
4112163953Srrs			} else {
4113163953Srrs				/************************NO TCB, SET TO default stuff ******************/
4114163953Srrs				SCTP_INP_WLOCK(inp);
4115163953Srrs				/*
4116163953Srrs				 * For the TOS/FLOWLABEL stuff you set it
4117163953Srrs				 * with the options on the socket
4118163953Srrs				 */
4119163953Srrs				if (paddrp->spp_pathmaxrxt) {
4120163953Srrs					inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
4121163953Srrs				}
4122170056Srrs				if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
4123170056Srrs					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
4124171477Srrs				else if (paddrp->spp_hbinterval) {
4125171477Srrs					if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
4126171477Srrs						paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL;
4127170056Srrs					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
4128171477Srrs				}
4129163953Srrs				if (paddrp->spp_flags & SPP_HB_ENABLE) {
4130163953Srrs					sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
4131170056Srrs
4132163953Srrs				} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
4133163953Srrs					sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
4134163953Srrs				}
4135163953Srrs				SCTP_INP_WUNLOCK(inp);
4136163953Srrs			}
4137163953Srrs		}
4138163953Srrs		break;
4139163953Srrs	case SCTP_RTOINFO:
4140163953Srrs		{
4141163953Srrs			struct sctp_rtoinfo *srto;
4142169655Srrs			uint32_t new_init, new_min, new_max;
4143163953Srrs
4144166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
4145166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
4146166675Srrs
4147166675Srrs			if (stcb) {
4148167598Srrs				if (srto->srto_initial)
4149169655Srrs					new_init = srto->srto_initial;
4150169655Srrs				else
4151169655Srrs					new_init = stcb->asoc.initial_rto;
4152167598Srrs				if (srto->srto_max)
4153169655Srrs					new_max = srto->srto_max;
4154169655Srrs				else
4155169655Srrs					new_max = stcb->asoc.maxrto;
4156167598Srrs				if (srto->srto_min)
4157169655Srrs					new_min = srto->srto_min;
4158169655Srrs				else
4159169655Srrs					new_min = stcb->asoc.minrto;
4160169655Srrs				if ((new_min <= new_init) && (new_init <= new_max)) {
4161169655Srrs					stcb->asoc.initial_rto = new_init;
4162169655Srrs					stcb->asoc.maxrto = new_max;
4163169655Srrs					stcb->asoc.minrto = new_min;
4164169655Srrs				} else {
4165179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4166179783Srrs					error = EINVAL;
4167169655Srrs				}
4168166675Srrs				SCTP_TCB_UNLOCK(stcb);
4169166675Srrs			} else {
4170163953Srrs				SCTP_INP_WLOCK(inp);
4171167598Srrs				if (srto->srto_initial)
4172169655Srrs					new_init = srto->srto_initial;
4173169655Srrs				else
4174169655Srrs					new_init = inp->sctp_ep.initial_rto;
4175167598Srrs				if (srto->srto_max)
4176169655Srrs					new_max = srto->srto_max;
4177169655Srrs				else
4178169655Srrs					new_max = inp->sctp_ep.sctp_maxrto;
4179167598Srrs				if (srto->srto_min)
4180169655Srrs					new_min = srto->srto_min;
4181169655Srrs				else
4182169655Srrs					new_min = inp->sctp_ep.sctp_minrto;
4183169655Srrs				if ((new_min <= new_init) && (new_init <= new_max)) {
4184169655Srrs					inp->sctp_ep.initial_rto = new_init;
4185169655Srrs					inp->sctp_ep.sctp_maxrto = new_max;
4186169655Srrs					inp->sctp_ep.sctp_minrto = new_min;
4187169655Srrs				} else {
4188179783Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4189179783Srrs					error = EINVAL;
4190169655Srrs				}
4191163953Srrs				SCTP_INP_WUNLOCK(inp);
4192163953Srrs			}
4193163953Srrs		}
4194163953Srrs		break;
4195163953Srrs	case SCTP_ASSOCINFO:
4196163953Srrs		{
4197163953Srrs			struct sctp_assocparams *sasoc;
4198163953Srrs
4199166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
4200166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
4201171477Srrs			if (sasoc->sasoc_cookie_life) {
4202171477Srrs				/* boundary check the cookie life */
4203171477Srrs				if (sasoc->sasoc_cookie_life < 1000)
4204171477Srrs					sasoc->sasoc_cookie_life = 1000;
4205171477Srrs				if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
4206171477Srrs					sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
4207171477Srrs				}
4208171477Srrs			}
4209163953Srrs			if (stcb) {
4210163953Srrs				if (sasoc->sasoc_asocmaxrxt)
4211163953Srrs					stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
4212163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
4213163953Srrs				sasoc->sasoc_peer_rwnd = 0;
4214163953Srrs				sasoc->sasoc_local_rwnd = 0;
4215170056Srrs				if (sasoc->sasoc_cookie_life) {
4216171572Srrs					stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
4217167598Srrs				}
4218163953Srrs				SCTP_TCB_UNLOCK(stcb);
4219163953Srrs			} else {
4220163953Srrs				SCTP_INP_WLOCK(inp);
4221163953Srrs				if (sasoc->sasoc_asocmaxrxt)
4222163953Srrs					inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
4223163953Srrs				sasoc->sasoc_number_peer_destinations = 0;
4224163953Srrs				sasoc->sasoc_peer_rwnd = 0;
4225163953Srrs				sasoc->sasoc_local_rwnd = 0;
4226170056Srrs				if (sasoc->sasoc_cookie_life) {
4227169655Srrs					inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
4228167598Srrs				}
4229163953Srrs				SCTP_INP_WUNLOCK(inp);
4230163953Srrs			}
4231163953Srrs		}
4232163953Srrs		break;
4233163953Srrs	case SCTP_INITMSG:
4234163953Srrs		{
4235163953Srrs			struct sctp_initmsg *sinit;
4236163953Srrs
4237166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
4238163953Srrs			SCTP_INP_WLOCK(inp);
4239163953Srrs			if (sinit->sinit_num_ostreams)
4240163953Srrs				inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
4241163953Srrs
4242163953Srrs			if (sinit->sinit_max_instreams)
4243163953Srrs				inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
4244163953Srrs
4245163953Srrs			if (sinit->sinit_max_attempts)
4246163953Srrs				inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
4247163953Srrs
4248167598Srrs			if (sinit->sinit_max_init_timeo)
4249163953Srrs				inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
4250163953Srrs			SCTP_INP_WUNLOCK(inp);
4251163953Srrs		}
4252163953Srrs		break;
4253163953Srrs	case SCTP_PRIMARY_ADDR:
4254163953Srrs		{
4255163953Srrs			struct sctp_setprim *spa;
4256163953Srrs			struct sctp_nets *net, *lnet;
4257163953Srrs
4258166675Srrs			SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
4259166675Srrs			SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
4260163953Srrs
4261166675Srrs			net = NULL;
4262166675Srrs			if (stcb) {
4263166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
4264166675Srrs			} else {
4265166675Srrs				/*
4266166675Srrs				 * We increment here since
4267166675Srrs				 * sctp_findassociation_ep_addr() wil do a
4268166675Srrs				 * decrement if it finds the stcb as long as
4269166675Srrs				 * the locked tcb (last argument) is NOT a
4270166675Srrs				 * TCB.. aka NULL.
4271166675Srrs				 */
4272163953Srrs				SCTP_INP_INCR_REF(inp);
4273163953Srrs				stcb = sctp_findassociation_ep_addr(&inp,
4274163953Srrs				    (struct sockaddr *)&spa->ssp_addr,
4275163953Srrs				    &net, NULL, NULL);
4276163953Srrs				if (stcb == NULL) {
4277163953Srrs					SCTP_INP_DECR_REF(inp);
4278163953Srrs				}
4279163953Srrs			}
4280166675Srrs
4281166675Srrs			if ((stcb) && (net)) {
4282166675Srrs				if ((net != stcb->asoc.primary_destination) &&
4283166675Srrs				    (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
4284166675Srrs					/* Ok we need to set it */
4285166675Srrs					lnet = stcb->asoc.primary_destination;
4286166675Srrs					if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
4287166675Srrs						if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
4288166675Srrs							net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
4289166675Srrs						}
4290166675Srrs						net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY;
4291163953Srrs					}
4292163953Srrs				}
4293166675Srrs			} else {
4294171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4295166675Srrs				error = EINVAL;
4296163953Srrs			}
4297166675Srrs			if (stcb) {
4298166675Srrs				SCTP_TCB_UNLOCK(stcb);
4299166675Srrs			}
4300163953Srrs		}
4301163953Srrs		break;
4302167598Srrs	case SCTP_SET_DYNAMIC_PRIMARY:
4303167598Srrs		{
4304167598Srrs			union sctp_sockstore *ss;
4305163953Srrs
4306170587Srwatson			error = priv_check(curthread,
4307170587Srwatson			    PRIV_NETINET_RESERVEDPORT);
4308167598Srrs			if (error)
4309167598Srrs				break;
4310167598Srrs
4311167598Srrs			SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
4312167598Srrs			/* SUPER USER CHECK? */
4313167598Srrs			error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
4314167598Srrs		}
4315167598Srrs		break;
4316163953Srrs	case SCTP_SET_PEER_PRIMARY_ADDR:
4317163953Srrs		{
4318163953Srrs			struct sctp_setpeerprim *sspp;
4319163953Srrs
4320166675Srrs			SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
4321166675Srrs			SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
4322169208Srrs			if (stcb != NULL) {
4323170056Srrs				struct sctp_ifa *ifa;
4324170056Srrs
4325170056Srrs				ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
4326172091Srrs				    stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
4327170056Srrs				if (ifa == NULL) {
4328171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4329166675Srrs					error = EINVAL;
4330170056Srrs					goto out_of_it;
4331166675Srrs				}
4332170056Srrs				if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
4333170056Srrs					/*
4334170056Srrs					 * Must validate the ifa found is in
4335170056Srrs					 * our ep
4336170056Srrs					 */
4337170056Srrs					struct sctp_laddr *laddr;
4338170056Srrs					int found = 0;
4339170056Srrs
4340170056Srrs					LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
4341170056Srrs						if (laddr->ifa == NULL) {
4342170056Srrs							SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
4343170056Srrs							    __FUNCTION__);
4344170056Srrs							continue;
4345170056Srrs						}
4346170056Srrs						if (laddr->ifa == ifa) {
4347170056Srrs							found = 1;
4348170056Srrs							break;
4349170056Srrs						}
4350170056Srrs					}
4351170056Srrs					if (!found) {
4352171943Srrs						SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4353170056Srrs						error = EINVAL;
4354170056Srrs						goto out_of_it;
4355170056Srrs					}
4356170056Srrs				}
4357170056Srrs				if (sctp_set_primary_ip_address_sa(stcb,
4358170056Srrs				    (struct sockaddr *)&sspp->sspp_addr) != 0) {
4359171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4360170056Srrs					error = EINVAL;
4361170056Srrs				}
4362170056Srrs		out_of_it:
4363169208Srrs				SCTP_TCB_UNLOCK(stcb);
4364166675Srrs			} else {
4365171943Srrs				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4366163953Srrs				error = EINVAL;
4367163953Srrs			}
4368169208Srrs
4369163953Srrs		}
4370163953Srrs		break;
4371163953Srrs	case SCTP_BINDX_ADD_ADDR:
4372163953Srrs		{
4373163953Srrs			struct sctp_getaddresses *addrs;
4374171531Srrs			size_t sz;
4375171477Srrs			struct thread *td;
4376163953Srrs
4377171477Srrs			td = (struct thread *)p;
4378170606Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses,
4379170606Srrs			    optsize);
4380221249Stuexen#ifdef INET
4381171477Srrs			if (addrs->addr->sa_family == AF_INET) {
4382171477Srrs				sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in);
4383171477Srrs				if (optsize < sz) {
4384171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4385171477Srrs					error = EINVAL;
4386171477Srrs					break;
4387171477Srrs				}
4388188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
4389188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
4390185435Sbz					break;
4391171477Srrs				}
4392221249Stuexen			} else
4393221249Stuexen#endif
4394185435Sbz#ifdef INET6
4395221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
4396171477Srrs				sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
4397171477Srrs				if (optsize < sz) {
4398171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4399171477Srrs					error = EINVAL;
4400171477Srrs					break;
4401171477Srrs				}
4402188590Srrs				if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
4403188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
4404188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
4405185435Sbz					break;
4406185435Sbz				}
4407221249Stuexen			} else
4408185435Sbz#endif
4409221249Stuexen			{
4410185435Sbz				error = EAFNOSUPPORT;
4411185435Sbz				break;
4412171477Srrs			}
4413170606Srrs			sctp_bindx_add_address(so, inp, addrs->addr,
4414170606Srrs			    addrs->sget_assoc_id, vrf_id,
4415170606Srrs			    &error, p);
4416163953Srrs		}
4417163953Srrs		break;
4418163953Srrs	case SCTP_BINDX_REM_ADDR:
4419163953Srrs		{
4420163953Srrs			struct sctp_getaddresses *addrs;
4421171531Srrs			size_t sz;
4422171477Srrs			struct thread *td;
4423163953Srrs
4424171477Srrs			td = (struct thread *)p;
4425185435Sbz
4426166675Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
4427221249Stuexen#ifdef INET
4428171477Srrs			if (addrs->addr->sa_family == AF_INET) {
4429171477Srrs				sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in);
4430171477Srrs				if (optsize < sz) {
4431171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4432171477Srrs					error = EINVAL;
4433171477Srrs					break;
4434171477Srrs				}
4435188590Srrs				if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) {
4436188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
4437185435Sbz					break;
4438171477Srrs				}
4439221249Stuexen			} else
4440221249Stuexen#endif
4441185435Sbz#ifdef INET6
4442221249Stuexen			if (addrs->addr->sa_family == AF_INET6) {
4443171477Srrs				sz = sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6);
4444171477Srrs				if (optsize < sz) {
4445171943Srrs					SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4446171477Srrs					error = EINVAL;
4447171477Srrs					break;
4448171477Srrs				}
4449188590Srrs				if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr),
4450188590Srrs				    (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
4451188590Srrs					SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
4452185435Sbz					break;
4453185435Sbz				}
4454221249Stuexen			} else
4455185435Sbz#endif
4456221249Stuexen			{
4457185435Sbz				error = EAFNOSUPPORT;
4458185435Sbz				break;
4459171477Srrs			}
4460170606Srrs			sctp_bindx_delete_address(so, inp, addrs->addr,
4461170606Srrs			    addrs->sget_assoc_id, vrf_id,
4462170606Srrs			    &error);
4463163953Srrs		}
4464163953Srrs		break;
4465163953Srrs	default:
4466171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
4467163953Srrs		error = ENOPROTOOPT;
4468163953Srrs		break;
4469163953Srrs	}			/* end switch (opt) */
4470163953Srrs	return (error);
4471163953Srrs}
4472163953Srrs
4473163953Srrsint
4474163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt)
4475163953Srrs{
4476166675Srrs	void *optval = NULL;
4477166675Srrs	size_t optsize = 0;
4478163953Srrs	struct sctp_inpcb *inp;
4479166675Srrs	void *p;
4480166675Srrs	int error = 0;
4481163953Srrs
4482163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4483163953Srrs	if (inp == 0) {
4484163953Srrs		/* I made the same as TCP since we are not setup? */
4485171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4486163953Srrs		return (ECONNRESET);
4487163953Srrs	}
4488163953Srrs	if (sopt->sopt_level != IPPROTO_SCTP) {
4489163953Srrs		/* wrong proto level... send back up to IP */
4490163953Srrs#ifdef INET6
4491163953Srrs		if (INP_CHECK_SOCKAF(so, AF_INET6))
4492163953Srrs			error = ip6_ctloutput(so, sopt);
4493221249Stuexen#endif				/* INET6 */
4494221249Stuexen#if defined(INET) && defined (INET6)
4495163953Srrs		else
4496221249Stuexen#endif
4497221249Stuexen#ifdef INET
4498163953Srrs			error = ip_ctloutput(so, sopt);
4499221249Stuexen#endif
4500163953Srrs		return (error);
4501163953Srrs	}
4502166675Srrs	optsize = sopt->sopt_valsize;
4503166675Srrs	if (optsize) {
4504170091Srrs		SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
4505166675Srrs		if (optval == NULL) {
4506171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
4507163953Srrs			return (ENOBUFS);
4508163953Srrs		}
4509166675Srrs		error = sooptcopyin(sopt, optval, optsize, optsize);
4510163953Srrs		if (error) {
4511170091Srrs			SCTP_FREE(optval, SCTP_M_SOCKOPT);
4512163953Srrs			goto out;
4513163953Srrs		}
4514163953Srrs	}
4515166675Srrs	p = (void *)sopt->sopt_td;
4516163953Srrs	if (sopt->sopt_dir == SOPT_SET) {
4517166675Srrs		error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
4518163953Srrs	} else if (sopt->sopt_dir == SOPT_GET) {
4519166675Srrs		error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
4520163953Srrs	} else {
4521171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4522163953Srrs		error = EINVAL;
4523163953Srrs	}
4524166675Srrs	if ((error == 0) && (optval != NULL)) {
4525166675Srrs		error = sooptcopyout(sopt, optval, optsize);
4526170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
4527166675Srrs	} else if (optval != NULL) {
4528170091Srrs		SCTP_FREE(optval, SCTP_M_SOCKOPT);
4529163953Srrs	}
4530163953Srrsout:
4531163953Srrs	return (error);
4532163953Srrs}
4533163953Srrs
4534221249Stuexen#ifdef INET
4535163953Srrsstatic int
4536163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
4537163953Srrs{
4538163953Srrs	int error = 0;
4539163953Srrs	int create_lock_on = 0;
4540167598Srrs	uint32_t vrf_id;
4541163953Srrs	struct sctp_inpcb *inp;
4542163953Srrs	struct sctp_tcb *stcb = NULL;
4543163953Srrs
4544163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4545163953Srrs	if (inp == 0) {
4546163953Srrs		/* I made the same as TCP since we are not setup? */
4547171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4548163953Srrs		return (ECONNRESET);
4549163953Srrs	}
4550171943Srrs	if (addr == NULL) {
4551171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4552170056Srrs		return EINVAL;
4553171943Srrs	}
4554221249Stuexen	switch (addr->sa_family) {
4555185435Sbz#ifdef INET6
4556221249Stuexen	case AF_INET6:
4557221249Stuexen		{
4558221249Stuexen			struct sockaddr_in6 *sin6p;
4559185694Srrs
4560221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
4561221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4562221249Stuexen				return (EINVAL);
4563221249Stuexen			}
4564221249Stuexen			sin6p = (struct sockaddr_in6 *)addr;
4565221249Stuexen			if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) {
4566221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4567221249Stuexen				return (error);
4568221249Stuexen			}
4569221249Stuexen			break;
4570185435Sbz		}
4571185435Sbz#endif
4572221249Stuexen#ifdef INET
4573221249Stuexen	case AF_INET:
4574221249Stuexen		{
4575221249Stuexen			struct sockaddr_in *sinp;
4576185694Srrs
4577221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
4578221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4579221249Stuexen				return (EINVAL);
4580221249Stuexen			}
4581221249Stuexen			sinp = (struct sockaddr_in *)addr;
4582221249Stuexen			if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) {
4583221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
4584221249Stuexen				return (error);
4585221249Stuexen			}
4586221249Stuexen			break;
4587185435Sbz		}
4588221249Stuexen#endif
4589221249Stuexen	default:
4590185435Sbz		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
4591185435Sbz		return (EAFNOSUPPORT);
4592170056Srrs	}
4593178202Srrs	SCTP_INP_INCR_REF(inp);
4594163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
4595163953Srrs	create_lock_on = 1;
4596163953Srrs
4597178202Srrs
4598163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
4599163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
4600163953Srrs		/* Should I really unlock ? */
4601171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
4602163953Srrs		error = EFAULT;
4603163953Srrs		goto out_now;
4604163953Srrs	}
4605163953Srrs#ifdef INET6
4606163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
4607163953Srrs	    (addr->sa_family == AF_INET6)) {
4608171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4609163953Srrs		error = EINVAL;
4610163953Srrs		goto out_now;
4611163953Srrs	}
4612163953Srrs#endif				/* INET6 */
4613163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
4614163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
4615163953Srrs		/* Bind a ephemeral port */
4616171572Srrs		error = sctp_inpcb_bind(so, NULL, NULL, p);
4617163953Srrs		if (error) {
4618163953Srrs			goto out_now;
4619163953Srrs		}
4620163953Srrs	}
4621163953Srrs	/* Now do we connect? */
4622181054Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
4623181054Srrs	    (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
4624171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4625163953Srrs		error = EINVAL;
4626163953Srrs		goto out_now;
4627163953Srrs	}
4628163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
4629163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
4630163953Srrs		/* We are already connected AND the TCP model */
4631171943Srrs		SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
4632163953Srrs		error = EADDRINUSE;
4633163953Srrs		goto out_now;
4634163953Srrs	}
4635163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
4636163953Srrs		SCTP_INP_RLOCK(inp);
4637163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
4638163953Srrs		SCTP_INP_RUNLOCK(inp);
4639163953Srrs	} else {
4640163953Srrs		/*
4641166675Srrs		 * We increment here since sctp_findassociation_ep_addr()
4642181054Srrs		 * will do a decrement if it finds the stcb as long as the
4643166675Srrs		 * locked tcb (last argument) is NOT a TCB.. aka NULL.
4644163953Srrs		 */
4645163953Srrs		SCTP_INP_INCR_REF(inp);
4646163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
4647163953Srrs		if (stcb == NULL) {
4648163953Srrs			SCTP_INP_DECR_REF(inp);
4649168299Srrs		} else {
4650178202Srrs			SCTP_TCB_UNLOCK(stcb);
4651163953Srrs		}
4652163953Srrs	}
4653163953Srrs	if (stcb != NULL) {
4654163953Srrs		/* Already have or am bring up an association */
4655171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
4656163953Srrs		error = EALREADY;
4657163953Srrs		goto out_now;
4658163953Srrs	}
4659168299Srrs	vrf_id = inp->def_vrf_id;
4660163953Srrs	/* We are GOOD to go */
4661206137Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
4662163953Srrs	if (stcb == NULL) {
4663163953Srrs		/* Gak! no memory */
4664167598Srrs		goto out_now;
4665163953Srrs	}
4666163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
4667163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
4668163953Srrs		/* Set the connected flag so we can queue data */
4669204096Stuexen		SOCKBUF_LOCK(&so->so_rcv);
4670204096Stuexen		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
4671204096Stuexen		SOCKBUF_UNLOCK(&so->so_rcv);
4672204096Stuexen		SOCKBUF_LOCK(&so->so_snd);
4673204096Stuexen		so->so_snd.sb_state &= ~SBS_CANTSENDMORE;
4674204096Stuexen		SOCKBUF_UNLOCK(&so->so_snd);
4675204096Stuexen		SOCK_LOCK(so);
4676204096Stuexen		so->so_state &= ~SS_ISDISCONNECTING;
4677204096Stuexen		SOCK_UNLOCK(so);
4678163953Srrs		soisconnecting(so);
4679163953Srrs	}
4680171943Srrs	SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
4681169378Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
4682163953Srrs
4683163953Srrs	/* initialize authentication parameters for the assoc */
4684163953Srrs	sctp_initialize_auth_params(inp, stcb);
4685163953Srrs
4686172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
4687168299Srrs	SCTP_TCB_UNLOCK(stcb);
4688163953Srrsout_now:
4689169420Srrs	if (create_lock_on) {
4690163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
4691169420Srrs	}
4692163953Srrs	SCTP_INP_DECR_REF(inp);
4693163953Srrs	return error;
4694163953Srrs}
4695163953Srrs
4696221249Stuexen#endif
4697221249Stuexen
4698163953Srrsint
4699163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p)
4700163953Srrs{
4701163953Srrs	/*
4702163953Srrs	 * Note this module depends on the protocol processing being called
4703163953Srrs	 * AFTER any socket level flags and backlog are applied to the
4704163953Srrs	 * socket. The traditional way that the socket flags are applied is
4705163953Srrs	 * AFTER protocol processing. We have made a change to the
4706163953Srrs	 * sys/kern/uipc_socket.c module to reverse this but this MUST be in
4707163953Srrs	 * place if the socket API for SCTP is to work properly.
4708163953Srrs	 */
4709163953Srrs
4710163953Srrs	int error = 0;
4711163953Srrs	struct sctp_inpcb *inp;
4712163953Srrs
4713163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4714163953Srrs	if (inp == 0) {
4715163953Srrs		/* I made the same as TCP since we are not setup? */
4716171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4717163953Srrs		return (ECONNRESET);
4718163953Srrs	}
4719181054Srrs	if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
4720181054Srrs		/* See if we have a listener */
4721181054Srrs		struct sctp_inpcb *tinp;
4722181054Srrs		union sctp_sockstore store, *sp;
4723181054Srrs
4724181054Srrs		sp = &store;
4725181054Srrs		if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
4726181054Srrs			/* not bound all */
4727181054Srrs			struct sctp_laddr *laddr;
4728181054Srrs
4729181054Srrs			LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
4730181054Srrs				memcpy(&store, &laddr->ifa->address, sizeof(store));
4731221249Stuexen				switch (sp->sa.sa_family) {
4732221249Stuexen#ifdef INET
4733221249Stuexen				case AF_INET:
4734221249Stuexen					sp->sin.sin_port = inp->sctp_lport;
4735221249Stuexen					break;
4736221249Stuexen#endif
4737221249Stuexen#ifdef INET6
4738221249Stuexen				case AF_INET6:
4739221249Stuexen					sp->sin6.sin6_port = inp->sctp_lport;
4740221249Stuexen					break;
4741221249Stuexen#endif
4742221249Stuexen				default:
4743221249Stuexen					break;
4744221249Stuexen				}
4745181054Srrs				tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id);
4746181054Srrs				if (tinp && (tinp != inp) &&
4747181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
4748181054Srrs				    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
4749181054Srrs				    (tinp->sctp_socket->so_qlimit)) {
4750181054Srrs					/*
4751181054Srrs					 * we have a listener already and
4752181054Srrs					 * its not this inp.
4753181054Srrs					 */
4754181054Srrs					SCTP_INP_DECR_REF(tinp);
4755181054Srrs					return (EADDRINUSE);
4756181054Srrs				} else if (tinp) {
4757181054Srrs					SCTP_INP_DECR_REF(tinp);
4758181054Srrs				}
4759181054Srrs			}
4760181054Srrs		} else {
4761181054Srrs			/* Setup a local addr bound all */
4762181054Srrs			memset(&store, 0, sizeof(store));
4763221249Stuexen			switch (sp->sa.sa_family) {
4764221249Stuexen#ifdef INET
4765221249Stuexen			case AF_INET:
4766221249Stuexen				store.sin.sin_port = inp->sctp_lport;
4767221249Stuexen				break;
4768221249Stuexen#endif
4769181054Srrs#ifdef INET6
4770221249Stuexen			case AF_INET6:
4771221249Stuexen				sp->sin6.sin6_port = inp->sctp_lport;
4772221249Stuexen				break;
4773221249Stuexen#endif
4774221249Stuexen			default:
4775221249Stuexen				break;
4776221249Stuexen			}
4777221249Stuexen#ifdef INET6
4778181054Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
4779181054Srrs				store.sa.sa_family = AF_INET6;
4780181054Srrs				store.sa.sa_len = sizeof(struct sockaddr_in6);
4781181054Srrs			}
4782181054Srrs#endif
4783221249Stuexen#ifdef INET
4784181054Srrs			if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
4785181054Srrs				store.sa.sa_family = AF_INET;
4786181054Srrs				store.sa.sa_len = sizeof(struct sockaddr_in);
4787181054Srrs			}
4788221249Stuexen#endif
4789181054Srrs			tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id);
4790181054Srrs			if (tinp && (tinp != inp) &&
4791181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
4792181054Srrs			    ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
4793181054Srrs			    (tinp->sctp_socket->so_qlimit)) {
4794181054Srrs				/*
4795181054Srrs				 * we have a listener already and its not
4796181054Srrs				 * this inp.
4797181054Srrs				 */
4798181054Srrs				SCTP_INP_DECR_REF(tinp);
4799181054Srrs				return (EADDRINUSE);
4800181054Srrs			} else if (tinp) {
4801181054Srrs				SCTP_INP_DECR_REF(inp);
4802181054Srrs			}
4803181054Srrs		}
4804181054Srrs	}
4805163953Srrs	SCTP_INP_RLOCK(inp);
4806163953Srrs#ifdef SCTP_LOCK_LOGGING
4807179783Srrs	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
4808170744Srrs		sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
4809170744Srrs	}
4810163953Srrs#endif
4811163953Srrs	SOCK_LOCK(so);
4812163953Srrs	error = solisten_proto_check(so);
4813163953Srrs	if (error) {
4814163953Srrs		SOCK_UNLOCK(so);
4815169208Srrs		SCTP_INP_RUNLOCK(inp);
4816163953Srrs		return (error);
4817163953Srrs	}
4818181054Srrs	if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
4819181054Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
4820181054Srrs		/*
4821181054Srrs		 * The unlucky case - We are in the tcp pool with this guy.
4822181054Srrs		 * - Someone else is in the main inp slot. - We must move
4823181054Srrs		 * this guy (the listener) to the main slot - We must then
4824181054Srrs		 * move the guy that was listener to the TCP Pool.
4825181054Srrs		 */
4826181054Srrs		if (sctp_swap_inpcb_for_listen(inp)) {
4827181054Srrs			goto in_use;
4828181054Srrs		}
4829181054Srrs	}
4830163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
4831163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
4832163953Srrs		/* We are already connected AND the TCP model */
4833181054Srrsin_use:
4834163953Srrs		SCTP_INP_RUNLOCK(inp);
4835163953Srrs		SOCK_UNLOCK(so);
4836171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
4837163953Srrs		return (EADDRINUSE);
4838163953Srrs	}
4839181054Srrs	SCTP_INP_RUNLOCK(inp);
4840163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
4841163953Srrs		/* We must do a bind. */
4842166675Srrs		SOCK_UNLOCK(so);
4843171572Srrs		if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
4844163953Srrs			/* bind error, probably perm */
4845163953Srrs			return (error);
4846163953Srrs		}
4847166675Srrs		SOCK_LOCK(so);
4848163953Srrs	}
4849163953Srrs	/* It appears for 7.0 and on, we must always call this. */
4850163953Srrs	solisten_proto(so, backlog);
4851163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
4852163953Srrs		/* remove the ACCEPTCONN flag for one-to-many sockets */
4853163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
4854163953Srrs	}
4855163953Srrs	if (backlog == 0) {
4856163953Srrs		/* turning off listen */
4857163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
4858163953Srrs	}
4859163953Srrs	SOCK_UNLOCK(so);
4860163953Srrs	return (error);
4861163953Srrs}
4862163953Srrs
4863163953Srrsstatic int sctp_defered_wakeup_cnt = 0;
4864163953Srrs
4865163953Srrsint
4866163953Srrssctp_accept(struct socket *so, struct sockaddr **addr)
4867163953Srrs{
4868163953Srrs	struct sctp_tcb *stcb;
4869163953Srrs	struct sctp_inpcb *inp;
4870163953Srrs	union sctp_sockstore store;
4871163953Srrs
4872178251Srrs#ifdef INET6
4873163953Srrs	int error;
4874163953Srrs
4875178251Srrs#endif
4876163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
4877163953Srrs
4878163953Srrs	if (inp == 0) {
4879171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4880163953Srrs		return (ECONNRESET);
4881163953Srrs	}
4882163953Srrs	SCTP_INP_RLOCK(inp);
4883163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
4884168299Srrs		SCTP_INP_RUNLOCK(inp);
4885171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
4886171943Srrs		return (EOPNOTSUPP);
4887163953Srrs	}
4888163953Srrs	if (so->so_state & SS_ISDISCONNECTED) {
4889163953Srrs		SCTP_INP_RUNLOCK(inp);
4890171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
4891163953Srrs		return (ECONNABORTED);
4892163953Srrs	}
4893163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
4894163953Srrs	if (stcb == NULL) {
4895163953Srrs		SCTP_INP_RUNLOCK(inp);
4896171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
4897163953Srrs		return (ECONNRESET);
4898163953Srrs	}
4899163953Srrs	SCTP_TCB_LOCK(stcb);
4900163953Srrs	SCTP_INP_RUNLOCK(inp);
4901163953Srrs	store = stcb->asoc.primary_destination->ro._l_addr;
4902207924Srrs	stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
4903163953Srrs	SCTP_TCB_UNLOCK(stcb);
4904178251Srrs	switch (store.sa.sa_family) {
4905221249Stuexen#ifdef INET
4906178251Srrs	case AF_INET:
4907178251Srrs		{
4908178251Srrs			struct sockaddr_in *sin;
4909163953Srrs
4910178251Srrs			SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
4911208863Srrs			if (sin == NULL)
4912208863Srrs				return (ENOMEM);
4913178251Srrs			sin->sin_family = AF_INET;
4914178251Srrs			sin->sin_len = sizeof(*sin);
4915178251Srrs			sin->sin_port = ((struct sockaddr_in *)&store)->sin_port;
4916178251Srrs			sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr;
4917178251Srrs			*addr = (struct sockaddr *)sin;
4918178251Srrs			break;
4919178251Srrs		}
4920221249Stuexen#endif
4921178251Srrs#ifdef INET6
4922178251Srrs	case AF_INET6:
4923178251Srrs		{
4924178251Srrs			struct sockaddr_in6 *sin6;
4925163953Srrs
4926178251Srrs			SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
4927208863Srrs			if (sin6 == NULL)
4928208863Srrs				return (ENOMEM);
4929178251Srrs			sin6->sin6_family = AF_INET6;
4930178251Srrs			sin6->sin6_len = sizeof(*sin6);
4931178251Srrs			sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port;
4932163953Srrs
4933178251Srrs			sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr;
4934178251Srrs			if ((error = sa6_recoverscope(sin6)) != 0) {
4935178251Srrs				SCTP_FREE_SONAME(sin6);
4936178251Srrs				return (error);
4937178251Srrs			}
4938178251Srrs			*addr = (struct sockaddr *)sin6;
4939178251Srrs			break;
4940164085Srrs		}
4941178251Srrs#endif
4942178251Srrs	default:
4943178251Srrs		/* TSNH */
4944178251Srrs		break;
4945163953Srrs	}
4946163953Srrs	/* Wake any delayed sleep action */
4947163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
4948166086Srrs		SCTP_INP_WLOCK(inp);
4949163953Srrs		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
4950163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
4951163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
4952166086Srrs			SCTP_INP_WUNLOCK(inp);
4953163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
4954163953Srrs			if (sowriteable(inp->sctp_socket)) {
4955163953Srrs				sowwakeup_locked(inp->sctp_socket);
4956163953Srrs			} else {
4957163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
4958163953Srrs			}
4959166086Srrs			SCTP_INP_WLOCK(inp);
4960163953Srrs		}
4961163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
4962163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
4963166086Srrs			SCTP_INP_WUNLOCK(inp);
4964163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
4965163953Srrs			if (soreadable(inp->sctp_socket)) {
4966163953Srrs				sctp_defered_wakeup_cnt++;
4967163953Srrs				sorwakeup_locked(inp->sctp_socket);
4968163953Srrs			} else {
4969163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
4970163953Srrs			}
4971166086Srrs			SCTP_INP_WLOCK(inp);
4972163953Srrs		}
4973166086Srrs		SCTP_INP_WUNLOCK(inp);
4974163953Srrs	}
4975207924Srrs	if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
4976207924Srrs		SCTP_TCB_LOCK(stcb);
4977207924Srrs		sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
4978207924Srrs	}
4979163953Srrs	return (0);
4980163953Srrs}
4981163953Srrs
4982221249Stuexen#ifdef INET
4983163953Srrsint
4984163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr)
4985163953Srrs{
4986163953Srrs	struct sockaddr_in *sin;
4987167598Srrs	uint32_t vrf_id;
4988163953Srrs	struct sctp_inpcb *inp;
4989167695Srrs	struct sctp_ifa *sctp_ifa;
4990163953Srrs
4991163953Srrs	/*
4992163953Srrs	 * Do the malloc first in case it blocks.
4993163953Srrs	 */
4994163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
4995208863Srrs	if (sin == NULL)
4996208863Srrs		return (ENOMEM);
4997163953Srrs	sin->sin_family = AF_INET;
4998163953Srrs	sin->sin_len = sizeof(*sin);
4999163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
5000163953Srrs	if (!inp) {
5001163953Srrs		SCTP_FREE_SONAME(sin);
5002171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5003163953Srrs		return ECONNRESET;
5004163953Srrs	}
5005163953Srrs	SCTP_INP_RLOCK(inp);
5006163953Srrs	sin->sin_port = inp->sctp_lport;
5007163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
5008163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
5009163953Srrs			struct sctp_tcb *stcb;
5010163953Srrs			struct sockaddr_in *sin_a;
5011163953Srrs			struct sctp_nets *net;
5012163953Srrs			int fnd;
5013163953Srrs
5014163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
5015163953Srrs			if (stcb == NULL) {
5016163953Srrs				goto notConn;
5017163953Srrs			}
5018163953Srrs			fnd = 0;
5019163953Srrs			sin_a = NULL;
5020163953Srrs			SCTP_TCB_LOCK(stcb);
5021163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5022163953Srrs				sin_a = (struct sockaddr_in *)&net->ro._l_addr;
5023164085Srrs				if (sin_a == NULL)
5024164085Srrs					/* this will make coverity happy */
5025164085Srrs					continue;
5026164085Srrs
5027163953Srrs				if (sin_a->sin_family == AF_INET) {
5028163953Srrs					fnd = 1;
5029163953Srrs					break;
5030163953Srrs				}
5031163953Srrs			}
5032163953Srrs			if ((!fnd) || (sin_a == NULL)) {
5033163953Srrs				/* punt */
5034163953Srrs				SCTP_TCB_UNLOCK(stcb);
5035163953Srrs				goto notConn;
5036163953Srrs			}
5037168299Srrs			vrf_id = inp->def_vrf_id;
5038167598Srrs			sctp_ifa = sctp_source_address_selection(inp,
5039167598Srrs			    stcb,
5040168299Srrs			    (sctp_route_t *) & net->ro,
5041167598Srrs			    net, 0, vrf_id);
5042167598Srrs			if (sctp_ifa) {
5043167598Srrs				sin->sin_addr = sctp_ifa->address.sin.sin_addr;
5044167598Srrs				sctp_free_ifa(sctp_ifa);
5045167598Srrs			}
5046163953Srrs			SCTP_TCB_UNLOCK(stcb);
5047163953Srrs		} else {
5048163953Srrs			/* For the bound all case you get back 0 */
5049163953Srrs	notConn:
5050163953Srrs			sin->sin_addr.s_addr = 0;
5051163953Srrs		}
5052163953Srrs
5053163953Srrs	} else {
5054163953Srrs		/* Take the first IPv4 address in the list */
5055163953Srrs		struct sctp_laddr *laddr;
5056163953Srrs		int fnd = 0;
5057163953Srrs
5058163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
5059167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET) {
5060163953Srrs				struct sockaddr_in *sin_a;
5061163953Srrs
5062167598Srrs				sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa;
5063163953Srrs				sin->sin_addr = sin_a->sin_addr;
5064163953Srrs				fnd = 1;
5065163953Srrs				break;
5066163953Srrs			}
5067163953Srrs		}
5068163953Srrs		if (!fnd) {
5069163953Srrs			SCTP_FREE_SONAME(sin);
5070163953Srrs			SCTP_INP_RUNLOCK(inp);
5071171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
5072163953Srrs			return ENOENT;
5073163953Srrs		}
5074163953Srrs	}
5075163953Srrs	SCTP_INP_RUNLOCK(inp);
5076163953Srrs	(*addr) = (struct sockaddr *)sin;
5077163953Srrs	return (0);
5078163953Srrs}
5079163953Srrs
5080163953Srrsint
5081163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr)
5082163953Srrs{
5083163953Srrs	struct sockaddr_in *sin = (struct sockaddr_in *)*addr;
5084166086Srrs	int fnd;
5085163953Srrs	struct sockaddr_in *sin_a;
5086163953Srrs	struct sctp_inpcb *inp;
5087163953Srrs	struct sctp_tcb *stcb;
5088163953Srrs	struct sctp_nets *net;
5089163953Srrs
5090163953Srrs	/* Do the malloc first in case it blocks. */
5091163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
5092163953Srrs	if ((inp == NULL) ||
5093163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
5094163953Srrs		/* UDP type and listeners will drop out here */
5095171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
5096163953Srrs		return (ENOTCONN);
5097163953Srrs	}
5098163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
5099208863Srrs	if (sin == NULL)
5100208863Srrs		return (ENOMEM);
5101163953Srrs	sin->sin_family = AF_INET;
5102163953Srrs	sin->sin_len = sizeof(*sin);
5103163953Srrs
5104163953Srrs	/* We must recapture incase we blocked */
5105163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
5106163953Srrs	if (!inp) {
5107163953Srrs		SCTP_FREE_SONAME(sin);
5108171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5109163953Srrs		return ECONNRESET;
5110163953Srrs	}
5111163953Srrs	SCTP_INP_RLOCK(inp);
5112163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
5113169420Srrs	if (stcb) {
5114163953Srrs		SCTP_TCB_LOCK(stcb);
5115169420Srrs	}
5116163953Srrs	SCTP_INP_RUNLOCK(inp);
5117163953Srrs	if (stcb == NULL) {
5118163953Srrs		SCTP_FREE_SONAME(sin);
5119171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
5120163953Srrs		return ECONNRESET;
5121163953Srrs	}
5122163953Srrs	fnd = 0;
5123163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
5124163953Srrs		sin_a = (struct sockaddr_in *)&net->ro._l_addr;
5125163953Srrs		if (sin_a->sin_family == AF_INET) {
5126163953Srrs			fnd = 1;
5127163953Srrs			sin->sin_port = stcb->rport;
5128163953Srrs			sin->sin_addr = sin_a->sin_addr;
5129163953Srrs			break;
5130163953Srrs		}
5131163953Srrs	}
5132163953Srrs	SCTP_TCB_UNLOCK(stcb);
5133163953Srrs	if (!fnd) {
5134163953Srrs		/* No IPv4 address */
5135163953Srrs		SCTP_FREE_SONAME(sin);
5136171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
5137163953Srrs		return ENOENT;
5138163953Srrs	}
5139163953Srrs	(*addr) = (struct sockaddr *)sin;
5140163953Srrs	return (0);
5141163953Srrs}
5142163953Srrs
5143221249Stuexen#ifdef INET
5144163953Srrsstruct pr_usrreqs sctp_usrreqs = {
5145163953Srrs	.pru_abort = sctp_abort,
5146163953Srrs	.pru_accept = sctp_accept,
5147163953Srrs	.pru_attach = sctp_attach,
5148163953Srrs	.pru_bind = sctp_bind,
5149163953Srrs	.pru_connect = sctp_connect,
5150163953Srrs	.pru_control = in_control,
5151163953Srrs	.pru_close = sctp_close,
5152163953Srrs	.pru_detach = sctp_close,
5153163953Srrs	.pru_sopoll = sopoll_generic,
5154178202Srrs	.pru_flush = sctp_flush,
5155163953Srrs	.pru_disconnect = sctp_disconnect,
5156163953Srrs	.pru_listen = sctp_listen,
5157163953Srrs	.pru_peeraddr = sctp_peeraddr,
5158163953Srrs	.pru_send = sctp_sendm,
5159163953Srrs	.pru_shutdown = sctp_shutdown,
5160163953Srrs	.pru_sockaddr = sctp_ingetaddr,
5161163953Srrs	.pru_sosend = sctp_sosend,
5162163953Srrs	.pru_soreceive = sctp_soreceive
5163163953Srrs};
5164221249Stuexen
5165221249Stuexen#endif
5166221249Stuexen#endif
5167