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