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