1/*-
2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * a) Redistributions of source code must retain the above copyright notice,
10 *    this list of conditions and the following disclaimer.
11 *
12 * b) Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in
14 *    the documentation and/or other materials provided with the distribution.
15 *
16 * c) Neither the name of Cisco Systems, Inc. nor the names of its
17 *    contributors may be used to endorse or promote products derived
18 *    from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#ifdef __FreeBSD__
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 271221 2014-09-07 09:06:26Z tuexen $");
36#endif
37
38#include <netinet/sctp_os.h>
39#ifdef INET6
40#ifdef __FreeBSD__
41#include <sys/proc.h>
42#endif
43#include <netinet/sctp_pcb.h>
44#include <netinet/sctp_header.h>
45#include <netinet/sctp_var.h>
46#ifdef INET6
47#include <netinet6/sctp6_var.h>
48#endif
49#include <netinet/sctp_sysctl.h>
50#include <netinet/sctp_output.h>
51#include <netinet/sctp_uio.h>
52#include <netinet/sctp_asconf.h>
53#include <netinet/sctputil.h>
54#include <netinet/sctp_indata.h>
55#include <netinet/sctp_timer.h>
56#include <netinet/sctp_auth.h>
57#include <netinet/sctp_input.h>
58#include <netinet/sctp_output.h>
59#include <netinet/sctp_bsd_addr.h>
60#include <netinet/sctp_crc32.h>
61#if !defined(__Userspace_os_Windows)
62#include <netinet/udp.h>
63#endif
64
65#if defined(__APPLE__)
66#define APPLE_FILE_NO 9
67#endif
68#ifdef IPSEC
69#include <netipsec/ipsec.h>
70#ifdef INET6
71#include <netipsec/ipsec6.h>
72#endif /* INET6 */
73#endif /* IPSEC */
74
75#if !defined(__Userspace__)
76extern struct protosw inetsw[];
77#endif
78#if defined(__Panda__) || defined(__Userspace__)
79int ip6_v6only=0;
80#endif
81#if defined(__Userspace__)
82void
83in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
84{
85#if defined(__Userspace_os_Windows)
86	uint32_t temp;
87#endif
88	bzero(sin, sizeof(*sin));
89#ifdef HAVE_SIN_LEN
90	sin->sin_len = sizeof(struct sockaddr_in);
91#endif
92	sin->sin_family = AF_INET;
93	sin->sin_port = sin6->sin6_port;
94#if defined(__Userspace_os_Windows)
95	temp = sin6->sin6_addr.s6_addr16[7];
96	temp = temp << 16;
97	temp = temp | sin6->sin6_addr.s6_addr16[6];
98	sin->sin_addr.s_addr = temp;
99	sctp_print_address((struct sockaddr*)sin);
100#else
101	sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3];
102#endif
103}
104
105void
106in6_sin6_2_sin_in_sock(struct sockaddr *nam)
107{
108	struct sockaddr_in *sin_p;
109	struct sockaddr_in6 sin6;
110
111	/* save original sockaddr_in6 addr and convert it to sockaddr_in  */
112	sin6 = *(struct sockaddr_in6 *)nam;
113	sin_p = (struct sockaddr_in *)nam;
114	in6_sin6_2_sin(sin_p, &sin6);
115}
116#endif
117
118#if !defined(__Userspace__)
119int
120#if defined(__APPLE__) || defined(__FreeBSD__)
121sctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port)
122#elif defined( __Panda__)
123sctp6_input(pakhandle_type *i_pak)
124#else
125sctp6_input(struct mbuf **i_pak, int *offp, int proto)
126#endif
127{
128	struct mbuf *m;
129	int iphlen;
130	uint32_t vrf_id;
131	uint8_t ecn_bits;
132	struct sockaddr_in6 src, dst;
133	struct ip6_hdr *ip6;
134	struct sctphdr *sh;
135	struct sctp_chunkhdr *ch;
136	int length, offset;
137#if !defined(SCTP_WITH_NO_CSUM)
138	uint8_t compute_crc;
139#endif
140#if defined(__FreeBSD__)
141	uint32_t mflowid;
142	uint8_t use_mflowid;
143#endif
144#if !(defined(__APPLE__) || defined (__FreeBSD__))
145	uint16_t port = 0;
146#endif
147
148#if defined(__Panda__)
149	/* This is Evil, but its the only way to make panda work right. */
150	iphlen = sizeof(struct ip6_hdr);
151#else
152	iphlen = *offp;
153#endif
154	if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) {
155		SCTP_RELEASE_PKT(*i_pak);
156		return (IPPROTO_DONE);
157	}
158	m = SCTP_HEADER_TO_CHAIN(*i_pak);
159#ifdef __Panda__
160	SCTP_DETACH_HEADER_FROM_CHAIN(*i_pak);
161	(void)SCTP_RELEASE_HEADER(*i_pak);
162#endif
163#ifdef SCTP_MBUF_LOGGING
164	/* Log in any input mbufs */
165	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) {
166		struct mbuf *mat;
167
168		for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
169			if (SCTP_BUF_IS_EXTENDED(mat)) {
170				sctp_log_mb(mat, SCTP_MBUF_INPUT);
171			}
172		}
173	}
174#endif
175#ifdef SCTP_PACKET_LOGGING
176	if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) {
177		sctp_packet_log(m);
178	}
179#endif
180#if defined(__FreeBSD__)
181#if __FreeBSD_version > 1000049
182	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
183	        "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n",
184	        m->m_pkthdr.len,
185	        if_name(m->m_pkthdr.rcvif),
186	        (int)m->m_pkthdr.csum_flags, CSUM_BITS);
187#elif __FreeBSD_version >= 800000
188	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
189	        "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
190	        m->m_pkthdr.len,
191	        if_name(m->m_pkthdr.rcvif),
192	        m->m_pkthdr.csum_flags);
193#else
194	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
195	        "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
196	        m->m_pkthdr.len,
197	        m->m_pkthdr.rcvif->if_xname,
198	        m->m_pkthdr.csum_flags);
199#endif
200#endif
201#if defined(__APPLE__)
202	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
203	        "sctp6_input(): Packet of length %d received on %s%d with csum_flags 0x%x.\n",
204	        m->m_pkthdr.len,
205	        m->m_pkthdr.rcvif->if_name,
206	        m->m_pkthdr.rcvif->if_unit,
207	        m->m_pkthdr.csum_flags);
208#endif
209#if defined(__Windows__)
210	SCTPDBG(SCTP_DEBUG_CRCOFFLOAD,
211	        "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n",
212	        m->m_pkthdr.len,
213	        m->m_pkthdr.rcvif->if_xname,
214	        m->m_pkthdr.csum_flags);
215#endif
216#if defined(__FreeBSD__)
217	if (m->m_flags & M_FLOWID) {
218		mflowid = m->m_pkthdr.flowid;
219		use_mflowid = 1;
220	} else {
221		mflowid = 0;
222		use_mflowid = 0;
223	}
224#endif
225	SCTP_STAT_INCR(sctps_recvpackets);
226	SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
227	/* Get IP, SCTP, and first chunk header together in the first mbuf. */
228	offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
229	ip6 = mtod(m, struct ip6_hdr *);
230	IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen,
231		       (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)));
232	if (sh == NULL) {
233		SCTP_STAT_INCR(sctps_hdrops);
234		return (IPPROTO_DONE);
235	}
236	ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
237	offset -= sizeof(struct sctp_chunkhdr);
238	memset(&src, 0, sizeof(struct sockaddr_in6));
239	src.sin6_family = AF_INET6;
240#ifdef HAVE_SIN6_LEN
241	src.sin6_len = sizeof(struct sockaddr_in6);
242#endif
243	src.sin6_port = sh->src_port;
244	src.sin6_addr = ip6->ip6_src;
245#if defined(__FreeBSD__)
246#if defined(__APPLE__)
247	/* XXX: This code should also be used on Apple */
248#endif
249	if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
250		goto out;
251	}
252#endif
253	memset(&dst, 0, sizeof(struct sockaddr_in6));
254	dst.sin6_family = AF_INET6;
255#ifdef HAVE_SIN6_LEN
256	dst.sin6_len = sizeof(struct sockaddr_in6);
257#endif
258	dst.sin6_port = sh->dest_port;
259	dst.sin6_addr = ip6->ip6_dst;
260#if defined(__FreeBSD__)
261#if defined(__APPLE__)
262	/* XXX: This code should also be used on Apple */
263#endif
264	if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) {
265		goto out;
266	}
267#endif
268#ifdef __FreeBSD__
269	if (faithprefix_p != NULL && (*faithprefix_p) (&dst.sin6_addr)) {
270		/* XXX send icmp6 host/port unreach? */
271		goto out;
272	}
273#endif
274#if defined(__APPLE__)
275#if defined(NFAITH) && 0 < NFAITH
276	if (faithprefix(&dst.sin6_addr)) {
277		goto out;
278	}
279#endif
280#endif
281	length = ntohs(ip6->ip6_plen) + iphlen;
282	/* Validate mbuf chain length with IP payload length. */
283	if (SCTP_HEADER_LEN(m) != length) {
284		SCTPDBG(SCTP_DEBUG_INPUT1,
285		        "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m));
286		SCTP_STAT_INCR(sctps_hdrops);
287		goto out;
288	}
289	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
290		goto out;
291	}
292	ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff);
293#if defined(SCTP_WITH_NO_CSUM)
294	SCTP_STAT_INCR(sctps_recvnocrc);
295#else
296#if defined(__FreeBSD__) && __FreeBSD_version >= 800000
297	if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) {
298		SCTP_STAT_INCR(sctps_recvhwcrc);
299		compute_crc = 0;
300	} else {
301#else
302	if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) &&
303	    (IN6_ARE_ADDR_EQUAL(&src.sin6_addr, &dst.sin6_addr))) {
304		SCTP_STAT_INCR(sctps_recvnocrc);
305		compute_crc = 0;
306	} else {
307#endif
308		SCTP_STAT_INCR(sctps_recvswcrc);
309		compute_crc = 1;
310	}
311#endif
312	sctp_common_input_processing(&m, iphlen, offset, length,
313	                             (struct sockaddr *)&src,
314	                             (struct sockaddr *)&dst,
315	                             sh, ch,
316#if !defined(SCTP_WITH_NO_CSUM)
317	                             compute_crc,
318#endif
319	                             ecn_bits,
320#if defined(__FreeBSD__)
321	                             use_mflowid, mflowid,
322#endif
323	                             vrf_id, port);
324 out:
325	if (m) {
326		sctp_m_freem(m);
327	}
328	return (IPPROTO_DONE);
329}
330
331#if defined(__APPLE__)
332int
333sctp6_input(struct mbuf **i_pak, int *offp)
334{
335	return (sctp6_input_with_port(i_pak, offp, 0));
336}
337#endif
338
339#if defined(__FreeBSD__)
340int
341sctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED)
342{
343	return (sctp6_input_with_port(i_pak, offp, 0));
344}
345#endif
346
347#if defined(__Panda__)
348void
349#else
350static void
351#endif
352sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6,
353		  struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net)
354{
355	uint32_t nxtsz;
356
357	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
358	    (icmp6 == NULL) || (sh == NULL)) {
359		goto out;
360	}
361	/* First do we even look at it? */
362	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag))
363		goto out;
364
365	if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) {
366		/* not PACKET TO BIG */
367		goto out;
368	}
369	/*
370	 * ok we need to look closely. We could even get smarter and look at
371	 * anyone that we sent to in case we get a different ICMP that tells
372	 * us there is no way to reach a host, but for this impl, all we
373	 * care about is MTU discovery.
374	 */
375	nxtsz = ntohl(icmp6->icmp6_mtu);
376	/* Stop any PMTU timer */
377	sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ+SCTP_LOC_1);
378
379	/* Adjust destination size limit */
380	if (net->mtu > nxtsz) {
381		net->mtu = nxtsz;
382		if (net->port) {
383			net->mtu -= sizeof(struct udphdr);
384		}
385	}
386	/* now what about the ep? */
387	if (stcb->asoc.smallest_mtu > nxtsz) {
388		struct sctp_tmit_chunk *chk;
389
390		/* Adjust that too */
391		stcb->asoc.smallest_mtu = nxtsz;
392		/* now off to subtract IP_DF flag if needed */
393
394		TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) {
395			if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
396				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
397			}
398		}
399		TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
400			if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) {
401				/*
402				 * For this guy we also mark for immediate
403				 * resend since we sent to big of chunk
404				 */
405				chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
406				if (chk->sent != SCTP_DATAGRAM_RESEND)
407					stcb->asoc.sent_queue_retran_cnt++;
408				chk->sent = SCTP_DATAGRAM_RESEND;
409				chk->rec.data.doing_fast_retransmit = 0;
410
411				chk->sent = SCTP_DATAGRAM_RESEND;
412				/* Clear any time so NO RTT is being done */
413				chk->sent_rcv_time.tv_sec = 0;
414				chk->sent_rcv_time.tv_usec = 0;
415				stcb->asoc.total_flight -= chk->send_size;
416				net->flight_size -= chk->send_size;
417			}
418		}
419	}
420	sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL);
421out:
422	if (stcb) {
423		SCTP_TCB_UNLOCK(stcb);
424	}
425}
426#endif
427
428
429void
430sctp6_notify(struct sctp_inpcb *inp,
431    struct icmp6_hdr *icmph,
432    struct sctphdr *sh,
433    struct sockaddr *to,
434    struct sctp_tcb *stcb,
435    struct sctp_nets *net)
436{
437#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
438	struct socket *so;
439
440#endif
441
442	/* protection */
443	if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
444	    (sh == NULL) || (to == NULL)) {
445		if (stcb)
446			SCTP_TCB_UNLOCK(stcb);
447		return;
448	}
449	/* First job is to verify the vtag matches what I would send */
450	if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
451		SCTP_TCB_UNLOCK(stcb);
452		return;
453	}
454	if (icmph->icmp6_type != ICMP_UNREACH) {
455		/* We only care about unreachable */
456		SCTP_TCB_UNLOCK(stcb);
457		return;
458	}
459	if ((icmph->icmp6_code == ICMP_UNREACH_NET) ||
460	    (icmph->icmp6_code == ICMP_UNREACH_HOST) ||
461	    (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) ||
462	    (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) ||
463	    (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) ||
464	    (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) ||
465	    (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) ||
466#if defined(__Panda__)
467            (icmph->icmp6_code == ICMP_UNREACH_ADMIN)) {
468#elif defined(__Userspace_os_NetBSD)
469            (icmph->icmp6_code == ICMP_UNREACH_ADMIN_PROHIBIT)) {
470#else
471            (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) {
472#endif
473
474		/*
475		 * Hmm reachablity problems we must examine closely. If its
476		 * not reachable, we may have lost a network. Or if there is
477		 * NO protocol at the other end named SCTP. well we consider
478		 * it a OOTB abort.
479		 */
480		if (net->dest_state & SCTP_ADDR_REACHABLE) {
481			/* Ok that destination is NOT reachable */
482			net->dest_state &= ~SCTP_ADDR_REACHABLE;
483			net->dest_state &= ~SCTP_ADDR_PF;
484			sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
485					stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED);
486		}
487		SCTP_TCB_UNLOCK(stcb);
488	} else  if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) ||
489		    (icmph->icmp6_code == ICMP_UNREACH_PORT)) {
490		/*
491		 * Here the peer is either playing tricks on us,
492		 * including an address that belongs to someone who
493		 * does not support SCTP OR was a userland
494		 * implementation that shutdown and now is dead. In
495		 * either case treat it like a OOTB abort with no
496		 * TCB
497		 */
498		sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED);
499#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
500		so = SCTP_INP_SO(inp);
501		atomic_add_int(&stcb->asoc.refcnt, 1);
502		SCTP_TCB_UNLOCK(stcb);
503		SCTP_SOCKET_LOCK(so, 1);
504		SCTP_TCB_LOCK(stcb);
505		atomic_subtract_int(&stcb->asoc.refcnt, 1);
506#endif
507		(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_2);
508#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
509		SCTP_SOCKET_UNLOCK(so, 1);
510		/* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/
511#endif
512		/* no need to unlock here, since the TCB is gone */
513	} else {
514		SCTP_TCB_UNLOCK(stcb);
515	}
516}
517
518
519
520#if !defined(__Panda__) && !defined(__Userspace__)
521void
522sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
523{
524	struct sctphdr sh;
525	struct ip6ctlparam *ip6cp = NULL;
526	uint32_t vrf_id;
527
528#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
529	vrf_id = SCTP_DEFAULT_VRFID;
530#endif
531
532#ifdef HAVE_SA_LEN
533	if (pktdst->sa_family != AF_INET6 ||
534	    pktdst->sa_len != sizeof(struct sockaddr_in6))
535#else
536	if (pktdst->sa_family != AF_INET6)
537#endif
538		return;
539
540	if ((unsigned)cmd >= PRC_NCMDS)
541		return;
542	if (PRC_IS_REDIRECT(cmd)) {
543		d = NULL;
544	} else if (inet6ctlerrmap[cmd] == 0) {
545		return;
546	}
547	/* if the parameter is from icmp6, decode it. */
548	if (d != NULL) {
549		ip6cp = (struct ip6ctlparam *)d;
550	} else {
551		ip6cp = (struct ip6ctlparam *)NULL;
552	}
553
554	if (ip6cp) {
555		/*
556		 * XXX: We assume that when IPV6 is non NULL, M and OFF are
557		 * valid.
558		 */
559		/* check if we can safely examine src and dst ports */
560		struct sctp_inpcb *inp = NULL;
561		struct sctp_tcb *stcb = NULL;
562		struct sctp_nets *net = NULL;
563		struct sockaddr_in6 final;
564
565		if (ip6cp->ip6c_m == NULL)
566			return;
567
568		bzero(&sh, sizeof(sh));
569		bzero(&final, sizeof(final));
570		inp = NULL;
571		net = NULL;
572		m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh),
573		    (caddr_t)&sh);
574		ip6cp->ip6c_src->sin6_port = sh.src_port;
575#ifdef HAVE_SIN6_LEN
576		final.sin6_len = sizeof(final);
577#endif
578		final.sin6_family = AF_INET6;
579#if defined(__FreeBSD__) && __FreeBSD_cc_version < 440000
580		final.sin6_addr = *ip6cp->ip6c_finaldst;
581#else
582		final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr;
583#endif				/* __FreeBSD_cc_version */
584		final.sin6_port = sh.dest_port;
585		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&final,
586		    (struct sockaddr *)ip6cp->ip6c_src,
587		    &inp, &net, 1, vrf_id);
588		/* inp's ref-count increased && stcb locked */
589		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
590			if (cmd == PRC_MSGSIZE) {
591				sctp6_notify_mbuf(inp,
592				    ip6cp->ip6c_icmp6,
593				    &sh,
594				    stcb,
595				    net);
596				/* inp's ref-count reduced && stcb unlocked */
597			} else {
598				sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh,
599				    (struct sockaddr *)&final,
600				    stcb, net);
601				/* inp's ref-count reduced && stcb unlocked */
602			}
603		} else {
604#if !defined(__Windows__)
605			if (PRC_IS_REDIRECT(cmd) && inp) {
606				in6_rtchange((struct in6pcb *)inp,
607				    inet6ctlerrmap[cmd]);
608			}
609#endif
610			if (inp) {
611				/* reduce inp's ref-count */
612				SCTP_INP_WLOCK(inp);
613				SCTP_INP_DECR_REF(inp);
614				SCTP_INP_WUNLOCK(inp);
615			}
616			if (stcb)
617				SCTP_TCB_UNLOCK(stcb);
618		}
619	}
620}
621#endif
622
623/*
624 * this routine can probably be collasped into the one in sctp_userreq.c
625 * since they do the same thing and now we lookup with a sockaddr
626 */
627#ifdef __FreeBSD__
628static int
629sctp6_getcred(SYSCTL_HANDLER_ARGS)
630{
631	struct xucred xuc;
632	struct sockaddr_in6 addrs[2];
633	struct sctp_inpcb *inp;
634	struct sctp_nets *net;
635	struct sctp_tcb *stcb;
636	int error;
637	uint32_t vrf_id;
638
639#if defined(__FreeBSD__) || defined(__APPLE__)
640	vrf_id = SCTP_DEFAULT_VRFID;
641#else
642	vrf_id = panda_get_vrf_from_call(); /* from connectx call? */
643#endif
644
645#if defined(__FreeBSD__) && __FreeBSD_version > 602000
646	error = priv_check(req->td, PRIV_NETINET_GETCRED);
647#elif defined(__FreeBSD__) && __FreeBSD_version >= 500000
648	error = suser(req->td);
649#else
650	error = suser(req->p);
651#endif
652	if (error)
653		return (error);
654
655	if (req->newlen != sizeof(addrs)) {
656		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
657		return (EINVAL);
658	}
659	if (req->oldlen != sizeof(struct ucred)) {
660		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
661		return (EINVAL);
662	}
663	error = SYSCTL_IN(req, addrs, sizeof(addrs));
664	if (error)
665		return (error);
666
667	stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]),
668	    sin6tosa(&addrs[0]),
669	    &inp, &net, 1, vrf_id);
670	if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
671		if ((inp != NULL) && (stcb == NULL)) {
672			/* reduce ref-count */
673			SCTP_INP_WLOCK(inp);
674			SCTP_INP_DECR_REF(inp);
675			goto cred_can_cont;
676		}
677		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
678		error = ENOENT;
679		goto out;
680	}
681	SCTP_TCB_UNLOCK(stcb);
682	/* We use the write lock here, only
683	 * since in the error leg we need it.
684	 * If we used RLOCK, then we would have
685	 * to wlock/decr/unlock/rlock. Which
686	 * in theory could create a hole. Better
687	 * to use higher wlock.
688	 */
689	SCTP_INP_WLOCK(inp);
690 cred_can_cont:
691	error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
692	if (error) {
693		SCTP_INP_WUNLOCK(inp);
694		goto out;
695	}
696	cru2x(inp->sctp_socket->so_cred, &xuc);
697	SCTP_INP_WUNLOCK(inp);
698	error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
699out:
700	return (error);
701}
702
703SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW,
704    0, 0,
705    sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection");
706
707#endif
708
709/* This is the same as the sctp_abort() could be made common */
710#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__)
711static void
712#elif defined(__Panda__) || defined(__Userspace__)
713int
714#else
715static int
716#endif
717sctp6_abort(struct socket *so)
718{
719	struct sctp_inpcb *inp;
720	uint32_t flags;
721
722	inp = (struct sctp_inpcb *)so->so_pcb;
723	if (inp == NULL) {
724		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
725#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__)
726		return;
727#else
728		return (EINVAL);
729#endif
730	}
731 sctp_must_try_again:
732	flags = inp->sctp_flags;
733#ifdef SCTP_LOG_CLOSING
734	sctp_log_closing(inp, NULL, 17);
735#endif
736	if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
737	    (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
738#ifdef SCTP_LOG_CLOSING
739		sctp_log_closing(inp, NULL, 16);
740#endif
741		sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
742				SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
743		SOCK_LOCK(so);
744		SCTP_SB_CLEAR(so->so_snd);
745		/* same for the rcv ones, they are only
746		 * here for the accounting/select.
747		 */
748		SCTP_SB_CLEAR(so->so_rcv);
749#if defined(__APPLE__)
750		so->so_usecount--;
751#else
752		/* Now null out the reference, we are completely detached. */
753		so->so_pcb = NULL;
754#endif
755		SOCK_UNLOCK(so);
756	} else {
757		flags = inp->sctp_flags;
758		if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
759			goto sctp_must_try_again;
760		}
761	}
762#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__)
763	return;
764#else
765	return (0);
766#endif
767}
768
769#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
770static int
771sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
772#elif defined(__Panda__) || defined(__Userspace__)
773int
774sctp6_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
775#elif defined(__Windows__)
776static int
777sctp6_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED)
778#else
779static int
780sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED)
781#endif
782{
783	struct in6pcb *inp6;
784	int error;
785	struct sctp_inpcb *inp;
786#if !defined(__Panda__) && !defined(__Userspace__)
787	uint32_t vrf_id = SCTP_DEFAULT_VRFID;
788#endif
789
790	inp = (struct sctp_inpcb *)so->so_pcb;
791	if (inp != NULL) {
792		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
793		return (EINVAL);
794	}
795
796	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
797		error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
798		if (error)
799			return (error);
800	}
801	error = sctp_inpcb_alloc(so, vrf_id);
802	if (error)
803		return (error);
804	inp = (struct sctp_inpcb *)so->so_pcb;
805	SCTP_INP_WLOCK(inp);
806	inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6;	/* I'm v6! */
807	inp6 = (struct in6pcb *)inp;
808
809#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
810	inp6->inp_vflag |= INP_IPV6;
811#else
812	inp->inp_vflag |= INP_IPV6;
813#endif
814#if !defined(__Panda__)
815	inp6->in6p_hops = -1;	/* use kernel default */
816	inp6->in6p_cksum = -1;	/* just to be sure */
817#endif
818#ifdef INET
819	/*
820	 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6
821	 * socket as well, because the socket may be bound to an IPv6
822	 * wildcard address, which may match an IPv4-mapped IPv6 address.
823	 */
824	inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
825#endif
826	/*
827	 * Hmm what about the IPSEC stuff that is missing here but in
828	 * sctp_attach()?
829	 */
830	SCTP_INP_WUNLOCK(inp);
831	return (0);
832}
833
834#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
835static int
836sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
837{
838#elif defined(__FreeBSD__) || defined(__APPLE__)
839static int
840sctp6_bind(struct socket *so, struct sockaddr *addr, struct proc *p)
841{
842#elif defined(__Panda__) || defined(__Userspace__)
843int
844sctp6_bind(struct socket *so, struct sockaddr *addr, void * p)
845{
846#elif defined(__Windows__)
847static int
848sctp6_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p)
849{
850#else
851static int
852sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
853{
854	struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL;
855
856#endif
857	struct sctp_inpcb *inp;
858	struct in6pcb *inp6;
859	int error;
860
861	inp = (struct sctp_inpcb *)so->so_pcb;
862	if (inp == NULL) {
863		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
864		return (EINVAL);
865	}
866
867#if !defined(__Windows__)
868	if (addr) {
869		switch (addr->sa_family) {
870#ifdef INET
871		case AF_INET:
872#ifdef HAVE_SA_LEN
873			if (addr->sa_len != sizeof(struct sockaddr_in)) {
874				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
875				return (EINVAL);
876			}
877#endif
878			break;
879#endif
880#ifdef INET6
881		case AF_INET6:
882#ifdef HAVE_SA_LEN
883			if (addr->sa_len != sizeof(struct sockaddr_in6)) {
884				SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
885				return (EINVAL);
886			}
887#endif
888			break;
889#endif
890		default:
891			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
892			return (EINVAL);
893		}
894	}
895#endif
896	inp6 = (struct in6pcb *)inp;
897#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
898	inp6->inp_vflag &= ~INP_IPV4;
899	inp6->inp_vflag |= INP_IPV6;
900#else
901	inp->inp_vflag &= ~INP_IPV4;
902	inp->inp_vflag |= INP_IPV6;
903#endif
904	if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) {
905		switch (addr->sa_family) {
906#ifdef INET
907		case AF_INET:
908			/* binding v4 addr to v6 socket, so reset flags */
909#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
910			inp6->inp_vflag |= INP_IPV4;
911			inp6->inp_vflag &= ~INP_IPV6;
912#else
913			inp->inp_vflag |= INP_IPV4;
914			inp->inp_vflag &= ~INP_IPV6;
915#endif
916			break;
917#endif
918#ifdef INET6
919		case AF_INET6:
920		{
921			struct sockaddr_in6 *sin6_p;
922
923			sin6_p = (struct sockaddr_in6 *)addr;
924
925			if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) {
926#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
927				inp6->inp_vflag |= INP_IPV4;
928#else
929				inp->inp_vflag |= INP_IPV4;
930#endif
931			}
932#ifdef INET
933			if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
934				struct sockaddr_in sin;
935
936				in6_sin6_2_sin(&sin, sin6_p);
937#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)
938				inp6->inp_vflag |= INP_IPV4;
939				inp6->inp_vflag &= ~INP_IPV6;
940#else
941				inp->inp_vflag |= INP_IPV4;
942				inp->inp_vflag &= ~INP_IPV6;
943#endif
944				error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p);
945				return (error);
946			}
947#endif
948			break;
949		}
950#endif
951		default:
952			break;
953		}
954	} else if (addr != NULL) {
955		struct sockaddr_in6 *sin6_p;
956
957		/* IPV6_V6ONLY socket */
958#ifdef INET
959		if (addr->sa_family == AF_INET) {
960			/* can't bind v4 addr to v6 only socket! */
961			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
962			return (EINVAL);
963		}
964#endif
965		sin6_p = (struct sockaddr_in6 *)addr;
966
967		if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
968			/* can't bind v4-mapped addrs either! */
969			/* NOTE: we don't support SIIT */
970			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
971			return (EINVAL);
972		}
973	}
974	error = sctp_inpcb_bind(so, addr, NULL, p);
975	return (error);
976}
977
978
979#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) || defined(__Userspace__)
980#if !defined(__Userspace__)
981static void
982#else
983void
984#endif
985sctp6_close(struct socket *so)
986{
987	sctp_close(so);
988}
989
990/* This could be made common with sctp_detach() since they are identical */
991#else
992
993#if !defined(__Panda__)
994static
995#endif
996int
997sctp6_detach(struct socket *so)
998{
999#if defined(__Userspace__)
1000	sctp_close(so);
1001	return (0);
1002#else
1003	return (sctp_detach(so));
1004#endif
1005}
1006
1007#endif
1008
1009#if !defined(__Panda__) && !defined(__Userspace__)
1010static
1011#endif
1012int
1013sctp6_disconnect(struct socket *so)
1014{
1015	return (sctp_disconnect(so));
1016}
1017
1018
1019int
1020#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
1021sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1022    struct mbuf *control, struct thread *p);
1023
1024#else
1025sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1026    struct mbuf *control, struct proc *p);
1027
1028#endif
1029
1030#if !defined(__Panda__) && !defined(__Windows__) && !defined(__Userspace__)
1031#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
1032static int
1033sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1034    struct mbuf *control, struct thread *p)
1035{
1036#elif defined(__FreeBSD__) || defined(__APPLE__)
1037static int
1038sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
1039    struct mbuf *control, struct proc *p)
1040{
1041#else
1042static int
1043sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam,
1044    struct mbuf *control, struct proc *p)
1045{
1046	struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL;
1047#endif
1048	struct sctp_inpcb *inp;
1049	struct in6pcb *inp6;
1050
1051#ifdef INET
1052	struct sockaddr_in6 *sin6;
1053#endif /* INET */
1054	/* No SPL needed since sctp_output does this */
1055
1056	inp = (struct sctp_inpcb *)so->so_pcb;
1057	if (inp == NULL) {
1058		if (control) {
1059			SCTP_RELEASE_PKT(control);
1060			control = NULL;
1061		}
1062		SCTP_RELEASE_PKT(m);
1063		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1064		return (EINVAL);
1065	}
1066	inp6 = (struct in6pcb *)inp;
1067	/*
1068	 * For the TCP model we may get a NULL addr, if we are a connected
1069	 * socket thats ok.
1070	 */
1071	if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) &&
1072	    (addr == NULL)) {
1073		goto connected_type;
1074	}
1075	if (addr == NULL) {
1076		SCTP_RELEASE_PKT(m);
1077		if (control) {
1078			SCTP_RELEASE_PKT(control);
1079			control = NULL;
1080		}
1081		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ);
1082		return (EDESTADDRREQ);
1083	}
1084#ifdef INET
1085	sin6 = (struct sockaddr_in6 *)addr;
1086	if (SCTP_IPV6_V6ONLY(inp6)) {
1087		/*
1088		 * if IPV6_V6ONLY flag, we discard datagrams destined to a
1089		 * v4 addr or v4-mapped addr
1090		 */
1091		if (addr->sa_family == AF_INET) {
1092			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1093			return (EINVAL);
1094		}
1095		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1096			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1097			return (EINVAL);
1098		}
1099	}
1100	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1101		struct sockaddr_in sin;
1102
1103		/* convert v4-mapped into v4 addr and send */
1104		in6_sin6_2_sin(&sin, sin6);
1105		return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p));
1106	}
1107#endif				/* INET */
1108connected_type:
1109	/* now what about control */
1110	if (control) {
1111		if (inp->control) {
1112			SCTP_PRINTF("huh? control set?\n");
1113			SCTP_RELEASE_PKT(inp->control);
1114			inp->control = NULL;
1115		}
1116		inp->control = control;
1117	}
1118	/* Place the data */
1119	if (inp->pkt) {
1120		SCTP_BUF_NEXT(inp->pkt_last) = m;
1121		inp->pkt_last = m;
1122	} else {
1123		inp->pkt_last = inp->pkt = m;
1124	}
1125	if (
1126#if defined(__FreeBSD__) || defined(__APPLE__)
1127	/* FreeBSD and MacOSX uses a flag passed */
1128	    ((flags & PRUS_MORETOCOME) == 0)
1129#else
1130	    1			/* Open BSD does not have any "more to come"
1131				 * indication */
1132#endif
1133	    ) {
1134		/*
1135		 * note with the current version this code will only be used
1136		 * by OpenBSD, NetBSD and FreeBSD have methods for
1137		 * re-defining sosend() to use sctp_sosend().  One can
1138		 * optionaly switch back to this code (by changing back the
1139		 * defininitions but this is not advisable.
1140		 */
1141		int ret;
1142
1143		ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
1144		inp->pkt = NULL;
1145		inp->control = NULL;
1146		return (ret);
1147	} else {
1148		return (0);
1149	}
1150}
1151#endif
1152
1153#if defined(__FreeBSD__) && __FreeBSD_version >= 500000
1154static int
1155sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
1156{
1157#elif defined(__FreeBSD__) || defined(__APPLE__)
1158static int
1159sctp6_connect(struct socket *so, struct sockaddr *addr, struct proc *p)
1160{
1161#elif defined(__Panda__)
1162int
1163sctp6_connect(struct socket *so, struct sockaddr *addr, void *p)
1164{
1165#elif defined(__Windows__)
1166static int
1167sctp6_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p)
1168{
1169#elif defined(__Userspace__)
1170int
1171sctp6_connect(struct socket *so, struct sockaddr *addr)
1172{
1173	void *p = NULL;
1174#else
1175static int
1176sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p)
1177{
1178	struct sockaddr *addr = mtod(nam, struct sockaddr *);
1179#endif
1180	uint32_t vrf_id;
1181	int error = 0;
1182	struct sctp_inpcb *inp;
1183	struct sctp_tcb *stcb;
1184#ifdef INET
1185	struct in6pcb *inp6;
1186	struct sockaddr_in6 *sin6;
1187	union sctp_sockstore store;
1188#endif
1189
1190#ifdef INET
1191	inp6 = (struct in6pcb *)so->so_pcb;
1192#endif
1193	inp = (struct sctp_inpcb *)so->so_pcb;
1194	if (inp == NULL) {
1195		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1196		return (ECONNRESET);	/* I made the same as TCP since we are
1197					 * not setup? */
1198	}
1199	if (addr == NULL) {
1200		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1201		return (EINVAL);
1202	}
1203#if !defined(__Windows__)
1204	switch (addr->sa_family) {
1205#ifdef INET
1206	case AF_INET:
1207#ifdef HAVE_SA_LEN
1208		if (addr->sa_len != sizeof(struct sockaddr_in)) {
1209			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1210			return (EINVAL);
1211		}
1212#endif
1213		break;
1214#endif
1215#ifdef INET6
1216	case AF_INET6:
1217#ifdef HAVE_SA_LEN
1218		if (addr->sa_len != sizeof(struct sockaddr_in6)) {
1219			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1220			return (EINVAL);
1221		}
1222#endif
1223		break;
1224#endif
1225	default:
1226		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1227		return (EINVAL);
1228	}
1229#endif
1230
1231	vrf_id = inp->def_vrf_id;
1232	SCTP_ASOC_CREATE_LOCK(inp);
1233	SCTP_INP_RLOCK(inp);
1234	if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) ==
1235	    SCTP_PCB_FLAGS_UNBOUND) {
1236		/* Bind a ephemeral port */
1237		SCTP_INP_RUNLOCK(inp);
1238		error = sctp6_bind(so, NULL, p);
1239		if (error) {
1240			SCTP_ASOC_CREATE_UNLOCK(inp);
1241
1242			return (error);
1243		}
1244		SCTP_INP_RLOCK(inp);
1245	}
1246	if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
1247	    (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
1248		/* We are already connected AND the TCP model */
1249		SCTP_INP_RUNLOCK(inp);
1250		SCTP_ASOC_CREATE_UNLOCK(inp);
1251		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE);
1252		return (EADDRINUSE);
1253	}
1254#ifdef INET
1255	sin6 = (struct sockaddr_in6 *)addr;
1256	if (SCTP_IPV6_V6ONLY(inp6)) {
1257		/*
1258		 * if IPV6_V6ONLY flag, ignore connections destined to a v4
1259		 * addr or v4-mapped addr
1260		 */
1261		if (addr->sa_family == AF_INET) {
1262			SCTP_INP_RUNLOCK(inp);
1263			SCTP_ASOC_CREATE_UNLOCK(inp);
1264			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1265			return (EINVAL);
1266		}
1267		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1268			SCTP_INP_RUNLOCK(inp);
1269			SCTP_ASOC_CREATE_UNLOCK(inp);
1270			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1271			return (EINVAL);
1272		}
1273	}
1274	if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
1275		/* convert v4-mapped into v4 addr */
1276		in6_sin6_2_sin(&store.sin, sin6);
1277		addr = &store.sa;
1278	}
1279#endif				/* INET */
1280	/* Now do we connect? */
1281	if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1282		stcb = LIST_FIRST(&inp->sctp_asoc_list);
1283		if (stcb) {
1284			SCTP_TCB_UNLOCK(stcb);
1285		}
1286		SCTP_INP_RUNLOCK(inp);
1287	} else {
1288		SCTP_INP_RUNLOCK(inp);
1289		SCTP_INP_WLOCK(inp);
1290		SCTP_INP_INCR_REF(inp);
1291		SCTP_INP_WUNLOCK(inp);
1292		stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
1293		if (stcb == NULL) {
1294			SCTP_INP_WLOCK(inp);
1295			SCTP_INP_DECR_REF(inp);
1296			SCTP_INP_WUNLOCK(inp);
1297		}
1298	}
1299
1300	if (stcb != NULL) {
1301		/* Already have or am bring up an association */
1302		SCTP_ASOC_CREATE_UNLOCK(inp);
1303		SCTP_TCB_UNLOCK(stcb);
1304		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY);
1305		return (EALREADY);
1306	}
1307	/* We are GOOD to go */
1308	stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p);
1309	SCTP_ASOC_CREATE_UNLOCK(inp);
1310	if (stcb == NULL) {
1311		/* Gak! no memory */
1312		return (error);
1313	}
1314	if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
1315		stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
1316		/* Set the connected flag so we can queue data */
1317		soisconnecting(so);
1318	}
1319	stcb->asoc.state = SCTP_STATE_COOKIE_WAIT;
1320	(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
1321
1322	/* initialize authentication parameters for the assoc */
1323	sctp_initialize_auth_params(inp, stcb);
1324
1325	sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
1326	SCTP_TCB_UNLOCK(stcb);
1327	return (error);
1328}
1329
1330static int
1331#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1332sctp6_getaddr(struct socket *so, struct sockaddr **addr)
1333{
1334	struct sockaddr_in6 *sin6;
1335#elif defined(__Panda__)
1336sctp6_getaddr(struct socket *so, struct sockaddr *addr)
1337{
1338	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
1339#else
1340sctp6_getaddr(struct socket *so, struct mbuf *nam)
1341{
1342	struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
1343#endif
1344	struct sctp_inpcb *inp;
1345	uint32_t vrf_id;
1346	struct sctp_ifa *sctp_ifa;
1347
1348#ifdef SCTP_KAME
1349	int error;
1350#endif /* SCTP_KAME */
1351
1352	/*
1353	 * Do the malloc first in case it blocks.
1354	 */
1355#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1356	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6));
1357	if (sin6 == NULL)
1358		return (ENOMEM);
1359#elif defined(__Panda__)
1360	bzero(sin6, sizeof(*sin6));
1361#else
1362	SCTP_BUF_LEN(nam) = sizeof(*sin6);
1363	bzero(sin6, sizeof(*sin6));
1364#endif
1365	sin6->sin6_family = AF_INET6;
1366#ifdef HAVE_SIN6_LEN
1367	sin6->sin6_len = sizeof(*sin6);
1368#endif
1369
1370	inp = (struct sctp_inpcb *)so->so_pcb;
1371	if (inp == NULL) {
1372#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1373		SCTP_FREE_SONAME(sin6);
1374#endif
1375		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1376		return (ECONNRESET);
1377	}
1378	SCTP_INP_RLOCK(inp);
1379	sin6->sin6_port = inp->sctp_lport;
1380	if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
1381		/* For the bound all case you get back 0 */
1382		if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
1383			struct sctp_tcb *stcb;
1384			struct sockaddr_in6 *sin_a6;
1385			struct sctp_nets *net;
1386			int fnd;
1387			stcb = LIST_FIRST(&inp->sctp_asoc_list);
1388			if (stcb == NULL) {
1389				goto notConn6;
1390			}
1391			fnd = 0;
1392			sin_a6 = NULL;
1393			TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1394				sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1395				if (sin_a6 == NULL)
1396					/* this will make coverity happy */
1397					continue;
1398
1399				if (sin_a6->sin6_family == AF_INET6) {
1400					fnd = 1;
1401					break;
1402				}
1403			}
1404			if ((!fnd) || (sin_a6 == NULL)) {
1405				/* punt */
1406				goto notConn6;
1407			}
1408			vrf_id = inp->def_vrf_id;
1409			sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *)&net->ro, net, 0, vrf_id);
1410			if (sctp_ifa) {
1411				sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr;
1412			}
1413		} else {
1414			/* For the bound all case you get back 0 */
1415	notConn6:
1416			memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
1417		}
1418	} else {
1419		/* Take the first IPv6 address in the list */
1420		struct sctp_laddr *laddr;
1421		int fnd = 0;
1422
1423		LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
1424			if (laddr->ifa->address.sa.sa_family == AF_INET6) {
1425				struct sockaddr_in6 *sin_a;
1426
1427				sin_a = &laddr->ifa->address.sin6;
1428				sin6->sin6_addr = sin_a->sin6_addr;
1429				fnd = 1;
1430				break;
1431			}
1432		}
1433		if (!fnd) {
1434#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1435			SCTP_FREE_SONAME(sin6);
1436#endif
1437			SCTP_INP_RUNLOCK(inp);
1438			SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1439			return (ENOENT);
1440		}
1441	}
1442	SCTP_INP_RUNLOCK(inp);
1443	/* Scoping things for v6 */
1444#ifdef SCTP_EMBEDDED_V6_SCOPE
1445#ifdef SCTP_KAME
1446	if ((error = sa6_recoverscope(sin6)) != 0) {
1447		SCTP_FREE_SONAME(sin6);
1448		return (error);
1449	}
1450#else
1451	if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
1452		/* skip ifp check below */
1453		in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
1454	else
1455		sin6->sin6_scope_id = 0;	/* XXX */
1456#endif /* SCTP_KAME */
1457#endif /* SCTP_EMBEDDED_V6_SCOPE */
1458#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1459	(*addr) = (struct sockaddr *)sin6;
1460#endif
1461	return (0);
1462}
1463
1464static int
1465#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1466sctp6_peeraddr(struct socket *so, struct sockaddr **addr)
1467{
1468	struct sockaddr_in6 *sin6;
1469#elif defined(__Panda__)
1470sctp6_peeraddr(struct socket *so, struct sockaddr *addr)
1471{
1472	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
1473#else
1474sctp6_peeraddr(struct socket *so, struct mbuf *nam)
1475{
1476	struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
1477#endif
1478	int fnd;
1479	struct sockaddr_in6 *sin_a6;
1480	struct sctp_inpcb *inp;
1481	struct sctp_tcb *stcb;
1482	struct sctp_nets *net;
1483#ifdef SCTP_KAME
1484	int error;
1485#endif
1486
1487	/* Do the malloc first in case it blocks. */
1488#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1489	SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
1490	if (sin6 == NULL)
1491		return (ENOMEM);
1492#elif defined(__Panda__)
1493	memset(sin6, 0, sizeof(*sin6));
1494#else
1495	SCTP_BUF_LEN(nam) = sizeof(*sin6);
1496	memset(sin6, 0, sizeof(*sin6));
1497#endif
1498	sin6->sin6_family = AF_INET6;
1499#ifdef HAVE_SIN6_LEN
1500	sin6->sin6_len = sizeof(*sin6);
1501#endif
1502
1503	inp = (struct sctp_inpcb *)so->so_pcb;
1504	if ((inp == NULL) ||
1505	    ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
1506		/* UDP type and listeners will drop out here */
1507#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1508		SCTP_FREE_SONAME(sin6);
1509#endif
1510		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN);
1511		return (ENOTCONN);
1512	}
1513	SCTP_INP_RLOCK(inp);
1514	stcb = LIST_FIRST(&inp->sctp_asoc_list);
1515	if (stcb) {
1516		SCTP_TCB_LOCK(stcb);
1517	}
1518	SCTP_INP_RUNLOCK(inp);
1519	if (stcb == NULL) {
1520#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1521		SCTP_FREE_SONAME(sin6);
1522#endif
1523		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET);
1524		return (ECONNRESET);
1525	}
1526	fnd = 0;
1527	TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
1528		sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr;
1529		if (sin_a6->sin6_family == AF_INET6) {
1530			fnd = 1;
1531			sin6->sin6_port = stcb->rport;
1532			sin6->sin6_addr = sin_a6->sin6_addr;
1533			break;
1534		}
1535	}
1536	SCTP_TCB_UNLOCK(stcb);
1537	if (!fnd) {
1538		/* No IPv4 address */
1539#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1540		SCTP_FREE_SONAME(sin6);
1541#endif
1542		SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT);
1543		return (ENOENT);
1544	}
1545#ifdef SCTP_EMBEDDED_V6_SCOPE
1546#ifdef SCTP_KAME
1547	if ((error = sa6_recoverscope(sin6)) != 0)
1548		return (error);
1549#else
1550	in6_recoverscope(sin6, &sin6->sin6_addr, NULL);
1551#endif /* SCTP_KAME */
1552#endif /* SCTP_EMBEDDED_V6_SCOPE */
1553#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1554	*addr = (struct sockaddr *)sin6;
1555#endif
1556	return (0);
1557}
1558
1559#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1560static int
1561sctp6_in6getaddr(struct socket *so, struct sockaddr **nam)
1562{
1563#ifdef INET
1564	struct sockaddr *addr;
1565#endif
1566#elif defined(__Panda__)
1567int
1568sctp6_in6getaddr(struct socket *so, struct sockaddr *nam, uint32_t *namelen)
1569{
1570	struct sockaddr *addr = nam;
1571#elif defined(__Userspace__)
1572int
1573sctp6_in6getaddr(struct socket *so, struct mbuf *nam)
1574{
1575#ifdef INET
1576	struct sockaddr *addr = mtod(nam, struct sockaddr *);
1577#endif
1578#else
1579static int
1580sctp6_in6getaddr(struct socket *so, struct mbuf *nam)
1581{
1582#ifdef INET
1583	struct sockaddr *addr = mtod(nam, struct sockaddr *);
1584#endif
1585#endif
1586	struct in6pcb *inp6 = sotoin6pcb(so);
1587	int error;
1588
1589	if (inp6 == NULL) {
1590		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1591		return (EINVAL);
1592	}
1593
1594	/* allow v6 addresses precedence */
1595	error = sctp6_getaddr(so, nam);
1596#ifdef INET
1597	if (error) {
1598		/* try v4 next if v6 failed */
1599		error = sctp_ingetaddr(so, nam);
1600		if (error) {
1601			return (error);
1602		}
1603#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1604		addr = *nam;
1605#endif
1606		/* if I'm V6ONLY, convert it to v4-mapped */
1607		if (SCTP_IPV6_V6ONLY(inp6)) {
1608			struct sockaddr_in6 sin6;
1609
1610			in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1611			memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1612		}
1613	}
1614#endif
1615#if defined(__Panda__)
1616	*namelen = nam->sa_len;
1617#endif
1618	return (error);
1619}
1620
1621
1622#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1623static int
1624sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam)
1625{
1626#ifdef INET
1627	struct sockaddr *addr;
1628#endif
1629#elif defined(__Panda__)
1630int
1631sctp6_getpeeraddr(struct socket *so, struct sockaddr *nam, uint32_t *namelen)
1632{
1633	struct sockaddr *addr = (struct sockaddr *)nam;
1634#elif defined(__Userspace__)
1635int
1636sctp6_getpeeraddr(struct socket *so, struct mbuf *nam)
1637{
1638#ifdef INET
1639	struct sockaddr *addr = mtod(nam, struct sockaddr *);
1640#endif
1641#else
1642static
1643int
1644sctp6_getpeeraddr(struct socket *so, struct mbuf *nam)
1645{
1646#ifdef INET
1647	struct sockaddr *addr = mtod(nam, struct sockaddr *);
1648#endif
1649
1650#endif
1651	struct in6pcb *inp6 = sotoin6pcb(so);
1652	int error;
1653
1654	if (inp6 == NULL) {
1655		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1656		return (EINVAL);
1657	}
1658
1659	/* allow v6 addresses precedence */
1660	error = sctp6_peeraddr(so, nam);
1661#ifdef INET
1662	if (error) {
1663		/* try v4 next if v6 failed */
1664		error = sctp_peeraddr(so, nam);
1665		if (error) {
1666			return (error);
1667		}
1668#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1669		addr = *nam;
1670#endif
1671		/* if I'm V6ONLY, convert it to v4-mapped */
1672		if (SCTP_IPV6_V6ONLY(inp6)) {
1673			struct sockaddr_in6 sin6;
1674
1675			in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6);
1676			memcpy(addr, &sin6, sizeof(struct sockaddr_in6));
1677		}
1678	}
1679#endif
1680#if defined(__Panda__)
1681	*namelen = nam->sa_len;
1682#endif
1683	return (error);
1684}
1685
1686#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__)
1687struct pr_usrreqs sctp6_usrreqs = {
1688#if defined(__FreeBSD__)
1689	.pru_abort = sctp6_abort,
1690	.pru_accept = sctp_accept,
1691	.pru_attach = sctp6_attach,
1692	.pru_bind = sctp6_bind,
1693	.pru_connect = sctp6_connect,
1694	.pru_control = in6_control,
1695#if __FreeBSD_version >= 690000
1696	.pru_close = sctp6_close,
1697	.pru_detach = sctp6_close,
1698	.pru_sopoll = sopoll_generic,
1699	.pru_flush = sctp_flush,
1700#else
1701	.pru_detach = sctp6_detach,
1702	.pru_sopoll = sopoll,
1703#endif
1704	.pru_disconnect = sctp6_disconnect,
1705	.pru_listen = sctp_listen,
1706	.pru_peeraddr = sctp6_getpeeraddr,
1707	.pru_send = sctp6_send,
1708	.pru_shutdown = sctp_shutdown,
1709	.pru_sockaddr = sctp6_in6getaddr,
1710	.pru_sosend = sctp_sosend,
1711	.pru_soreceive = sctp_soreceive
1712#elif defined(__APPLE__)
1713	.pru_abort = sctp6_abort,
1714	.pru_accept = sctp_accept,
1715	.pru_attach = sctp6_attach,
1716	.pru_bind = sctp6_bind,
1717	.pru_connect = sctp6_connect,
1718	.pru_connect2 = pru_connect2_notsupp,
1719	.pru_control = in6_control,
1720	.pru_detach = sctp6_detach,
1721	.pru_disconnect = sctp6_disconnect,
1722	.pru_listen = sctp_listen,
1723	.pru_peeraddr = sctp6_getpeeraddr,
1724	.pru_rcvd = NULL,
1725	.pru_rcvoob = pru_rcvoob_notsupp,
1726	.pru_send = sctp6_send,
1727	.pru_sense = pru_sense_null,
1728	.pru_shutdown = sctp_shutdown,
1729	.pru_sockaddr = sctp6_in6getaddr,
1730	.pru_sosend = sctp_sosend,
1731	.pru_soreceive = sctp_soreceive,
1732	.pru_sopoll = sopoll
1733#elif defined(__Windows__)
1734	sctp6_abort,
1735	sctp_accept,
1736	sctp6_attach,
1737	sctp6_bind,
1738	sctp6_connect,
1739	pru_connect2_notsupp,
1740	NULL,
1741	NULL,
1742	sctp6_disconnect,
1743	sctp_listen,
1744	sctp6_getpeeraddr,
1745	NULL,
1746	pru_rcvoob_notsupp,
1747	NULL,
1748	pru_sense_null,
1749	sctp_shutdown,
1750	sctp_flush,
1751	sctp6_in6getaddr,
1752	sctp_sosend,
1753	sctp_soreceive,
1754	sopoll_generic,
1755	NULL,
1756	sctp6_close
1757#endif
1758};
1759
1760#elif !defined(__Panda__) && !defined(__Userspace__)
1761int
1762sctp6_usrreq(so, req, m, nam, control, p)
1763	struct socket *so;
1764	int req;
1765	struct mbuf *m, *nam, *control;
1766	struct proc *p;
1767{
1768	int s;
1769	int error = 0;
1770	int family;
1771	uint32_t vrf_id;
1772	family = so->so_proto->pr_domain->dom_family;
1773
1774	if (req == PRU_CONTROL) {
1775		switch (family) {
1776		case PF_INET:
1777			error = in_control(so, (long)m, (caddr_t)nam,
1778			    (struct ifnet *)control
1779			    );
1780#ifdef INET6
1781		case PF_INET6:
1782			error = in6_control(so, (long)m, (caddr_t)nam,
1783			    (struct ifnet *)control, p);
1784#endif
1785		default:
1786			SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT);
1787			error = EAFNOSUPPORT;
1788		}
1789		return (error);
1790	}
1791	switch (req) {
1792	case PRU_ATTACH:
1793		error = sctp6_attach(so, family, p);
1794		break;
1795	case PRU_DETACH:
1796		error = sctp6_detach(so);
1797		break;
1798	case PRU_BIND:
1799		if (nam == NULL) {
1800			SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1801			return (EINVAL);
1802		}
1803		error = sctp6_bind(so, nam, p);
1804		break;
1805	case PRU_LISTEN:
1806		error = sctp_listen(so, p);
1807		break;
1808	case PRU_CONNECT:
1809		if (nam == NULL) {
1810			SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1811			return (EINVAL);
1812		}
1813		error = sctp6_connect(so, nam, p);
1814		break;
1815	case PRU_DISCONNECT:
1816		error = sctp6_disconnect(so);
1817		break;
1818	case PRU_ACCEPT:
1819		if (nam == NULL) {
1820			SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
1821			return (EINVAL);
1822		}
1823		error = sctp_accept(so, nam);
1824		break;
1825	case PRU_SHUTDOWN:
1826		error = sctp_shutdown(so);
1827		break;
1828
1829	case PRU_RCVD:
1830		/*
1831		 * For OpenBSD and NetBSD, this is real ugly. The (mbuf *)
1832		 * nam that is passed (by soreceive()) is the int flags cast
1833		 * as a (mbuf *) yuck!
1834		 */
1835		error = sctp_usr_recvd(so, (int)((long)nam));
1836		break;
1837
1838	case PRU_SEND:
1839		/* Flags are ignored */
1840		error = sctp6_send(so, 0, m, nam, control, p);
1841		break;
1842	case PRU_ABORT:
1843		error = sctp6_abort(so);
1844		break;
1845
1846	case PRU_SENSE:
1847		error = 0;
1848		break;
1849	case PRU_RCVOOB:
1850		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT);
1851		error = EAFNOSUPPORT;
1852		break;
1853	case PRU_SENDOOB:
1854		SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT);
1855		error = EAFNOSUPPORT;
1856		break;
1857	case PRU_PEERADDR:
1858		error = sctp6_getpeeraddr(so, nam);
1859		break;
1860	case PRU_SOCKADDR:
1861		error = sctp6_in6getaddr(so, nam);
1862		break;
1863	case PRU_SLOWTIMO:
1864		error = 0;
1865		break;
1866	default:
1867		break;
1868	}
1869	return (error);
1870}
1871#endif
1872#endif
1873