netwerk/sctp/src/netinet6/sctp6_usrreq.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

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

mercurial