sctp6_usrreq.c revision 169352
148905Srnordier/*-
248905Srnordier * Copyright (c) 2001-2007, Cisco Systems, Inc. All rights reserved.
348905Srnordier *
448905Srnordier * Redistribution and use in source and binary forms, with or without
548905Srnordier * modification, are permitted provided that the following conditions are met:
648905Srnordier *
748905Srnordier * a) Redistributions of source code must retain the above copyright notice,
848905Srnordier *   this list of conditions and the following disclaimer.
948905Srnordier *
1048905Srnordier * b) Redistributions in binary form must reproduce the above copyright
1148905Srnordier *    notice, this list of conditions and the following disclaimer in
1248905Srnordier *   the documentation and/or other materials provided with the distribution.
1348905Srnordier *
1448905Srnordier * c) Neither the name of Cisco Systems, Inc. nor the names of its
1548905Srnordier *    contributors may be used to endorse or promote products derived
1648905Srnordier *    from this software without specific prior written permission.
1748905Srnordier *
1848905Srnordier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1948905Srnordier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
2048905Srnordier * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2148905Srnordier * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2248905Srnordier * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2348905Srnordier * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2448905Srnordier * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2548905Srnordier * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2650479Speter * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2748905Srnordier * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2848905Srnordier * THE POSSIBILITY OF SUCH DAMAGE.
2948905Srnordier */
3048905Srnordier/*	$KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $	*/
3148905Srnordier#include <sys/cdefs.h>
3248905Srnordier__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 169352 2007-05-08 00:21:05Z rrs $");
3348905Srnordier
3448905Srnordier
3548905Srnordier#include <netinet/sctp_os.h>
3648905Srnordier#include <sys/proc.h>
3748905Srnordier#include <netinet/sctp_pcb.h>
3848905Srnordier#include <netinet/sctp_header.h>
3948905Srnordier#include <netinet/sctp_var.h>
4048905Srnordier#if defined(INET6)
4168313Srnordier#include <netinet6/sctp6_var.h>
4248905Srnordier#endif
4348905Srnordier#include <netinet/sctp_sysctl.h>
4448905Srnordier#include <netinet/sctp_output.h>
4548905Srnordier#include <netinet/sctp_uio.h>
4668313Srnordier#include <netinet/sctp_asconf.h>
4748905Srnordier#include <netinet/sctputil.h>
4848905Srnordier#include <netinet/sctp_indata.h>
4948905Srnordier#include <netinet/sctp_timer.h>
5048905Srnordier#include <netinet/sctp_auth.h>
5148905Srnordier#include <netinet/sctp_input.h>
5248905Srnordier#include <netinet/sctp_output.h>
5348905Srnordier
5448905Srnordier
5548905Srnordierextern struct protosw inetsw[];
5648905Srnordier
5748905Srnordier
5848905Srnordier
5948905Srnordier
6048905Srnordierint
6148905Srnordiersctp6_input(i_pak, offp, proto)
6248905Srnordier	struct mbuf **i_pak;
6348905Srnordier	int *offp;
6448905Srnordier	int proto;
6548905Srnordier{
6648905Srnordier	struct mbuf *m;
6748905Srnordier	struct ip6_hdr *ip6;
6848905Srnordier	struct sctphdr *sh;
6968313Srnordier	struct sctp_inpcb *in6p = NULL;
7068313Srnordier	struct sctp_nets *net;
7168313Srnordier	int refcount_up = 0;
7268313Srnordier	uint32_t check, calc_check;
7348905Srnordier	uint32_t vrf_id = 0, table_id = 0;
7448905Srnordier	struct inpcb *in6p_ip;
7568313Srnordier	struct sctp_chunkhdr *ch;
7668313Srnordier	int length, mlen, offset, iphlen;
7768313Srnordier	uint8_t ecn_bits;
7868313Srnordier	struct sctp_tcb *stcb = NULL;
7968313Srnordier	int off = *offp;
8068313Srnordier
8168313Srnordier	/* get the VRF and table id's */
8268313Srnordier	if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
8368313Srnordier		SCTP_RELEASE_PKT(*i_pak);
8468313Srnordier		return (-1);
8568313Srnordier	}
8668313Srnordier	if (SCTP_GET_PKT_TABLEID(*i_pak, table_id)) {
8768313Srnordier		SCTP_RELEASE_PKT(*i_pak);
8868313Srnordier		return (-1);
8968313Srnordier	}
9068313Srnordier	m = SCTP_HEADER_TO_CHAIN(*i_pak);
9168313Srnordier
9268313Srnordier	ip6 = mtod(m, struct ip6_hdr *);
9368313Srnordier	/* Ensure that (sctphdr + sctp_chunkhdr) in a row. */
9448905Srnordier	IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch));
9548905Srnordier	if (sh == NULL) {
9648905Srnordier		SCTP_STAT_INCR(sctps_hdrops);
9748905Srnordier		return IPPROTO_DONE;
9848905Srnordier	}
9948905Srnordier	ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
10048905Srnordier	iphlen = off;
10148905Srnordier	offset = iphlen + sizeof(*sh) + sizeof(*ch);
10248905Srnordier
10348905Srnordier#if defined(NFAITH) && NFAITH > 0
10468313Srnordier
10548905Srnordier	if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) {
10648905Srnordier		/* XXX send icmp6 host/port unreach? */
10748905Srnordier		goto bad;
10848905Srnordier	}
10948905Srnordier#endif				/* NFAITH defined and > 0 */
11048905Srnordier	SCTP_STAT_INCR(sctps_recvpackets);
11148905Srnordier	SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
11248905Srnordier#ifdef SCTP_DEBUG
11348905Srnordier	if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
11448905Srnordier		printf("V6 input gets a packet iphlen:%d pktlen:%d\n", iphlen,
11548905Srnordier		    SCTP_HEADER_LEN((*i_pak)));
11648905Srnordier	}
11748905Srnordier#endif
11848905Srnordier	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
11948905Srnordier		/* No multi-cast support in SCTP */
12048905Srnordier		goto bad;
12148905Srnordier	}
12248905Srnordier	/* destination port of 0 is illegal, based on RFC2960. */
12348905Srnordier	if (sh->dest_port == 0)
12448905Srnordier		goto bad;
12568313Srnordier	if ((sctp_no_csum_on_loopback == 0) ||
12648905Srnordier	    (!SCTP_IS_IT_LOOPBACK(m))) {
12748905Srnordier		/*
12848905Srnordier		 * we do NOT validate things from the loopback if the sysctl
12948905Srnordier		 * is set to 1.
13048905Srnordier		 */
13148905Srnordier		check = sh->checksum;	/* save incoming checksum */
13248905Srnordier		if ((check == 0) && (sctp_no_csum_on_loopback)) {
13348905Srnordier			/*
13448905Srnordier			 * special hook for where we got a local address
13548905Srnordier			 * somehow routed across a non IFT_LOOP type
13648905Srnordier			 * interface
13748905Srnordier			 */
138112047Sru			if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst))
13948905Srnordier				goto sctp_skip_csum;
14048905Srnordier		}
14148905Srnordier		sh->checksum = 0;	/* prepare for calc */
14248905Srnordier		calc_check = sctp_calculate_sum(m, &mlen, iphlen);
14348905Srnordier		if (calc_check != check) {
14448905Srnordier#ifdef SCTP_DEBUG
14548905Srnordier			if (sctp_debug_on & SCTP_DEBUG_INPUT1) {
14648905Srnordier				printf("Bad CSUM on SCTP packet calc_check:%x check:%x  m:%p mlen:%d iphlen:%d\n",
14748905Srnordier				    calc_check, check, m,
14848905Srnordier				    mlen, iphlen);
14948905Srnordier			}
15048905Srnordier#endif
15148905Srnordier			stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
15248905Srnordier			    sh, ch, &in6p, &net, vrf_id);
15348905Srnordier			/* in6p's ref-count increased && stcb locked */
15448905Srnordier			if ((in6p) && (stcb)) {
15548905Srnordier				sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
15662986Skris				sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, 2);
15768313Srnordier			} else if ((in6p != NULL) && (stcb == NULL)) {
15848905Srnordier				refcount_up = 1;
15948905Srnordier			}
16048905Srnordier			SCTP_STAT_INCR(sctps_badsum);
16148905Srnordier			SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors);
16248905Srnordier			goto bad;
16348905Srnordier		}
16448905Srnordier		sh->checksum = calc_check;
16548905Srnordier	}
16648905Srnordiersctp_skip_csum:
16748905Srnordier	net = NULL;
16848905Srnordier	/*
16948905Srnordier	 * Locate pcb and tcb for datagram sctp_findassociation_addr() wants
17048905Srnordier	 * IP/SCTP/first chunk header...
17148905Srnordier	 */
17248905Srnordier	stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch),
17348905Srnordier	    sh, ch, &in6p, &net, vrf_id);
17448905Srnordier	/* in6p's ref-count increased */
17548905Srnordier	if (in6p == NULL) {
17648905Srnordier		struct sctp_init_chunk *init_chk, chunk_buf;
17748905Srnordier
17848905Srnordier		SCTP_STAT_INCR(sctps_noport);
17948905Srnordier		if (ch->chunk_type == SCTP_INITIATION) {
18048905Srnordier			/*
18148905Srnordier			 * we do a trick here to get the INIT tag, dig in
18248905Srnordier			 * and get the tag from the INIT and put it in the
18348905Srnordier			 * common header.
18448905Srnordier			 */
18548905Srnordier			init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m,
18648905Srnordier			    iphlen + sizeof(*sh), sizeof(*init_chk),
18748905Srnordier			    (uint8_t *) & chunk_buf);
18848905Srnordier			sh->v_tag = init_chk->init.initiate_tag;
18948905Srnordier		}
19048905Srnordier		if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
19148905Srnordier			sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id,
19248905Srnordier			    table_id);
19348905Srnordier			goto bad;
19448905Srnordier		}
19548905Srnordier		if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) {
19648905Srnordier			goto bad;
19748905Srnordier		}
19848905Srnordier		if (ch->chunk_type != SCTP_ABORT_ASSOCIATION)
19948905Srnordier			sctp_send_abort(m, iphlen, sh, 0, NULL, vrf_id,
20048905Srnordier			    table_id);
20148905Srnordier		goto bad;
20248905Srnordier	} else if (stcb == NULL) {
20348905Srnordier		refcount_up = 1;
20448905Srnordier	}
20548905Srnordier	in6p_ip = (struct inpcb *)in6p;
20648905Srnordier#ifdef IPSEC
20748905Srnordier	/*
20848905Srnordier	 * Check AH/ESP integrity.
20948905Srnordier	 */
21048905Srnordier	if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) {
21148905Srnordier/* XXX */
21248905Srnordier		ipsec6stat.in_polvio++;
21348905Srnordier		goto bad;
21448905Srnordier	}
21548905Srnordier#endif				/* IPSEC */
21648905Srnordier
21748905Srnordier	/*
21848905Srnordier	 * CONTROL chunk processing
21948905Srnordier	 */
22048905Srnordier	offset -= sizeof(*ch);
22148905Srnordier	ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
22248905Srnordier
22348905Srnordier	/* Length now holds the total packet length payload + iphlen */
22448905Srnordier	length = ntohs(ip6->ip6_plen) + iphlen;
22548905Srnordier
22648905Srnordier	(void)sctp_common_input_processing(&m, iphlen, offset, length, sh, ch,
227	    in6p, stcb, net, ecn_bits, vrf_id, table_id);
228	/* inp's ref-count reduced && stcb unlocked */
229	/* XXX this stuff below gets moved to appropriate parts later... */
230	if (m)
231		sctp_m_freem(m);
232	if ((in6p) && refcount_up) {
233		/* reduce ref-count */
234		SCTP_INP_WLOCK(in6p);
235		SCTP_INP_DECR_REF(in6p);
236		SCTP_INP_WUNLOCK(in6p);
237	}
238	return IPPROTO_DONE;
239
240bad:
241	if (stcb)
242		SCTP_TCB_UNLOCK(stcb);
243
244	if ((in6p) && refcount_up) {
245		/* reduce ref-count */
246		SCTP_INP_WLOCK(in6p);
247		SCTP_INP_DECR_REF(in6p);
248		SCTP_INP_WUNLOCK(in6p);
249	}
250	if (m)
251		sctp_m_freem(m);
252	/* For BSD/MAC this does nothing */
253	SCTP_DETACH_HEADER_FROM_CHAIN(*i_pak);
254	SCTP_RELEASE_HEADER(*i_pak);
255	return IPPROTO_DONE;
256}
257
258
259static void
260sctp6_notify_mbuf(struct sctp_inpcb *inp,
261    struct icmp6_hdr *icmp6,
262    struct sctphdr *sh,
263    struct sctp_tcb *stcb,
264    struct sctp_nets *net)
265{
266	uint32_t nxtsz;
267
268	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
269	    (icmp6 == NULL) || (sh == NULL)) {
270		goto out;
271	}
272	/* First do we even look at it? */
273	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
274		goto out;
275
276	if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
277		/* not PACKET TO BIG */
278		goto out;
279	}
280	/*
281	 * ok we need to look closely. We could even get smarter and look at
282	 * anyone that we sent to in case we get a different ICMP that tells
283	 * us there is no way to reach a host, but for this impl, all we
284	 * care about is MTU discovery.
285	 */
286	nxtsz = ntohl(icmp6->icmp6_mtu);
287	/* Stop any PMTU timer */
288	sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1);
289
290	/* Adjust destination size limit */
291	if (net->mtu > nxtsz) {
292		net->mtu = nxtsz;
293	}
294	/* now what about the ep? */
295	if (stcb->asoc.smallest_mtu > nxtsz) {
296		struct sctp_tmit_chunk *chk;
297
298		/* Adjust that too */
299		stcb->asoc.smallest_mtu = nxtsz;
300		/* now off to subtract IP_DF flag if needed */
301
302		TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
303			if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
304				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
305			}
306		}
307		TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
308			if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
309				/*
310				 * For this guy we also mark for immediate
311				 * resend since we sent to big of chunk
312				 */
313				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
314				if (chk->sent != SCTP_DATAGRAM_RESEND)
315					stcb->asoc.sent_queue_retran_cnt++;
316				chk->sent = SCTP_DATAGRAM_RESEND;
317				chk->rec.data.doing_fast_retransmit = 0;
318
319				chk->sent = SCTP_DATAGRAM_RESEND;
320				/* Clear any time so NO RTT is being done */
321				chk->sent_rcv_time.tv_sec = 0;
322				chk->sent_rcv_time.tv_usec = 0;
323				stcb->asoc.total_flight -= chk->send_size;
324				net->flight_size -= chk->send_size;
325			}
326		}
327	}
328	sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
329out:
330	if (stcb)
331		SCTP_TCB_UNLOCK(stcb);
332}
333
334
335void
336sctp6_ctlinput(cmd, pktdst, d)
337	int cmd;
338	struct sockaddr *pktdst;
339	void *d;
340{
341	struct sctphdr sh;
342	struct ip6ctlparam *ip6cp = NULL;
343	uint32_t vrf_id;
344	int cm;
345
346	vrf_id = SCTP_DEFAULT_VRFID;
347
348	if (pktdst->sa_family != AF_INET6 ||
349	    pktdst->sa_len != sizeof(struct sockaddr_in6))
350		return;
351
352	if ((unsigned)cmd >= PRC_NCMDS)
353		return;
354	if (PRC_IS_REDIRECT(cmd)) {
355		d = NULL;
356	} else if (inet6ctlerrmap[cmd] == 0) {
357		return;
358	}
359	/* if the parameter is from icmp6, decode it. */
360	if (d != NULL) {
361		ip6cp = (struct ip6ctlparam *)d;
362	} else {
363		ip6cp = (struct ip6ctlparam *)NULL;
364	}
365
366	if (ip6cp) {
367		/*
368		 * XXX: We assume that when IPV6 is non NULL, M and OFF are
369		 * valid.
370		 */
371		/* check if we can safely examine src and dst ports */
372		struct sctp_inpcb *inp = NULL;
373		struct sctp_tcb *stcb = NULL;
374		struct sctp_nets *net = NULL;
375		struct sockaddr_in6 final;
376
377		if (ip6cp->ip6c_m == NULL)
378			return;
379
380		bzero(&sh, sizeof(sh));
381		bzero(&final, sizeof(final));
382		inp = NULL;
383		net = NULL;
384		m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
385		    (caddr_t)&sh);
386		ip6cp->ip6c_src->sin6_port = sh.src_port;
387		final.sin6_len = sizeof(final);
388		final.sin6_family = AF_INET6;
389		final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
390		final.sin6_port = sh.dest_port;
391		stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src,
392		    (struct sockaddr *)&final,
393		    &inp, &net, 1, vrf_id);
394		/* inp's ref-count increased && stcb locked */
395		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
396			if (cmd == PRC_MSGSIZE) {
397				sctp6_notify_mbuf(inp,
398				    ip6cp->ip6c_icmp6,
399				    &sh,
400				    stcb,
401				    net);
402				/* inp's ref-count reduced && stcb unlocked */
403			} else {
404				if (cmd == PRC_HOSTDEAD) {
405					cm = EHOSTUNREACH;
406				} else {
407					cm = inet6ctlerrmap[cmd];
408				}
409				sctp_notify(inp, cm, &sh,
410				    (struct sockaddr *)&final,
411				    stcb, net);
412				/* inp's ref-count reduced && stcb unlocked */
413			}
414		} else {
415			if (PRC_IS_REDIRECT(cmd) && inp) {
416				in6_rtchange((struct in6pcb *)inp,
417				    inet6ctlerrmap[cmd]);
418			}
419			if (inp) {
420				/* reduce inp's ref-count */
421				SCTP_INP_WLOCK(inp);
422				SCTP_INP_DECR_REF(inp);
423				SCTP_INP_WUNLOCK(inp);
424			}
425			if (stcb)
426				SCTP_TCB_UNLOCK(stcb);
427		}
428	}
429}
430
431/*
432 * this routine can probably be collasped into the one in sctp_userreq.c
433 * since they do the same thing and now we lookup with a sockaddr
434 */
435static int
436sctp6_getcred(SYSCTL_HANDLER_ARGS)
437{
438	struct xucred xuc;
439	struct sockaddr_in6 addrs[2];
440	struct sctp_inpcb *inp;
441	struct sctp_nets *net;
442	struct sctp_tcb *stcb;
443	int error;
444	uint32_t vrf_id;
445
446	vrf_id = SCTP_DEFAULT_VRFID;
447
448	/*
449	 * XXXRW: Other instances of getcred use SUSER_ALLOWJAIL, as socket
450	 * visibility is scoped using cr_canseesocket(), which it is not
451	 * here.
452	 */
453	error = priv_check_cred(req->td->td_ucred, PRIV_NETINET_RESERVEDPORT,
454	    0);
455	if (error)
456		return (error);
457
458	if (req->newlen != sizeof(addrs))
459		return (EINVAL);
460	if (req->oldlen != sizeof(struct ucred))
461		return (EINVAL);
462	error = SYSCTL_IN(req, addrs, sizeof(addrs));
463	if (error)
464		return (error);
465
466	stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
467	    sin6tosa(&addrs[1]),
468	    &inp, &net, 1, vrf_id);
469	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
470		if ((inp != NULL) && (stcb == NULL)) {
471			/* reduce ref-count */
472			SCTP_INP_WLOCK(inp);
473			SCTP_INP_DECR_REF(inp);
474			goto cred_can_cont;
475		}
476		error = ENOENT;
477		goto out;
478	}
479	SCTP_TCB_UNLOCK(stcb);
480	/*
481	 * We use the write lock here, only since in the error leg we need
482	 * it. If we used RLOCK, then we would have to
483	 * wlock/decr/unlock/rlock. Which in theory could create a hole.
484	 * Better to use higher wlock.
485	 */
486	SCTP_INP_WLOCK(inp);
487cred_can_cont:
488	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
489	if (error) {
490		SCTP_INP_WUNLOCK(inp);
491		goto out;
492	}
493	cru2x(inp->sctp_socket->so_cred, &xuc);
494	SCTP_INP_WUNLOCK(inp);
495	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
496out:
497	return (error);
498}
499
500SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
501    0, 0,
502    sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
503
504
505/* This is the same as the sctp_abort() could be made common */
506static void
507sctp6_abort(struct socket *so)
508{
509	struct sctp_inpcb *inp;
510	uint32_t flags;
511
512	inp = (struct sctp_inpcb *)so->so_pcb;
513	if (inp == 0)
514		return;
515sctp_must_try_again:
516	flags = inp->sctp_flags;
517#ifdef SCTP_LOG_CLOSING
518	sctp_log_closing(inp, NULL, 17);
519#endif
520	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
521	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
522#ifdef SCTP_LOG_CLOSING
523		sctp_log_closing(inp, NULL, 16);
524#endif
525		sctp_inpcb_free(inp, 1, 0);
526		SOCK_LOCK(so);
527		SCTP_SB_CLEAR(so->so_snd);
528		/*
529		 * same for the rcv ones, they are only here for the
530		 * accounting/select.
531		 */
532		SCTP_SB_CLEAR(so->so_rcv);
533		/* Now null out the reference, we are completely detached. */
534		so->so_pcb = NULL;
535		SOCK_UNLOCK(so);
536	} else {
537		flags = inp->sctp_flags;
538		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
539			goto sctp_must_try_again;
540		}
541	}
542	return;
543}
544
545static int
546sctp6_attach(struct socket *so, int proto, struct thread *p)
547{
548	struct in6pcb *inp6;
549	int error;
550	struct sctp_inpcb *inp;
551
552	inp = (struct sctp_inpcb *)so->so_pcb;
553	if (inp != NULL)
554		return EINVAL;
555
556	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
557		error = SCTP_SORESERVE(so, sctp_sendspace, sctp_recvspace);
558		if (error)
559			return error;
560	}
561	error = sctp_inpcb_alloc(so);
562	if (error)
563		return error;
564	inp = (struct sctp_inpcb *)so->so_pcb;
565	inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;	/* I'm v6! */
566	inp6 = (struct in6pcb *)inp;
567
568	inp6->inp_vflag |= INP_IPV6;
569	inp6->in6p_hops = -1;	/* use kernel default */
570	inp6->in6p_cksum = -1;	/* just to be sure */
571#ifdef INET
572	/*
573	 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
574	 * socket as well, because the socket may be bound to an IPv6
575	 * wildcard address, which may match an IPv4-mapped IPv6 address.
576	 */
577	inp6->inp_ip_ttl = ip_defttl;
578#endif
579	/*
580	 * Hmm what about the IPSEC stuff that is missing here but in
581	 * sctp_attach()?
582	 */
583	return 0;
584}
585
586static int
587sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
588{
589	struct sctp_inpcb *inp;
590	struct in6pcb *inp6;
591	int error;
592
593	inp = (struct sctp_inpcb *)so->so_pcb;
594	if (inp == 0)
595		return EINVAL;
596
597	inp6 = (struct in6pcb *)inp;
598	inp6->inp_vflag &= ~INP_IPV4;
599	inp6->inp_vflag |= INP_IPV6;
600	if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
601		if (addr->sa_family == AF_INET) {
602			/* binding v4 addr to v6 socket, so reset flags */
603			inp6->inp_vflag |= INP_IPV4;
604			inp6->inp_vflag &= ~INP_IPV6;
605		} else {
606			struct sockaddr_in6 *sin6_p;
607
608			sin6_p = (struct sockaddr_in6 *)addr;
609
610			if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
611				inp6->inp_vflag |= INP_IPV4;
612			} else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
613				struct sockaddr_in sin;
614
615				in6_sin6_2_sin(&sin, sin6_p);
616				inp6->inp_vflag |= INP_IPV4;
617				inp6->inp_vflag &= ~INP_IPV6;
618				error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, p);
619				return error;
620			}
621		}
622	} else if (addr != NULL) {
623		/* IPV6_V6ONLY socket */
624		if (addr->sa_family == AF_INET) {
625			/* can't bind v4 addr to v6 only socket! */
626			return EINVAL;
627		} else {
628			struct sockaddr_in6 *sin6_p;
629
630			sin6_p = (struct sockaddr_in6 *)addr;
631
632			if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr))
633				/* can't bind v4-mapped addrs either! */
634				/* NOTE: we don't support SIIT */
635				return EINVAL;
636		}
637	}
638	error = sctp_inpcb_bind(so, addr, p);
639	return error;
640}
641
642
643static void
644sctp6_close(struct socket *so)
645{
646	struct sctp_inpcb *inp;
647	uint32_t flags;
648
649	inp = (struct sctp_inpcb *)so->so_pcb;
650	if (inp == 0)
651		return;
652
653	/*
654	 * Inform all the lower layer assoc that we are done.
655	 */
656sctp_must_try_again:
657	flags = inp->sctp_flags;
658#ifdef SCTP_LOG_CLOSING
659	sctp_log_closing(inp, NULL, 17);
660#endif
661	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
662	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
663		if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
664		    (so->so_rcv.sb_cc > 0)) {
665#ifdef SCTP_LOG_CLOSING
666			sctp_log_closing(inp, NULL, 13);
667#endif
668			sctp_inpcb_free(inp, 1, 1);
669		} else {
670#ifdef SCTP_LOG_CLOSING
671			sctp_log_closing(inp, NULL, 14);
672#endif
673			sctp_inpcb_free(inp, 0, 1);
674		}
675		/*
676		 * The socket is now detached, no matter what the state of
677		 * the SCTP association.
678		 */
679		SOCK_LOCK(so);
680		SCTP_SB_CLEAR(so->so_snd);
681		/*
682		 * same for the rcv ones, they are only here for the
683		 * accounting/select.
684		 */
685		SCTP_SB_CLEAR(so->so_rcv);
686		/* Now null out the reference, we are completely detached. */
687		so->so_pcb = NULL;
688		SOCK_UNLOCK(so);
689	} else {
690		flags = inp->sctp_flags;
691		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
692			goto sctp_must_try_again;
693		}
694	}
695	return;
696
697}
698
699/* This could be made common with sctp_detach() since they are identical */
700
701static
702int
703sctp6_disconnect(struct socket *so)
704{
705	struct sctp_inpcb *inp;
706
707	inp = (struct sctp_inpcb *)so->so_pcb;
708	if (inp == NULL) {
709		return (ENOTCONN);
710	}
711	SCTP_INP_RLOCK(inp);
712	if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
713		if (SCTP_LIST_EMPTY(&inp->sctp_asoc_list)) {
714			/* No connection */
715			SCTP_INP_RUNLOCK(inp);
716			return (ENOTCONN);
717		} else {
718			int some_on_streamwheel = 0;
719			struct sctp_association *asoc;
720			struct sctp_tcb *stcb;
721
722			stcb = LIST_FIRST(&inp->sctp_asoc_list);
723			if (stcb == NULL) {
724				SCTP_INP_RUNLOCK(inp);
725				return (EINVAL);
726			}
727			SCTP_TCB_LOCK(stcb);
728			asoc = &stcb->asoc;
729			if (((so->so_options & SO_LINGER) &&
730			    (so->so_linger == 0)) ||
731			    (so->so_rcv.sb_cc > 0)) {
732				if (SCTP_GET_STATE(asoc) !=
733				    SCTP_STATE_COOKIE_WAIT) {
734					/* Left with Data unread */
735					struct mbuf *op_err;
736
737					op_err = sctp_generate_invmanparam(SCTP_CAUSE_USER_INITIATED_ABT);
738					sctp_send_abort_tcb(stcb, op_err);
739					SCTP_STAT_INCR_COUNTER32(sctps_aborted);
740				}
741				SCTP_INP_RUNLOCK(inp);
742				if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
743				    (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
744					SCTP_STAT_DECR_GAUGE32(sctps_currestab);
745				}
746				sctp_free_assoc(inp, stcb, SCTP_DONOT_SETSCOPE,
747				    SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_2);
748				/* No unlock tcb assoc is gone */
749				return (0);
750			}
751			if (!TAILQ_EMPTY(&asoc->out_wheel)) {
752				/* Check to see if some data queued */
753				struct sctp_stream_out *outs;
754
755				TAILQ_FOREACH(outs, &asoc->out_wheel,
756				    next_spoke) {
757					if (!TAILQ_EMPTY(&outs->outqueue)) {
758						some_on_streamwheel = 1;
759						break;
760					}
761				}
762			}
763			if (TAILQ_EMPTY(&asoc->send_queue) &&
764			    TAILQ_EMPTY(&asoc->sent_queue) &&
765			    (some_on_streamwheel == 0)) {
766				/* nothing queued to send, so I'm done... */
767				if ((SCTP_GET_STATE(asoc) !=
768				    SCTP_STATE_SHUTDOWN_SENT) &&
769				    (SCTP_GET_STATE(asoc) !=
770				    SCTP_STATE_SHUTDOWN_ACK_SENT)) {
771					/* only send SHUTDOWN the first time */
772					sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
773					sctp_chunk_output(stcb->sctp_ep, stcb, 1);
774					if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
775					    (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
776						SCTP_STAT_DECR_GAUGE32(sctps_currestab);
777					}
778					asoc->state = SCTP_STATE_SHUTDOWN_SENT;
779					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
780					    stcb->sctp_ep, stcb,
781					    asoc->primary_destination);
782					sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
783					    stcb->sctp_ep, stcb,
784					    asoc->primary_destination);
785				}
786			} else {
787				/*
788				 * we still got (or just got) data to send,
789				 * so set SHUTDOWN_PENDING
790				 */
791				/*
792				 * XXX sockets draft says that MSG_EOF
793				 * should be sent with no data.  currently,
794				 * we will allow user data to be sent first
795				 * and move to SHUTDOWN-PENDING
796				 */
797				asoc->state |= SCTP_STATE_SHUTDOWN_PENDING;
798			}
799			SCTP_TCB_UNLOCK(stcb);
800			SCTP_INP_RUNLOCK(inp);
801			return (0);
802		}
803	} else {
804		/* UDP model does not support this */
805		SCTP_INP_RUNLOCK(inp);
806		return EOPNOTSUPP;
807	}
808}
809
810
811int
812sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
813    struct mbuf *control, struct thread *p);
814
815
816static int
817sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
818    struct mbuf *control, struct thread *p)
819{
820	struct sctp_inpcb *inp;
821	struct inpcb *in_inp;
822	struct in6pcb *inp6;
823
824#ifdef INET
825	struct sockaddr_in6 *sin6;
826
827#endif				/* INET */
828	/* No SPL needed since sctp_output does this */
829
830	inp = (struct sctp_inpcb *)so->so_pcb;
831	if (inp == NULL) {
832		if (control) {
833			SCTP_RELEASE_PKT(control);
834			control = NULL;
835		}
836		SCTP_RELEASE_PKT(m);
837		return EINVAL;
838	}
839	in_inp = (struct inpcb *)inp;
840	inp6 = (struct in6pcb *)inp;
841	/*
842	 * For the TCP model we may get a NULL addr, if we are a connected
843	 * socket thats ok.
844	 */
845	if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
846	    (addr == NULL)) {
847		goto connected_type;
848	}
849	if (addr == NULL) {
850		SCTP_RELEASE_PKT(m);
851		if (control) {
852			SCTP_RELEASE_PKT(control);
853			control = NULL;
854		}
855		return (EDESTADDRREQ);
856	}
857#ifdef INET
858	sin6 = (struct sockaddr_in6 *)addr;
859	if (SCTP_IPV6_V6ONLY(inp6)) {
860		/*
861		 * if IPV6_V6ONLY flag, we discard datagrams destined to a
862		 * v4 addr or v4-mapped addr
863		 */
864		if (addr->sa_family == AF_INET) {
865			return EINVAL;
866		}
867		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
868			return EINVAL;
869		}
870	}
871	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
872		if (!ip6_v6only) {
873			struct sockaddr_in sin;
874
875			/* convert v4-mapped into v4 addr and send */
876			in6_sin6_2_sin(&sin, sin6);
877			return sctp_sendm(so, flags, m, (struct sockaddr *)&sin,
878			    control, p);
879		} else {
880			/* mapped addresses aren't enabled */
881			return EINVAL;
882		}
883	}
884#endif				/* INET */
885connected_type:
886	/* now what about control */
887	if (control) {
888		if (inp->control) {
889			printf("huh? control set?\n");
890			SCTP_RELEASE_PKT(inp->control);
891			inp->control = NULL;
892		}
893		inp->control = control;
894	}
895	/* Place the data */
896	if (inp->pkt) {
897		SCTP_BUF_NEXT(inp->pkt_last) = m;
898		inp->pkt_last = m;
899	} else {
900		inp->pkt_last = inp->pkt = m;
901	}
902	if (
903	/* FreeBSD and MacOSX uses a flag passed */
904	    ((flags & PRUS_MORETOCOME) == 0)
905	    ) {
906		/*
907		 * note with the current version this code will only be used
908		 * by OpenBSD, NetBSD and FreeBSD have methods for
909		 * re-defining sosend() to use sctp_sosend().  One can
910		 * optionaly switch back to this code (by changing back the
911		 * defininitions but this is not advisable.
912		 */
913		int ret;
914
915		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
916		inp->pkt = NULL;
917		inp->control = NULL;
918		return (ret);
919	} else {
920		return (0);
921	}
922}
923
924static int
925sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
926{
927	uint32_t vrf_id;
928	int error = 0;
929	struct sctp_inpcb *inp;
930	struct in6pcb *inp6;
931	struct sctp_tcb *stcb;
932
933#ifdef INET
934	struct sockaddr_in6 *sin6;
935	struct sockaddr_storage ss;
936
937#endif				/* INET */
938
939	inp6 = (struct in6pcb *)so->so_pcb;
940	inp = (struct sctp_inpcb *)so->so_pcb;
941	if (inp == 0) {
942		return (ECONNRESET);	/* I made the same as TCP since we are
943					 * not setup? */
944	}
945	vrf_id = inp->def_vrf_id;
946	SCTP_ASOC_CREATE_LOCK(inp);
947	SCTP_INP_RLOCK(inp);
948	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
949	    SCTP_PCB_FLAGS_UNBOUND) {
950		/* Bind a ephemeral port */
951		SCTP_INP_RUNLOCK(inp);
952		error = sctp6_bind(so, NULL, p);
953		if (error) {
954			SCTP_ASOC_CREATE_UNLOCK(inp);
955
956			return (error);
957		}
958		SCTP_INP_RLOCK(inp);
959	}
960	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
961	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
962		/* We are already connected AND the TCP model */
963		SCTP_INP_RUNLOCK(inp);
964		SCTP_ASOC_CREATE_UNLOCK(inp);
965		return (EADDRINUSE);
966	}
967#ifdef INET
968	sin6 = (struct sockaddr_in6 *)addr;
969	if (SCTP_IPV6_V6ONLY(inp6)) {
970		/*
971		 * if IPV6_V6ONLY flag, ignore connections destined to a v4
972		 * addr or v4-mapped addr
973		 */
974		if (addr->sa_family == AF_INET) {
975			SCTP_INP_RUNLOCK(inp);
976			SCTP_ASOC_CREATE_UNLOCK(inp);
977			return EINVAL;
978		}
979		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
980			SCTP_INP_RUNLOCK(inp);
981			SCTP_ASOC_CREATE_UNLOCK(inp);
982			return EINVAL;
983		}
984	}
985	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
986		if (!ip6_v6only) {
987			/* convert v4-mapped into v4 addr */
988			in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6);
989			addr = (struct sockaddr *)&ss;
990		} else {
991			/* mapped addresses aren't enabled */
992			SCTP_INP_RUNLOCK(inp);
993			SCTP_ASOC_CREATE_UNLOCK(inp);
994			return EINVAL;
995		}
996	} else
997#endif				/* INET */
998		addr = addr;	/* for true v6 address case */
999
1000	/* Now do we connect? */
1001	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1002		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1003		if (stcb)
1004			SCTP_TCB_UNLOCK(stcb);
1005		SCTP_INP_RUNLOCK(inp);
1006	} else {
1007		SCTP_INP_RUNLOCK(inp);
1008		SCTP_INP_WLOCK(inp);
1009		SCTP_INP_INCR_REF(inp);
1010		SCTP_INP_WUNLOCK(inp);
1011		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
1012		if (stcb == NULL) {
1013			SCTP_INP_WLOCK(inp);
1014			SCTP_INP_DECR_REF(inp);
1015			SCTP_INP_WUNLOCK(inp);
1016		}
1017	}
1018
1019	if (stcb != NULL) {
1020		/* Already have or am bring up an association */
1021		SCTP_ASOC_CREATE_UNLOCK(inp);
1022		SCTP_TCB_UNLOCK(stcb);
1023		return (EALREADY);
1024	}
1025	/* We are GOOD to go */
1026	stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id);
1027	SCTP_ASOC_CREATE_UNLOCK(inp);
1028	if (stcb == NULL) {
1029		/* Gak! no memory */
1030		return (error);
1031	}
1032	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1033		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1034		/* Set the connected flag so we can queue data */
1035		soisconnecting(so);
1036	}
1037	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
1038	SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1039
1040	/* initialize authentication parameters for the assoc */
1041	sctp_initialize_auth_params(inp, stcb);
1042
1043	sctp_send_initiate(inp, stcb);
1044	SCTP_TCB_UNLOCK(stcb);
1045	return error;
1046}
1047
1048static int
1049sctp6_getaddr(struct socket *so, struct sockaddr **addr)
1050{
1051	struct sockaddr_in6 *sin6;
1052	struct sctp_inpcb *inp;
1053	uint32_t vrf_id;
1054	struct sctp_ifa *sctp_ifa;
1055
1056	int error;
1057
1058	/*
1059	 * Do the malloc first in case it blocks.
1060	 */
1061	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1062	sin6->sin6_family = AF_INET6;
1063	sin6->sin6_len = sizeof(*sin6);
1064
1065	inp = (struct sctp_inpcb *)so->so_pcb;
1066	if (inp == NULL) {
1067		SCTP_FREE_SONAME(sin6);
1068		return ECONNRESET;
1069	}
1070	SCTP_INP_RLOCK(inp);
1071	sin6->sin6_port = inp->sctp_lport;
1072	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1073		/* For the bound all case you get back 0 */
1074		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1075			struct sctp_tcb *stcb;
1076			struct sockaddr_in6 *sin_a6;
1077			struct sctp_nets *net;
1078			int fnd;
1079
1080			stcb = LIST_FIRST(&inp->sctp_asoc_list);
1081			if (stcb == NULL) {
1082				goto notConn6;
1083			}
1084			fnd = 0;
1085			sin_a6 = NULL;
1086			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1087				sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1088				if (sin_a6 == NULL)
1089					/* this will make coverity happy */
1090					continue;
1091
1092				if (sin_a6->sin6_family == AF_INET6) {
1093					fnd = 1;
1094					break;
1095				}
1096			}
1097			if ((!fnd) || (sin_a6 == NULL)) {
1098				/* punt */
1099				goto notConn6;
1100			}
1101			vrf_id = inp->def_vrf_id;
1102			sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id);
1103			if (sctp_ifa) {
1104				sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
1105			}
1106		} else {
1107			/* For the bound all case you get back 0 */
1108	notConn6:
1109			memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1110		}
1111	} else {
1112		/* Take the first IPv6 address in the list */
1113		struct sctp_laddr *laddr;
1114		int fnd = 0;
1115
1116		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1117			if (laddr->ifa->address.sa.sa_family == AF_INET6) {
1118				struct sockaddr_in6 *sin_a;
1119
1120				sin_a = (struct sockaddr_in6 *)&laddr->ifa->address.sin6;
1121				sin6->sin6_addr = sin_a->sin6_addr;
1122				fnd = 1;
1123				break;
1124			}
1125		}
1126		if (!fnd) {
1127			SCTP_FREE_SONAME(sin6);
1128			SCTP_INP_RUNLOCK(inp);
1129			return ENOENT;
1130		}
1131	}
1132	SCTP_INP_RUNLOCK(inp);
1133	/* Scoping things for v6 */
1134	if ((error = sa6_recoverscope(sin6)) != 0) {
1135		SCTP_FREE_SONAME(sin6);
1136		return (error);
1137	}
1138	(*addr) = (struct sockaddr *)sin6;
1139	return (0);
1140}
1141
1142static int
1143sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1144{
1145	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr;
1146	int fnd;
1147	struct sockaddr_in6 *sin_a6;
1148	struct sctp_inpcb *inp;
1149	struct sctp_tcb *stcb;
1150	struct sctp_nets *net;
1151
1152	int error;
1153
1154	/*
1155	 * Do the malloc first in case it blocks.
1156	 */
1157	inp = (struct sctp_inpcb *)so->so_pcb;
1158	if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) {
1159		/* UDP type and listeners will drop out here */
1160		return (ENOTCONN);
1161	}
1162	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1163	sin6->sin6_family = AF_INET6;
1164	sin6->sin6_len = sizeof(*sin6);
1165
1166	/* We must recapture incase we blocked */
1167	inp = (struct sctp_inpcb *)so->so_pcb;
1168	if (inp == NULL) {
1169		SCTP_FREE_SONAME(sin6);
1170		return ECONNRESET;
1171	}
1172	SCTP_INP_RLOCK(inp);
1173	stcb = LIST_FIRST(&inp->sctp_asoc_list);
1174	if (stcb)
1175		SCTP_TCB_LOCK(stcb);
1176	SCTP_INP_RUNLOCK(inp);
1177	if (stcb == NULL) {
1178		SCTP_FREE_SONAME(sin6);
1179		return ECONNRESET;
1180	}
1181	fnd = 0;
1182	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1183		sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1184		if (sin_a6->sin6_family == AF_INET6) {
1185			fnd = 1;
1186			sin6->sin6_port = stcb->rport;
1187			sin6->sin6_addr = sin_a6->sin6_addr;
1188			break;
1189		}
1190	}
1191	SCTP_TCB_UNLOCK(stcb);
1192	if (!fnd) {
1193		/* No IPv4 address */
1194		SCTP_FREE_SONAME(sin6);
1195		return ENOENT;
1196	}
1197	if ((error = sa6_recoverscope(sin6)) != 0)
1198		return (error);
1199	*addr = (struct sockaddr *)sin6;
1200	return (0);
1201}
1202
1203static int
1204sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1205{
1206	struct sockaddr *addr;
1207	struct in6pcb *inp6 = sotoin6pcb(so);
1208	int error;
1209
1210	if (inp6 == NULL)
1211		return EINVAL;
1212
1213	/* allow v6 addresses precedence */
1214	error = sctp6_getaddr(so, nam);
1215	if (error) {
1216		/* try v4 next if v6 failed */
1217		error = sctp_ingetaddr(so, nam);
1218		if (error) {
1219			return (error);
1220		}
1221		addr = *nam;
1222		/* if I'm V6ONLY, convert it to v4-mapped */
1223		if (SCTP_IPV6_V6ONLY(inp6)) {
1224			struct sockaddr_in6 sin6;
1225
1226			in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1227			memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1228
1229		}
1230	}
1231	return (error);
1232}
1233
1234
1235static int
1236sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1237{
1238	struct sockaddr *addr = *nam;
1239	struct in6pcb *inp6 = sotoin6pcb(so);
1240	int error;
1241
1242	if (inp6 == NULL)
1243		return EINVAL;
1244
1245	/* allow v6 addresses precedence */
1246	error = sctp6_peeraddr(so, nam);
1247	if (error) {
1248		/* try v4 next if v6 failed */
1249		error = sctp_peeraddr(so, nam);
1250		if (error) {
1251			return (error);
1252		}
1253		/* if I'm V6ONLY, convert it to v4-mapped */
1254		if (SCTP_IPV6_V6ONLY(inp6)) {
1255			struct sockaddr_in6 sin6;
1256
1257			in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1258			memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1259		}
1260	}
1261	return error;
1262}
1263
1264struct pr_usrreqs sctp6_usrreqs = {
1265	.pru_abort = sctp6_abort,
1266	.pru_accept = sctp_accept,
1267	.pru_attach = sctp6_attach,
1268	.pru_bind = sctp6_bind,
1269	.pru_connect = sctp6_connect,
1270	.pru_control = in6_control,
1271	.pru_close = sctp6_close,
1272	.pru_detach = sctp6_close,
1273	.pru_sopoll = sopoll_generic,
1274	.pru_disconnect = sctp6_disconnect,
1275	.pru_listen = sctp_listen,
1276	.pru_peeraddr = sctp6_getpeeraddr,
1277	.pru_send = sctp6_send,
1278	.pru_shutdown = sctp_shutdown,
1279	.pru_sockaddr = sctp6_in6getaddr,
1280	.pru_sosend = sctp_sosend,
1281	.pru_soreceive = sctp_soreceive
1282};
1283