sctp6_usrreq.c revision 338986
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 338986 2018-09-27 18:50:10Z gordon $");
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;
72238003Stuexen	uint8_t compute_crc;
73238003Stuexen	uint32_t mflowid;
74275483Stuexen	uint8_t mflowtype;
75284515Stuexen	uint16_t fibnum;
76163953Srrs
77237569Stuexen	iphlen = *offp;
78169352Srrs	if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
79169352Srrs		SCTP_RELEASE_PKT(*i_pak);
80237569Stuexen		return (IPPROTO_DONE);
81169352Srrs	}
82168709Srrs	m = SCTP_HEADER_TO_CHAIN(*i_pak);
83237569Stuexen#ifdef SCTP_MBUF_LOGGING
84237569Stuexen	/* Log in any input mbufs */
85237569Stuexen	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
86276914Stuexen		sctp_log_mbc(m, SCTP_MBUF_INPUT);
87237569Stuexen	}
88237569Stuexen#endif
89237540Stuexen#ifdef SCTP_PACKET_LOGGING
90237540Stuexen	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
91237540Stuexen		sctp_packet_log(m);
92237540Stuexen	}
93170091Srrs#endif
94238003Stuexen	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
95254854Stuexen	    "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n",
96238003Stuexen	    m->m_pkthdr.len,
97238003Stuexen	    if_name(m->m_pkthdr.rcvif),
98254854Stuexen	    (int)m->m_pkthdr.csum_flags, CSUM_BITS);
99275483Stuexen	mflowid = m->m_pkthdr.flowid;
100275483Stuexen	mflowtype = M_HASHTYPE_GET(m);
101284515Stuexen	fibnum = M_GETFIB(m);
102237569Stuexen	SCTP_STAT_INCR(sctps_recvpackets);
103237569Stuexen	SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
104237569Stuexen	/* Get IP, SCTP, and first chunk header together in the first mbuf. */
105238003Stuexen	offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
106163953Srrs	ip6 = mtod(m, struct ip6_hdr *);
107237569Stuexen	IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
108237569Stuexen	    (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
109163953Srrs	if (sh == NULL) {
110163953Srrs		SCTP_STAT_INCR(sctps_hdrops);
111228907Stuexen		return (IPPROTO_DONE);
112163953Srrs	}
113163953Srrs	ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
114237569Stuexen	offset -= sizeof(struct sctp_chunkhdr);
115237715Stuexen	memset(&src, 0, sizeof(struct sockaddr_in6));
116237715Stuexen	src.sin6_family = AF_INET6;
117237715Stuexen	src.sin6_len = sizeof(struct sockaddr_in6);
118237715Stuexen	src.sin6_port = sh->src_port;
119237715Stuexen	src.sin6_addr = ip6->ip6_src;
120237715Stuexen	if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
121238003Stuexen		goto out;
122237715Stuexen	}
123237715Stuexen	memset(&dst, 0, sizeof(struct sockaddr_in6));
124237715Stuexen	dst.sin6_family = AF_INET6;
125237715Stuexen	dst.sin6_len = sizeof(struct sockaddr_in6);
126237715Stuexen	dst.sin6_port = sh->dest_port;
127237715Stuexen	dst.sin6_addr = ip6->ip6_dst;
128237715Stuexen	if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
129238003Stuexen		goto out;
130237715Stuexen	}
131237569Stuexen	length = ntohs(ip6->ip6_plen) + iphlen;
132237569Stuexen	/* Validate mbuf chain length with IP payload length. */
133238003Stuexen	if (SCTP_HEADER_LEN(m) != length) {
134237569Stuexen		SCTPDBG(SCTP_DEBUG_INPUT1,
135238003Stuexen		    "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m));
136237569Stuexen		SCTP_STAT_INCR(sctps_hdrops);
137238003Stuexen		goto out;
138237569Stuexen	}
139163953Srrs	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
140238003Stuexen		goto out;
141163953Srrs	}
142238003Stuexen	ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
143188067Srrs	if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
144188067Srrs		SCTP_STAT_INCR(sctps_recvhwcrc);
145238003Stuexen		compute_crc = 0;
146238003Stuexen	} else {
147238003Stuexen		SCTP_STAT_INCR(sctps_recvswcrc);
148238003Stuexen		compute_crc = 1;
149188067Srrs	}
150238003Stuexen	sctp_common_input_processing(&m, iphlen, offset, length,
151237715Stuexen	    (struct sockaddr *)&src,
152237715Stuexen	    (struct sockaddr *)&dst,
153238003Stuexen	    sh, ch,
154238003Stuexen	    compute_crc,
155238003Stuexen	    ecn_bits,
156284515Stuexen	    mflowtype, mflowid, fibnum,
157237049Stuexen	    vrf_id, port);
158238003Stuexenout:
159237569Stuexen	if (m) {
160169352Srrs		sctp_m_freem(m);
161237569Stuexen	}
162228907Stuexen	return (IPPROTO_DONE);
163163953Srrs}
164163953Srrs
165163953Srrs
166243186Stuexenint
167243186Stuexensctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED)
168243186Stuexen{
169243186Stuexen	return (sctp6_input_with_port(i_pak, offp, 0));
170243186Stuexen}
171243186Stuexen
172172156Srrsvoid
173172091Srrssctp6_notify(struct sctp_inpcb *inp,
174172091Srrs    struct sctp_tcb *stcb,
175298132Stuexen    struct sctp_nets *net,
176298132Stuexen    uint8_t icmp6_type,
177298132Stuexen    uint8_t icmp6_code,
178319402Stuexen    uint32_t next_mtu)
179172091Srrs{
180237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
181172091Srrs	struct socket *so;
182172091Srrs#endif
183298132Stuexen	int timer_stopped;
184235360Stuexen
185298132Stuexen	switch (icmp6_type) {
186298132Stuexen	case ICMP6_DST_UNREACH:
187298132Stuexen		if ((icmp6_code == ICMP6_DST_UNREACH_NOROUTE) ||
188298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_ADMIN) ||
189298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_BEYONDSCOPE) ||
190298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_ADDR)) {
191298132Stuexen			/* Mark the net unreachable. */
192298132Stuexen			if (net->dest_state & SCTP_ADDR_REACHABLE) {
193298132Stuexen				/* Ok that destination is not reachable */
194298132Stuexen				net->dest_state &= ~SCTP_ADDR_REACHABLE;
195298132Stuexen				net->dest_state &= ~SCTP_ADDR_PF;
196298132Stuexen				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
197298132Stuexen				    stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED);
198298132Stuexen			}
199172091Srrs		}
200172091Srrs		SCTP_TCB_UNLOCK(stcb);
201298132Stuexen		break;
202298132Stuexen	case ICMP6_PARAM_PROB:
203298132Stuexen		/* Treat it like an ABORT. */
204298132Stuexen		if (icmp6_code == ICMP6_PARAMPROB_NEXTHEADER) {
205298132Stuexen			sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
206237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
207298132Stuexen			so = SCTP_INP_SO(inp);
208298132Stuexen			atomic_add_int(&stcb->asoc.refcnt, 1);
209298132Stuexen			SCTP_TCB_UNLOCK(stcb);
210298132Stuexen			SCTP_SOCKET_LOCK(so, 1);
211298132Stuexen			SCTP_TCB_LOCK(stcb);
212298132Stuexen			atomic_subtract_int(&stcb->asoc.refcnt, 1);
213172091Srrs#endif
214298132Stuexen			(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
215298132Stuexen			    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
216237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
217298132Stuexen			SCTP_SOCKET_UNLOCK(so, 1);
218172091Srrs#endif
219298132Stuexen		} else {
220298132Stuexen			SCTP_TCB_UNLOCK(stcb);
221298132Stuexen		}
222298132Stuexen		break;
223298132Stuexen	case ICMP6_PACKET_TOO_BIG:
224332636Stuexen		if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
225332222Stuexen			SCTP_TCB_UNLOCK(stcb);
226332222Stuexen			break;
227332222Stuexen		}
228298132Stuexen		if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
229298132Stuexen			timer_stopped = 1;
230298132Stuexen			sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
231298132Stuexen			    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
232298132Stuexen		} else {
233298132Stuexen			timer_stopped = 0;
234298132Stuexen		}
235298132Stuexen		/* Update the path MTU. */
236319403Stuexen		if (net->port) {
237319403Stuexen			next_mtu -= sizeof(struct udphdr);
238319403Stuexen		}
239298132Stuexen		if (net->mtu > next_mtu) {
240298132Stuexen			net->mtu = next_mtu;
241298132Stuexen		}
242298132Stuexen		/* Update the association MTU */
243298132Stuexen		if (stcb->asoc.smallest_mtu > next_mtu) {
244298132Stuexen			sctp_pathmtu_adjustment(stcb, next_mtu);
245298132Stuexen		}
246298132Stuexen		/* Finally, start the PMTU timer if it was running before. */
247298132Stuexen		if (timer_stopped) {
248298132Stuexen			sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
249298132Stuexen		}
250172091Srrs		SCTP_TCB_UNLOCK(stcb);
251298132Stuexen		break;
252298132Stuexen	default:
253298132Stuexen		SCTP_TCB_UNLOCK(stcb);
254298132Stuexen		break;
255172091Srrs	}
256172091Srrs}
257172091Srrs
258163953Srrsvoid
259171259Sdelphijsctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
260163953Srrs{
261298132Stuexen	struct ip6ctlparam *ip6cp;
262298132Stuexen	struct sctp_inpcb *inp;
263298132Stuexen	struct sctp_tcb *stcb;
264298132Stuexen	struct sctp_nets *net;
265163953Srrs	struct sctphdr sh;
266298132Stuexen	struct sockaddr_in6 src, dst;
267163953Srrs
268163953Srrs	if (pktdst->sa_family != AF_INET6 ||
269298132Stuexen	    pktdst->sa_len != sizeof(struct sockaddr_in6)) {
270163953Srrs		return;
271298132Stuexen	}
272298132Stuexen	if ((unsigned)cmd >= PRC_NCMDS) {
273163953Srrs		return;
274298132Stuexen	}
275163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
276163953Srrs		d = NULL;
277163953Srrs	} else if (inet6ctlerrmap[cmd] == 0) {
278163953Srrs		return;
279163953Srrs	}
280298132Stuexen	/* If the parameter is from icmp6, decode it. */
281163953Srrs	if (d != NULL) {
282163953Srrs		ip6cp = (struct ip6ctlparam *)d;
283163953Srrs	} else {
284163953Srrs		ip6cp = (struct ip6ctlparam *)NULL;
285163953Srrs	}
286163953Srrs
287298132Stuexen	if (ip6cp != NULL) {
288163953Srrs		/*
289163953Srrs		 * XXX: We assume that when IPV6 is non NULL, M and OFF are
290163953Srrs		 * valid.
291163953Srrs		 */
292298132Stuexen		if (ip6cp->ip6c_m == NULL) {
293163953Srrs			return;
294298132Stuexen		}
295298132Stuexen		/*
296298132Stuexen		 * Check if we can safely examine the ports and the
297298132Stuexen		 * verification tag of the SCTP common header.
298298132Stuexen		 */
299298132Stuexen		if (ip6cp->ip6c_m->m_pkthdr.len <
300310773Stuexen		    (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) {
301293906Sglebius			return;
302298132Stuexen		}
303298132Stuexen		/* Copy out the port numbers and the verification tag. */
304332172Stuexen		memset(&sh, 0, sizeof(sh));
305298132Stuexen		m_copydata(ip6cp->ip6c_m,
306298132Stuexen		    ip6cp->ip6c_off,
307298132Stuexen		    sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
308298132Stuexen		    (caddr_t)&sh);
309298132Stuexen		memset(&src, 0, sizeof(struct sockaddr_in6));
310298132Stuexen		src.sin6_family = AF_INET6;
311298132Stuexen		src.sin6_len = sizeof(struct sockaddr_in6);
312298132Stuexen		src.sin6_port = sh.src_port;
313298132Stuexen		src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
314298132Stuexen		if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
315298132Stuexen			return;
316298132Stuexen		}
317298132Stuexen		memset(&dst, 0, sizeof(struct sockaddr_in6));
318298132Stuexen		dst.sin6_family = AF_INET6;
319298132Stuexen		dst.sin6_len = sizeof(struct sockaddr_in6);
320298132Stuexen		dst.sin6_port = sh.dest_port;
321298132Stuexen		dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
322298132Stuexen		if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
323298132Stuexen			return;
324298132Stuexen		}
325163953Srrs		inp = NULL;
326163953Srrs		net = NULL;
327298132Stuexen		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
328298132Stuexen		    (struct sockaddr *)&src,
329298132Stuexen		    &inp, &net, 1, SCTP_DEFAULT_VRFID);
330298132Stuexen		if ((stcb != NULL) &&
331298132Stuexen		    (net != NULL) &&
332302138Stuexen		    (inp != NULL)) {
333298132Stuexen			/* Check the verification tag */
334298132Stuexen			if (ntohl(sh.v_tag) != 0) {
335298132Stuexen				/*
336298132Stuexen				 * This must be the verification tag used
337298132Stuexen				 * for sending out packets. We don't
338298132Stuexen				 * consider packets reflecting the
339298132Stuexen				 * verification tag.
340298132Stuexen				 */
341298132Stuexen				if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
342298132Stuexen					SCTP_TCB_UNLOCK(stcb);
343298132Stuexen					return;
344298132Stuexen				}
345163953Srrs			} else {
346298132Stuexen				if (ip6cp->ip6c_m->m_pkthdr.len >=
347298132Stuexen				    ip6cp->ip6c_off + sizeof(struct sctphdr) +
348298132Stuexen				    sizeof(struct sctp_chunkhdr) +
349298132Stuexen				    offsetof(struct sctp_init, a_rwnd)) {
350298132Stuexen					/*
351298132Stuexen					 * In this case we can check if we
352298132Stuexen					 * got an INIT chunk and if the
353298132Stuexen					 * initiate tag matches.
354298132Stuexen					 */
355298132Stuexen					uint32_t initiate_tag;
356298132Stuexen					uint8_t chunk_type;
357298132Stuexen
358298132Stuexen					m_copydata(ip6cp->ip6c_m,
359298132Stuexen					    ip6cp->ip6c_off +
360298132Stuexen					    sizeof(struct sctphdr),
361298132Stuexen					    sizeof(uint8_t),
362298132Stuexen					    (caddr_t)&chunk_type);
363298132Stuexen					m_copydata(ip6cp->ip6c_m,
364298132Stuexen					    ip6cp->ip6c_off +
365298132Stuexen					    sizeof(struct sctphdr) +
366298132Stuexen					    sizeof(struct sctp_chunkhdr),
367298132Stuexen					    sizeof(uint32_t),
368298132Stuexen					    (caddr_t)&initiate_tag);
369298132Stuexen					if ((chunk_type != SCTP_INITIATION) ||
370298132Stuexen					    (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
371298132Stuexen						SCTP_TCB_UNLOCK(stcb);
372298132Stuexen						return;
373298132Stuexen					}
374298132Stuexen				} else {
375298132Stuexen					SCTP_TCB_UNLOCK(stcb);
376298132Stuexen					return;
377298132Stuexen				}
378163953Srrs			}
379298132Stuexen			sctp6_notify(inp, stcb, net,
380298132Stuexen			    ip6cp->ip6c_icmp6->icmp6_type,
381298132Stuexen			    ip6cp->ip6c_icmp6->icmp6_code,
382319402Stuexen			    ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
383163953Srrs		} else {
384298132Stuexen			if ((stcb == NULL) && (inp != NULL)) {
385163953Srrs				/* reduce inp's ref-count */
386163953Srrs				SCTP_INP_WLOCK(inp);
387163953Srrs				SCTP_INP_DECR_REF(inp);
388163953Srrs				SCTP_INP_WUNLOCK(inp);
389163953Srrs			}
390298132Stuexen			if (stcb) {
391163953Srrs				SCTP_TCB_UNLOCK(stcb);
392298132Stuexen			}
393163953Srrs		}
394163953Srrs	}
395163953Srrs}
396163953Srrs
397163953Srrs/*
398163953Srrs * this routine can probably be collasped into the one in sctp_userreq.c
399163953Srrs * since they do the same thing and now we lookup with a sockaddr
400163953Srrs */
401163953Srrsstatic int
402163953Srrssctp6_getcred(SYSCTL_HANDLER_ARGS)
403163953Srrs{
404164085Srrs	struct xucred xuc;
405163953Srrs	struct sockaddr_in6 addrs[2];
406163953Srrs	struct sctp_inpcb *inp;
407163953Srrs	struct sctp_nets *net;
408163953Srrs	struct sctp_tcb *stcb;
409164085Srrs	int error;
410167598Srrs	uint32_t vrf_id;
411163953Srrs
412167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
413167598Srrs
414170587Srwatson	error = priv_check(req->td, PRIV_NETINET_GETCRED);
415163953Srrs	if (error)
416163953Srrs		return (error);
417163953Srrs
418171943Srrs	if (req->newlen != sizeof(addrs)) {
419171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
420163953Srrs		return (EINVAL);
421171943Srrs	}
422171943Srrs	if (req->oldlen != sizeof(struct ucred)) {
423171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
424163953Srrs		return (EINVAL);
425171943Srrs	}
426163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
427163953Srrs	if (error)
428163953Srrs		return (error);
429163953Srrs
430237715Stuexen	stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]),
431237715Stuexen	    sin6tosa(&addrs[0]),
432167598Srrs	    &inp, &net, 1, vrf_id);
433163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
434164085Srrs		if ((inp != NULL) && (stcb == NULL)) {
435164085Srrs			/* reduce ref-count */
436163953Srrs			SCTP_INP_WLOCK(inp);
437163953Srrs			SCTP_INP_DECR_REF(inp);
438164085Srrs			goto cred_can_cont;
439163953Srrs		}
440171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
441164085Srrs		error = ENOENT;
442163953Srrs		goto out;
443163953Srrs	}
444163953Srrs	SCTP_TCB_UNLOCK(stcb);
445164085Srrs	/*
446164085Srrs	 * We use the write lock here, only since in the error leg we need
447164085Srrs	 * it. If we used RLOCK, then we would have to
448164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
449164085Srrs	 * Better to use higher wlock.
450164085Srrs	 */
451164085Srrs	SCTP_INP_WLOCK(inp);
452164085Srrscred_can_cont:
453164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
454164085Srrs	if (error) {
455164085Srrs		SCTP_INP_WUNLOCK(inp);
456164085Srrs		goto out;
457164085Srrs	}
458164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
459164085Srrs	SCTP_INP_WUNLOCK(inp);
460164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
461163953Srrsout:
462163953Srrs	return (error);
463163953Srrs}
464163953Srrs
465163953SrrsSYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
466163953Srrs    0, 0,
467163953Srrs    sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
468163953Srrs
469163953Srrs
470163953Srrs/* This is the same as the sctp_abort() could be made common */
471163953Srrsstatic void
472163953Srrssctp6_abort(struct socket *so)
473163953Srrs{
474163953Srrs	struct sctp_inpcb *inp;
475163953Srrs	uint32_t flags;
476163953Srrs
477163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
478233005Stuexen	if (inp == NULL) {
479172091Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
480163953Srrs		return;
481172091Srrs	}
482163953Srrssctp_must_try_again:
483163953Srrs	flags = inp->sctp_flags;
484163953Srrs#ifdef SCTP_LOG_CLOSING
485163953Srrs	sctp_log_closing(inp, NULL, 17);
486163953Srrs#endif
487163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
488163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
489163953Srrs#ifdef SCTP_LOG_CLOSING
490163953Srrs		sctp_log_closing(inp, NULL, 16);
491163953Srrs#endif
492169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
493169380Srrs		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
494163953Srrs		SOCK_LOCK(so);
495167695Srrs		SCTP_SB_CLEAR(so->so_snd);
496163953Srrs		/*
497163953Srrs		 * same for the rcv ones, they are only here for the
498163953Srrs		 * accounting/select.
499163953Srrs		 */
500167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
501167695Srrs		/* Now null out the reference, we are completely detached. */
502163953Srrs		so->so_pcb = NULL;
503163953Srrs		SOCK_UNLOCK(so);
504163953Srrs	} else {
505163953Srrs		flags = inp->sctp_flags;
506163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
507163953Srrs			goto sctp_must_try_again;
508163953Srrs		}
509163953Srrs	}
510163953Srrs	return;
511163953Srrs}
512163953Srrs
513163953Srrsstatic int
514228653Stuexensctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
515163953Srrs{
516163953Srrs	struct in6pcb *inp6;
517166086Srrs	int error;
518163953Srrs	struct sctp_inpcb *inp;
519170205Srrs	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
520163953Srrs
521163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
522171943Srrs	if (inp != NULL) {
523171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
524228907Stuexen		return (EINVAL);
525171943Srrs	}
526163953Srrs	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
527179783Srrs		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
528163953Srrs		if (error)
529228907Stuexen			return (error);
530163953Srrs	}
531170205Srrs	error = sctp_inpcb_alloc(so, vrf_id);
532163953Srrs	if (error)
533228907Stuexen		return (error);
534163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
535170205Srrs	SCTP_INP_WLOCK(inp);
536163953Srrs	inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;	/* I'm v6! */
537163953Srrs	inp6 = (struct in6pcb *)inp;
538163953Srrs
539163953Srrs	inp6->inp_vflag |= INP_IPV6;
540163953Srrs	inp6->in6p_hops = -1;	/* use kernel default */
541163953Srrs	inp6->in6p_cksum = -1;	/* just to be sure */
542163953Srrs#ifdef INET
543163953Srrs	/*
544163953Srrs	 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
545163953Srrs	 * socket as well, because the socket may be bound to an IPv6
546163953Srrs	 * wildcard address, which may match an IPv4-mapped IPv6 address.
547163953Srrs	 */
548197288Srrs	inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
549163953Srrs#endif
550170205Srrs	SCTP_INP_WUNLOCK(inp);
551228907Stuexen	return (0);
552163953Srrs}
553163953Srrs
554163953Srrsstatic int
555163953Srrssctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
556163953Srrs{
557163953Srrs	struct sctp_inpcb *inp;
558163953Srrs	struct in6pcb *inp6;
559166086Srrs	int error;
560338986Sgordon	u_char vflagsav;
561163953Srrs
562163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
563233005Stuexen	if (inp == NULL) {
564171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
565228907Stuexen		return (EINVAL);
566171943Srrs	}
567170056Srrs	if (addr) {
568221249Stuexen		switch (addr->sa_family) {
569221249Stuexen#ifdef INET
570221249Stuexen		case AF_INET:
571221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
572221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
573228907Stuexen				return (EINVAL);
574221249Stuexen			}
575221249Stuexen			break;
576221249Stuexen#endif
577221249Stuexen#ifdef INET6
578221249Stuexen		case AF_INET6:
579221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
580221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
581228907Stuexen				return (EINVAL);
582221249Stuexen			}
583221249Stuexen			break;
584221249Stuexen#endif
585221249Stuexen		default:
586171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
587228907Stuexen			return (EINVAL);
588170056Srrs		}
589170056Srrs	}
590163953Srrs	inp6 = (struct in6pcb *)inp;
591338986Sgordon	vflagsav = inp6->inp_vflag;
592163953Srrs	inp6->inp_vflag &= ~INP_IPV4;
593163953Srrs	inp6->inp_vflag |= INP_IPV6;
594166023Srrs	if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
595221249Stuexen		switch (addr->sa_family) {
596221249Stuexen#ifdef INET
597221249Stuexen		case AF_INET:
598163953Srrs			/* binding v4 addr to v6 socket, so reset flags */
599163953Srrs			inp6->inp_vflag |= INP_IPV4;
600163953Srrs			inp6->inp_vflag &= ~INP_IPV6;
601221249Stuexen			break;
602221249Stuexen#endif
603221249Stuexen#ifdef INET6
604221249Stuexen		case AF_INET6:
605221249Stuexen			{
606221249Stuexen				struct sockaddr_in6 *sin6_p;
607163953Srrs
608221249Stuexen				sin6_p = (struct sockaddr_in6 *)addr;
609163953Srrs
610221249Stuexen				if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
611221249Stuexen					inp6->inp_vflag |= INP_IPV4;
612221249Stuexen				}
613221249Stuexen#ifdef INET
614221249Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
615221249Stuexen					struct sockaddr_in sin;
616163953Srrs
617221249Stuexen					in6_sin6_2_sin(&sin, sin6_p);
618221249Stuexen					inp6->inp_vflag |= INP_IPV4;
619221249Stuexen					inp6->inp_vflag &= ~INP_IPV6;
620221249Stuexen					error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
621338986Sgordon					goto out;
622221249Stuexen				}
623221249Stuexen#endif
624221249Stuexen				break;
625163953Srrs			}
626221249Stuexen#endif
627221249Stuexen		default:
628221249Stuexen			break;
629163953Srrs		}
630163953Srrs	} else if (addr != NULL) {
631221249Stuexen		struct sockaddr_in6 *sin6_p;
632221249Stuexen
633163953Srrs		/* IPV6_V6ONLY socket */
634221249Stuexen#ifdef INET
635163953Srrs		if (addr->sa_family == AF_INET) {
636163953Srrs			/* can't bind v4 addr to v6 only socket! */
637171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
638338986Sgordon			error = EINVAL;
639338986Sgordon			goto out;
640221249Stuexen		}
641221249Stuexen#endif
642221249Stuexen		sin6_p = (struct sockaddr_in6 *)addr;
643163953Srrs
644221249Stuexen		if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
645221249Stuexen			/* can't bind v4-mapped addrs either! */
646221249Stuexen			/* NOTE: we don't support SIIT */
647221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
648338986Sgordon			error = EINVAL;
649338986Sgordon			goto out;
650163953Srrs		}
651163953Srrs	}
652171572Srrs	error = sctp_inpcb_bind(so, addr, NULL, p);
653338986Sgordonout:
654338986Sgordon	if (error != 0)
655338986Sgordon		inp6->inp_vflag = vflagsav;
656228907Stuexen	return (error);
657163953Srrs}
658163953Srrs
659163953Srrs
660163953Srrsstatic void
661163953Srrssctp6_close(struct socket *so)
662163953Srrs{
663171990Srrs	sctp_close(so);
664163953Srrs}
665163953Srrs
666167598Srrs/* This could be made common with sctp_detach() since they are identical */
667163953Srrs
668168709Srrsstatic
669168709Srrsint
670163953Srrssctp6_disconnect(struct socket *so)
671163953Srrs{
672171990Srrs	return (sctp_disconnect(so));
673163953Srrs}
674163953Srrs
675168709Srrs
676163953Srrsint
677163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
678163953Srrs    struct mbuf *control, struct thread *p);
679163953Srrs
680163953Srrs
681163953Srrsstatic int
682163953Srrssctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
683163953Srrs    struct mbuf *control, struct thread *p)
684163953Srrs{
685163953Srrs	struct sctp_inpcb *inp;
686163953Srrs	struct in6pcb *inp6;
687163953Srrs
688163953Srrs#ifdef INET
689163953Srrs	struct sockaddr_in6 *sin6;
690163953Srrs#endif				/* INET */
691163953Srrs	/* No SPL needed since sctp_output does this */
692163953Srrs
693163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
694163953Srrs	if (inp == NULL) {
695163953Srrs		if (control) {
696169352Srrs			SCTP_RELEASE_PKT(control);
697163953Srrs			control = NULL;
698163953Srrs		}
699169352Srrs		SCTP_RELEASE_PKT(m);
700171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
701228907Stuexen		return (EINVAL);
702163953Srrs	}
703163953Srrs	inp6 = (struct in6pcb *)inp;
704163953Srrs	/*
705163953Srrs	 * For the TCP model we may get a NULL addr, if we are a connected
706163953Srrs	 * socket thats ok.
707163953Srrs	 */
708163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
709163953Srrs	    (addr == NULL)) {
710163953Srrs		goto connected_type;
711163953Srrs	}
712163953Srrs	if (addr == NULL) {
713169352Srrs		SCTP_RELEASE_PKT(m);
714163953Srrs		if (control) {
715169352Srrs			SCTP_RELEASE_PKT(control);
716163953Srrs			control = NULL;
717163953Srrs		}
718171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
719163953Srrs		return (EDESTADDRREQ);
720163953Srrs	}
721163953Srrs#ifdef INET
722163953Srrs	sin6 = (struct sockaddr_in6 *)addr;
723166023Srrs	if (SCTP_IPV6_V6ONLY(inp6)) {
724163953Srrs		/*
725163953Srrs		 * if IPV6_V6ONLY flag, we discard datagrams destined to a
726163953Srrs		 * v4 addr or v4-mapped addr
727163953Srrs		 */
728163953Srrs		if (addr->sa_family == AF_INET) {
729171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
730228907Stuexen			return (EINVAL);
731163953Srrs		}
732163953Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
733171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
734228907Stuexen			return (EINVAL);
735163953Srrs		}
736163953Srrs	}
737163953Srrs	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
738250466Stuexen		struct sockaddr_in sin;
739163953Srrs
740250466Stuexen		/* convert v4-mapped into v4 addr and send */
741250466Stuexen		in6_sin6_2_sin(&sin, sin6);
742250466Stuexen		return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p));
743163953Srrs	}
744163953Srrs#endif				/* INET */
745163953Srrsconnected_type:
746163953Srrs	/* now what about control */
747163953Srrs	if (control) {
748163953Srrs		if (inp->control) {
749169420Srrs			SCTP_PRINTF("huh? control set?\n");
750169352Srrs			SCTP_RELEASE_PKT(inp->control);
751163953Srrs			inp->control = NULL;
752163953Srrs		}
753163953Srrs		inp->control = control;
754163953Srrs	}
755163953Srrs	/* Place the data */
756163953Srrs	if (inp->pkt) {
757165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
758163953Srrs		inp->pkt_last = m;
759163953Srrs	} else {
760163953Srrs		inp->pkt_last = inp->pkt = m;
761163953Srrs	}
762163953Srrs	if (
763163953Srrs	/* FreeBSD and MacOSX uses a flag passed */
764163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
765163953Srrs	    ) {
766163953Srrs		/*
767163953Srrs		 * note with the current version this code will only be used
768163953Srrs		 * by OpenBSD, NetBSD and FreeBSD have methods for
769163953Srrs		 * re-defining sosend() to use sctp_sosend().  One can
770163953Srrs		 * optionaly switch back to this code (by changing back the
771163953Srrs		 * defininitions but this is not advisable.
772163953Srrs		 */
773163953Srrs		int ret;
774163953Srrs
775163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
776163953Srrs		inp->pkt = NULL;
777163953Srrs		inp->control = NULL;
778163953Srrs		return (ret);
779163953Srrs	} else {
780163953Srrs		return (0);
781163953Srrs	}
782163953Srrs}
783163953Srrs
784163953Srrsstatic int
785163953Srrssctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
786163953Srrs{
787167598Srrs	uint32_t vrf_id;
788163953Srrs	int error = 0;
789163953Srrs	struct sctp_inpcb *inp;
790163953Srrs	struct sctp_tcb *stcb;
791163953Srrs#ifdef INET
792257555Stuexen	struct in6pcb *inp6;
793163953Srrs	struct sockaddr_in6 *sin6;
794271221Stuexen	union sctp_sockstore store;
795221249Stuexen#endif
796163953Srrs
797257555Stuexen#ifdef INET
798163953Srrs	inp6 = (struct in6pcb *)so->so_pcb;
799257555Stuexen#endif
800163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
801233005Stuexen	if (inp == NULL) {
802171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
803163953Srrs		return (ECONNRESET);	/* I made the same as TCP since we are
804163953Srrs					 * not setup? */
805163953Srrs	}
806170056Srrs	if (addr == NULL) {
807171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
808170056Srrs		return (EINVAL);
809170056Srrs	}
810221249Stuexen	switch (addr->sa_family) {
811221249Stuexen#ifdef INET
812221249Stuexen	case AF_INET:
813221249Stuexen		if (addr->sa_len != sizeof(struct sockaddr_in)) {
814221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
815221249Stuexen			return (EINVAL);
816221249Stuexen		}
817221249Stuexen		break;
818221249Stuexen#endif
819221249Stuexen#ifdef INET6
820221249Stuexen	case AF_INET6:
821221249Stuexen		if (addr->sa_len != sizeof(struct sockaddr_in6)) {
822221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
823221249Stuexen			return (EINVAL);
824221249Stuexen		}
825221249Stuexen		break;
826221249Stuexen#endif
827221249Stuexen	default:
828171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
829170056Srrs		return (EINVAL);
830170056Srrs	}
831221249Stuexen
832168299Srrs	vrf_id = inp->def_vrf_id;
833163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
834163953Srrs	SCTP_INP_RLOCK(inp);
835163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
836163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
837163953Srrs		/* Bind a ephemeral port */
838163953Srrs		SCTP_INP_RUNLOCK(inp);
839163953Srrs		error = sctp6_bind(so, NULL, p);
840163953Srrs		if (error) {
841163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
842163953Srrs
843163953Srrs			return (error);
844163953Srrs		}
845163953Srrs		SCTP_INP_RLOCK(inp);
846163953Srrs	}
847163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
848163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
849163953Srrs		/* We are already connected AND the TCP model */
850163953Srrs		SCTP_INP_RUNLOCK(inp);
851163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
852171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
853163953Srrs		return (EADDRINUSE);
854163953Srrs	}
855163953Srrs#ifdef INET
856163953Srrs	sin6 = (struct sockaddr_in6 *)addr;
857166023Srrs	if (SCTP_IPV6_V6ONLY(inp6)) {
858163953Srrs		/*
859163953Srrs		 * if IPV6_V6ONLY flag, ignore connections destined to a v4
860163953Srrs		 * addr or v4-mapped addr
861163953Srrs		 */
862163953Srrs		if (addr->sa_family == AF_INET) {
863163953Srrs			SCTP_INP_RUNLOCK(inp);
864163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
865171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
866228907Stuexen			return (EINVAL);
867163953Srrs		}
868163953Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
869163953Srrs			SCTP_INP_RUNLOCK(inp);
870163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
871171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
872228907Stuexen			return (EINVAL);
873163953Srrs		}
874163953Srrs	}
875163953Srrs	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
876250466Stuexen		/* convert v4-mapped into v4 addr */
877271221Stuexen		in6_sin6_2_sin(&store.sin, sin6);
878271221Stuexen		addr = &store.sa;
879221411Stuexen	}
880163953Srrs#endif				/* INET */
881163953Srrs	/* Now do we connect? */
882163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
883163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
884169420Srrs		if (stcb) {
885332186Stuexen			SCTP_TCB_LOCK(stcb);
886169420Srrs		}
887163953Srrs		SCTP_INP_RUNLOCK(inp);
888163953Srrs	} else {
889163953Srrs		SCTP_INP_RUNLOCK(inp);
890163953Srrs		SCTP_INP_WLOCK(inp);
891163953Srrs		SCTP_INP_INCR_REF(inp);
892163953Srrs		SCTP_INP_WUNLOCK(inp);
893163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
894163953Srrs		if (stcb == NULL) {
895163953Srrs			SCTP_INP_WLOCK(inp);
896163953Srrs			SCTP_INP_DECR_REF(inp);
897163953Srrs			SCTP_INP_WUNLOCK(inp);
898163953Srrs		}
899163953Srrs	}
900163953Srrs
901163953Srrs	if (stcb != NULL) {
902163953Srrs		/* Already have or am bring up an association */
903163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
904163953Srrs		SCTP_TCB_UNLOCK(stcb);
905171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
906163953Srrs		return (EALREADY);
907163953Srrs	}
908163953Srrs	/* We are GOOD to go */
909298902Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id,
910298902Stuexen	    inp->sctp_ep.pre_open_stream_count,
911298902Stuexen	    inp->sctp_ep.port, p);
912163953Srrs	SCTP_ASOC_CREATE_UNLOCK(inp);
913163953Srrs	if (stcb == NULL) {
914163953Srrs		/* Gak! no memory */
915163953Srrs		return (error);
916163953Srrs	}
917163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
918163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
919163953Srrs		/* Set the connected flag so we can queue data */
920163953Srrs		soisconnecting(so);
921163953Srrs	}
922163953Srrs	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
923169420Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
924163953Srrs
925163953Srrs	/* initialize authentication parameters for the assoc */
926163953Srrs	sctp_initialize_auth_params(inp, stcb);
927163953Srrs
928172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
929163953Srrs	SCTP_TCB_UNLOCK(stcb);
930228907Stuexen	return (error);
931163953Srrs}
932163953Srrs
933163953Srrsstatic int
934163953Srrssctp6_getaddr(struct socket *so, struct sockaddr **addr)
935163953Srrs{
936163953Srrs	struct sockaddr_in6 *sin6;
937163953Srrs	struct sctp_inpcb *inp;
938167598Srrs	uint32_t vrf_id;
939167598Srrs	struct sctp_ifa *sctp_ifa;
940163953Srrs
941163953Srrs	int error;
942163953Srrs
943163953Srrs	/*
944163953Srrs	 * Do the malloc first in case it blocks.
945163953Srrs	 */
946221249Stuexen	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
947211944Stuexen	if (sin6 == NULL)
948228907Stuexen		return (ENOMEM);
949163953Srrs	sin6->sin6_family = AF_INET6;
950163953Srrs	sin6->sin6_len = sizeof(*sin6);
951163953Srrs
952163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
953163953Srrs	if (inp == NULL) {
954163953Srrs		SCTP_FREE_SONAME(sin6);
955171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
956228907Stuexen		return (ECONNRESET);
957163953Srrs	}
958163953Srrs	SCTP_INP_RLOCK(inp);
959163953Srrs	sin6->sin6_port = inp->sctp_lport;
960163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
961163953Srrs		/* For the bound all case you get back 0 */
962163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
963163953Srrs			struct sctp_tcb *stcb;
964163953Srrs			struct sockaddr_in6 *sin_a6;
965163953Srrs			struct sctp_nets *net;
966163953Srrs			int fnd;
967163953Srrs
968163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
969163953Srrs			if (stcb == NULL) {
970295771Stuexen				SCTP_INP_RUNLOCK(inp);
971295929Stuexen				SCTP_FREE_SONAME(sin6);
972295771Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
973295771Stuexen				return (ENOENT);
974163953Srrs			}
975163953Srrs			fnd = 0;
976163953Srrs			sin_a6 = NULL;
977163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
978163953Srrs				sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
979164085Srrs				if (sin_a6 == NULL)
980164085Srrs					/* this will make coverity happy */
981164085Srrs					continue;
982164085Srrs
983163953Srrs				if (sin_a6->sin6_family == AF_INET6) {
984163953Srrs					fnd = 1;
985163953Srrs					break;
986163953Srrs				}
987163953Srrs			}
988163953Srrs			if ((!fnd) || (sin_a6 == NULL)) {
989163953Srrs				/* punt */
990295771Stuexen				SCTP_INP_RUNLOCK(inp);
991295929Stuexen				SCTP_FREE_SONAME(sin6);
992295771Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
993295771Stuexen				return (ENOENT);
994163953Srrs			}
995168299Srrs			vrf_id = inp->def_vrf_id;
996310773Stuexen			sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *)&net->ro, net, 0, vrf_id);
997167598Srrs			if (sctp_ifa) {
998167598Srrs				sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
999167598Srrs			}
1000163953Srrs		} else {
1001163953Srrs			/* For the bound all case you get back 0 */
1002163953Srrs			memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1003163953Srrs		}
1004163953Srrs	} else {
1005163953Srrs		/* Take the first IPv6 address in the list */
1006163953Srrs		struct sctp_laddr *laddr;
1007163953Srrs		int fnd = 0;
1008163953Srrs
1009163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1010167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET6) {
1011163953Srrs				struct sockaddr_in6 *sin_a;
1012163953Srrs
1013271221Stuexen				sin_a = &laddr->ifa->address.sin6;
1014163953Srrs				sin6->sin6_addr = sin_a->sin6_addr;
1015163953Srrs				fnd = 1;
1016163953Srrs				break;
1017163953Srrs			}
1018163953Srrs		}
1019163953Srrs		if (!fnd) {
1020163953Srrs			SCTP_FREE_SONAME(sin6);
1021163953Srrs			SCTP_INP_RUNLOCK(inp);
1022171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1023228907Stuexen			return (ENOENT);
1024163953Srrs		}
1025163953Srrs	}
1026163953Srrs	SCTP_INP_RUNLOCK(inp);
1027163953Srrs	/* Scoping things for v6 */
1028164085Srrs	if ((error = sa6_recoverscope(sin6)) != 0) {
1029164085Srrs		SCTP_FREE_SONAME(sin6);
1030163953Srrs		return (error);
1031164085Srrs	}
1032163953Srrs	(*addr) = (struct sockaddr *)sin6;
1033163953Srrs	return (0);
1034163953Srrs}
1035163953Srrs
1036163953Srrsstatic int
1037163953Srrssctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1038163953Srrs{
1039231895Stuexen	struct sockaddr_in6 *sin6;
1040163953Srrs	int fnd;
1041163953Srrs	struct sockaddr_in6 *sin_a6;
1042163953Srrs	struct sctp_inpcb *inp;
1043163953Srrs	struct sctp_tcb *stcb;
1044163953Srrs	struct sctp_nets *net;
1045163953Srrs	int error;
1046163953Srrs
1047228907Stuexen	/* Do the malloc first in case it blocks. */
1048163953Srrs	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1049211944Stuexen	if (sin6 == NULL)
1050211944Stuexen		return (ENOMEM);
1051163953Srrs	sin6->sin6_family = AF_INET6;
1052163953Srrs	sin6->sin6_len = sizeof(*sin6);
1053163953Srrs
1054163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1055228907Stuexen	if ((inp == NULL) ||
1056228907Stuexen	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
1057228907Stuexen		/* UDP type and listeners will drop out here */
1058163953Srrs		SCTP_FREE_SONAME(sin6);
1059228907Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
1060228907Stuexen		return (ENOTCONN);
1061163953Srrs	}
1062163953Srrs	SCTP_INP_RLOCK(inp);
1063163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
1064169420Srrs	if (stcb) {
1065163953Srrs		SCTP_TCB_LOCK(stcb);
1066169420Srrs	}
1067163953Srrs	SCTP_INP_RUNLOCK(inp);
1068163953Srrs	if (stcb == NULL) {
1069163953Srrs		SCTP_FREE_SONAME(sin6);
1070171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1071228907Stuexen		return (ECONNRESET);
1072163953Srrs	}
1073163953Srrs	fnd = 0;
1074163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1075163953Srrs		sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1076163953Srrs		if (sin_a6->sin6_family == AF_INET6) {
1077163953Srrs			fnd = 1;
1078163953Srrs			sin6->sin6_port = stcb->rport;
1079163953Srrs			sin6->sin6_addr = sin_a6->sin6_addr;
1080163953Srrs			break;
1081163953Srrs		}
1082163953Srrs	}
1083163953Srrs	SCTP_TCB_UNLOCK(stcb);
1084163953Srrs	if (!fnd) {
1085163953Srrs		/* No IPv4 address */
1086163953Srrs		SCTP_FREE_SONAME(sin6);
1087171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1088228907Stuexen		return (ENOENT);
1089163953Srrs	}
1090275868Stuexen	if ((error = sa6_recoverscope(sin6)) != 0) {
1091275868Stuexen		SCTP_FREE_SONAME(sin6);
1092275868Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, error);
1093163953Srrs		return (error);
1094275868Stuexen	}
1095163953Srrs	*addr = (struct sockaddr *)sin6;
1096163953Srrs	return (0);
1097163953Srrs}
1098163953Srrs
1099163953Srrsstatic int
1100163953Srrssctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1101163953Srrs{
1102163953Srrs	struct in6pcb *inp6 = sotoin6pcb(so);
1103166086Srrs	int error;
1104163953Srrs
1105171943Srrs	if (inp6 == NULL) {
1106171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1107228907Stuexen		return (EINVAL);
1108171943Srrs	}
1109163953Srrs	/* allow v6 addresses precedence */
1110163953Srrs	error = sctp6_getaddr(so, nam);
1111221249Stuexen#ifdef INET
1112163953Srrs	if (error) {
1113295771Stuexen		struct sockaddr_in6 *sin6;
1114295771Stuexen
1115163953Srrs		/* try v4 next if v6 failed */
1116163953Srrs		error = sctp_ingetaddr(so, nam);
1117163953Srrs		if (error) {
1118163953Srrs			return (error);
1119163953Srrs		}
1120295771Stuexen		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1121295771Stuexen		if (sin6 == NULL) {
1122295771Stuexen			SCTP_FREE_SONAME(*nam);
1123295771Stuexen			return (ENOMEM);
1124163953Srrs		}
1125295771Stuexen		in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
1126295771Stuexen		SCTP_FREE_SONAME(*nam);
1127295771Stuexen		*nam = (struct sockaddr *)sin6;
1128163953Srrs	}
1129221249Stuexen#endif
1130163953Srrs	return (error);
1131163953Srrs}
1132163953Srrs
1133163953Srrs
1134163953Srrsstatic int
1135163953Srrssctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1136163953Srrs{
1137163953Srrs	struct in6pcb *inp6 = sotoin6pcb(so);
1138166086Srrs	int error;
1139163953Srrs
1140171943Srrs	if (inp6 == NULL) {
1141171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1142228907Stuexen		return (EINVAL);
1143171943Srrs	}
1144163953Srrs	/* allow v6 addresses precedence */
1145163953Srrs	error = sctp6_peeraddr(so, nam);
1146221249Stuexen#ifdef INET
1147163953Srrs	if (error) {
1148295771Stuexen		struct sockaddr_in6 *sin6;
1149295771Stuexen
1150163953Srrs		/* try v4 next if v6 failed */
1151163953Srrs		error = sctp_peeraddr(so, nam);
1152163953Srrs		if (error) {
1153163953Srrs			return (error);
1154163953Srrs		}
1155295771Stuexen		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1156295771Stuexen		if (sin6 == NULL) {
1157295771Stuexen			SCTP_FREE_SONAME(*nam);
1158295771Stuexen			return (ENOMEM);
1159163953Srrs		}
1160295771Stuexen		in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
1161295771Stuexen		SCTP_FREE_SONAME(*nam);
1162295771Stuexen		*nam = (struct sockaddr *)sin6;
1163163953Srrs	}
1164221249Stuexen#endif
1165228907Stuexen	return (error);
1166163953Srrs}
1167163953Srrs
1168163953Srrsstruct pr_usrreqs sctp6_usrreqs = {
1169163953Srrs	.pru_abort = sctp6_abort,
1170163953Srrs	.pru_accept = sctp_accept,
1171163953Srrs	.pru_attach = sctp6_attach,
1172163953Srrs	.pru_bind = sctp6_bind,
1173163953Srrs	.pru_connect = sctp6_connect,
1174163953Srrs	.pru_control = in6_control,
1175163953Srrs	.pru_close = sctp6_close,
1176163953Srrs	.pru_detach = sctp6_close,
1177163953Srrs	.pru_sopoll = sopoll_generic,
1178178201Srrs	.pru_flush = sctp_flush,
1179163953Srrs	.pru_disconnect = sctp6_disconnect,
1180163953Srrs	.pru_listen = sctp_listen,
1181163953Srrs	.pru_peeraddr = sctp6_getpeeraddr,
1182163953Srrs	.pru_send = sctp6_send,
1183163953Srrs	.pru_shutdown = sctp_shutdown,
1184163953Srrs	.pru_sockaddr = sctp6_in6getaddr,
1185163953Srrs	.pru_sosend = sctp_sosend,
1186163953Srrs	.pru_soreceive = sctp_soreceive
1187163953Srrs};
1188238501Stuexen
1189238501Stuexen#endif
1190