sctp6_usrreq.c revision 283703
1/*- 2 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. 3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * a) Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * b) Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the distribution. 15 * 16 * c) Neither the name of Cisco Systems, Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: stable/10/sys/netinet6/sctp6_usrreq.c 283703 2015-05-29 11:25:38Z tuexen $"); 35 36#include <netinet/sctp_os.h> 37#ifdef INET6 38#include <sys/proc.h> 39#include <netinet/sctp_pcb.h> 40#include <netinet/sctp_header.h> 41#include <netinet/sctp_var.h> 42#ifdef INET6 43#include <netinet6/sctp6_var.h> 44#endif 45#include <netinet/sctp_sysctl.h> 46#include <netinet/sctp_output.h> 47#include <netinet/sctp_uio.h> 48#include <netinet/sctp_asconf.h> 49#include <netinet/sctputil.h> 50#include <netinet/sctp_indata.h> 51#include <netinet/sctp_timer.h> 52#include <netinet/sctp_auth.h> 53#include <netinet/sctp_input.h> 54#include <netinet/sctp_output.h> 55#include <netinet/sctp_bsd_addr.h> 56#include <netinet/sctp_crc32.h> 57#include <netinet/udp.h> 58 59#ifdef IPSEC 60#include <netipsec/ipsec.h> 61#ifdef INET6 62#include <netipsec/ipsec6.h> 63#endif /* INET6 */ 64#endif /* IPSEC */ 65 66extern struct protosw inetsw[]; 67 68int 69sctp6_input_with_port(struct mbuf **i_pak, int *offp, uint16_t port) 70{ 71 struct mbuf *m; 72 int iphlen; 73 uint32_t vrf_id; 74 uint8_t ecn_bits; 75 struct sockaddr_in6 src, dst; 76 struct ip6_hdr *ip6; 77 struct sctphdr *sh; 78 struct sctp_chunkhdr *ch; 79 int length, offset; 80 81#if !defined(SCTP_WITH_NO_CSUM) 82 uint8_t compute_crc; 83 84#endif 85 uint32_t mflowid; 86 uint8_t mflowtype; 87 88 iphlen = *offp; 89 if (SCTP_GET_PKT_VRFID(*i_pak, vrf_id)) { 90 SCTP_RELEASE_PKT(*i_pak); 91 return (IPPROTO_DONE); 92 } 93 m = SCTP_HEADER_TO_CHAIN(*i_pak); 94#ifdef SCTP_MBUF_LOGGING 95 /* Log in any input mbufs */ 96 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { 97 struct mbuf *mat; 98 99 for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { 100 if (SCTP_BUF_IS_EXTENDED(mat)) { 101 sctp_log_mb(mat, SCTP_MBUF_INPUT); 102 } 103 } 104 } 105#endif 106#ifdef SCTP_PACKET_LOGGING 107 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LAST_PACKET_TRACING) { 108 sctp_packet_log(m); 109 } 110#endif 111 SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 112 "sctp6_input(): Packet of length %d received on %s with csum_flags 0x%b.\n", 113 m->m_pkthdr.len, 114 if_name(m->m_pkthdr.rcvif), 115 (int)m->m_pkthdr.csum_flags, CSUM_BITS); 116 mflowid = m->m_pkthdr.flowid; 117 mflowtype = M_HASHTYPE_GET(m); 118 SCTP_STAT_INCR(sctps_recvpackets); 119 SCTP_STAT_INCR_COUNTER64(sctps_inpackets); 120 /* Get IP, SCTP, and first chunk header together in the first mbuf. */ 121 offset = iphlen + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); 122 ip6 = mtod(m, struct ip6_hdr *); 123 IP6_EXTHDR_GET(sh, struct sctphdr *, m, iphlen, 124 (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))); 125 if (sh == NULL) { 126 SCTP_STAT_INCR(sctps_hdrops); 127 return (IPPROTO_DONE); 128 } 129 ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); 130 offset -= sizeof(struct sctp_chunkhdr); 131 memset(&src, 0, sizeof(struct sockaddr_in6)); 132 src.sin6_family = AF_INET6; 133 src.sin6_len = sizeof(struct sockaddr_in6); 134 src.sin6_port = sh->src_port; 135 src.sin6_addr = ip6->ip6_src; 136 if (in6_setscope(&src.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) { 137 goto out; 138 } 139 memset(&dst, 0, sizeof(struct sockaddr_in6)); 140 dst.sin6_family = AF_INET6; 141 dst.sin6_len = sizeof(struct sockaddr_in6); 142 dst.sin6_port = sh->dest_port; 143 dst.sin6_addr = ip6->ip6_dst; 144 if (in6_setscope(&dst.sin6_addr, m->m_pkthdr.rcvif, NULL) != 0) { 145 goto out; 146 } 147 if (faithprefix_p != NULL && (*faithprefix_p) (&dst.sin6_addr)) { 148 /* XXX send icmp6 host/port unreach? */ 149 goto out; 150 } 151 length = ntohs(ip6->ip6_plen) + iphlen; 152 /* Validate mbuf chain length with IP payload length. */ 153 if (SCTP_HEADER_LEN(m) != length) { 154 SCTPDBG(SCTP_DEBUG_INPUT1, 155 "sctp6_input() length:%d reported length:%d\n", length, SCTP_HEADER_LEN(m)); 156 SCTP_STAT_INCR(sctps_hdrops); 157 goto out; 158 } 159 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 160 goto out; 161 } 162 ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); 163#if defined(SCTP_WITH_NO_CSUM) 164 SCTP_STAT_INCR(sctps_recvnocrc); 165#else 166 if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { 167 SCTP_STAT_INCR(sctps_recvhwcrc); 168 compute_crc = 0; 169 } else { 170 SCTP_STAT_INCR(sctps_recvswcrc); 171 compute_crc = 1; 172 } 173#endif 174 sctp_common_input_processing(&m, iphlen, offset, length, 175 (struct sockaddr *)&src, 176 (struct sockaddr *)&dst, 177 sh, ch, 178#if !defined(SCTP_WITH_NO_CSUM) 179 compute_crc, 180#endif 181 ecn_bits, 182 mflowtype, mflowid, 183 vrf_id, port); 184out: 185 if (m) { 186 sctp_m_freem(m); 187 } 188 return (IPPROTO_DONE); 189} 190 191 192int 193sctp6_input(struct mbuf **i_pak, int *offp, int proto SCTP_UNUSED) 194{ 195 return (sctp6_input_with_port(i_pak, offp, 0)); 196} 197 198static void 199sctp6_notify_mbuf(struct sctp_inpcb *inp, struct icmp6_hdr *icmp6, 200 struct sctphdr *sh, struct sctp_tcb *stcb, struct sctp_nets *net) 201{ 202 uint32_t nxtsz; 203 204 if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 205 (icmp6 == NULL) || (sh == NULL)) { 206 goto out; 207 } 208 /* First do we even look at it? */ 209 if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) 210 goto out; 211 212 if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) { 213 /* not PACKET TO BIG */ 214 goto out; 215 } 216 /* 217 * ok we need to look closely. We could even get smarter and look at 218 * anyone that we sent to in case we get a different ICMP that tells 219 * us there is no way to reach a host, but for this impl, all we 220 * care about is MTU discovery. 221 */ 222 nxtsz = ntohl(icmp6->icmp6_mtu); 223 /* Stop any PMTU timer */ 224 sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1); 225 226 /* Adjust destination size limit */ 227 if (net->mtu > nxtsz) { 228 net->mtu = nxtsz; 229 if (net->port) { 230 net->mtu -= sizeof(struct udphdr); 231 } 232 } 233 /* now what about the ep? */ 234 if (stcb->asoc.smallest_mtu > nxtsz) { 235 struct sctp_tmit_chunk *chk; 236 237 /* Adjust that too */ 238 stcb->asoc.smallest_mtu = nxtsz; 239 /* now off to subtract IP_DF flag if needed */ 240 241 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 242 if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 243 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 244 } 245 } 246 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 247 if ((uint32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 248 /* 249 * For this guy we also mark for immediate 250 * resend since we sent to big of chunk 251 */ 252 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 253 if (chk->sent != SCTP_DATAGRAM_RESEND) 254 stcb->asoc.sent_queue_retran_cnt++; 255 chk->sent = SCTP_DATAGRAM_RESEND; 256 chk->rec.data.doing_fast_retransmit = 0; 257 258 chk->sent = SCTP_DATAGRAM_RESEND; 259 /* Clear any time so NO RTT is being done */ 260 chk->sent_rcv_time.tv_sec = 0; 261 chk->sent_rcv_time.tv_usec = 0; 262 stcb->asoc.total_flight -= chk->send_size; 263 net->flight_size -= chk->send_size; 264 } 265 } 266 } 267 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 268out: 269 if (stcb) { 270 SCTP_TCB_UNLOCK(stcb); 271 } 272} 273 274 275void 276sctp6_notify(struct sctp_inpcb *inp, 277 struct icmp6_hdr *icmph, 278 struct sctphdr *sh, 279 struct sockaddr *to, 280 struct sctp_tcb *stcb, 281 struct sctp_nets *net) 282{ 283#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 284 struct socket *so; 285 286#endif 287 288 /* protection */ 289 if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 290 (sh == NULL) || (to == NULL)) { 291 if (stcb) 292 SCTP_TCB_UNLOCK(stcb); 293 return; 294 } 295 /* First job is to verify the vtag matches what I would send */ 296 if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { 297 SCTP_TCB_UNLOCK(stcb); 298 return; 299 } 300 if (icmph->icmp6_type != ICMP_UNREACH) { 301 /* We only care about unreachable */ 302 SCTP_TCB_UNLOCK(stcb); 303 return; 304 } 305 if ((icmph->icmp6_code == ICMP_UNREACH_NET) || 306 (icmph->icmp6_code == ICMP_UNREACH_HOST) || 307 (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) || 308 (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) || 309 (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) || 310 (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) || 311 (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) || 312 (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) { 313 314 /* 315 * Hmm reachablity problems we must examine closely. If its 316 * not reachable, we may have lost a network. Or if there is 317 * NO protocol at the other end named SCTP. well we consider 318 * it a OOTB abort. 319 */ 320 if (net->dest_state & SCTP_ADDR_REACHABLE) { 321 /* Ok that destination is NOT reachable */ 322 net->dest_state &= ~SCTP_ADDR_REACHABLE; 323 net->dest_state &= ~SCTP_ADDR_PF; 324 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, 325 stcb, 0, (void *)net, SCTP_SO_NOT_LOCKED); 326 } 327 SCTP_TCB_UNLOCK(stcb); 328 } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) || 329 (icmph->icmp6_code == ICMP_UNREACH_PORT)) { 330 /* 331 * Here the peer is either playing tricks on us, including 332 * an address that belongs to someone who does not support 333 * SCTP OR was a userland implementation that shutdown and 334 * now is dead. In either case treat it like a OOTB abort 335 * with no TCB 336 */ 337 sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); 338#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 339 so = SCTP_INP_SO(inp); 340 atomic_add_int(&stcb->asoc.refcnt, 1); 341 SCTP_TCB_UNLOCK(stcb); 342 SCTP_SOCKET_LOCK(so, 1); 343 SCTP_TCB_LOCK(stcb); 344 atomic_subtract_int(&stcb->asoc.refcnt, 1); 345#endif 346 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); 347#if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 348 SCTP_SOCKET_UNLOCK(so, 1); 349 /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed. */ 350#endif 351 /* no need to unlock here, since the TCB is gone */ 352 } else { 353 SCTP_TCB_UNLOCK(stcb); 354 } 355} 356 357 358 359void 360sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d) 361{ 362 struct sctphdr sh; 363 struct ip6ctlparam *ip6cp = NULL; 364 uint32_t vrf_id; 365 366 vrf_id = SCTP_DEFAULT_VRFID; 367 368 if (pktdst->sa_family != AF_INET6 || 369 pktdst->sa_len != sizeof(struct sockaddr_in6)) 370 return; 371 372 if ((unsigned)cmd >= PRC_NCMDS) 373 return; 374 if (PRC_IS_REDIRECT(cmd)) { 375 d = NULL; 376 } else if (inet6ctlerrmap[cmd] == 0) { 377 return; 378 } 379 /* if the parameter is from icmp6, decode it. */ 380 if (d != NULL) { 381 ip6cp = (struct ip6ctlparam *)d; 382 } else { 383 ip6cp = (struct ip6ctlparam *)NULL; 384 } 385 386 if (ip6cp) { 387 /* 388 * XXX: We assume that when IPV6 is non NULL, M and OFF are 389 * valid. 390 */ 391 /* check if we can safely examine src and dst ports */ 392 struct sctp_inpcb *inp = NULL; 393 struct sctp_tcb *stcb = NULL; 394 struct sctp_nets *net = NULL; 395 struct sockaddr_in6 final; 396 397 if (ip6cp->ip6c_m == NULL) 398 return; 399 400 bzero(&sh, sizeof(sh)); 401 bzero(&final, sizeof(final)); 402 inp = NULL; 403 net = NULL; 404 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh), 405 (caddr_t)&sh); 406 ip6cp->ip6c_src->sin6_port = sh.src_port; 407 final.sin6_len = sizeof(final); 408 final.sin6_family = AF_INET6; 409 final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr; 410 final.sin6_port = sh.dest_port; 411 stcb = sctp_findassociation_addr_sa((struct sockaddr *)&final, 412 (struct sockaddr *)ip6cp->ip6c_src, 413 &inp, &net, 1, vrf_id); 414 /* inp's ref-count increased && stcb locked */ 415 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 416 if (cmd == PRC_MSGSIZE) { 417 sctp6_notify_mbuf(inp, 418 ip6cp->ip6c_icmp6, 419 &sh, 420 stcb, 421 net); 422 /* inp's ref-count reduced && stcb unlocked */ 423 } else { 424 sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh, 425 (struct sockaddr *)&final, 426 stcb, net); 427 /* inp's ref-count reduced && stcb unlocked */ 428 } 429 } else { 430 if (PRC_IS_REDIRECT(cmd) && inp) { 431 in6_rtchange((struct in6pcb *)inp, 432 inet6ctlerrmap[cmd]); 433 } 434 if (inp) { 435 /* reduce inp's ref-count */ 436 SCTP_INP_WLOCK(inp); 437 SCTP_INP_DECR_REF(inp); 438 SCTP_INP_WUNLOCK(inp); 439 } 440 if (stcb) 441 SCTP_TCB_UNLOCK(stcb); 442 } 443 } 444} 445 446/* 447 * this routine can probably be collasped into the one in sctp_userreq.c 448 * since they do the same thing and now we lookup with a sockaddr 449 */ 450static int 451sctp6_getcred(SYSCTL_HANDLER_ARGS) 452{ 453 struct xucred xuc; 454 struct sockaddr_in6 addrs[2]; 455 struct sctp_inpcb *inp; 456 struct sctp_nets *net; 457 struct sctp_tcb *stcb; 458 int error; 459 uint32_t vrf_id; 460 461 vrf_id = SCTP_DEFAULT_VRFID; 462 463 error = priv_check(req->td, PRIV_NETINET_GETCRED); 464 if (error) 465 return (error); 466 467 if (req->newlen != sizeof(addrs)) { 468 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 469 return (EINVAL); 470 } 471 if (req->oldlen != sizeof(struct ucred)) { 472 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 473 return (EINVAL); 474 } 475 error = SYSCTL_IN(req, addrs, sizeof(addrs)); 476 if (error) 477 return (error); 478 479 stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[1]), 480 sin6tosa(&addrs[0]), 481 &inp, &net, 1, vrf_id); 482 if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 483 if ((inp != NULL) && (stcb == NULL)) { 484 /* reduce ref-count */ 485 SCTP_INP_WLOCK(inp); 486 SCTP_INP_DECR_REF(inp); 487 goto cred_can_cont; 488 } 489 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 490 error = ENOENT; 491 goto out; 492 } 493 SCTP_TCB_UNLOCK(stcb); 494 /* 495 * We use the write lock here, only since in the error leg we need 496 * it. If we used RLOCK, then we would have to 497 * wlock/decr/unlock/rlock. Which in theory could create a hole. 498 * Better to use higher wlock. 499 */ 500 SCTP_INP_WLOCK(inp); 501cred_can_cont: 502 error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 503 if (error) { 504 SCTP_INP_WUNLOCK(inp); 505 goto out; 506 } 507 cru2x(inp->sctp_socket->so_cred, &xuc); 508 SCTP_INP_WUNLOCK(inp); 509 error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 510out: 511 return (error); 512} 513 514SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 515 0, 0, 516 sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection"); 517 518 519/* This is the same as the sctp_abort() could be made common */ 520static void 521sctp6_abort(struct socket *so) 522{ 523 struct sctp_inpcb *inp; 524 uint32_t flags; 525 526 inp = (struct sctp_inpcb *)so->so_pcb; 527 if (inp == NULL) { 528 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 529 return; 530 } 531sctp_must_try_again: 532 flags = inp->sctp_flags; 533#ifdef SCTP_LOG_CLOSING 534 sctp_log_closing(inp, NULL, 17); 535#endif 536 if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 537 (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 538#ifdef SCTP_LOG_CLOSING 539 sctp_log_closing(inp, NULL, 16); 540#endif 541 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 542 SCTP_CALLED_AFTER_CMPSET_OFCLOSE); 543 SOCK_LOCK(so); 544 SCTP_SB_CLEAR(so->so_snd); 545 /* 546 * same for the rcv ones, they are only here for the 547 * accounting/select. 548 */ 549 SCTP_SB_CLEAR(so->so_rcv); 550 /* Now null out the reference, we are completely detached. */ 551 so->so_pcb = NULL; 552 SOCK_UNLOCK(so); 553 } else { 554 flags = inp->sctp_flags; 555 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 556 goto sctp_must_try_again; 557 } 558 } 559 return; 560} 561 562static int 563sctp6_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) 564{ 565 struct in6pcb *inp6; 566 int error; 567 struct sctp_inpcb *inp; 568 uint32_t vrf_id = SCTP_DEFAULT_VRFID; 569 570 inp = (struct sctp_inpcb *)so->so_pcb; 571 if (inp != NULL) { 572 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 573 return (EINVAL); 574 } 575 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 576 error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); 577 if (error) 578 return (error); 579 } 580 error = sctp_inpcb_alloc(so, vrf_id); 581 if (error) 582 return (error); 583 inp = (struct sctp_inpcb *)so->so_pcb; 584 SCTP_INP_WLOCK(inp); 585 inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */ 586 inp6 = (struct in6pcb *)inp; 587 588 inp6->inp_vflag |= INP_IPV6; 589 inp6->in6p_hops = -1; /* use kernel default */ 590 inp6->in6p_cksum = -1; /* just to be sure */ 591#ifdef INET 592 /* 593 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6 594 * socket as well, because the socket may be bound to an IPv6 595 * wildcard address, which may match an IPv4-mapped IPv6 address. 596 */ 597 inp6->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); 598#endif 599 /* 600 * Hmm what about the IPSEC stuff that is missing here but in 601 * sctp_attach()? 602 */ 603 SCTP_INP_WUNLOCK(inp); 604 return (0); 605} 606 607static int 608sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 609{ 610 struct sctp_inpcb *inp; 611 struct in6pcb *inp6; 612 int error; 613 614 inp = (struct sctp_inpcb *)so->so_pcb; 615 if (inp == NULL) { 616 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 617 return (EINVAL); 618 } 619 if (addr) { 620 switch (addr->sa_family) { 621#ifdef INET 622 case AF_INET: 623 if (addr->sa_len != sizeof(struct sockaddr_in)) { 624 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 625 return (EINVAL); 626 } 627 break; 628#endif 629#ifdef INET6 630 case AF_INET6: 631 if (addr->sa_len != sizeof(struct sockaddr_in6)) { 632 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 633 return (EINVAL); 634 } 635 break; 636#endif 637 default: 638 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 639 return (EINVAL); 640 } 641 } 642 inp6 = (struct in6pcb *)inp; 643 inp6->inp_vflag &= ~INP_IPV4; 644 inp6->inp_vflag |= INP_IPV6; 645 if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) { 646 switch (addr->sa_family) { 647#ifdef INET 648 case AF_INET: 649 /* binding v4 addr to v6 socket, so reset flags */ 650 inp6->inp_vflag |= INP_IPV4; 651 inp6->inp_vflag &= ~INP_IPV6; 652 break; 653#endif 654#ifdef INET6 655 case AF_INET6: 656 { 657 struct sockaddr_in6 *sin6_p; 658 659 sin6_p = (struct sockaddr_in6 *)addr; 660 661 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) { 662 inp6->inp_vflag |= INP_IPV4; 663 } 664#ifdef INET 665 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 666 struct sockaddr_in sin; 667 668 in6_sin6_2_sin(&sin, sin6_p); 669 inp6->inp_vflag |= INP_IPV4; 670 inp6->inp_vflag &= ~INP_IPV6; 671 error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, NULL, p); 672 return (error); 673 } 674#endif 675 break; 676 } 677#endif 678 default: 679 break; 680 } 681 } else if (addr != NULL) { 682 struct sockaddr_in6 *sin6_p; 683 684 /* IPV6_V6ONLY socket */ 685#ifdef INET 686 if (addr->sa_family == AF_INET) { 687 /* can't bind v4 addr to v6 only socket! */ 688 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 689 return (EINVAL); 690 } 691#endif 692 sin6_p = (struct sockaddr_in6 *)addr; 693 694 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 695 /* can't bind v4-mapped addrs either! */ 696 /* NOTE: we don't support SIIT */ 697 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 698 return (EINVAL); 699 } 700 } 701 error = sctp_inpcb_bind(so, addr, NULL, p); 702 return (error); 703} 704 705 706static void 707sctp6_close(struct socket *so) 708{ 709 sctp_close(so); 710} 711 712/* This could be made common with sctp_detach() since they are identical */ 713 714static 715int 716sctp6_disconnect(struct socket *so) 717{ 718 return (sctp_disconnect(so)); 719} 720 721 722int 723sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 724 struct mbuf *control, struct thread *p); 725 726 727static int 728sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 729 struct mbuf *control, struct thread *p) 730{ 731 struct sctp_inpcb *inp; 732 struct in6pcb *inp6; 733 734#ifdef INET 735 struct sockaddr_in6 *sin6; 736 737#endif /* INET */ 738 /* No SPL needed since sctp_output does this */ 739 740 inp = (struct sctp_inpcb *)so->so_pcb; 741 if (inp == NULL) { 742 if (control) { 743 SCTP_RELEASE_PKT(control); 744 control = NULL; 745 } 746 SCTP_RELEASE_PKT(m); 747 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 748 return (EINVAL); 749 } 750 inp6 = (struct in6pcb *)inp; 751 /* 752 * For the TCP model we may get a NULL addr, if we are a connected 753 * socket thats ok. 754 */ 755 if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) && 756 (addr == NULL)) { 757 goto connected_type; 758 } 759 if (addr == NULL) { 760 SCTP_RELEASE_PKT(m); 761 if (control) { 762 SCTP_RELEASE_PKT(control); 763 control = NULL; 764 } 765 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EDESTADDRREQ); 766 return (EDESTADDRREQ); 767 } 768#ifdef INET 769 sin6 = (struct sockaddr_in6 *)addr; 770 if (SCTP_IPV6_V6ONLY(inp6)) { 771 /* 772 * if IPV6_V6ONLY flag, we discard datagrams destined to a 773 * v4 addr or v4-mapped addr 774 */ 775 if (addr->sa_family == AF_INET) { 776 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 777 return (EINVAL); 778 } 779 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 780 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 781 return (EINVAL); 782 } 783 } 784 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 785 struct sockaddr_in sin; 786 787 /* convert v4-mapped into v4 addr and send */ 788 in6_sin6_2_sin(&sin, sin6); 789 return (sctp_sendm(so, flags, m, (struct sockaddr *)&sin, control, p)); 790 } 791#endif /* INET */ 792connected_type: 793 /* now what about control */ 794 if (control) { 795 if (inp->control) { 796 SCTP_PRINTF("huh? control set?\n"); 797 SCTP_RELEASE_PKT(inp->control); 798 inp->control = NULL; 799 } 800 inp->control = control; 801 } 802 /* Place the data */ 803 if (inp->pkt) { 804 SCTP_BUF_NEXT(inp->pkt_last) = m; 805 inp->pkt_last = m; 806 } else { 807 inp->pkt_last = inp->pkt = m; 808 } 809 if ( 810 /* FreeBSD and MacOSX uses a flag passed */ 811 ((flags & PRUS_MORETOCOME) == 0) 812 ) { 813 /* 814 * note with the current version this code will only be used 815 * by OpenBSD, NetBSD and FreeBSD have methods for 816 * re-defining sosend() to use sctp_sosend(). One can 817 * optionaly switch back to this code (by changing back the 818 * defininitions but this is not advisable. 819 */ 820 int ret; 821 822 ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 823 inp->pkt = NULL; 824 inp->control = NULL; 825 return (ret); 826 } else { 827 return (0); 828 } 829} 830 831static int 832sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 833{ 834 uint32_t vrf_id; 835 int error = 0; 836 struct sctp_inpcb *inp; 837 struct sctp_tcb *stcb; 838 839#ifdef INET 840 struct in6pcb *inp6; 841 struct sockaddr_in6 *sin6; 842 union sctp_sockstore store; 843 844#endif 845 846#ifdef INET 847 inp6 = (struct in6pcb *)so->so_pcb; 848#endif 849 inp = (struct sctp_inpcb *)so->so_pcb; 850 if (inp == NULL) { 851 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 852 return (ECONNRESET); /* I made the same as TCP since we are 853 * not setup? */ 854 } 855 if (addr == NULL) { 856 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 857 return (EINVAL); 858 } 859 switch (addr->sa_family) { 860#ifdef INET 861 case AF_INET: 862 if (addr->sa_len != sizeof(struct sockaddr_in)) { 863 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 864 return (EINVAL); 865 } 866 break; 867#endif 868#ifdef INET6 869 case AF_INET6: 870 if (addr->sa_len != sizeof(struct sockaddr_in6)) { 871 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 872 return (EINVAL); 873 } 874 break; 875#endif 876 default: 877 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 878 return (EINVAL); 879 } 880 881 vrf_id = inp->def_vrf_id; 882 SCTP_ASOC_CREATE_LOCK(inp); 883 SCTP_INP_RLOCK(inp); 884 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 885 SCTP_PCB_FLAGS_UNBOUND) { 886 /* Bind a ephemeral port */ 887 SCTP_INP_RUNLOCK(inp); 888 error = sctp6_bind(so, NULL, p); 889 if (error) { 890 SCTP_ASOC_CREATE_UNLOCK(inp); 891 892 return (error); 893 } 894 SCTP_INP_RLOCK(inp); 895 } 896 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 897 (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 898 /* We are already connected AND the TCP model */ 899 SCTP_INP_RUNLOCK(inp); 900 SCTP_ASOC_CREATE_UNLOCK(inp); 901 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EADDRINUSE); 902 return (EADDRINUSE); 903 } 904#ifdef INET 905 sin6 = (struct sockaddr_in6 *)addr; 906 if (SCTP_IPV6_V6ONLY(inp6)) { 907 /* 908 * if IPV6_V6ONLY flag, ignore connections destined to a v4 909 * addr or v4-mapped addr 910 */ 911 if (addr->sa_family == AF_INET) { 912 SCTP_INP_RUNLOCK(inp); 913 SCTP_ASOC_CREATE_UNLOCK(inp); 914 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 915 return (EINVAL); 916 } 917 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 918 SCTP_INP_RUNLOCK(inp); 919 SCTP_ASOC_CREATE_UNLOCK(inp); 920 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 921 return (EINVAL); 922 } 923 } 924 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 925 /* convert v4-mapped into v4 addr */ 926 in6_sin6_2_sin(&store.sin, sin6); 927 addr = &store.sa; 928 } 929#endif /* INET */ 930 /* Now do we connect? */ 931 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 932 stcb = LIST_FIRST(&inp->sctp_asoc_list); 933 if (stcb) { 934 SCTP_TCB_UNLOCK(stcb); 935 } 936 SCTP_INP_RUNLOCK(inp); 937 } else { 938 SCTP_INP_RUNLOCK(inp); 939 SCTP_INP_WLOCK(inp); 940 SCTP_INP_INCR_REF(inp); 941 SCTP_INP_WUNLOCK(inp); 942 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 943 if (stcb == NULL) { 944 SCTP_INP_WLOCK(inp); 945 SCTP_INP_DECR_REF(inp); 946 SCTP_INP_WUNLOCK(inp); 947 } 948 } 949 950 if (stcb != NULL) { 951 /* Already have or am bring up an association */ 952 SCTP_ASOC_CREATE_UNLOCK(inp); 953 SCTP_TCB_UNLOCK(stcb); 954 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EALREADY); 955 return (EALREADY); 956 } 957 /* We are GOOD to go */ 958 stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); 959 SCTP_ASOC_CREATE_UNLOCK(inp); 960 if (stcb == NULL) { 961 /* Gak! no memory */ 962 return (error); 963 } 964 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 965 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 966 /* Set the connected flag so we can queue data */ 967 soisconnecting(so); 968 } 969 stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 970 (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 971 972 /* initialize authentication parameters for the assoc */ 973 sctp_initialize_auth_params(inp, stcb); 974 975 sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); 976 SCTP_TCB_UNLOCK(stcb); 977 return (error); 978} 979 980static int 981sctp6_getaddr(struct socket *so, struct sockaddr **addr) 982{ 983 struct sockaddr_in6 *sin6; 984 struct sctp_inpcb *inp; 985 uint32_t vrf_id; 986 struct sctp_ifa *sctp_ifa; 987 988 int error; 989 990 /* 991 * Do the malloc first in case it blocks. 992 */ 993 SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof(*sin6)); 994 if (sin6 == NULL) 995 return (ENOMEM); 996 sin6->sin6_family = AF_INET6; 997 sin6->sin6_len = sizeof(*sin6); 998 999 inp = (struct sctp_inpcb *)so->so_pcb; 1000 if (inp == NULL) { 1001 SCTP_FREE_SONAME(sin6); 1002 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1003 return (ECONNRESET); 1004 } 1005 SCTP_INP_RLOCK(inp); 1006 sin6->sin6_port = inp->sctp_lport; 1007 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1008 /* For the bound all case you get back 0 */ 1009 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1010 struct sctp_tcb *stcb; 1011 struct sockaddr_in6 *sin_a6; 1012 struct sctp_nets *net; 1013 int fnd; 1014 1015 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1016 if (stcb == NULL) { 1017 goto notConn6; 1018 } 1019 fnd = 0; 1020 sin_a6 = NULL; 1021 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1022 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1023 if (sin_a6 == NULL) 1024 /* this will make coverity happy */ 1025 continue; 1026 1027 if (sin_a6->sin6_family == AF_INET6) { 1028 fnd = 1; 1029 break; 1030 } 1031 } 1032 if ((!fnd) || (sin_a6 == NULL)) { 1033 /* punt */ 1034 goto notConn6; 1035 } 1036 vrf_id = inp->def_vrf_id; 1037 sctp_ifa = sctp_source_address_selection(inp, stcb, (sctp_route_t *) & net->ro, net, 0, vrf_id); 1038 if (sctp_ifa) { 1039 sin6->sin6_addr = sctp_ifa->address.sin6.sin6_addr; 1040 } 1041 } else { 1042 /* For the bound all case you get back 0 */ 1043 notConn6: 1044 memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); 1045 } 1046 } else { 1047 /* Take the first IPv6 address in the list */ 1048 struct sctp_laddr *laddr; 1049 int fnd = 0; 1050 1051 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1052 if (laddr->ifa->address.sa.sa_family == AF_INET6) { 1053 struct sockaddr_in6 *sin_a; 1054 1055 sin_a = &laddr->ifa->address.sin6; 1056 sin6->sin6_addr = sin_a->sin6_addr; 1057 fnd = 1; 1058 break; 1059 } 1060 } 1061 if (!fnd) { 1062 SCTP_FREE_SONAME(sin6); 1063 SCTP_INP_RUNLOCK(inp); 1064 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1065 return (ENOENT); 1066 } 1067 } 1068 SCTP_INP_RUNLOCK(inp); 1069 /* Scoping things for v6 */ 1070 if ((error = sa6_recoverscope(sin6)) != 0) { 1071 SCTP_FREE_SONAME(sin6); 1072 return (error); 1073 } 1074 (*addr) = (struct sockaddr *)sin6; 1075 return (0); 1076} 1077 1078static int 1079sctp6_peeraddr(struct socket *so, struct sockaddr **addr) 1080{ 1081 struct sockaddr_in6 *sin6; 1082 int fnd; 1083 struct sockaddr_in6 *sin_a6; 1084 struct sctp_inpcb *inp; 1085 struct sctp_tcb *stcb; 1086 struct sctp_nets *net; 1087 int error; 1088 1089 /* Do the malloc first in case it blocks. */ 1090 SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 1091 if (sin6 == NULL) 1092 return (ENOMEM); 1093 sin6->sin6_family = AF_INET6; 1094 sin6->sin6_len = sizeof(*sin6); 1095 1096 inp = (struct sctp_inpcb *)so->so_pcb; 1097 if ((inp == NULL) || 1098 ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { 1099 /* UDP type and listeners will drop out here */ 1100 SCTP_FREE_SONAME(sin6); 1101 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOTCONN); 1102 return (ENOTCONN); 1103 } 1104 SCTP_INP_RLOCK(inp); 1105 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1106 if (stcb) { 1107 SCTP_TCB_LOCK(stcb); 1108 } 1109 SCTP_INP_RUNLOCK(inp); 1110 if (stcb == NULL) { 1111 SCTP_FREE_SONAME(sin6); 1112 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ECONNRESET); 1113 return (ECONNRESET); 1114 } 1115 fnd = 0; 1116 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1117 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1118 if (sin_a6->sin6_family == AF_INET6) { 1119 fnd = 1; 1120 sin6->sin6_port = stcb->rport; 1121 sin6->sin6_addr = sin_a6->sin6_addr; 1122 break; 1123 } 1124 } 1125 SCTP_TCB_UNLOCK(stcb); 1126 if (!fnd) { 1127 /* No IPv4 address */ 1128 SCTP_FREE_SONAME(sin6); 1129 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, ENOENT); 1130 return (ENOENT); 1131 } 1132 if ((error = sa6_recoverscope(sin6)) != 0) { 1133 SCTP_FREE_SONAME(sin6); 1134 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, error); 1135 return (error); 1136 } 1137 *addr = (struct sockaddr *)sin6; 1138 return (0); 1139} 1140 1141static int 1142sctp6_in6getaddr(struct socket *so, struct sockaddr **nam) 1143{ 1144#ifdef INET 1145 struct sockaddr *addr; 1146 1147#endif 1148 struct in6pcb *inp6 = sotoin6pcb(so); 1149 int error; 1150 1151 if (inp6 == NULL) { 1152 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1153 return (EINVAL); 1154 } 1155 /* allow v6 addresses precedence */ 1156 error = sctp6_getaddr(so, nam); 1157#ifdef INET 1158 if (error) { 1159 /* try v4 next if v6 failed */ 1160 error = sctp_ingetaddr(so, nam); 1161 if (error) { 1162 return (error); 1163 } 1164 addr = *nam; 1165 /* if I'm V6ONLY, convert it to v4-mapped */ 1166 if (SCTP_IPV6_V6ONLY(inp6)) { 1167 struct sockaddr_in6 sin6; 1168 1169 in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1170 memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1171 } 1172 } 1173#endif 1174 return (error); 1175} 1176 1177 1178static int 1179sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam) 1180{ 1181#ifdef INET 1182 struct sockaddr *addr; 1183 1184#endif 1185 struct in6pcb *inp6 = sotoin6pcb(so); 1186 int error; 1187 1188 if (inp6 == NULL) { 1189 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); 1190 return (EINVAL); 1191 } 1192 /* allow v6 addresses precedence */ 1193 error = sctp6_peeraddr(so, nam); 1194#ifdef INET 1195 if (error) { 1196 /* try v4 next if v6 failed */ 1197 error = sctp_peeraddr(so, nam); 1198 if (error) { 1199 return (error); 1200 } 1201 addr = *nam; 1202 /* if I'm V6ONLY, convert it to v4-mapped */ 1203 if (SCTP_IPV6_V6ONLY(inp6)) { 1204 struct sockaddr_in6 sin6; 1205 1206 in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1207 memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1208 } 1209 } 1210#endif 1211 return (error); 1212} 1213 1214struct pr_usrreqs sctp6_usrreqs = { 1215 .pru_abort = sctp6_abort, 1216 .pru_accept = sctp_accept, 1217 .pru_attach = sctp6_attach, 1218 .pru_bind = sctp6_bind, 1219 .pru_connect = sctp6_connect, 1220 .pru_control = in6_control, 1221 .pru_close = sctp6_close, 1222 .pru_detach = sctp6_close, 1223 .pru_sopoll = sopoll_generic, 1224 .pru_flush = sctp_flush, 1225 .pru_disconnect = sctp6_disconnect, 1226 .pru_listen = sctp_listen, 1227 .pru_peeraddr = sctp6_getpeeraddr, 1228 .pru_send = sctp6_send, 1229 .pru_shutdown = sctp_shutdown, 1230 .pru_sockaddr = sctp6_in6getaddr, 1231 .pru_sosend = sctp_sosend, 1232 .pru_soreceive = sctp_soreceive 1233}; 1234 1235#endif 1236