sctp_usrreq.c revision 169420
1163953Srrs/*-
2169382Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3163953Srrs *
4163953Srrs * Redistribution and use in source and binary forms, with or without
5163953Srrs * modification, are permitted provided that the following conditions are met:
6163953Srrs *
7163953Srrs * a) Redistributions of source code must retain the above copyright notice,
8163953Srrs *   this list of conditions and the following disclaimer.
9163953Srrs *
10163953Srrs * b) Redistributions in binary form must reproduce the above copyright
11163953Srrs *    notice, this list of conditions and the following disclaimer in
12163953Srrs *   the documentation and/or other materials provided with the distribution.
13163953Srrs *
14163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
15163953Srrs *    contributors may be used to endorse or promote products derived
16163953Srrs *    from this software without specific prior written permission.
17163953Srrs *
18163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
29163953Srrs */
30163953Srrs
31163953Srrs/* $KAME: sctp_usrreq.c,v 1.48 2005/03/07 23:26:08 itojun Exp $	 */
32163953Srrs
33163953Srrs#include <sys/cdefs.h>
34163953Srrs__FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 169420 2007-05-09 13:30:06Z rrs $");
35166086Srrs#include <netinet/sctp_os.h>
36163953Srrs#include <sys/proc.h>
37163953Srrs#include <netinet/sctp_pcb.h>
38163953Srrs#include <netinet/sctp_header.h>
39163953Srrs#include <netinet/sctp_var.h>
40167695Srrs#if defined(INET6)
41167695Srrs#include <netinet6/sctp6_var.h>
42167695Srrs#endif
43167598Srrs#include <netinet/sctp_sysctl.h>
44163953Srrs#include <netinet/sctp_output.h>
45163953Srrs#include <netinet/sctp_uio.h>
46163953Srrs#include <netinet/sctp_asconf.h>
47163953Srrs#include <netinet/sctputil.h>
48163953Srrs#include <netinet/sctp_indata.h>
49163953Srrs#include <netinet/sctp_timer.h>
50163953Srrs#include <netinet/sctp_auth.h>
51164085Srrs
52163953Srrs
53163953Srrs
54163953Srrsvoid
55163953Srrssctp_init(void)
56163953Srrs{
57163953Srrs	/* Init the SCTP pcb in sctp_pcb.c */
58163953Srrs	u_long sb_max_adj;
59163953Srrs
60163953Srrs	sctp_pcb_init();
61163953Srrs
62163953Srrs	if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
63163953Srrs		sctp_max_chunks_on_queue = (nmbclusters / 8);
64163953Srrs	/*
65163953Srrs	 * Allow a user to take no more than 1/2 the number of clusters or
66163953Srrs	 * the SB_MAX whichever is smaller for the send window.
67163953Srrs	 */
68163953Srrs	sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
69163953Srrs	sctp_sendspace = min((min(SB_MAX, sb_max_adj)),
70163953Srrs	    ((nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT));
71163953Srrs	/*
72163953Srrs	 * Now for the recv window, should we take the same amount? or
73163953Srrs	 * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
74163953Srrs	 * now I will just copy.
75163953Srrs	 */
76163953Srrs	sctp_recvspace = sctp_sendspace;
77163953Srrs
78163953Srrs
79163953Srrs}
80163953Srrs
81163953Srrs
82166023Srrs
83166023Srrs/*
84166023Srrs * cleanup of the sctppcbinfo structure.
85166023Srrs * Assumes that the sctppcbinfo lock is held.
86166023Srrs */
87166023Srrsvoid
88166023Srrssctp_pcbinfo_cleanup(void)
89166023Srrs{
90166023Srrs	/* free the hash tables */
91166023Srrs	if (sctppcbinfo.sctp_asochash != NULL)
92166023Srrs		SCTP_HASH_FREE(sctppcbinfo.sctp_asochash, sctppcbinfo.hashasocmark);
93166023Srrs	if (sctppcbinfo.sctp_ephash != NULL)
94166023Srrs		SCTP_HASH_FREE(sctppcbinfo.sctp_ephash, sctppcbinfo.hashmark);
95166023Srrs	if (sctppcbinfo.sctp_tcpephash != NULL)
96166023Srrs		SCTP_HASH_FREE(sctppcbinfo.sctp_tcpephash, sctppcbinfo.hashtcpmark);
97166023Srrs	if (sctppcbinfo.sctp_restarthash != NULL)
98166023Srrs		SCTP_HASH_FREE(sctppcbinfo.sctp_restarthash, sctppcbinfo.hashrestartmark);
99166023Srrs}
100166023Srrs
101163953Srrs
102163953Srrsstatic void
103167695Srrssctp_pathmtu_adjustment(struct sctp_inpcb *inp,
104163953Srrs    struct sctp_tcb *stcb,
105163953Srrs    struct sctp_nets *net,
106163953Srrs    uint16_t nxtsz)
107163953Srrs{
108163953Srrs	struct sctp_tmit_chunk *chk;
109163953Srrs
110163953Srrs	/* Adjust that too */
111163953Srrs	stcb->asoc.smallest_mtu = nxtsz;
112163953Srrs	/* now off to subtract IP_DF flag if needed */
113169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M
114169420Srrs	SCTP_PRINTF("sctp_pathmtu_adjust called inp:%p stcb:%p net:%p nxtsz:%d\n",
115169352Srrs	    inp, stcb, net, nxtsz);
116169352Srrs#endif
117163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
118163953Srrs		if ((chk->send_size + IP_HDR_SIZE) > nxtsz) {
119163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
120163953Srrs		}
121163953Srrs	}
122163953Srrs	TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
123163953Srrs		if ((chk->send_size + IP_HDR_SIZE) > nxtsz) {
124163953Srrs			/*
125163953Srrs			 * For this guy we also mark for immediate resend
126163953Srrs			 * since we sent to big of chunk
127163953Srrs			 */
128163953Srrs			chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
129163953Srrs			if (chk->sent != SCTP_DATAGRAM_RESEND) {
130163953Srrs				sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
131163953Srrs			}
132163953Srrs			chk->sent = SCTP_DATAGRAM_RESEND;
133163953Srrs			chk->rec.data.doing_fast_retransmit = 0;
134168709Srrs#ifdef SCTP_FLIGHT_LOGGING
135168709Srrs			sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
136168709Srrs			    chk->whoTo->flight_size,
137168709Srrs			    chk->book_size,
138168709Srrs			    (uintptr_t) chk->whoTo,
139168709Srrs			    chk->rec.data.TSN_seq);
140168709Srrs#endif
141163953Srrs			/* Clear any time so NO RTT is being done */
142163953Srrs			chk->do_rtt = 0;
143168709Srrs			sctp_flight_size_decrease(chk);
144168709Srrs			sctp_total_flight_decrease(stcb, chk);
145163953Srrs		}
146163953Srrs	}
147163953Srrs}
148163953Srrs
149163953Srrsstatic void
150163953Srrssctp_notify_mbuf(struct sctp_inpcb *inp,
151163953Srrs    struct sctp_tcb *stcb,
152163953Srrs    struct sctp_nets *net,
153163953Srrs    struct ip *ip,
154163953Srrs    struct sctphdr *sh)
155163953Srrs{
156163953Srrs	struct icmp *icmph;
157163953Srrs	int totsz, tmr_stopped = 0;
158163953Srrs	uint16_t nxtsz;
159163953Srrs
160163953Srrs	/* protection */
161163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
162163953Srrs	    (ip == NULL) || (sh == NULL)) {
163169420Srrs		if (stcb != NULL) {
164163953Srrs			SCTP_TCB_UNLOCK(stcb);
165169420Srrs		}
166163953Srrs		return;
167163953Srrs	}
168163953Srrs	/* First job is to verify the vtag matches what I would send */
169163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
170163953Srrs		SCTP_TCB_UNLOCK(stcb);
171163953Srrs		return;
172163953Srrs	}
173163953Srrs	icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
174163953Srrs	    sizeof(struct ip)));
175163953Srrs	if (icmph->icmp_type != ICMP_UNREACH) {
176163953Srrs		/* We only care about unreachable */
177163953Srrs		SCTP_TCB_UNLOCK(stcb);
178163953Srrs		return;
179163953Srrs	}
180163953Srrs	if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) {
181163953Srrs		/* not a unreachable message due to frag. */
182163953Srrs		SCTP_TCB_UNLOCK(stcb);
183163953Srrs		return;
184163953Srrs	}
185163953Srrs	totsz = ip->ip_len;
186163953Srrs
187163953Srrs	nxtsz = ntohs(icmph->icmp_seq);
188163953Srrs	if (nxtsz == 0) {
189163953Srrs		/*
190163953Srrs		 * old type router that does not tell us what the next size
191163953Srrs		 * mtu is. Rats we will have to guess (in a educated fashion
192163953Srrs		 * of course)
193163953Srrs		 */
194163953Srrs		nxtsz = find_next_best_mtu(totsz);
195163953Srrs	}
196163953Srrs	/* Stop any PMTU timer */
197165647Srrs	if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
198163953Srrs		tmr_stopped = 1;
199165220Srrs		sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
200165220Srrs		    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
201163953Srrs	}
202163953Srrs	/* Adjust destination size limit */
203163953Srrs	if (net->mtu > nxtsz) {
204163953Srrs		net->mtu = nxtsz;
205163953Srrs	}
206163953Srrs	/* now what about the ep? */
207163953Srrs	if (stcb->asoc.smallest_mtu > nxtsz) {
208169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M
209169420Srrs		SCTP_PRINTF("notify_mbuf (ICMP) calls sctp_pathmtu_adjust mtu:%d\n",
210169352Srrs		    nxtsz);
211169352Srrs#endif
212167695Srrs		sctp_pathmtu_adjustment(inp, stcb, net, nxtsz);
213163953Srrs	}
214163953Srrs	if (tmr_stopped)
215163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
216163953Srrs
217163953Srrs	SCTP_TCB_UNLOCK(stcb);
218163953Srrs}
219163953Srrs
220163953Srrs
221163953Srrsvoid
222163953Srrssctp_notify(struct sctp_inpcb *inp,
223167695Srrs    int error,
224163953Srrs    struct sctphdr *sh,
225163953Srrs    struct sockaddr *to,
226163953Srrs    struct sctp_tcb *stcb,
227163953Srrs    struct sctp_nets *net)
228163953Srrs{
229163953Srrs	/* protection */
230163953Srrs	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
231163953Srrs	    (sh == NULL) || (to == NULL)) {
232163953Srrs		return;
233163953Srrs	}
234163953Srrs	/* First job is to verify the vtag matches what I would send */
235163953Srrs	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
236163953Srrs		return;
237163953Srrs	}
238163953Srrs	/* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */
239163953Srrs
240167695Srrs	if ((error == EHOSTUNREACH) ||	/* Host is not reachable */
241167695Srrs	    (error == EHOSTDOWN) ||	/* Host is down */
242167695Srrs	    (error == ECONNREFUSED) ||	/* Host refused the connection, (not
243163953Srrs					 * an abort?) */
244167695Srrs	    (error == ENOPROTOOPT)	/* SCTP is not present on host */
245163953Srrs	    ) {
246163953Srrs		/*
247163953Srrs		 * Hmm reachablity problems we must examine closely. If its
248163953Srrs		 * not reachable, we may have lost a network. Or if there is
249163953Srrs		 * NO protocol at the other end named SCTP. well we consider
250163953Srrs		 * it a OOTB abort.
251163953Srrs		 */
252167695Srrs		if ((error == EHOSTUNREACH) || (error == EHOSTDOWN)) {
253163953Srrs			if (net->dest_state & SCTP_ADDR_REACHABLE) {
254163953Srrs				/* Ok that destination is NOT reachable */
255169420Srrs				SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
256167598Srrs				    net->error_count,
257167598Srrs				    net->failure_threshold,
258167598Srrs				    net);
259167598Srrs
260163953Srrs				net->dest_state &= ~SCTP_ADDR_REACHABLE;
261163953Srrs				net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
262163953Srrs				net->error_count = net->failure_threshold + 1;
263163953Srrs				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
264163953Srrs				    stcb, SCTP_FAILED_THRESHOLD,
265163953Srrs				    (void *)net);
266163953Srrs			}
267169420Srrs			if (stcb) {
268163953Srrs				SCTP_TCB_UNLOCK(stcb);
269169420Srrs			}
270163953Srrs		} else {
271163953Srrs			/*
272163953Srrs			 * Here the peer is either playing tricks on us,
273163953Srrs			 * including an address that belongs to someone who
274163953Srrs			 * does not support SCTP OR was a userland
275163953Srrs			 * implementation that shutdown and now is dead. In
276163953Srrs			 * either case treat it like a OOTB abort with no
277163953Srrs			 * TCB
278163953Srrs			 */
279163953Srrs			sctp_abort_notification(stcb, SCTP_PEER_FAULTY);
280165220Srrs			sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
281163953Srrs			/* no need to unlock here, since the TCB is gone */
282163953Srrs		}
283163953Srrs	} else {
284163953Srrs		/* Send all others to the app */
285169420Srrs		if (stcb) {
286163953Srrs			SCTP_TCB_UNLOCK(stcb);
287169420Srrs		}
288163953Srrs		if (inp->sctp_socket) {
289163953Srrs#ifdef SCTP_LOCK_LOGGING
290163953Srrs			sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCK);
291163953Srrs#endif
292163953Srrs			SOCK_LOCK(inp->sctp_socket);
293167695Srrs			inp->sctp_socket->so_error = error;
294163953Srrs			sctp_sowwakeup(inp, inp->sctp_socket);
295163953Srrs			SOCK_UNLOCK(inp->sctp_socket);
296163953Srrs		}
297163953Srrs	}
298163953Srrs}
299163953Srrs
300163953Srrsvoid
301163953Srrssctp_ctlinput(cmd, sa, vip)
302163953Srrs	int cmd;
303163953Srrs	struct sockaddr *sa;
304163953Srrs	void *vip;
305163953Srrs{
306163953Srrs	struct ip *ip = vip;
307163953Srrs	struct sctphdr *sh;
308167598Srrs	uint32_t vrf_id;
309163953Srrs
310168299Srrs	/* FIX, for non-bsd is this right? */
311167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
312163953Srrs	if (sa->sa_family != AF_INET ||
313163953Srrs	    ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
314163953Srrs		return;
315163953Srrs	}
316163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
317163953Srrs		ip = 0;
318163953Srrs	} else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
319163953Srrs		return;
320163953Srrs	}
321163953Srrs	if (ip) {
322163953Srrs		struct sctp_inpcb *inp = NULL;
323163953Srrs		struct sctp_tcb *stcb = NULL;
324163953Srrs		struct sctp_nets *net = NULL;
325163953Srrs		struct sockaddr_in to, from;
326163953Srrs
327163953Srrs		sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2));
328163953Srrs		bzero(&to, sizeof(to));
329163953Srrs		bzero(&from, sizeof(from));
330163953Srrs		from.sin_family = to.sin_family = AF_INET;
331163953Srrs		from.sin_len = to.sin_len = sizeof(to);
332163953Srrs		from.sin_port = sh->src_port;
333163953Srrs		from.sin_addr = ip->ip_src;
334163953Srrs		to.sin_port = sh->dest_port;
335163953Srrs		to.sin_addr = ip->ip_dst;
336163953Srrs
337163953Srrs		/*
338163953Srrs		 * 'to' holds the dest of the packet that failed to be sent.
339163953Srrs		 * 'from' holds our local endpoint address. Thus we reverse
340163953Srrs		 * the to and the from in the lookup.
341163953Srrs		 */
342163953Srrs		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from,
343163953Srrs		    (struct sockaddr *)&to,
344167598Srrs		    &inp, &net, 1, vrf_id);
345163953Srrs		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
346163953Srrs			if (cmd != PRC_MSGSIZE) {
347163953Srrs				int cm;
348163953Srrs
349163953Srrs				if (cmd == PRC_HOSTDEAD) {
350163953Srrs					cm = EHOSTUNREACH;
351163953Srrs				} else {
352163953Srrs					cm = inetctlerrmap[cmd];
353163953Srrs				}
354163953Srrs				sctp_notify(inp, cm, sh,
355163953Srrs				    (struct sockaddr *)&to, stcb,
356163953Srrs				    net);
357163953Srrs			} else {
358163953Srrs				/* handle possible ICMP size messages */
359163953Srrs				sctp_notify_mbuf(inp, stcb, net, ip, sh);
360163953Srrs			}
361163953Srrs		} else {
362163953Srrs			if ((stcb == NULL) && (inp != NULL)) {
363163953Srrs				/* reduce ref-count */
364163953Srrs				SCTP_INP_WLOCK(inp);
365163953Srrs				SCTP_INP_DECR_REF(inp);
366163953Srrs				SCTP_INP_WUNLOCK(inp);
367163953Srrs			}
368163953Srrs		}
369163953Srrs	}
370163953Srrs	return;
371163953Srrs}
372163953Srrs
373163953Srrsstatic int
374163953Srrssctp_getcred(SYSCTL_HANDLER_ARGS)
375163953Srrs{
376164085Srrs	struct xucred xuc;
377163953Srrs	struct sockaddr_in addrs[2];
378163953Srrs	struct sctp_inpcb *inp;
379163953Srrs	struct sctp_nets *net;
380163953Srrs	struct sctp_tcb *stcb;
381164085Srrs	int error;
382167598Srrs	uint32_t vrf_id;
383163953Srrs
384168299Srrs
385168299Srrs	/* FIX, for non-bsd is this right? */
386167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
387168299Srrs
388164039Srwatson	/*
389164039Srwatson	 * XXXRW: Other instances of getcred use SUSER_ALLOWJAIL, as socket
390164039Srwatson	 * visibility is scoped using cr_canseesocket(), which it is not
391164039Srwatson	 * here.
392164039Srwatson	 */
393167598Srrs	error = priv_check_cred(req->td->td_ucred, PRIV_NETINET_GETCRED,
394167598Srrs	    SUSER_ALLOWJAIL);
395163953Srrs	if (error)
396163953Srrs		return (error);
397164039Srwatson
398163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
399163953Srrs	if (error)
400163953Srrs		return (error);
401163953Srrs
402163953Srrs	stcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]),
403163953Srrs	    sintosa(&addrs[1]),
404167598Srrs	    &inp, &net, 1, vrf_id);
405163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
406163953Srrs		if ((inp != NULL) && (stcb == NULL)) {
407163953Srrs			/* reduce ref-count */
408163953Srrs			SCTP_INP_WLOCK(inp);
409163953Srrs			SCTP_INP_DECR_REF(inp);
410164085Srrs			goto cred_can_cont;
411163953Srrs		}
412163953Srrs		error = ENOENT;
413163953Srrs		goto out;
414163953Srrs	}
415163953Srrs	SCTP_TCB_UNLOCK(stcb);
416164085Srrs	/*
417164085Srrs	 * We use the write lock here, only since in the error leg we need
418164085Srrs	 * it. If we used RLOCK, then we would have to
419164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
420164085Srrs	 * Better to use higher wlock.
421164085Srrs	 */
422164085Srrs	SCTP_INP_WLOCK(inp);
423164085Srrscred_can_cont:
424164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
425164085Srrs	if (error) {
426164085Srrs		SCTP_INP_WUNLOCK(inp);
427164085Srrs		goto out;
428164085Srrs	}
429164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
430164085Srrs	SCTP_INP_WUNLOCK(inp);
431164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
432163953Srrsout:
433163953Srrs	return (error);
434163953Srrs}
435163953Srrs
436163953SrrsSYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
437163953Srrs    0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection");
438163953Srrs
439163953Srrs
440163953Srrsstatic void
441163953Srrssctp_abort(struct socket *so)
442163953Srrs{
443163953Srrs	struct sctp_inpcb *inp;
444163953Srrs	uint32_t flags;
445163953Srrs
446163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
447163953Srrs	if (inp == 0)
448163953Srrs		return;
449163953Srrs
450163953Srrssctp_must_try_again:
451163953Srrs	flags = inp->sctp_flags;
452163953Srrs#ifdef SCTP_LOG_CLOSING
453163953Srrs	sctp_log_closing(inp, NULL, 17);
454163953Srrs#endif
455163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
456163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
457163953Srrs#ifdef SCTP_LOG_CLOSING
458163953Srrs		sctp_log_closing(inp, NULL, 16);
459163953Srrs#endif
460169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
461169380Srrs		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
462163953Srrs		SOCK_LOCK(so);
463167695Srrs		SCTP_SB_CLEAR(so->so_snd);
464163953Srrs		/*
465163953Srrs		 * same for the rcv ones, they are only here for the
466163953Srrs		 * accounting/select.
467163953Srrs		 */
468167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
469167695Srrs
470167695Srrs		/* Now null out the reference, we are completely detached. */
471163953Srrs		so->so_pcb = NULL;
472163953Srrs		SOCK_UNLOCK(so);
473163953Srrs	} else {
474163953Srrs		flags = inp->sctp_flags;
475163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
476163953Srrs			goto sctp_must_try_again;
477163953Srrs		}
478163953Srrs	}
479163953Srrs	return;
480163953Srrs}
481163953Srrs
482163953Srrsstatic int
483163953Srrssctp_attach(struct socket *so, int proto, struct thread *p)
484163953Srrs{
485163953Srrs	struct sctp_inpcb *inp;
486163953Srrs	struct inpcb *ip_inp;
487166086Srrs	int error;
488163953Srrs
489163953Srrs#ifdef IPSEC
490163953Srrs	uint32_t flags;
491163953Srrs
492163953Srrs#endif
493163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
494163953Srrs	if (inp != 0) {
495163953Srrs		return EINVAL;
496163953Srrs	}
497167695Srrs	error = SCTP_SORESERVE(so, sctp_sendspace, sctp_recvspace);
498163953Srrs	if (error) {
499163953Srrs		return error;
500163953Srrs	}
501163953Srrs	error = sctp_inpcb_alloc(so);
502163953Srrs	if (error) {
503163953Srrs		return error;
504163953Srrs	}
505163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
506163953Srrs	SCTP_INP_WLOCK(inp);
507163953Srrs
508163953Srrs	inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;	/* I'm not v6! */
509163953Srrs	ip_inp = &inp->ip_inp.inp;
510163953Srrs	ip_inp->inp_vflag |= INP_IPV4;
511163953Srrs	ip_inp->inp_ip_ttl = ip_defttl;
512163953Srrs
513163953Srrs#ifdef IPSEC
514163953Srrs	error = ipsec_init_pcbpolicy(so, &ip_inp->inp_sp);
515163953Srrs#ifdef SCTP_LOG_CLOSING
516163953Srrs	sctp_log_closing(inp, NULL, 17);
517163953Srrs#endif
518163953Srrs	if (error != 0) {
519163953Srrs		flags = inp->sctp_flags;
520163953Srrs		if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
521163953Srrs		    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
522163953Srrs#ifdef SCTP_LOG_CLOSING
523163953Srrs			sctp_log_closing(inp, NULL, 15);
524163953Srrs#endif
525169352Srrs			SCTP_INP_WUNLOCK(inp);
526169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
527169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
528169254Srrs		} else {
529169352Srrs			SCTP_INP_WUNLOCK(inp);
530163953Srrs		}
531163953Srrs		return error;
532163953Srrs	}
533163953Srrs#endif				/* IPSEC */
534163953Srrs	SCTP_INP_WUNLOCK(inp);
535163953Srrs	return 0;
536163953Srrs}
537163953Srrs
538163953Srrsstatic int
539163953Srrssctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
540163953Srrs{
541163953Srrs	struct sctp_inpcb *inp;
542166086Srrs	int error;
543163953Srrs
544163953Srrs#ifdef INET6
545163953Srrs	if (addr && addr->sa_family != AF_INET)
546163953Srrs		/* must be a v4 address! */
547163953Srrs		return EINVAL;
548163953Srrs#endif				/* INET6 */
549163953Srrs
550163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
551163953Srrs	if (inp == 0)
552163953Srrs		return EINVAL;
553163953Srrs
554163953Srrs	error = sctp_inpcb_bind(so, addr, p);
555163953Srrs	return error;
556163953Srrs}
557163953Srrs
558163953Srrsstatic void
559163953Srrssctp_close(struct socket *so)
560163953Srrs{
561163953Srrs	struct sctp_inpcb *inp;
562163953Srrs	uint32_t flags;
563163953Srrs
564163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
565163953Srrs	if (inp == 0)
566163953Srrs		return;
567163953Srrs
568163953Srrs	/*
569163953Srrs	 * Inform all the lower layer assoc that we are done.
570163953Srrs	 */
571163953Srrssctp_must_try_again:
572163953Srrs	flags = inp->sctp_flags;
573163953Srrs#ifdef SCTP_LOG_CLOSING
574163953Srrs	sctp_log_closing(inp, NULL, 17);
575163953Srrs#endif
576163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
577163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
578163953Srrs		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
579163953Srrs		    (so->so_rcv.sb_cc > 0)) {
580163953Srrs#ifdef SCTP_LOG_CLOSING
581163953Srrs			sctp_log_closing(inp, NULL, 13);
582163953Srrs#endif
583169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
584169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
585163953Srrs		} else {
586163953Srrs#ifdef SCTP_LOG_CLOSING
587163953Srrs			sctp_log_closing(inp, NULL, 14);
588163953Srrs#endif
589169380Srrs			sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
590169380Srrs			    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
591163953Srrs		}
592163953Srrs		/*
593163953Srrs		 * The socket is now detached, no matter what the state of
594163953Srrs		 * the SCTP association.
595163953Srrs		 */
596163953Srrs		SOCK_LOCK(so);
597167695Srrs		SCTP_SB_CLEAR(so->so_snd);
598163953Srrs		/*
599163953Srrs		 * same for the rcv ones, they are only here for the
600163953Srrs		 * accounting/select.
601163953Srrs		 */
602167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
603167695Srrs
604167695Srrs		/* Now null out the reference, we are completely detached. */
605163953Srrs		so->so_pcb = NULL;
606163953Srrs		SOCK_UNLOCK(so);
607163953Srrs	} else {
608163953Srrs		flags = inp->sctp_flags;
609163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
610163953Srrs			goto sctp_must_try_again;
611163953Srrs		}
612163953Srrs	}
613163953Srrs	return;
614163953Srrs}
615163953Srrs
616163953Srrs
617163953Srrsint
618163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
619163953Srrs    struct mbuf *control, struct thread *p);
620163953Srrs
621163953Srrs
622163953Srrsint
623163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
624163953Srrs    struct mbuf *control, struct thread *p)
625163953Srrs{
626163953Srrs	struct sctp_inpcb *inp;
627163953Srrs	int error;
628163953Srrs
629163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
630163953Srrs	if (inp == 0) {
631163953Srrs		if (control) {
632163953Srrs			sctp_m_freem(control);
633163953Srrs			control = NULL;
634163953Srrs		}
635163953Srrs		sctp_m_freem(m);
636163953Srrs		return EINVAL;
637163953Srrs	}
638163953Srrs	/* Got to have an to address if we are NOT a connected socket */
639163953Srrs	if ((addr == NULL) &&
640163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
641163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))
642163953Srrs	    ) {
643163953Srrs		goto connected_type;
644163953Srrs	} else if (addr == NULL) {
645163953Srrs		error = EDESTADDRREQ;
646163953Srrs		sctp_m_freem(m);
647163953Srrs		if (control) {
648163953Srrs			sctp_m_freem(control);
649163953Srrs			control = NULL;
650163953Srrs		}
651163953Srrs		return (error);
652163953Srrs	}
653163953Srrs#ifdef INET6
654163953Srrs	if (addr->sa_family != AF_INET) {
655163953Srrs		/* must be a v4 address! */
656163953Srrs		sctp_m_freem(m);
657163953Srrs		if (control) {
658163953Srrs			sctp_m_freem(control);
659163953Srrs			control = NULL;
660163953Srrs		}
661163953Srrs		error = EDESTADDRREQ;
662163953Srrs		return EINVAL;
663163953Srrs	}
664163953Srrs#endif				/* INET6 */
665163953Srrsconnected_type:
666163953Srrs	/* now what about control */
667163953Srrs	if (control) {
668163953Srrs		if (inp->control) {
669169420Srrs			SCTP_PRINTF("huh? control set?\n");
670163953Srrs			sctp_m_freem(inp->control);
671163953Srrs			inp->control = NULL;
672163953Srrs		}
673163953Srrs		inp->control = control;
674163953Srrs	}
675163953Srrs	/* Place the data */
676163953Srrs	if (inp->pkt) {
677165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
678163953Srrs		inp->pkt_last = m;
679163953Srrs	} else {
680163953Srrs		inp->pkt_last = inp->pkt = m;
681163953Srrs	}
682163953Srrs	if (
683163953Srrs	/* FreeBSD uses a flag passed */
684163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
685163953Srrs	    ) {
686163953Srrs		/*
687163953Srrs		 * note with the current version this code will only be used
688163953Srrs		 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
689163953Srrs		 * re-defining sosend to use the sctp_sosend. One can
690163953Srrs		 * optionally switch back to this code (by changing back the
691163953Srrs		 * definitions) but this is not advisable. This code is used
692163953Srrs		 * by FreeBSD when sending a file with sendfile() though.
693163953Srrs		 */
694163953Srrs		int ret;
695163953Srrs
696163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
697163953Srrs		inp->pkt = NULL;
698163953Srrs		inp->control = NULL;
699163953Srrs		return (ret);
700163953Srrs	} else {
701163953Srrs		return (0);
702163953Srrs	}
703163953Srrs}
704163953Srrs
705163953Srrsstatic int
706163953Srrssctp_disconnect(struct socket *so)
707163953Srrs{
708163953Srrs	struct sctp_inpcb *inp;
709163953Srrs
710163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
711163953Srrs	if (inp == NULL) {
712163953Srrs		return (ENOTCONN);
713163953Srrs	}
714163953Srrs	SCTP_INP_RLOCK(inp);
715163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
716166675Srrs		if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) {
717163953Srrs			/* No connection */
718163953Srrs			SCTP_INP_RUNLOCK(inp);
719163953Srrs			return (0);
720163953Srrs		} else {
721163953Srrs			struct sctp_association *asoc;
722163953Srrs			struct sctp_tcb *stcb;
723163953Srrs
724163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
725163953Srrs			if (stcb == NULL) {
726163953Srrs				SCTP_INP_RUNLOCK(inp);
727163953Srrs				return (EINVAL);
728163953Srrs			}
729163953Srrs			SCTP_TCB_LOCK(stcb);
730163953Srrs			asoc = &stcb->asoc;
731163953Srrs			if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
732163953Srrs				/* We are about to be freed, out of here */
733163953Srrs				SCTP_TCB_UNLOCK(stcb);
734163953Srrs				SCTP_INP_RUNLOCK(inp);
735163953Srrs				return (0);
736163953Srrs			}
737163953Srrs			if (((so->so_options & SO_LINGER) &&
738163953Srrs			    (so->so_linger == 0)) ||
739163953Srrs			    (so->so_rcv.sb_cc > 0)) {
740163953Srrs				if (SCTP_GET_STATE(asoc) !=
741163953Srrs				    SCTP_STATE_COOKIE_WAIT) {
742163953Srrs					/* Left with Data unread */
743163953Srrs					struct mbuf *err;
744163953Srrs
745163953Srrs					err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA);
746163953Srrs					if (err) {
747163953Srrs						/*
748163953Srrs						 * Fill in the user
749163953Srrs						 * initiated abort
750163953Srrs						 */
751163953Srrs						struct sctp_paramhdr *ph;
752163953Srrs
753163953Srrs						ph = mtod(err, struct sctp_paramhdr *);
754165647Srrs						SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr);
755163953Srrs						ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
756165647Srrs						ph->param_length = htons(SCTP_BUF_LEN(err));
757163953Srrs					}
758163953Srrs					sctp_send_abort_tcb(stcb, err);
759163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
760163953Srrs				}
761163953Srrs				SCTP_INP_RUNLOCK(inp);
762163953Srrs				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
763163953Srrs				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
764163953Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
765163953Srrs				}
766165220Srrs				sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
767163953Srrs				/* No unlock tcb assoc is gone */
768163953Srrs				return (0);
769163953Srrs			}
770163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
771163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
772163953Srrs			    (asoc->stream_queue_cnt == 0)) {
773163953Srrs				/* there is nothing queued to send, so done */
774163953Srrs				if (asoc->locked_on_sending) {
775163953Srrs					goto abort_anyway;
776163953Srrs				}
777166675Srrs				if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) &&
778166675Srrs				    (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
779163953Srrs					/* only send SHUTDOWN 1st time thru */
780163953Srrs					sctp_stop_timers_for_shutdown(stcb);
781163953Srrs					sctp_send_shutdown(stcb,
782163953Srrs					    stcb->asoc.primary_destination);
783163953Srrs					sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3);
784166675Srrs					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
785166675Srrs					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
786166675Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
787166675Srrs					}
788163953Srrs					asoc->state = SCTP_STATE_SHUTDOWN_SENT;
789163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
790163953Srrs					    stcb->sctp_ep, stcb,
791163953Srrs					    asoc->primary_destination);
792163953Srrs					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
793163953Srrs					    stcb->sctp_ep, stcb,
794163953Srrs					    asoc->primary_destination);
795163953Srrs				}
796163953Srrs			} else {
797163953Srrs				/*
798163953Srrs				 * we still got (or just got) data to send,
799163953Srrs				 * so set SHUTDOWN_PENDING
800163953Srrs				 */
801163953Srrs				/*
802163953Srrs				 * XXX sockets draft says that SCTP_EOF
803163953Srrs				 * should be sent with no data. currently,
804163953Srrs				 * we will allow user data to be sent first
805163953Srrs				 * and move to SHUTDOWN-PENDING
806163953Srrs				 */
807163953Srrs				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
808163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
809163953Srrs				    asoc->primary_destination);
810163953Srrs				if (asoc->locked_on_sending) {
811163953Srrs					/* Locked to send out the data */
812163953Srrs					struct sctp_stream_queue_pending *sp;
813163953Srrs
814163953Srrs					sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
815163953Srrs					if (sp == NULL) {
816169420Srrs						SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
817163953Srrs						    asoc->locked_on_sending->stream_no);
818163953Srrs					} else {
819163953Srrs						if ((sp->length == 0) && (sp->msg_is_complete == 0))
820163953Srrs							asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
821163953Srrs					}
822163953Srrs				}
823163953Srrs				if (TAILQ_EMPTY(&asoc->send_queue) &&
824163953Srrs				    TAILQ_EMPTY(&asoc->sent_queue) &&
825163953Srrs				    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
826163953Srrs					struct mbuf *op_err;
827163953Srrs
828163953Srrs			abort_anyway:
829163953Srrs					op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
830163953Srrs					    0, M_DONTWAIT, 1, MT_DATA);
831163953Srrs					if (op_err) {
832163953Srrs						/*
833163953Srrs						 * Fill in the user
834163953Srrs						 * initiated abort
835163953Srrs						 */
836163953Srrs						struct sctp_paramhdr *ph;
837163953Srrs						uint32_t *ippp;
838163953Srrs
839165647Srrs						SCTP_BUF_LEN(op_err) =
840163953Srrs						    (sizeof(struct sctp_paramhdr) + sizeof(uint32_t));
841163953Srrs						ph = mtod(op_err,
842163953Srrs						    struct sctp_paramhdr *);
843163953Srrs						ph->param_type = htons(
844163953Srrs						    SCTP_CAUSE_USER_INITIATED_ABT);
845165647Srrs						ph->param_length = htons(SCTP_BUF_LEN(op_err));
846163953Srrs						ippp = (uint32_t *) (ph + 1);
847165220Srrs						*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4);
848163953Srrs					}
849165220Srrs					stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
850163953Srrs					sctp_send_abort_tcb(stcb, op_err);
851163953Srrs					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
852163953Srrs					if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
853163953Srrs					    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
854163953Srrs						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
855163953Srrs					}
856163953Srrs					SCTP_INP_RUNLOCK(inp);
857165220Srrs					sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
858163953Srrs					return (0);
859163953Srrs				}
860163953Srrs			}
861163953Srrs			SCTP_TCB_UNLOCK(stcb);
862163953Srrs			SCTP_INP_RUNLOCK(inp);
863163953Srrs			return (0);
864163953Srrs		}
865163953Srrs		/* not reached */
866163953Srrs	} else {
867163953Srrs		/* UDP model does not support this */
868163953Srrs		SCTP_INP_RUNLOCK(inp);
869163953Srrs		return EOPNOTSUPP;
870163953Srrs	}
871163953Srrs}
872163953Srrs
873163953Srrsint
874163953Srrssctp_shutdown(struct socket *so)
875163953Srrs{
876163953Srrs	struct sctp_inpcb *inp;
877163953Srrs
878163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
879163953Srrs	if (inp == 0) {
880163953Srrs		return EINVAL;
881163953Srrs	}
882163953Srrs	SCTP_INP_RLOCK(inp);
883163953Srrs	/* For UDP model this is a invalid call */
884163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
885163953Srrs		/* Restore the flags that the soshutdown took away. */
886163953Srrs		so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
887163953Srrs		/* This proc will wakeup for read and do nothing (I hope) */
888163953Srrs		SCTP_INP_RUNLOCK(inp);
889163953Srrs		return (EOPNOTSUPP);
890163953Srrs	}
891163953Srrs	/*
892163953Srrs	 * Ok if we reach here its the TCP model and it is either a SHUT_WR
893163953Srrs	 * or SHUT_RDWR. This means we put the shutdown flag against it.
894163953Srrs	 */
895163953Srrs	{
896163953Srrs		struct sctp_tcb *stcb;
897163953Srrs		struct sctp_association *asoc;
898163953Srrs
899163953Srrs		socantsendmore(so);
900163953Srrs
901163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
902163953Srrs		if (stcb == NULL) {
903163953Srrs			/*
904163953Srrs			 * Ok we hit the case that the shutdown call was
905163953Srrs			 * made after an abort or something. Nothing to do
906163953Srrs			 * now.
907163953Srrs			 */
908168299Srrs			SCTP_INP_RUNLOCK(inp);
909163953Srrs			return (0);
910163953Srrs		}
911163953Srrs		SCTP_TCB_LOCK(stcb);
912163953Srrs		asoc = &stcb->asoc;
913163953Srrs		if (TAILQ_EMPTY(&asoc->send_queue) &&
914163953Srrs		    TAILQ_EMPTY(&asoc->sent_queue) &&
915163953Srrs		    (asoc->stream_queue_cnt == 0)) {
916163953Srrs			if (asoc->locked_on_sending) {
917163953Srrs				goto abort_anyway;
918163953Srrs			}
919163953Srrs			/* there is nothing queued to send, so I'm done... */
920163953Srrs			if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) {
921163953Srrs				/* only send SHUTDOWN the first time through */
922163953Srrs				sctp_stop_timers_for_shutdown(stcb);
923163953Srrs				sctp_send_shutdown(stcb,
924163953Srrs				    stcb->asoc.primary_destination);
925163953Srrs				sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3);
926166675Srrs				if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
927166675Srrs				    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
928166675Srrs					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
929166675Srrs				}
930163953Srrs				asoc->state = SCTP_STATE_SHUTDOWN_SENT;
931163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
932163953Srrs				    stcb->sctp_ep, stcb,
933163953Srrs				    asoc->primary_destination);
934163953Srrs				sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
935163953Srrs				    stcb->sctp_ep, stcb,
936163953Srrs				    asoc->primary_destination);
937163953Srrs			}
938163953Srrs		} else {
939163953Srrs			/*
940163953Srrs			 * we still got (or just got) data to send, so set
941163953Srrs			 * SHUTDOWN_PENDING
942163953Srrs			 */
943163953Srrs			asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
944163953Srrs			sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb,
945163953Srrs			    asoc->primary_destination);
946163953Srrs
947163953Srrs			if (asoc->locked_on_sending) {
948163953Srrs				/* Locked to send out the data */
949163953Srrs				struct sctp_stream_queue_pending *sp;
950163953Srrs
951163953Srrs				sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead);
952163953Srrs				if (sp == NULL) {
953169420Srrs					SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n",
954163953Srrs					    asoc->locked_on_sending->stream_no);
955163953Srrs				} else {
956163953Srrs					if ((sp->length == 0) && (sp->msg_is_complete == 0)) {
957163953Srrs						asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT;
958163953Srrs					}
959163953Srrs				}
960163953Srrs			}
961163953Srrs			if (TAILQ_EMPTY(&asoc->send_queue) &&
962163953Srrs			    TAILQ_EMPTY(&asoc->sent_queue) &&
963163953Srrs			    (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
964163953Srrs				struct mbuf *op_err;
965163953Srrs
966163953Srrs		abort_anyway:
967163953Srrs				op_err = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
968163953Srrs				    0, M_DONTWAIT, 1, MT_DATA);
969163953Srrs				if (op_err) {
970163953Srrs					/* Fill in the user initiated abort */
971163953Srrs					struct sctp_paramhdr *ph;
972163953Srrs					uint32_t *ippp;
973163953Srrs
974165647Srrs					SCTP_BUF_LEN(op_err) =
975163953Srrs					    sizeof(struct sctp_paramhdr) + sizeof(uint32_t);
976163953Srrs					ph = mtod(op_err,
977163953Srrs					    struct sctp_paramhdr *);
978163953Srrs					ph->param_type = htons(
979163953Srrs					    SCTP_CAUSE_USER_INITIATED_ABT);
980165647Srrs					ph->param_length = htons(SCTP_BUF_LEN(op_err));
981163953Srrs					ippp = (uint32_t *) (ph + 1);
982165220Srrs					*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
983163953Srrs				}
984165220Srrs				stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
985163953Srrs				sctp_abort_an_association(stcb->sctp_ep, stcb,
986163953Srrs				    SCTP_RESPONSE_TO_USER_REQ,
987163953Srrs				    op_err);
988163953Srrs				goto skip_unlock;
989163953Srrs			}
990163953Srrs		}
991163953Srrs		SCTP_TCB_UNLOCK(stcb);
992163953Srrs	}
993163953Srrsskip_unlock:
994163953Srrs	SCTP_INP_RUNLOCK(inp);
995163953Srrs	return 0;
996163953Srrs}
997163953Srrs
998163953Srrs/*
999163953Srrs * copies a "user" presentable address and removes embedded scope, etc.
1000163953Srrs * returns 0 on success, 1 on error
1001163953Srrs */
1002163953Srrsstatic uint32_t
1003163953Srrssctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
1004163953Srrs{
1005163953Srrs	struct sockaddr_in6 lsa6;
1006163953Srrs
1007163953Srrs	sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa,
1008163953Srrs	    &lsa6);
1009163953Srrs	memcpy(ss, sa, sa->sa_len);
1010163953Srrs	return (0);
1011163953Srrs}
1012163953Srrs
1013163953Srrs
1014163953Srrs
1015166675Srrsstatic size_t
1016168124Srrssctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
1017163953Srrs    struct sctp_tcb *stcb,
1018166675Srrs    size_t limit,
1019167598Srrs    struct sockaddr_storage *sas,
1020167598Srrs    uint32_t vrf_id)
1021163953Srrs{
1022167598Srrs	struct sctp_ifn *sctp_ifn;
1023167598Srrs	struct sctp_ifa *sctp_ifa;
1024166675Srrs	int loopback_scope, ipv4_local_scope, local_scope, site_scope;
1025166675Srrs	size_t actual;
1026163953Srrs	int ipv4_addr_legal, ipv6_addr_legal;
1027167598Srrs	struct sctp_vrf *vrf;
1028163953Srrs
1029163953Srrs	actual = 0;
1030163953Srrs	if (limit <= 0)
1031163953Srrs		return (actual);
1032163953Srrs
1033163953Srrs	if (stcb) {
1034163953Srrs		/* Turn on all the appropriate scope */
1035163953Srrs		loopback_scope = stcb->asoc.loopback_scope;
1036163953Srrs		ipv4_local_scope = stcb->asoc.ipv4_local_scope;
1037163953Srrs		local_scope = stcb->asoc.local_scope;
1038163953Srrs		site_scope = stcb->asoc.site_scope;
1039163953Srrs	} else {
1040163953Srrs		/* Turn on ALL scope, since we look at the EP */
1041163953Srrs		loopback_scope = ipv4_local_scope = local_scope =
1042163953Srrs		    site_scope = 1;
1043163953Srrs	}
1044163953Srrs	ipv4_addr_legal = ipv6_addr_legal = 0;
1045163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1046163953Srrs		ipv6_addr_legal = 1;
1047166023Srrs		if (SCTP_IPV6_V6ONLY(inp) == 0) {
1048163953Srrs			ipv4_addr_legal = 1;
1049163953Srrs		}
1050163953Srrs	} else {
1051163953Srrs		ipv4_addr_legal = 1;
1052163953Srrs	}
1053167598Srrs	vrf = sctp_find_vrf(vrf_id);
1054167598Srrs	if (vrf == NULL) {
1055167598Srrs		return (0);
1056167598Srrs	}
1057163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1058167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1059163953Srrs			if ((loopback_scope == 0) &&
1060167598Srrs			    SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
1061163953Srrs				/* Skip loopback if loopback_scope not set */
1062163953Srrs				continue;
1063163953Srrs			}
1064167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1065163953Srrs				if (stcb) {
1066163953Srrs					/*
1067163953Srrs					 * For the BOUND-ALL case, the list
1068163953Srrs					 * associated with a TCB is Always
1069163953Srrs					 * considered a reverse list.. i.e.
1070163953Srrs					 * it lists addresses that are NOT
1071163953Srrs					 * part of the association. If this
1072163953Srrs					 * is one of those we must skip it.
1073163953Srrs					 */
1074163953Srrs					if (sctp_is_addr_restricted(stcb,
1075167598Srrs					    sctp_ifa)) {
1076163953Srrs						continue;
1077163953Srrs					}
1078163953Srrs				}
1079167598Srrs				if ((sctp_ifa->address.sa.sa_family == AF_INET) &&
1080163953Srrs				    (ipv4_addr_legal)) {
1081163953Srrs					struct sockaddr_in *sin;
1082163953Srrs
1083167598Srrs					sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
1084163953Srrs					if (sin->sin_addr.s_addr == 0) {
1085163953Srrs						/*
1086163953Srrs						 * we skip unspecifed
1087163953Srrs						 * addresses
1088163953Srrs						 */
1089163953Srrs						continue;
1090163953Srrs					}
1091163953Srrs					if ((ipv4_local_scope == 0) &&
1092163953Srrs					    (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
1093163953Srrs						continue;
1094163953Srrs					}
1095163953Srrs					if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) {
1096163953Srrs						in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas);
1097163953Srrs						((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1098163953Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6));
1099163953Srrs						actual += sizeof(sizeof(struct sockaddr_in6));
1100163953Srrs					} else {
1101163953Srrs						memcpy(sas, sin, sizeof(*sin));
1102163953Srrs						((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport;
1103163953Srrs						sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin));
1104163953Srrs						actual += sizeof(*sin);
1105163953Srrs					}
1106163953Srrs					if (actual >= limit) {
1107163953Srrs						return (actual);
1108163953Srrs					}
1109167598Srrs				} else if ((sctp_ifa->address.sa.sa_family == AF_INET6) &&
1110163953Srrs				    (ipv6_addr_legal)) {
1111163953Srrs					struct sockaddr_in6 *sin6;
1112163953Srrs
1113167598Srrs					sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
1114163953Srrs					if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1115163953Srrs						/*
1116163953Srrs						 * we skip unspecifed
1117163953Srrs						 * addresses
1118163953Srrs						 */
1119163953Srrs						continue;
1120163953Srrs					}
1121163953Srrs					if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1122163953Srrs						if (local_scope == 0)
1123163953Srrs							continue;
1124163953Srrs						if (sin6->sin6_scope_id == 0) {
1125163953Srrs							if (sa6_recoverscope(sin6) != 0)
1126163953Srrs								/*
1127163953Srrs								 * bad link
1128163953Srrs								 * local
1129163953Srrs								 * address
1130163953Srrs								 */
1131163953Srrs								continue;
1132163953Srrs						}
1133163953Srrs					}
1134163953Srrs					if ((site_scope == 0) &&
1135163953Srrs					    (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
1136163953Srrs						continue;
1137163953Srrs					}
1138163953Srrs					memcpy(sas, sin6, sizeof(*sin6));
1139163953Srrs					((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1140163953Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6));
1141163953Srrs					actual += sizeof(*sin6);
1142163953Srrs					if (actual >= limit) {
1143163953Srrs						return (actual);
1144163953Srrs					}
1145163953Srrs				}
1146163953Srrs			}
1147163953Srrs		}
1148163953Srrs	} else {
1149163953Srrs		struct sctp_laddr *laddr;
1150163953Srrs
1151167598Srrs		/* The list is a NEGATIVE list */
1152167598Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1153167598Srrs			if (stcb) {
1154167598Srrs				if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
1155163953Srrs					continue;
1156163953Srrs				}
1157163953Srrs			}
1158167598Srrs			if (sctp_fill_user_address(sas, &laddr->ifa->address.sa))
1159167598Srrs				continue;
1160167598Srrs
1161167598Srrs			((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport;
1162167598Srrs			sas = (struct sockaddr_storage *)((caddr_t)sas +
1163167598Srrs			    laddr->ifa->address.sa.sa_len);
1164167598Srrs			actual += laddr->ifa->address.sa.sa_len;
1165167598Srrs			if (actual >= limit) {
1166167598Srrs				return (actual);
1167163953Srrs			}
1168163953Srrs		}
1169163953Srrs	}
1170163953Srrs	return (actual);
1171163953Srrs}
1172163953Srrs
1173168124Srrsstatic size_t
1174168124Srrssctp_fill_up_addresses(struct sctp_inpcb *inp,
1175168124Srrs    struct sctp_tcb *stcb,
1176168124Srrs    size_t limit,
1177168124Srrs    struct sockaddr_storage *sas)
1178168124Srrs{
1179168124Srrs	size_t size = 0;
1180168124Srrs
1181168124Srrs	/* fill up addresses for the endpoint's default vrf */
1182168124Srrs	size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
1183168124Srrs	    inp->def_vrf_id);
1184168124Srrs	return (size);
1185168124Srrs}
1186168124Srrs
1187163953Srrsstatic int
1188168124Srrssctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
1189163953Srrs{
1190163953Srrs	int cnt = 0;
1191167598Srrs	struct sctp_vrf *vrf = NULL;
1192163953Srrs
1193163953Srrs	/*
1194163953Srrs	 * In both sub-set bound an bound_all cases we return the MAXIMUM
1195163953Srrs	 * number of addresses that you COULD get. In reality the sub-set
1196163953Srrs	 * bound may have an exclusion list for a given TCB OR in the
1197163953Srrs	 * bound-all case a TCB may NOT include the loopback or other
1198163953Srrs	 * addresses as well.
1199163953Srrs	 */
1200167598Srrs	vrf = sctp_find_vrf(vrf_id);
1201167598Srrs	if (vrf == NULL) {
1202167598Srrs		return (0);
1203167598Srrs	}
1204163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1205167598Srrs		struct sctp_ifn *sctp_ifn;
1206167598Srrs		struct sctp_ifa *sctp_ifa;
1207163953Srrs
1208167598Srrs		LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
1209167598Srrs			LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
1210163953Srrs				/* Count them if they are the right type */
1211167598Srrs				if (sctp_ifa->address.sa.sa_family == AF_INET) {
1212163953Srrs					if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)
1213163953Srrs						cnt += sizeof(struct sockaddr_in6);
1214163953Srrs					else
1215163953Srrs						cnt += sizeof(struct sockaddr_in);
1216163953Srrs
1217167598Srrs				} else if (sctp_ifa->address.sa.sa_family == AF_INET6)
1218163953Srrs					cnt += sizeof(struct sockaddr_in6);
1219163953Srrs			}
1220163953Srrs		}
1221163953Srrs	} else {
1222163953Srrs		struct sctp_laddr *laddr;
1223163953Srrs
1224163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1225167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET) {
1226163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)
1227163953Srrs					cnt += sizeof(struct sockaddr_in6);
1228163953Srrs				else
1229163953Srrs					cnt += sizeof(struct sockaddr_in);
1230163953Srrs
1231167598Srrs			} else if (laddr->ifa->address.sa.sa_family == AF_INET6)
1232163953Srrs				cnt += sizeof(struct sockaddr_in6);
1233163953Srrs		}
1234163953Srrs	}
1235163953Srrs	return (cnt);
1236163953Srrs}
1237163953Srrs
1238168124Srrsstatic int
1239168124Srrssctp_count_max_addresses(struct sctp_inpcb *inp)
1240168124Srrs{
1241168124Srrs	int cnt = 0;
1242166675Srrs
1243168124Srrs	/* count addresses for the endpoint's default VRF */
1244168124Srrs	cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
1245168124Srrs	return (cnt);
1246168124Srrs}
1247168124Srrs
1248163953Srrsstatic int
1249166675Srrssctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
1250166675Srrs    size_t optsize, void *p, int delay)
1251163953Srrs{
1252163953Srrs	int error = 0;
1253163953Srrs	int creat_lock_on = 0;
1254163953Srrs	struct sctp_tcb *stcb = NULL;
1255163953Srrs	struct sockaddr *sa;
1256169352Srrs	int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
1257169352Srrs	int added = 0;
1258167598Srrs	uint32_t vrf_id;
1259167598Srrs	sctp_assoc_t *a_id;
1260163953Srrs
1261169420Srrs	SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
1262163953Srrs
1263163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1264163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1265163953Srrs		/* We are already connected AND the TCP model */
1266163953Srrs		return (EADDRINUSE);
1267163953Srrs	}
1268163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) {
1269163953Srrs		return (EINVAL);
1270163953Srrs	}
1271163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1272163953Srrs		SCTP_INP_RLOCK(inp);
1273163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1274163953Srrs		SCTP_INP_RUNLOCK(inp);
1275163953Srrs	}
1276163953Srrs	if (stcb) {
1277163953Srrs		return (EALREADY);
1278163953Srrs	}
1279163953Srrs	SCTP_INP_INCR_REF(inp);
1280163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
1281163953Srrs	creat_lock_on = 1;
1282163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
1283163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
1284163953Srrs		error = EFAULT;
1285163953Srrs		goto out_now;
1286163953Srrs	}
1287166675Srrs	totaddrp = (int *)optval;
1288163953Srrs	totaddr = *totaddrp;
1289163953Srrs	sa = (struct sockaddr *)(totaddrp + 1);
1290169352Srrs	stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)));
1291169352Srrs	if (stcb != NULL) {
1292169352Srrs		/* Already have or am bring up an association */
1293169352Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1294169352Srrs		creat_lock_on = 0;
1295169352Srrs		SCTP_TCB_UNLOCK(stcb);
1296169352Srrs		error = EALREADY;
1297169352Srrs		goto out_now;
1298163953Srrs	}
1299163953Srrs#ifdef INET6
1300163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
1301163953Srrs	    (num_v6 > 0)) {
1302163953Srrs		error = EINVAL;
1303163953Srrs		goto out_now;
1304163953Srrs	}
1305163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
1306163953Srrs	    (num_v4 > 0)) {
1307163953Srrs		struct in6pcb *inp6;
1308163953Srrs
1309163953Srrs		inp6 = (struct in6pcb *)inp;
1310166023Srrs		if (SCTP_IPV6_V6ONLY(inp6)) {
1311163953Srrs			/*
1312163953Srrs			 * if IPV6_V6ONLY flag, ignore connections destined
1313163953Srrs			 * to a v4 addr or v4-mapped addr
1314163953Srrs			 */
1315163953Srrs			error = EINVAL;
1316163953Srrs			goto out_now;
1317163953Srrs		}
1318163953Srrs	}
1319163953Srrs#endif				/* INET6 */
1320163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1321163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
1322163953Srrs		/* Bind a ephemeral port */
1323163953Srrs		error = sctp_inpcb_bind(so, NULL, p);
1324163953Srrs		if (error) {
1325163953Srrs			goto out_now;
1326163953Srrs		}
1327163953Srrs	}
1328167695Srrs	/* FIX ME: do we want to pass in a vrf on the connect call? */
1329167695Srrs	vrf_id = inp->def_vrf_id;
1330167695Srrs
1331163953Srrs	/* We are GOOD to go */
1332167598Srrs	stcb = sctp_aloc_assoc(inp, sa, 1, &error, 0, vrf_id);
1333163953Srrs	if (stcb == NULL) {
1334163953Srrs		/* Gak! no memory */
1335163953Srrs		goto out_now;
1336163953Srrs	}
1337169352Srrs	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
1338163953Srrs	/* move to second address */
1339163953Srrs	if (sa->sa_family == AF_INET)
1340163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
1341163953Srrs	else
1342163953Srrs		sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
1343163953Srrs
1344169352Srrs	added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
1345167598Srrs	/* Fill in the return id */
1346167598Srrs	a_id = (sctp_assoc_t *) optval;
1347167598Srrs	*a_id = sctp_get_associd(stcb);
1348163953Srrs
1349163953Srrs	/* initialize authentication parameters for the assoc */
1350163953Srrs	sctp_initialize_auth_params(inp, stcb);
1351163953Srrs
1352163953Srrs	if (delay) {
1353163953Srrs		/* doing delayed connection */
1354163953Srrs		stcb->asoc.delayed_connection = 1;
1355163953Srrs		sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
1356163953Srrs	} else {
1357169378Srrs		(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1358163953Srrs		sctp_send_initiate(inp, stcb);
1359163953Srrs	}
1360163953Srrs	SCTP_TCB_UNLOCK(stcb);
1361163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1362163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1363163953Srrs		/* Set the connected flag so we can queue data */
1364163953Srrs		soisconnecting(so);
1365163953Srrs	}
1366163953Srrsout_now:
1367163953Srrs	if (creat_lock_on)
1368163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
1369163953Srrs	SCTP_INP_DECR_REF(inp);
1370163953Srrs	return error;
1371163953Srrs}
1372163953Srrs
1373169420Srrs#define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
1374166675Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { \
1375166675Srrs		SCTP_INP_RLOCK(inp); \
1376166675Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list); \
1377166675Srrs		if (stcb) \
1378166675Srrs			SCTP_TCB_LOCK(stcb); \
1379166675Srrs		SCTP_INP_RUNLOCK(inp); \
1380166675Srrs	} else if (assoc_id != 0) { \
1381166675Srrs		stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
1382166675Srrs		if (stcb == NULL) { \
1383166675Srrs			error = ENOENT; \
1384166675Srrs			break; \
1385166675Srrs		} \
1386166675Srrs	} else { \
1387166675Srrs		stcb = NULL; \
1388169420Srrs        } \
1389169420Srrs  }
1390163953Srrs
1391169420Srrs
1392169420Srrs#define SCTP_CHECK_AND_CAST(destp, srcp, type, size)  {\
1393166675Srrs	if (size < sizeof(type)) { \
1394166675Srrs		error = EINVAL; \
1395166675Srrs		break; \
1396166675Srrs	} else { \
1397166675Srrs		destp = (type *)srcp; \
1398169420Srrs	} \
1399169420Srrs      }
1400163953Srrs
1401163953Srrsstatic int
1402166675Srrssctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
1403166675Srrs    void *p)
1404163953Srrs{
1405163953Srrs	struct sctp_inpcb *inp;
1406166675Srrs	int error, val = 0;
1407163953Srrs	struct sctp_tcb *stcb = NULL;
1408163953Srrs
1409166675Srrs	if (optval == NULL) {
1410166675Srrs		return (EINVAL);
1411166675Srrs	}
1412163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1413163953Srrs	if (inp == 0)
1414163953Srrs		return EINVAL;
1415163953Srrs	error = 0;
1416163953Srrs
1417166675Srrs	switch (optname) {
1418163953Srrs	case SCTP_NODELAY:
1419163953Srrs	case SCTP_AUTOCLOSE:
1420163953Srrs	case SCTP_EXPLICIT_EOR:
1421163953Srrs	case SCTP_AUTO_ASCONF:
1422163953Srrs	case SCTP_DISABLE_FRAGMENTS:
1423163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
1424163953Srrs	case SCTP_USE_EXT_RCVINFO:
1425163953Srrs		SCTP_INP_RLOCK(inp);
1426166675Srrs		switch (optname) {
1427163953Srrs		case SCTP_DISABLE_FRAGMENTS:
1428166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
1429163953Srrs			break;
1430163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
1431166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
1432163953Srrs			break;
1433163953Srrs		case SCTP_AUTO_ASCONF:
1434166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
1435163953Srrs			break;
1436163953Srrs		case SCTP_EXPLICIT_EOR:
1437166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
1438163953Srrs			break;
1439163953Srrs		case SCTP_NODELAY:
1440166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
1441163953Srrs			break;
1442163953Srrs		case SCTP_USE_EXT_RCVINFO:
1443166675Srrs			val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
1444163953Srrs			break;
1445163953Srrs		case SCTP_AUTOCLOSE:
1446163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
1447166675Srrs				val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time);
1448163953Srrs			else
1449166675Srrs				val = 0;
1450163953Srrs			break;
1451163953Srrs
1452163953Srrs		default:
1453163953Srrs			error = ENOPROTOOPT;
1454163953Srrs		}		/* end switch (sopt->sopt_name) */
1455166675Srrs		if (optname != SCTP_AUTOCLOSE) {
1456163953Srrs			/* make it an "on/off" value */
1457166675Srrs			val = (val != 0);
1458163953Srrs		}
1459166675Srrs		if (*optsize < sizeof(val)) {
1460163953Srrs			error = EINVAL;
1461163953Srrs		}
1462163953Srrs		SCTP_INP_RUNLOCK(inp);
1463163953Srrs		if (error == 0) {
1464163953Srrs			/* return the option value */
1465166675Srrs			*(int *)optval = val;
1466166675Srrs			*optsize = sizeof(val);
1467163953Srrs		}
1468163953Srrs		break;
1469167598Srrs
1470163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
1471163953Srrs		{
1472166675Srrs			uint32_t *value;
1473166675Srrs
1474166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1475166675Srrs			*value = inp->partial_delivery_point;
1476166675Srrs			*optsize = sizeof(uint32_t);
1477163953Srrs		}
1478163953Srrs		break;
1479163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
1480163953Srrs		{
1481166675Srrs			uint32_t *value;
1482166675Srrs
1483166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1484168943Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
1485168943Srrs				if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
1486168943Srrs					*value = SCTP_FRAG_LEVEL_2;
1487168943Srrs				} else {
1488168943Srrs					*value = SCTP_FRAG_LEVEL_1;
1489168943Srrs				}
1490168943Srrs			} else {
1491168943Srrs				*value = SCTP_FRAG_LEVEL_0;
1492168943Srrs			}
1493166675Srrs			*optsize = sizeof(uint32_t);
1494163953Srrs		}
1495163953Srrs		break;
1496163953Srrs	case SCTP_CMT_ON_OFF:
1497163953Srrs		{
1498166675Srrs			struct sctp_assoc_value *av;
1499166675Srrs
1500166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1501166675Srrs			if (sctp_cmt_on_off) {
1502166675Srrs				SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1503166675Srrs				if (stcb) {
1504166675Srrs					av->assoc_value = stcb->asoc.sctp_cmt_on_off;
1505166675Srrs					SCTP_TCB_UNLOCK(stcb);
1506166675Srrs
1507166675Srrs				} else {
1508166675Srrs					error = ENOTCONN;
1509166675Srrs				}
1510166675Srrs			} else {
1511166675Srrs				error = ENOPROTOOPT;
1512163953Srrs			}
1513166675Srrs			*optsize = sizeof(*av);
1514163953Srrs		}
1515163953Srrs		break;
1516163953Srrs	case SCTP_GET_ADDR_LEN:
1517163953Srrs		{
1518163953Srrs			struct sctp_assoc_value *av;
1519163953Srrs
1520166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1521163953Srrs			error = EINVAL;
1522167598Srrs#ifdef INET
1523163953Srrs			if (av->assoc_value == AF_INET) {
1524163953Srrs				av->assoc_value = sizeof(struct sockaddr_in);
1525163953Srrs				error = 0;
1526163953Srrs			}
1527163953Srrs#endif
1528167598Srrs#ifdef INET6
1529163953Srrs			if (av->assoc_value == AF_INET6) {
1530163953Srrs				av->assoc_value = sizeof(struct sockaddr_in6);
1531163953Srrs				error = 0;
1532163953Srrs			}
1533163953Srrs#endif
1534166675Srrs			*optsize = sizeof(*av);
1535163953Srrs		}
1536163953Srrs		break;
1537163953Srrs	case SCTP_GET_ASOC_ID_LIST:
1538163953Srrs		{
1539163953Srrs			struct sctp_assoc_ids *ids;
1540163953Srrs			int cnt, at;
1541163953Srrs			uint16_t orig;
1542163953Srrs
1543166675Srrs			SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
1544163953Srrs			cnt = 0;
1545163953Srrs			SCTP_INP_RLOCK(inp);
1546163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
1547163953Srrs			if (stcb == NULL) {
1548163953Srrs		none_out_now:
1549163953Srrs				ids->asls_numb_present = 0;
1550163953Srrs				ids->asls_more_to_get = 0;
1551163953Srrs				SCTP_INP_RUNLOCK(inp);
1552163953Srrs				break;
1553163953Srrs			}
1554163953Srrs			orig = ids->asls_assoc_start;
1555163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
1556163953Srrs			while (orig) {
1557163953Srrs				stcb = LIST_NEXT(stcb, sctp_tcblist);
1558163953Srrs				orig--;
1559163953Srrs				cnt--;
1560163953Srrs				if (stcb == NULL)
1561163953Srrs					goto none_out_now;
1562163953Srrs			}
1563163953Srrs			if (stcb == NULL)
1564163953Srrs				goto none_out_now;
1565163953Srrs
1566163953Srrs			at = 0;
1567163953Srrs			ids->asls_numb_present = 0;
1568163953Srrs			ids->asls_more_to_get = 1;
1569163953Srrs			while (at < MAX_ASOC_IDS_RET) {
1570163953Srrs				ids->asls_assoc_id[at] = sctp_get_associd(stcb);
1571163953Srrs				at++;
1572163953Srrs				ids->asls_numb_present++;
1573163953Srrs				stcb = LIST_NEXT(stcb, sctp_tcblist);
1574163953Srrs				if (stcb == NULL) {
1575163953Srrs					ids->asls_more_to_get = 0;
1576163953Srrs					break;
1577163953Srrs				}
1578163953Srrs			}
1579163953Srrs			SCTP_INP_RUNLOCK(inp);
1580163953Srrs		}
1581163953Srrs		break;
1582163953Srrs	case SCTP_CONTEXT:
1583163953Srrs		{
1584163953Srrs			struct sctp_assoc_value *av;
1585163953Srrs
1586166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1587166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1588166675Srrs
1589166675Srrs			if (stcb) {
1590166675Srrs				av->assoc_value = stcb->asoc.context;
1591166675Srrs				SCTP_TCB_UNLOCK(stcb);
1592163953Srrs			} else {
1593166675Srrs				SCTP_INP_RLOCK(inp);
1594163953Srrs				av->assoc_value = inp->sctp_context;
1595166675Srrs				SCTP_INP_RUNLOCK(inp);
1596163953Srrs			}
1597166675Srrs			*optsize = sizeof(*av);
1598163953Srrs		}
1599163953Srrs		break;
1600167598Srrs	case SCTP_VRF_ID:
1601167598Srrs		{
1602167598Srrs			uint32_t *vrf_id;
1603167598Srrs
1604167598Srrs			SCTP_CHECK_AND_CAST(vrf_id, optval, uint32_t, *optsize);
1605167598Srrs			*vrf_id = inp->def_vrf_id;
1606167598Srrs			break;
1607167598Srrs		}
1608167598Srrs	case SCTP_GET_ASOC_VRF:
1609167598Srrs		{
1610167598Srrs			struct sctp_assoc_value *id;
1611167598Srrs
1612167598Srrs			SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
1613167598Srrs			SCTP_FIND_STCB(inp, stcb, id->assoc_id);
1614167598Srrs			if (stcb == NULL) {
1615167598Srrs				error = EINVAL;
1616167598Srrs				break;
1617167598Srrs			}
1618167598Srrs			id->assoc_value = stcb->asoc.vrf_id;
1619167598Srrs			break;
1620167598Srrs		}
1621167598Srrs	case SCTP_GET_VRF_IDS:
1622167598Srrs		{
1623167598Srrs			error = EOPNOTSUPP;
1624167598Srrs			break;
1625167598Srrs		}
1626163953Srrs	case SCTP_GET_NONCE_VALUES:
1627163953Srrs		{
1628163953Srrs			struct sctp_get_nonce_values *gnv;
1629163953Srrs
1630166675Srrs			SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
1631166675Srrs			SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
1632166675Srrs
1633166675Srrs			if (stcb) {
1634163953Srrs				gnv->gn_peers_tag = stcb->asoc.peer_vtag;
1635163953Srrs				gnv->gn_local_tag = stcb->asoc.my_vtag;
1636163953Srrs				SCTP_TCB_UNLOCK(stcb);
1637166675Srrs			} else {
1638166675Srrs				error = ENOTCONN;
1639163953Srrs			}
1640166675Srrs			*optsize = sizeof(*gnv);
1641163953Srrs		}
1642163953Srrs		break;
1643163953Srrs	case SCTP_DELAYED_ACK_TIME:
1644163953Srrs		{
1645163953Srrs			struct sctp_assoc_value *tm;
1646163953Srrs
1647166675Srrs			SCTP_CHECK_AND_CAST(tm, optval, struct sctp_assoc_value, *optsize);
1648166675Srrs			SCTP_FIND_STCB(inp, stcb, tm->assoc_id);
1649163953Srrs
1650166675Srrs			if (stcb) {
1651166675Srrs				tm->assoc_value = stcb->asoc.delayed_ack;
1652166675Srrs				SCTP_TCB_UNLOCK(stcb);
1653166675Srrs			} else {
1654163953Srrs				SCTP_INP_RLOCK(inp);
1655166675Srrs				tm->assoc_value = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
1656163953Srrs				SCTP_INP_RUNLOCK(inp);
1657163953Srrs			}
1658166675Srrs			*optsize = sizeof(*tm);
1659163953Srrs		}
1660163953Srrs		break;
1661163953Srrs
1662163953Srrs	case SCTP_GET_SNDBUF_USE:
1663166675Srrs		{
1664163953Srrs			struct sctp_sockstat *ss;
1665163953Srrs
1666166675Srrs			SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
1667166675Srrs			SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
1668166675Srrs
1669166675Srrs			if (stcb) {
1670166675Srrs				ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
1671166675Srrs				ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
1672166675Srrs				    stcb->asoc.size_on_all_streams);
1673166675Srrs				SCTP_TCB_UNLOCK(stcb);
1674166675Srrs			} else {
1675163953Srrs				error = ENOTCONN;
1676163953Srrs			}
1677166675Srrs			*optsize = sizeof(struct sctp_sockstat);
1678163953Srrs		}
1679163953Srrs		break;
1680163953Srrs	case SCTP_MAXBURST:
1681163953Srrs		{
1682166675Srrs			uint8_t *value;
1683163953Srrs
1684166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize);
1685166675Srrs
1686163953Srrs			SCTP_INP_RLOCK(inp);
1687166675Srrs			*value = inp->sctp_ep.max_burst;
1688163953Srrs			SCTP_INP_RUNLOCK(inp);
1689166675Srrs			*optsize = sizeof(uint8_t);
1690163953Srrs		}
1691163953Srrs		break;
1692163953Srrs	case SCTP_MAXSEG:
1693163953Srrs		{
1694167598Srrs			struct sctp_assoc_value *av;
1695163953Srrs			int ovh;
1696163953Srrs
1697167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
1698168859Srrs			if (av->assoc_id) {
1699168859Srrs				SCTP_FIND_STCB(inp, stcb, av->assoc_id);
1700168859Srrs			} else {
1701168859Srrs				stcb = NULL;
1702168859Srrs			}
1703163953Srrs
1704167598Srrs			if (stcb) {
1705167598Srrs				av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
1706167598Srrs				SCTP_TCB_UNLOCK(stcb);
1707163953Srrs			} else {
1708167598Srrs				SCTP_INP_RLOCK(inp);
1709167598Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1710167598Srrs					ovh = SCTP_MED_OVERHEAD;
1711167598Srrs				} else {
1712167598Srrs					ovh = SCTP_MED_V4_OVERHEAD;
1713167598Srrs				}
1714167598Srrs				av->assoc_value = inp->sctp_frag_point - ovh;
1715167598Srrs				SCTP_INP_RUNLOCK(inp);
1716163953Srrs			}
1717167598Srrs			*optsize = sizeof(struct sctp_assoc_value);
1718163953Srrs		}
1719163953Srrs		break;
1720163953Srrs	case SCTP_GET_STAT_LOG:
1721163953Srrs#ifdef SCTP_STAT_LOGGING
1722167598Srrs		error = sctp_fill_stat_log(optval, optsize);
1723167598Srrs#else
1724163953Srrs		error = EOPNOTSUPP;
1725163953Srrs#endif
1726163953Srrs		break;
1727163953Srrs	case SCTP_EVENTS:
1728163953Srrs		{
1729163953Srrs			struct sctp_event_subscribe *events;
1730163953Srrs
1731166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
1732163953Srrs			memset(events, 0, sizeof(*events));
1733163953Srrs			SCTP_INP_RLOCK(inp);
1734163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
1735163953Srrs				events->sctp_data_io_event = 1;
1736163953Srrs
1737163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
1738163953Srrs				events->sctp_association_event = 1;
1739163953Srrs
1740163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
1741163953Srrs				events->sctp_address_event = 1;
1742163953Srrs
1743163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
1744163953Srrs				events->sctp_send_failure_event = 1;
1745163953Srrs
1746163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
1747163953Srrs				events->sctp_peer_error_event = 1;
1748163953Srrs
1749163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
1750163953Srrs				events->sctp_shutdown_event = 1;
1751163953Srrs
1752163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
1753163953Srrs				events->sctp_partial_delivery_event = 1;
1754163953Srrs
1755163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
1756163953Srrs				events->sctp_adaptation_layer_event = 1;
1757163953Srrs
1758163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
1759163953Srrs				events->sctp_authentication_event = 1;
1760163953Srrs
1761163953Srrs			if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
1762163953Srrs				events->sctp_stream_reset_events = 1;
1763163953Srrs			SCTP_INP_RUNLOCK(inp);
1764166675Srrs			*optsize = sizeof(struct sctp_event_subscribe);
1765163953Srrs		}
1766163953Srrs		break;
1767163953Srrs
1768163953Srrs	case SCTP_ADAPTATION_LAYER:
1769166675Srrs		{
1770166675Srrs			uint32_t *value;
1771166675Srrs
1772166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1773166675Srrs
1774166675Srrs			SCTP_INP_RLOCK(inp);
1775166675Srrs			*value = inp->sctp_ep.adaptation_layer_indicator;
1776166675Srrs			SCTP_INP_RUNLOCK(inp);
1777166675Srrs			*optsize = sizeof(uint32_t);
1778163953Srrs		}
1779163953Srrs		break;
1780163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
1781166675Srrs		{
1782166675Srrs			uint32_t *value;
1783166675Srrs
1784166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1785166675Srrs			SCTP_INP_RLOCK(inp);
1786166675Srrs			*value = inp->sctp_ep.initial_sequence_debug;
1787166675Srrs			SCTP_INP_RUNLOCK(inp);
1788166675Srrs			*optsize = sizeof(uint32_t);
1789163953Srrs		}
1790163953Srrs		break;
1791163953Srrs	case SCTP_GET_LOCAL_ADDR_SIZE:
1792166675Srrs		{
1793166675Srrs			uint32_t *value;
1794166675Srrs
1795166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1796166675Srrs			SCTP_INP_RLOCK(inp);
1797168124Srrs			*value = sctp_count_max_addresses(inp);
1798166675Srrs			SCTP_INP_RUNLOCK(inp);
1799166675Srrs			*optsize = sizeof(uint32_t);
1800163953Srrs		}
1801163953Srrs		break;
1802163953Srrs	case SCTP_GET_REMOTE_ADDR_SIZE:
1803163953Srrs		{
1804166675Srrs			uint32_t *value;
1805166675Srrs			size_t size;
1806163953Srrs			struct sctp_nets *net;
1807163953Srrs
1808166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
1809166675Srrs			/* FIXME MT: change to sctp_assoc_value? */
1810166675Srrs			SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
1811166675Srrs
1812166675Srrs			if (stcb) {
1813166675Srrs				size = 0;
1814166675Srrs				/* Count the sizes */
1815166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1816166675Srrs					if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
1817166675Srrs					    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
1818166675Srrs						size += sizeof(struct sockaddr_in6);
1819166675Srrs					} else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
1820166675Srrs						size += sizeof(struct sockaddr_in);
1821166675Srrs					} else {
1822166675Srrs						/* huh */
1823166675Srrs						break;
1824166675Srrs					}
1825163953Srrs				}
1826166675Srrs				SCTP_TCB_UNLOCK(stcb);
1827166675Srrs				*value = (uint32_t) size;
1828166675Srrs			} else {
1829166675Srrs				error = ENOTCONN;
1830163953Srrs			}
1831166675Srrs			*optsize = sizeof(uint32_t);
1832163953Srrs		}
1833163953Srrs		break;
1834163953Srrs	case SCTP_GET_PEER_ADDRESSES:
1835163953Srrs		/*
1836163953Srrs		 * Get the address information, an array is passed in to
1837163953Srrs		 * fill up we pack it.
1838163953Srrs		 */
1839163953Srrs		{
1840166675Srrs			size_t cpsz, left;
1841163953Srrs			struct sockaddr_storage *sas;
1842163953Srrs			struct sctp_nets *net;
1843163953Srrs			struct sctp_getaddresses *saddr;
1844163953Srrs
1845166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
1846166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
1847163953Srrs
1848166675Srrs			if (stcb) {
1849166675Srrs				left = (*optsize) - sizeof(struct sctp_getaddresses);
1850166675Srrs				*optsize = sizeof(struct sctp_getaddresses);
1851166675Srrs				sas = (struct sockaddr_storage *)&saddr->addr[0];
1852166675Srrs
1853166675Srrs				TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1854166675Srrs					if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) ||
1855166675Srrs					    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET6)) {
1856166675Srrs						cpsz = sizeof(struct sockaddr_in6);
1857166675Srrs					} else if (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET) {
1858166675Srrs						cpsz = sizeof(struct sockaddr_in);
1859166675Srrs					} else {
1860166675Srrs						/* huh */
1861166675Srrs						break;
1862166675Srrs					}
1863166675Srrs					if (left < cpsz) {
1864166675Srrs						/* not enough room. */
1865166675Srrs						break;
1866166675Srrs					}
1867166675Srrs					if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_NEEDS_MAPPED_V4) &&
1868166675Srrs					    (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) {
1869166675Srrs						/* Must map the address */
1870166675Srrs						in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr,
1871166675Srrs						    (struct sockaddr_in6 *)sas);
1872166675Srrs					} else {
1873166675Srrs						memcpy(sas, &net->ro._l_addr, cpsz);
1874166675Srrs					}
1875166675Srrs					((struct sockaddr_in *)sas)->sin_port = stcb->rport;
1876166675Srrs
1877166675Srrs					sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz);
1878166675Srrs					left -= cpsz;
1879166675Srrs					*optsize += cpsz;
1880163953Srrs				}
1881166675Srrs				SCTP_TCB_UNLOCK(stcb);
1882166675Srrs			} else {
1883166675Srrs				error = ENOENT;
1884163953Srrs			}
1885163953Srrs		}
1886163953Srrs		break;
1887163953Srrs	case SCTP_GET_LOCAL_ADDRESSES:
1888163953Srrs		{
1889166675Srrs			size_t limit, actual;
1890163953Srrs			struct sockaddr_storage *sas;
1891163953Srrs			struct sctp_getaddresses *saddr;
1892163953Srrs
1893166675Srrs			SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
1894166675Srrs			SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
1895163953Srrs
1896163953Srrs			sas = (struct sockaddr_storage *)&saddr->addr[0];
1897166675Srrs			limit = *optsize - sizeof(sctp_assoc_t);
1898168124Srrs			actual = sctp_fill_up_addresses(inp, stcb, limit, sas);
1899163953Srrs			if (stcb)
1900163953Srrs				SCTP_TCB_UNLOCK(stcb);
1901166675Srrs			*optsize = sizeof(struct sockaddr_storage) + actual;
1902163953Srrs		}
1903163953Srrs		break;
1904163953Srrs	case SCTP_PEER_ADDR_PARAMS:
1905163953Srrs		{
1906163953Srrs			struct sctp_paddrparams *paddrp;
1907163953Srrs			struct sctp_nets *net;
1908163953Srrs
1909166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
1910166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
1911163953Srrs
1912163953Srrs			net = NULL;
1913166675Srrs			if (stcb) {
1914166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
1915166675Srrs			} else {
1916166675Srrs				/*
1917166675Srrs				 * We increment here since
1918166675Srrs				 * sctp_findassociation_ep_addr() wil do a
1919166675Srrs				 * decrement if it finds the stcb as long as
1920166675Srrs				 * the locked tcb (last argument) is NOT a
1921166675Srrs				 * TCB.. aka NULL.
1922166675Srrs				 */
1923166675Srrs				SCTP_INP_INCR_REF(inp);
1924166675Srrs				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL);
1925163953Srrs				if (stcb == NULL) {
1926166675Srrs					SCTP_INP_DECR_REF(inp);
1927163953Srrs				}
1928163953Srrs			}
1929163953Srrs
1930163953Srrs			if (stcb) {
1931163953Srrs				/* Applys to the specific association */
1932163953Srrs				paddrp->spp_flags = 0;
1933163953Srrs				if (net) {
1934163953Srrs					paddrp->spp_pathmaxrxt = net->failure_threshold;
1935163953Srrs					paddrp->spp_pathmtu = net->mtu;
1936163953Srrs					/* get flags for HB */
1937163953Srrs					if (net->dest_state & SCTP_ADDR_NOHB)
1938163953Srrs						paddrp->spp_flags |= SPP_HB_DISABLE;
1939163953Srrs					else
1940163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
1941163953Srrs					/* get flags for PMTU */
1942165647Srrs					if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
1943163953Srrs						paddrp->spp_flags |= SPP_PMTUD_ENABLE;
1944163953Srrs					} else {
1945163953Srrs						paddrp->spp_flags |= SPP_PMTUD_DISABLE;
1946163953Srrs					}
1947167598Srrs#ifdef INET
1948163953Srrs					if (net->ro._l_addr.sin.sin_family == AF_INET) {
1949163953Srrs						paddrp->spp_ipv4_tos = net->tos_flowlabel & 0x000000fc;
1950163953Srrs						paddrp->spp_flags |= SPP_IPV4_TOS;
1951163953Srrs					}
1952163953Srrs#endif
1953167598Srrs#ifdef INET6
1954163953Srrs					if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
1955163953Srrs						paddrp->spp_ipv6_flowlabel = net->tos_flowlabel;
1956163953Srrs						paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
1957163953Srrs					}
1958163953Srrs#endif
1959163953Srrs				} else {
1960163953Srrs					/*
1961163953Srrs					 * No destination so return default
1962163953Srrs					 * value
1963163953Srrs					 */
1964163953Srrs					paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
1965163953Srrs					paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc);
1966167598Srrs#ifdef INET
1967163953Srrs					paddrp->spp_ipv4_tos = stcb->asoc.default_tos & 0x000000fc;
1968163953Srrs					paddrp->spp_flags |= SPP_IPV4_TOS;
1969163953Srrs#endif
1970167598Srrs#ifdef INET6
1971163953Srrs					paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel;
1972163953Srrs					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
1973163953Srrs#endif
1974163953Srrs					/* default settings should be these */
1975163953Srrs					if (sctp_is_hb_timer_running(stcb)) {
1976163953Srrs						paddrp->spp_flags |= SPP_HB_ENABLE;
1977163953Srrs					}
1978163953Srrs				}
1979163953Srrs				paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
1980163953Srrs				paddrp->spp_assoc_id = sctp_get_associd(stcb);
1981163953Srrs				SCTP_TCB_UNLOCK(stcb);
1982163953Srrs			} else {
1983163953Srrs				/* Use endpoint defaults */
1984163953Srrs				SCTP_INP_RLOCK(inp);
1985163953Srrs				paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
1986163953Srrs				paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
1987163953Srrs				paddrp->spp_assoc_id = (sctp_assoc_t) 0;
1988163953Srrs				/* get inp's default */
1989167598Srrs#ifdef INET
1990163953Srrs				paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos;
1991163953Srrs				paddrp->spp_flags |= SPP_IPV4_TOS;
1992163953Srrs#endif
1993167598Srrs#ifdef INET6
1994163953Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
1995163953Srrs					paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
1996163953Srrs					paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
1997163953Srrs				}
1998163953Srrs#endif
1999163953Srrs				/* can't return this */
2000163953Srrs				paddrp->spp_pathmaxrxt = 0;
2001163953Srrs				paddrp->spp_pathmtu = 0;
2002163953Srrs				/* default behavior, no stcb */
2003167598Srrs				paddrp->spp_flags = SPP_HB_ENABLE | SPP_PMTUD_ENABLE;
2004163953Srrs
2005163953Srrs				SCTP_INP_RUNLOCK(inp);
2006163953Srrs			}
2007166675Srrs			*optsize = sizeof(struct sctp_paddrparams);
2008163953Srrs		}
2009163953Srrs		break;
2010163953Srrs	case SCTP_GET_PEER_ADDR_INFO:
2011163953Srrs		{
2012163953Srrs			struct sctp_paddrinfo *paddri;
2013163953Srrs			struct sctp_nets *net;
2014163953Srrs
2015166675Srrs			SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
2016166675Srrs			SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
2017166675Srrs
2018163953Srrs			net = NULL;
2019166675Srrs			if (stcb) {
2020166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address);
2021166675Srrs			} else {
2022166675Srrs				/*
2023166675Srrs				 * We increment here since
2024166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2025166675Srrs				 * decrement if it finds the stcb as long as
2026166675Srrs				 * the locked tcb (last argument) is NOT a
2027166675Srrs				 * TCB.. aka NULL.
2028166675Srrs				 */
2029166675Srrs				SCTP_INP_INCR_REF(inp);
2030166675Srrs				stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL);
2031166675Srrs				if (stcb == NULL) {
2032166675Srrs					SCTP_INP_DECR_REF(inp);
2033163953Srrs				}
2034166675Srrs			}
2035163953Srrs
2036166675Srrs			if ((stcb) && (net)) {
2037166675Srrs				paddri->spinfo_state = net->dest_state & (SCTP_REACHABLE_MASK | SCTP_ADDR_NOHB);
2038166675Srrs				paddri->spinfo_cwnd = net->cwnd;
2039166675Srrs				paddri->spinfo_srtt = ((net->lastsa >> 2) + net->lastsv) >> 1;
2040166675Srrs				paddri->spinfo_rto = net->RTO;
2041166675Srrs				paddri->spinfo_assoc_id = sctp_get_associd(stcb);
2042166675Srrs				SCTP_TCB_UNLOCK(stcb);
2043163953Srrs			} else {
2044163953Srrs				if (stcb) {
2045163953Srrs					SCTP_TCB_UNLOCK(stcb);
2046163953Srrs				}
2047163953Srrs				error = ENOENT;
2048163953Srrs			}
2049166675Srrs			*optsize = sizeof(struct sctp_paddrinfo);
2050163953Srrs		}
2051163953Srrs		break;
2052163953Srrs	case SCTP_PCB_STATUS:
2053163953Srrs		{
2054163953Srrs			struct sctp_pcbinfo *spcb;
2055163953Srrs
2056166675Srrs			SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
2057163953Srrs			sctp_fill_pcbinfo(spcb);
2058166675Srrs			*optsize = sizeof(struct sctp_pcbinfo);
2059163953Srrs		}
2060163953Srrs		break;
2061167598Srrs
2062163953Srrs	case SCTP_STATUS:
2063163953Srrs		{
2064163953Srrs			struct sctp_nets *net;
2065163953Srrs			struct sctp_status *sstat;
2066163953Srrs
2067166675Srrs			SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
2068166675Srrs			SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
2069163953Srrs
2070163953Srrs			if (stcb == NULL) {
2071163953Srrs				error = EINVAL;
2072163953Srrs				break;
2073163953Srrs			}
2074163953Srrs			/*
2075163953Srrs			 * I think passing the state is fine since
2076163953Srrs			 * sctp_constants.h will be available to the user
2077163953Srrs			 * land.
2078163953Srrs			 */
2079163953Srrs			sstat->sstat_state = stcb->asoc.state;
2080163953Srrs			sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
2081163953Srrs			sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
2082163953Srrs			/*
2083163953Srrs			 * We can't include chunks that have been passed to
2084163953Srrs			 * the socket layer. Only things in queue.
2085163953Srrs			 */
2086163953Srrs			sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
2087163953Srrs			    stcb->asoc.cnt_on_all_streams);
2088163953Srrs
2089163953Srrs
2090163953Srrs			sstat->sstat_instrms = stcb->asoc.streamincnt;
2091163953Srrs			sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
2092163953Srrs			sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc);
2093163953Srrs			memcpy(&sstat->sstat_primary.spinfo_address,
2094163953Srrs			    &stcb->asoc.primary_destination->ro._l_addr,
2095163953Srrs			    ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len);
2096163953Srrs			net = stcb->asoc.primary_destination;
2097163953Srrs			((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
2098163953Srrs			/*
2099163953Srrs			 * Again the user can get info from sctp_constants.h
2100163953Srrs			 * for what the state of the network is.
2101163953Srrs			 */
2102163953Srrs			sstat->sstat_primary.spinfo_state = net->dest_state & SCTP_REACHABLE_MASK;
2103163953Srrs			sstat->sstat_primary.spinfo_cwnd = net->cwnd;
2104163953Srrs			sstat->sstat_primary.spinfo_srtt = net->lastsa;
2105163953Srrs			sstat->sstat_primary.spinfo_rto = net->RTO;
2106163953Srrs			sstat->sstat_primary.spinfo_mtu = net->mtu;
2107163953Srrs			sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
2108163953Srrs			SCTP_TCB_UNLOCK(stcb);
2109166675Srrs			*optsize = sizeof(*sstat);
2110163953Srrs		}
2111163953Srrs		break;
2112163953Srrs	case SCTP_RTOINFO:
2113163953Srrs		{
2114163953Srrs			struct sctp_rtoinfo *srto;
2115163953Srrs
2116166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
2117166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
2118166675Srrs
2119166675Srrs			if (stcb) {
2120166675Srrs				srto->srto_initial = stcb->asoc.initial_rto;
2121166675Srrs				srto->srto_max = stcb->asoc.maxrto;
2122166675Srrs				srto->srto_min = stcb->asoc.minrto;
2123166675Srrs				SCTP_TCB_UNLOCK(stcb);
2124166675Srrs			} else {
2125163953Srrs				SCTP_INP_RLOCK(inp);
2126163953Srrs				srto->srto_initial = inp->sctp_ep.initial_rto;
2127163953Srrs				srto->srto_max = inp->sctp_ep.sctp_maxrto;
2128163953Srrs				srto->srto_min = inp->sctp_ep.sctp_minrto;
2129163953Srrs				SCTP_INP_RUNLOCK(inp);
2130163953Srrs			}
2131166675Srrs			*optsize = sizeof(*srto);
2132163953Srrs		}
2133163953Srrs		break;
2134163953Srrs	case SCTP_ASSOCINFO:
2135163953Srrs		{
2136163953Srrs			struct sctp_assocparams *sasoc;
2137163953Srrs
2138166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
2139166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
2140163953Srrs
2141163953Srrs			if (stcb) {
2142163953Srrs				sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
2143163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
2144163953Srrs				sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
2145163953Srrs				sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
2146163953Srrs				sasoc->sasoc_cookie_life = stcb->asoc.cookie_life;
2147167598Srrs				sasoc->sasoc_sack_delay = stcb->asoc.delayed_ack;
2148167598Srrs				sasoc->sasoc_sack_freq = stcb->asoc.sack_freq;
2149163953Srrs				SCTP_TCB_UNLOCK(stcb);
2150163953Srrs			} else {
2151163953Srrs				SCTP_INP_RLOCK(inp);
2152163953Srrs				sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
2153163953Srrs				sasoc->sasoc_number_peer_destinations = 0;
2154163953Srrs				sasoc->sasoc_peer_rwnd = 0;
2155163953Srrs				sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
2156163953Srrs				sasoc->sasoc_cookie_life = inp->sctp_ep.def_cookie_life;
2157167598Srrs				sasoc->sasoc_sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
2158167598Srrs				sasoc->sasoc_sack_freq = inp->sctp_ep.sctp_sack_freq;
2159163953Srrs				SCTP_INP_RUNLOCK(inp);
2160163953Srrs			}
2161166675Srrs			*optsize = sizeof(*sasoc);
2162163953Srrs		}
2163163953Srrs		break;
2164163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
2165163953Srrs		{
2166163953Srrs			struct sctp_sndrcvinfo *s_info;
2167163953Srrs
2168166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
2169166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
2170166675Srrs
2171166675Srrs			if (stcb) {
2172166675Srrs				*s_info = stcb->asoc.def_send;
2173166675Srrs				SCTP_TCB_UNLOCK(stcb);
2174166675Srrs			} else {
2175163953Srrs				SCTP_INP_RLOCK(inp);
2176166675Srrs				*s_info = inp->def_send;
2177163953Srrs				SCTP_INP_RUNLOCK(inp);
2178163953Srrs			}
2179166675Srrs			*optsize = sizeof(*s_info);
2180163953Srrs		}
2181163953Srrs		break;
2182163953Srrs	case SCTP_INITMSG:
2183163953Srrs		{
2184163953Srrs			struct sctp_initmsg *sinit;
2185163953Srrs
2186166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
2187163953Srrs			SCTP_INP_RLOCK(inp);
2188163953Srrs			sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
2189163953Srrs			sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
2190163953Srrs			sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
2191163953Srrs			sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
2192163953Srrs			SCTP_INP_RUNLOCK(inp);
2193166675Srrs			*optsize = sizeof(*sinit);
2194163953Srrs		}
2195163953Srrs		break;
2196163953Srrs	case SCTP_PRIMARY_ADDR:
2197163953Srrs		/* we allow a "get" operation on this */
2198163953Srrs		{
2199163953Srrs			struct sctp_setprim *ssp;
2200163953Srrs
2201166675Srrs			SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
2202166675Srrs			SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
2203166675Srrs
2204166675Srrs			if (stcb) {
2205166675Srrs				/* simply copy out the sockaddr_storage... */
2206166675Srrs				memcpy(&ssp->ssp_addr, &stcb->asoc.primary_destination->ro._l_addr,
2207166675Srrs				    ((struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr)->sa_len);
2208166675Srrs				SCTP_TCB_UNLOCK(stcb);
2209166675Srrs			} else {
2210163953Srrs				error = EINVAL;
2211163953Srrs			}
2212166675Srrs			*optsize = sizeof(*ssp);
2213163953Srrs		}
2214163953Srrs		break;
2215163953Srrs
2216163953Srrs	case SCTP_HMAC_IDENT:
2217163953Srrs		{
2218163953Srrs			struct sctp_hmacalgo *shmac;
2219163953Srrs			sctp_hmaclist_t *hmaclist;
2220163953Srrs			uint32_t size;
2221163953Srrs			int i;
2222163953Srrs
2223166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
2224166675Srrs
2225163953Srrs			SCTP_INP_RLOCK(inp);
2226163953Srrs			hmaclist = inp->sctp_ep.local_hmacs;
2227163953Srrs			if (hmaclist == NULL) {
2228163953Srrs				/* no HMACs to return */
2229166675Srrs				*optsize = sizeof(*shmac);
2230168299Srrs				SCTP_INP_RUNLOCK(inp);
2231163953Srrs				break;
2232163953Srrs			}
2233163953Srrs			/* is there room for all of the hmac ids? */
2234163953Srrs			size = sizeof(*shmac) + (hmaclist->num_algo *
2235163953Srrs			    sizeof(shmac->shmac_idents[0]));
2236166675Srrs			if ((size_t)(*optsize) < size) {
2237163953Srrs				error = EINVAL;
2238163953Srrs				SCTP_INP_RUNLOCK(inp);
2239163953Srrs				break;
2240163953Srrs			}
2241163953Srrs			/* copy in the list */
2242163953Srrs			for (i = 0; i < hmaclist->num_algo; i++)
2243163953Srrs				shmac->shmac_idents[i] = hmaclist->hmac[i];
2244163953Srrs			SCTP_INP_RUNLOCK(inp);
2245166675Srrs			*optsize = size;
2246163953Srrs			break;
2247163953Srrs		}
2248163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
2249163953Srrs		{
2250163953Srrs			struct sctp_authkeyid *scact;
2251163953Srrs
2252166675Srrs			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
2253166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
2254166675Srrs
2255166675Srrs			if (stcb) {
2256163953Srrs				/* get the active key on the assoc */
2257163953Srrs				scact->scact_keynumber = stcb->asoc.authinfo.assoc_keyid;
2258163953Srrs				SCTP_TCB_UNLOCK(stcb);
2259163953Srrs			} else {
2260163953Srrs				/* get the endpoint active key */
2261163953Srrs				SCTP_INP_RLOCK(inp);
2262163953Srrs				scact->scact_keynumber = inp->sctp_ep.default_keyid;
2263163953Srrs				SCTP_INP_RUNLOCK(inp);
2264163953Srrs			}
2265166675Srrs			*optsize = sizeof(*scact);
2266163953Srrs			break;
2267163953Srrs		}
2268163953Srrs	case SCTP_LOCAL_AUTH_CHUNKS:
2269163953Srrs		{
2270163953Srrs			struct sctp_authchunks *sac;
2271163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2272166675Srrs			size_t size = 0;
2273163953Srrs
2274166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2275166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2276166675Srrs
2277166675Srrs			if (stcb) {
2278163953Srrs				/* get off the assoc */
2279163953Srrs				chklist = stcb->asoc.local_auth_chunks;
2280163953Srrs				/* is there enough space? */
2281163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2282166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2283163953Srrs					error = EINVAL;
2284166675Srrs				} else {
2285166675Srrs					/* copy in the chunks */
2286169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2287163953Srrs				}
2288163953Srrs				SCTP_TCB_UNLOCK(stcb);
2289163953Srrs			} else {
2290163953Srrs				/* get off the endpoint */
2291163953Srrs				SCTP_INP_RLOCK(inp);
2292163953Srrs				chklist = inp->sctp_ep.local_auth_chunks;
2293163953Srrs				/* is there enough space? */
2294163953Srrs				size = sctp_auth_get_chklist_size(chklist);
2295166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2296163953Srrs					error = EINVAL;
2297166675Srrs				} else {
2298166675Srrs					/* copy in the chunks */
2299169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2300163953Srrs				}
2301163953Srrs				SCTP_INP_RUNLOCK(inp);
2302163953Srrs			}
2303166675Srrs			*optsize = sizeof(struct sctp_authchunks) + size;
2304163953Srrs			break;
2305163953Srrs		}
2306163953Srrs	case SCTP_PEER_AUTH_CHUNKS:
2307163953Srrs		{
2308163953Srrs			struct sctp_authchunks *sac;
2309163953Srrs			sctp_auth_chklist_t *chklist = NULL;
2310166675Srrs			size_t size = 0;
2311163953Srrs
2312166675Srrs			SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
2313166675Srrs			SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
2314166675Srrs
2315166675Srrs			if (stcb) {
2316166675Srrs				/* get off the assoc */
2317166675Srrs				chklist = stcb->asoc.peer_auth_chunks;
2318166675Srrs				/* is there enough space? */
2319166675Srrs				size = sctp_auth_get_chklist_size(chklist);
2320166675Srrs				if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
2321166675Srrs					error = EINVAL;
2322166675Srrs				} else {
2323166675Srrs					/* copy in the chunks */
2324169420Srrs					(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
2325166675Srrs				}
2326166675Srrs				SCTP_TCB_UNLOCK(stcb);
2327166675Srrs			} else {
2328163953Srrs				error = ENOENT;
2329163953Srrs			}
2330166675Srrs			*optsize = sizeof(struct sctp_authchunks) + size;
2331163953Srrs			break;
2332163953Srrs		}
2333163953Srrs
2334163953Srrs
2335163953Srrs	default:
2336163953Srrs		error = ENOPROTOOPT;
2337166675Srrs		*optsize = 0;
2338163953Srrs		break;
2339163953Srrs	}			/* end switch (sopt->sopt_name) */
2340163953Srrs	return (error);
2341163953Srrs}
2342163953Srrs
2343163953Srrsstatic int
2344166675Srrssctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
2345166675Srrs    void *p)
2346163953Srrs{
2347166675Srrs	int error, set_opt;
2348166675Srrs	uint32_t *mopt;
2349163953Srrs	struct sctp_tcb *stcb = NULL;
2350163953Srrs	struct sctp_inpcb *inp;
2351167598Srrs	uint32_t vrf_id;
2352163953Srrs
2353166675Srrs	if (optval == NULL) {
2354169420Srrs		SCTP_PRINTF("optval is NULL\n");
2355163953Srrs		return (EINVAL);
2356163953Srrs	}
2357163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
2358167598Srrs	if (inp == 0) {
2359169420Srrs		SCTP_PRINTF("inp is NULL?\n");
2360163953Srrs		return EINVAL;
2361167598Srrs	}
2362168299Srrs	vrf_id = inp->def_vrf_id;
2363163953Srrs
2364163953Srrs	error = 0;
2365166675Srrs	switch (optname) {
2366163953Srrs	case SCTP_NODELAY:
2367163953Srrs	case SCTP_AUTOCLOSE:
2368163953Srrs	case SCTP_AUTO_ASCONF:
2369163953Srrs	case SCTP_EXPLICIT_EOR:
2370163953Srrs	case SCTP_DISABLE_FRAGMENTS:
2371163953Srrs	case SCTP_USE_EXT_RCVINFO:
2372163953Srrs	case SCTP_I_WANT_MAPPED_V4_ADDR:
2373163953Srrs		/* copy in the option value */
2374166675Srrs		SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
2375163953Srrs		set_opt = 0;
2376163953Srrs		if (error)
2377163953Srrs			break;
2378166675Srrs		switch (optname) {
2379163953Srrs		case SCTP_DISABLE_FRAGMENTS:
2380163953Srrs			set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
2381163953Srrs			break;
2382163953Srrs		case SCTP_AUTO_ASCONF:
2383163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
2384163953Srrs			break;
2385163953Srrs		case SCTP_EXPLICIT_EOR:
2386163953Srrs			set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
2387163953Srrs			break;
2388163953Srrs		case SCTP_USE_EXT_RCVINFO:
2389163953Srrs			set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
2390163953Srrs			break;
2391163953Srrs		case SCTP_I_WANT_MAPPED_V4_ADDR:
2392163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2393163953Srrs				set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
2394163953Srrs			} else {
2395163953Srrs				return (EINVAL);
2396163953Srrs			}
2397163953Srrs			break;
2398163953Srrs		case SCTP_NODELAY:
2399163953Srrs			set_opt = SCTP_PCB_FLAGS_NODELAY;
2400163953Srrs			break;
2401163953Srrs		case SCTP_AUTOCLOSE:
2402163953Srrs			set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
2403163953Srrs			/*
2404163953Srrs			 * The value is in ticks. Note this does not effect
2405163953Srrs			 * old associations, only new ones.
2406163953Srrs			 */
2407163953Srrs			inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt);
2408163953Srrs			break;
2409163953Srrs		}
2410163953Srrs		SCTP_INP_WLOCK(inp);
2411163953Srrs		if (*mopt != 0) {
2412163953Srrs			sctp_feature_on(inp, set_opt);
2413163953Srrs		} else {
2414163953Srrs			sctp_feature_off(inp, set_opt);
2415163953Srrs		}
2416163953Srrs		SCTP_INP_WUNLOCK(inp);
2417163953Srrs		break;
2418163953Srrs	case SCTP_PARTIAL_DELIVERY_POINT:
2419163953Srrs		{
2420166675Srrs			uint32_t *value;
2421166675Srrs
2422166675Srrs			SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
2423167736Srrs			if (*value > SCTP_SB_LIMIT_RCV(so)) {
2424167736Srrs				error = EINVAL;
2425167736Srrs				break;
2426167736Srrs			}
2427166675Srrs			inp->partial_delivery_point = *value;
2428163953Srrs		}
2429163953Srrs		break;
2430163953Srrs	case SCTP_FRAGMENT_INTERLEAVE:
2431163953Srrs		/* not yet until we re-write sctp_recvmsg() */
2432163953Srrs		{
2433168943Srrs			uint32_t *level;
2434163953Srrs
2435168943Srrs			SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
2436168943Srrs			if (*level == SCTP_FRAG_LEVEL_2) {
2437163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
2438168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
2439168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_1) {
2440168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
2441168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
2442168943Srrs			} else if (*level == SCTP_FRAG_LEVEL_0) {
2443168943Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
2444168943Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
2445168943Srrs
2446163953Srrs			} else {
2447168943Srrs				error = EINVAL;
2448163953Srrs			}
2449163953Srrs		}
2450163953Srrs		break;
2451163953Srrs	case SCTP_CMT_ON_OFF:
2452163953Srrs		{
2453163953Srrs			struct sctp_assoc_value *av;
2454163953Srrs
2455166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
2456166675Srrs			if (sctp_cmt_on_off) {
2457166675Srrs				SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2458166675Srrs				if (stcb) {
2459163953Srrs					stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value;
2460166675Srrs					SCTP_TCB_UNLOCK(stcb);
2461163953Srrs				} else {
2462166675Srrs					error = ENOTCONN;
2463163953Srrs				}
2464166675Srrs			} else {
2465166675Srrs				error = ENOPROTOOPT;
2466163953Srrs			}
2467163953Srrs		}
2468163953Srrs		break;
2469163953Srrs	case SCTP_CLR_STAT_LOG:
2470163953Srrs#ifdef SCTP_STAT_LOGGING
2471163953Srrs		sctp_clr_stat_log();
2472163953Srrs#else
2473163953Srrs		error = EOPNOTSUPP;
2474163953Srrs#endif
2475163953Srrs		break;
2476163953Srrs	case SCTP_CONTEXT:
2477163953Srrs		{
2478163953Srrs			struct sctp_assoc_value *av;
2479163953Srrs
2480166675Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
2481166675Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2482166675Srrs
2483166675Srrs			if (stcb) {
2484166675Srrs				stcb->asoc.context = av->assoc_value;
2485166675Srrs				SCTP_TCB_UNLOCK(stcb);
2486163953Srrs			} else {
2487166675Srrs				SCTP_INP_WLOCK(inp);
2488163953Srrs				inp->sctp_context = av->assoc_value;
2489166675Srrs				SCTP_INP_WUNLOCK(inp);
2490163953Srrs			}
2491163953Srrs		}
2492163953Srrs		break;
2493167598Srrs	case SCTP_VRF_ID:
2494167598Srrs		{
2495167598Srrs			uint32_t *vrf_id;
2496167598Srrs
2497167598Srrs			SCTP_CHECK_AND_CAST(vrf_id, optval, uint32_t, optsize);
2498167598Srrs			if (*vrf_id > SCTP_MAX_VRF_ID) {
2499167598Srrs				error = EINVAL;
2500167598Srrs				break;
2501167598Srrs			}
2502167598Srrs			inp->def_vrf_id = *vrf_id;
2503167598Srrs			break;
2504167598Srrs		}
2505167598Srrs	case SCTP_DEL_VRF_ID:
2506167598Srrs		{
2507167598Srrs			error = EOPNOTSUPP;
2508167598Srrs			break;
2509167598Srrs		}
2510167598Srrs	case SCTP_ADD_VRF_ID:
2511167598Srrs		{
2512167598Srrs			error = EOPNOTSUPP;
2513167598Srrs			break;
2514167598Srrs		}
2515167598Srrs
2516163953Srrs	case SCTP_DELAYED_ACK_TIME:
2517163953Srrs		{
2518163953Srrs			struct sctp_assoc_value *tm;
2519163953Srrs
2520166675Srrs			SCTP_CHECK_AND_CAST(tm, optval, struct sctp_assoc_value, optsize);
2521166675Srrs			SCTP_FIND_STCB(inp, stcb, tm->assoc_id);
2522163953Srrs
2523166675Srrs			if (stcb) {
2524166675Srrs				stcb->asoc.delayed_ack = tm->assoc_value;
2525166675Srrs				SCTP_TCB_UNLOCK(stcb);
2526166675Srrs			} else {
2527163953Srrs				SCTP_INP_WLOCK(inp);
2528166675Srrs				inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(tm->assoc_value);
2529163953Srrs				SCTP_INP_WUNLOCK(inp);
2530163953Srrs			}
2531166675Srrs			break;
2532163953Srrs		}
2533163953Srrs	case SCTP_AUTH_CHUNK:
2534163953Srrs		{
2535163953Srrs			struct sctp_authchunk *sauth;
2536163953Srrs
2537166675Srrs			SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
2538166675Srrs
2539166675Srrs			SCTP_INP_WLOCK(inp);
2540166675Srrs			if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks))
2541163953Srrs				error = EINVAL;
2542166675Srrs			SCTP_INP_WUNLOCK(inp);
2543163953Srrs			break;
2544163953Srrs		}
2545163953Srrs	case SCTP_AUTH_KEY:
2546163953Srrs		{
2547163953Srrs			struct sctp_authkey *sca;
2548163953Srrs			struct sctp_keyhead *shared_keys;
2549163953Srrs			sctp_sharedkey_t *shared_key;
2550163953Srrs			sctp_key_t *key = NULL;
2551166675Srrs			size_t size;
2552163953Srrs
2553166675Srrs			SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
2554169420Srrs			SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
2555169420Srrs			size = optsize - sizeof(*sca);
2556166675Srrs
2557166675Srrs			if (stcb) {
2558163953Srrs				/* set it on the assoc */
2559163953Srrs				shared_keys = &stcb->asoc.shared_keys;
2560163953Srrs				/* clear the cached keys for this key id */
2561163953Srrs				sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
2562163953Srrs				/*
2563163953Srrs				 * create the new shared key and
2564163953Srrs				 * insert/replace it
2565163953Srrs				 */
2566163953Srrs				if (size > 0) {
2567163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
2568163953Srrs					if (key == NULL) {
2569163953Srrs						error = ENOMEM;
2570163953Srrs						SCTP_TCB_UNLOCK(stcb);
2571163953Srrs						break;
2572163953Srrs					}
2573163953Srrs				}
2574163953Srrs				shared_key = sctp_alloc_sharedkey();
2575163953Srrs				if (shared_key == NULL) {
2576163953Srrs					sctp_free_key(key);
2577163953Srrs					error = ENOMEM;
2578163953Srrs					SCTP_TCB_UNLOCK(stcb);
2579163953Srrs					break;
2580163953Srrs				}
2581163953Srrs				shared_key->key = key;
2582163953Srrs				shared_key->keyid = sca->sca_keynumber;
2583163953Srrs				sctp_insert_sharedkey(shared_keys, shared_key);
2584163953Srrs				SCTP_TCB_UNLOCK(stcb);
2585163953Srrs			} else {
2586166675Srrs				/* set it on the endpoint */
2587163953Srrs				SCTP_INP_WLOCK(inp);
2588163953Srrs				shared_keys = &inp->sctp_ep.shared_keys;
2589163953Srrs				/*
2590163953Srrs				 * clear the cached keys on all assocs for
2591163953Srrs				 * this key id
2592163953Srrs				 */
2593163953Srrs				sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
2594163953Srrs				/*
2595163953Srrs				 * create the new shared key and
2596163953Srrs				 * insert/replace it
2597163953Srrs				 */
2598163953Srrs				if (size > 0) {
2599163953Srrs					key = sctp_set_key(sca->sca_key, (uint32_t) size);
2600163953Srrs					if (key == NULL) {
2601163953Srrs						error = ENOMEM;
2602163953Srrs						SCTP_INP_WUNLOCK(inp);
2603163953Srrs						break;
2604163953Srrs					}
2605163953Srrs				}
2606163953Srrs				shared_key = sctp_alloc_sharedkey();
2607163953Srrs				if (shared_key == NULL) {
2608163953Srrs					sctp_free_key(key);
2609163953Srrs					error = ENOMEM;
2610163953Srrs					SCTP_INP_WUNLOCK(inp);
2611163953Srrs					break;
2612163953Srrs				}
2613163953Srrs				shared_key->key = key;
2614163953Srrs				shared_key->keyid = sca->sca_keynumber;
2615163953Srrs				sctp_insert_sharedkey(shared_keys, shared_key);
2616163953Srrs				SCTP_INP_WUNLOCK(inp);
2617163953Srrs			}
2618163953Srrs			break;
2619163953Srrs		}
2620163953Srrs	case SCTP_HMAC_IDENT:
2621163953Srrs		{
2622163953Srrs			struct sctp_hmacalgo *shmac;
2623163953Srrs			sctp_hmaclist_t *hmaclist;
2624163953Srrs			uint32_t hmacid;
2625166675Srrs			size_t size, i;
2626163953Srrs
2627166675Srrs			SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
2628166675Srrs			size = (optsize - sizeof(*shmac)) / sizeof(shmac->shmac_idents[0]);
2629163953Srrs			hmaclist = sctp_alloc_hmaclist(size);
2630163953Srrs			if (hmaclist == NULL) {
2631163953Srrs				error = ENOMEM;
2632163953Srrs				break;
2633163953Srrs			}
2634163953Srrs			for (i = 0; i < size; i++) {
2635163953Srrs				hmacid = shmac->shmac_idents[i];
2636163953Srrs				if (sctp_auth_add_hmacid(hmaclist, (uint16_t) hmacid)) {
2637163953Srrs					 /* invalid HMACs were found */ ;
2638163953Srrs					error = EINVAL;
2639164085Srrs					sctp_free_hmaclist(hmaclist);
2640163953Srrs					goto sctp_set_hmac_done;
2641163953Srrs				}
2642163953Srrs			}
2643163953Srrs			/* set it on the endpoint */
2644163953Srrs			SCTP_INP_WLOCK(inp);
2645163953Srrs			if (inp->sctp_ep.local_hmacs)
2646163953Srrs				sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
2647163953Srrs			inp->sctp_ep.local_hmacs = hmaclist;
2648163953Srrs			SCTP_INP_WUNLOCK(inp);
2649163953Srrs	sctp_set_hmac_done:
2650163953Srrs			break;
2651163953Srrs		}
2652163953Srrs	case SCTP_AUTH_ACTIVE_KEY:
2653163953Srrs		{
2654163953Srrs			struct sctp_authkeyid *scact;
2655163953Srrs
2656166675Srrs			SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
2657166675Srrs			SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
2658166675Srrs
2659163953Srrs			/* set the active key on the right place */
2660166675Srrs			if (stcb) {
2661163953Srrs				/* set the active key on the assoc */
2662163953Srrs				if (sctp_auth_setactivekey(stcb, scact->scact_keynumber))
2663163953Srrs					error = EINVAL;
2664163953Srrs				SCTP_TCB_UNLOCK(stcb);
2665163953Srrs			} else {
2666163953Srrs				/* set the active key on the endpoint */
2667163953Srrs				SCTP_INP_WLOCK(inp);
2668163953Srrs				if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber))
2669163953Srrs					error = EINVAL;
2670163953Srrs				SCTP_INP_WUNLOCK(inp);
2671163953Srrs			}
2672163953Srrs			break;
2673163953Srrs		}
2674163953Srrs	case SCTP_AUTH_DELETE_KEY:
2675163953Srrs		{
2676163953Srrs			struct sctp_authkeyid *scdel;
2677163953Srrs
2678166675Srrs			SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
2679166675Srrs			SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
2680166675Srrs
2681163953Srrs			/* delete the key from the right place */
2682166675Srrs			if (stcb) {
2683163953Srrs				if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber))
2684163953Srrs					error = EINVAL;
2685163953Srrs				SCTP_TCB_UNLOCK(stcb);
2686163953Srrs			} else {
2687163953Srrs				SCTP_INP_WLOCK(inp);
2688163953Srrs				if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber))
2689163953Srrs					error = EINVAL;
2690163953Srrs				SCTP_INP_WUNLOCK(inp);
2691163953Srrs			}
2692163953Srrs			break;
2693163953Srrs		}
2694163953Srrs
2695163953Srrs	case SCTP_RESET_STREAMS:
2696163953Srrs		{
2697163953Srrs			struct sctp_stream_reset *strrst;
2698163953Srrs			uint8_t send_in = 0, send_tsn = 0, send_out = 0;
2699163953Srrs			int i;
2700163953Srrs
2701166675Srrs			SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize);
2702166675Srrs			SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id);
2703163953Srrs
2704163953Srrs			if (stcb == NULL) {
2705163953Srrs				error = ENOENT;
2706163953Srrs				break;
2707163953Srrs			}
2708163953Srrs			if (stcb->asoc.peer_supports_strreset == 0) {
2709163953Srrs				/*
2710163953Srrs				 * Peer does not support it, we return
2711163953Srrs				 * protocol not supported since this is true
2712163953Srrs				 * for this feature and this peer, not the
2713163953Srrs				 * socket request in general.
2714163953Srrs				 */
2715163953Srrs				error = EPROTONOSUPPORT;
2716163953Srrs				SCTP_TCB_UNLOCK(stcb);
2717163953Srrs				break;
2718163953Srrs			}
2719163953Srrs			if (stcb->asoc.stream_reset_outstanding) {
2720163953Srrs				error = EALREADY;
2721163953Srrs				SCTP_TCB_UNLOCK(stcb);
2722163953Srrs				break;
2723163953Srrs			}
2724163953Srrs			if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) {
2725163953Srrs				send_in = 1;
2726163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) {
2727163953Srrs				send_out = 1;
2728163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_BOTH) {
2729163953Srrs				send_in = 1;
2730163953Srrs				send_out = 1;
2731163953Srrs			} else if (strrst->strrst_flags == SCTP_RESET_TSN) {
2732163953Srrs				send_tsn = 1;
2733163953Srrs			} else {
2734163953Srrs				error = EINVAL;
2735163953Srrs				SCTP_TCB_UNLOCK(stcb);
2736163953Srrs				break;
2737163953Srrs			}
2738163953Srrs			for (i = 0; i < strrst->strrst_num_streams; i++) {
2739163953Srrs				if ((send_in) &&
2740163953Srrs
2741163953Srrs				    (strrst->strrst_list[i] > stcb->asoc.streamincnt)) {
2742163953Srrs					error = EINVAL;
2743163953Srrs					goto get_out;
2744163953Srrs				}
2745163953Srrs				if ((send_out) &&
2746163953Srrs				    (strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) {
2747163953Srrs					error = EINVAL;
2748163953Srrs					goto get_out;
2749163953Srrs				}
2750163953Srrs			}
2751163953Srrs			if (error) {
2752163953Srrs		get_out:
2753163953Srrs				SCTP_TCB_UNLOCK(stcb);
2754163953Srrs				break;
2755163953Srrs			}
2756163953Srrs			error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams,
2757163953Srrs			    strrst->strrst_list,
2758163953Srrs			    send_out, (stcb->asoc.str_reset_seq_in - 3),
2759163953Srrs			    send_in, send_tsn);
2760163953Srrs
2761163953Srrs			sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ);
2762163953Srrs			SCTP_TCB_UNLOCK(stcb);
2763163953Srrs		}
2764163953Srrs		break;
2765166675Srrs
2766163953Srrs	case SCTP_CONNECT_X:
2767166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
2768163953Srrs			error = EINVAL;
2769163953Srrs			break;
2770163953Srrs		}
2771166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
2772163953Srrs		break;
2773163953Srrs
2774163953Srrs	case SCTP_CONNECT_X_DELAYED:
2775166675Srrs		if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
2776163953Srrs			error = EINVAL;
2777163953Srrs			break;
2778163953Srrs		}
2779166675Srrs		error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
2780163953Srrs		break;
2781163953Srrs
2782163953Srrs	case SCTP_CONNECT_X_COMPLETE:
2783163953Srrs		{
2784163953Srrs			struct sockaddr *sa;
2785163953Srrs			struct sctp_nets *net;
2786163953Srrs
2787166675Srrs			/* FIXME MT: check correct? */
2788166675Srrs			SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
2789166675Srrs
2790163953Srrs			/* find tcb */
2791163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
2792163953Srrs				SCTP_INP_RLOCK(inp);
2793163953Srrs				stcb = LIST_FIRST(&inp->sctp_asoc_list);
2794163953Srrs				if (stcb) {
2795163953Srrs					SCTP_TCB_LOCK(stcb);
2796163953Srrs					net = sctp_findnet(stcb, sa);
2797163953Srrs				}
2798163953Srrs				SCTP_INP_RUNLOCK(inp);
2799163953Srrs			} else {
2800166675Srrs				/*
2801166675Srrs				 * We increment here since
2802166675Srrs				 * sctp_findassociation_ep_addr() wil do a
2803166675Srrs				 * decrement if it finds the stcb as long as
2804166675Srrs				 * the locked tcb (last argument) is NOT a
2805166675Srrs				 * TCB.. aka NULL.
2806166675Srrs				 */
2807163953Srrs				SCTP_INP_INCR_REF(inp);
2808163953Srrs				stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL);
2809163953Srrs				if (stcb == NULL) {
2810163953Srrs					SCTP_INP_DECR_REF(inp);
2811163953Srrs				}
2812163953Srrs			}
2813163953Srrs
2814163953Srrs			if (stcb == NULL) {
2815163953Srrs				error = ENOENT;
2816163953Srrs				break;
2817163953Srrs			}
2818163953Srrs			if (stcb->asoc.delayed_connection == 1) {
2819163953Srrs				stcb->asoc.delayed_connection = 0;
2820169378Srrs				(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
2821165220Srrs				sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
2822165220Srrs				    stcb->asoc.primary_destination,
2823165220Srrs				    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
2824163953Srrs				sctp_send_initiate(inp, stcb);
2825163953Srrs			} else {
2826163953Srrs				/*
2827163953Srrs				 * already expired or did not use delayed
2828163953Srrs				 * connectx
2829163953Srrs				 */
2830163953Srrs				error = EALREADY;
2831163953Srrs			}
2832163953Srrs			SCTP_TCB_UNLOCK(stcb);
2833163953Srrs		}
2834163953Srrs		break;
2835163953Srrs	case SCTP_MAXBURST:
2836163953Srrs		{
2837163953Srrs			uint8_t *burst;
2838163953Srrs
2839166675Srrs			SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize);
2840166675Srrs
2841163953Srrs			SCTP_INP_WLOCK(inp);
2842163953Srrs			if (*burst) {
2843163953Srrs				inp->sctp_ep.max_burst = *burst;
2844163953Srrs			}
2845163953Srrs			SCTP_INP_WUNLOCK(inp);
2846163953Srrs		}
2847163953Srrs		break;
2848163953Srrs	case SCTP_MAXSEG:
2849163953Srrs		{
2850167598Srrs			struct sctp_assoc_value *av;
2851163953Srrs			int ovh;
2852163953Srrs
2853167598Srrs			SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
2854167598Srrs			SCTP_FIND_STCB(inp, stcb, av->assoc_id);
2855166675Srrs
2856167598Srrs			if (stcb) {
2857167598Srrs				error = EINVAL;
2858167598Srrs				SCTP_TCB_UNLOCK(stcb);
2859163953Srrs			} else {
2860167598Srrs				SCTP_INP_WLOCK(inp);
2861167598Srrs				if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
2862167598Srrs					ovh = SCTP_MED_OVERHEAD;
2863167598Srrs				} else {
2864167598Srrs					ovh = SCTP_MED_V4_OVERHEAD;
2865167598Srrs				}
2866167598Srrs				/*
2867167598Srrs				 * FIXME MT: I think this is not in tune
2868167598Srrs				 * with the API ID
2869167598Srrs				 */
2870167598Srrs				if (av->assoc_value) {
2871167598Srrs					inp->sctp_frag_point = (av->assoc_value + ovh);
2872167598Srrs				} else {
2873167598Srrs					error = EINVAL;
2874167598Srrs				}
2875167598Srrs				SCTP_INP_WUNLOCK(inp);
2876163953Srrs			}
2877163953Srrs		}
2878163953Srrs		break;
2879163953Srrs	case SCTP_EVENTS:
2880163953Srrs		{
2881163953Srrs			struct sctp_event_subscribe *events;
2882163953Srrs
2883166675Srrs			SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
2884166675Srrs
2885163953Srrs			SCTP_INP_WLOCK(inp);
2886163953Srrs			if (events->sctp_data_io_event) {
2887163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
2888163953Srrs			} else {
2889163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
2890163953Srrs			}
2891163953Srrs
2892163953Srrs			if (events->sctp_association_event) {
2893163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
2894163953Srrs			} else {
2895163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
2896163953Srrs			}
2897163953Srrs
2898163953Srrs			if (events->sctp_address_event) {
2899163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
2900163953Srrs			} else {
2901163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
2902163953Srrs			}
2903163953Srrs
2904163953Srrs			if (events->sctp_send_failure_event) {
2905163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
2906163953Srrs			} else {
2907163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
2908163953Srrs			}
2909163953Srrs
2910163953Srrs			if (events->sctp_peer_error_event) {
2911163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
2912163953Srrs			} else {
2913163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
2914163953Srrs			}
2915163953Srrs
2916163953Srrs			if (events->sctp_shutdown_event) {
2917163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
2918163953Srrs			} else {
2919163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
2920163953Srrs			}
2921163953Srrs
2922163953Srrs			if (events->sctp_partial_delivery_event) {
2923163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
2924163953Srrs			} else {
2925163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
2926163953Srrs			}
2927163953Srrs
2928163953Srrs			if (events->sctp_adaptation_layer_event) {
2929163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
2930163953Srrs			} else {
2931163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
2932163953Srrs			}
2933163953Srrs
2934163953Srrs			if (events->sctp_authentication_event) {
2935163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
2936163953Srrs			} else {
2937163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
2938163953Srrs			}
2939163953Srrs
2940163953Srrs			if (events->sctp_stream_reset_events) {
2941163953Srrs				sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
2942163953Srrs			} else {
2943163953Srrs				sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
2944163953Srrs			}
2945163953Srrs			SCTP_INP_WUNLOCK(inp);
2946163953Srrs		}
2947163953Srrs		break;
2948163953Srrs
2949163953Srrs	case SCTP_ADAPTATION_LAYER:
2950163953Srrs		{
2951163953Srrs			struct sctp_setadaptation *adap_bits;
2952163953Srrs
2953166675Srrs			SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
2954163953Srrs			SCTP_INP_WLOCK(inp);
2955163953Srrs			inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
2956163953Srrs			SCTP_INP_WUNLOCK(inp);
2957163953Srrs		}
2958163953Srrs		break;
2959166675Srrs#ifdef SCTP_DEBUG
2960163953Srrs	case SCTP_SET_INITIAL_DBG_SEQ:
2961163953Srrs		{
2962163953Srrs			uint32_t *vvv;
2963163953Srrs
2964166675Srrs			SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
2965163953Srrs			SCTP_INP_WLOCK(inp);
2966163953Srrs			inp->sctp_ep.initial_sequence_debug = *vvv;
2967163953Srrs			SCTP_INP_WUNLOCK(inp);
2968163953Srrs		}
2969163953Srrs		break;
2970166675Srrs#endif
2971163953Srrs	case SCTP_DEFAULT_SEND_PARAM:
2972163953Srrs		{
2973163953Srrs			struct sctp_sndrcvinfo *s_info;
2974163953Srrs
2975166675Srrs			SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
2976166675Srrs			SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
2977163953Srrs
2978166675Srrs			if (stcb) {
2979166675Srrs				if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) {
2980166675Srrs					stcb->asoc.def_send = *s_info;
2981163953Srrs				} else {
2982166675Srrs					error = EINVAL;
2983163953Srrs				}
2984166675Srrs				SCTP_TCB_UNLOCK(stcb);
2985166675Srrs			} else {
2986166675Srrs				SCTP_INP_WLOCK(inp);
2987163953Srrs				inp->def_send = *s_info;
2988166675Srrs				SCTP_INP_WUNLOCK(inp);
2989163953Srrs			}
2990163953Srrs		}
2991163953Srrs		break;
2992163953Srrs	case SCTP_PEER_ADDR_PARAMS:
2993163953Srrs		/* Applys to the specific association */
2994163953Srrs		{
2995163953Srrs			struct sctp_paddrparams *paddrp;
2996163953Srrs			struct sctp_nets *net;
2997163953Srrs
2998166675Srrs			SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
2999166675Srrs			SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
3000163953Srrs			net = NULL;
3001166675Srrs			if (stcb) {
3002166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address);
3003166675Srrs			} else {
3004166675Srrs				/*
3005166675Srrs				 * We increment here since
3006166675Srrs				 * sctp_findassociation_ep_addr() wil do a
3007166675Srrs				 * decrement if it finds the stcb as long as
3008166675Srrs				 * the locked tcb (last argument) is NOT a
3009166675Srrs				 * TCB.. aka NULL.
3010166675Srrs				 */
3011166675Srrs				SCTP_INP_INCR_REF(inp);
3012166675Srrs				stcb = sctp_findassociation_ep_addr(&inp,
3013166675Srrs				    (struct sockaddr *)&paddrp->spp_address,
3014166675Srrs				    &net, NULL, NULL);
3015163953Srrs				if (stcb == NULL) {
3016166675Srrs					SCTP_INP_DECR_REF(inp);
3017163953Srrs				}
3018163953Srrs			}
3019166675Srrs
3020166675Srrs
3021163953Srrs			if (stcb) {
3022163953Srrs				/************************TCB SPECIFIC SET ******************/
3023163953Srrs				/*
3024163953Srrs				 * do we change the timer for HB, we run
3025163953Srrs				 * only one?
3026163953Srrs				 */
3027163953Srrs				if (paddrp->spp_hbinterval)
3028163953Srrs					stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
3029163953Srrs				else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
3030163953Srrs					stcb->asoc.heart_beat_delay = 0;
3031163953Srrs
3032163953Srrs				/* network sets ? */
3033163953Srrs				if (net) {
3034163953Srrs					/************************NET SPECIFIC SET ******************/
3035163953Srrs					if (paddrp->spp_flags & SPP_HB_DEMAND) {
3036163953Srrs						/* on demand HB */
3037169378Srrs						(void)sctp_send_hb(stcb, 1, net);
3038163953Srrs					}
3039163953Srrs					if (paddrp->spp_flags & SPP_HB_DISABLE) {
3040163953Srrs						net->dest_state |= SCTP_ADDR_NOHB;
3041163953Srrs					}
3042163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
3043163953Srrs						net->dest_state &= ~SCTP_ADDR_NOHB;
3044163953Srrs					}
3045163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
3046165647Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
3047165220Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
3048165220Srrs							    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
3049163953Srrs						}
3050163953Srrs						if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) {
3051163953Srrs							net->mtu = paddrp->spp_pathmtu;
3052169352Srrs							if (net->mtu < stcb->asoc.smallest_mtu) {
3053169352Srrs#ifdef SCTP_PRINT_FOR_B_AND_M
3054169420Srrs								SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n",
3055169352Srrs								    net->mtu);
3056169352Srrs#endif
3057167695Srrs								sctp_pathmtu_adjustment(inp, stcb, net, net->mtu);
3058169352Srrs							}
3059163953Srrs						}
3060163953Srrs					}
3061163953Srrs					if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
3062165647Srrs						if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
3063163953Srrs							sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
3064163953Srrs						}
3065163953Srrs					}
3066163953Srrs					if (paddrp->spp_pathmaxrxt)
3067163953Srrs						net->failure_threshold = paddrp->spp_pathmaxrxt;
3068167598Srrs#ifdef INET
3069163953Srrs					if (paddrp->spp_flags & SPP_IPV4_TOS) {
3070163953Srrs						if (net->ro._l_addr.sin.sin_family == AF_INET) {
3071163953Srrs							net->tos_flowlabel = paddrp->spp_ipv4_tos & 0x000000fc;
3072163953Srrs						}
3073163953Srrs					}
3074163953Srrs#endif
3075167598Srrs#ifdef INET6
3076163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
3077163953Srrs						if (net->ro._l_addr.sin6.sin6_family == AF_INET6) {
3078163953Srrs							net->tos_flowlabel = paddrp->spp_ipv6_flowlabel;
3079163953Srrs						}
3080163953Srrs					}
3081163953Srrs#endif
3082163953Srrs				} else {
3083163953Srrs					/************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
3084163953Srrs					if (paddrp->spp_pathmaxrxt)
3085163953Srrs						stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
3086163953Srrs
3087163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
3088163953Srrs						/* Turn back on the timer */
3089163953Srrs						stcb->asoc.hb_is_disabled = 0;
3090163953Srrs						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
3091163953Srrs					}
3092163953Srrs					if (paddrp->spp_flags & SPP_HB_DISABLE) {
3093163953Srrs						int cnt_of_unconf = 0;
3094163953Srrs						struct sctp_nets *lnet;
3095163953Srrs
3096163953Srrs						stcb->asoc.hb_is_disabled = 1;
3097163953Srrs						TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
3098163953Srrs							if (lnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
3099163953Srrs								cnt_of_unconf++;
3100163953Srrs							}
3101163953Srrs						}
3102163953Srrs						/*
3103163953Srrs						 * stop the timer ONLY if we
3104163953Srrs						 * have no unconfirmed
3105163953Srrs						 * addresses
3106163953Srrs						 */
3107163953Srrs						if (cnt_of_unconf == 0) {
3108165220Srrs							sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
3109163953Srrs						}
3110163953Srrs					}
3111163953Srrs					if (paddrp->spp_flags & SPP_HB_ENABLE) {
3112163953Srrs						/* start up the timer. */
3113163953Srrs						sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
3114163953Srrs					}
3115167598Srrs#ifdef INET
3116163953Srrs					if (paddrp->spp_flags & SPP_IPV4_TOS)
3117163953Srrs						stcb->asoc.default_tos = paddrp->spp_ipv4_tos & 0x000000fc;
3118163953Srrs#endif
3119167598Srrs#ifdef INET6
3120163953Srrs					if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL)
3121163953Srrs						stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel;
3122163953Srrs#endif
3123163953Srrs
3124163953Srrs				}
3125163953Srrs				SCTP_TCB_UNLOCK(stcb);
3126163953Srrs			} else {
3127163953Srrs				/************************NO TCB, SET TO default stuff ******************/
3128163953Srrs				SCTP_INP_WLOCK(inp);
3129163953Srrs				/*
3130163953Srrs				 * For the TOS/FLOWLABEL stuff you set it
3131163953Srrs				 * with the options on the socket
3132163953Srrs				 */
3133163953Srrs				if (paddrp->spp_pathmaxrxt) {
3134163953Srrs					inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
3135163953Srrs				}
3136163953Srrs				if (paddrp->spp_flags & SPP_HB_ENABLE) {
3137163953Srrs					inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
3138163953Srrs					sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
3139163953Srrs				} else if (paddrp->spp_flags & SPP_HB_DISABLE) {
3140163953Srrs					sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
3141163953Srrs				}
3142163953Srrs				SCTP_INP_WUNLOCK(inp);
3143163953Srrs			}
3144163953Srrs		}
3145163953Srrs		break;
3146163953Srrs	case SCTP_RTOINFO:
3147163953Srrs		{
3148163953Srrs			struct sctp_rtoinfo *srto;
3149163953Srrs
3150166675Srrs			SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
3151166675Srrs			SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
3152166675Srrs
3153166675Srrs			if (stcb) {
3154166675Srrs				/* Set in ms we hope :-) */
3155167598Srrs				if (srto->srto_initial)
3156166675Srrs					stcb->asoc.initial_rto = srto->srto_initial;
3157167598Srrs				if (srto->srto_max)
3158166675Srrs					stcb->asoc.maxrto = srto->srto_max;
3159167598Srrs				if (srto->srto_min)
3160166675Srrs					stcb->asoc.minrto = srto->srto_min;
3161166675Srrs				SCTP_TCB_UNLOCK(stcb);
3162166675Srrs			} else {
3163163953Srrs				SCTP_INP_WLOCK(inp);
3164163953Srrs				/*
3165163953Srrs				 * If we have a null asoc, its default for
3166163953Srrs				 * the endpoint
3167163953Srrs				 */
3168167598Srrs				if (srto->srto_initial)
3169163953Srrs					inp->sctp_ep.initial_rto = srto->srto_initial;
3170167598Srrs				if (srto->srto_max)
3171163953Srrs					inp->sctp_ep.sctp_maxrto = srto->srto_max;
3172167598Srrs				if (srto->srto_min)
3173163953Srrs					inp->sctp_ep.sctp_minrto = srto->srto_min;
3174163953Srrs				SCTP_INP_WUNLOCK(inp);
3175163953Srrs			}
3176163953Srrs		}
3177163953Srrs		break;
3178163953Srrs	case SCTP_ASSOCINFO:
3179163953Srrs		{
3180163953Srrs			struct sctp_assocparams *sasoc;
3181163953Srrs
3182166675Srrs			SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
3183166675Srrs			SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
3184166675Srrs
3185163953Srrs			if (stcb) {
3186163953Srrs				if (sasoc->sasoc_asocmaxrxt)
3187163953Srrs					stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
3188163953Srrs				sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
3189163953Srrs				sasoc->sasoc_peer_rwnd = 0;
3190163953Srrs				sasoc->sasoc_local_rwnd = 0;
3191163953Srrs				if (stcb->asoc.cookie_life)
3192163953Srrs					stcb->asoc.cookie_life = sasoc->sasoc_cookie_life;
3193167598Srrs				stcb->asoc.delayed_ack = sasoc->sasoc_sack_delay;
3194167598Srrs				if (sasoc->sasoc_sack_freq) {
3195167598Srrs					stcb->asoc.sack_freq = sasoc->sasoc_sack_freq;
3196167598Srrs				}
3197163953Srrs				SCTP_TCB_UNLOCK(stcb);
3198163953Srrs			} else {
3199163953Srrs				SCTP_INP_WLOCK(inp);
3200163953Srrs				if (sasoc->sasoc_asocmaxrxt)
3201163953Srrs					inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
3202163953Srrs				sasoc->sasoc_number_peer_destinations = 0;
3203163953Srrs				sasoc->sasoc_peer_rwnd = 0;
3204163953Srrs				sasoc->sasoc_local_rwnd = 0;
3205163953Srrs				if (sasoc->sasoc_cookie_life)
3206163953Srrs					inp->sctp_ep.def_cookie_life = sasoc->sasoc_cookie_life;
3207167598Srrs				inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sasoc->sasoc_sack_delay);
3208167598Srrs				if (sasoc->sasoc_sack_freq) {
3209167598Srrs					inp->sctp_ep.sctp_sack_freq = sasoc->sasoc_sack_freq;
3210167598Srrs				}
3211163953Srrs				SCTP_INP_WUNLOCK(inp);
3212163953Srrs			}
3213163953Srrs		}
3214163953Srrs		break;
3215163953Srrs	case SCTP_INITMSG:
3216163953Srrs		{
3217163953Srrs			struct sctp_initmsg *sinit;
3218163953Srrs
3219166675Srrs			SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
3220163953Srrs			SCTP_INP_WLOCK(inp);
3221163953Srrs			if (sinit->sinit_num_ostreams)
3222163953Srrs				inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
3223163953Srrs
3224163953Srrs			if (sinit->sinit_max_instreams)
3225163953Srrs				inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
3226163953Srrs
3227163953Srrs			if (sinit->sinit_max_attempts)
3228163953Srrs				inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
3229163953Srrs
3230167598Srrs			if (sinit->sinit_max_init_timeo)
3231163953Srrs				inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
3232163953Srrs			SCTP_INP_WUNLOCK(inp);
3233163953Srrs		}
3234163953Srrs		break;
3235163953Srrs	case SCTP_PRIMARY_ADDR:
3236163953Srrs		{
3237163953Srrs			struct sctp_setprim *spa;
3238163953Srrs			struct sctp_nets *net, *lnet;
3239163953Srrs
3240166675Srrs			SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
3241166675Srrs			SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
3242163953Srrs
3243166675Srrs			net = NULL;
3244166675Srrs			if (stcb) {
3245166675Srrs				net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr);
3246166675Srrs			} else {
3247166675Srrs				/*
3248166675Srrs				 * We increment here since
3249166675Srrs				 * sctp_findassociation_ep_addr() wil do a
3250166675Srrs				 * decrement if it finds the stcb as long as
3251166675Srrs				 * the locked tcb (last argument) is NOT a
3252166675Srrs				 * TCB.. aka NULL.
3253166675Srrs				 */
3254163953Srrs				SCTP_INP_INCR_REF(inp);
3255163953Srrs				stcb = sctp_findassociation_ep_addr(&inp,
3256163953Srrs				    (struct sockaddr *)&spa->ssp_addr,
3257163953Srrs				    &net, NULL, NULL);
3258163953Srrs				if (stcb == NULL) {
3259163953Srrs					SCTP_INP_DECR_REF(inp);
3260163953Srrs				}
3261163953Srrs			}
3262166675Srrs
3263166675Srrs			if ((stcb) && (net)) {
3264166675Srrs				if ((net != stcb->asoc.primary_destination) &&
3265166675Srrs				    (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
3266166675Srrs					/* Ok we need to set it */
3267166675Srrs					lnet = stcb->asoc.primary_destination;
3268166675Srrs					if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
3269166675Srrs						if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
3270166675Srrs							net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
3271166675Srrs						}
3272166675Srrs						net->dest_state |= SCTP_ADDR_SWITCH_PRIMARY;
3273163953Srrs					}
3274163953Srrs				}
3275166675Srrs			} else {
3276166675Srrs				error = EINVAL;
3277163953Srrs			}
3278166675Srrs			if (stcb) {
3279166675Srrs				SCTP_TCB_UNLOCK(stcb);
3280166675Srrs			}
3281163953Srrs		}
3282163953Srrs		break;
3283167598Srrs	case SCTP_SET_DYNAMIC_PRIMARY:
3284167598Srrs		{
3285167598Srrs			union sctp_sockstore *ss;
3286163953Srrs
3287167598Srrs			error = priv_check_cred(curthread->td_ucred,
3288167598Srrs			    PRIV_NETINET_RESERVEDPORT,
3289167598Srrs			    SUSER_ALLOWJAIL);
3290167598Srrs			if (error)
3291167598Srrs				break;
3292167598Srrs
3293167598Srrs			SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
3294167598Srrs			/* SUPER USER CHECK? */
3295167598Srrs			error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
3296167598Srrs		}
3297167598Srrs		break;
3298163953Srrs	case SCTP_SET_PEER_PRIMARY_ADDR:
3299163953Srrs		{
3300163953Srrs			struct sctp_setpeerprim *sspp;
3301163953Srrs
3302166675Srrs			SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
3303166675Srrs			SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
3304169208Srrs			if (stcb != NULL) {
3305166675Srrs				if (sctp_set_primary_ip_address_sa(stcb, (struct sockaddr *)&sspp->sspp_addr) != 0) {
3306166675Srrs					error = EINVAL;
3307166675Srrs				}
3308169208Srrs				SCTP_TCB_UNLOCK(stcb);
3309166675Srrs			} else {
3310163953Srrs				error = EINVAL;
3311163953Srrs			}
3312169208Srrs
3313163953Srrs		}
3314163953Srrs		break;
3315163953Srrs	case SCTP_BINDX_ADD_ADDR:
3316163953Srrs		{
3317163953Srrs			struct sctp_getaddresses *addrs;
3318163953Srrs			struct sockaddr *addr_touse;
3319163953Srrs			struct sockaddr_in sin;
3320163953Srrs
3321166675Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
3322166675Srrs
3323163953Srrs			/* see if we're bound all already! */
3324163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3325163953Srrs				error = EINVAL;
3326163953Srrs				break;
3327163953Srrs			}
3328167598Srrs			/* Is the VRF one we have */
3329163953Srrs			addr_touse = addrs->addr;
3330167695Srrs#if defined(INET6)
3331163953Srrs			if (addrs->addr->sa_family == AF_INET6) {
3332163953Srrs				struct sockaddr_in6 *sin6;
3333163953Srrs
3334163953Srrs				sin6 = (struct sockaddr_in6 *)addr_touse;
3335163953Srrs				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3336163953Srrs					in6_sin6_2_sin(&sin, sin6);
3337163953Srrs					addr_touse = (struct sockaddr *)&sin;
3338163953Srrs				}
3339163953Srrs			}
3340167695Srrs#endif
3341163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
3342163953Srrs				if (p == NULL) {
3343163953Srrs					/* Can't get proc for Net/Open BSD */
3344163953Srrs					error = EINVAL;
3345163953Srrs					break;
3346163953Srrs				}
3347163953Srrs				error = sctp_inpcb_bind(so, addr_touse, p);
3348163953Srrs				break;
3349163953Srrs			}
3350163953Srrs			/*
3351163953Srrs			 * No locks required here since bind and mgmt_ep_sa
3352163953Srrs			 * all do their own locking. If we do something for
3353163953Srrs			 * the FIX: below we may need to lock in that case.
3354163953Srrs			 */
3355163953Srrs			if (addrs->sget_assoc_id == 0) {
3356163953Srrs				/* add the address */
3357163953Srrs				struct sctp_inpcb *lep;
3358163953Srrs
3359163953Srrs				((struct sockaddr_in *)addr_touse)->sin_port = inp->sctp_lport;
3360167598Srrs				lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id);
3361163953Srrs				if (lep != NULL) {
3362163953Srrs					/*
3363163953Srrs					 * We must decrement the refcount
3364163953Srrs					 * since we have the ep already and
3365163953Srrs					 * are binding. No remove going on
3366163953Srrs					 * here.
3367163953Srrs					 */
3368163953Srrs					SCTP_INP_DECR_REF(inp);
3369163953Srrs				}
3370163953Srrs				if (lep == inp) {
3371163953Srrs					/* already bound to it.. ok */
3372163953Srrs					break;
3373163953Srrs				} else if (lep == NULL) {
3374163953Srrs					((struct sockaddr_in *)addr_touse)->sin_port = 0;
3375163953Srrs					error = sctp_addr_mgmt_ep_sa(inp, addr_touse,
3376167598Srrs					    SCTP_ADD_IP_ADDRESS, vrf_id);
3377163953Srrs				} else {
3378163953Srrs					error = EADDRNOTAVAIL;
3379163953Srrs				}
3380163953Srrs				if (error)
3381163953Srrs					break;
3382163953Srrs
3383163953Srrs			} else {
3384163953Srrs				/*
3385163953Srrs				 * FIX: decide whether we allow assoc based
3386163953Srrs				 * bindx
3387163953Srrs				 */
3388163953Srrs			}
3389163953Srrs		}
3390163953Srrs		break;
3391163953Srrs	case SCTP_BINDX_REM_ADDR:
3392163953Srrs		{
3393163953Srrs			struct sctp_getaddresses *addrs;
3394163953Srrs			struct sockaddr *addr_touse;
3395163953Srrs			struct sockaddr_in sin;
3396163953Srrs
3397166675Srrs			SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize);
3398163953Srrs			/* see if we're bound all already! */
3399163953Srrs			if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3400163953Srrs				error = EINVAL;
3401163953Srrs				break;
3402163953Srrs			}
3403163953Srrs			addr_touse = addrs->addr;
3404167695Srrs#if defined(INET6)
3405163953Srrs			if (addrs->addr->sa_family == AF_INET6) {
3406163953Srrs				struct sockaddr_in6 *sin6;
3407163953Srrs
3408163953Srrs				sin6 = (struct sockaddr_in6 *)addr_touse;
3409163953Srrs				if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
3410163953Srrs					in6_sin6_2_sin(&sin, sin6);
3411163953Srrs					addr_touse = (struct sockaddr *)&sin;
3412163953Srrs				}
3413163953Srrs			}
3414167695Srrs#endif
3415163953Srrs			/*
3416163953Srrs			 * No lock required mgmt_ep_sa does its own locking.
3417163953Srrs			 * If the FIX: below is ever changed we may need to
3418163953Srrs			 * lock before calling association level binding.
3419163953Srrs			 */
3420163953Srrs			if (addrs->sget_assoc_id == 0) {
3421163953Srrs				/* delete the address */
3422169420Srrs				(void)sctp_addr_mgmt_ep_sa(inp, addr_touse,
3423167598Srrs				    SCTP_DEL_IP_ADDRESS, vrf_id);
3424163953Srrs			} else {
3425163953Srrs				/*
3426163953Srrs				 * FIX: decide whether we allow assoc based
3427163953Srrs				 * bindx
3428163953Srrs				 */
3429163953Srrs			}
3430163953Srrs		}
3431163953Srrs		break;
3432163953Srrs	default:
3433163953Srrs		error = ENOPROTOOPT;
3434163953Srrs		break;
3435163953Srrs	}			/* end switch (opt) */
3436163953Srrs	return (error);
3437163953Srrs}
3438163953Srrs
3439163953Srrs
3440163953Srrsint
3441163953Srrssctp_ctloutput(struct socket *so, struct sockopt *sopt)
3442163953Srrs{
3443166675Srrs	void *optval = NULL;
3444166675Srrs	size_t optsize = 0;
3445163953Srrs	struct sctp_inpcb *inp;
3446166675Srrs	void *p;
3447166675Srrs	int error = 0;
3448163953Srrs
3449163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3450163953Srrs	if (inp == 0) {
3451163953Srrs		/* I made the same as TCP since we are not setup? */
3452163953Srrs		return (ECONNRESET);
3453163953Srrs	}
3454163953Srrs	if (sopt->sopt_level != IPPROTO_SCTP) {
3455163953Srrs		/* wrong proto level... send back up to IP */
3456163953Srrs#ifdef INET6
3457163953Srrs		if (INP_CHECK_SOCKAF(so, AF_INET6))
3458163953Srrs			error = ip6_ctloutput(so, sopt);
3459163953Srrs		else
3460163953Srrs#endif				/* INET6 */
3461163953Srrs			error = ip_ctloutput(so, sopt);
3462163953Srrs		return (error);
3463163953Srrs	}
3464166675Srrs	optsize = sopt->sopt_valsize;
3465166675Srrs	if (optsize) {
3466166675Srrs		SCTP_MALLOC(optval, void *, optsize, "SCTPSockOpt");
3467166675Srrs		if (optval == NULL) {
3468163953Srrs			return (ENOBUFS);
3469163953Srrs		}
3470166675Srrs		error = sooptcopyin(sopt, optval, optsize, optsize);
3471163953Srrs		if (error) {
3472166675Srrs			SCTP_FREE(optval);
3473163953Srrs			goto out;
3474163953Srrs		}
3475163953Srrs	}
3476166675Srrs	p = (void *)sopt->sopt_td;
3477163953Srrs	if (sopt->sopt_dir == SOPT_SET) {
3478166675Srrs		error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
3479163953Srrs	} else if (sopt->sopt_dir == SOPT_GET) {
3480166675Srrs		error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
3481163953Srrs	} else {
3482163953Srrs		error = EINVAL;
3483163953Srrs	}
3484166675Srrs	if ((error == 0) && (optval != NULL)) {
3485166675Srrs		error = sooptcopyout(sopt, optval, optsize);
3486166675Srrs		SCTP_FREE(optval);
3487166675Srrs	} else if (optval != NULL) {
3488166675Srrs		SCTP_FREE(optval);
3489163953Srrs	}
3490163953Srrsout:
3491163953Srrs	return (error);
3492163953Srrs}
3493163953Srrs
3494163953Srrs
3495163953Srrsstatic int
3496163953Srrssctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
3497163953Srrs{
3498163953Srrs	int error = 0;
3499163953Srrs	int create_lock_on = 0;
3500167598Srrs	uint32_t vrf_id;
3501163953Srrs	struct sctp_inpcb *inp;
3502163953Srrs	struct sctp_tcb *stcb = NULL;
3503163953Srrs
3504163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3505163953Srrs	if (inp == 0) {
3506163953Srrs		/* I made the same as TCP since we are not setup? */
3507163953Srrs		return (ECONNRESET);
3508163953Srrs	}
3509163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
3510163953Srrs	create_lock_on = 1;
3511163953Srrs
3512163953Srrs	SCTP_INP_INCR_REF(inp);
3513163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
3514163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
3515163953Srrs		/* Should I really unlock ? */
3516163953Srrs		error = EFAULT;
3517163953Srrs		goto out_now;
3518163953Srrs	}
3519163953Srrs#ifdef INET6
3520163953Srrs	if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
3521163953Srrs	    (addr->sa_family == AF_INET6)) {
3522163953Srrs		error = EINVAL;
3523163953Srrs		goto out_now;
3524163953Srrs	}
3525163953Srrs#endif				/* INET6 */
3526163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
3527163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
3528163953Srrs		/* Bind a ephemeral port */
3529163953Srrs		error = sctp_inpcb_bind(so, NULL, p);
3530163953Srrs		if (error) {
3531163953Srrs			goto out_now;
3532163953Srrs		}
3533163953Srrs	}
3534163953Srrs	/* Now do we connect? */
3535163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) {
3536163953Srrs		error = EINVAL;
3537163953Srrs		goto out_now;
3538163953Srrs	}
3539163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
3540163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
3541163953Srrs		/* We are already connected AND the TCP model */
3542163953Srrs		error = EADDRINUSE;
3543163953Srrs		goto out_now;
3544163953Srrs	}
3545163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3546163953Srrs		SCTP_INP_RLOCK(inp);
3547163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
3548163953Srrs		SCTP_INP_RUNLOCK(inp);
3549163953Srrs	} else {
3550163953Srrs		/*
3551166675Srrs		 * We increment here since sctp_findassociation_ep_addr()
3552166675Srrs		 * wil do a decrement if it finds the stcb as long as the
3553166675Srrs		 * locked tcb (last argument) is NOT a TCB.. aka NULL.
3554163953Srrs		 */
3555163953Srrs		SCTP_INP_INCR_REF(inp);
3556163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
3557163953Srrs		if (stcb == NULL) {
3558163953Srrs			SCTP_INP_DECR_REF(inp);
3559168299Srrs		} else {
3560168299Srrs			SCTP_TCB_LOCK(stcb);
3561163953Srrs		}
3562163953Srrs	}
3563163953Srrs	if (stcb != NULL) {
3564163953Srrs		/* Already have or am bring up an association */
3565163953Srrs		error = EALREADY;
3566163953Srrs		goto out_now;
3567163953Srrs	}
3568168299Srrs	vrf_id = inp->def_vrf_id;
3569163953Srrs	/* We are GOOD to go */
3570167598Srrs	stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id);
3571163953Srrs	if (stcb == NULL) {
3572163953Srrs		/* Gak! no memory */
3573167598Srrs		goto out_now;
3574163953Srrs	}
3575163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
3576163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
3577163953Srrs		/* Set the connected flag so we can queue data */
3578163953Srrs		soisconnecting(so);
3579163953Srrs	}
3580163953Srrs	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
3581169378Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
3582163953Srrs
3583163953Srrs	/* initialize authentication parameters for the assoc */
3584163953Srrs	sctp_initialize_auth_params(inp, stcb);
3585163953Srrs
3586163953Srrs	sctp_send_initiate(inp, stcb);
3587168299Srrs	SCTP_TCB_UNLOCK(stcb);
3588163953Srrsout_now:
3589169420Srrs	if (create_lock_on) {
3590163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
3591169420Srrs	}
3592163953Srrs	SCTP_INP_DECR_REF(inp);
3593163953Srrs	return error;
3594163953Srrs}
3595163953Srrs
3596163953Srrsint
3597163953Srrssctp_listen(struct socket *so, int backlog, struct thread *p)
3598163953Srrs{
3599163953Srrs	/*
3600163953Srrs	 * Note this module depends on the protocol processing being called
3601163953Srrs	 * AFTER any socket level flags and backlog are applied to the
3602163953Srrs	 * socket. The traditional way that the socket flags are applied is
3603163953Srrs	 * AFTER protocol processing. We have made a change to the
3604163953Srrs	 * sys/kern/uipc_socket.c module to reverse this but this MUST be in
3605163953Srrs	 * place if the socket API for SCTP is to work properly.
3606163953Srrs	 */
3607163953Srrs
3608163953Srrs	int error = 0;
3609163953Srrs	struct sctp_inpcb *inp;
3610163953Srrs
3611163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3612163953Srrs	if (inp == 0) {
3613163953Srrs		/* I made the same as TCP since we are not setup? */
3614163953Srrs		return (ECONNRESET);
3615163953Srrs	}
3616163953Srrs	SCTP_INP_RLOCK(inp);
3617163953Srrs#ifdef SCTP_LOCK_LOGGING
3618163953Srrs	sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
3619163953Srrs#endif
3620163953Srrs	SOCK_LOCK(so);
3621163953Srrs	error = solisten_proto_check(so);
3622163953Srrs	if (error) {
3623163953Srrs		SOCK_UNLOCK(so);
3624169208Srrs		SCTP_INP_RUNLOCK(inp);
3625163953Srrs		return (error);
3626163953Srrs	}
3627163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
3628163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
3629163953Srrs		/* We are already connected AND the TCP model */
3630163953Srrs		SCTP_INP_RUNLOCK(inp);
3631163953Srrs		SOCK_UNLOCK(so);
3632163953Srrs		return (EADDRINUSE);
3633163953Srrs	}
3634163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
3635163953Srrs		/* We must do a bind. */
3636166675Srrs		SOCK_UNLOCK(so);
3637163953Srrs		SCTP_INP_RUNLOCK(inp);
3638163953Srrs		if ((error = sctp_inpcb_bind(so, NULL, p))) {
3639163953Srrs			/* bind error, probably perm */
3640163953Srrs			return (error);
3641163953Srrs		}
3642166675Srrs		SOCK_LOCK(so);
3643163953Srrs	} else {
3644163953Srrs		SCTP_INP_RUNLOCK(inp);
3645163953Srrs	}
3646163953Srrs	/* It appears for 7.0 and on, we must always call this. */
3647163953Srrs	solisten_proto(so, backlog);
3648163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
3649163953Srrs		/* remove the ACCEPTCONN flag for one-to-many sockets */
3650163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
3651163953Srrs	}
3652163953Srrs	if (backlog == 0) {
3653163953Srrs		/* turning off listen */
3654163953Srrs		so->so_options &= ~SO_ACCEPTCONN;
3655163953Srrs	}
3656163953Srrs	SOCK_UNLOCK(so);
3657163953Srrs	return (error);
3658163953Srrs}
3659163953Srrs
3660163953Srrsstatic int sctp_defered_wakeup_cnt = 0;
3661163953Srrs
3662163953Srrsint
3663163953Srrssctp_accept(struct socket *so, struct sockaddr **addr)
3664163953Srrs{
3665163953Srrs	struct sctp_tcb *stcb;
3666163953Srrs	struct sctp_inpcb *inp;
3667163953Srrs	union sctp_sockstore store;
3668163953Srrs
3669163953Srrs	int error;
3670163953Srrs
3671163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3672163953Srrs
3673163953Srrs	if (inp == 0) {
3674163953Srrs		return (ECONNRESET);
3675163953Srrs	}
3676163953Srrs	SCTP_INP_RLOCK(inp);
3677163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
3678168299Srrs		SCTP_INP_RUNLOCK(inp);
3679163953Srrs		return (ENOTSUP);
3680163953Srrs	}
3681163953Srrs	if (so->so_state & SS_ISDISCONNECTED) {
3682163953Srrs		SCTP_INP_RUNLOCK(inp);
3683163953Srrs		return (ECONNABORTED);
3684163953Srrs	}
3685163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
3686163953Srrs	if (stcb == NULL) {
3687163953Srrs		SCTP_INP_RUNLOCK(inp);
3688163953Srrs		return (ECONNRESET);
3689163953Srrs	}
3690163953Srrs	SCTP_TCB_LOCK(stcb);
3691163953Srrs	SCTP_INP_RUNLOCK(inp);
3692163953Srrs	store = stcb->asoc.primary_destination->ro._l_addr;
3693163953Srrs	SCTP_TCB_UNLOCK(stcb);
3694163953Srrs	if (store.sa.sa_family == AF_INET) {
3695163953Srrs		struct sockaddr_in *sin;
3696163953Srrs
3697163953Srrs		SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
3698163953Srrs		sin->sin_family = AF_INET;
3699163953Srrs		sin->sin_len = sizeof(*sin);
3700163953Srrs		sin->sin_port = ((struct sockaddr_in *)&store)->sin_port;
3701163953Srrs		sin->sin_addr = ((struct sockaddr_in *)&store)->sin_addr;
3702163953Srrs		*addr = (struct sockaddr *)sin;
3703163953Srrs	} else {
3704163953Srrs		struct sockaddr_in6 *sin6;
3705163953Srrs
3706163953Srrs		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
3707163953Srrs		sin6->sin6_family = AF_INET6;
3708163953Srrs		sin6->sin6_len = sizeof(*sin6);
3709163953Srrs		sin6->sin6_port = ((struct sockaddr_in6 *)&store)->sin6_port;
3710163953Srrs
3711163953Srrs		sin6->sin6_addr = ((struct sockaddr_in6 *)&store)->sin6_addr;
3712164085Srrs		if ((error = sa6_recoverscope(sin6)) != 0) {
3713164085Srrs			SCTP_FREE_SONAME(sin6);
3714163953Srrs			return (error);
3715164085Srrs		}
3716163953Srrs		*addr = (struct sockaddr *)sin6;
3717163953Srrs	}
3718163953Srrs	/* Wake any delayed sleep action */
3719163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
3720166086Srrs		SCTP_INP_WLOCK(inp);
3721163953Srrs		inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
3722163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
3723163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
3724166086Srrs			SCTP_INP_WUNLOCK(inp);
3725163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
3726163953Srrs			if (sowriteable(inp->sctp_socket)) {
3727163953Srrs				sowwakeup_locked(inp->sctp_socket);
3728163953Srrs			} else {
3729163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
3730163953Srrs			}
3731166086Srrs			SCTP_INP_WLOCK(inp);
3732163953Srrs		}
3733163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
3734163953Srrs			inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
3735166086Srrs			SCTP_INP_WUNLOCK(inp);
3736163953Srrs			SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
3737163953Srrs			if (soreadable(inp->sctp_socket)) {
3738163953Srrs				sctp_defered_wakeup_cnt++;
3739163953Srrs				sorwakeup_locked(inp->sctp_socket);
3740163953Srrs			} else {
3741163953Srrs				SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
3742163953Srrs			}
3743166086Srrs			SCTP_INP_WLOCK(inp);
3744163953Srrs		}
3745166086Srrs		SCTP_INP_WUNLOCK(inp);
3746163953Srrs	}
3747163953Srrs	return (0);
3748163953Srrs}
3749163953Srrs
3750163953Srrsint
3751163953Srrssctp_ingetaddr(struct socket *so, struct sockaddr **addr)
3752163953Srrs{
3753163953Srrs	struct sockaddr_in *sin;
3754167598Srrs	uint32_t vrf_id;
3755163953Srrs	struct sctp_inpcb *inp;
3756167695Srrs	struct sctp_ifa *sctp_ifa;
3757163953Srrs
3758163953Srrs	/*
3759163953Srrs	 * Do the malloc first in case it blocks.
3760163953Srrs	 */
3761163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
3762163953Srrs	sin->sin_family = AF_INET;
3763163953Srrs	sin->sin_len = sizeof(*sin);
3764163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3765163953Srrs	if (!inp) {
3766163953Srrs		SCTP_FREE_SONAME(sin);
3767163953Srrs		return ECONNRESET;
3768163953Srrs	}
3769163953Srrs	SCTP_INP_RLOCK(inp);
3770163953Srrs	sin->sin_port = inp->sctp_lport;
3771163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
3772163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
3773163953Srrs			struct sctp_tcb *stcb;
3774163953Srrs			struct sockaddr_in *sin_a;
3775163953Srrs			struct sctp_nets *net;
3776163953Srrs			int fnd;
3777163953Srrs
3778163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
3779163953Srrs			if (stcb == NULL) {
3780163953Srrs				goto notConn;
3781163953Srrs			}
3782163953Srrs			fnd = 0;
3783163953Srrs			sin_a = NULL;
3784163953Srrs			SCTP_TCB_LOCK(stcb);
3785163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3786163953Srrs				sin_a = (struct sockaddr_in *)&net->ro._l_addr;
3787164085Srrs				if (sin_a == NULL)
3788164085Srrs					/* this will make coverity happy */
3789164085Srrs					continue;
3790164085Srrs
3791163953Srrs				if (sin_a->sin_family == AF_INET) {
3792163953Srrs					fnd = 1;
3793163953Srrs					break;
3794163953Srrs				}
3795163953Srrs			}
3796163953Srrs			if ((!fnd) || (sin_a == NULL)) {
3797163953Srrs				/* punt */
3798163953Srrs				SCTP_TCB_UNLOCK(stcb);
3799163953Srrs				goto notConn;
3800163953Srrs			}
3801168299Srrs			vrf_id = inp->def_vrf_id;
3802167598Srrs			sctp_ifa = sctp_source_address_selection(inp,
3803167598Srrs			    stcb,
3804168299Srrs			    (sctp_route_t *) & net->ro,
3805167598Srrs			    net, 0, vrf_id);
3806167598Srrs			if (sctp_ifa) {
3807167598Srrs				sin->sin_addr = sctp_ifa->address.sin.sin_addr;
3808167598Srrs				sctp_free_ifa(sctp_ifa);
3809167598Srrs			}
3810163953Srrs			SCTP_TCB_UNLOCK(stcb);
3811163953Srrs		} else {
3812163953Srrs			/* For the bound all case you get back 0 */
3813163953Srrs	notConn:
3814163953Srrs			sin->sin_addr.s_addr = 0;
3815163953Srrs		}
3816163953Srrs
3817163953Srrs	} else {
3818163953Srrs		/* Take the first IPv4 address in the list */
3819163953Srrs		struct sctp_laddr *laddr;
3820163953Srrs		int fnd = 0;
3821163953Srrs
3822163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
3823167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET) {
3824163953Srrs				struct sockaddr_in *sin_a;
3825163953Srrs
3826167598Srrs				sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa;
3827163953Srrs				sin->sin_addr = sin_a->sin_addr;
3828163953Srrs				fnd = 1;
3829163953Srrs				break;
3830163953Srrs			}
3831163953Srrs		}
3832163953Srrs		if (!fnd) {
3833163953Srrs			SCTP_FREE_SONAME(sin);
3834163953Srrs			SCTP_INP_RUNLOCK(inp);
3835163953Srrs			return ENOENT;
3836163953Srrs		}
3837163953Srrs	}
3838163953Srrs	SCTP_INP_RUNLOCK(inp);
3839163953Srrs	(*addr) = (struct sockaddr *)sin;
3840163953Srrs	return (0);
3841163953Srrs}
3842163953Srrs
3843163953Srrsint
3844163953Srrssctp_peeraddr(struct socket *so, struct sockaddr **addr)
3845163953Srrs{
3846163953Srrs	struct sockaddr_in *sin = (struct sockaddr_in *)*addr;
3847166086Srrs	int fnd;
3848163953Srrs	struct sockaddr_in *sin_a;
3849163953Srrs	struct sctp_inpcb *inp;
3850163953Srrs	struct sctp_tcb *stcb;
3851163953Srrs	struct sctp_nets *net;
3852163953Srrs
3853163953Srrs	/* Do the malloc first in case it blocks. */
3854163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3855163953Srrs	if ((inp == NULL) ||
3856163953Srrs	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
3857163953Srrs		/* UDP type and listeners will drop out here */
3858163953Srrs		return (ENOTCONN);
3859163953Srrs	}
3860163953Srrs	SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
3861163953Srrs	sin->sin_family = AF_INET;
3862163953Srrs	sin->sin_len = sizeof(*sin);
3863163953Srrs
3864163953Srrs	/* We must recapture incase we blocked */
3865163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
3866163953Srrs	if (!inp) {
3867163953Srrs		SCTP_FREE_SONAME(sin);
3868163953Srrs		return ECONNRESET;
3869163953Srrs	}
3870163953Srrs	SCTP_INP_RLOCK(inp);
3871163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
3872169420Srrs	if (stcb) {
3873163953Srrs		SCTP_TCB_LOCK(stcb);
3874169420Srrs	}
3875163953Srrs	SCTP_INP_RUNLOCK(inp);
3876163953Srrs	if (stcb == NULL) {
3877163953Srrs		SCTP_FREE_SONAME(sin);
3878163953Srrs		return ECONNRESET;
3879163953Srrs	}
3880163953Srrs	fnd = 0;
3881163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
3882163953Srrs		sin_a = (struct sockaddr_in *)&net->ro._l_addr;
3883163953Srrs		if (sin_a->sin_family == AF_INET) {
3884163953Srrs			fnd = 1;
3885163953Srrs			sin->sin_port = stcb->rport;
3886163953Srrs			sin->sin_addr = sin_a->sin_addr;
3887163953Srrs			break;
3888163953Srrs		}
3889163953Srrs	}
3890163953Srrs	SCTP_TCB_UNLOCK(stcb);
3891163953Srrs	if (!fnd) {
3892163953Srrs		/* No IPv4 address */
3893163953Srrs		SCTP_FREE_SONAME(sin);
3894163953Srrs		return ENOENT;
3895163953Srrs	}
3896163953Srrs	(*addr) = (struct sockaddr *)sin;
3897163953Srrs	return (0);
3898163953Srrs}
3899163953Srrs
3900163953Srrsstruct pr_usrreqs sctp_usrreqs = {
3901163953Srrs	.pru_abort = sctp_abort,
3902163953Srrs	.pru_accept = sctp_accept,
3903163953Srrs	.pru_attach = sctp_attach,
3904163953Srrs	.pru_bind = sctp_bind,
3905163953Srrs	.pru_connect = sctp_connect,
3906163953Srrs	.pru_control = in_control,
3907163953Srrs	.pru_close = sctp_close,
3908163953Srrs	.pru_detach = sctp_close,
3909163953Srrs	.pru_sopoll = sopoll_generic,
3910163953Srrs	.pru_disconnect = sctp_disconnect,
3911163953Srrs	.pru_listen = sctp_listen,
3912163953Srrs	.pru_peeraddr = sctp_peeraddr,
3913163953Srrs	.pru_send = sctp_sendm,
3914163953Srrs	.pru_shutdown = sctp_shutdown,
3915163953Srrs	.pru_sockaddr = sctp_ingetaddr,
3916163953Srrs	.pru_sosend = sctp_sosend,
3917163953Srrs	.pru_soreceive = sctp_soreceive
3918163953Srrs};
3919