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