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 360750 2020-05-07 02:31:24Z 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;
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;
241360750Stuexen			if (net->port) {
242360750Stuexen				sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr));
243360750Stuexen			} else {
244360750Stuexen				sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu);
245360750Stuexen			}
246298132Stuexen		}
247298132Stuexen		/* Update the association MTU */
248298132Stuexen		if (stcb->asoc.smallest_mtu > next_mtu) {
249298132Stuexen			sctp_pathmtu_adjustment(stcb, next_mtu);
250298132Stuexen		}
251298132Stuexen		/* Finally, start the PMTU timer if it was running before. */
252298132Stuexen		if (timer_stopped) {
253298132Stuexen			sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
254298132Stuexen		}
255172091Srrs		SCTP_TCB_UNLOCK(stcb);
256298132Stuexen		break;
257298132Stuexen	default:
258298132Stuexen		SCTP_TCB_UNLOCK(stcb);
259298132Stuexen		break;
260172091Srrs	}
261172091Srrs}
262172091Srrs
263163953Srrsvoid
264171259Sdelphijsctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
265163953Srrs{
266298132Stuexen	struct ip6ctlparam *ip6cp;
267298132Stuexen	struct sctp_inpcb *inp;
268298132Stuexen	struct sctp_tcb *stcb;
269298132Stuexen	struct sctp_nets *net;
270163953Srrs	struct sctphdr sh;
271298132Stuexen	struct sockaddr_in6 src, dst;
272163953Srrs
273163953Srrs	if (pktdst->sa_family != AF_INET6 ||
274298132Stuexen	    pktdst->sa_len != sizeof(struct sockaddr_in6)) {
275163953Srrs		return;
276298132Stuexen	}
277347154Stuexen
278298132Stuexen	if ((unsigned)cmd >= PRC_NCMDS) {
279163953Srrs		return;
280298132Stuexen	}
281163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
282163953Srrs		d = NULL;
283163953Srrs	} else if (inet6ctlerrmap[cmd] == 0) {
284163953Srrs		return;
285163953Srrs	}
286298132Stuexen	/* If the parameter is from icmp6, decode it. */
287163953Srrs	if (d != NULL) {
288163953Srrs		ip6cp = (struct ip6ctlparam *)d;
289163953Srrs	} else {
290163953Srrs		ip6cp = (struct ip6ctlparam *)NULL;
291163953Srrs	}
292163953Srrs
293298132Stuexen	if (ip6cp != NULL) {
294163953Srrs		/*
295163953Srrs		 * XXX: We assume that when IPV6 is non NULL, M and OFF are
296163953Srrs		 * valid.
297163953Srrs		 */
298298132Stuexen		if (ip6cp->ip6c_m == NULL) {
299163953Srrs			return;
300298132Stuexen		}
301347154Stuexen
302298132Stuexen		/*
303298132Stuexen		 * Check if we can safely examine the ports and the
304298132Stuexen		 * verification tag of the SCTP common header.
305298132Stuexen		 */
306298132Stuexen		if (ip6cp->ip6c_m->m_pkthdr.len <
307310773Stuexen		    (int32_t)(ip6cp->ip6c_off + offsetof(struct sctphdr, checksum))) {
308293906Sglebius			return;
309298132Stuexen		}
310347154Stuexen
311298132Stuexen		/* Copy out the port numbers and the verification tag. */
312332172Stuexen		memset(&sh, 0, sizeof(sh));
313298132Stuexen		m_copydata(ip6cp->ip6c_m,
314298132Stuexen		    ip6cp->ip6c_off,
315298132Stuexen		    sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
316298132Stuexen		    (caddr_t)&sh);
317298132Stuexen		memset(&src, 0, sizeof(struct sockaddr_in6));
318298132Stuexen		src.sin6_family = AF_INET6;
319298132Stuexen		src.sin6_len = sizeof(struct sockaddr_in6);
320298132Stuexen		src.sin6_port = sh.src_port;
321298132Stuexen		src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
322298132Stuexen		if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
323298132Stuexen			return;
324298132Stuexen		}
325298132Stuexen		memset(&dst, 0, sizeof(struct sockaddr_in6));
326298132Stuexen		dst.sin6_family = AF_INET6;
327298132Stuexen		dst.sin6_len = sizeof(struct sockaddr_in6);
328298132Stuexen		dst.sin6_port = sh.dest_port;
329298132Stuexen		dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
330298132Stuexen		if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
331298132Stuexen			return;
332298132Stuexen		}
333163953Srrs		inp = NULL;
334163953Srrs		net = NULL;
335298132Stuexen		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
336298132Stuexen		    (struct sockaddr *)&src,
337298132Stuexen		    &inp, &net, 1, SCTP_DEFAULT_VRFID);
338298132Stuexen		if ((stcb != NULL) &&
339298132Stuexen		    (net != NULL) &&
340302138Stuexen		    (inp != NULL)) {
341298132Stuexen			/* Check the verification tag */
342298132Stuexen			if (ntohl(sh.v_tag) != 0) {
343298132Stuexen				/*
344298132Stuexen				 * This must be the verification tag used
345298132Stuexen				 * for sending out packets. We don't
346298132Stuexen				 * consider packets reflecting the
347298132Stuexen				 * verification tag.
348298132Stuexen				 */
349298132Stuexen				if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
350298132Stuexen					SCTP_TCB_UNLOCK(stcb);
351298132Stuexen					return;
352298132Stuexen				}
353163953Srrs			} else {
354298132Stuexen				if (ip6cp->ip6c_m->m_pkthdr.len >=
355298132Stuexen				    ip6cp->ip6c_off + sizeof(struct sctphdr) +
356298132Stuexen				    sizeof(struct sctp_chunkhdr) +
357298132Stuexen				    offsetof(struct sctp_init, a_rwnd)) {
358298132Stuexen					/*
359298132Stuexen					 * In this case we can check if we
360298132Stuexen					 * got an INIT chunk and if the
361298132Stuexen					 * initiate tag matches.
362298132Stuexen					 */
363298132Stuexen					uint32_t initiate_tag;
364298132Stuexen					uint8_t chunk_type;
365298132Stuexen
366298132Stuexen					m_copydata(ip6cp->ip6c_m,
367298132Stuexen					    ip6cp->ip6c_off +
368298132Stuexen					    sizeof(struct sctphdr),
369298132Stuexen					    sizeof(uint8_t),
370298132Stuexen					    (caddr_t)&chunk_type);
371298132Stuexen					m_copydata(ip6cp->ip6c_m,
372298132Stuexen					    ip6cp->ip6c_off +
373298132Stuexen					    sizeof(struct sctphdr) +
374298132Stuexen					    sizeof(struct sctp_chunkhdr),
375298132Stuexen					    sizeof(uint32_t),
376298132Stuexen					    (caddr_t)&initiate_tag);
377298132Stuexen					if ((chunk_type != SCTP_INITIATION) ||
378298132Stuexen					    (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
379298132Stuexen						SCTP_TCB_UNLOCK(stcb);
380298132Stuexen						return;
381298132Stuexen					}
382298132Stuexen				} else {
383298132Stuexen					SCTP_TCB_UNLOCK(stcb);
384298132Stuexen					return;
385298132Stuexen				}
386163953Srrs			}
387298132Stuexen			sctp6_notify(inp, stcb, net,
388298132Stuexen			    ip6cp->ip6c_icmp6->icmp6_type,
389298132Stuexen			    ip6cp->ip6c_icmp6->icmp6_code,
390319402Stuexen			    ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
391163953Srrs		} else {
392298132Stuexen			if ((stcb == NULL) && (inp != NULL)) {
393163953Srrs				/* reduce inp's ref-count */
394163953Srrs				SCTP_INP_WLOCK(inp);
395163953Srrs				SCTP_INP_DECR_REF(inp);
396163953Srrs				SCTP_INP_WUNLOCK(inp);
397163953Srrs			}
398298132Stuexen			if (stcb) {
399163953Srrs				SCTP_TCB_UNLOCK(stcb);
400298132Stuexen			}
401163953Srrs		}
402163953Srrs	}
403163953Srrs}
404163953Srrs
405163953Srrs/*
406163953Srrs * this routine can probably be collasped into the one in sctp_userreq.c
407163953Srrs * since they do the same thing and now we lookup with a sockaddr
408163953Srrs */
409163953Srrsstatic int
410163953Srrssctp6_getcred(SYSCTL_HANDLER_ARGS)
411163953Srrs{
412164085Srrs	struct xucred xuc;
413163953Srrs	struct sockaddr_in6 addrs[2];
414163953Srrs	struct sctp_inpcb *inp;
415163953Srrs	struct sctp_nets *net;
416163953Srrs	struct sctp_tcb *stcb;
417164085Srrs	int error;
418167598Srrs	uint32_t vrf_id;
419163953Srrs
420167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
421167598Srrs
422170587Srwatson	error = priv_check(req->td, PRIV_NETINET_GETCRED);
423163953Srrs	if (error)
424163953Srrs		return (error);
425163953Srrs
426171943Srrs	if (req->newlen != sizeof(addrs)) {
427171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
428163953Srrs		return (EINVAL);
429171943Srrs	}
430171943Srrs	if (req->oldlen != sizeof(struct ucred)) {
431171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
432163953Srrs		return (EINVAL);
433171943Srrs	}
434163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
435163953Srrs	if (error)
436163953Srrs		return (error);
437163953Srrs
438237715Stuexen	stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]),
439237715Stuexen	    sin6tosa(&addrs[0]),
440167598Srrs	    &inp, &net, 1, vrf_id);
441163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
442164085Srrs		if ((inp != NULL) && (stcb == NULL)) {
443164085Srrs			/* reduce ref-count */
444163953Srrs			SCTP_INP_WLOCK(inp);
445163953Srrs			SCTP_INP_DECR_REF(inp);
446164085Srrs			goto cred_can_cont;
447163953Srrs		}
448171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
449164085Srrs		error = ENOENT;
450163953Srrs		goto out;
451163953Srrs	}
452163953Srrs	SCTP_TCB_UNLOCK(stcb);
453164085Srrs	/*
454164085Srrs	 * We use the write lock here, only since in the error leg we need
455164085Srrs	 * it. If we used RLOCK, then we would have to
456164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
457164085Srrs	 * Better to use higher wlock.
458164085Srrs	 */
459164085Srrs	SCTP_INP_WLOCK(inp);
460164085Srrscred_can_cont:
461164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
462164085Srrs	if (error) {
463164085Srrs		SCTP_INP_WUNLOCK(inp);
464164085Srrs		goto out;
465164085Srrs	}
466164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
467164085Srrs	SCTP_INP_WUNLOCK(inp);
468164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
469163953Srrsout:
470163953Srrs	return (error);
471163953Srrs}
472163953Srrs
473163953SrrsSYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
474163953Srrs    0, 0,
475163953Srrs    sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
476163953Srrs
477163953Srrs
478163953Srrs/* This is the same as the sctp_abort() could be made common */
479163953Srrsstatic void
480163953Srrssctp6_abort(struct socket *so)
481163953Srrs{
482163953Srrs	struct sctp_inpcb *inp;
483163953Srrs	uint32_t flags;
484163953Srrs
485163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
486233005Stuexen	if (inp == NULL) {
487172091Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
488163953Srrs		return;
489172091Srrs	}
490163953Srrssctp_must_try_again:
491163953Srrs	flags = inp->sctp_flags;
492163953Srrs#ifdef SCTP_LOG_CLOSING
493163953Srrs	sctp_log_closing(inp, NULL, 17);
494163953Srrs#endif
495163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
496163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
497163953Srrs#ifdef SCTP_LOG_CLOSING
498163953Srrs		sctp_log_closing(inp, NULL, 16);
499163953Srrs#endif
500169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
501169380Srrs		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
502163953Srrs		SOCK_LOCK(so);
503167695Srrs		SCTP_SB_CLEAR(so->so_snd);
504163953Srrs		/*
505163953Srrs		 * same for the rcv ones, they are only here for the
506163953Srrs		 * accounting/select.
507163953Srrs		 */
508167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
509167695Srrs		/* Now null out the reference, we are completely detached. */
510163953Srrs		so->so_pcb = NULL;
511163953Srrs		SOCK_UNLOCK(so);
512163953Srrs	} else {
513163953Srrs		flags = inp->sctp_flags;
514163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
515163953Srrs			goto sctp_must_try_again;
516163953Srrs		}
517163953Srrs	}
518163953Srrs	return;
519163953Srrs}
520163953Srrs
521163953Srrsstatic int
522228653Stuexensctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
523163953Srrs{
524163953Srrs	struct in6pcb *inp6;
525166086Srrs	int error;
526163953Srrs	struct sctp_inpcb *inp;
527170205Srrs	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
528163953Srrs
529163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
530171943Srrs	if (inp != NULL) {
531171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
532228907Stuexen		return (EINVAL);
533171943Srrs	}
534347154Stuexen
535163953Srrs	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
536179783Srrs		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
537163953Srrs		if (error)
538228907Stuexen			return (error);
539163953Srrs	}
540170205Srrs	error = sctp_inpcb_alloc(so, vrf_id);
541163953Srrs	if (error)
542228907Stuexen		return (error);
543163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
544170205Srrs	SCTP_INP_WLOCK(inp);
545163953Srrs	inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;	/* I'm v6! */
546163953Srrs	inp6 = (struct in6pcb *)inp;
547163953Srrs
548163953Srrs	inp6->inp_vflag |= INP_IPV6;
549163953Srrs	inp6->in6p_hops = -1;	/* use kernel default */
550163953Srrs	inp6->in6p_cksum = -1;	/* just to be sure */
551163953Srrs#ifdef INET
552163953Srrs	/*
553163953Srrs	 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
554163953Srrs	 * socket as well, because the socket may be bound to an IPv6
555163953Srrs	 * wildcard address, which may match an IPv4-mapped IPv6 address.
556163953Srrs	 */
557197288Srrs	inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
558163953Srrs#endif
559170205Srrs	SCTP_INP_WUNLOCK(inp);
560228907Stuexen	return (0);
561163953Srrs}
562163953Srrs
563163953Srrsstatic int
564163953Srrssctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
565163953Srrs{
566163953Srrs	struct sctp_inpcb *inp;
567163953Srrs	struct in6pcb *inp6;
568166086Srrs	int error;
569338986Sgordon	u_char vflagsav;
570163953Srrs
571163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
572233005Stuexen	if (inp == NULL) {
573171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
574228907Stuexen		return (EINVAL);
575171943Srrs	}
576347154Stuexen
577170056Srrs	if (addr) {
578221249Stuexen		switch (addr->sa_family) {
579221249Stuexen#ifdef INET
580221249Stuexen		case AF_INET:
581221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
582221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
583228907Stuexen				return (EINVAL);
584221249Stuexen			}
585221249Stuexen			break;
586221249Stuexen#endif
587221249Stuexen#ifdef INET6
588221249Stuexen		case AF_INET6:
589221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
590221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
591228907Stuexen				return (EINVAL);
592221249Stuexen			}
593221249Stuexen			break;
594221249Stuexen#endif
595221249Stuexen		default:
596171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
597228907Stuexen			return (EINVAL);
598170056Srrs		}
599170056Srrs	}
600163953Srrs	inp6 = (struct in6pcb *)inp;
601338986Sgordon	vflagsav = inp6->inp_vflag;
602163953Srrs	inp6->inp_vflag &= ~INP_IPV4;
603163953Srrs	inp6->inp_vflag |= INP_IPV6;
604166023Srrs	if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
605221249Stuexen		switch (addr->sa_family) {
606221249Stuexen#ifdef INET
607221249Stuexen		case AF_INET:
608163953Srrs			/* binding v4 addr to v6 socket, so reset flags */
609163953Srrs			inp6->inp_vflag |= INP_IPV4;
610163953Srrs			inp6->inp_vflag &= ~INP_IPV6;
611221249Stuexen			break;
612221249Stuexen#endif
613221249Stuexen#ifdef INET6
614221249Stuexen		case AF_INET6:
615221249Stuexen			{
616221249Stuexen				struct sockaddr_in6 *sin6_p;
617163953Srrs
618221249Stuexen				sin6_p = (struct sockaddr_in6 *)addr;
619163953Srrs
620221249Stuexen				if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
621221249Stuexen					inp6->inp_vflag |= INP_IPV4;
622221249Stuexen				}
623221249Stuexen#ifdef INET
624221249Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
625221249Stuexen					struct sockaddr_in sin;
626163953Srrs
627221249Stuexen					in6_sin6_2_sin(&sin, sin6_p);
628221249Stuexen					inp6->inp_vflag |= INP_IPV4;
629221249Stuexen					inp6->inp_vflag &= ~INP_IPV6;
630221249Stuexen					error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
631338986Sgordon					goto out;
632221249Stuexen				}
633221249Stuexen#endif
634221249Stuexen				break;
635163953Srrs			}
636221249Stuexen#endif
637221249Stuexen		default:
638221249Stuexen			break;
639163953Srrs		}
640163953Srrs	} else if (addr != NULL) {
641221249Stuexen		struct sockaddr_in6 *sin6_p;
642221249Stuexen
643163953Srrs		/* IPV6_V6ONLY socket */
644221249Stuexen#ifdef INET
645163953Srrs		if (addr->sa_family == AF_INET) {
646163953Srrs			/* can't bind v4 addr to v6 only socket! */
647171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
648338986Sgordon			error = EINVAL;
649338986Sgordon			goto out;
650221249Stuexen		}
651221249Stuexen#endif
652221249Stuexen		sin6_p = (struct sockaddr_in6 *)addr;
653163953Srrs
654221249Stuexen		if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
655221249Stuexen			/* can't bind v4-mapped addrs either! */
656221249Stuexen			/* NOTE: we don't support SIIT */
657221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
658338986Sgordon			error = EINVAL;
659338986Sgordon			goto out;
660163953Srrs		}
661163953Srrs	}
662171572Srrs	error = sctp_inpcb_bind(so, addr, NULL, p);
663338986Sgordonout:
664338986Sgordon	if (error != 0)
665338986Sgordon		inp6->inp_vflag = vflagsav;
666228907Stuexen	return (error);
667163953Srrs}
668163953Srrs
669163953Srrs
670163953Srrsstatic void
671163953Srrssctp6_close(struct socket *so)
672163953Srrs{
673171990Srrs	sctp_close(so);
674163953Srrs}
675163953Srrs
676167598Srrs/* This could be made common with sctp_detach() since they are identical */
677163953Srrs
678168709Srrsstatic
679168709Srrsint
680163953Srrssctp6_disconnect(struct socket *so)
681163953Srrs{
682171990Srrs	return (sctp_disconnect(so));
683163953Srrs}
684163953Srrs
685168709Srrs
686163953Srrsint
687163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
688163953Srrs    struct mbuf *control, struct thread *p);
689163953Srrs
690163953Srrs
691163953Srrsstatic int
692163953Srrssctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
693163953Srrs    struct mbuf *control, struct thread *p)
694163953Srrs{
695163953Srrs	struct sctp_inpcb *inp;
696163953Srrs	struct in6pcb *inp6;
697163953Srrs
698163953Srrs#ifdef INET
699163953Srrs	struct sockaddr_in6 *sin6;
700163953Srrs#endif				/* INET */
701163953Srrs	/* No SPL needed since sctp_output does this */
702163953Srrs
703163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
704163953Srrs	if (inp == NULL) {
705163953Srrs		if (control) {
706169352Srrs			SCTP_RELEASE_PKT(control);
707163953Srrs			control = NULL;
708163953Srrs		}
709169352Srrs		SCTP_RELEASE_PKT(m);
710171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
711228907Stuexen		return (EINVAL);
712163953Srrs	}
713163953Srrs	inp6 = (struct in6pcb *)inp;
714163953Srrs	/*
715163953Srrs	 * For the TCP model we may get a NULL addr, if we are a connected
716163953Srrs	 * socket thats ok.
717163953Srrs	 */
718163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
719163953Srrs	    (addr == NULL)) {
720163953Srrs		goto connected_type;
721163953Srrs	}
722163953Srrs	if (addr == NULL) {
723169352Srrs		SCTP_RELEASE_PKT(m);
724163953Srrs		if (control) {
725169352Srrs			SCTP_RELEASE_PKT(control);
726163953Srrs			control = NULL;
727163953Srrs		}
728171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
729163953Srrs		return (EDESTADDRREQ);
730163953Srrs	}
731163953Srrs#ifdef INET
732163953Srrs	sin6 = (struct sockaddr_in6 *)addr;
733166023Srrs	if (SCTP_IPV6_V6ONLY(inp6)) {
734163953Srrs		/*
735163953Srrs		 * if IPV6_V6ONLY flag, we discard datagrams destined to a
736163953Srrs		 * v4 addr or v4-mapped addr
737163953Srrs		 */
738163953Srrs		if (addr->sa_family == AF_INET) {
739171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
740228907Stuexen			return (EINVAL);
741163953Srrs		}
742163953Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
743171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
744228907Stuexen			return (EINVAL);
745163953Srrs		}
746163953Srrs	}
747163953Srrs	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
748250466Stuexen		struct sockaddr_in sin;
749163953Srrs
750250466Stuexen		/* convert v4-mapped into v4 addr and send */
751250466Stuexen		in6_sin6_2_sin(&sin, sin6);
752250466Stuexen		return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p));
753163953Srrs	}
754163953Srrs#endif				/* INET */
755163953Srrsconnected_type:
756163953Srrs	/* now what about control */
757163953Srrs	if (control) {
758163953Srrs		if (inp->control) {
759169420Srrs			SCTP_PRINTF("huh? control set?\n");
760169352Srrs			SCTP_RELEASE_PKT(inp->control);
761163953Srrs			inp->control = NULL;
762163953Srrs		}
763163953Srrs		inp->control = control;
764163953Srrs	}
765163953Srrs	/* Place the data */
766163953Srrs	if (inp->pkt) {
767165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
768163953Srrs		inp->pkt_last = m;
769163953Srrs	} else {
770163953Srrs		inp->pkt_last = inp->pkt = m;
771163953Srrs	}
772163953Srrs	if (
773163953Srrs	/* FreeBSD and MacOSX uses a flag passed */
774163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
775163953Srrs	    ) {
776163953Srrs		/*
777163953Srrs		 * note with the current version this code will only be used
778163953Srrs		 * by OpenBSD, NetBSD and FreeBSD have methods for
779163953Srrs		 * re-defining sosend() to use sctp_sosend().  One can
780163953Srrs		 * optionaly switch back to this code (by changing back the
781163953Srrs		 * defininitions but this is not advisable.
782163953Srrs		 */
783163953Srrs		int ret;
784163953Srrs
785163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
786163953Srrs		inp->pkt = NULL;
787163953Srrs		inp->control = NULL;
788163953Srrs		return (ret);
789163953Srrs	} else {
790163953Srrs		return (0);
791163953Srrs	}
792163953Srrs}
793163953Srrs
794163953Srrsstatic int
795163953Srrssctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
796163953Srrs{
797167598Srrs	uint32_t vrf_id;
798163953Srrs	int error = 0;
799163953Srrs	struct sctp_inpcb *inp;
800163953Srrs	struct sctp_tcb *stcb;
801163953Srrs#ifdef INET
802257555Stuexen	struct in6pcb *inp6;
803163953Srrs	struct sockaddr_in6 *sin6;
804271221Stuexen	union sctp_sockstore store;
805221249Stuexen#endif
806163953Srrs
807257555Stuexen#ifdef INET
808163953Srrs	inp6 = (struct in6pcb *)so->so_pcb;
809257555Stuexen#endif
810163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
811233005Stuexen	if (inp == NULL) {
812171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
813163953Srrs		return (ECONNRESET);	/* I made the same as TCP since we are
814163953Srrs					 * not setup? */
815163953Srrs	}
816170056Srrs	if (addr == NULL) {
817171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
818170056Srrs		return (EINVAL);
819170056Srrs	}
820221249Stuexen	switch (addr->sa_family) {
821221249Stuexen#ifdef INET
822221249Stuexen	case AF_INET:
823221249Stuexen		if (addr->sa_len != sizeof(struct sockaddr_in)) {
824221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
825221249Stuexen			return (EINVAL);
826221249Stuexen		}
827221249Stuexen		break;
828221249Stuexen#endif
829221249Stuexen#ifdef INET6
830221249Stuexen	case AF_INET6:
831221249Stuexen		if (addr->sa_len != sizeof(struct sockaddr_in6)) {
832221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
833221249Stuexen			return (EINVAL);
834221249Stuexen		}
835221249Stuexen		break;
836221249Stuexen#endif
837221249Stuexen	default:
838171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
839170056Srrs		return (EINVAL);
840170056Srrs	}
841221249Stuexen
842168299Srrs	vrf_id = inp->def_vrf_id;
843163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
844163953Srrs	SCTP_INP_RLOCK(inp);
845163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
846163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
847163953Srrs		/* Bind a ephemeral port */
848163953Srrs		SCTP_INP_RUNLOCK(inp);
849163953Srrs		error = sctp6_bind(so, NULL, p);
850163953Srrs		if (error) {
851163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
852163953Srrs
853163953Srrs			return (error);
854163953Srrs		}
855163953Srrs		SCTP_INP_RLOCK(inp);
856163953Srrs	}
857163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
858163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
859163953Srrs		/* We are already connected AND the TCP model */
860163953Srrs		SCTP_INP_RUNLOCK(inp);
861163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
862171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
863163953Srrs		return (EADDRINUSE);
864163953Srrs	}
865163953Srrs#ifdef INET
866163953Srrs	sin6 = (struct sockaddr_in6 *)addr;
867166023Srrs	if (SCTP_IPV6_V6ONLY(inp6)) {
868163953Srrs		/*
869163953Srrs		 * if IPV6_V6ONLY flag, ignore connections destined to a v4
870163953Srrs		 * addr or v4-mapped addr
871163953Srrs		 */
872163953Srrs		if (addr->sa_family == AF_INET) {
873163953Srrs			SCTP_INP_RUNLOCK(inp);
874163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
875171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
876228907Stuexen			return (EINVAL);
877163953Srrs		}
878163953Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
879163953Srrs			SCTP_INP_RUNLOCK(inp);
880163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
881171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
882228907Stuexen			return (EINVAL);
883163953Srrs		}
884163953Srrs	}
885163953Srrs	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
886250466Stuexen		/* convert v4-mapped into v4 addr */
887271221Stuexen		in6_sin6_2_sin(&store.sin, sin6);
888271221Stuexen		addr = &store.sa;
889221411Stuexen	}
890163953Srrs#endif				/* INET */
891163953Srrs	/* Now do we connect? */
892163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
893163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
894169420Srrs		if (stcb) {
895332186Stuexen			SCTP_TCB_LOCK(stcb);
896169420Srrs		}
897163953Srrs		SCTP_INP_RUNLOCK(inp);
898163953Srrs	} else {
899163953Srrs		SCTP_INP_RUNLOCK(inp);
900163953Srrs		SCTP_INP_WLOCK(inp);
901163953Srrs		SCTP_INP_INCR_REF(inp);
902163953Srrs		SCTP_INP_WUNLOCK(inp);
903163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
904163953Srrs		if (stcb == NULL) {
905163953Srrs			SCTP_INP_WLOCK(inp);
906163953Srrs			SCTP_INP_DECR_REF(inp);
907163953Srrs			SCTP_INP_WUNLOCK(inp);
908163953Srrs		}
909163953Srrs	}
910163953Srrs
911163953Srrs	if (stcb != NULL) {
912163953Srrs		/* Already have or am bring up an association */
913163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
914163953Srrs		SCTP_TCB_UNLOCK(stcb);
915171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
916163953Srrs		return (EALREADY);
917163953Srrs	}
918163953Srrs	/* We are GOOD to go */
919298902Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id,
920298902Stuexen	    inp->sctp_ep.pre_open_stream_count,
921352057Stuexen	    inp->sctp_ep.port, p,
922352057Stuexen	    SCTP_INITIALIZE_AUTH_PARAMS);
923163953Srrs	SCTP_ASOC_CREATE_UNLOCK(inp);
924163953Srrs	if (stcb == NULL) {
925163953Srrs		/* Gak! no memory */
926163953Srrs		return (error);
927163953Srrs	}
928163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
929163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
930163953Srrs		/* Set the connected flag so we can queue data */
931163953Srrs		soisconnecting(so);
932163953Srrs	}
933347613Stuexen	SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
934169420Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
935172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
936163953Srrs	SCTP_TCB_UNLOCK(stcb);
937228907Stuexen	return (error);
938163953Srrs}
939163953Srrs
940163953Srrsstatic int
941163953Srrssctp6_getaddr(struct socket *so, struct sockaddr **addr)
942163953Srrs{
943163953Srrs	struct sockaddr_in6 *sin6;
944163953Srrs	struct sctp_inpcb *inp;
945167598Srrs	uint32_t vrf_id;
946167598Srrs	struct sctp_ifa *sctp_ifa;
947163953Srrs
948163953Srrs	int error;
949163953Srrs
950163953Srrs	/*
951163953Srrs	 * Do the malloc first in case it blocks.
952163953Srrs	 */
953221249Stuexen	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
954211944Stuexen	if (sin6 == NULL)
955228907Stuexen		return (ENOMEM);
956163953Srrs	sin6->sin6_family = AF_INET6;
957163953Srrs	sin6->sin6_len = sizeof(*sin6);
958163953Srrs
959163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
960163953Srrs	if (inp == NULL) {
961163953Srrs		SCTP_FREE_SONAME(sin6);
962171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
963228907Stuexen		return (ECONNRESET);
964163953Srrs	}
965163953Srrs	SCTP_INP_RLOCK(inp);
966163953Srrs	sin6->sin6_port = inp->sctp_lport;
967163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
968163953Srrs		/* For the bound all case you get back 0 */
969163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
970163953Srrs			struct sctp_tcb *stcb;
971163953Srrs			struct sockaddr_in6 *sin_a6;
972163953Srrs			struct sctp_nets *net;
973163953Srrs			int fnd;
974163953Srrs
975163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
976163953Srrs			if (stcb == NULL) {
977295771Stuexen				SCTP_INP_RUNLOCK(inp);
978295929Stuexen				SCTP_FREE_SONAME(sin6);
979295771Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
980295771Stuexen				return (ENOENT);
981163953Srrs			}
982163953Srrs			fnd = 0;
983163953Srrs			sin_a6 = NULL;
984163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
985163953Srrs				sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
986164085Srrs				if (sin_a6 == NULL)
987164085Srrs					/* this will make coverity happy */
988164085Srrs					continue;
989164085Srrs
990163953Srrs				if (sin_a6->sin6_family == AF_INET6) {
991163953Srrs					fnd = 1;
992163953Srrs					break;
993163953Srrs				}
994163953Srrs			}
995163953Srrs			if ((!fnd) || (sin_a6 == NULL)) {
996163953Srrs				/* punt */
997295771Stuexen				SCTP_INP_RUNLOCK(inp);
998295929Stuexen				SCTP_FREE_SONAME(sin6);
999295771Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1000295771Stuexen				return (ENOENT);
1001163953Srrs			}
1002168299Srrs			vrf_id = inp->def_vrf_id;
1003310773Stuexen			sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *)&net->ro, net, 0, vrf_id);
1004167598Srrs			if (sctp_ifa) {
1005167598Srrs				sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
1006167598Srrs			}
1007163953Srrs		} else {
1008163953Srrs			/* For the bound all case you get back 0 */
1009163953Srrs			memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1010163953Srrs		}
1011163953Srrs	} else {
1012163953Srrs		/* Take the first IPv6 address in the list */
1013163953Srrs		struct sctp_laddr *laddr;
1014163953Srrs		int fnd = 0;
1015163953Srrs
1016163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1017167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET6) {
1018163953Srrs				struct sockaddr_in6 *sin_a;
1019163953Srrs
1020271221Stuexen				sin_a = &laddr->ifa->address.sin6;
1021163953Srrs				sin6->sin6_addr = sin_a->sin6_addr;
1022163953Srrs				fnd = 1;
1023163953Srrs				break;
1024163953Srrs			}
1025163953Srrs		}
1026163953Srrs		if (!fnd) {
1027163953Srrs			SCTP_FREE_SONAME(sin6);
1028163953Srrs			SCTP_INP_RUNLOCK(inp);
1029171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1030228907Stuexen			return (ENOENT);
1031163953Srrs		}
1032163953Srrs	}
1033163953Srrs	SCTP_INP_RUNLOCK(inp);
1034163953Srrs	/* Scoping things for v6 */
1035164085Srrs	if ((error = sa6_recoverscope(sin6)) != 0) {
1036164085Srrs		SCTP_FREE_SONAME(sin6);
1037163953Srrs		return (error);
1038164085Srrs	}
1039163953Srrs	(*addr) = (struct sockaddr *)sin6;
1040163953Srrs	return (0);
1041163953Srrs}
1042163953Srrs
1043163953Srrsstatic int
1044163953Srrssctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1045163953Srrs{
1046231895Stuexen	struct sockaddr_in6 *sin6;
1047163953Srrs	int fnd;
1048163953Srrs	struct sockaddr_in6 *sin_a6;
1049163953Srrs	struct sctp_inpcb *inp;
1050163953Srrs	struct sctp_tcb *stcb;
1051163953Srrs	struct sctp_nets *net;
1052163953Srrs	int error;
1053163953Srrs
1054228907Stuexen	/* Do the malloc first in case it blocks. */
1055163953Srrs	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1056211944Stuexen	if (sin6 == NULL)
1057211944Stuexen		return (ENOMEM);
1058163953Srrs	sin6->sin6_family = AF_INET6;
1059163953Srrs	sin6->sin6_len = sizeof(*sin6);
1060163953Srrs
1061163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1062228907Stuexen	if ((inp == NULL) ||
1063228907Stuexen	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
1064228907Stuexen		/* UDP type and listeners will drop out here */
1065163953Srrs		SCTP_FREE_SONAME(sin6);
1066228907Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
1067228907Stuexen		return (ENOTCONN);
1068163953Srrs	}
1069163953Srrs	SCTP_INP_RLOCK(inp);
1070163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
1071169420Srrs	if (stcb) {
1072163953Srrs		SCTP_TCB_LOCK(stcb);
1073169420Srrs	}
1074163953Srrs	SCTP_INP_RUNLOCK(inp);
1075163953Srrs	if (stcb == NULL) {
1076163953Srrs		SCTP_FREE_SONAME(sin6);
1077171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1078228907Stuexen		return (ECONNRESET);
1079163953Srrs	}
1080163953Srrs	fnd = 0;
1081163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1082163953Srrs		sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1083163953Srrs		if (sin_a6->sin6_family == AF_INET6) {
1084163953Srrs			fnd = 1;
1085163953Srrs			sin6->sin6_port = stcb->rport;
1086163953Srrs			sin6->sin6_addr = sin_a6->sin6_addr;
1087163953Srrs			break;
1088163953Srrs		}
1089163953Srrs	}
1090163953Srrs	SCTP_TCB_UNLOCK(stcb);
1091163953Srrs	if (!fnd) {
1092163953Srrs		/* No IPv4 address */
1093163953Srrs		SCTP_FREE_SONAME(sin6);
1094171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1095228907Stuexen		return (ENOENT);
1096163953Srrs	}
1097275868Stuexen	if ((error = sa6_recoverscope(sin6)) != 0) {
1098275868Stuexen		SCTP_FREE_SONAME(sin6);
1099275868Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, error);
1100163953Srrs		return (error);
1101275868Stuexen	}
1102163953Srrs	*addr = (struct sockaddr *)sin6;
1103163953Srrs	return (0);
1104163953Srrs}
1105163953Srrs
1106163953Srrsstatic int
1107163953Srrssctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1108163953Srrs{
1109163953Srrs	struct in6pcb *inp6 = sotoin6pcb(so);
1110166086Srrs	int error;
1111163953Srrs
1112171943Srrs	if (inp6 == NULL) {
1113171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1114228907Stuexen		return (EINVAL);
1115171943Srrs	}
1116347154Stuexen
1117163953Srrs	/* allow v6 addresses precedence */
1118163953Srrs	error = sctp6_getaddr(so, nam);
1119221249Stuexen#ifdef INET
1120163953Srrs	if (error) {
1121295771Stuexen		struct sockaddr_in6 *sin6;
1122295771Stuexen
1123163953Srrs		/* try v4 next if v6 failed */
1124163953Srrs		error = sctp_ingetaddr(so, nam);
1125163953Srrs		if (error) {
1126163953Srrs			return (error);
1127163953Srrs		}
1128295771Stuexen		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1129295771Stuexen		if (sin6 == NULL) {
1130295771Stuexen			SCTP_FREE_SONAME(*nam);
1131295771Stuexen			return (ENOMEM);
1132163953Srrs		}
1133295771Stuexen		in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
1134295771Stuexen		SCTP_FREE_SONAME(*nam);
1135295771Stuexen		*nam = (struct sockaddr *)sin6;
1136163953Srrs	}
1137221249Stuexen#endif
1138163953Srrs	return (error);
1139163953Srrs}
1140163953Srrs
1141163953Srrs
1142163953Srrsstatic int
1143163953Srrssctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1144163953Srrs{
1145163953Srrs	struct in6pcb *inp6 = sotoin6pcb(so);
1146166086Srrs	int error;
1147163953Srrs
1148171943Srrs	if (inp6 == NULL) {
1149171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1150228907Stuexen		return (EINVAL);
1151171943Srrs	}
1152347154Stuexen
1153163953Srrs	/* allow v6 addresses precedence */
1154163953Srrs	error = sctp6_peeraddr(so, nam);
1155221249Stuexen#ifdef INET
1156163953Srrs	if (error) {
1157295771Stuexen		struct sockaddr_in6 *sin6;
1158295771Stuexen
1159163953Srrs		/* try v4 next if v6 failed */
1160163953Srrs		error = sctp_peeraddr(so, nam);
1161163953Srrs		if (error) {
1162163953Srrs			return (error);
1163163953Srrs		}
1164295771Stuexen		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1165295771Stuexen		if (sin6 == NULL) {
1166295771Stuexen			SCTP_FREE_SONAME(*nam);
1167295771Stuexen			return (ENOMEM);
1168163953Srrs		}
1169295771Stuexen		in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
1170295771Stuexen		SCTP_FREE_SONAME(*nam);
1171295771Stuexen		*nam = (struct sockaddr *)sin6;
1172163953Srrs	}
1173221249Stuexen#endif
1174228907Stuexen	return (error);
1175163953Srrs}
1176163953Srrs
1177163953Srrsstruct pr_usrreqs sctp6_usrreqs = {
1178163953Srrs	.pru_abort = sctp6_abort,
1179163953Srrs	.pru_accept = sctp_accept,
1180163953Srrs	.pru_attach = sctp6_attach,
1181163953Srrs	.pru_bind = sctp6_bind,
1182163953Srrs	.pru_connect = sctp6_connect,
1183163953Srrs	.pru_control = in6_control,
1184163953Srrs	.pru_close = sctp6_close,
1185163953Srrs	.pru_detach = sctp6_close,
1186163953Srrs	.pru_sopoll = sopoll_generic,
1187178201Srrs	.pru_flush = sctp_flush,
1188163953Srrs	.pru_disconnect = sctp6_disconnect,
1189163953Srrs	.pru_listen = sctp_listen,
1190163953Srrs	.pru_peeraddr = sctp6_getpeeraddr,
1191163953Srrs	.pru_send = sctp6_send,
1192163953Srrs	.pru_shutdown = sctp_shutdown,
1193163953Srrs	.pru_sockaddr = sctp6_in6getaddr,
1194163953Srrs	.pru_sosend = sctp_sosend,
1195163953Srrs	.pru_soreceive = sctp_soreceive
1196163953Srrs};
1197238501Stuexen
1198238501Stuexen#endif
1199