sctp6_usrreq.c revision 298132
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: head/sys/netinet6/sctp6_usrreq.c 298132 2016-04-16 21:34:49Z 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
58171167Sgnn#ifdef IPSEC
59171133Sgnn#include <netipsec/ipsec.h>
60171133Sgnn#include <netipsec/ipsec6.h>
61171440Srrs#endif				/* IPSEC */
62163953Srrs
63163953Srrsextern struct protosw inetsw[];
64163953Srrs
65163953Srrsint
66243186Stuexensctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port)
67163953Srrs{
68165647Srrs	struct mbuf *m;
69237569Stuexen	int iphlen;
70238003Stuexen	uint32_t vrf_id;
71237569Stuexen	uint8_t ecn_bits;
72237715Stuexen	struct sockaddr_in6 src, dst;
73163953Srrs	struct ip6_hdr *ip6;
74163953Srrs	struct sctphdr *sh;
75163953Srrs	struct sctp_chunkhdr *ch;
76237569Stuexen	int length, offset;
77211969Stuexen
78211969Stuexen#if !defined(SCTP_WITH_NO_CSUM)
79238003Stuexen	uint8_t compute_crc;
80211969Stuexen
81211969Stuexen#endif
82238003Stuexen	uint32_t mflowid;
83275483Stuexen	uint8_t mflowtype;
84284515Stuexen	uint16_t fibnum;
85163953Srrs
86237569Stuexen	iphlen = *offp;
87169352Srrs	if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
88169352Srrs		SCTP_RELEASE_PKT(*i_pak);
89237569Stuexen		return (IPPROTO_DONE);
90169352Srrs	}
91168709Srrs	m = SCTP_HEADER_TO_CHAIN(*i_pak);
92237569Stuexen#ifdef SCTP_MBUF_LOGGING
93237569Stuexen	/* Log in any input mbufs */
94237569Stuexen	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
95276914Stuexen		sctp_log_mbc(m, SCTP_MBUF_INPUT);
96237569Stuexen	}
97237569Stuexen#endif
98237540Stuexen#ifdef SCTP_PACKET_LOGGING
99237540Stuexen	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
100237540Stuexen		sctp_packet_log(m);
101237540Stuexen	}
102170091Srrs#endif
103238003Stuexen	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
104254854Stuexen	    "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n",
105238003Stuexen	    m->m_pkthdr.len,
106238003Stuexen	    if_name(m->m_pkthdr.rcvif),
107254854Stuexen	    (int)m->m_pkthdr.csum_flags, CSUM_BITS);
108275483Stuexen	mflowid = m->m_pkthdr.flowid;
109275483Stuexen	mflowtype = M_HASHTYPE_GET(m);
110284515Stuexen	fibnum = M_GETFIB(m);
111237569Stuexen	SCTP_STAT_INCR(sctps_recvpackets);
112237569Stuexen	SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
113237569Stuexen	/* Get IP, SCTP, and first chunk header together in the first mbuf. */
114238003Stuexen	offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
115163953Srrs	ip6 = mtod(m, struct ip6_hdr *);
116237569Stuexen	IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
117237569Stuexen	    (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
118163953Srrs	if (sh == NULL) {
119163953Srrs		SCTP_STAT_INCR(sctps_hdrops);
120228907Stuexen		return (IPPROTO_DONE);
121163953Srrs	}
122163953Srrs	ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
123237569Stuexen	offset -= sizeof(struct sctp_chunkhdr);
124237715Stuexen	memset(&src, 0, sizeof(struct sockaddr_in6));
125237715Stuexen	src.sin6_family = AF_INET6;
126237715Stuexen	src.sin6_len = sizeof(struct sockaddr_in6);
127237715Stuexen	src.sin6_port = sh->src_port;
128237715Stuexen	src.sin6_addr = ip6->ip6_src;
129237715Stuexen	if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
130238003Stuexen		goto out;
131237715Stuexen	}
132237715Stuexen	memset(&dst, 0, sizeof(struct sockaddr_in6));
133237715Stuexen	dst.sin6_family = AF_INET6;
134237715Stuexen	dst.sin6_len = sizeof(struct sockaddr_in6);
135237715Stuexen	dst.sin6_port = sh->dest_port;
136237715Stuexen	dst.sin6_addr = ip6->ip6_dst;
137237715Stuexen	if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
138238003Stuexen		goto out;
139237715Stuexen	}
140237569Stuexen	length = ntohs(ip6->ip6_plen) + iphlen;
141237569Stuexen	/* Validate mbuf chain length with IP payload length. */
142238003Stuexen	if (SCTP_HEADER_LEN(m) != length) {
143237569Stuexen		SCTPDBG(SCTP_DEBUG_INPUT1,
144238003Stuexen		    "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m));
145237569Stuexen		SCTP_STAT_INCR(sctps_hdrops);
146238003Stuexen		goto out;
147237569Stuexen	}
148163953Srrs	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
149238003Stuexen		goto out;
150163953Srrs	}
151238003Stuexen	ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
152211969Stuexen#if defined(SCTP_WITH_NO_CSUM)
153211969Stuexen	SCTP_STAT_INCR(sctps_recvnocrc);
154211969Stuexen#else
155188067Srrs	if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
156188067Srrs		SCTP_STAT_INCR(sctps_recvhwcrc);
157238003Stuexen		compute_crc = 0;
158238003Stuexen	} else {
159238003Stuexen		SCTP_STAT_INCR(sctps_recvswcrc);
160238003Stuexen		compute_crc = 1;
161188067Srrs	}
162218400Stuexen#endif
163238003Stuexen	sctp_common_input_processing(&m, iphlen, offset, length,
164237715Stuexen	    (struct sockaddr *)&src,
165237715Stuexen	    (struct sockaddr *)&dst,
166238003Stuexen	    sh, ch,
167238003Stuexen#if !defined(SCTP_WITH_NO_CSUM)
168238003Stuexen	    compute_crc,
169218400Stuexen#endif
170238003Stuexen	    ecn_bits,
171284515Stuexen	    mflowtype, mflowid, fibnum,
172237049Stuexen	    vrf_id, port);
173238003Stuexenout:
174237569Stuexen	if (m) {
175169352Srrs		sctp_m_freem(m);
176237569Stuexen	}
177228907Stuexen	return (IPPROTO_DONE);
178163953Srrs}
179163953Srrs
180163953Srrs
181243186Stuexenint
182243186Stuexensctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED)
183243186Stuexen{
184243186Stuexen	return (sctp6_input_with_port(i_pak, offp, 0));
185243186Stuexen}
186243186Stuexen
187172156Srrsvoid
188172091Srrssctp6_notify(struct sctp_inpcb *inp,
189172091Srrs    struct sctp_tcb *stcb,
190298132Stuexen    struct sctp_nets *net,
191298132Stuexen    uint8_t icmp6_type,
192298132Stuexen    uint8_t icmp6_code,
193298132Stuexen    uint16_t next_mtu)
194172091Srrs{
195237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
196172091Srrs	struct socket *so;
197172091Srrs
198172091Srrs#endif
199298132Stuexen	int timer_stopped;
200235360Stuexen
201298132Stuexen	switch (icmp6_type) {
202298132Stuexen	case ICMP6_DST_UNREACH:
203298132Stuexen		if ((icmp6_code == ICMP6_DST_UNREACH_NOROUTE) ||
204298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_ADMIN) ||
205298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_BEYONDSCOPE) ||
206298132Stuexen		    (icmp6_code == ICMP6_DST_UNREACH_ADDR)) {
207298132Stuexen			/* Mark the net unreachable. */
208298132Stuexen			if (net->dest_state & SCTP_ADDR_REACHABLE) {
209298132Stuexen				/* Ok that destination is not reachable */
210298132Stuexen				net->dest_state &= ~SCTP_ADDR_REACHABLE;
211298132Stuexen				net->dest_state &= ~SCTP_ADDR_PF;
212298132Stuexen				sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
213298132Stuexen				    stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED);
214298132Stuexen			}
215172091Srrs		}
216172091Srrs		SCTP_TCB_UNLOCK(stcb);
217298132Stuexen		break;
218298132Stuexen	case ICMP6_PARAM_PROB:
219298132Stuexen		/* Treat it like an ABORT. */
220298132Stuexen		if (icmp6_code == ICMP6_PARAMPROB_NEXTHEADER) {
221298132Stuexen			sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
222237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
223298132Stuexen			so = SCTP_INP_SO(inp);
224298132Stuexen			atomic_add_int(&stcb->asoc.refcnt, 1);
225298132Stuexen			SCTP_TCB_UNLOCK(stcb);
226298132Stuexen			SCTP_SOCKET_LOCK(so, 1);
227298132Stuexen			SCTP_TCB_LOCK(stcb);
228298132Stuexen			atomic_subtract_int(&stcb->asoc.refcnt, 1);
229172091Srrs#endif
230298132Stuexen			(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
231298132Stuexen			    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
232237565Stuexen#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
233298132Stuexen			SCTP_SOCKET_UNLOCK(so, 1);
234172091Srrs#endif
235298132Stuexen		} else {
236298132Stuexen			SCTP_TCB_UNLOCK(stcb);
237298132Stuexen		}
238298132Stuexen		break;
239298132Stuexen	case ICMP6_PACKET_TOO_BIG:
240298132Stuexen		if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
241298132Stuexen			timer_stopped = 1;
242298132Stuexen			sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
243298132Stuexen			    SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
244298132Stuexen		} else {
245298132Stuexen			timer_stopped = 0;
246298132Stuexen		}
247298132Stuexen		break;
248298132Stuexen		/* Update the path MTU. */
249298132Stuexen		if (net->mtu > next_mtu) {
250298132Stuexen			net->mtu = next_mtu;
251298132Stuexen			if (net->port) {
252298132Stuexen				net->mtu -= sizeof(struct udphdr);
253298132Stuexen			}
254298132Stuexen		}
255298132Stuexen		/* Update the association MTU */
256298132Stuexen		if (stcb->asoc.smallest_mtu > next_mtu) {
257298132Stuexen			sctp_pathmtu_adjustment(stcb, next_mtu);
258298132Stuexen		}
259298132Stuexen		/* Finally, start the PMTU timer if it was running before. */
260298132Stuexen		if (timer_stopped) {
261298132Stuexen			sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
262298132Stuexen		}
263172091Srrs		SCTP_TCB_UNLOCK(stcb);
264298132Stuexen		break;
265298132Stuexen	default:
266298132Stuexen		SCTP_TCB_UNLOCK(stcb);
267298132Stuexen		break;
268172091Srrs	}
269172091Srrs}
270172091Srrs
271163953Srrsvoid
272171259Sdelphijsctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
273163953Srrs{
274298132Stuexen	struct ip6ctlparam *ip6cp;
275298132Stuexen	struct sctp_inpcb *inp;
276298132Stuexen	struct sctp_tcb *stcb;
277298132Stuexen	struct sctp_nets *net;
278163953Srrs	struct sctphdr sh;
279298132Stuexen	struct sockaddr_in6 src, dst;
280163953Srrs
281163953Srrs	if (pktdst->sa_family != AF_INET6 ||
282298132Stuexen	    pktdst->sa_len != sizeof(struct sockaddr_in6)) {
283163953Srrs		return;
284298132Stuexen	}
285298132Stuexen	if ((unsigned)cmd >= PRC_NCMDS) {
286163953Srrs		return;
287298132Stuexen	}
288163953Srrs	if (PRC_IS_REDIRECT(cmd)) {
289163953Srrs		d = NULL;
290163953Srrs	} else if (inet6ctlerrmap[cmd] == 0) {
291163953Srrs		return;
292163953Srrs	}
293298132Stuexen	/* If the parameter is from icmp6, decode it. */
294163953Srrs	if (d != NULL) {
295163953Srrs		ip6cp = (struct ip6ctlparam *)d;
296163953Srrs	} else {
297163953Srrs		ip6cp = (struct ip6ctlparam *)NULL;
298163953Srrs	}
299163953Srrs
300298132Stuexen	if (ip6cp != NULL) {
301163953Srrs		/*
302163953Srrs		 * XXX: We assume that when IPV6 is non NULL, M and OFF are
303163953Srrs		 * valid.
304163953Srrs		 */
305298132Stuexen		if (ip6cp->ip6c_m == NULL) {
306163953Srrs			return;
307298132Stuexen		}
308298132Stuexen		/*
309298132Stuexen		 * Check if we can safely examine the ports and the
310298132Stuexen		 * verification tag of the SCTP common header.
311298132Stuexen		 */
312298132Stuexen		if (ip6cp->ip6c_m->m_pkthdr.len <
313298132Stuexen		    ip6cp->ip6c_off + offsetof(struct sctphdr, checksum)) {
314293906Sglebius			return;
315298132Stuexen		}
316298132Stuexen		/* Copy out the port numbers and the verification tag. */
317163953Srrs		bzero(&sh, sizeof(sh));
318298132Stuexen		m_copydata(ip6cp->ip6c_m,
319298132Stuexen		    ip6cp->ip6c_off,
320298132Stuexen		    sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t),
321298132Stuexen		    (caddr_t)&sh);
322298132Stuexen		memset(&src, 0, sizeof(struct sockaddr_in6));
323298132Stuexen		src.sin6_family = AF_INET6;
324298132Stuexen		src.sin6_len = sizeof(struct sockaddr_in6);
325298132Stuexen		src.sin6_port = sh.src_port;
326298132Stuexen		src.sin6_addr = ip6cp->ip6c_ip6->ip6_src;
327298132Stuexen		if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
328298132Stuexen			return;
329298132Stuexen		}
330298132Stuexen		memset(&dst, 0, sizeof(struct sockaddr_in6));
331298132Stuexen		dst.sin6_family = AF_INET6;
332298132Stuexen		dst.sin6_len = sizeof(struct sockaddr_in6);
333298132Stuexen		dst.sin6_port = sh.dest_port;
334298132Stuexen		dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst;
335298132Stuexen		if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) {
336298132Stuexen			return;
337298132Stuexen		}
338163953Srrs		inp = NULL;
339163953Srrs		net = NULL;
340298132Stuexen		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
341298132Stuexen		    (struct sockaddr *)&src,
342298132Stuexen		    &inp, &net, 1, SCTP_DEFAULT_VRFID);
343298132Stuexen		if ((stcb != NULL) &&
344298132Stuexen		    (net != NULL) &&
345298132Stuexen		    (inp != NULL) &&
346298132Stuexen		    (inp->sctp_socket != NULL)) {
347298132Stuexen			/* Check the verification tag */
348298132Stuexen			if (ntohl(sh.v_tag) != 0) {
349298132Stuexen				/*
350298132Stuexen				 * This must be the verification tag used
351298132Stuexen				 * for sending out packets. We don't
352298132Stuexen				 * consider packets reflecting the
353298132Stuexen				 * verification tag.
354298132Stuexen				 */
355298132Stuexen				if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) {
356298132Stuexen					SCTP_TCB_UNLOCK(stcb);
357298132Stuexen					return;
358298132Stuexen				}
359163953Srrs			} else {
360298132Stuexen				if (ip6cp->ip6c_m->m_pkthdr.len >=
361298132Stuexen				    ip6cp->ip6c_off + sizeof(struct sctphdr) +
362298132Stuexen				    sizeof(struct sctp_chunkhdr) +
363298132Stuexen				    offsetof(struct sctp_init, a_rwnd)) {
364298132Stuexen					/*
365298132Stuexen					 * In this case we can check if we
366298132Stuexen					 * got an INIT chunk and if the
367298132Stuexen					 * initiate tag matches.
368298132Stuexen					 */
369298132Stuexen					uint32_t initiate_tag;
370298132Stuexen					uint8_t chunk_type;
371298132Stuexen
372298132Stuexen					m_copydata(ip6cp->ip6c_m,
373298132Stuexen					    ip6cp->ip6c_off +
374298132Stuexen					    sizeof(struct sctphdr),
375298132Stuexen					    sizeof(uint8_t),
376298132Stuexen					    (caddr_t)&chunk_type);
377298132Stuexen					m_copydata(ip6cp->ip6c_m,
378298132Stuexen					    ip6cp->ip6c_off +
379298132Stuexen					    sizeof(struct sctphdr) +
380298132Stuexen					    sizeof(struct sctp_chunkhdr),
381298132Stuexen					    sizeof(uint32_t),
382298132Stuexen					    (caddr_t)&initiate_tag);
383298132Stuexen					if ((chunk_type != SCTP_INITIATION) ||
384298132Stuexen					    (ntohl(initiate_tag) != stcb->asoc.my_vtag)) {
385298132Stuexen						SCTP_TCB_UNLOCK(stcb);
386298132Stuexen						return;
387298132Stuexen					}
388298132Stuexen				} else {
389298132Stuexen					SCTP_TCB_UNLOCK(stcb);
390298132Stuexen					return;
391298132Stuexen				}
392163953Srrs			}
393298132Stuexen			sctp6_notify(inp, stcb, net,
394298132Stuexen			    ip6cp->ip6c_icmp6->icmp6_type,
395298132Stuexen			    ip6cp->ip6c_icmp6->icmp6_code,
396298132Stuexen			    (uint16_t) ntohl(ip6cp->ip6c_icmp6->icmp6_mtu));
397163953Srrs		} else {
398298132Stuexen			if ((stcb == NULL) && (inp != NULL)) {
399163953Srrs				/* reduce inp's ref-count */
400163953Srrs				SCTP_INP_WLOCK(inp);
401163953Srrs				SCTP_INP_DECR_REF(inp);
402163953Srrs				SCTP_INP_WUNLOCK(inp);
403163953Srrs			}
404298132Stuexen			if (stcb) {
405163953Srrs				SCTP_TCB_UNLOCK(stcb);
406298132Stuexen			}
407163953Srrs		}
408163953Srrs	}
409163953Srrs}
410163953Srrs
411163953Srrs/*
412163953Srrs * this routine can probably be collasped into the one in sctp_userreq.c
413163953Srrs * since they do the same thing and now we lookup with a sockaddr
414163953Srrs */
415163953Srrsstatic int
416163953Srrssctp6_getcred(SYSCTL_HANDLER_ARGS)
417163953Srrs{
418164085Srrs	struct xucred xuc;
419163953Srrs	struct sockaddr_in6 addrs[2];
420163953Srrs	struct sctp_inpcb *inp;
421163953Srrs	struct sctp_nets *net;
422163953Srrs	struct sctp_tcb *stcb;
423164085Srrs	int error;
424167598Srrs	uint32_t vrf_id;
425163953Srrs
426167598Srrs	vrf_id = SCTP_DEFAULT_VRFID;
427167598Srrs
428170587Srwatson	error = priv_check(req->td, PRIV_NETINET_GETCRED);
429163953Srrs	if (error)
430163953Srrs		return (error);
431163953Srrs
432171943Srrs	if (req->newlen != sizeof(addrs)) {
433171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
434163953Srrs		return (EINVAL);
435171943Srrs	}
436171943Srrs	if (req->oldlen != sizeof(struct ucred)) {
437171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
438163953Srrs		return (EINVAL);
439171943Srrs	}
440163953Srrs	error = SYSCTL_IN(req, addrs, sizeof(addrs));
441163953Srrs	if (error)
442163953Srrs		return (error);
443163953Srrs
444237715Stuexen	stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]),
445237715Stuexen	    sin6tosa(&addrs[0]),
446167598Srrs	    &inp, &net, 1, vrf_id);
447163953Srrs	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
448164085Srrs		if ((inp != NULL) && (stcb == NULL)) {
449164085Srrs			/* reduce ref-count */
450163953Srrs			SCTP_INP_WLOCK(inp);
451163953Srrs			SCTP_INP_DECR_REF(inp);
452164085Srrs			goto cred_can_cont;
453163953Srrs		}
454171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
455164085Srrs		error = ENOENT;
456163953Srrs		goto out;
457163953Srrs	}
458163953Srrs	SCTP_TCB_UNLOCK(stcb);
459164085Srrs	/*
460164085Srrs	 * We use the write lock here, only since in the error leg we need
461164085Srrs	 * it. If we used RLOCK, then we would have to
462164085Srrs	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
463164085Srrs	 * Better to use higher wlock.
464164085Srrs	 */
465164085Srrs	SCTP_INP_WLOCK(inp);
466164085Srrscred_can_cont:
467164085Srrs	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
468164085Srrs	if (error) {
469164085Srrs		SCTP_INP_WUNLOCK(inp);
470164085Srrs		goto out;
471164085Srrs	}
472164085Srrs	cru2x(inp->sctp_socket->so_cred, &xuc);
473164085Srrs	SCTP_INP_WUNLOCK(inp);
474164085Srrs	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
475163953Srrsout:
476163953Srrs	return (error);
477163953Srrs}
478163953Srrs
479163953SrrsSYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
480163953Srrs    0, 0,
481163953Srrs    sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
482163953Srrs
483163953Srrs
484163953Srrs/* This is the same as the sctp_abort() could be made common */
485163953Srrsstatic void
486163953Srrssctp6_abort(struct socket *so)
487163953Srrs{
488163953Srrs	struct sctp_inpcb *inp;
489163953Srrs	uint32_t flags;
490163953Srrs
491163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
492233005Stuexen	if (inp == NULL) {
493172091Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
494163953Srrs		return;
495172091Srrs	}
496163953Srrssctp_must_try_again:
497163953Srrs	flags = inp->sctp_flags;
498163953Srrs#ifdef SCTP_LOG_CLOSING
499163953Srrs	sctp_log_closing(inp, NULL, 17);
500163953Srrs#endif
501163953Srrs	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
502163953Srrs	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
503163953Srrs#ifdef SCTP_LOG_CLOSING
504163953Srrs		sctp_log_closing(inp, NULL, 16);
505163953Srrs#endif
506169380Srrs		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
507169380Srrs		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
508163953Srrs		SOCK_LOCK(so);
509167695Srrs		SCTP_SB_CLEAR(so->so_snd);
510163953Srrs		/*
511163953Srrs		 * same for the rcv ones, they are only here for the
512163953Srrs		 * accounting/select.
513163953Srrs		 */
514167695Srrs		SCTP_SB_CLEAR(so->so_rcv);
515167695Srrs		/* Now null out the reference, we are completely detached. */
516163953Srrs		so->so_pcb = NULL;
517163953Srrs		SOCK_UNLOCK(so);
518163953Srrs	} else {
519163953Srrs		flags = inp->sctp_flags;
520163953Srrs		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
521163953Srrs			goto sctp_must_try_again;
522163953Srrs		}
523163953Srrs	}
524163953Srrs	return;
525163953Srrs}
526163953Srrs
527163953Srrsstatic int
528228653Stuexensctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
529163953Srrs{
530163953Srrs	struct in6pcb *inp6;
531166086Srrs	int error;
532163953Srrs	struct sctp_inpcb *inp;
533170205Srrs	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
534163953Srrs
535163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
536171943Srrs	if (inp != NULL) {
537171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
538228907Stuexen		return (EINVAL);
539171943Srrs	}
540163953Srrs	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
541179783Srrs		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
542163953Srrs		if (error)
543228907Stuexen			return (error);
544163953Srrs	}
545170205Srrs	error = sctp_inpcb_alloc(so, vrf_id);
546163953Srrs	if (error)
547228907Stuexen		return (error);
548163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
549170205Srrs	SCTP_INP_WLOCK(inp);
550163953Srrs	inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;	/* I'm v6! */
551163953Srrs	inp6 = (struct in6pcb *)inp;
552163953Srrs
553163953Srrs	inp6->inp_vflag |= INP_IPV6;
554163953Srrs	inp6->in6p_hops = -1;	/* use kernel default */
555163953Srrs	inp6->in6p_cksum = -1;	/* just to be sure */
556163953Srrs#ifdef INET
557163953Srrs	/*
558163953Srrs	 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
559163953Srrs	 * socket as well, because the socket may be bound to an IPv6
560163953Srrs	 * wildcard address, which may match an IPv4-mapped IPv6 address.
561163953Srrs	 */
562197288Srrs	inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
563163953Srrs#endif
564163953Srrs	/*
565163953Srrs	 * Hmm what about the IPSEC stuff that is missing here but in
566163953Srrs	 * sctp_attach()?
567163953Srrs	 */
568170205Srrs	SCTP_INP_WUNLOCK(inp);
569228907Stuexen	return (0);
570163953Srrs}
571163953Srrs
572163953Srrsstatic int
573163953Srrssctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
574163953Srrs{
575163953Srrs	struct sctp_inpcb *inp;
576163953Srrs	struct in6pcb *inp6;
577166086Srrs	int error;
578163953Srrs
579163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
580233005Stuexen	if (inp == NULL) {
581171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
582228907Stuexen		return (EINVAL);
583171943Srrs	}
584170056Srrs	if (addr) {
585221249Stuexen		switch (addr->sa_family) {
586221249Stuexen#ifdef INET
587221249Stuexen		case AF_INET:
588221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in)) {
589221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
590228907Stuexen				return (EINVAL);
591221249Stuexen			}
592221249Stuexen			break;
593221249Stuexen#endif
594221249Stuexen#ifdef INET6
595221249Stuexen		case AF_INET6:
596221249Stuexen			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
597221249Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
598228907Stuexen				return (EINVAL);
599221249Stuexen			}
600221249Stuexen			break;
601221249Stuexen#endif
602221249Stuexen		default:
603171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
604228907Stuexen			return (EINVAL);
605170056Srrs		}
606170056Srrs	}
607163953Srrs	inp6 = (struct in6pcb *)inp;
608163953Srrs	inp6->inp_vflag &= ~INP_IPV4;
609163953Srrs	inp6->inp_vflag |= INP_IPV6;
610166023Srrs	if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
611221249Stuexen		switch (addr->sa_family) {
612221249Stuexen#ifdef INET
613221249Stuexen		case AF_INET:
614163953Srrs			/* binding v4 addr to v6 socket, so reset flags */
615163953Srrs			inp6->inp_vflag |= INP_IPV4;
616163953Srrs			inp6->inp_vflag &= ~INP_IPV6;
617221249Stuexen			break;
618221249Stuexen#endif
619221249Stuexen#ifdef INET6
620221249Stuexen		case AF_INET6:
621221249Stuexen			{
622221249Stuexen				struct sockaddr_in6 *sin6_p;
623163953Srrs
624221249Stuexen				sin6_p = (struct sockaddr_in6 *)addr;
625163953Srrs
626221249Stuexen				if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
627221249Stuexen					inp6->inp_vflag |= INP_IPV4;
628221249Stuexen				}
629221249Stuexen#ifdef INET
630221249Stuexen				if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
631221249Stuexen					struct sockaddr_in sin;
632163953Srrs
633221249Stuexen					in6_sin6_2_sin(&sin, sin6_p);
634221249Stuexen					inp6->inp_vflag |= INP_IPV4;
635221249Stuexen					inp6->inp_vflag &= ~INP_IPV6;
636221249Stuexen					error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
637228907Stuexen					return (error);
638221249Stuexen				}
639221249Stuexen#endif
640221249Stuexen				break;
641163953Srrs			}
642221249Stuexen#endif
643221249Stuexen		default:
644221249Stuexen			break;
645163953Srrs		}
646163953Srrs	} else if (addr != NULL) {
647221249Stuexen		struct sockaddr_in6 *sin6_p;
648221249Stuexen
649163953Srrs		/* IPV6_V6ONLY socket */
650221249Stuexen#ifdef INET
651163953Srrs		if (addr->sa_family == AF_INET) {
652163953Srrs			/* can't bind v4 addr to v6 only socket! */
653171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
654228907Stuexen			return (EINVAL);
655221249Stuexen		}
656221249Stuexen#endif
657221249Stuexen		sin6_p = (struct sockaddr_in6 *)addr;
658163953Srrs
659221249Stuexen		if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
660221249Stuexen			/* can't bind v4-mapped addrs either! */
661221249Stuexen			/* NOTE: we don't support SIIT */
662221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
663228907Stuexen			return (EINVAL);
664163953Srrs		}
665163953Srrs	}
666171572Srrs	error = sctp_inpcb_bind(so, addr, NULL, p);
667228907Stuexen	return (error);
668163953Srrs}
669163953Srrs
670163953Srrs
671163953Srrsstatic void
672163953Srrssctp6_close(struct socket *so)
673163953Srrs{
674171990Srrs	sctp_close(so);
675163953Srrs}
676163953Srrs
677167598Srrs/* This could be made common with sctp_detach() since they are identical */
678163953Srrs
679168709Srrsstatic
680168709Srrsint
681163953Srrssctp6_disconnect(struct socket *so)
682163953Srrs{
683171990Srrs	return (sctp_disconnect(so));
684163953Srrs}
685163953Srrs
686168709Srrs
687163953Srrsint
688163953Srrssctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
689163953Srrs    struct mbuf *control, struct thread *p);
690163953Srrs
691163953Srrs
692163953Srrsstatic int
693163953Srrssctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
694163953Srrs    struct mbuf *control, struct thread *p)
695163953Srrs{
696163953Srrs	struct sctp_inpcb *inp;
697163953Srrs	struct in6pcb *inp6;
698163953Srrs
699163953Srrs#ifdef INET
700163953Srrs	struct sockaddr_in6 *sin6;
701163953Srrs
702163953Srrs#endif				/* INET */
703163953Srrs	/* No SPL needed since sctp_output does this */
704163953Srrs
705163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
706163953Srrs	if (inp == NULL) {
707163953Srrs		if (control) {
708169352Srrs			SCTP_RELEASE_PKT(control);
709163953Srrs			control = NULL;
710163953Srrs		}
711169352Srrs		SCTP_RELEASE_PKT(m);
712171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
713228907Stuexen		return (EINVAL);
714163953Srrs	}
715163953Srrs	inp6 = (struct in6pcb *)inp;
716163953Srrs	/*
717163953Srrs	 * For the TCP model we may get a NULL addr, if we are a connected
718163953Srrs	 * socket thats ok.
719163953Srrs	 */
720163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
721163953Srrs	    (addr == NULL)) {
722163953Srrs		goto connected_type;
723163953Srrs	}
724163953Srrs	if (addr == NULL) {
725169352Srrs		SCTP_RELEASE_PKT(m);
726163953Srrs		if (control) {
727169352Srrs			SCTP_RELEASE_PKT(control);
728163953Srrs			control = NULL;
729163953Srrs		}
730171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
731163953Srrs		return (EDESTADDRREQ);
732163953Srrs	}
733163953Srrs#ifdef INET
734163953Srrs	sin6 = (struct sockaddr_in6 *)addr;
735166023Srrs	if (SCTP_IPV6_V6ONLY(inp6)) {
736163953Srrs		/*
737163953Srrs		 * if IPV6_V6ONLY flag, we discard datagrams destined to a
738163953Srrs		 * v4 addr or v4-mapped addr
739163953Srrs		 */
740163953Srrs		if (addr->sa_family == AF_INET) {
741171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
742228907Stuexen			return (EINVAL);
743163953Srrs		}
744163953Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
745171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
746228907Stuexen			return (EINVAL);
747163953Srrs		}
748163953Srrs	}
749163953Srrs	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
750250466Stuexen		struct sockaddr_in sin;
751163953Srrs
752250466Stuexen		/* convert v4-mapped into v4 addr and send */
753250466Stuexen		in6_sin6_2_sin(&sin, sin6);
754250466Stuexen		return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p));
755163953Srrs	}
756163953Srrs#endif				/* INET */
757163953Srrsconnected_type:
758163953Srrs	/* now what about control */
759163953Srrs	if (control) {
760163953Srrs		if (inp->control) {
761169420Srrs			SCTP_PRINTF("huh? control set?\n");
762169352Srrs			SCTP_RELEASE_PKT(inp->control);
763163953Srrs			inp->control = NULL;
764163953Srrs		}
765163953Srrs		inp->control = control;
766163953Srrs	}
767163953Srrs	/* Place the data */
768163953Srrs	if (inp->pkt) {
769165647Srrs		SCTP_BUF_NEXT(inp->pkt_last) = m;
770163953Srrs		inp->pkt_last = m;
771163953Srrs	} else {
772163953Srrs		inp->pkt_last = inp->pkt = m;
773163953Srrs	}
774163953Srrs	if (
775163953Srrs	/* FreeBSD and MacOSX uses a flag passed */
776163953Srrs	    ((flags & PRUS_MORETOCOME) == 0)
777163953Srrs	    ) {
778163953Srrs		/*
779163953Srrs		 * note with the current version this code will only be used
780163953Srrs		 * by OpenBSD, NetBSD and FreeBSD have methods for
781163953Srrs		 * re-defining sosend() to use sctp_sosend().  One can
782163953Srrs		 * optionaly switch back to this code (by changing back the
783163953Srrs		 * defininitions but this is not advisable.
784163953Srrs		 */
785163953Srrs		int ret;
786163953Srrs
787163953Srrs		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
788163953Srrs		inp->pkt = NULL;
789163953Srrs		inp->control = NULL;
790163953Srrs		return (ret);
791163953Srrs	} else {
792163953Srrs		return (0);
793163953Srrs	}
794163953Srrs}
795163953Srrs
796163953Srrsstatic int
797163953Srrssctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
798163953Srrs{
799167598Srrs	uint32_t vrf_id;
800163953Srrs	int error = 0;
801163953Srrs	struct sctp_inpcb *inp;
802163953Srrs	struct sctp_tcb *stcb;
803163953Srrs
804163953Srrs#ifdef INET
805257555Stuexen	struct in6pcb *inp6;
806163953Srrs	struct sockaddr_in6 *sin6;
807271221Stuexen	union sctp_sockstore store;
808163953Srrs
809221249Stuexen#endif
810163953Srrs
811257555Stuexen#ifdef INET
812163953Srrs	inp6 = (struct in6pcb *)so->so_pcb;
813257555Stuexen#endif
814163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
815233005Stuexen	if (inp == NULL) {
816171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
817163953Srrs		return (ECONNRESET);	/* I made the same as TCP since we are
818163953Srrs					 * not setup? */
819163953Srrs	}
820170056Srrs	if (addr == NULL) {
821171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
822170056Srrs		return (EINVAL);
823170056Srrs	}
824221249Stuexen	switch (addr->sa_family) {
825221249Stuexen#ifdef INET
826221249Stuexen	case AF_INET:
827221249Stuexen		if (addr->sa_len != sizeof(struct sockaddr_in)) {
828221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
829221249Stuexen			return (EINVAL);
830221249Stuexen		}
831221249Stuexen		break;
832221249Stuexen#endif
833221249Stuexen#ifdef INET6
834221249Stuexen	case AF_INET6:
835221249Stuexen		if (addr->sa_len != sizeof(struct sockaddr_in6)) {
836221249Stuexen			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
837221249Stuexen			return (EINVAL);
838221249Stuexen		}
839221249Stuexen		break;
840221249Stuexen#endif
841221249Stuexen	default:
842171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
843170056Srrs		return (EINVAL);
844170056Srrs	}
845221249Stuexen
846168299Srrs	vrf_id = inp->def_vrf_id;
847163953Srrs	SCTP_ASOC_CREATE_LOCK(inp);
848163953Srrs	SCTP_INP_RLOCK(inp);
849163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
850163953Srrs	    SCTP_PCB_FLAGS_UNBOUND) {
851163953Srrs		/* Bind a ephemeral port */
852163953Srrs		SCTP_INP_RUNLOCK(inp);
853163953Srrs		error = sctp6_bind(so, NULL, p);
854163953Srrs		if (error) {
855163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
856163953Srrs
857163953Srrs			return (error);
858163953Srrs		}
859163953Srrs		SCTP_INP_RLOCK(inp);
860163953Srrs	}
861163953Srrs	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
862163953Srrs	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
863163953Srrs		/* We are already connected AND the TCP model */
864163953Srrs		SCTP_INP_RUNLOCK(inp);
865163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
866171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
867163953Srrs		return (EADDRINUSE);
868163953Srrs	}
869163953Srrs#ifdef INET
870163953Srrs	sin6 = (struct sockaddr_in6 *)addr;
871166023Srrs	if (SCTP_IPV6_V6ONLY(inp6)) {
872163953Srrs		/*
873163953Srrs		 * if IPV6_V6ONLY flag, ignore connections destined to a v4
874163953Srrs		 * addr or v4-mapped addr
875163953Srrs		 */
876163953Srrs		if (addr->sa_family == AF_INET) {
877163953Srrs			SCTP_INP_RUNLOCK(inp);
878163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
879171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
880228907Stuexen			return (EINVAL);
881163953Srrs		}
882163953Srrs		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
883163953Srrs			SCTP_INP_RUNLOCK(inp);
884163953Srrs			SCTP_ASOC_CREATE_UNLOCK(inp);
885171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
886228907Stuexen			return (EINVAL);
887163953Srrs		}
888163953Srrs	}
889163953Srrs	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
890250466Stuexen		/* convert v4-mapped into v4 addr */
891271221Stuexen		in6_sin6_2_sin(&store.sin, sin6);
892271221Stuexen		addr = &store.sa;
893221411Stuexen	}
894163953Srrs#endif				/* INET */
895163953Srrs	/* Now do we connect? */
896163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
897163953Srrs		stcb = LIST_FIRST(&inp->sctp_asoc_list);
898169420Srrs		if (stcb) {
899163953Srrs			SCTP_TCB_UNLOCK(stcb);
900169420Srrs		}
901163953Srrs		SCTP_INP_RUNLOCK(inp);
902163953Srrs	} else {
903163953Srrs		SCTP_INP_RUNLOCK(inp);
904163953Srrs		SCTP_INP_WLOCK(inp);
905163953Srrs		SCTP_INP_INCR_REF(inp);
906163953Srrs		SCTP_INP_WUNLOCK(inp);
907163953Srrs		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
908163953Srrs		if (stcb == NULL) {
909163953Srrs			SCTP_INP_WLOCK(inp);
910163953Srrs			SCTP_INP_DECR_REF(inp);
911163953Srrs			SCTP_INP_WUNLOCK(inp);
912163953Srrs		}
913163953Srrs	}
914163953Srrs
915163953Srrs	if (stcb != NULL) {
916163953Srrs		/* Already have or am bring up an association */
917163953Srrs		SCTP_ASOC_CREATE_UNLOCK(inp);
918163953Srrs		SCTP_TCB_UNLOCK(stcb);
919171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
920163953Srrs		return (EALREADY);
921163953Srrs	}
922163953Srrs	/* We are GOOD to go */
923291904Stuexen	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, p);
924163953Srrs	SCTP_ASOC_CREATE_UNLOCK(inp);
925163953Srrs	if (stcb == NULL) {
926163953Srrs		/* Gak! no memory */
927163953Srrs		return (error);
928163953Srrs	}
929163953Srrs	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
930163953Srrs		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
931163953Srrs		/* Set the connected flag so we can queue data */
932163953Srrs		soisconnecting(so);
933163953Srrs	}
934163953Srrs	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
935169420Srrs	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
936163953Srrs
937163953Srrs	/* initialize authentication parameters for the assoc */
938163953Srrs	sctp_initialize_auth_params(inp, stcb);
939163953Srrs
940172090Srrs	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
941163953Srrs	SCTP_TCB_UNLOCK(stcb);
942228907Stuexen	return (error);
943163953Srrs}
944163953Srrs
945163953Srrsstatic int
946163953Srrssctp6_getaddr(struct socket *so, struct sockaddr **addr)
947163953Srrs{
948163953Srrs	struct sockaddr_in6 *sin6;
949163953Srrs	struct sctp_inpcb *inp;
950167598Srrs	uint32_t vrf_id;
951167598Srrs	struct sctp_ifa *sctp_ifa;
952163953Srrs
953163953Srrs	int error;
954163953Srrs
955163953Srrs	/*
956163953Srrs	 * Do the malloc first in case it blocks.
957163953Srrs	 */
958221249Stuexen	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
959211944Stuexen	if (sin6 == NULL)
960228907Stuexen		return (ENOMEM);
961163953Srrs	sin6->sin6_family = AF_INET6;
962163953Srrs	sin6->sin6_len = sizeof(*sin6);
963163953Srrs
964163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
965163953Srrs	if (inp == NULL) {
966163953Srrs		SCTP_FREE_SONAME(sin6);
967171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
968228907Stuexen		return (ECONNRESET);
969163953Srrs	}
970163953Srrs	SCTP_INP_RLOCK(inp);
971163953Srrs	sin6->sin6_port = inp->sctp_lport;
972163953Srrs	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
973163953Srrs		/* For the bound all case you get back 0 */
974163953Srrs		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
975163953Srrs			struct sctp_tcb *stcb;
976163953Srrs			struct sockaddr_in6 *sin_a6;
977163953Srrs			struct sctp_nets *net;
978163953Srrs			int fnd;
979163953Srrs
980163953Srrs			stcb = LIST_FIRST(&inp->sctp_asoc_list);
981163953Srrs			if (stcb == NULL) {
982295771Stuexen				SCTP_INP_RUNLOCK(inp);
983295929Stuexen				SCTP_FREE_SONAME(sin6);
984295771Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
985295771Stuexen				return (ENOENT);
986163953Srrs			}
987163953Srrs			fnd = 0;
988163953Srrs			sin_a6 = NULL;
989163953Srrs			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
990163953Srrs				sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
991164085Srrs				if (sin_a6 == NULL)
992164085Srrs					/* this will make coverity happy */
993164085Srrs					continue;
994164085Srrs
995163953Srrs				if (sin_a6->sin6_family == AF_INET6) {
996163953Srrs					fnd = 1;
997163953Srrs					break;
998163953Srrs				}
999163953Srrs			}
1000163953Srrs			if ((!fnd) || (sin_a6 == NULL)) {
1001163953Srrs				/* punt */
1002295771Stuexen				SCTP_INP_RUNLOCK(inp);
1003295929Stuexen				SCTP_FREE_SONAME(sin6);
1004295771Stuexen				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1005295771Stuexen				return (ENOENT);
1006163953Srrs			}
1007168299Srrs			vrf_id = inp->def_vrf_id;
1008168299Srrs			sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id);
1009167598Srrs			if (sctp_ifa) {
1010167598Srrs				sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
1011167598Srrs			}
1012163953Srrs		} else {
1013163953Srrs			/* For the bound all case you get back 0 */
1014163953Srrs			memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1015163953Srrs		}
1016163953Srrs	} else {
1017163953Srrs		/* Take the first IPv6 address in the list */
1018163953Srrs		struct sctp_laddr *laddr;
1019163953Srrs		int fnd = 0;
1020163953Srrs
1021163953Srrs		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1022167598Srrs			if (laddr->ifa->address.sa.sa_family == AF_INET6) {
1023163953Srrs				struct sockaddr_in6 *sin_a;
1024163953Srrs
1025271221Stuexen				sin_a = &laddr->ifa->address.sin6;
1026163953Srrs				sin6->sin6_addr = sin_a->sin6_addr;
1027163953Srrs				fnd = 1;
1028163953Srrs				break;
1029163953Srrs			}
1030163953Srrs		}
1031163953Srrs		if (!fnd) {
1032163953Srrs			SCTP_FREE_SONAME(sin6);
1033163953Srrs			SCTP_INP_RUNLOCK(inp);
1034171943Srrs			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1035228907Stuexen			return (ENOENT);
1036163953Srrs		}
1037163953Srrs	}
1038163953Srrs	SCTP_INP_RUNLOCK(inp);
1039163953Srrs	/* Scoping things for v6 */
1040164085Srrs	if ((error = sa6_recoverscope(sin6)) != 0) {
1041164085Srrs		SCTP_FREE_SONAME(sin6);
1042163953Srrs		return (error);
1043164085Srrs	}
1044163953Srrs	(*addr) = (struct sockaddr *)sin6;
1045163953Srrs	return (0);
1046163953Srrs}
1047163953Srrs
1048163953Srrsstatic int
1049163953Srrssctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1050163953Srrs{
1051231895Stuexen	struct sockaddr_in6 *sin6;
1052163953Srrs	int fnd;
1053163953Srrs	struct sockaddr_in6 *sin_a6;
1054163953Srrs	struct sctp_inpcb *inp;
1055163953Srrs	struct sctp_tcb *stcb;
1056163953Srrs	struct sctp_nets *net;
1057163953Srrs	int error;
1058163953Srrs
1059228907Stuexen	/* Do the malloc first in case it blocks. */
1060163953Srrs	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1061211944Stuexen	if (sin6 == NULL)
1062211944Stuexen		return (ENOMEM);
1063163953Srrs	sin6->sin6_family = AF_INET6;
1064163953Srrs	sin6->sin6_len = sizeof(*sin6);
1065163953Srrs
1066163953Srrs	inp = (struct sctp_inpcb *)so->so_pcb;
1067228907Stuexen	if ((inp == NULL) ||
1068228907Stuexen	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
1069228907Stuexen		/* UDP type and listeners will drop out here */
1070163953Srrs		SCTP_FREE_SONAME(sin6);
1071228907Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
1072228907Stuexen		return (ENOTCONN);
1073163953Srrs	}
1074163953Srrs	SCTP_INP_RLOCK(inp);
1075163953Srrs	stcb = LIST_FIRST(&inp->sctp_asoc_list);
1076169420Srrs	if (stcb) {
1077163953Srrs		SCTP_TCB_LOCK(stcb);
1078169420Srrs	}
1079163953Srrs	SCTP_INP_RUNLOCK(inp);
1080163953Srrs	if (stcb == NULL) {
1081163953Srrs		SCTP_FREE_SONAME(sin6);
1082171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1083228907Stuexen		return (ECONNRESET);
1084163953Srrs	}
1085163953Srrs	fnd = 0;
1086163953Srrs	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1087163953Srrs		sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1088163953Srrs		if (sin_a6->sin6_family == AF_INET6) {
1089163953Srrs			fnd = 1;
1090163953Srrs			sin6->sin6_port = stcb->rport;
1091163953Srrs			sin6->sin6_addr = sin_a6->sin6_addr;
1092163953Srrs			break;
1093163953Srrs		}
1094163953Srrs	}
1095163953Srrs	SCTP_TCB_UNLOCK(stcb);
1096163953Srrs	if (!fnd) {
1097163953Srrs		/* No IPv4 address */
1098163953Srrs		SCTP_FREE_SONAME(sin6);
1099171943Srrs		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1100228907Stuexen		return (ENOENT);
1101163953Srrs	}
1102275868Stuexen	if ((error = sa6_recoverscope(sin6)) != 0) {
1103275868Stuexen		SCTP_FREE_SONAME(sin6);
1104275868Stuexen		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, error);
1105163953Srrs		return (error);
1106275868Stuexen	}
1107163953Srrs	*addr = (struct sockaddr *)sin6;
1108163953Srrs	return (0);
1109163953Srrs}
1110163953Srrs
1111163953Srrsstatic int
1112163953Srrssctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1113163953Srrs{
1114163953Srrs	struct in6pcb *inp6 = sotoin6pcb(so);
1115166086Srrs	int error;
1116163953Srrs
1117171943Srrs	if (inp6 == NULL) {
1118171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1119228907Stuexen		return (EINVAL);
1120171943Srrs	}
1121163953Srrs	/* allow v6 addresses precedence */
1122163953Srrs	error = sctp6_getaddr(so, nam);
1123221249Stuexen#ifdef INET
1124163953Srrs	if (error) {
1125295771Stuexen		struct sockaddr_in6 *sin6;
1126295771Stuexen
1127163953Srrs		/* try v4 next if v6 failed */
1128163953Srrs		error = sctp_ingetaddr(so, nam);
1129163953Srrs		if (error) {
1130163953Srrs			return (error);
1131163953Srrs		}
1132295771Stuexen		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1133295771Stuexen		if (sin6 == NULL) {
1134295771Stuexen			SCTP_FREE_SONAME(*nam);
1135295771Stuexen			return (ENOMEM);
1136163953Srrs		}
1137295771Stuexen		in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
1138295771Stuexen		SCTP_FREE_SONAME(*nam);
1139295771Stuexen		*nam = (struct sockaddr *)sin6;
1140163953Srrs	}
1141221249Stuexen#endif
1142163953Srrs	return (error);
1143163953Srrs}
1144163953Srrs
1145163953Srrs
1146163953Srrsstatic int
1147163953Srrssctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1148163953Srrs{
1149163953Srrs	struct in6pcb *inp6 = sotoin6pcb(so);
1150166086Srrs	int error;
1151163953Srrs
1152171943Srrs	if (inp6 == NULL) {
1153171943Srrs		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1154228907Stuexen		return (EINVAL);
1155171943Srrs	}
1156163953Srrs	/* allow v6 addresses precedence */
1157163953Srrs	error = sctp6_peeraddr(so, nam);
1158221249Stuexen#ifdef INET
1159163953Srrs	if (error) {
1160295771Stuexen		struct sockaddr_in6 *sin6;
1161295771Stuexen
1162163953Srrs		/* try v4 next if v6 failed */
1163163953Srrs		error = sctp_peeraddr(so, nam);
1164163953Srrs		if (error) {
1165163953Srrs			return (error);
1166163953Srrs		}
1167295771Stuexen		SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1168295771Stuexen		if (sin6 == NULL) {
1169295771Stuexen			SCTP_FREE_SONAME(*nam);
1170295771Stuexen			return (ENOMEM);
1171163953Srrs		}
1172295771Stuexen		in6_sin_2_v4mapsin6((struct sockaddr_in *)*nam, sin6);
1173295771Stuexen		SCTP_FREE_SONAME(*nam);
1174295771Stuexen		*nam = (struct sockaddr *)sin6;
1175163953Srrs	}
1176221249Stuexen#endif
1177228907Stuexen	return (error);
1178163953Srrs}
1179163953Srrs
1180163953Srrsstruct pr_usrreqs sctp6_usrreqs = {
1181163953Srrs	.pru_abort = sctp6_abort,
1182163953Srrs	.pru_accept = sctp_accept,
1183163953Srrs	.pru_attach = sctp6_attach,
1184163953Srrs	.pru_bind = sctp6_bind,
1185163953Srrs	.pru_connect = sctp6_connect,
1186163953Srrs	.pru_control = in6_control,
1187163953Srrs	.pru_close = sctp6_close,
1188163953Srrs	.pru_detach = sctp6_close,
1189163953Srrs	.pru_sopoll = sopoll_generic,
1190178201Srrs	.pru_flush = sctp_flush,
1191163953Srrs	.pru_disconnect = sctp6_disconnect,
1192163953Srrs	.pru_listen = sctp_listen,
1193163953Srrs	.pru_peeraddr = sctp6_getpeeraddr,
1194163953Srrs	.pru_send = sctp6_send,
1195163953Srrs	.pru_shutdown = sctp_shutdown,
1196163953Srrs	.pru_sockaddr = sctp6_in6getaddr,
1197163953Srrs	.pru_sosend = sctp_sosend,
1198163953Srrs	.pru_soreceive = sctp_soreceive
1199163953Srrs};
1200238501Stuexen
1201238501Stuexen#endif
1202