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