1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/sctp/src/netinet6/sctp6_usrreq.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1872 @@ 1.4 +/*- 1.5 + * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 1.6 + * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 1.7 + * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions are met: 1.11 + * 1.12 + * a) Redistributions of source code must retain the above copyright notice, 1.13 + * this list of conditions and the following disclaimer. 1.14 + * 1.15 + * b) Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in 1.17 + * the documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * c) Neither the name of Cisco Systems, Inc. nor the names of its 1.20 + * contributors may be used to endorse or promote products derived 1.21 + * from this software without specific prior written permission. 1.22 + * 1.23 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 1.25 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.26 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 1.27 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.28 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.29 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.30 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.31 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.32 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 1.33 + * THE POSSIBILITY OF SUCH DAMAGE. 1.34 + */ 1.35 + 1.36 +#ifdef __FreeBSD__ 1.37 +#include <sys/cdefs.h> 1.38 +__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 257555 2013-11-02 20:12:19Z tuexen $"); 1.39 +#endif 1.40 + 1.41 +#include <netinet/sctp_os.h> 1.42 +#ifdef INET6 1.43 +#ifdef __FreeBSD__ 1.44 +#include <sys/proc.h> 1.45 +#endif 1.46 +#include <netinet/sctp_pcb.h> 1.47 +#include <netinet/sctp_header.h> 1.48 +#include <netinet/sctp_var.h> 1.49 +#ifdef INET6 1.50 +#include <netinet6/sctp6_var.h> 1.51 +#endif 1.52 +#include <netinet/sctp_sysctl.h> 1.53 +#include <netinet/sctp_output.h> 1.54 +#include <netinet/sctp_uio.h> 1.55 +#include <netinet/sctp_asconf.h> 1.56 +#include <netinet/sctputil.h> 1.57 +#include <netinet/sctp_indata.h> 1.58 +#include <netinet/sctp_timer.h> 1.59 +#include <netinet/sctp_auth.h> 1.60 +#include <netinet/sctp_input.h> 1.61 +#include <netinet/sctp_output.h> 1.62 +#include <netinet/sctp_bsd_addr.h> 1.63 +#include <netinet/sctp_crc32.h> 1.64 +#if !defined(__Userspace_os_Windows) 1.65 +#include <netinet/udp.h> 1.66 +#endif 1.67 + 1.68 +#if defined(__APPLE__) 1.69 +#define APPLE_FILE_NO 9 1.70 +#endif 1.71 +#ifdef IPSEC 1.72 +#include <netipsec/ipsec.h> 1.73 +#ifdef INET6 1.74 +#include <netipsec/ipsec6.h> 1.75 +#endif /* INET6 */ 1.76 +#endif /* IPSEC */ 1.77 + 1.78 +#if !defined(__Userspace__) 1.79 +extern struct protosw inetsw[]; 1.80 +#endif 1.81 +#if defined(__Panda__) || defined(__Userspace__) 1.82 +int ip6_v6only=0; 1.83 +#endif 1.84 +#if defined(__Userspace__) 1.85 +void 1.86 +in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) 1.87 +{ 1.88 +#if defined(__Userspace_os_Windows) 1.89 + uint32_t temp; 1.90 +#endif 1.91 + bzero(sin, sizeof(*sin)); 1.92 +#ifdef HAVE_SIN_LEN 1.93 + sin->sin_len = sizeof(struct sockaddr_in); 1.94 +#endif 1.95 + sin->sin_family = AF_INET; 1.96 + sin->sin_port = sin6->sin6_port; 1.97 +#if defined(__Userspace_os_Windows) 1.98 + temp = sin6->sin6_addr.s6_addr16[7]; 1.99 + temp = temp << 16; 1.100 + temp = temp | sin6->sin6_addr.s6_addr16[6]; 1.101 + sin->sin_addr.s_addr = temp; 1.102 + sctp_print_address((struct sockaddr*)sin); 1.103 +#else 1.104 + sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; 1.105 +#endif 1.106 +} 1.107 + 1.108 +void 1.109 +in6_sin6_2_sin_in_sock(struct sockaddr *nam) 1.110 +{ 1.111 + struct sockaddr_in *sin_p; 1.112 + struct sockaddr_in6 sin6; 1.113 + 1.114 + /* save original sockaddr_in6 addr and convert it to sockaddr_in */ 1.115 + sin6 = *(struct sockaddr_in6 *)nam; 1.116 + sin_p = (struct sockaddr_in *)nam; 1.117 + in6_sin6_2_sin(sin_p, &sin6); 1.118 +} 1.119 +#endif 1.120 + 1.121 +#if !defined(__Userspace__) 1.122 +int 1.123 +#if defined(__APPLE__) || defined(__FreeBSD__) 1.124 +sctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port) 1.125 +#elif defined( __Panda__) 1.126 +sctp6_input(pakhandle_type *i_pak) 1.127 +#else 1.128 +sctp6_input(struct mbuf **i_pak, int *offp, int proto) 1.129 +#endif 1.130 +{ 1.131 + struct mbuf *m; 1.132 + int iphlen; 1.133 + uint32_t vrf_id; 1.134 + uint8_t ecn_bits; 1.135 + struct sockaddr_in6 src, dst; 1.136 + struct ip6_hdr *ip6; 1.137 + struct sctphdr *sh; 1.138 + struct sctp_chunkhdr *ch; 1.139 + int length, offset; 1.140 +#if !defined(SCTP_WITH_NO_CSUM) 1.141 + uint8_t compute_crc; 1.142 +#endif 1.143 +#if defined(__FreeBSD__) 1.144 + uint32_t mflowid; 1.145 + uint8_t use_mflowid; 1.146 +#endif 1.147 +#if !(defined(__APPLE__) || defined (__FreeBSD__)) 1.148 + uint16_t port = 0; 1.149 +#endif 1.150 + 1.151 +#if defined(__Panda__) 1.152 + /* This is Evil, but its the only way to make panda work right. */ 1.153 + iphlen = sizeof(struct ip6_hdr); 1.154 +#else 1.155 + iphlen = *offp; 1.156 +#endif 1.157 + if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) { 1.158 + SCTP_RELEASE_PKT(*i_pak); 1.159 + return (IPPROTO_DONE); 1.160 + } 1.161 + m = SCTP_HEADER_TO_CHAIN(*i_pak); 1.162 +#ifdef __Panda__ 1.163 + SCTP_DETACH_HEADER_FROM_CHAIN(*i_pak); 1.164 + (void)SCTP_RELEASE_HEADER(*i_pak); 1.165 +#endif 1.166 +#ifdef SCTP_MBUF_LOGGING 1.167 + /* Log in any input mbufs */ 1.168 + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { 1.169 + struct mbuf *mat; 1.170 + 1.171 + for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { 1.172 + if (SCTP_BUF_IS_EXTENDED(mat)) { 1.173 + sctp_log_mb(mat, SCTP_MBUF_INPUT); 1.174 + } 1.175 + } 1.176 + } 1.177 +#endif 1.178 +#ifdef SCTP_PACKET_LOGGING 1.179 + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { 1.180 + sctp_packet_log(m); 1.181 + } 1.182 +#endif 1.183 +#if defined(__FreeBSD__) 1.184 +#if __FreeBSD_version > 1000049 1.185 + SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 1.186 + "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n", 1.187 + m->m_pkthdr.len, 1.188 + if_name(m->m_pkthdr.rcvif), 1.189 + (int)m->m_pkthdr.csum_flags, CSUM_BITS); 1.190 +#elif __FreeBSD_version >= 800000 1.191 + SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 1.192 + "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", 1.193 + m->m_pkthdr.len, 1.194 + if_name(m->m_pkthdr.rcvif), 1.195 + m->m_pkthdr.csum_flags); 1.196 +#else 1.197 + SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 1.198 + "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", 1.199 + m->m_pkthdr.len, 1.200 + m->m_pkthdr.rcvif->if_xname, 1.201 + m->m_pkthdr.csum_flags); 1.202 +#endif 1.203 +#endif 1.204 +#if defined(__APPLE__) 1.205 + SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 1.206 + "sctp6_input(): Packet of length %d received on %s%d with csum_flags 0x%x.\n", 1.207 + m->m_pkthdr.len, 1.208 + m->m_pkthdr.rcvif->if_name, 1.209 + m->m_pkthdr.rcvif->if_unit, 1.210 + m->m_pkthdr.csum_flags); 1.211 +#endif 1.212 +#if defined(__Windows__) 1.213 + SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 1.214 + "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%x.\n", 1.215 + m->m_pkthdr.len, 1.216 + m->m_pkthdr.rcvif->if_xname, 1.217 + m->m_pkthdr.csum_flags); 1.218 +#endif 1.219 +#if defined(__FreeBSD__) 1.220 + if (m->m_flags & M_FLOWID) { 1.221 + mflowid = m->m_pkthdr.flowid; 1.222 + use_mflowid = 1; 1.223 + } else { 1.224 + mflowid = 0; 1.225 + use_mflowid = 0; 1.226 + } 1.227 +#endif 1.228 + SCTP_STAT_INCR(sctps_recvpackets); 1.229 + SCTP_STAT_INCR_COUNTER64(sctps_inpackets); 1.230 + /* Get IP, SCTP, and first chunk header together in the first mbuf. */ 1.231 + offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); 1.232 + ip6 = mtod(m, struct ip6_hdr *); 1.233 + IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen, 1.234 + (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))); 1.235 + if (sh == NULL) { 1.236 + SCTP_STAT_INCR(sctps_hdrops); 1.237 + return (IPPROTO_DONE); 1.238 + } 1.239 + ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); 1.240 + offset -= sizeof(struct sctp_chunkhdr); 1.241 + memset(&src, 0, sizeof(struct sockaddr_in6)); 1.242 + src.sin6_family = AF_INET6; 1.243 +#ifdef HAVE_SIN6_LEN 1.244 + src.sin6_len = sizeof(struct sockaddr_in6); 1.245 +#endif 1.246 + src.sin6_port = sh->src_port; 1.247 + src.sin6_addr = ip6->ip6_src; 1.248 +#if defined(__FreeBSD__) 1.249 +#if defined(__APPLE__) 1.250 + /* XXX: This code should also be used on Apple */ 1.251 +#endif 1.252 + if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) { 1.253 + goto out; 1.254 + } 1.255 +#endif 1.256 + memset(&dst, 0, sizeof(struct sockaddr_in6)); 1.257 + dst.sin6_family = AF_INET6; 1.258 +#ifdef HAVE_SIN6_LEN 1.259 + dst.sin6_len = sizeof(struct sockaddr_in6); 1.260 +#endif 1.261 + dst.sin6_port = sh->dest_port; 1.262 + dst.sin6_addr = ip6->ip6_dst; 1.263 +#if defined(__FreeBSD__) 1.264 +#if defined(__APPLE__) 1.265 + /* XXX: This code should also be used on Apple */ 1.266 +#endif 1.267 + if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) { 1.268 + goto out; 1.269 + } 1.270 +#endif 1.271 +#ifdef __FreeBSD__ 1.272 + if (faithprefix_p != NULL && (*faithprefix_p) (&dst.sin6_addr)) { 1.273 + /* XXX send icmp6 host/port unreach? */ 1.274 + goto out; 1.275 + } 1.276 +#endif 1.277 +#if defined(__APPLE__) 1.278 +#if defined(NFAITH) && 0 < NFAITH 1.279 + if (faithprefix(&dst.sin6_addr)) { 1.280 + goto out; 1.281 + } 1.282 +#endif 1.283 +#endif 1.284 + length = ntohs(ip6->ip6_plen) + iphlen; 1.285 + /* Validate mbuf chain length with IP payload length. */ 1.286 + if (SCTP_HEADER_LEN(m) != length) { 1.287 + SCTPDBG(SCTP_DEBUG_INPUT1, 1.288 + "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m)); 1.289 + SCTP_STAT_INCR(sctps_hdrops); 1.290 + goto out; 1.291 + } 1.292 + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 1.293 + goto out; 1.294 + } 1.295 + ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); 1.296 +#if defined(SCTP_WITH_NO_CSUM) 1.297 + SCTP_STAT_INCR(sctps_recvnocrc); 1.298 +#else 1.299 +#if defined(__FreeBSD__) && __FreeBSD_version >= 800000 1.300 + if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { 1.301 + SCTP_STAT_INCR(sctps_recvhwcrc); 1.302 + compute_crc = 0; 1.303 + } else { 1.304 +#else 1.305 + if (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && 1.306 + (IN6_ARE_ADDR_EQUAL(&src.sin6_addr, &dst.sin6_addr))) { 1.307 + SCTP_STAT_INCR(sctps_recvnocrc); 1.308 + compute_crc = 0; 1.309 + } else { 1.310 +#endif 1.311 + SCTP_STAT_INCR(sctps_recvswcrc); 1.312 + compute_crc = 1; 1.313 + } 1.314 +#endif 1.315 + sctp_common_input_processing(&m, iphlen, offset, length, 1.316 + (struct sockaddr *)&src, 1.317 + (struct sockaddr *)&dst, 1.318 + sh, ch, 1.319 +#if !defined(SCTP_WITH_NO_CSUM) 1.320 + compute_crc, 1.321 +#endif 1.322 + ecn_bits, 1.323 +#if defined(__FreeBSD__) 1.324 + use_mflowid, mflowid, 1.325 +#endif 1.326 + vrf_id, port); 1.327 + out: 1.328 + if (m) { 1.329 + sctp_m_freem(m); 1.330 + } 1.331 + return (IPPROTO_DONE); 1.332 +} 1.333 + 1.334 +#if defined(__APPLE__) 1.335 +int 1.336 +sctp6_input(struct mbuf **i_pak, int *offp) 1.337 +{ 1.338 + return (sctp6_input_with_port(i_pak, offp, 0)); 1.339 +} 1.340 +#endif 1.341 + 1.342 +#if defined(__FreeBSD__) 1.343 +int 1.344 +sctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED) 1.345 +{ 1.346 + return (sctp6_input_with_port(i_pak, offp, 0)); 1.347 +} 1.348 +#endif 1.349 + 1.350 +#if defined(__Panda__) 1.351 +void 1.352 +#else 1.353 +static void 1.354 +#endif 1.355 +sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6, 1.356 + struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net) 1.357 +{ 1.358 + uint32_t nxtsz; 1.359 + 1.360 + if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 1.361 + (icmp6 == NULL) || (sh == NULL)) { 1.362 + goto out; 1.363 + } 1.364 + /* First do we even look at it? */ 1.365 + if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) 1.366 + goto out; 1.367 + 1.368 + if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) { 1.369 + /* not PACKET TO BIG */ 1.370 + goto out; 1.371 + } 1.372 + /* 1.373 + * ok we need to look closely. We could even get smarter and look at 1.374 + * anyone that we sent to in case we get a different ICMP that tells 1.375 + * us there is no way to reach a host, but for this impl, all we 1.376 + * care about is MTU discovery. 1.377 + */ 1.378 + nxtsz = ntohl(icmp6->icmp6_mtu); 1.379 + /* Stop any PMTU timer */ 1.380 + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ+SCTP_LOC_1); 1.381 + 1.382 + /* Adjust destination size limit */ 1.383 + if (net->mtu > nxtsz) { 1.384 + net->mtu = nxtsz; 1.385 + if (net->port) { 1.386 + net->mtu -= sizeof(struct udphdr); 1.387 + } 1.388 + } 1.389 + /* now what about the ep? */ 1.390 + if (stcb->asoc.smallest_mtu > nxtsz) { 1.391 + struct sctp_tmit_chunk *chk; 1.392 + 1.393 + /* Adjust that too */ 1.394 + stcb->asoc.smallest_mtu = nxtsz; 1.395 + /* now off to subtract IP_DF flag if needed */ 1.396 + 1.397 + TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 1.398 + if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 1.399 + chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 1.400 + } 1.401 + } 1.402 + TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 1.403 + if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 1.404 + /* 1.405 + * For this guy we also mark for immediate 1.406 + * resend since we sent to big of chunk 1.407 + */ 1.408 + chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 1.409 + if (chk->sent != SCTP_DATAGRAM_RESEND) 1.410 + stcb->asoc.sent_queue_retran_cnt++; 1.411 + chk->sent = SCTP_DATAGRAM_RESEND; 1.412 + chk->rec.data.doing_fast_retransmit = 0; 1.413 + 1.414 + chk->sent = SCTP_DATAGRAM_RESEND; 1.415 + /* Clear any time so NO RTT is being done */ 1.416 + chk->sent_rcv_time.tv_sec = 0; 1.417 + chk->sent_rcv_time.tv_usec = 0; 1.418 + stcb->asoc.total_flight -= chk->send_size; 1.419 + net->flight_size -= chk->send_size; 1.420 + } 1.421 + } 1.422 + } 1.423 + sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 1.424 +out: 1.425 + if (stcb) { 1.426 + SCTP_TCB_UNLOCK(stcb); 1.427 + } 1.428 +} 1.429 +#endif 1.430 + 1.431 + 1.432 +void 1.433 +sctp6_notify(struct sctp_inpcb *inp, 1.434 + struct icmp6_hdr *icmph, 1.435 + struct sctphdr *sh, 1.436 + struct sockaddr *to, 1.437 + struct sctp_tcb *stcb, 1.438 + struct sctp_nets *net) 1.439 +{ 1.440 +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1.441 + struct socket *so; 1.442 + 1.443 +#endif 1.444 + 1.445 + /* protection */ 1.446 + if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 1.447 + (sh == NULL) || (to == NULL)) { 1.448 + if (stcb) 1.449 + SCTP_TCB_UNLOCK(stcb); 1.450 + return; 1.451 + } 1.452 + /* First job is to verify the vtag matches what I would send */ 1.453 + if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 1.454 + SCTP_TCB_UNLOCK(stcb); 1.455 + return; 1.456 + } 1.457 + if (icmph->icmp6_type != ICMP_UNREACH) { 1.458 + /* We only care about unreachable */ 1.459 + SCTP_TCB_UNLOCK(stcb); 1.460 + return; 1.461 + } 1.462 + if ((icmph->icmp6_code == ICMP_UNREACH_NET) || 1.463 + (icmph->icmp6_code == ICMP_UNREACH_HOST) || 1.464 + (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) || 1.465 + (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) || 1.466 + (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) || 1.467 + (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) || 1.468 + (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) || 1.469 +#if defined(__Panda__) 1.470 + (icmph->icmp6_code == ICMP_UNREACH_ADMIN)) { 1.471 +#elif defined(__Userspace_os_NetBSD) 1.472 + (icmph->icmp6_code == ICMP_UNREACH_ADMIN_PROHIBIT)) { 1.473 +#else 1.474 + (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) { 1.475 +#endif 1.476 + 1.477 + /* 1.478 + * Hmm reachablity problems we must examine closely. If its 1.479 + * not reachable, we may have lost a network. Or if there is 1.480 + * NO protocol at the other end named SCTP. well we consider 1.481 + * it a OOTB abort. 1.482 + */ 1.483 + if (net->dest_state & SCTP_ADDR_REACHABLE) { 1.484 + /* Ok that destination is NOT reachable */ 1.485 + net->dest_state &= ~SCTP_ADDR_REACHABLE; 1.486 + net->dest_state &= ~SCTP_ADDR_PF; 1.487 + sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 1.488 + stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED); 1.489 + } 1.490 + SCTP_TCB_UNLOCK(stcb); 1.491 + } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) || 1.492 + (icmph->icmp6_code == ICMP_UNREACH_PORT)) { 1.493 + /* 1.494 + * Here the peer is either playing tricks on us, 1.495 + * including an address that belongs to someone who 1.496 + * does not support SCTP OR was a userland 1.497 + * implementation that shutdown and now is dead. In 1.498 + * either case treat it like a OOTB abort with no 1.499 + * TCB 1.500 + */ 1.501 + sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); 1.502 +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1.503 + so = SCTP_INP_SO(inp); 1.504 + atomic_add_int(&stcb->asoc.refcnt, 1); 1.505 + SCTP_TCB_UNLOCK(stcb); 1.506 + SCTP_SOCKET_LOCK(so, 1); 1.507 + SCTP_TCB_LOCK(stcb); 1.508 + atomic_subtract_int(&stcb->asoc.refcnt, 1); 1.509 +#endif 1.510 + (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_2); 1.511 +#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1.512 + SCTP_SOCKET_UNLOCK(so, 1); 1.513 + /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/ 1.514 +#endif 1.515 + /* no need to unlock here, since the TCB is gone */ 1.516 + } else { 1.517 + SCTP_TCB_UNLOCK(stcb); 1.518 + } 1.519 +} 1.520 + 1.521 + 1.522 + 1.523 +#if !defined(__Panda__) && !defined(__Userspace__) 1.524 +void 1.525 +sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) 1.526 +{ 1.527 + struct sctphdr sh; 1.528 + struct ip6ctlparam *ip6cp = NULL; 1.529 + uint32_t vrf_id; 1.530 + 1.531 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.532 + vrf_id = SCTP_DEFAULT_VRFID; 1.533 +#endif 1.534 + 1.535 +#ifdef HAVE_SA_LEN 1.536 + if (pktdst->sa_family != AF_INET6 || 1.537 + pktdst->sa_len != sizeof(struct sockaddr_in6)) 1.538 +#else 1.539 + if (pktdst->sa_family != AF_INET6) 1.540 +#endif 1.541 + return; 1.542 + 1.543 + if ((unsigned)cmd >= PRC_NCMDS) 1.544 + return; 1.545 + if (PRC_IS_REDIRECT(cmd)) { 1.546 + d = NULL; 1.547 + } else if (inet6ctlerrmap[cmd] == 0) { 1.548 + return; 1.549 + } 1.550 + /* if the parameter is from icmp6, decode it. */ 1.551 + if (d != NULL) { 1.552 + ip6cp = (struct ip6ctlparam *)d; 1.553 + } else { 1.554 + ip6cp = (struct ip6ctlparam *)NULL; 1.555 + } 1.556 + 1.557 + if (ip6cp) { 1.558 + /* 1.559 + * XXX: We assume that when IPV6 is non NULL, M and OFF are 1.560 + * valid. 1.561 + */ 1.562 + /* check if we can safely examine src and dst ports */ 1.563 + struct sctp_inpcb *inp = NULL; 1.564 + struct sctp_tcb *stcb = NULL; 1.565 + struct sctp_nets *net = NULL; 1.566 + struct sockaddr_in6 final; 1.567 + 1.568 + if (ip6cp->ip6c_m == NULL) 1.569 + return; 1.570 + 1.571 + bzero(&sh, sizeof(sh)); 1.572 + bzero(&final, sizeof(final)); 1.573 + inp = NULL; 1.574 + net = NULL; 1.575 + m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh), 1.576 + (caddr_t)&sh); 1.577 + ip6cp->ip6c_src->sin6_port = sh.src_port; 1.578 +#ifdef HAVE_SIN6_LEN 1.579 + final.sin6_len = sizeof(final); 1.580 +#endif 1.581 + final.sin6_family = AF_INET6; 1.582 +#if defined(__FreeBSD__) && __FreeBSD_cc_version < 440000 1.583 + final.sin6_addr = *ip6cp->ip6c_finaldst; 1.584 +#else 1.585 + final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr; 1.586 +#endif /* __FreeBSD_cc_version */ 1.587 + final.sin6_port = sh.dest_port; 1.588 + stcb = sctp_findassociation_addr_sa((struct sockaddr *)&final, 1.589 + (struct sockaddr *)ip6cp->ip6c_src, 1.590 + &inp, &net, 1, vrf_id); 1.591 + /* inp's ref-count increased && stcb locked */ 1.592 + if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 1.593 + if (cmd == PRC_MSGSIZE) { 1.594 + sctp6_notify_mbuf(inp, 1.595 + ip6cp->ip6c_icmp6, 1.596 + &sh, 1.597 + stcb, 1.598 + net); 1.599 + /* inp's ref-count reduced && stcb unlocked */ 1.600 + } else { 1.601 + sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh, 1.602 + (struct sockaddr *)&final, 1.603 + stcb, net); 1.604 + /* inp's ref-count reduced && stcb unlocked */ 1.605 + } 1.606 + } else { 1.607 +#if !defined(__Windows__) 1.608 + if (PRC_IS_REDIRECT(cmd) && inp) { 1.609 + in6_rtchange((struct in6pcb *)inp, 1.610 + inet6ctlerrmap[cmd]); 1.611 + } 1.612 +#endif 1.613 + if (inp) { 1.614 + /* reduce inp's ref-count */ 1.615 + SCTP_INP_WLOCK(inp); 1.616 + SCTP_INP_DECR_REF(inp); 1.617 + SCTP_INP_WUNLOCK(inp); 1.618 + } 1.619 + if (stcb) 1.620 + SCTP_TCB_UNLOCK(stcb); 1.621 + } 1.622 + } 1.623 +} 1.624 +#endif 1.625 + 1.626 +/* 1.627 + * this routine can probably be collasped into the one in sctp_userreq.c 1.628 + * since they do the same thing and now we lookup with a sockaddr 1.629 + */ 1.630 +#ifdef __FreeBSD__ 1.631 +static int 1.632 +sctp6_getcred(SYSCTL_HANDLER_ARGS) 1.633 +{ 1.634 + struct xucred xuc; 1.635 + struct sockaddr_in6 addrs[2]; 1.636 + struct sctp_inpcb *inp; 1.637 + struct sctp_nets *net; 1.638 + struct sctp_tcb *stcb; 1.639 + int error; 1.640 + uint32_t vrf_id; 1.641 + 1.642 +#if defined(__FreeBSD__) || defined(__APPLE__) 1.643 + vrf_id = SCTP_DEFAULT_VRFID; 1.644 +#else 1.645 + vrf_id = panda_get_vrf_from_call(); /* from connectx call? */ 1.646 +#endif 1.647 + 1.648 +#if defined(__FreeBSD__) && __FreeBSD_version > 602000 1.649 + error = priv_check(req->td, PRIV_NETINET_GETCRED); 1.650 +#elif defined(__FreeBSD__) && __FreeBSD_version >= 500000 1.651 + error = suser(req->td); 1.652 +#else 1.653 + error = suser(req->p); 1.654 +#endif 1.655 + if (error) 1.656 + return (error); 1.657 + 1.658 + if (req->newlen != sizeof(addrs)) { 1.659 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.660 + return (EINVAL); 1.661 + } 1.662 + if (req->oldlen != sizeof(struct ucred)) { 1.663 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.664 + return (EINVAL); 1.665 + } 1.666 + error = SYSCTL_IN(req, addrs, sizeof(addrs)); 1.667 + if (error) 1.668 + return (error); 1.669 + 1.670 + stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]), 1.671 + sin6tosa(&addrs[0]), 1.672 + &inp, &net, 1, vrf_id); 1.673 + if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 1.674 + if ((inp != NULL) && (stcb == NULL)) { 1.675 + /* reduce ref-count */ 1.676 + SCTP_INP_WLOCK(inp); 1.677 + SCTP_INP_DECR_REF(inp); 1.678 + goto cred_can_cont; 1.679 + } 1.680 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1.681 + error = ENOENT; 1.682 + goto out; 1.683 + } 1.684 + SCTP_TCB_UNLOCK(stcb); 1.685 + /* We use the write lock here, only 1.686 + * since in the error leg we need it. 1.687 + * If we used RLOCK, then we would have 1.688 + * to wlock/decr/unlock/rlock. Which 1.689 + * in theory could create a hole. Better 1.690 + * to use higher wlock. 1.691 + */ 1.692 + SCTP_INP_WLOCK(inp); 1.693 + cred_can_cont: 1.694 + error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 1.695 + if (error) { 1.696 + SCTP_INP_WUNLOCK(inp); 1.697 + goto out; 1.698 + } 1.699 + cru2x(inp->sctp_socket->so_cred, &xuc); 1.700 + SCTP_INP_WUNLOCK(inp); 1.701 + error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 1.702 +out: 1.703 + return (error); 1.704 +} 1.705 + 1.706 +SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 1.707 + 0, 0, 1.708 + sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection"); 1.709 + 1.710 +#endif 1.711 + 1.712 +/* This is the same as the sctp_abort() could be made common */ 1.713 +#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) 1.714 +static void 1.715 +#elif defined(__Panda__) || defined(__Userspace__) 1.716 +int 1.717 +#else 1.718 +static int 1.719 +#endif 1.720 +sctp6_abort(struct socket *so) 1.721 +{ 1.722 + struct sctp_inpcb *inp; 1.723 + uint32_t flags; 1.724 + 1.725 + inp = (struct sctp_inpcb *)so->so_pcb; 1.726 + if (inp == NULL) { 1.727 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.728 +#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) 1.729 + return; 1.730 +#else 1.731 + return (EINVAL); 1.732 +#endif 1.733 + } 1.734 + sctp_must_try_again: 1.735 + flags = inp->sctp_flags; 1.736 +#ifdef SCTP_LOG_CLOSING 1.737 + sctp_log_closing(inp, NULL, 17); 1.738 +#endif 1.739 + if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 1.740 + (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 1.741 +#ifdef SCTP_LOG_CLOSING 1.742 + sctp_log_closing(inp, NULL, 16); 1.743 +#endif 1.744 + sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 1.745 + SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 1.746 + SOCK_LOCK(so); 1.747 + SCTP_SB_CLEAR(so->so_snd); 1.748 + /* same for the rcv ones, they are only 1.749 + * here for the accounting/select. 1.750 + */ 1.751 + SCTP_SB_CLEAR(so->so_rcv); 1.752 +#if defined(__APPLE__) 1.753 + so->so_usecount--; 1.754 +#else 1.755 + /* Now null out the reference, we are completely detached. */ 1.756 + so->so_pcb = NULL; 1.757 +#endif 1.758 + SOCK_UNLOCK(so); 1.759 + } else { 1.760 + flags = inp->sctp_flags; 1.761 + if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 1.762 + goto sctp_must_try_again; 1.763 + } 1.764 + } 1.765 +#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) 1.766 + return; 1.767 +#else 1.768 + return (0); 1.769 +#endif 1.770 +} 1.771 + 1.772 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 1.773 +static int 1.774 +sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) 1.775 +#elif defined(__Panda__) || defined(__Userspace__) 1.776 +int 1.777 +sctp6_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id) 1.778 +#elif defined(__Windows__) 1.779 +static int 1.780 +sctp6_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED) 1.781 +#else 1.782 +static int 1.783 +sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED) 1.784 +#endif 1.785 +{ 1.786 + struct in6pcb *inp6; 1.787 + int error; 1.788 + struct sctp_inpcb *inp; 1.789 +#if !defined(__Panda__) && !defined(__Userspace__) 1.790 + uint32_t vrf_id = SCTP_DEFAULT_VRFID; 1.791 +#endif 1.792 + 1.793 + inp = (struct sctp_inpcb *)so->so_pcb; 1.794 + if (inp != NULL) { 1.795 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.796 + return (EINVAL); 1.797 + } 1.798 + 1.799 + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 1.800 + error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 1.801 + if (error) 1.802 + return (error); 1.803 + } 1.804 + error = sctp_inpcb_alloc(so, vrf_id); 1.805 + if (error) 1.806 + return (error); 1.807 + inp = (struct sctp_inpcb *)so->so_pcb; 1.808 + SCTP_INP_WLOCK(inp); 1.809 + inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */ 1.810 + inp6 = (struct in6pcb *)inp; 1.811 + 1.812 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) 1.813 + inp6->inp_vflag |= INP_IPV6; 1.814 +#else 1.815 + inp->inp_vflag |= INP_IPV6; 1.816 +#endif 1.817 +#if !defined(__Panda__) 1.818 + inp6->in6p_hops = -1; /* use kernel default */ 1.819 + inp6->in6p_cksum = -1; /* just to be sure */ 1.820 +#endif 1.821 +#ifdef INET 1.822 + /* 1.823 + * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6 1.824 + * socket as well, because the socket may be bound to an IPv6 1.825 + * wildcard address, which may match an IPv4-mapped IPv6 address. 1.826 + */ 1.827 + inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); 1.828 +#endif 1.829 + /* 1.830 + * Hmm what about the IPSEC stuff that is missing here but in 1.831 + * sctp_attach()? 1.832 + */ 1.833 + SCTP_INP_WUNLOCK(inp); 1.834 + return (0); 1.835 +} 1.836 + 1.837 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 1.838 +static int 1.839 +sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 1.840 +{ 1.841 +#elif defined(__FreeBSD__) || defined(__APPLE__) 1.842 +static int 1.843 +sctp6_bind(struct socket *so, struct sockaddr *addr, struct proc *p) 1.844 +{ 1.845 +#elif defined(__Panda__) || defined(__Userspace__) 1.846 +int 1.847 +sctp6_bind(struct socket *so, struct sockaddr *addr, void * p) 1.848 +{ 1.849 +#elif defined(__Windows__) 1.850 +static int 1.851 +sctp6_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p) 1.852 +{ 1.853 +#else 1.854 +static int 1.855 +sctp6_bind(struct socket *so, struct mbuf *nam, struct proc *p) 1.856 +{ 1.857 + struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL; 1.858 + 1.859 +#endif 1.860 + struct sctp_inpcb *inp; 1.861 + struct in6pcb *inp6; 1.862 + int error; 1.863 + 1.864 + inp = (struct sctp_inpcb *)so->so_pcb; 1.865 + if (inp == NULL) { 1.866 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.867 + return (EINVAL); 1.868 + } 1.869 + 1.870 +#if !defined(__Windows__) 1.871 + if (addr) { 1.872 + switch (addr->sa_family) { 1.873 +#ifdef INET 1.874 + case AF_INET: 1.875 +#ifdef HAVE_SA_LEN 1.876 + if (addr->sa_len != sizeof(struct sockaddr_in)) { 1.877 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.878 + return (EINVAL); 1.879 + } 1.880 +#endif 1.881 + break; 1.882 +#endif 1.883 +#ifdef INET6 1.884 + case AF_INET6: 1.885 +#ifdef HAVE_SA_LEN 1.886 + if (addr->sa_len != sizeof(struct sockaddr_in6)) { 1.887 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.888 + return (EINVAL); 1.889 + } 1.890 +#endif 1.891 + break; 1.892 +#endif 1.893 + default: 1.894 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.895 + return (EINVAL); 1.896 + } 1.897 + } 1.898 +#endif 1.899 + inp6 = (struct in6pcb *)inp; 1.900 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) 1.901 + inp6->inp_vflag &= ~INP_IPV4; 1.902 + inp6->inp_vflag |= INP_IPV6; 1.903 +#else 1.904 + inp->inp_vflag &= ~INP_IPV4; 1.905 + inp->inp_vflag |= INP_IPV6; 1.906 +#endif 1.907 + if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) { 1.908 + switch (addr->sa_family) { 1.909 +#ifdef INET 1.910 + case AF_INET: 1.911 + /* binding v4 addr to v6 socket, so reset flags */ 1.912 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) 1.913 + inp6->inp_vflag |= INP_IPV4; 1.914 + inp6->inp_vflag &= ~INP_IPV6; 1.915 +#else 1.916 + inp->inp_vflag |= INP_IPV4; 1.917 + inp->inp_vflag &= ~INP_IPV6; 1.918 +#endif 1.919 + break; 1.920 +#endif 1.921 +#ifdef INET6 1.922 + case AF_INET6: 1.923 + { 1.924 + struct sockaddr_in6 *sin6_p; 1.925 + 1.926 + sin6_p = (struct sockaddr_in6 *)addr; 1.927 + 1.928 + if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) { 1.929 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) 1.930 + inp6->inp_vflag |= INP_IPV4; 1.931 +#else 1.932 + inp->inp_vflag |= INP_IPV4; 1.933 +#endif 1.934 + } 1.935 +#ifdef INET 1.936 + if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 1.937 + struct sockaddr_in sin; 1.938 + 1.939 + in6_sin6_2_sin(&sin, sin6_p); 1.940 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) 1.941 + inp6->inp_vflag |= INP_IPV4; 1.942 + inp6->inp_vflag &= ~INP_IPV6; 1.943 +#else 1.944 + inp->inp_vflag |= INP_IPV4; 1.945 + inp->inp_vflag &= ~INP_IPV6; 1.946 +#endif 1.947 + error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p); 1.948 + return (error); 1.949 + } 1.950 +#endif 1.951 + break; 1.952 + } 1.953 +#endif 1.954 + default: 1.955 + break; 1.956 + } 1.957 + } else if (addr != NULL) { 1.958 + struct sockaddr_in6 *sin6_p; 1.959 + 1.960 + /* IPV6_V6ONLY socket */ 1.961 +#ifdef INET 1.962 + if (addr->sa_family == AF_INET) { 1.963 + /* can't bind v4 addr to v6 only socket! */ 1.964 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.965 + return (EINVAL); 1.966 + } 1.967 +#endif 1.968 + sin6_p = (struct sockaddr_in6 *)addr; 1.969 + 1.970 + if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 1.971 + /* can't bind v4-mapped addrs either! */ 1.972 + /* NOTE: we don't support SIIT */ 1.973 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.974 + return (EINVAL); 1.975 + } 1.976 + } 1.977 + error = sctp_inpcb_bind(so, addr, NULL, p); 1.978 + return (error); 1.979 +} 1.980 + 1.981 + 1.982 +#if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) || defined(__Userspace__) 1.983 +#if !defined(__Userspace__) 1.984 +static void 1.985 +#else 1.986 +void 1.987 +#endif 1.988 +sctp6_close(struct socket *so) 1.989 +{ 1.990 + sctp_close(so); 1.991 +} 1.992 + 1.993 +/* This could be made common with sctp_detach() since they are identical */ 1.994 +#else 1.995 + 1.996 +#if !defined(__Panda__) 1.997 +static 1.998 +#endif 1.999 +int 1.1000 +sctp6_detach(struct socket *so) 1.1001 +{ 1.1002 +#if defined(__Userspace__) 1.1003 + sctp_close(so); 1.1004 + return (0); 1.1005 +#else 1.1006 + return (sctp_detach(so)); 1.1007 +#endif 1.1008 +} 1.1009 + 1.1010 +#endif 1.1011 + 1.1012 +#if !defined(__Panda__) && !defined(__Userspace__) 1.1013 +static 1.1014 +#endif 1.1015 +int 1.1016 +sctp6_disconnect(struct socket *so) 1.1017 +{ 1.1018 + return (sctp_disconnect(so)); 1.1019 +} 1.1020 + 1.1021 + 1.1022 +int 1.1023 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 1.1024 +sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 1.1025 + struct mbuf *control, struct thread *p); 1.1026 + 1.1027 +#else 1.1028 +sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 1.1029 + struct mbuf *control, struct proc *p); 1.1030 + 1.1031 +#endif 1.1032 + 1.1033 +#if !defined(__Panda__) && !defined(__Windows__) && !defined(__Userspace__) 1.1034 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 1.1035 +static int 1.1036 +sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 1.1037 + struct mbuf *control, struct thread *p) 1.1038 +{ 1.1039 +#elif defined(__FreeBSD__) || defined(__APPLE__) 1.1040 +static int 1.1041 +sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 1.1042 + struct mbuf *control, struct proc *p) 1.1043 +{ 1.1044 +#else 1.1045 +static int 1.1046 +sctp6_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam, 1.1047 + struct mbuf *control, struct proc *p) 1.1048 +{ 1.1049 + struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL; 1.1050 +#endif 1.1051 + struct sctp_inpcb *inp; 1.1052 + struct in6pcb *inp6; 1.1053 + 1.1054 +#ifdef INET 1.1055 + struct sockaddr_in6 *sin6; 1.1056 +#endif /* INET */ 1.1057 + /* No SPL needed since sctp_output does this */ 1.1058 + 1.1059 + inp = (struct sctp_inpcb *)so->so_pcb; 1.1060 + if (inp == NULL) { 1.1061 + if (control) { 1.1062 + SCTP_RELEASE_PKT(control); 1.1063 + control = NULL; 1.1064 + } 1.1065 + SCTP_RELEASE_PKT(m); 1.1066 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1067 + return (EINVAL); 1.1068 + } 1.1069 + inp6 = (struct in6pcb *)inp; 1.1070 + /* 1.1071 + * For the TCP model we may get a NULL addr, if we are a connected 1.1072 + * socket thats ok. 1.1073 + */ 1.1074 + if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) && 1.1075 + (addr == NULL)) { 1.1076 + goto connected_type; 1.1077 + } 1.1078 + if (addr == NULL) { 1.1079 + SCTP_RELEASE_PKT(m); 1.1080 + if (control) { 1.1081 + SCTP_RELEASE_PKT(control); 1.1082 + control = NULL; 1.1083 + } 1.1084 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ); 1.1085 + return (EDESTADDRREQ); 1.1086 + } 1.1087 +#ifdef INET 1.1088 + sin6 = (struct sockaddr_in6 *)addr; 1.1089 + if (SCTP_IPV6_V6ONLY(inp6)) { 1.1090 + /* 1.1091 + * if IPV6_V6ONLY flag, we discard datagrams destined to a 1.1092 + * v4 addr or v4-mapped addr 1.1093 + */ 1.1094 + if (addr->sa_family == AF_INET) { 1.1095 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1096 + return (EINVAL); 1.1097 + } 1.1098 + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1.1099 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1100 + return (EINVAL); 1.1101 + } 1.1102 + } 1.1103 + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1.1104 + struct sockaddr_in sin; 1.1105 + 1.1106 + /* convert v4-mapped into v4 addr and send */ 1.1107 + in6_sin6_2_sin(&sin, sin6); 1.1108 + return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p)); 1.1109 + } 1.1110 +#endif /* INET */ 1.1111 +connected_type: 1.1112 + /* now what about control */ 1.1113 + if (control) { 1.1114 + if (inp->control) { 1.1115 + SCTP_PRINTF("huh? control set?\n"); 1.1116 + SCTP_RELEASE_PKT(inp->control); 1.1117 + inp->control = NULL; 1.1118 + } 1.1119 + inp->control = control; 1.1120 + } 1.1121 + /* Place the data */ 1.1122 + if (inp->pkt) { 1.1123 + SCTP_BUF_NEXT(inp->pkt_last) = m; 1.1124 + inp->pkt_last = m; 1.1125 + } else { 1.1126 + inp->pkt_last = inp->pkt = m; 1.1127 + } 1.1128 + if ( 1.1129 +#if defined(__FreeBSD__) || defined(__APPLE__) 1.1130 + /* FreeBSD and MacOSX uses a flag passed */ 1.1131 + ((flags & PRUS_MORETOCOME) == 0) 1.1132 +#else 1.1133 + 1 /* Open BSD does not have any "more to come" 1.1134 + * indication */ 1.1135 +#endif 1.1136 + ) { 1.1137 + /* 1.1138 + * note with the current version this code will only be used 1.1139 + * by OpenBSD, NetBSD and FreeBSD have methods for 1.1140 + * re-defining sosend() to use sctp_sosend(). One can 1.1141 + * optionaly switch back to this code (by changing back the 1.1142 + * defininitions but this is not advisable. 1.1143 + */ 1.1144 + int ret; 1.1145 + 1.1146 + ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 1.1147 + inp->pkt = NULL; 1.1148 + inp->control = NULL; 1.1149 + return (ret); 1.1150 + } else { 1.1151 + return (0); 1.1152 + } 1.1153 +} 1.1154 +#endif 1.1155 + 1.1156 +#if defined(__FreeBSD__) && __FreeBSD_version >= 500000 1.1157 +static int 1.1158 +sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 1.1159 +{ 1.1160 +#elif defined(__FreeBSD__) || defined(__APPLE__) 1.1161 +static int 1.1162 +sctp6_connect(struct socket *so, struct sockaddr *addr, struct proc *p) 1.1163 +{ 1.1164 +#elif defined(__Panda__) 1.1165 +int 1.1166 +sctp6_connect(struct socket *so, struct sockaddr *addr, void *p) 1.1167 +{ 1.1168 +#elif defined(__Windows__) 1.1169 +static int 1.1170 +sctp6_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p) 1.1171 +{ 1.1172 +#elif defined(__Userspace__) 1.1173 +int 1.1174 +sctp6_connect(struct socket *so, struct sockaddr *addr) 1.1175 +{ 1.1176 + void *p = NULL; 1.1177 +#else 1.1178 +static int 1.1179 +sctp6_connect(struct socket *so, struct mbuf *nam, struct proc *p) 1.1180 +{ 1.1181 + struct sockaddr *addr = mtod(nam, struct sockaddr *); 1.1182 +#endif 1.1183 + uint32_t vrf_id; 1.1184 + int error = 0; 1.1185 + struct sctp_inpcb *inp; 1.1186 + struct sctp_tcb *stcb; 1.1187 +#ifdef INET 1.1188 + struct in6pcb *inp6; 1.1189 + struct sockaddr_in6 *sin6; 1.1190 + struct sockaddr_storage ss; 1.1191 +#endif 1.1192 + 1.1193 +#ifdef INET 1.1194 + inp6 = (struct in6pcb *)so->so_pcb; 1.1195 +#endif 1.1196 + inp = (struct sctp_inpcb *)so->so_pcb; 1.1197 + if (inp == NULL) { 1.1198 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1.1199 + return (ECONNRESET); /* I made the same as TCP since we are 1.1200 + * not setup? */ 1.1201 + } 1.1202 + if (addr == NULL) { 1.1203 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1204 + return (EINVAL); 1.1205 + } 1.1206 +#if !defined(__Windows__) 1.1207 + switch (addr->sa_family) { 1.1208 +#ifdef INET 1.1209 + case AF_INET: 1.1210 +#ifdef HAVE_SA_LEN 1.1211 + if (addr->sa_len != sizeof(struct sockaddr_in)) { 1.1212 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1213 + return (EINVAL); 1.1214 + } 1.1215 +#endif 1.1216 + break; 1.1217 +#endif 1.1218 +#ifdef INET6 1.1219 + case AF_INET6: 1.1220 +#ifdef HAVE_SA_LEN 1.1221 + if (addr->sa_len != sizeof(struct sockaddr_in6)) { 1.1222 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1223 + return (EINVAL); 1.1224 + } 1.1225 +#endif 1.1226 + break; 1.1227 +#endif 1.1228 + default: 1.1229 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1230 + return (EINVAL); 1.1231 + } 1.1232 +#endif 1.1233 + 1.1234 + vrf_id = inp->def_vrf_id; 1.1235 + SCTP_ASOC_CREATE_LOCK(inp); 1.1236 + SCTP_INP_RLOCK(inp); 1.1237 + if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1.1238 + SCTP_PCB_FLAGS_UNBOUND) { 1.1239 + /* Bind a ephemeral port */ 1.1240 + SCTP_INP_RUNLOCK(inp); 1.1241 + error = sctp6_bind(so, NULL, p); 1.1242 + if (error) { 1.1243 + SCTP_ASOC_CREATE_UNLOCK(inp); 1.1244 + 1.1245 + return (error); 1.1246 + } 1.1247 + SCTP_INP_RLOCK(inp); 1.1248 + } 1.1249 + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1.1250 + (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1.1251 + /* We are already connected AND the TCP model */ 1.1252 + SCTP_INP_RUNLOCK(inp); 1.1253 + SCTP_ASOC_CREATE_UNLOCK(inp); 1.1254 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE); 1.1255 + return (EADDRINUSE); 1.1256 + } 1.1257 +#ifdef INET 1.1258 + sin6 = (struct sockaddr_in6 *)addr; 1.1259 + if (SCTP_IPV6_V6ONLY(inp6)) { 1.1260 + /* 1.1261 + * if IPV6_V6ONLY flag, ignore connections destined to a v4 1.1262 + * addr or v4-mapped addr 1.1263 + */ 1.1264 + if (addr->sa_family == AF_INET) { 1.1265 + SCTP_INP_RUNLOCK(inp); 1.1266 + SCTP_ASOC_CREATE_UNLOCK(inp); 1.1267 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1268 + return (EINVAL); 1.1269 + } 1.1270 + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1.1271 + SCTP_INP_RUNLOCK(inp); 1.1272 + SCTP_ASOC_CREATE_UNLOCK(inp); 1.1273 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1274 + return (EINVAL); 1.1275 + } 1.1276 + } 1.1277 + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1.1278 + /* convert v4-mapped into v4 addr */ 1.1279 + in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6); 1.1280 + addr = (struct sockaddr *)&ss; 1.1281 + } 1.1282 +#endif /* INET */ 1.1283 + /* Now do we connect? */ 1.1284 + if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1.1285 + stcb = LIST_FIRST(&inp->sctp_asoc_list); 1.1286 + if (stcb) { 1.1287 + SCTP_TCB_UNLOCK(stcb); 1.1288 + } 1.1289 + SCTP_INP_RUNLOCK(inp); 1.1290 + } else { 1.1291 + SCTP_INP_RUNLOCK(inp); 1.1292 + SCTP_INP_WLOCK(inp); 1.1293 + SCTP_INP_INCR_REF(inp); 1.1294 + SCTP_INP_WUNLOCK(inp); 1.1295 + stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 1.1296 + if (stcb == NULL) { 1.1297 + SCTP_INP_WLOCK(inp); 1.1298 + SCTP_INP_DECR_REF(inp); 1.1299 + SCTP_INP_WUNLOCK(inp); 1.1300 + } 1.1301 + } 1.1302 + 1.1303 + if (stcb != NULL) { 1.1304 + /* Already have or am bring up an association */ 1.1305 + SCTP_ASOC_CREATE_UNLOCK(inp); 1.1306 + SCTP_TCB_UNLOCK(stcb); 1.1307 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY); 1.1308 + return (EALREADY); 1.1309 + } 1.1310 + /* We are GOOD to go */ 1.1311 + stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); 1.1312 + SCTP_ASOC_CREATE_UNLOCK(inp); 1.1313 + if (stcb == NULL) { 1.1314 + /* Gak! no memory */ 1.1315 + return (error); 1.1316 + } 1.1317 + if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1.1318 + stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1.1319 + /* Set the connected flag so we can queue data */ 1.1320 + soisconnecting(so); 1.1321 + } 1.1322 + stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 1.1323 + (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1.1324 + 1.1325 + /* initialize authentication parameters for the assoc */ 1.1326 + sctp_initialize_auth_params(inp, stcb); 1.1327 + 1.1328 + sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 1.1329 + SCTP_TCB_UNLOCK(stcb); 1.1330 + return (error); 1.1331 +} 1.1332 + 1.1333 +static int 1.1334 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1335 +sctp6_getaddr(struct socket *so, struct sockaddr **addr) 1.1336 +{ 1.1337 + struct sockaddr_in6 *sin6; 1.1338 +#elif defined(__Panda__) 1.1339 +sctp6_getaddr(struct socket *so, struct sockaddr *addr) 1.1340 +{ 1.1341 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 1.1342 +#else 1.1343 +sctp6_getaddr(struct socket *so, struct mbuf *nam) 1.1344 +{ 1.1345 + struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *); 1.1346 +#endif 1.1347 + struct sctp_inpcb *inp; 1.1348 + uint32_t vrf_id; 1.1349 + struct sctp_ifa *sctp_ifa; 1.1350 + 1.1351 +#ifdef SCTP_KAME 1.1352 + int error; 1.1353 +#endif /* SCTP_KAME */ 1.1354 + 1.1355 + /* 1.1356 + * Do the malloc first in case it blocks. 1.1357 + */ 1.1358 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1359 + SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6)); 1.1360 + if (sin6 == NULL) 1.1361 + return (ENOMEM); 1.1362 +#elif defined(__Panda__) 1.1363 + bzero(sin6, sizeof(*sin6)); 1.1364 +#else 1.1365 + SCTP_BUF_LEN(nam) = sizeof(*sin6); 1.1366 + bzero(sin6, sizeof(*sin6)); 1.1367 +#endif 1.1368 + sin6->sin6_family = AF_INET6; 1.1369 +#ifdef HAVE_SIN6_LEN 1.1370 + sin6->sin6_len = sizeof(*sin6); 1.1371 +#endif 1.1372 + 1.1373 + inp = (struct sctp_inpcb *)so->so_pcb; 1.1374 + if (inp == NULL) { 1.1375 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1376 + SCTP_FREE_SONAME(sin6); 1.1377 +#endif 1.1378 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1.1379 + return (ECONNRESET); 1.1380 + } 1.1381 + SCTP_INP_RLOCK(inp); 1.1382 + sin6->sin6_port = inp->sctp_lport; 1.1383 + if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1.1384 + /* For the bound all case you get back 0 */ 1.1385 + if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1.1386 + struct sctp_tcb *stcb; 1.1387 + struct sockaddr_in6 *sin_a6; 1.1388 + struct sctp_nets *net; 1.1389 + int fnd; 1.1390 + stcb = LIST_FIRST(&inp->sctp_asoc_list); 1.1391 + if (stcb == NULL) { 1.1392 + goto notConn6; 1.1393 + } 1.1394 + fnd = 0; 1.1395 + sin_a6 = NULL; 1.1396 + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1.1397 + sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1.1398 + if (sin_a6 == NULL) 1.1399 + /* this will make coverity happy */ 1.1400 + continue; 1.1401 + 1.1402 + if (sin_a6->sin6_family == AF_INET6) { 1.1403 + fnd = 1; 1.1404 + break; 1.1405 + } 1.1406 + } 1.1407 + if ((!fnd) || (sin_a6 == NULL)) { 1.1408 + /* punt */ 1.1409 + goto notConn6; 1.1410 + } 1.1411 + vrf_id = inp->def_vrf_id; 1.1412 + sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *)&net->ro, net, 0, vrf_id); 1.1413 + if (sctp_ifa) { 1.1414 + sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr; 1.1415 + } 1.1416 + } else { 1.1417 + /* For the bound all case you get back 0 */ 1.1418 + notConn6: 1.1419 + memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); 1.1420 + } 1.1421 + } else { 1.1422 + /* Take the first IPv6 address in the list */ 1.1423 + struct sctp_laddr *laddr; 1.1424 + int fnd = 0; 1.1425 + 1.1426 + LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1.1427 + if (laddr->ifa->address.sa.sa_family == AF_INET6) { 1.1428 + struct sockaddr_in6 *sin_a; 1.1429 + 1.1430 + sin_a = (struct sockaddr_in6 *)&laddr->ifa->address.sin6; 1.1431 + sin6->sin6_addr = sin_a->sin6_addr; 1.1432 + fnd = 1; 1.1433 + break; 1.1434 + } 1.1435 + } 1.1436 + if (!fnd) { 1.1437 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1438 + SCTP_FREE_SONAME(sin6); 1.1439 +#endif 1.1440 + SCTP_INP_RUNLOCK(inp); 1.1441 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1.1442 + return (ENOENT); 1.1443 + } 1.1444 + } 1.1445 + SCTP_INP_RUNLOCK(inp); 1.1446 + /* Scoping things for v6 */ 1.1447 +#ifdef SCTP_EMBEDDED_V6_SCOPE 1.1448 +#ifdef SCTP_KAME 1.1449 + if ((error = sa6_recoverscope(sin6)) != 0) { 1.1450 + SCTP_FREE_SONAME(sin6); 1.1451 + return (error); 1.1452 + } 1.1453 +#else 1.1454 + if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) 1.1455 + /* skip ifp check below */ 1.1456 + in6_recoverscope(sin6, &sin6->sin6_addr, NULL); 1.1457 + else 1.1458 + sin6->sin6_scope_id = 0; /* XXX */ 1.1459 +#endif /* SCTP_KAME */ 1.1460 +#endif /* SCTP_EMBEDDED_V6_SCOPE */ 1.1461 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1462 + (*addr) = (struct sockaddr *)sin6; 1.1463 +#endif 1.1464 + return (0); 1.1465 +} 1.1466 + 1.1467 +static int 1.1468 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1469 +sctp6_peeraddr(struct socket *so, struct sockaddr **addr) 1.1470 +{ 1.1471 + struct sockaddr_in6 *sin6; 1.1472 +#elif defined(__Panda__) 1.1473 +sctp6_peeraddr(struct socket *so, struct sockaddr *addr) 1.1474 +{ 1.1475 + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 1.1476 +#else 1.1477 +sctp6_peeraddr(struct socket *so, struct mbuf *nam) 1.1478 +{ 1.1479 + struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *); 1.1480 +#endif 1.1481 + int fnd; 1.1482 + struct sockaddr_in6 *sin_a6; 1.1483 + struct sctp_inpcb *inp; 1.1484 + struct sctp_tcb *stcb; 1.1485 + struct sctp_nets *net; 1.1486 +#ifdef SCTP_KAME 1.1487 + int error; 1.1488 +#endif 1.1489 + 1.1490 + /* Do the malloc first in case it blocks. */ 1.1491 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1492 + SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 1.1493 + if (sin6 == NULL) 1.1494 + return (ENOMEM); 1.1495 +#elif defined(__Panda__) 1.1496 + memset(sin6, 0, sizeof(*sin6)); 1.1497 +#else 1.1498 + SCTP_BUF_LEN(nam) = sizeof(*sin6); 1.1499 + memset(sin6, 0, sizeof(*sin6)); 1.1500 +#endif 1.1501 + sin6->sin6_family = AF_INET6; 1.1502 +#ifdef HAVE_SIN6_LEN 1.1503 + sin6->sin6_len = sizeof(*sin6); 1.1504 +#endif 1.1505 + 1.1506 + inp = (struct sctp_inpcb *)so->so_pcb; 1.1507 + if ((inp == NULL) || 1.1508 + ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 1.1509 + /* UDP type and listeners will drop out here */ 1.1510 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1511 + SCTP_FREE_SONAME(sin6); 1.1512 +#endif 1.1513 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN); 1.1514 + return (ENOTCONN); 1.1515 + } 1.1516 + SCTP_INP_RLOCK(inp); 1.1517 + stcb = LIST_FIRST(&inp->sctp_asoc_list); 1.1518 + if (stcb) { 1.1519 + SCTP_TCB_LOCK(stcb); 1.1520 + } 1.1521 + SCTP_INP_RUNLOCK(inp); 1.1522 + if (stcb == NULL) { 1.1523 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1524 + SCTP_FREE_SONAME(sin6); 1.1525 +#endif 1.1526 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1.1527 + return (ECONNRESET); 1.1528 + } 1.1529 + fnd = 0; 1.1530 + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1.1531 + sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1.1532 + if (sin_a6->sin6_family == AF_INET6) { 1.1533 + fnd = 1; 1.1534 + sin6->sin6_port = stcb->rport; 1.1535 + sin6->sin6_addr = sin_a6->sin6_addr; 1.1536 + break; 1.1537 + } 1.1538 + } 1.1539 + SCTP_TCB_UNLOCK(stcb); 1.1540 + if (!fnd) { 1.1541 + /* No IPv4 address */ 1.1542 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1543 + SCTP_FREE_SONAME(sin6); 1.1544 +#endif 1.1545 + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1.1546 + return (ENOENT); 1.1547 + } 1.1548 +#ifdef SCTP_EMBEDDED_V6_SCOPE 1.1549 +#ifdef SCTP_KAME 1.1550 + if ((error = sa6_recoverscope(sin6)) != 0) 1.1551 + return (error); 1.1552 +#else 1.1553 + in6_recoverscope(sin6, &sin6->sin6_addr, NULL); 1.1554 +#endif /* SCTP_KAME */ 1.1555 +#endif /* SCTP_EMBEDDED_V6_SCOPE */ 1.1556 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1557 + *addr = (struct sockaddr *)sin6; 1.1558 +#endif 1.1559 + return (0); 1.1560 +} 1.1561 + 1.1562 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1563 +static int 1.1564 +sctp6_in6getaddr(struct socket *so, struct sockaddr **nam) 1.1565 +{ 1.1566 +#ifdef INET 1.1567 + struct sockaddr *addr; 1.1568 +#endif 1.1569 +#elif defined(__Panda__) 1.1570 +int 1.1571 +sctp6_in6getaddr(struct socket *so, struct sockaddr *nam, uint32_t *namelen) 1.1572 +{ 1.1573 + struct sockaddr *addr = nam; 1.1574 +#elif defined(__Userspace__) 1.1575 +int 1.1576 +sctp6_in6getaddr(struct socket *so, struct mbuf *nam) 1.1577 +{ 1.1578 +#ifdef INET 1.1579 + struct sockaddr *addr = mtod(nam, struct sockaddr *); 1.1580 +#endif 1.1581 +#else 1.1582 +static int 1.1583 +sctp6_in6getaddr(struct socket *so, struct mbuf *nam) 1.1584 +{ 1.1585 +#ifdef INET 1.1586 + struct sockaddr *addr = mtod(nam, struct sockaddr *); 1.1587 +#endif 1.1588 +#endif 1.1589 + struct in6pcb *inp6 = sotoin6pcb(so); 1.1590 + int error; 1.1591 + 1.1592 + if (inp6 == NULL) { 1.1593 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1594 + return (EINVAL); 1.1595 + } 1.1596 + 1.1597 + /* allow v6 addresses precedence */ 1.1598 + error = sctp6_getaddr(so, nam); 1.1599 +#ifdef INET 1.1600 + if (error) { 1.1601 + /* try v4 next if v6 failed */ 1.1602 + error = sctp_ingetaddr(so, nam); 1.1603 + if (error) { 1.1604 + return (error); 1.1605 + } 1.1606 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1607 + addr = *nam; 1.1608 +#endif 1.1609 + /* if I'm V6ONLY, convert it to v4-mapped */ 1.1610 + if (SCTP_IPV6_V6ONLY(inp6)) { 1.1611 + struct sockaddr_in6 sin6; 1.1612 + 1.1613 + in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1.1614 + memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1.1615 + } 1.1616 + } 1.1617 +#endif 1.1618 +#if defined(__Panda__) 1.1619 + *namelen = nam->sa_len; 1.1620 +#endif 1.1621 + return (error); 1.1622 +} 1.1623 + 1.1624 + 1.1625 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1626 +static int 1.1627 +sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam) 1.1628 +{ 1.1629 +#ifdef INET 1.1630 + struct sockaddr *addr; 1.1631 +#endif 1.1632 +#elif defined(__Panda__) 1.1633 +int 1.1634 +sctp6_getpeeraddr(struct socket *so, struct sockaddr *nam, uint32_t *namelen) 1.1635 +{ 1.1636 + struct sockaddr *addr = (struct sockaddr *)nam; 1.1637 +#elif defined(__Userspace__) 1.1638 +int 1.1639 +sctp6_getpeeraddr(struct socket *so, struct mbuf *nam) 1.1640 +{ 1.1641 +#ifdef INET 1.1642 + struct sockaddr *addr = mtod(nam, struct sockaddr *); 1.1643 +#endif 1.1644 +#else 1.1645 +static 1.1646 +int 1.1647 +sctp6_getpeeraddr(struct socket *so, struct mbuf *nam) 1.1648 +{ 1.1649 +#ifdef INET 1.1650 + struct sockaddr *addr = mtod(nam, struct sockaddr *); 1.1651 +#endif 1.1652 + 1.1653 +#endif 1.1654 + struct in6pcb *inp6 = sotoin6pcb(so); 1.1655 + int error; 1.1656 + 1.1657 + if (inp6 == NULL) { 1.1658 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1659 + return (EINVAL); 1.1660 + } 1.1661 + 1.1662 + /* allow v6 addresses precedence */ 1.1663 + error = sctp6_peeraddr(so, nam); 1.1664 +#ifdef INET 1.1665 + if (error) { 1.1666 + /* try v4 next if v6 failed */ 1.1667 + error = sctp_peeraddr(so, nam); 1.1668 + if (error) { 1.1669 + return (error); 1.1670 + } 1.1671 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1672 + addr = *nam; 1.1673 +#endif 1.1674 + /* if I'm V6ONLY, convert it to v4-mapped */ 1.1675 + if (SCTP_IPV6_V6ONLY(inp6)) { 1.1676 + struct sockaddr_in6 sin6; 1.1677 + 1.1678 + in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1.1679 + memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1.1680 + } 1.1681 + } 1.1682 +#endif 1.1683 +#if defined(__Panda__) 1.1684 + *namelen = nam->sa_len; 1.1685 +#endif 1.1686 + return (error); 1.1687 +} 1.1688 + 1.1689 +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) 1.1690 +struct pr_usrreqs sctp6_usrreqs = { 1.1691 +#if defined(__FreeBSD__) 1.1692 + .pru_abort = sctp6_abort, 1.1693 + .pru_accept = sctp_accept, 1.1694 + .pru_attach = sctp6_attach, 1.1695 + .pru_bind = sctp6_bind, 1.1696 + .pru_connect = sctp6_connect, 1.1697 + .pru_control = in6_control, 1.1698 +#if __FreeBSD_version >= 690000 1.1699 + .pru_close = sctp6_close, 1.1700 + .pru_detach = sctp6_close, 1.1701 + .pru_sopoll = sopoll_generic, 1.1702 + .pru_flush = sctp_flush, 1.1703 +#else 1.1704 + .pru_detach = sctp6_detach, 1.1705 + .pru_sopoll = sopoll, 1.1706 +#endif 1.1707 + .pru_disconnect = sctp6_disconnect, 1.1708 + .pru_listen = sctp_listen, 1.1709 + .pru_peeraddr = sctp6_getpeeraddr, 1.1710 + .pru_send = sctp6_send, 1.1711 + .pru_shutdown = sctp_shutdown, 1.1712 + .pru_sockaddr = sctp6_in6getaddr, 1.1713 + .pru_sosend = sctp_sosend, 1.1714 + .pru_soreceive = sctp_soreceive 1.1715 +#elif defined(__APPLE__) 1.1716 + .pru_abort = sctp6_abort, 1.1717 + .pru_accept = sctp_accept, 1.1718 + .pru_attach = sctp6_attach, 1.1719 + .pru_bind = sctp6_bind, 1.1720 + .pru_connect = sctp6_connect, 1.1721 + .pru_connect2 = pru_connect2_notsupp, 1.1722 + .pru_control = in6_control, 1.1723 + .pru_detach = sctp6_detach, 1.1724 + .pru_disconnect = sctp6_disconnect, 1.1725 + .pru_listen = sctp_listen, 1.1726 + .pru_peeraddr = sctp6_getpeeraddr, 1.1727 + .pru_rcvd = NULL, 1.1728 + .pru_rcvoob = pru_rcvoob_notsupp, 1.1729 + .pru_send = sctp6_send, 1.1730 + .pru_sense = pru_sense_null, 1.1731 + .pru_shutdown = sctp_shutdown, 1.1732 + .pru_sockaddr = sctp6_in6getaddr, 1.1733 + .pru_sosend = sctp_sosend, 1.1734 + .pru_soreceive = sctp_soreceive, 1.1735 + .pru_sopoll = sopoll 1.1736 +#elif defined(__Windows__) 1.1737 + sctp6_abort, 1.1738 + sctp_accept, 1.1739 + sctp6_attach, 1.1740 + sctp6_bind, 1.1741 + sctp6_connect, 1.1742 + pru_connect2_notsupp, 1.1743 + NULL, 1.1744 + NULL, 1.1745 + sctp6_disconnect, 1.1746 + sctp_listen, 1.1747 + sctp6_getpeeraddr, 1.1748 + NULL, 1.1749 + pru_rcvoob_notsupp, 1.1750 + NULL, 1.1751 + pru_sense_null, 1.1752 + sctp_shutdown, 1.1753 + sctp_flush, 1.1754 + sctp6_in6getaddr, 1.1755 + sctp_sosend, 1.1756 + sctp_soreceive, 1.1757 + sopoll_generic, 1.1758 + NULL, 1.1759 + sctp6_close 1.1760 +#endif 1.1761 +}; 1.1762 + 1.1763 +#elif !defined(__Panda__) && !defined(__Userspace__) 1.1764 +int 1.1765 +sctp6_usrreq(so, req, m, nam, control, p) 1.1766 + struct socket *so; 1.1767 + int req; 1.1768 + struct mbuf *m, *nam, *control; 1.1769 + struct proc *p; 1.1770 +{ 1.1771 + int s; 1.1772 + int error = 0; 1.1773 + int family; 1.1774 + uint32_t vrf_id; 1.1775 + family = so->so_proto->pr_domain->dom_family; 1.1776 + 1.1777 + if (req == PRU_CONTROL) { 1.1778 + switch (family) { 1.1779 + case PF_INET: 1.1780 + error = in_control(so, (long)m, (caddr_t)nam, 1.1781 + (struct ifnet *)control 1.1782 + ); 1.1783 +#ifdef INET6 1.1784 + case PF_INET6: 1.1785 + error = in6_control(so, (long)m, (caddr_t)nam, 1.1786 + (struct ifnet *)control, p); 1.1787 +#endif 1.1788 + default: 1.1789 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT); 1.1790 + error = EAFNOSUPPORT; 1.1791 + } 1.1792 + return (error); 1.1793 + } 1.1794 + switch (req) { 1.1795 + case PRU_ATTACH: 1.1796 + error = sctp6_attach(so, family, p); 1.1797 + break; 1.1798 + case PRU_DETACH: 1.1799 + error = sctp6_detach(so); 1.1800 + break; 1.1801 + case PRU_BIND: 1.1802 + if (nam == NULL) { 1.1803 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1804 + return (EINVAL); 1.1805 + } 1.1806 + error = sctp6_bind(so, nam, p); 1.1807 + break; 1.1808 + case PRU_LISTEN: 1.1809 + error = sctp_listen(so, p); 1.1810 + break; 1.1811 + case PRU_CONNECT: 1.1812 + if (nam == NULL) { 1.1813 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1814 + return (EINVAL); 1.1815 + } 1.1816 + error = sctp6_connect(so, nam, p); 1.1817 + break; 1.1818 + case PRU_DISCONNECT: 1.1819 + error = sctp6_disconnect(so); 1.1820 + break; 1.1821 + case PRU_ACCEPT: 1.1822 + if (nam == NULL) { 1.1823 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1.1824 + return (EINVAL); 1.1825 + } 1.1826 + error = sctp_accept(so, nam); 1.1827 + break; 1.1828 + case PRU_SHUTDOWN: 1.1829 + error = sctp_shutdown(so); 1.1830 + break; 1.1831 + 1.1832 + case PRU_RCVD: 1.1833 + /* 1.1834 + * For OpenBSD and NetBSD, this is real ugly. The (mbuf *) 1.1835 + * nam that is passed (by soreceive()) is the int flags cast 1.1836 + * as a (mbuf *) yuck! 1.1837 + */ 1.1838 + error = sctp_usr_recvd(so, (int)((long)nam)); 1.1839 + break; 1.1840 + 1.1841 + case PRU_SEND: 1.1842 + /* Flags are ignored */ 1.1843 + error = sctp6_send(so, 0, m, nam, control, p); 1.1844 + break; 1.1845 + case PRU_ABORT: 1.1846 + error = sctp6_abort(so); 1.1847 + break; 1.1848 + 1.1849 + case PRU_SENSE: 1.1850 + error = 0; 1.1851 + break; 1.1852 + case PRU_RCVOOB: 1.1853 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT); 1.1854 + error = EAFNOSUPPORT; 1.1855 + break; 1.1856 + case PRU_SENDOOB: 1.1857 + SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EAFNOSUPPORT); 1.1858 + error = EAFNOSUPPORT; 1.1859 + break; 1.1860 + case PRU_PEERADDR: 1.1861 + error = sctp6_getpeeraddr(so, nam); 1.1862 + break; 1.1863 + case PRU_SOCKADDR: 1.1864 + error = sctp6_in6getaddr(so, nam); 1.1865 + break; 1.1866 + case PRU_SLOWTIMO: 1.1867 + error = 0; 1.1868 + break; 1.1869 + default: 1.1870 + break; 1.1871 + } 1.1872 + return (error); 1.1873 +} 1.1874 +#endif 1.1875 +#endif