sctp6_usrreq.c revision 283708
1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4219820Sjeff * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5219820Sjeff *
6219820Sjeff * Redistribution and use in source and binary forms, with or without
7219820Sjeff * modification, are permitted provided that the following conditions are met:
8219820Sjeff *
9219820Sjeff * a) Redistributions of source code must retain the above copyright notice,
10219820Sjeff *    this list of conditions and the following disclaimer.
11219820Sjeff *
12219820Sjeff * b) Redistributions in binary form must reproduce the above copyright
13219820Sjeff *    notice, this list of conditions and the following disclaimer in
14219820Sjeff *    the documentation and/or other materials provided with the distribution.
15219820Sjeff *
16219820Sjeff * c) Neither the name of Cisco Systems, Inc. nor the names of its
17219820Sjeff *    contributors may be used to endorse or promote products derived
18219820Sjeff *    from this software without specific prior written permission.
19219820Sjeff *
20219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21219820Sjeff * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22219820Sjeff * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23219820Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24219820Sjeff * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25219820Sjeff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26219820Sjeff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27219820Sjeff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28219820Sjeff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29219820Sjeff * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30219820Sjeff * THE POSSIBILITY OF SUCH DAMAGE.
31219820Sjeff */
32219820Sjeff
33219820Sjeff#include <sys/cdefs.h>
34219820Sjeff__FBSDID("$FreeBSD: stable/10/sys/netinet6/sctp6_usrreq.c 283708 2015-05-29 12:03:02Z tuexen $");
35219820Sjeff
36219820Sjeff#include <netinet/sctp_os.h>
37219820Sjeff#ifdef INET6
38219820Sjeff#include <sys/proc.h>
39219820Sjeff#include <netinet/sctp_pcb.h>
40219820Sjeff#include <netinet/sctp_header.h>
41219820Sjeff#include <netinet/sctp_var.h>
42219820Sjeff#ifdef INET6
43219820Sjeff#include <netinet6/sctp6_var.h>
44219820Sjeff#endif
45219820Sjeff#include <netinet/sctp_sysctl.h>
46219820Sjeff#include <netinet/sctp_output.h>
47219820Sjeff#include <netinet/sctp_uio.h>
48219820Sjeff#include <netinet/sctp_asconf.h>
49219820Sjeff#include <netinet/sctputil.h>
50219820Sjeff#include <netinet/sctp_indata.h>
51219820Sjeff#include <netinet/sctp_timer.h>
52219820Sjeff#include <netinet/sctp_auth.h>
53219820Sjeff#include <netinet/sctp_input.h>
54219820Sjeff#include <netinet/sctp_output.h>
55219820Sjeff#include <netinet/sctp_bsd_addr.h>
56219820Sjeff#include <netinet/sctp_crc32.h>
57219820Sjeff#include <netinet/udp.h>
58219820Sjeff
59219820Sjeff#ifdef IPSEC
60219820Sjeff#include <netipsec/ipsec.h>
61219820Sjeff#ifdef INET6
62219820Sjeff#include <netipsec/ipsec6.h>
63219820Sjeff#endif				/* INET6 */
64219820Sjeff#endif				/* IPSEC */
65219820Sjeff
66219820Sjeffextern struct protosw inetsw[];
67219820Sjeff
68219820Sjeffint
69219820Sjeffsctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port)
70219820Sjeff{
71219820Sjeff	struct mbuf *m;
72219820Sjeff	int iphlen;
73219820Sjeff	uint32_t vrf_id;
74219820Sjeff	uint8_t ecn_bits;
75219820Sjeff	struct sockaddr_in6 src, dst;
76219820Sjeff	struct ip6_hdr *ip6;
77219820Sjeff	struct sctphdr *sh;
78219820Sjeff	struct sctp_chunkhdr *ch;
79219820Sjeff	int length, offset;
80219820Sjeff
81219820Sjeff#if !defined(SCTP_WITH_NO_CSUM)
82219820Sjeff	uint8_t compute_crc;
83219820Sjeff
84219820Sjeff#endif
85219820Sjeff	uint32_t mflowid;
86219820Sjeff	uint8_t mflowtype;
87219820Sjeff
88219820Sjeff	iphlen = *offp;
89219820Sjeff	if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
90219820Sjeff		SCTP_RELEASE_PKT(*i_pak);
91219820Sjeff		return (IPPROTO_DONE);
92219820Sjeff	}
93219820Sjeff	m = SCTP_HEADER_TO_CHAIN(*i_pak);
94219820Sjeff#ifdef SCTP_MBUF_LOGGING
95219820Sjeff	/* Log in any input mbufs */
96219820Sjeff	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
97219820Sjeff		sctp_log_mbc(m, SCTP_MBUF_INPUT);
98219820Sjeff	}
99219820Sjeff#endif
100219820Sjeff#ifdef SCTP_PACKET_LOGGING
101219820Sjeff	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
102219820Sjeff		sctp_packet_log(m);
103219820Sjeff	}
104219820Sjeff#endif
105219820Sjeff	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
106219820Sjeff	    "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n",
107219820Sjeff	    m->m_pkthdr.len,
108219820Sjeff	    if_name(m->m_pkthdr.rcvif),
109219820Sjeff	    (int)m->m_pkthdr.csum_flags, CSUM_BITS);
110219820Sjeff	mflowid = m->m_pkthdr.flowid;
111219820Sjeff	mflowtype = M_HASHTYPE_GET(m);
112219820Sjeff	SCTP_STAT_INCR(sctps_recvpackets);
113219820Sjeff	SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
114219820Sjeff	/* Get IP, SCTP, and first chunk header together in the first mbuf. */
115219820Sjeff	offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
116219820Sjeff	ip6 = mtod(m, struct ip6_hdr *);
117219820Sjeff	IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
118219820Sjeff	    (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
119219820Sjeff	if (sh == NULL) {
120219820Sjeff		SCTP_STAT_INCR(sctps_hdrops);
121219820Sjeff		return (IPPROTO_DONE);
122219820Sjeff	}
123219820Sjeff	ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
124219820Sjeff	offset -= sizeof(struct sctp_chunkhdr);
125219820Sjeff	memset(&src, 0, sizeof(struct sockaddr_in6));
126219820Sjeff	src.sin6_family = AF_INET6;
127219820Sjeff	src.sin6_len = sizeof(struct sockaddr_in6);
128219820Sjeff	src.sin6_port = sh->src_port;
129219820Sjeff	src.sin6_addr = ip6->ip6_src;
130219820Sjeff	if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
131219820Sjeff		goto out;
132219820Sjeff	}
133219820Sjeff	memset(&dst, 0, sizeof(struct sockaddr_in6));
134219820Sjeff	dst.sin6_family = AF_INET6;
135219820Sjeff	dst.sin6_len = sizeof(struct sockaddr_in6);
136219820Sjeff	dst.sin6_port = sh->dest_port;
137219820Sjeff	dst.sin6_addr = ip6->ip6_dst;
138219820Sjeff	if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
139219820Sjeff		goto out;
140219820Sjeff	}
141219820Sjeff	if (faithprefix_p != NULL && (*faithprefix_p) (&dst.sin6_addr)) {
142219820Sjeff		/* XXX send icmp6 host/port unreach? */
143219820Sjeff		goto out;
144219820Sjeff	}
145219820Sjeff	length = ntohs(ip6->ip6_plen) + iphlen;
146219820Sjeff	/* Validate mbuf chain length with IP payload length. */
147219820Sjeff	if (SCTP_HEADER_LEN(m) != length) {
148219820Sjeff		SCTPDBG(SCTP_DEBUG_INPUT1,
149219820Sjeff		    "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m));
150219820Sjeff		SCTP_STAT_INCR(sctps_hdrops);
151219820Sjeff		goto out;
152219820Sjeff	}
153219820Sjeff	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
154219820Sjeff		goto out;
155219820Sjeff	}
156219820Sjeff	ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
157219820Sjeff#if defined(SCTP_WITH_NO_CSUM)
158219820Sjeff	SCTP_STAT_INCR(sctps_recvnocrc);
159219820Sjeff#else
160219820Sjeff	if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
161219820Sjeff		SCTP_STAT_INCR(sctps_recvhwcrc);
162219820Sjeff		compute_crc = 0;
163219820Sjeff	} else {
164219820Sjeff		SCTP_STAT_INCR(sctps_recvswcrc);
165219820Sjeff		compute_crc = 1;
166219820Sjeff	}
167219820Sjeff#endif
168219820Sjeff	sctp_common_input_processing(&m, iphlen, offset, length,
169219820Sjeff	    (struct sockaddr *)&src,
170219820Sjeff	    (struct sockaddr *)&dst,
171219820Sjeff	    sh, ch,
172219820Sjeff#if !defined(SCTP_WITH_NO_CSUM)
173219820Sjeff	    compute_crc,
174219820Sjeff#endif
175219820Sjeff	    ecn_bits,
176219820Sjeff	    mflowtype, mflowid,
177219820Sjeff	    vrf_id, port);
178219820Sjeffout:
179219820Sjeff	if (m) {
180219820Sjeff		sctp_m_freem(m);
181219820Sjeff	}
182219820Sjeff	return (IPPROTO_DONE);
183219820Sjeff}
184219820Sjeff
185219820Sjeff
186219820Sjeffint
187219820Sjeffsctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED)
188219820Sjeff{
189219820Sjeff	return (sctp6_input_with_port(i_pak, offp, 0));
190219820Sjeff}
191219820Sjeff
192219820Sjeffstatic void
193219820Sjeffsctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6,
194219820Sjeff    struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net)
195219820Sjeff{
196219820Sjeff	uint32_t nxtsz;
197219820Sjeff
198219820Sjeff	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
199219820Sjeff	    (icmp6 == NULL) || (sh == NULL)) {
200219820Sjeff		goto out;
201219820Sjeff	}
202219820Sjeff	/* First do we even look at it? */
203219820Sjeff	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
204219820Sjeff		goto out;
205219820Sjeff
206219820Sjeff	if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
207219820Sjeff		/* not PACKET TO BIG */
208219820Sjeff		goto out;
209219820Sjeff	}
210219820Sjeff	/*
211219820Sjeff	 * ok we need to look closely. We could even get smarter and look at
212219820Sjeff	 * anyone that we sent to in case we get a different ICMP that tells
213219820Sjeff	 * us there is no way to reach a host, but for this impl, all we
214219820Sjeff	 * care about is MTU discovery.
215219820Sjeff	 */
216219820Sjeff	nxtsz = ntohl(icmp6->icmp6_mtu);
217219820Sjeff	/* Stop any PMTU timer */
218	sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1);
219
220	/* Adjust destination size limit */
221	if (net->mtu > nxtsz) {
222		net->mtu = nxtsz;
223		if (net->port) {
224			net->mtu -= sizeof(struct udphdr);
225		}
226	}
227	/* now what about the ep? */
228	if (stcb->asoc.smallest_mtu > nxtsz) {
229		struct sctp_tmit_chunk *chk;
230
231		/* Adjust that too */
232		stcb->asoc.smallest_mtu = nxtsz;
233		/* now off to subtract IP_DF flag if needed */
234
235		TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
236			if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
237				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
238			}
239		}
240		TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
241			if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
242				/*
243				 * For this guy we also mark for immediate
244				 * resend since we sent to big of chunk
245				 */
246				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
247				if (chk->sent != SCTP_DATAGRAM_RESEND)
248					stcb->asoc.sent_queue_retran_cnt++;
249				chk->sent = SCTP_DATAGRAM_RESEND;
250				chk->rec.data.doing_fast_retransmit = 0;
251
252				chk->sent = SCTP_DATAGRAM_RESEND;
253				/* Clear any time so NO RTT is being done */
254				chk->sent_rcv_time.tv_sec = 0;
255				chk->sent_rcv_time.tv_usec = 0;
256				stcb->asoc.total_flight -= chk->send_size;
257				net->flight_size -= chk->send_size;
258			}
259		}
260	}
261	sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
262out:
263	if (stcb) {
264		SCTP_TCB_UNLOCK(stcb);
265	}
266}
267
268
269void
270sctp6_notify(struct sctp_inpcb *inp,
271    struct icmp6_hdr *icmph,
272    struct sctphdr *sh,
273    struct sockaddr *to,
274    struct sctp_tcb *stcb,
275    struct sctp_nets *net)
276{
277#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
278	struct socket *so;
279
280#endif
281
282	/* protection */
283	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
284	    (sh == NULL) || (to == NULL)) {
285		if (stcb)
286			SCTP_TCB_UNLOCK(stcb);
287		return;
288	}
289	/* First job is to verify the vtag matches what I would send */
290	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
291		SCTP_TCB_UNLOCK(stcb);
292		return;
293	}
294	if (icmph->icmp6_type != ICMP_UNREACH) {
295		/* We only care about unreachable */
296		SCTP_TCB_UNLOCK(stcb);
297		return;
298	}
299	if ((icmph->icmp6_code == ICMP_UNREACH_NET) ||
300	    (icmph->icmp6_code == ICMP_UNREACH_HOST) ||
301	    (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) ||
302	    (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) ||
303	    (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) ||
304	    (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) ||
305	    (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) ||
306	    (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) {
307
308		/*
309		 * Hmm reachablity problems we must examine closely. If its
310		 * not reachable, we may have lost a network. Or if there is
311		 * NO protocol at the other end named SCTP. well we consider
312		 * it a OOTB abort.
313		 */
314		if (net->dest_state & SCTP_ADDR_REACHABLE) {
315			/* Ok that destination is NOT reachable */
316			net->dest_state &= ~SCTP_ADDR_REACHABLE;
317			net->dest_state &= ~SCTP_ADDR_PF;
318			sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
319			    stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED);
320		}
321		SCTP_TCB_UNLOCK(stcb);
322	} else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) ||
323	    (icmph->icmp6_code == ICMP_UNREACH_PORT)) {
324		/*
325		 * Here the peer is either playing tricks on us, including
326		 * an address that belongs to someone who does not support
327		 * SCTP OR was a userland implementation that shutdown and
328		 * now is dead. In either case treat it like a OOTB abort
329		 * with no TCB
330		 */
331		sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
332#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
333		so = SCTP_INP_SO(inp);
334		atomic_add_int(&stcb->asoc.refcnt, 1);
335		SCTP_TCB_UNLOCK(stcb);
336		SCTP_SOCKET_LOCK(so, 1);
337		SCTP_TCB_LOCK(stcb);
338		atomic_subtract_int(&stcb->asoc.refcnt, 1);
339#endif
340		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
341#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
342		SCTP_SOCKET_UNLOCK(so, 1);
343		/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */
344#endif
345		/* no need to unlock here, since the TCB is gone */
346	} else {
347		SCTP_TCB_UNLOCK(stcb);
348	}
349}
350
351
352
353void
354sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
355{
356	struct sctphdr sh;
357	struct ip6ctlparam *ip6cp = NULL;
358	uint32_t vrf_id;
359
360	vrf_id = SCTP_DEFAULT_VRFID;
361
362	if (pktdst->sa_family != AF_INET6 ||
363	    pktdst->sa_len != sizeof(struct sockaddr_in6))
364		return;
365
366	if ((unsigned)cmd >= PRC_NCMDS)
367		return;
368	if (PRC_IS_REDIRECT(cmd)) {
369		d = NULL;
370	} else if (inet6ctlerrmap[cmd] == 0) {
371		return;
372	}
373	/* if the parameter is from icmp6, decode it. */
374	if (d != NULL) {
375		ip6cp = (struct ip6ctlparam *)d;
376	} else {
377		ip6cp = (struct ip6ctlparam *)NULL;
378	}
379
380	if (ip6cp) {
381		/*
382		 * XXX: We assume that when IPV6 is non NULL, M and OFF are
383		 * valid.
384		 */
385		/* check if we can safely examine src and dst ports */
386		struct sctp_inpcb *inp = NULL;
387		struct sctp_tcb *stcb = NULL;
388		struct sctp_nets *net = NULL;
389		struct sockaddr_in6 final;
390
391		if (ip6cp->ip6c_m == NULL)
392			return;
393
394		bzero(&sh, sizeof(sh));
395		bzero(&final, sizeof(final));
396		inp = NULL;
397		net = NULL;
398		m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
399		    (caddr_t)&sh);
400		ip6cp->ip6c_src->sin6_port = sh.src_port;
401		final.sin6_len = sizeof(final);
402		final.sin6_family = AF_INET6;
403		final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
404		final.sin6_port = sh.dest_port;
405		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&final,
406		    (struct sockaddr *)ip6cp->ip6c_src,
407		    &inp, &net, 1, vrf_id);
408		/* inp's ref-count increased && stcb locked */
409		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
410			if (cmd == PRC_MSGSIZE) {
411				sctp6_notify_mbuf(inp,
412				    ip6cp->ip6c_icmp6,
413				    &sh,
414				    stcb,
415				    net);
416				/* inp's ref-count reduced && stcb unlocked */
417			} else {
418				sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh,
419				    (struct sockaddr *)&final,
420				    stcb, net);
421				/* inp's ref-count reduced && stcb unlocked */
422			}
423		} else {
424			if (PRC_IS_REDIRECT(cmd) && inp) {
425				in6_rtchange((struct in6pcb *)inp,
426				    inet6ctlerrmap[cmd]);
427			}
428			if (inp) {
429				/* reduce inp's ref-count */
430				SCTP_INP_WLOCK(inp);
431				SCTP_INP_DECR_REF(inp);
432				SCTP_INP_WUNLOCK(inp);
433			}
434			if (stcb)
435				SCTP_TCB_UNLOCK(stcb);
436		}
437	}
438}
439
440/*
441 * this routine can probably be collasped into the one in sctp_userreq.c
442 * since they do the same thing and now we lookup with a sockaddr
443 */
444static int
445sctp6_getcred(SYSCTL_HANDLER_ARGS)
446{
447	struct xucred xuc;
448	struct sockaddr_in6 addrs[2];
449	struct sctp_inpcb *inp;
450	struct sctp_nets *net;
451	struct sctp_tcb *stcb;
452	int error;
453	uint32_t vrf_id;
454
455	vrf_id = SCTP_DEFAULT_VRFID;
456
457	error = priv_check(req->td, PRIV_NETINET_GETCRED);
458	if (error)
459		return (error);
460
461	if (req->newlen != sizeof(addrs)) {
462		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
463		return (EINVAL);
464	}
465	if (req->oldlen != sizeof(struct ucred)) {
466		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
467		return (EINVAL);
468	}
469	error = SYSCTL_IN(req, addrs, sizeof(addrs));
470	if (error)
471		return (error);
472
473	stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]),
474	    sin6tosa(&addrs[0]),
475	    &inp, &net, 1, vrf_id);
476	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
477		if ((inp != NULL) && (stcb == NULL)) {
478			/* reduce ref-count */
479			SCTP_INP_WLOCK(inp);
480			SCTP_INP_DECR_REF(inp);
481			goto cred_can_cont;
482		}
483		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
484		error = ENOENT;
485		goto out;
486	}
487	SCTP_TCB_UNLOCK(stcb);
488	/*
489	 * We use the write lock here, only since in the error leg we need
490	 * it. If we used RLOCK, then we would have to
491	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
492	 * Better to use higher wlock.
493	 */
494	SCTP_INP_WLOCK(inp);
495cred_can_cont:
496	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
497	if (error) {
498		SCTP_INP_WUNLOCK(inp);
499		goto out;
500	}
501	cru2x(inp->sctp_socket->so_cred, &xuc);
502	SCTP_INP_WUNLOCK(inp);
503	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
504out:
505	return (error);
506}
507
508SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
509    0, 0,
510    sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
511
512
513/* This is the same as the sctp_abort() could be made common */
514static void
515sctp6_abort(struct socket *so)
516{
517	struct sctp_inpcb *inp;
518	uint32_t flags;
519
520	inp = (struct sctp_inpcb *)so->so_pcb;
521	if (inp == NULL) {
522		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
523		return;
524	}
525sctp_must_try_again:
526	flags = inp->sctp_flags;
527#ifdef SCTP_LOG_CLOSING
528	sctp_log_closing(inp, NULL, 17);
529#endif
530	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
531	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
532#ifdef SCTP_LOG_CLOSING
533		sctp_log_closing(inp, NULL, 16);
534#endif
535		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
536		    SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
537		SOCK_LOCK(so);
538		SCTP_SB_CLEAR(so->so_snd);
539		/*
540		 * same for the rcv ones, they are only here for the
541		 * accounting/select.
542		 */
543		SCTP_SB_CLEAR(so->so_rcv);
544		/* Now null out the reference, we are completely detached. */
545		so->so_pcb = NULL;
546		SOCK_UNLOCK(so);
547	} else {
548		flags = inp->sctp_flags;
549		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
550			goto sctp_must_try_again;
551		}
552	}
553	return;
554}
555
556static int
557sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
558{
559	struct in6pcb *inp6;
560	int error;
561	struct sctp_inpcb *inp;
562	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
563
564	inp = (struct sctp_inpcb *)so->so_pcb;
565	if (inp != NULL) {
566		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
567		return (EINVAL);
568	}
569	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
570		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
571		if (error)
572			return (error);
573	}
574	error = sctp_inpcb_alloc(so, vrf_id);
575	if (error)
576		return (error);
577	inp = (struct sctp_inpcb *)so->so_pcb;
578	SCTP_INP_WLOCK(inp);
579	inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;	/* I'm v6! */
580	inp6 = (struct in6pcb *)inp;
581
582	inp6->inp_vflag |= INP_IPV6;
583	inp6->in6p_hops = -1;	/* use kernel default */
584	inp6->in6p_cksum = -1;	/* just to be sure */
585#ifdef INET
586	/*
587	 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
588	 * socket as well, because the socket may be bound to an IPv6
589	 * wildcard address, which may match an IPv4-mapped IPv6 address.
590	 */
591	inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
592#endif
593	/*
594	 * Hmm what about the IPSEC stuff that is missing here but in
595	 * sctp_attach()?
596	 */
597	SCTP_INP_WUNLOCK(inp);
598	return (0);
599}
600
601static int
602sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
603{
604	struct sctp_inpcb *inp;
605	struct in6pcb *inp6;
606	int error;
607
608	inp = (struct sctp_inpcb *)so->so_pcb;
609	if (inp == NULL) {
610		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
611		return (EINVAL);
612	}
613	if (addr) {
614		switch (addr->sa_family) {
615#ifdef INET
616		case AF_INET:
617			if (addr->sa_len != sizeof(struct sockaddr_in)) {
618				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
619				return (EINVAL);
620			}
621			break;
622#endif
623#ifdef INET6
624		case AF_INET6:
625			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
626				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
627				return (EINVAL);
628			}
629			break;
630#endif
631		default:
632			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
633			return (EINVAL);
634		}
635	}
636	inp6 = (struct in6pcb *)inp;
637	inp6->inp_vflag &= ~INP_IPV4;
638	inp6->inp_vflag |= INP_IPV6;
639	if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
640		switch (addr->sa_family) {
641#ifdef INET
642		case AF_INET:
643			/* binding v4 addr to v6 socket, so reset flags */
644			inp6->inp_vflag |= INP_IPV4;
645			inp6->inp_vflag &= ~INP_IPV6;
646			break;
647#endif
648#ifdef INET6
649		case AF_INET6:
650			{
651				struct sockaddr_in6 *sin6_p;
652
653				sin6_p = (struct sockaddr_in6 *)addr;
654
655				if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
656					inp6->inp_vflag |= INP_IPV4;
657				}
658#ifdef INET
659				if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
660					struct sockaddr_in sin;
661
662					in6_sin6_2_sin(&sin, sin6_p);
663					inp6->inp_vflag |= INP_IPV4;
664					inp6->inp_vflag &= ~INP_IPV6;
665					error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
666					return (error);
667				}
668#endif
669				break;
670			}
671#endif
672		default:
673			break;
674		}
675	} else if (addr != NULL) {
676		struct sockaddr_in6 *sin6_p;
677
678		/* IPV6_V6ONLY socket */
679#ifdef INET
680		if (addr->sa_family == AF_INET) {
681			/* can't bind v4 addr to v6 only socket! */
682			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
683			return (EINVAL);
684		}
685#endif
686		sin6_p = (struct sockaddr_in6 *)addr;
687
688		if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
689			/* can't bind v4-mapped addrs either! */
690			/* NOTE: we don't support SIIT */
691			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
692			return (EINVAL);
693		}
694	}
695	error = sctp_inpcb_bind(so, addr, NULL, p);
696	return (error);
697}
698
699
700static void
701sctp6_close(struct socket *so)
702{
703	sctp_close(so);
704}
705
706/* This could be made common with sctp_detach() since they are identical */
707
708static
709int
710sctp6_disconnect(struct socket *so)
711{
712	return (sctp_disconnect(so));
713}
714
715
716int
717sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
718    struct mbuf *control, struct thread *p);
719
720
721static int
722sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
723    struct mbuf *control, struct thread *p)
724{
725	struct sctp_inpcb *inp;
726	struct in6pcb *inp6;
727
728#ifdef INET
729	struct sockaddr_in6 *sin6;
730
731#endif				/* INET */
732	/* No SPL needed since sctp_output does this */
733
734	inp = (struct sctp_inpcb *)so->so_pcb;
735	if (inp == NULL) {
736		if (control) {
737			SCTP_RELEASE_PKT(control);
738			control = NULL;
739		}
740		SCTP_RELEASE_PKT(m);
741		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
742		return (EINVAL);
743	}
744	inp6 = (struct in6pcb *)inp;
745	/*
746	 * For the TCP model we may get a NULL addr, if we are a connected
747	 * socket thats ok.
748	 */
749	if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
750	    (addr == NULL)) {
751		goto connected_type;
752	}
753	if (addr == NULL) {
754		SCTP_RELEASE_PKT(m);
755		if (control) {
756			SCTP_RELEASE_PKT(control);
757			control = NULL;
758		}
759		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
760		return (EDESTADDRREQ);
761	}
762#ifdef INET
763	sin6 = (struct sockaddr_in6 *)addr;
764	if (SCTP_IPV6_V6ONLY(inp6)) {
765		/*
766		 * if IPV6_V6ONLY flag, we discard datagrams destined to a
767		 * v4 addr or v4-mapped addr
768		 */
769		if (addr->sa_family == AF_INET) {
770			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
771			return (EINVAL);
772		}
773		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
774			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
775			return (EINVAL);
776		}
777	}
778	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
779		struct sockaddr_in sin;
780
781		/* convert v4-mapped into v4 addr and send */
782		in6_sin6_2_sin(&sin, sin6);
783		return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p));
784	}
785#endif				/* INET */
786connected_type:
787	/* now what about control */
788	if (control) {
789		if (inp->control) {
790			SCTP_PRINTF("huh? control set?\n");
791			SCTP_RELEASE_PKT(inp->control);
792			inp->control = NULL;
793		}
794		inp->control = control;
795	}
796	/* Place the data */
797	if (inp->pkt) {
798		SCTP_BUF_NEXT(inp->pkt_last) = m;
799		inp->pkt_last = m;
800	} else {
801		inp->pkt_last = inp->pkt = m;
802	}
803	if (
804	/* FreeBSD and MacOSX uses a flag passed */
805	    ((flags & PRUS_MORETOCOME) == 0)
806	    ) {
807		/*
808		 * note with the current version this code will only be used
809		 * by OpenBSD, NetBSD and FreeBSD have methods for
810		 * re-defining sosend() to use sctp_sosend().  One can
811		 * optionaly switch back to this code (by changing back the
812		 * defininitions but this is not advisable.
813		 */
814		int ret;
815
816		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
817		inp->pkt = NULL;
818		inp->control = NULL;
819		return (ret);
820	} else {
821		return (0);
822	}
823}
824
825static int
826sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
827{
828	uint32_t vrf_id;
829	int error = 0;
830	struct sctp_inpcb *inp;
831	struct sctp_tcb *stcb;
832
833#ifdef INET
834	struct in6pcb *inp6;
835	struct sockaddr_in6 *sin6;
836	union sctp_sockstore store;
837
838#endif
839
840#ifdef INET
841	inp6 = (struct in6pcb *)so->so_pcb;
842#endif
843	inp = (struct sctp_inpcb *)so->so_pcb;
844	if (inp == NULL) {
845		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
846		return (ECONNRESET);	/* I made the same as TCP since we are
847					 * not setup? */
848	}
849	if (addr == NULL) {
850		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
851		return (EINVAL);
852	}
853	switch (addr->sa_family) {
854#ifdef INET
855	case AF_INET:
856		if (addr->sa_len != sizeof(struct sockaddr_in)) {
857			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
858			return (EINVAL);
859		}
860		break;
861#endif
862#ifdef INET6
863	case AF_INET6:
864		if (addr->sa_len != sizeof(struct sockaddr_in6)) {
865			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
866			return (EINVAL);
867		}
868		break;
869#endif
870	default:
871		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
872		return (EINVAL);
873	}
874
875	vrf_id = inp->def_vrf_id;
876	SCTP_ASOC_CREATE_LOCK(inp);
877	SCTP_INP_RLOCK(inp);
878	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
879	    SCTP_PCB_FLAGS_UNBOUND) {
880		/* Bind a ephemeral port */
881		SCTP_INP_RUNLOCK(inp);
882		error = sctp6_bind(so, NULL, p);
883		if (error) {
884			SCTP_ASOC_CREATE_UNLOCK(inp);
885
886			return (error);
887		}
888		SCTP_INP_RLOCK(inp);
889	}
890	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
891	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
892		/* We are already connected AND the TCP model */
893		SCTP_INP_RUNLOCK(inp);
894		SCTP_ASOC_CREATE_UNLOCK(inp);
895		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
896		return (EADDRINUSE);
897	}
898#ifdef INET
899	sin6 = (struct sockaddr_in6 *)addr;
900	if (SCTP_IPV6_V6ONLY(inp6)) {
901		/*
902		 * if IPV6_V6ONLY flag, ignore connections destined to a v4
903		 * addr or v4-mapped addr
904		 */
905		if (addr->sa_family == AF_INET) {
906			SCTP_INP_RUNLOCK(inp);
907			SCTP_ASOC_CREATE_UNLOCK(inp);
908			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
909			return (EINVAL);
910		}
911		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
912			SCTP_INP_RUNLOCK(inp);
913			SCTP_ASOC_CREATE_UNLOCK(inp);
914			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
915			return (EINVAL);
916		}
917	}
918	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
919		/* convert v4-mapped into v4 addr */
920		in6_sin6_2_sin(&store.sin, sin6);
921		addr = &store.sa;
922	}
923#endif				/* INET */
924	/* Now do we connect? */
925	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
926		stcb = LIST_FIRST(&inp->sctp_asoc_list);
927		if (stcb) {
928			SCTP_TCB_UNLOCK(stcb);
929		}
930		SCTP_INP_RUNLOCK(inp);
931	} else {
932		SCTP_INP_RUNLOCK(inp);
933		SCTP_INP_WLOCK(inp);
934		SCTP_INP_INCR_REF(inp);
935		SCTP_INP_WUNLOCK(inp);
936		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
937		if (stcb == NULL) {
938			SCTP_INP_WLOCK(inp);
939			SCTP_INP_DECR_REF(inp);
940			SCTP_INP_WUNLOCK(inp);
941		}
942	}
943
944	if (stcb != NULL) {
945		/* Already have or am bring up an association */
946		SCTP_ASOC_CREATE_UNLOCK(inp);
947		SCTP_TCB_UNLOCK(stcb);
948		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
949		return (EALREADY);
950	}
951	/* We are GOOD to go */
952	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
953	SCTP_ASOC_CREATE_UNLOCK(inp);
954	if (stcb == NULL) {
955		/* Gak! no memory */
956		return (error);
957	}
958	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
959		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
960		/* Set the connected flag so we can queue data */
961		soisconnecting(so);
962	}
963	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
964	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
965
966	/* initialize authentication parameters for the assoc */
967	sctp_initialize_auth_params(inp, stcb);
968
969	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
970	SCTP_TCB_UNLOCK(stcb);
971	return (error);
972}
973
974static int
975sctp6_getaddr(struct socket *so, struct sockaddr **addr)
976{
977	struct sockaddr_in6 *sin6;
978	struct sctp_inpcb *inp;
979	uint32_t vrf_id;
980	struct sctp_ifa *sctp_ifa;
981
982	int error;
983
984	/*
985	 * Do the malloc first in case it blocks.
986	 */
987	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
988	if (sin6 == NULL)
989		return (ENOMEM);
990	sin6->sin6_family = AF_INET6;
991	sin6->sin6_len = sizeof(*sin6);
992
993	inp = (struct sctp_inpcb *)so->so_pcb;
994	if (inp == NULL) {
995		SCTP_FREE_SONAME(sin6);
996		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
997		return (ECONNRESET);
998	}
999	SCTP_INP_RLOCK(inp);
1000	sin6->sin6_port = inp->sctp_lport;
1001	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1002		/* For the bound all case you get back 0 */
1003		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1004			struct sctp_tcb *stcb;
1005			struct sockaddr_in6 *sin_a6;
1006			struct sctp_nets *net;
1007			int fnd;
1008
1009			stcb = LIST_FIRST(&inp->sctp_asoc_list);
1010			if (stcb == NULL) {
1011				goto notConn6;
1012			}
1013			fnd = 0;
1014			sin_a6 = NULL;
1015			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1016				sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1017				if (sin_a6 == NULL)
1018					/* this will make coverity happy */
1019					continue;
1020
1021				if (sin_a6->sin6_family == AF_INET6) {
1022					fnd = 1;
1023					break;
1024				}
1025			}
1026			if ((!fnd) || (sin_a6 == NULL)) {
1027				/* punt */
1028				goto notConn6;
1029			}
1030			vrf_id = inp->def_vrf_id;
1031			sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id);
1032			if (sctp_ifa) {
1033				sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
1034			}
1035		} else {
1036			/* For the bound all case you get back 0 */
1037	notConn6:
1038			memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1039		}
1040	} else {
1041		/* Take the first IPv6 address in the list */
1042		struct sctp_laddr *laddr;
1043		int fnd = 0;
1044
1045		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1046			if (laddr->ifa->address.sa.sa_family == AF_INET6) {
1047				struct sockaddr_in6 *sin_a;
1048
1049				sin_a = &laddr->ifa->address.sin6;
1050				sin6->sin6_addr = sin_a->sin6_addr;
1051				fnd = 1;
1052				break;
1053			}
1054		}
1055		if (!fnd) {
1056			SCTP_FREE_SONAME(sin6);
1057			SCTP_INP_RUNLOCK(inp);
1058			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1059			return (ENOENT);
1060		}
1061	}
1062	SCTP_INP_RUNLOCK(inp);
1063	/* Scoping things for v6 */
1064	if ((error = sa6_recoverscope(sin6)) != 0) {
1065		SCTP_FREE_SONAME(sin6);
1066		return (error);
1067	}
1068	(*addr) = (struct sockaddr *)sin6;
1069	return (0);
1070}
1071
1072static int
1073sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1074{
1075	struct sockaddr_in6 *sin6;
1076	int fnd;
1077	struct sockaddr_in6 *sin_a6;
1078	struct sctp_inpcb *inp;
1079	struct sctp_tcb *stcb;
1080	struct sctp_nets *net;
1081	int error;
1082
1083	/* Do the malloc first in case it blocks. */
1084	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1085	if (sin6 == NULL)
1086		return (ENOMEM);
1087	sin6->sin6_family = AF_INET6;
1088	sin6->sin6_len = sizeof(*sin6);
1089
1090	inp = (struct sctp_inpcb *)so->so_pcb;
1091	if ((inp == NULL) ||
1092	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
1093		/* UDP type and listeners will drop out here */
1094		SCTP_FREE_SONAME(sin6);
1095		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
1096		return (ENOTCONN);
1097	}
1098	SCTP_INP_RLOCK(inp);
1099	stcb = LIST_FIRST(&inp->sctp_asoc_list);
1100	if (stcb) {
1101		SCTP_TCB_LOCK(stcb);
1102	}
1103	SCTP_INP_RUNLOCK(inp);
1104	if (stcb == NULL) {
1105		SCTP_FREE_SONAME(sin6);
1106		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1107		return (ECONNRESET);
1108	}
1109	fnd = 0;
1110	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1111		sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1112		if (sin_a6->sin6_family == AF_INET6) {
1113			fnd = 1;
1114			sin6->sin6_port = stcb->rport;
1115			sin6->sin6_addr = sin_a6->sin6_addr;
1116			break;
1117		}
1118	}
1119	SCTP_TCB_UNLOCK(stcb);
1120	if (!fnd) {
1121		/* No IPv4 address */
1122		SCTP_FREE_SONAME(sin6);
1123		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1124		return (ENOENT);
1125	}
1126	if ((error = sa6_recoverscope(sin6)) != 0) {
1127		SCTP_FREE_SONAME(sin6);
1128		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, error);
1129		return (error);
1130	}
1131	*addr = (struct sockaddr *)sin6;
1132	return (0);
1133}
1134
1135static int
1136sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1137{
1138#ifdef INET
1139	struct sockaddr *addr;
1140
1141#endif
1142	struct in6pcb *inp6 = sotoin6pcb(so);
1143	int error;
1144
1145	if (inp6 == NULL) {
1146		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1147		return (EINVAL);
1148	}
1149	/* allow v6 addresses precedence */
1150	error = sctp6_getaddr(so, nam);
1151#ifdef INET
1152	if (error) {
1153		/* try v4 next if v6 failed */
1154		error = sctp_ingetaddr(so, nam);
1155		if (error) {
1156			return (error);
1157		}
1158		addr = *nam;
1159		/* if I'm V6ONLY, convert it to v4-mapped */
1160		if (SCTP_IPV6_V6ONLY(inp6)) {
1161			struct sockaddr_in6 sin6;
1162
1163			in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1164			memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1165		}
1166	}
1167#endif
1168	return (error);
1169}
1170
1171
1172static int
1173sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1174{
1175#ifdef INET
1176	struct sockaddr *addr;
1177
1178#endif
1179	struct in6pcb *inp6 = sotoin6pcb(so);
1180	int error;
1181
1182	if (inp6 == NULL) {
1183		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1184		return (EINVAL);
1185	}
1186	/* allow v6 addresses precedence */
1187	error = sctp6_peeraddr(so, nam);
1188#ifdef INET
1189	if (error) {
1190		/* try v4 next if v6 failed */
1191		error = sctp_peeraddr(so, nam);
1192		if (error) {
1193			return (error);
1194		}
1195		addr = *nam;
1196		/* if I'm V6ONLY, convert it to v4-mapped */
1197		if (SCTP_IPV6_V6ONLY(inp6)) {
1198			struct sockaddr_in6 sin6;
1199
1200			in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1201			memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1202		}
1203	}
1204#endif
1205	return (error);
1206}
1207
1208struct pr_usrreqs sctp6_usrreqs = {
1209	.pru_abort = sctp6_abort,
1210	.pru_accept = sctp_accept,
1211	.pru_attach = sctp6_attach,
1212	.pru_bind = sctp6_bind,
1213	.pru_connect = sctp6_connect,
1214	.pru_control = in6_control,
1215	.pru_close = sctp6_close,
1216	.pru_detach = sctp6_close,
1217	.pru_sopoll = sopoll_generic,
1218	.pru_flush = sctp_flush,
1219	.pru_disconnect = sctp6_disconnect,
1220	.pru_listen = sctp_listen,
1221	.pru_peeraddr = sctp6_getpeeraddr,
1222	.pru_send = sctp6_send,
1223	.pru_shutdown = sctp_shutdown,
1224	.pru_sockaddr = sctp6_in6getaddr,
1225	.pru_sosend = sctp_sosend,
1226	.pru_soreceive = sctp_soreceive
1227};
1228
1229#endif
1230