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