sctp6_usrreq.c revision 319402
1163953Srrs/*-
2169382Srrs * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3235828Stuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4235828Stuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5163953Srrs *
6163953Srrs * Redistribution and use in source and binary forms, with or without
7163953Srrs * modification, are permitted provided that the following conditions are met:
8163953Srrs *
9163953Srrs * a) Redistributions of source code must retain the above copyright notice,
10228653Stuexen *    this list of conditions and the following disclaimer.
11163953Srrs *
12163953Srrs * b) Redistributions in binary form must reproduce the above copyright
13163953Srrs *    notice, this list of conditions and the following disclaimer in
14228653Stuexen *    the documentation and/or other materials provided with the distribution.
15163953Srrs *
16163953Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its
17163953Srrs *    contributors may be used to endorse or promote products derived
18163953Srrs *    from this software without specific prior written permission.
19163953Srrs *
20163953Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21163953Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22163953Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24163953Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25163953Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26163953Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27163953Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28163953Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29163953Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30163953Srrs * THE POSSIBILITY OF SUCH DAMAGE.
31163953Srrs */
32174510Sobrien
33163954Srrs#include <sys/cdefs.h>
34163953Srrs__FBSDID("$FreeBSD: stable/11/sys/netinet6/sctp6_usrreq.c 319402 2017-06-01 08:48:16Z tuexen $");
35163953Srrs
36166086Srrs#include <netinet/sctp_os.h>
37238501Stuexen#ifdef INET6
38163953Srrs#include <sys/proc.h>
39163953Srrs#include <netinet/sctp_pcb.h>
40163953Srrs#include <netinet/sctp_header.h>
41163953Srrs#include <netinet/sctp_var.h>
42168709Srrs#include <netinet6/sctp6_var.h>
43167598Srrs#include <netinet/sctp_sysctl.h>
44163953Srrs#include <netinet/sctp_output.h>
45166086Srrs#include <netinet/sctp_uio.h>
46163953Srrs#include <netinet/sctp_asconf.h>
47166086Srrs#include <netinet/sctputil.h>
48166086Srrs#include <netinet/sctp_indata.h>
49166086Srrs#include <netinet/sctp_timer.h>
50166086Srrs#include <netinet/sctp_auth.h>
51168709Srrs#include <netinet/sctp_input.h>
52168709Srrs#include <netinet/sctp_output.h>
53170091Srrs#include <netinet/sctp_bsd_addr.h>
54188067Srrs#include <netinet/sctp_crc32.h>
55285877Stuexen#include <netinet/icmp6.h>
56179783Srrs#include <netinet/udp.h>
57163953Srrs
58163953Srrsextern struct protosw inetsw[];
59163953Srrs
60163953Srrsint
61243186Stuexensctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port)
62163953Srrs{
63165647Srrs	struct mbuf *m;
64237569Stuexen	int iphlen;
65238003Stuexen	uint32_t vrf_id;
66237569Stuexen	uint8_t ecn_bits;
67237715Stuexen	struct sockaddr_in6 src, dst;
68163953Srrs	struct ip6_hdr *ip6;
69163953Srrs	struct sctphdr *sh;
70163953Srrs	struct sctp_chunkhdr *ch;
71237569Stuexen	int length, offset;
72211969Stuexen#if !defined(SCTP_WITH_NO_CSUM)
73238003Stuexen	uint8_t compute_crc;
74211969Stuexen#endif
75238003Stuexen	uint32_t mflowid;
76275483Stuexen	uint8_t mflowtype;
77284515Stuexen	uint16_t fibnum;
78163953Srrs
79237569Stuexen	iphlen = *offp;
80169352Srrs	if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
81169352Srrs		SCTP_RELEASE_PKT(*i_pak);
82237569Stuexen		return (IPPROTO_DONE);
83169352Srrs	}
84168709Srrs	m = SCTP_HEADER_TO_CHAIN(*i_pak);
85237569Stuexen#ifdef SCTP_MBUF_LOGGING
86237569Stuexen	/* Log in any input mbufs */
87237569Stuexen	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
88276914Stuexen		sctp_log_mbc(m, SCTP_MBUF_INPUT);
89237569Stuexen	}
90237569Stuexen#endif
91237540Stuexen#ifdef SCTP_PACKET_LOGGING
92237540Stuexen	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
93237540Stuexen		sctp_packet_log(m);
94237540Stuexen	}
95170091Srrs#endif
96238003Stuexen	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
97254854Stuexen	    "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n",
98238003Stuexen	    m->m_pkthdr.len,
99238003Stuexen	    if_name(m->m_pkthdr.rcvif),
100254854Stuexen	    (int)m->m_pkthdr.csum_flags, CSUM_BITS);
101275483Stuexen	mflowid = m->m_pkthdr.flowid;
102275483Stuexen	mflowtype = M_HASHTYPE_GET(m);
103284515Stuexen	fibnum = M_GETFIB(m);
104237569Stuexen	SCTP_STAT_INCR(sctps_recvpackets);
105237569Stuexen	SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
106237569Stuexen	/* Get IP, SCTP, and first chunk header together in the first mbuf. */
107238003Stuexen	offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
108163953Srrs	ip6 = mtod(m, struct ip6_hdr *);
109237569Stuexen	IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
110237569Stuexen	    (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
111163953Srrs	if (sh == NULL) {
112163953Srrs		SCTP_STAT_INCR(sctps_hdrops);
113228907Stuexen		return (IPPROTO_DONE);
114163953Srrs	}
115163953Srrs	ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
116237569Stuexen	offset -= sizeof(struct sctp_chunkhdr);
117237715Stuexen	memset(&src, 0, sizeof(struct sockaddr_in6));
118237715Stuexen	src.sin6_family = AF_INET6;
119237715Stuexen	src.sin6_len = sizeof(struct sockaddr_in6);
120237715Stuexen	src.sin6_port = sh->src_port;
121237715Stuexen	src.sin6_addr = ip6->ip6_src;
122237715Stuexen	if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
123238003Stuexen		goto out;
124237715Stuexen	}
125237715Stuexen	memset(&dst, 0, sizeof(struct sockaddr_in6));
126237715Stuexen	dst.sin6_family = AF_INET6;
127237715Stuexen	dst.sin6_len = sizeof(struct sockaddr_in6);
128237715Stuexen	dst.sin6_port = sh->dest_port;
129237715Stuexen	dst.sin6_addr = ip6->ip6_dst;
130237715Stuexen	if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
131238003Stuexen		goto out;
132237715Stuexen	}
133237569Stuexen	length = ntohs(ip6->ip6_plen) + iphlen;
134237569Stuexen	/* Validate mbuf chain length with IP payload length. */
135238003Stuexen	if (SCTP_HEADER_LEN(m) != length) {
136237569Stuexen		SCTPDBG(SCTP_DEBUG_INPUT1,
137238003Stuexen		    "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m));
138237569Stuexen		SCTP_STAT_INCR(sctps_hdrops);
139238003Stuexen		goto out;
140237569Stuexen	}
141163953Srrs	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
142238003Stuexen		goto out;
143163953Srrs	}
144238003Stuexen	ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
145211969Stuexen#if defined(SCTP_WITH_NO_CSUM)
146211969Stuexen	SCTP_STAT_INCR(sctps_recvnocrc);
147211969Stuexen#else
148188067Srrs	if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
149188067Srrs		SCTP_STAT_INCR(sctps_recvhwcrc);
150238003Stuexen		compute_crc = 0;
151238003Stuexen	} else {
152238003Stuexen		SCTP_STAT_INCR(sctps_recvswcrc);
153238003Stuexen		compute_crc = 1;
154188067Srrs	}
155218400Stuexen#endif
156238003Stuexen	sctp_common_input_processing(&m, iphlen, offset, length,
157237715Stuexen	    (struct sockaddr *)&src,
158237715Stuexen	    (struct sockaddr *)&dst,
159238003Stuexen	    sh, ch,
160238003Stuexen#if !defined(SCTP_WITH_NO_CSUM)
161238003Stuexen	    compute_crc,
162218400Stuexen#endif
163238003Stuexen	    ecn_bits,
164284515Stuexen	    mflowtype, mflowid, fibnum,
165237049Stuexen	    vrf_id, port);
166238003Stuexenout:
167237569Stuexen	if (m) {
168169352Srrs		sctp_m_freem(m);
169237569Stuexen	}
170228907Stuexen	return (IPPROTO_DONE);
171163953Srrs}
172163953Srrs
173163953Srrs
174243186Stuexenint
175243186Stuexensctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED)
176243186Stuexen{
177243186Stuexen	return (sctp6_input_with_port(i_pak, offp, 0));
178243186Stuexen}
179243186Stuexen
180172156Srrsvoid
181172091Srrssctp6_notify(struct sctp_inpcb *inp,
182172091Srrs    struct sctp_tcb *stcb,
183298132Stuexen    struct sctp_nets *net,
184298132Stuexen    uint8_t icmp6_type,
185298132Stuexen    uint8_t icmp6_code,
186319402Stuexen    uint32_t next_mtu)
187172091Srrs{
188237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
189172091Srrs	struct socket *so;
190172091Srrs#endif
191298132Stuexen	int timer_stopped;
192235360Stuexen
193298132Stuexen	switch (icmp6_type) {
194298132Stuexen	case ICMP6_DST_UNREACH:
195298132Stuexen		if ((icmp6_code == ICMP6_DST_UNREACH_NOROUTE) ||
196298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_ADMIN) ||
197298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_BEYONDSCOPE) ||
198298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_ADDR)) {
199298132Stuexen			/* Mark the net unreachable. */
200298132Stuexen			if (net->dest_state & SCTP_ADDR_REACHABLE) {
201298132Stuexen				/* Ok that destination is not reachable */
202298132Stuexen				net->dest_state &= ~SCTP_ADDR_REACHABLE;
203298132Stuexen				net->dest_state &= ~SCTP_ADDR_PF;
204298132Stuexen				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
205298132Stuexen				    stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED);
206298132Stuexen			}
207172091Srrs		}
208172091Srrs		SCTP_TCB_UNLOCK(stcb);
209298132Stuexen		break;
210298132Stuexen	case ICMP6_PARAM_PROB:
211298132Stuexen		/* Treat it like an ABORT. */
212298132Stuexen		if (icmp6_code == ICMP6_PARAMPROB_NEXTHEADER) {
213298132Stuexen			sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
214237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
215298132Stuexen			so = SCTP_INP_SO(inp);
216298132Stuexen			atomic_add_int(&stcb->asoc.refcnt, 1);
217298132Stuexen			SCTP_TCB_UNLOCK(stcb);
218298132Stuexen			SCTP_SOCKET_LOCK(so, 1);
219298132Stuexen			SCTP_TCB_LOCK(stcb);
220298132Stuexen			atomic_subtract_int(&stcb->asoc.refcnt, 1);
221172091Srrs#endif
222298132Stuexen			(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
223298132Stuexen			    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
224237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
225298132Stuexen			SCTP_SOCKET_UNLOCK(so, 1);
226172091Srrs#endif
227298132Stuexen		} else {
228298132Stuexen			SCTP_TCB_UNLOCK(stcb);
229298132Stuexen		}
230298132Stuexen		break;
231298132Stuexen	case ICMP6_PACKET_TOO_BIG:
232298132Stuexen		if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
233298132Stuexen			timer_stopped = 1;
234298132Stuexen			sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
235298132Stuexen			    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
236298132Stuexen		} else {
237298132Stuexen			timer_stopped = 0;
238298132Stuexen		}
239298132Stuexen		/* Update the path MTU. */
240298132Stuexen		if (net->mtu > next_mtu) {
241298132Stuexen			net->mtu = next_mtu;
242298132Stuexen			if (net->port) {
243298132Stuexen				net->mtu -= sizeof(struct udphdr);
244298132Stuexen			}
245298132Stuexen		}
246298132Stuexen		/* Update the association MTU */
247298132Stuexen		if (stcb->asoc.smallest_mtu > next_mtu) {
248298132Stuexen			sctp_pathmtu_adjustment(stcb, next_mtu);
249298132Stuexen		}
250298132Stuexen		/* Finally, start the PMTU timer if it was running before. */
251298132Stuexen		if (timer_stopped) {
252298132Stuexen			sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
253298132Stuexen		}
254172091Srrs		SCTP_TCB_UNLOCK(stcb);
255298132Stuexen		break;
256298132Stuexen	default:
257298132Stuexen		SCTP_TCB_UNLOCK(stcb);
258298132Stuexen		break;
259172091Srrs	}
260172091Srrs}
261172091Srrs
262163953Srrsvoid
263171259Sdelphijsctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
264163953Srrs{
265298132Stuexen	struct ip6ctlparam *ip6cp;
266298132Stuexen	struct sctp_inpcb *inp;
267298132Stuexen	struct sctp_tcb *stcb;
268298132Stuexen	struct sctp_nets *net;
269163953Srrs	struct sctphdr sh;
270298132Stuexen	struct sockaddr_in6 src, dst;
271163953Srrs
272163953Srrs	if (pktdst->sa_family != AF_INET6 ||
273298132Stuexen	    pktdst->sa_len != sizeof(struct sockaddr_in6)) {
274163953Srrs		return;
275298132Stuexen	}
276298132Stuexen	if ((unsigned)cmd >= PRC_NCMDS) {
277163953Srrs		return;
278298132Stuexen	}
279163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
280163953Srrs		d = NULL;
281163953Srrs	} else if (inet6ctlerrmap[cmd] == 0) {
282163953Srrs		return;
283163953Srrs	}
284298132Stuexen	/* If the parameter is from icmp6, decode it. */
285163953Srrs	if (d != NULL) {
286163953Srrs		ip6cp = (struct ip6ctlparam *)d;
287163953Srrs	} else {
288163953Srrs		ip6cp = (struct ip6ctlparam *)NULL;
289163953Srrs	}
290163953Srrs
291298132Stuexen	if (ip6cp != NULL) {
292163953Srrs		/*
293163953Srrs		 * XXX: We assume that when IPV6 is non NULL, M and OFF are
294163953Srrs		 * valid.
295163953Srrs		 */
296298132Stuexen		if (ip6cp->ip6c_m == NULL) {
297163953Srrs			return;
298298132Stuexen		}
299298132Stuexen		/*
300298132Stuexen		 * Check if we can safely examine the ports and the
301298132Stuexen		 * verification tag of the SCTP common header.
302298132Stuexen		 */
303298132Stuexen		if (ip6cp->ip6c_m->m_pkthdr.len <
304310773Stuexen		    (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) {
305293906Sglebius			return;
306298132Stuexen		}
307298132Stuexen		/* Copy out the port numbers and the verification tag. */
308163953Srrs		bzero(&sh, sizeof(sh));
309298132Stuexen		m_copydata(ip6cp->ip6c_m,
310298132Stuexen		    ip6cp->ip6c_off,
311298132Stuexen		    sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
312298132Stuexen		    (caddr_t)&sh);
313298132Stuexen		memset(&src, 0, sizeof(struct sockaddr_in6));
314298132Stuexen		src.sin6_family = AF_INET6;
315298132Stuexen		src.sin6_len = sizeof(struct sockaddr_in6);
316298132Stuexen		src.sin6_port = sh.src_port;
317298132Stuexen		src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
318298132Stuexen		if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
319298132Stuexen			return;
320298132Stuexen		}
321298132Stuexen		memset(&dst, 0, sizeof(struct sockaddr_in6));
322298132Stuexen		dst.sin6_family = AF_INET6;
323298132Stuexen		dst.sin6_len = sizeof(struct sockaddr_in6);
324298132Stuexen		dst.sin6_port = sh.dest_port;
325298132Stuexen		dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
326298132Stuexen		if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
327298132Stuexen			return;
328298132Stuexen		}
329163953Srrs		inp = NULL;
330163953Srrs		net = NULL;
331298132Stuexen		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
332298132Stuexen		    (struct sockaddr *)&src,
333298132Stuexen		    &inp, &net, 1, SCTP_DEFAULT_VRFID);
334298132Stuexen		if ((stcb != NULL) &&
335298132Stuexen		    (net != NULL) &&
336302138Stuexen		    (inp != NULL)) {
337298132Stuexen			/* Check the verification tag */
338298132Stuexen			if (ntohl(sh.v_tag) != 0) {
339298132Stuexen				/*
340298132Stuexen				 * This must be the verification tag used
341298132Stuexen				 * for sending out packets. We don't
342298132Stuexen				 * consider packets reflecting the
343298132Stuexen				 * verification tag.
344298132Stuexen				 */
345298132Stuexen				if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
346298132Stuexen					SCTP_TCB_UNLOCK(stcb);
347298132Stuexen					return;
348298132Stuexen				}
349163953Srrs			} else {
350298132Stuexen				if (ip6cp->ip6c_m->m_pkthdr.len >=
351298132Stuexen				    ip6cp->ip6c_off + sizeof(struct sctphdr) +
352298132Stuexen				    sizeof(struct sctp_chunkhdr) +
353298132Stuexen				    offsetof(struct sctp_init, a_rwnd)) {
354298132Stuexen					/*
355298132Stuexen					 * In this case we can check if we
356298132Stuexen					 * got an INIT chunk and if the
357298132Stuexen					 * initiate tag matches.
358298132Stuexen					 */
359298132Stuexen					uint32_t initiate_tag;
360298132Stuexen					uint8_t chunk_type;
361298132Stuexen
362298132Stuexen					m_copydata(ip6cp->ip6c_m,
363298132Stuexen					    ip6cp->ip6c_off +
364298132Stuexen					    sizeof(struct sctphdr),
365298132Stuexen					    sizeof(uint8_t),
366298132Stuexen					    (caddr_t)&chunk_type);
367298132Stuexen					m_copydata(ip6cp->ip6c_m,
368298132Stuexen					    ip6cp->ip6c_off +
369298132Stuexen					    sizeof(struct sctphdr) +
370298132Stuexen					    sizeof(struct sctp_chunkhdr),
371298132Stuexen					    sizeof(uint32_t),
372298132Stuexen					    (caddr_t)&initiate_tag);
373298132Stuexen					if ((chunk_type != SCTP_INITIATION) ||
374298132Stuexen					    (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
375298132Stuexen						SCTP_TCB_UNLOCK(stcb);
376298132Stuexen						return;
377298132Stuexen					}
378298132Stuexen				} else {
379298132Stuexen					SCTP_TCB_UNLOCK(stcb);
380298132Stuexen					return;
381298132Stuexen				}
382163953Srrs			}
383298132Stuexen			sctp6_notify(inp, stcb, net,
384298132Stuexen			    ip6cp->ip6c_icmp6->icmp6_type,
385298132Stuexen			    ip6cp->ip6c_icmp6->icmp6_code,
386319402Stuexen			    ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
387163953Srrs		} else {
388298132Stuexen			if ((stcb == NULL) && (inp != NULL)) {
389163953Srrs				/* reduce inp's ref-count */
390163953Srrs				SCTP_INP_WLOCK(inp);
391163953Srrs				SCTP_INP_DECR_REF(inp);
392163953Srrs				SCTP_INP_WUNLOCK(inp);
393163953Srrs			}
394298132Stuexen			if (stcb) {
395163953Srrs				SCTP_TCB_UNLOCK(stcb);
396298132Stuexen			}
397163953Srrs		}
398163953Srrs	}
399163953Srrs}
400163953Srrs
401163953Srrs/*
402163953Srrs * this routine can probably be collasped into the one in sctp_userreq.c
403163953Srrs * since they do the same thing and now we lookup with a sockaddr
404163953Srrs */
405163953Srrsstatic int
406163953Srrssctp6_getcred(SYSCTL_HANDLER_ARGS)
407163953Srrs{
408164085Srrs	struct xucred xuc;
409163953Srrs	struct sockaddr_in6 addrs[2];
410163953Srrs	struct sctp_inpcb *inp;
411163953Srrs	struct sctp_nets *net;
412163953Srrs	struct sctp_tcb *stcb;
413164085Srrs	int error;
414167598Srrs	uint32_t vrf_id;
415163953Srrs
416167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
417167598Srrs
418170587Srwatson	error = priv_check(req->td, PRIV_NETINET_GETCRED);
419163953Srrs	if (error)
420163953Srrs		return (error);
421163953Srrs
422171943Srrs	if (req->newlen != sizeof(addrs)) {
423171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
424163953Srrs		return (EINVAL);
425171943Srrs	}
426171943Srrs	if (req->oldlen != sizeof(struct ucred)) {
427171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
428163953Srrs		return (EINVAL);
429171943Srrs	}
430163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
431163953Srrs	if (error)
432163953Srrs		return (error);
433163953Srrs
434237715Stuexen	stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]),
435237715Stuexen	    sin6tosa(&addrs[0]),
436167598Srrs	    &inp, &net, 1, vrf_id);
437163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
438164085Srrs		if ((inp != NULL) && (stcb == NULL)) {
439164085Srrs			/* reduce ref-count */
440163953Srrs			SCTP_INP_WLOCK(inp);
441163953Srrs			SCTP_INP_DECR_REF(inp);
442164085Srrs			goto cred_can_cont;
443163953Srrs		}
444171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
445164085Srrs		error = ENOENT;
446163953Srrs		goto out;
447163953Srrs	}
448163953Srrs	SCTP_TCB_UNLOCK(stcb);
449164085Srrs	/*
450164085Srrs	 * We use the write lock here, only since in the error leg we need
451164085Srrs	 * it. If we used RLOCK, then we would have to
452164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
453164085Srrs	 * Better to use higher wlock.
454164085Srrs	 */
455164085Srrs	SCTP_INP_WLOCK(inp);
456164085Srrscred_can_cont:
457164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
458164085Srrs	if (error) {
459164085Srrs		SCTP_INP_WUNLOCK(inp);
460164085Srrs		goto out;
461164085Srrs	}
462164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
463164085Srrs	SCTP_INP_WUNLOCK(inp);
464164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
465163953Srrsout:
466163953Srrs	return (error);
467163953Srrs}
468163953Srrs
469163953SrrsSYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
470163953Srrs    0, 0,
471163953Srrs    sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
472163953Srrs
473163953Srrs
474163953Srrs/* This is the same as the sctp_abort() could be made common */
475163953Srrsstatic void
476163953Srrssctp6_abort(struct socket *so)
477163953Srrs{
478163953Srrs	struct sctp_inpcb *inp;
479163953Srrs	uint32_t flags;
480163953Srrs
481163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
482233005Stuexen	if (inp == NULL) {
483172091Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
484163953Srrs		return;
485172091Srrs	}
486163953Srrssctp_must_try_again:
487163953Srrs	flags = inp->sctp_flags;
488163953Srrs#ifdef SCTP_LOG_CLOSING
489163953Srrs	sctp_log_closing(inp, NULL, 17);
490163953Srrs#endif
491163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
492163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
493163953Srrs#ifdef SCTP_LOG_CLOSING
494163953Srrs		sctp_log_closing(inp, NULL, 16);
495163953Srrs#endif
496169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
497169380Srrs		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
498163953Srrs		SOCK_LOCK(so);
499167695Srrs		SCTP_SB_CLEAR(so->so_snd);
500163953Srrs		/*
501163953Srrs		 * same for the rcv ones, they are only here for the
502163953Srrs		 * accounting/select.
503163953Srrs		 */
504167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
505167695Srrs		/* Now null out the reference, we are completely detached. */
506163953Srrs		so->so_pcb = NULL;
507163953Srrs		SOCK_UNLOCK(so);
508163953Srrs	} else {
509163953Srrs		flags = inp->sctp_flags;
510163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
511163953Srrs			goto sctp_must_try_again;
512163953Srrs		}
513163953Srrs	}
514163953Srrs	return;
515163953Srrs}
516163953Srrs
517163953Srrsstatic int
518228653Stuexensctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
519163953Srrs{
520163953Srrs	struct in6pcb *inp6;
521166086Srrs	int error;
522163953Srrs	struct sctp_inpcb *inp;
523170205Srrs	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
524163953Srrs
525163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
526171943Srrs	if (inp != NULL) {
527171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
528228907Stuexen		return (EINVAL);
529171943Srrs	}
530163953Srrs	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
531179783Srrs		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
532163953Srrs		if (error)
533228907Stuexen			return (error);
534163953Srrs	}
535170205Srrs	error = sctp_inpcb_alloc(so, vrf_id);
536163953Srrs	if (error)
537228907Stuexen		return (error);
538163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
539170205Srrs	SCTP_INP_WLOCK(inp);
540163953Srrs	inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;	/* I'm v6! */
541163953Srrs	inp6 = (struct in6pcb *)inp;
542163953Srrs
543163953Srrs	inp6->inp_vflag |= INP_IPV6;
544163953Srrs	inp6->in6p_hops = -1;	/* use kernel default */
545163953Srrs	inp6->in6p_cksum = -1;	/* just to be sure */
546163953Srrs#ifdef INET
547163953Srrs	/*
548163953Srrs	 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
549163953Srrs	 * socket as well, because the socket may be bound to an IPv6
550163953Srrs	 * wildcard address, which may match an IPv4-mapped IPv6 address.
551163953Srrs	 */
552197288Srrs	inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
553163953Srrs#endif
554170205Srrs	SCTP_INP_WUNLOCK(inp);
555228907Stuexen	return (0);
556163953Srrs}
557163953Srrs
558163953Srrsstatic int
559163953Srrssctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
560163953Srrs{
561163953Srrs	struct sctp_inpcb *inp;
562163953Srrs	struct in6pcb *inp6;
563166086Srrs	int error;
564163953Srrs
565163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
566233005Stuexen	if (inp == NULL) {
567171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
568228907Stuexen		return (EINVAL);
569171943Srrs	}
570170056Srrs	if (addr) {
571221249Stuexen		switch (addr->sa_family) {
572221249Stuexen#ifdef INET
573221249Stuexen		case AF_INET:
574221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
575221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
576228907Stuexen				return (EINVAL);
577221249Stuexen			}
578221249Stuexen			break;
579221249Stuexen#endif
580221249Stuexen#ifdef INET6
581221249Stuexen		case AF_INET6:
582221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
583221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
584228907Stuexen				return (EINVAL);
585221249Stuexen			}
586221249Stuexen			break;
587221249Stuexen#endif
588221249Stuexen		default:
589171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
590228907Stuexen			return (EINVAL);
591170056Srrs		}
592170056Srrs	}
593163953Srrs	inp6 = (struct in6pcb *)inp;
594163953Srrs	inp6->inp_vflag &= ~INP_IPV4;
595163953Srrs	inp6->inp_vflag |= INP_IPV6;
596166023Srrs	if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
597221249Stuexen		switch (addr->sa_family) {
598221249Stuexen#ifdef INET
599221249Stuexen		case AF_INET:
600163953Srrs			/* binding v4 addr to v6 socket, so reset flags */
601163953Srrs			inp6->inp_vflag |= INP_IPV4;
602163953Srrs			inp6->inp_vflag &= ~INP_IPV6;
603221249Stuexen			break;
604221249Stuexen#endif
605221249Stuexen#ifdef INET6
606221249Stuexen		case AF_INET6:
607221249Stuexen			{
608221249Stuexen				struct sockaddr_in6 *sin6_p;
609163953Srrs
610221249Stuexen				sin6_p = (struct sockaddr_in6 *)addr;
611163953Srrs
612221249Stuexen				if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
613221249Stuexen					inp6->inp_vflag |= INP_IPV4;
614221249Stuexen				}
615221249Stuexen#ifdef INET
616221249Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
617221249Stuexen					struct sockaddr_in sin;
618163953Srrs
619221249Stuexen					in6_sin6_2_sin(&sin, sin6_p);
620221249Stuexen					inp6->inp_vflag |= INP_IPV4;
621221249Stuexen					inp6->inp_vflag &= ~INP_IPV6;
622221249Stuexen					error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
623228907Stuexen					return (error);
624221249Stuexen				}
625221249Stuexen#endif
626221249Stuexen				break;
627163953Srrs			}
628221249Stuexen#endif
629221249Stuexen		default:
630221249Stuexen			break;
631163953Srrs		}
632163953Srrs	} else if (addr != NULL) {
633221249Stuexen		struct sockaddr_in6 *sin6_p;
634221249Stuexen
635163953Srrs		/* IPV6_V6ONLY socket */
636221249Stuexen#ifdef INET
637163953Srrs		if (addr->sa_family == AF_INET) {
638163953Srrs			/* can't bind v4 addr to v6 only socket! */
639171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
640228907Stuexen			return (EINVAL);
641221249Stuexen		}
642221249Stuexen#endif
643221249Stuexen		sin6_p = (struct sockaddr_in6 *)addr;
644163953Srrs
645221249Stuexen		if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
646221249Stuexen			/* can't bind v4-mapped addrs either! */
647221249Stuexen			/* NOTE: we don't support SIIT */
648221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
649228907Stuexen			return (EINVAL);
650163953Srrs		}
651163953Srrs	}
652171572Srrs	error = sctp_inpcb_bind(so, addr, NULL, p);
653228907Stuexen	return (error);
654163953Srrs}
655163953Srrs
656163953Srrs
657163953Srrsstatic void
658163953Srrssctp6_close(struct socket *so)
659163953Srrs{
660171990Srrs	sctp_close(so);
661163953Srrs}
662163953Srrs
663167598Srrs/* This could be made common with sctp_detach() since they are identical */
664163953Srrs
665168709Srrsstatic
666168709Srrsint
667163953Srrssctp6_disconnect(struct socket *so)
668163953Srrs{
669171990Srrs	return (sctp_disconnect(so));
670163953Srrs}
671163953Srrs
672168709Srrs
673163953Srrsint
674163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
675163953Srrs    struct mbuf *control, struct thread *p);
676163953Srrs
677163953Srrs
678163953Srrsstatic int
679163953Srrssctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
680163953Srrs    struct mbuf *control, struct thread *p)
681163953Srrs{
682163953Srrs	struct sctp_inpcb *inp;
683163953Srrs	struct in6pcb *inp6;
684163953Srrs
685163953Srrs#ifdef INET
686163953Srrs	struct sockaddr_in6 *sin6;
687163953Srrs#endif				/* INET */
688163953Srrs	/* No SPL needed since sctp_output does this */
689163953Srrs
690163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
691163953Srrs	if (inp == NULL) {
692163953Srrs		if (control) {
693169352Srrs			SCTP_RELEASE_PKT(control);
694163953Srrs			control = NULL;
695163953Srrs		}
696169352Srrs		SCTP_RELEASE_PKT(m);
697171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
698228907Stuexen		return (EINVAL);
699163953Srrs	}
700163953Srrs	inp6 = (struct in6pcb *)inp;
701163953Srrs	/*
702163953Srrs	 * For the TCP model we may get a NULL addr, if we are a connected
703163953Srrs	 * socket thats ok.
704163953Srrs	 */
705163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
706163953Srrs	    (addr == NULL)) {
707163953Srrs		goto connected_type;
708163953Srrs	}
709163953Srrs	if (addr == NULL) {
710169352Srrs		SCTP_RELEASE_PKT(m);
711163953Srrs		if (control) {
712169352Srrs			SCTP_RELEASE_PKT(control);
713163953Srrs			control = NULL;
714163953Srrs		}
715171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
716163953Srrs		return (EDESTADDRREQ);
717163953Srrs	}
718163953Srrs#ifdef INET
719163953Srrs	sin6 = (struct sockaddr_in6 *)addr;
720166023Srrs	if (SCTP_IPV6_V6ONLY(inp6)) {
721163953Srrs		/*
722163953Srrs		 * if IPV6_V6ONLY flag, we discard datagrams destined to a
723163953Srrs		 * v4 addr or v4-mapped addr
724163953Srrs		 */
725163953Srrs		if (addr->sa_family == AF_INET) {
726171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
727228907Stuexen			return (EINVAL);
728163953Srrs		}
729163953Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
730171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
731228907Stuexen			return (EINVAL);
732163953Srrs		}
733163953Srrs	}
734163953Srrs	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
735250466Stuexen		struct sockaddr_in sin;
736163953Srrs
737250466Stuexen		/* convert v4-mapped into v4 addr and send */
738250466Stuexen		in6_sin6_2_sin(&sin, sin6);
739250466Stuexen		return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p));
740163953Srrs	}
741163953Srrs#endif				/* INET */
742163953Srrsconnected_type:
743163953Srrs	/* now what about control */
744163953Srrs	if (control) {
745163953Srrs		if (inp->control) {
746169420Srrs			SCTP_PRINTF("huh? control set?\n");
747169352Srrs			SCTP_RELEASE_PKT(inp->control);
748163953Srrs			inp->control = NULL;
749163953Srrs		}
750163953Srrs		inp->control = control;
751163953Srrs	}
752163953Srrs	/* Place the data */
753163953Srrs	if (inp->pkt) {
754165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
755163953Srrs		inp->pkt_last = m;
756163953Srrs	} else {
757163953Srrs		inp->pkt_last = inp->pkt = m;
758163953Srrs	}
759163953Srrs	if (
760163953Srrs	/* FreeBSD and MacOSX uses a flag passed */
761163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
762163953Srrs	    ) {
763163953Srrs		/*
764163953Srrs		 * note with the current version this code will only be used
765163953Srrs		 * by OpenBSD, NetBSD and FreeBSD have methods for
766163953Srrs		 * re-defining sosend() to use sctp_sosend().  One can
767163953Srrs		 * optionaly switch back to this code (by changing back the
768163953Srrs		 * defininitions but this is not advisable.
769163953Srrs		 */
770163953Srrs		int ret;
771163953Srrs
772163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
773163953Srrs		inp->pkt = NULL;
774163953Srrs		inp->control = NULL;
775163953Srrs		return (ret);
776163953Srrs	} else {
777163953Srrs		return (0);
778163953Srrs	}
779163953Srrs}
780163953Srrs
781163953Srrsstatic int
782163953Srrssctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
783163953Srrs{
784167598Srrs	uint32_t vrf_id;
785163953Srrs	int error = 0;
786163953Srrs	struct sctp_inpcb *inp;
787163953Srrs	struct sctp_tcb *stcb;
788163953Srrs#ifdef INET
789257555Stuexen	struct in6pcb *inp6;
790163953Srrs	struct sockaddr_in6 *sin6;
791271221Stuexen	union sctp_sockstore store;
792221249Stuexen#endif
793163953Srrs
794257555Stuexen#ifdef INET
795163953Srrs	inp6 = (struct in6pcb *)so->so_pcb;
796257555Stuexen#endif
797163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
798233005Stuexen	if (inp == NULL) {
799171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
800163953Srrs		return (ECONNRESET);	/* I made the same as TCP since we are
801163953Srrs					 * not setup? */
802163953Srrs	}
803170056Srrs	if (addr == NULL) {
804171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
805170056Srrs		return (EINVAL);
806170056Srrs	}
807221249Stuexen	switch (addr->sa_family) {
808221249Stuexen#ifdef INET
809221249Stuexen	case AF_INET:
810221249Stuexen		if (addr->sa_len != sizeof(struct sockaddr_in)) {
811221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
812221249Stuexen			return (EINVAL);
813221249Stuexen		}
814221249Stuexen		break;
815221249Stuexen#endif
816221249Stuexen#ifdef INET6
817221249Stuexen	case AF_INET6:
818221249Stuexen		if (addr->sa_len != sizeof(struct sockaddr_in6)) {
819221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
820221249Stuexen			return (EINVAL);
821221249Stuexen		}
822221249Stuexen		break;
823221249Stuexen#endif
824221249Stuexen	default:
825171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
826170056Srrs		return (EINVAL);
827170056Srrs	}
828221249Stuexen
829168299Srrs	vrf_id = inp->def_vrf_id;
830163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
831163953Srrs	SCTP_INP_RLOCK(inp);
832163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
833163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
834163953Srrs		/* Bind a ephemeral port */
835163953Srrs		SCTP_INP_RUNLOCK(inp);
836163953Srrs		error = sctp6_bind(so, NULL, p);
837163953Srrs		if (error) {
838163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
839163953Srrs
840163953Srrs			return (error);
841163953Srrs		}
842163953Srrs		SCTP_INP_RLOCK(inp);
843163953Srrs	}
844163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
845163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
846163953Srrs		/* We are already connected AND the TCP model */
847163953Srrs		SCTP_INP_RUNLOCK(inp);
848163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
849171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
850163953Srrs		return (EADDRINUSE);
851163953Srrs	}
852163953Srrs#ifdef INET
853163953Srrs	sin6 = (struct sockaddr_in6 *)addr;
854166023Srrs	if (SCTP_IPV6_V6ONLY(inp6)) {
855163953Srrs		/*
856163953Srrs		 * if IPV6_V6ONLY flag, ignore connections destined to a v4
857163953Srrs		 * addr or v4-mapped addr
858163953Srrs		 */
859163953Srrs		if (addr->sa_family == AF_INET) {
860163953Srrs			SCTP_INP_RUNLOCK(inp);
861163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
862171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
863228907Stuexen			return (EINVAL);
864163953Srrs		}
865163953Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
866163953Srrs			SCTP_INP_RUNLOCK(inp);
867163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
868171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
869228907Stuexen			return (EINVAL);
870163953Srrs		}
871163953Srrs	}
872163953Srrs	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
873250466Stuexen		/* convert v4-mapped into v4 addr */
874271221Stuexen		in6_sin6_2_sin(&store.sin, sin6);
875271221Stuexen		addr = &store.sa;
876221411Stuexen	}
877163953Srrs#endif				/* INET */
878163953Srrs	/* Now do we connect? */
879163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
880163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
881169420Srrs		if (stcb) {
882163953Srrs			SCTP_TCB_UNLOCK(stcb);
883169420Srrs		}
884163953Srrs		SCTP_INP_RUNLOCK(inp);
885163953Srrs	} else {
886163953Srrs		SCTP_INP_RUNLOCK(inp);
887163953Srrs		SCTP_INP_WLOCK(inp);
888163953Srrs		SCTP_INP_INCR_REF(inp);
889163953Srrs		SCTP_INP_WUNLOCK(inp);
890163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
891163953Srrs		if (stcb == NULL) {
892163953Srrs			SCTP_INP_WLOCK(inp);
893163953Srrs			SCTP_INP_DECR_REF(inp);
894163953Srrs			SCTP_INP_WUNLOCK(inp);
895163953Srrs		}
896163953Srrs	}
897163953Srrs
898163953Srrs	if (stcb != NULL) {
899163953Srrs		/* Already have or am bring up an association */
900163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
901163953Srrs		SCTP_TCB_UNLOCK(stcb);
902171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
903163953Srrs		return (EALREADY);
904163953Srrs	}
905163953Srrs	/* We are GOOD to go */
906298902Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id,
907298902Stuexen	    inp->sctp_ep.pre_open_stream_count,
908298902Stuexen	    inp->sctp_ep.port, p);
909163953Srrs	SCTP_ASOC_CREATE_UNLOCK(inp);
910163953Srrs	if (stcb == NULL) {
911163953Srrs		/* Gak! no memory */
912163953Srrs		return (error);
913163953Srrs	}
914163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
915163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
916163953Srrs		/* Set the connected flag so we can queue data */
917163953Srrs		soisconnecting(so);
918163953Srrs	}
919163953Srrs	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
920169420Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
921163953Srrs
922163953Srrs	/* initialize authentication parameters for the assoc */
923163953Srrs	sctp_initialize_auth_params(inp, stcb);
924163953Srrs
925172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
926163953Srrs	SCTP_TCB_UNLOCK(stcb);
927228907Stuexen	return (error);
928163953Srrs}
929163953Srrs
930163953Srrsstatic int
931163953Srrssctp6_getaddr(struct socket *so, struct sockaddr **addr)
932163953Srrs{
933163953Srrs	struct sockaddr_in6 *sin6;
934163953Srrs	struct sctp_inpcb *inp;
935167598Srrs	uint32_t vrf_id;
936167598Srrs	struct sctp_ifa *sctp_ifa;
937163953Srrs
938163953Srrs	int error;
939163953Srrs
940163953Srrs	/*
941163953Srrs	 * Do the malloc first in case it blocks.
942163953Srrs	 */
943221249Stuexen	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
944211944Stuexen	if (sin6 == NULL)
945228907Stuexen		return (ENOMEM);
946163953Srrs	sin6->sin6_family = AF_INET6;
947163953Srrs	sin6->sin6_len = sizeof(*sin6);
948163953Srrs
949163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
950163953Srrs	if (inp == NULL) {
951163953Srrs		SCTP_FREE_SONAME(sin6);
952171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
953228907Stuexen		return (ECONNRESET);
954163953Srrs	}
955163953Srrs	SCTP_INP_RLOCK(inp);
956163953Srrs	sin6->sin6_port = inp->sctp_lport;
957163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
958163953Srrs		/* For the bound all case you get back 0 */
959163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
960163953Srrs			struct sctp_tcb *stcb;
961163953Srrs			struct sockaddr_in6 *sin_a6;
962163953Srrs			struct sctp_nets *net;
963163953Srrs			int fnd;
964163953Srrs
965163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
966163953Srrs			if (stcb == NULL) {
967295771Stuexen				SCTP_INP_RUNLOCK(inp);
968295929Stuexen				SCTP_FREE_SONAME(sin6);
969295771Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
970295771Stuexen				return (ENOENT);
971163953Srrs			}
972163953Srrs			fnd = 0;
973163953Srrs			sin_a6 = NULL;
974163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
975163953Srrs				sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
976164085Srrs				if (sin_a6 == NULL)
977164085Srrs					/* this will make coverity happy */
978164085Srrs					continue;
979164085Srrs
980163953Srrs				if (sin_a6->sin6_family == AF_INET6) {
981163953Srrs					fnd = 1;
982163953Srrs					break;
983163953Srrs				}
984163953Srrs			}
985163953Srrs			if ((!fnd) || (sin_a6 == NULL)) {
986163953Srrs				/* punt */
987295771Stuexen				SCTP_INP_RUNLOCK(inp);
988295929Stuexen				SCTP_FREE_SONAME(sin6);
989295771Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
990295771Stuexen				return (ENOENT);
991163953Srrs			}
992168299Srrs			vrf_id = inp->def_vrf_id;
993310773Stuexen			sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *)&net->ro, net, 0, vrf_id);
994167598Srrs			if (sctp_ifa) {
995167598Srrs				sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
996167598Srrs			}
997163953Srrs		} else {
998163953Srrs			/* For the bound all case you get back 0 */
999163953Srrs			memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1000163953Srrs		}
1001163953Srrs	} else {
1002163953Srrs		/* Take the first IPv6 address in the list */
1003163953Srrs		struct sctp_laddr *laddr;
1004163953Srrs		int fnd = 0;
1005163953Srrs
1006163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1007167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET6) {
1008163953Srrs				struct sockaddr_in6 *sin_a;
1009163953Srrs
1010271221Stuexen				sin_a = &laddr->ifa->address.sin6;
1011163953Srrs				sin6->sin6_addr = sin_a->sin6_addr;
1012163953Srrs				fnd = 1;
1013163953Srrs				break;
1014163953Srrs			}
1015163953Srrs		}
1016163953Srrs		if (!fnd) {
1017163953Srrs			SCTP_FREE_SONAME(sin6);
1018163953Srrs			SCTP_INP_RUNLOCK(inp);
1019171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1020228907Stuexen			return (ENOENT);
1021163953Srrs		}
1022163953Srrs	}
1023163953Srrs	SCTP_INP_RUNLOCK(inp);
1024163953Srrs	/* Scoping things for v6 */
1025164085Srrs	if ((error = sa6_recoverscope(sin6)) != 0) {
1026164085Srrs		SCTP_FREE_SONAME(sin6);
1027163953Srrs		return (error);
1028164085Srrs	}
1029163953Srrs	(*addr) = (struct sockaddr *)sin6;
1030163953Srrs	return (0);
1031163953Srrs}
1032163953Srrs
1033163953Srrsstatic int
1034163953Srrssctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1035163953Srrs{
1036231895Stuexen	struct sockaddr_in6 *sin6;
1037163953Srrs	int fnd;
1038163953Srrs	struct sockaddr_in6 *sin_a6;
1039163953Srrs	struct sctp_inpcb *inp;
1040163953Srrs	struct sctp_tcb *stcb;
1041163953Srrs	struct sctp_nets *net;
1042163953Srrs	int error;
1043163953Srrs
1044228907Stuexen	/* Do the malloc first in case it blocks. */
1045163953Srrs	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1046211944Stuexen	if (sin6 == NULL)
1047211944Stuexen		return (ENOMEM);
1048163953Srrs	sin6->sin6_family = AF_INET6;
1049163953Srrs	sin6->sin6_len = sizeof(*sin6);
1050163953Srrs
1051163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1052228907Stuexen	if ((inp == NULL) ||
1053228907Stuexen	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
1054228907Stuexen		/* UDP type and listeners will drop out here */
1055163953Srrs		SCTP_FREE_SONAME(sin6);
1056228907Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
1057228907Stuexen		return (ENOTCONN);
1058163953Srrs	}
1059163953Srrs	SCTP_INP_RLOCK(inp);
1060163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
1061169420Srrs	if (stcb) {
1062163953Srrs		SCTP_TCB_LOCK(stcb);
1063169420Srrs	}
1064163953Srrs	SCTP_INP_RUNLOCK(inp);
1065163953Srrs	if (stcb == NULL) {
1066163953Srrs		SCTP_FREE_SONAME(sin6);
1067171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1068228907Stuexen		return (ECONNRESET);
1069163953Srrs	}
1070163953Srrs	fnd = 0;
1071163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1072163953Srrs		sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1073163953Srrs		if (sin_a6->sin6_family == AF_INET6) {
1074163953Srrs			fnd = 1;
1075163953Srrs			sin6->sin6_port = stcb->rport;
1076163953Srrs			sin6->sin6_addr = sin_a6->sin6_addr;
1077163953Srrs			break;
1078163953Srrs		}
1079163953Srrs	}
1080163953Srrs	SCTP_TCB_UNLOCK(stcb);
1081163953Srrs	if (!fnd) {
1082163953Srrs		/* No IPv4 address */
1083163953Srrs		SCTP_FREE_SONAME(sin6);
1084171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1085228907Stuexen		return (ENOENT);
1086163953Srrs	}
1087275868Stuexen	if ((error = sa6_recoverscope(sin6)) != 0) {
1088275868Stuexen		SCTP_FREE_SONAME(sin6);
1089275868Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, error);
1090163953Srrs		return (error);
1091275868Stuexen	}
1092163953Srrs	*addr = (struct sockaddr *)sin6;
1093163953Srrs	return (0);
1094163953Srrs}
1095163953Srrs
1096163953Srrsstatic int
1097163953Srrssctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1098163953Srrs{
1099163953Srrs	struct in6pcb *inp6 = sotoin6pcb(so);
1100166086Srrs	int error;
1101163953Srrs
1102171943Srrs	if (inp6 == NULL) {
1103171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1104228907Stuexen		return (EINVAL);
1105171943Srrs	}
1106163953Srrs	/* allow v6 addresses precedence */
1107163953Srrs	error = sctp6_getaddr(so, nam);
1108221249Stuexen#ifdef INET
1109163953Srrs	if (error) {
1110295771Stuexen		struct sockaddr_in6 *sin6;
1111295771Stuexen
1112163953Srrs		/* try v4 next if v6 failed */
1113163953Srrs		error = sctp_ingetaddr(so, nam);
1114163953Srrs		if (error) {
1115163953Srrs			return (error);
1116163953Srrs		}
1117295771Stuexen		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1118295771Stuexen		if (sin6 == NULL) {
1119295771Stuexen			SCTP_FREE_SONAME(*nam);
1120295771Stuexen			return (ENOMEM);
1121163953Srrs		}
1122295771Stuexen		in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
1123295771Stuexen		SCTP_FREE_SONAME(*nam);
1124295771Stuexen		*nam = (struct sockaddr *)sin6;
1125163953Srrs	}
1126221249Stuexen#endif
1127163953Srrs	return (error);
1128163953Srrs}
1129163953Srrs
1130163953Srrs
1131163953Srrsstatic int
1132163953Srrssctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1133163953Srrs{
1134163953Srrs	struct in6pcb *inp6 = sotoin6pcb(so);
1135166086Srrs	int error;
1136163953Srrs
1137171943Srrs	if (inp6 == NULL) {
1138171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1139228907Stuexen		return (EINVAL);
1140171943Srrs	}
1141163953Srrs	/* allow v6 addresses precedence */
1142163953Srrs	error = sctp6_peeraddr(so, nam);
1143221249Stuexen#ifdef INET
1144163953Srrs	if (error) {
1145295771Stuexen		struct sockaddr_in6 *sin6;
1146295771Stuexen
1147163953Srrs		/* try v4 next if v6 failed */
1148163953Srrs		error = sctp_peeraddr(so, nam);
1149163953Srrs		if (error) {
1150163953Srrs			return (error);
1151163953Srrs		}
1152295771Stuexen		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1153295771Stuexen		if (sin6 == NULL) {
1154295771Stuexen			SCTP_FREE_SONAME(*nam);
1155295771Stuexen			return (ENOMEM);
1156163953Srrs		}
1157295771Stuexen		in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
1158295771Stuexen		SCTP_FREE_SONAME(*nam);
1159295771Stuexen		*nam = (struct sockaddr *)sin6;
1160163953Srrs	}
1161221249Stuexen#endif
1162228907Stuexen	return (error);
1163163953Srrs}
1164163953Srrs
1165163953Srrsstruct pr_usrreqs sctp6_usrreqs = {
1166163953Srrs	.pru_abort = sctp6_abort,
1167163953Srrs	.pru_accept = sctp_accept,
1168163953Srrs	.pru_attach = sctp6_attach,
1169163953Srrs	.pru_bind = sctp6_bind,
1170163953Srrs	.pru_connect = sctp6_connect,
1171163953Srrs	.pru_control = in6_control,
1172163953Srrs	.pru_close = sctp6_close,
1173163953Srrs	.pru_detach = sctp6_close,
1174163953Srrs	.pru_sopoll = sopoll_generic,
1175178201Srrs	.pru_flush = sctp_flush,
1176163953Srrs	.pru_disconnect = sctp6_disconnect,
1177163953Srrs	.pru_listen = sctp_listen,
1178163953Srrs	.pru_peeraddr = sctp6_getpeeraddr,
1179163953Srrs	.pru_send = sctp6_send,
1180163953Srrs	.pru_shutdown = sctp_shutdown,
1181163953Srrs	.pru_sockaddr = sctp6_in6getaddr,
1182163953Srrs	.pru_sosend = sctp_sosend,
1183163953Srrs	.pru_soreceive = sctp_soreceive
1184163953Srrs};
1185238501Stuexen
1186238501Stuexen#endif
1187