sctp6_usrreq.c revision 166023
1/*- 2 * Copyright (c) 2001-2006, 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#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sys/netinet6/sctp6_usrreq.c 166023 2007-01-15 15:12:10Z rrs $"); 33#include "opt_inet.h" 34#include "opt_inet6.h" 35#include "opt_inet.h" 36#include "opt_ipsec.h" 37#include "opt_sctp.h" 38 39#include <sys/param.h> 40#include <sys/kernel.h> 41#include <sys/mbuf.h> 42#include <sys/domain.h> 43#include <sys/protosw.h> 44#include <sys/socket.h> 45#include <sys/malloc.h> 46#include <sys/socketvar.h> 47#include <sys/sysctl.h> 48#include <sys/errno.h> 49#include <sys/stat.h> 50#include <sys/systm.h> 51#include <sys/syslog.h> 52#include <sys/priv.h> 53#include <sys/proc.h> 54#include <net/if.h> 55#include <net/route.h> 56#include <net/if_types.h> 57#include <netinet/in.h> 58#include <netinet/in_systm.h> 59#include <netinet/ip.h> 60#include <netinet/in_pcb.h> 61#include <netinet/in_var.h> 62#include <netinet/ip_var.h> 63#include <netinet/sctp_os.h> 64#include <netinet/sctp_pcb.h> 65#include <netinet/sctp_header.h> 66#include <netinet/sctp_var.h> 67#include <netinet/sctputil.h> 68#include <netinet/sctp_output.h> 69#include <netinet/sctp_bsd_addr.h> 70#include <netinet/sctp_input.h> 71#include <netinet/sctp_asconf.h> 72#include <netinet6/ip6_var.h> 73#include <netinet6/scope6_var.h> 74#include <netinet/sctp_bsd_addr.h> 75#include <netinet/ip6.h> 76#include <netinet6/in6_pcb.h> 77#include <netinet/icmp6.h> 78#include <netinet6/sctp6_var.h> 79#include <netinet6/ip6protosw.h> 80#include <netinet6/nd6.h> 81 82#ifdef IPSEC 83#include <netinet6/ipsec.h> 84#include <netinet6/ipsec6.h> 85#endif /* IPSEC */ 86 87#if defined(NFAITH) && NFAITH > 0 88#include <net/if_faith.h> 89#endif 90 91 92 93extern struct protosw inetsw[]; 94 95 96#ifndef in6pcb 97#define in6pcb inpcb 98#endif 99#ifndef sotoin6pcb 100#define sotoin6pcb sotoinpcb 101#endif 102 103 104#ifdef SCTP_DEBUG 105extern u_int32_t sctp_debug_on; 106 107#endif 108 109 110 111extern int sctp_no_csum_on_loopback; 112 113int 114sctp6_input(mp, offp, proto) 115 struct mbuf **mp; 116 int *offp; 117 118 int proto; 119 120{ 121 struct mbuf *m; 122 struct ip6_hdr *ip6; 123 struct sctphdr *sh; 124 struct sctp_inpcb *in6p = NULL; 125 struct sctp_nets *net; 126 int refcount_up = 0; 127 u_int32_t check, calc_check; 128 struct inpcb *in6p_ip; 129 struct sctp_chunkhdr *ch; 130 int length, mlen, offset, iphlen; 131 u_int8_t ecn_bits; 132 struct sctp_tcb *stcb = NULL; 133 int off = *offp; 134 int s; 135 136 m = SCTP_HEADER_TO_CHAIN(*mp); 137 138 ip6 = mtod(m, struct ip6_hdr *); 139#ifndef PULLDOWN_TEST 140 /* If PULLDOWN_TEST off, must be in a single mbuf. */ 141 IP6_EXTHDR_CHECK(m, off, (int)(sizeof(*sh) + sizeof(*ch)), IPPROTO_DONE); 142 sh = (struct sctphdr *)((caddr_t)ip6 + off); 143 ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(*sh)); 144#else 145 /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */ 146 IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch)); 147 if (sh == NULL) { 148 SCTP_STAT_INCR(sctps_hdrops); 149 return IPPROTO_DONE; 150 } 151 ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr)); 152#endif 153 154 iphlen = off; 155 offset = iphlen + sizeof(*sh) + sizeof(*ch); 156 157#if defined(NFAITH) && NFAITH > 0 158 159 if (faithprefix_p != NULL && (*faithprefix_p) (&ip6->ip6_dst)) { 160 /* XXX send icmp6 host/port unreach? */ 161 goto bad; 162 } 163#endif /* NFAITH defined and > 0 */ 164 SCTP_STAT_INCR(sctps_recvpackets); 165 SCTP_STAT_INCR_COUNTER64(sctps_inpackets); 166#ifdef SCTP_DEBUG 167 if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 168 printf("V6 input gets a packet iphlen:%d pktlen:%d\n", iphlen, SCTP_HEADER_LEN((*mp))); 169 } 170#endif 171 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 172 /* No multi-cast support in SCTP */ 173 goto bad; 174 } 175 /* destination port of 0 is illegal, based on RFC2960. */ 176 if (sh->dest_port == 0) 177 goto bad; 178 if ((sctp_no_csum_on_loopback == 0) || 179 (!SCTP_IS_IT_LOOPBACK(m))) { 180 /* 181 * we do NOT validate things from the loopback if the sysctl 182 * is set to 1. 183 */ 184 check = sh->checksum; /* save incoming checksum */ 185 if ((check == 0) && (sctp_no_csum_on_loopback)) { 186 /* 187 * special hook for where we got a local address 188 * somehow routed across a non IFT_LOOP type 189 * interface 190 */ 191 if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst)) 192 goto sctp_skip_csum; 193 } 194 sh->checksum = 0; /* prepare for calc */ 195 calc_check = sctp_calculate_sum(m, &mlen, iphlen); 196 if (calc_check != check) { 197#ifdef SCTP_DEBUG 198 if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 199 printf("Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", 200 calc_check, check, m, 201 mlen, iphlen); 202 } 203#endif 204 stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), 205 sh, ch, &in6p, &net); 206 /* in6p's ref-count increased && stcb locked */ 207 if ((in6p) && (stcb)) { 208 sctp_send_packet_dropped(stcb, net, m, iphlen, 1); 209 sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, 2); 210 } else if ((in6p != NULL) && (stcb == NULL)) { 211 refcount_up = 1; 212 } 213 SCTP_STAT_INCR(sctps_badsum); 214 SCTP_STAT_INCR_COUNTER32(sctps_checksumerrors); 215 goto bad; 216 } 217 sh->checksum = calc_check; 218 } 219sctp_skip_csum: 220 net = NULL; 221 /* 222 * Locate pcb and tcb for datagram sctp_findassociation_addr() wants 223 * IP/SCTP/first chunk header... 224 */ 225 stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), 226 sh, ch, &in6p, &net); 227 /* in6p's ref-count increased */ 228 if (in6p == NULL) { 229 struct sctp_init_chunk *init_chk, chunk_buf; 230 231 SCTP_STAT_INCR(sctps_noport); 232 if (ch->chunk_type == SCTP_INITIATION) { 233 /* 234 * we do a trick here to get the INIT tag, dig in 235 * and get the tag from the INIT and put it in the 236 * common header. 237 */ 238 init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 239 iphlen + sizeof(*sh), sizeof(*init_chk), 240 (u_int8_t *) & chunk_buf); 241 sh->v_tag = init_chk->init.initiate_tag; 242 } 243 if (ch->chunk_type == SCTP_SHUTDOWN_ACK) { 244 sctp_send_shutdown_complete2(m, iphlen, sh); 245 goto bad; 246 } 247 if (ch->chunk_type == SCTP_SHUTDOWN_COMPLETE) { 248 goto bad; 249 } 250 if (ch->chunk_type != SCTP_ABORT_ASSOCIATION) 251 sctp_send_abort(m, iphlen, sh, 0, NULL); 252 goto bad; 253 } else if (stcb == NULL) { 254 refcount_up = 1; 255 } 256 in6p_ip = (struct inpcb *)in6p; 257#ifdef IPSEC 258 /* 259 * Check AH/ESP integrity. 260 */ 261 if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) { 262/* XXX */ 263 ipsec6stat.in_polvio++; 264 goto bad; 265 } 266#endif /* IPSEC */ 267 268 269 /* 270 * CONTROL chunk processing 271 */ 272 offset -= sizeof(*ch); 273 ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); 274 275 /* Length now holds the total packet length payload + iphlen */ 276 length = ntohs(ip6->ip6_plen) + iphlen; 277 278 s = splnet(); 279 (void)sctp_common_input_processing(&m, iphlen, offset, length, sh, ch, 280 in6p, stcb, net, ecn_bits); 281 /* inp's ref-count reduced && stcb unlocked */ 282 splx(s); 283 /* XXX this stuff below gets moved to appropriate parts later... */ 284 if (m) 285 m_freem(m); 286 if ((in6p) && refcount_up) { 287 /* reduce ref-count */ 288 SCTP_INP_WLOCK(in6p); 289 SCTP_INP_DECR_REF(in6p); 290 SCTP_INP_WUNLOCK(in6p); 291 } 292 return IPPROTO_DONE; 293 294bad: 295 if (stcb) 296 SCTP_TCB_UNLOCK(stcb); 297 298 if ((in6p) && refcount_up) { 299 /* reduce ref-count */ 300 SCTP_INP_WLOCK(in6p); 301 SCTP_INP_DECR_REF(in6p); 302 SCTP_INP_WUNLOCK(in6p); 303 } 304 if (m) 305 m_freem(m); 306 return IPPROTO_DONE; 307} 308 309 310static void 311sctp6_notify_mbuf(struct sctp_inpcb *inp, 312 struct icmp6_hdr *icmp6, 313 struct sctphdr *sh, 314 struct sctp_tcb *stcb, 315 struct sctp_nets *net) 316{ 317 u_int32_t nxtsz; 318 319 if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 320 (icmp6 == NULL) || (sh == NULL)) { 321 goto out; 322 } 323 /* First do we even look at it? */ 324 if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) 325 goto out; 326 327 if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) { 328 /* not PACKET TO BIG */ 329 goto out; 330 } 331 /* 332 * ok we need to look closely. We could even get smarter and look at 333 * anyone that we sent to in case we get a different ICMP that tells 334 * us there is no way to reach a host, but for this impl, all we 335 * care about is MTU discovery. 336 */ 337 nxtsz = ntohl(icmp6->icmp6_mtu); 338 /* Stop any PMTU timer */ 339 sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL, SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_1); 340 341 /* Adjust destination size limit */ 342 if (net->mtu > nxtsz) { 343 net->mtu = nxtsz; 344 } 345 /* now what about the ep? */ 346 if (stcb->asoc.smallest_mtu > nxtsz) { 347 struct sctp_tmit_chunk *chk; 348 349 /* Adjust that too */ 350 stcb->asoc.smallest_mtu = nxtsz; 351 /* now off to subtract IP_DF flag if needed */ 352 353 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 354 if ((u_int32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 355 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 356 } 357 } 358 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 359 if ((u_int32_t) (chk->send_size + IP_HDR_SIZE) > nxtsz) { 360 /* 361 * For this guy we also mark for immediate 362 * resend since we sent to big of chunk 363 */ 364 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 365 if (chk->sent != SCTP_DATAGRAM_RESEND) 366 stcb->asoc.sent_queue_retran_cnt++; 367 chk->sent = SCTP_DATAGRAM_RESEND; 368 chk->rec.data.doing_fast_retransmit = 0; 369 370 chk->sent = SCTP_DATAGRAM_RESEND; 371 /* Clear any time so NO RTT is being done */ 372 chk->sent_rcv_time.tv_sec = 0; 373 chk->sent_rcv_time.tv_usec = 0; 374 stcb->asoc.total_flight -= chk->send_size; 375 net->flight_size -= chk->send_size; 376 } 377 } 378 } 379 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 380out: 381 if (stcb) 382 SCTP_TCB_UNLOCK(stcb); 383} 384 385 386void 387sctp6_ctlinput(cmd, pktdst, d) 388 int cmd; 389 struct sockaddr *pktdst; 390 void *d; 391{ 392 struct sctphdr sh; 393 struct ip6ctlparam *ip6cp = NULL; 394 int s, cm; 395 396 if (pktdst->sa_family != AF_INET6 || 397 pktdst->sa_len != sizeof(struct sockaddr_in6)) 398 return; 399 400 if ((unsigned)cmd >= PRC_NCMDS) 401 return; 402 if (PRC_IS_REDIRECT(cmd)) { 403 d = NULL; 404 } else if (inet6ctlerrmap[cmd] == 0) { 405 return; 406 } 407 /* if the parameter is from icmp6, decode it. */ 408 if (d != NULL) { 409 ip6cp = (struct ip6ctlparam *)d; 410 } else { 411 ip6cp = (struct ip6ctlparam *)NULL; 412 } 413 414 if (ip6cp) { 415 /* 416 * XXX: We assume that when IPV6 is non NULL, M and OFF are 417 * valid. 418 */ 419 /* check if we can safely examine src and dst ports */ 420 struct sctp_inpcb *inp = NULL; 421 struct sctp_tcb *stcb = NULL; 422 struct sctp_nets *net = NULL; 423 struct sockaddr_in6 final; 424 425 if (ip6cp->ip6c_m == NULL) 426 return; 427 428 bzero(&sh, sizeof(sh)); 429 bzero(&final, sizeof(final)); 430 inp = NULL; 431 net = NULL; 432 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh), 433 (caddr_t)&sh); 434 ip6cp->ip6c_src->sin6_port = sh.src_port; 435 final.sin6_len = sizeof(final); 436 final.sin6_family = AF_INET6; 437 final.sin6_addr = ((struct sockaddr_in6 *)pktdst)->sin6_addr; 438 final.sin6_port = sh.dest_port; 439 s = splnet(); 440 stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src, 441 (struct sockaddr *)&final, 442 &inp, &net, 1); 443 /* inp's ref-count increased && stcb locked */ 444 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 445 if (cmd == PRC_MSGSIZE) { 446 sctp6_notify_mbuf(inp, 447 ip6cp->ip6c_icmp6, 448 &sh, 449 stcb, 450 net); 451 /* inp's ref-count reduced && stcb unlocked */ 452 } else { 453 if (cmd == PRC_HOSTDEAD) { 454 cm = EHOSTUNREACH; 455 } else { 456 cm = inet6ctlerrmap[cmd]; 457 } 458 sctp_notify(inp, cm, &sh, 459 (struct sockaddr *)&final, 460 stcb, net); 461 /* inp's ref-count reduced && stcb unlocked */ 462 } 463 } else { 464 if (PRC_IS_REDIRECT(cmd) && inp) { 465 in6_rtchange((struct in6pcb *)inp, 466 inet6ctlerrmap[cmd]); 467 } 468 if (inp) { 469 /* reduce inp's ref-count */ 470 SCTP_INP_WLOCK(inp); 471 SCTP_INP_DECR_REF(inp); 472 SCTP_INP_WUNLOCK(inp); 473 } 474 if (stcb) 475 SCTP_TCB_UNLOCK(stcb); 476 } 477 splx(s); 478 } 479} 480 481/* 482 * this routine can probably be collasped into the one in sctp_userreq.c 483 * since they do the same thing and now we lookup with a sockaddr 484 */ 485static int 486sctp6_getcred(SYSCTL_HANDLER_ARGS) 487{ 488 struct xucred xuc; 489 struct sockaddr_in6 addrs[2]; 490 struct sctp_inpcb *inp; 491 struct sctp_nets *net; 492 struct sctp_tcb *stcb; 493 int error; 494 495 /* 496 * XXXRW: Other instances of getcred use SUSER_ALLOWJAIL, as socket 497 * visibility is scoped using cr_canseesocket(), which it is not 498 * here. 499 */ 500 error = priv_check_cred(req->td->td_ucred, PRIV_NETINET_RESERVEDPORT, 501 0); 502 if (error) 503 return (error); 504 505 if (req->newlen != sizeof(addrs)) 506 return (EINVAL); 507 if (req->oldlen != sizeof(struct ucred)) 508 return (EINVAL); 509 error = SYSCTL_IN(req, addrs, sizeof(addrs)); 510 if (error) 511 return (error); 512 513 stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]), 514 sin6tosa(&addrs[1]), 515 &inp, &net, 1); 516 if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 517 if ((inp != NULL) && (stcb == NULL)) { 518 /* reduce ref-count */ 519 SCTP_INP_WLOCK(inp); 520 SCTP_INP_DECR_REF(inp); 521 goto cred_can_cont; 522 } 523 error = ENOENT; 524 goto out; 525 } 526 SCTP_TCB_UNLOCK(stcb); 527 /* 528 * We use the write lock here, only since in the error leg we need 529 * it. If we used RLOCK, then we would have to 530 * wlock/decr/unlock/rlock. Which in theory could create a hole. 531 * Better to use higher wlock. 532 */ 533 SCTP_INP_WLOCK(inp); 534cred_can_cont: 535 error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); 536 if (error) { 537 SCTP_INP_WUNLOCK(inp); 538 goto out; 539 } 540 cru2x(inp->sctp_socket->so_cred, &xuc); 541 SCTP_INP_WUNLOCK(inp); 542 error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); 543out: 544 return (error); 545} 546 547SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 548 0, 0, 549 sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection"); 550 551 552/* This is the same as the sctp_abort() could be made common */ 553static void 554sctp6_abort(struct socket *so) 555{ 556 struct sctp_inpcb *inp; 557 int s; 558 uint32_t flags; 559 560 inp = (struct sctp_inpcb *)so->so_pcb; 561 if (inp == 0) 562 return; 563 s = splnet(); 564sctp_must_try_again: 565 flags = inp->sctp_flags; 566#ifdef SCTP_LOG_CLOSING 567 sctp_log_closing(inp, NULL, 17); 568#endif 569 if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 570 (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 571#ifdef SCTP_LOG_CLOSING 572 sctp_log_closing(inp, NULL, 16); 573#endif 574 sctp_inpcb_free(inp, 1, 0); 575 SOCK_LOCK(so); 576 so->so_snd.sb_cc = 0; 577 so->so_snd.sb_mb = NULL; 578 so->so_snd.sb_mbcnt = 0; 579 580 /* 581 * same for the rcv ones, they are only here for the 582 * accounting/select. 583 */ 584 so->so_rcv.sb_cc = 0; 585 so->so_rcv.sb_mb = NULL; 586 so->so_rcv.sb_mbcnt = 0; 587 /* 588 * Now null out the reference, we are completely detached. 589 */ 590 so->so_pcb = NULL; 591 SOCK_UNLOCK(so); 592 } else { 593 flags = inp->sctp_flags; 594 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 595 goto sctp_must_try_again; 596 } 597 } 598 splx(s); 599 return; 600} 601 602static int 603sctp6_attach(struct socket *so, int proto, struct thread *p) 604{ 605 struct in6pcb *inp6; 606 int s, error; 607 struct sctp_inpcb *inp; 608 609 inp = (struct sctp_inpcb *)so->so_pcb; 610 if (inp != NULL) 611 return EINVAL; 612 613 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 614 error = soreserve(so, sctp_sendspace, sctp_recvspace); 615 if (error) 616 return error; 617 } 618 s = splnet(); 619 error = sctp_inpcb_alloc(so); 620 splx(s); 621 if (error) 622 return error; 623 inp = (struct sctp_inpcb *)so->so_pcb; 624 inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */ 625 inp6 = (struct in6pcb *)inp; 626 627 inp6->inp_vflag |= INP_IPV6; 628 inp6->in6p_hops = -1; /* use kernel default */ 629 inp6->in6p_cksum = -1; /* just to be sure */ 630#ifdef INET 631 /* 632 * XXX: ugly!! IPv4 TTL initialization is necessary for an IPv6 633 * socket as well, because the socket may be bound to an IPv6 634 * wildcard address, which may match an IPv4-mapped IPv6 address. 635 */ 636 inp6->inp_ip_ttl = ip_defttl; 637#endif 638 /* 639 * Hmm what about the IPSEC stuff that is missing here but in 640 * sctp_attach()? 641 */ 642 return 0; 643} 644 645static int 646sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p) 647{ 648 struct sctp_inpcb *inp; 649 struct in6pcb *inp6; 650 int s, error; 651 652 inp = (struct sctp_inpcb *)so->so_pcb; 653 if (inp == 0) 654 return EINVAL; 655 656 inp6 = (struct in6pcb *)inp; 657 inp6->inp_vflag &= ~INP_IPV4; 658 inp6->inp_vflag |= INP_IPV6; 659 if ((addr != NULL) && (SCTP_IPV6_V6ONLY(inp6) == 0)) { 660 if (addr->sa_family == AF_INET) { 661 /* binding v4 addr to v6 socket, so reset flags */ 662 inp6->inp_vflag |= INP_IPV4; 663 inp6->inp_vflag &= ~INP_IPV6; 664 } else { 665 struct sockaddr_in6 *sin6_p; 666 667 sin6_p = (struct sockaddr_in6 *)addr; 668 669 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) { 670 inp6->inp_vflag |= INP_IPV4; 671 } else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 672 struct sockaddr_in sin; 673 674 in6_sin6_2_sin(&sin, sin6_p); 675 inp6->inp_vflag |= INP_IPV4; 676 inp6->inp_vflag &= ~INP_IPV6; 677 s = splnet(); 678 error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, p); 679 splx(s); 680 return error; 681 } 682 } 683 } else if (addr != NULL) { 684 /* IPV6_V6ONLY socket */ 685 if (addr->sa_family == AF_INET) { 686 /* can't bind v4 addr to v6 only socket! */ 687 return EINVAL; 688 } else { 689 struct sockaddr_in6 *sin6_p; 690 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 return EINVAL; 697 } 698 } 699 s = splnet(); 700 error = sctp_inpcb_bind(so, addr, p); 701 splx(s); 702 return error; 703} 704 705 706static void 707sctp6_close(struct socket *so) 708{ 709 struct sctp_inpcb *inp; 710 uint32_t flags; 711 712 inp = (struct sctp_inpcb *)so->so_pcb; 713 if (inp == 0) 714 return; 715 716 /* 717 * Inform all the lower layer assoc that we are done. 718 */ 719sctp_must_try_again: 720 flags = inp->sctp_flags; 721#ifdef SCTP_LOG_CLOSING 722 sctp_log_closing(inp, NULL, 17); 723#endif 724 if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && 725 (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { 726 if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 727 (so->so_rcv.sb_cc > 0)) { 728#ifdef SCTP_LOG_CLOSING 729 sctp_log_closing(inp, NULL, 13); 730#endif 731 sctp_inpcb_free(inp, 1, 1); 732 } else { 733#ifdef SCTP_LOG_CLOSING 734 sctp_log_closing(inp, NULL, 14); 735#endif 736 sctp_inpcb_free(inp, 0, 1); 737 } 738 /* 739 * The socket is now detached, no matter what the state of 740 * the SCTP association. 741 */ 742 SOCK_LOCK(so); 743 so->so_snd.sb_cc = 0; 744 so->so_snd.sb_mb = NULL; 745 so->so_snd.sb_mbcnt = 0; 746 747 /* 748 * same for the rcv ones, they are only here for the 749 * accounting/select. 750 */ 751 so->so_rcv.sb_cc = 0; 752 so->so_rcv.sb_mb = NULL; 753 so->so_rcv.sb_mbcnt = 0; 754 /* 755 * Now null out the reference, we are completely detached. 756 */ 757 so->so_pcb = NULL; 758 SOCK_UNLOCK(so); 759 } else { 760 flags = inp->sctp_flags; 761 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 762 goto sctp_must_try_again; 763 } 764 } 765 return; 766 767} 768 769 770static int 771sctp6_disconnect(struct socket *so) 772{ 773 struct sctp_inpcb *inp; 774 int s; 775 776 s = splnet(); /* XXX */ 777 inp = (struct sctp_inpcb *)so->so_pcb; 778 if (inp == NULL) { 779 splx(s); 780 return (ENOTCONN); 781 } 782 SCTP_INP_RLOCK(inp); 783 if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 784 if (LIST_EMPTY(&inp->sctp_asoc_list)) { 785 /* No connection */ 786 splx(s); 787 SCTP_INP_RUNLOCK(inp); 788 return (ENOTCONN); 789 } else { 790 int some_on_streamwheel = 0; 791 struct sctp_association *asoc; 792 struct sctp_tcb *stcb; 793 794 stcb = LIST_FIRST(&inp->sctp_asoc_list); 795 if (stcb == NULL) { 796 splx(s); 797 SCTP_INP_RUNLOCK(inp); 798 return (EINVAL); 799 } 800 SCTP_TCB_LOCK(stcb); 801 asoc = &stcb->asoc; 802 if (((so->so_options & SO_LINGER) && 803 (so->so_linger == 0)) || 804 (so->so_rcv.sb_cc > 0)) { 805 if (SCTP_GET_STATE(asoc) != 806 SCTP_STATE_COOKIE_WAIT) { 807 /* Left with Data unread */ 808 struct mbuf *err; 809 810 err = NULL; 811 MGET(err, M_DONTWAIT, MT_DATA); 812 if (err) { 813 /* 814 * Fill in the user 815 * initiated abort 816 */ 817 struct sctp_paramhdr *ph; 818 819 ph = mtod(err, struct sctp_paramhdr *); 820 SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); 821 ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); 822 ph->param_length = htons(SCTP_BUF_LEN(err)); 823 } 824 sctp_send_abort_tcb(stcb, err); 825 SCTP_STAT_INCR_COUNTER32(sctps_aborted); 826 } 827 SCTP_INP_RUNLOCK(inp); 828 if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 829 (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 830 SCTP_STAT_DECR_GAUGE32(sctps_currestab); 831 } 832 sctp_free_assoc(inp, stcb, SCTP_DONOT_SETSCOPE, 833 SCTP_FROM_SCTP6_USRREQ + SCTP_LOC_2); 834 /* No unlock tcb assoc is gone */ 835 splx(s); 836 return (0); 837 } 838 if (!TAILQ_EMPTY(&asoc->out_wheel)) { 839 /* Check to see if some data queued */ 840 struct sctp_stream_out *outs; 841 842 TAILQ_FOREACH(outs, &asoc->out_wheel, 843 next_spoke) { 844 if (!TAILQ_EMPTY(&outs->outqueue)) { 845 some_on_streamwheel = 1; 846 break; 847 } 848 } 849 } 850 if (TAILQ_EMPTY(&asoc->send_queue) && 851 TAILQ_EMPTY(&asoc->sent_queue) && 852 (some_on_streamwheel == 0)) { 853 /* nothing queued to send, so I'm done... */ 854 if ((SCTP_GET_STATE(asoc) != 855 SCTP_STATE_SHUTDOWN_SENT) && 856 (SCTP_GET_STATE(asoc) != 857 SCTP_STATE_SHUTDOWN_ACK_SENT)) { 858 /* only send SHUTDOWN the first time */ 859 sctp_send_shutdown(stcb, stcb->asoc.primary_destination); 860 sctp_chunk_output(stcb->sctp_ep, stcb, 1); 861 asoc->state = SCTP_STATE_SHUTDOWN_SENT; 862 SCTP_STAT_DECR_GAUGE32(sctps_currestab); 863 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 864 stcb->sctp_ep, stcb, 865 asoc->primary_destination); 866 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 867 stcb->sctp_ep, stcb, 868 asoc->primary_destination); 869 } 870 } else { 871 /* 872 * we still got (or just got) data to send, 873 * so set SHUTDOWN_PENDING 874 */ 875 /* 876 * XXX sockets draft says that MSG_EOF 877 * should be sent with no data. currently, 878 * we will allow user data to be sent first 879 * and move to SHUTDOWN-PENDING 880 */ 881 asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 882 } 883 SCTP_TCB_UNLOCK(stcb); 884 SCTP_INP_RUNLOCK(inp); 885 splx(s); 886 return (0); 887 } 888 } else { 889 /* UDP model does not support this */ 890 SCTP_INP_RUNLOCK(inp); 891 splx(s); 892 return EOPNOTSUPP; 893 } 894} 895 896int 897sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 898 struct mbuf *control, struct thread *p); 899 900 901 902static int 903sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 904 struct mbuf *control, struct thread *p) 905{ 906 struct sctp_inpcb *inp; 907 struct inpcb *in_inp; 908 struct in6pcb *inp6; 909 910#ifdef INET 911 struct sockaddr_in6 *sin6; 912 913#endif /* INET */ 914 /* No SPL needed since sctp_output does this */ 915 916 inp = (struct sctp_inpcb *)so->so_pcb; 917 if (inp == NULL) { 918 if (control) { 919 m_freem(control); 920 control = NULL; 921 } 922 m_freem(m); 923 return EINVAL; 924 } 925 in_inp = (struct inpcb *)inp; 926 inp6 = (struct in6pcb *)inp; 927 /* 928 * For the TCP model we may get a NULL addr, if we are a connected 929 * socket thats ok. 930 */ 931 if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) && 932 (addr == NULL)) { 933 goto connected_type; 934 } 935 if (addr == NULL) { 936 m_freem(m); 937 if (control) { 938 m_freem(control); 939 control = NULL; 940 } 941 return (EDESTADDRREQ); 942 } 943#ifdef INET 944 sin6 = (struct sockaddr_in6 *)addr; 945 if (SCTP_IPV6_V6ONLY(inp6)) { 946 /* 947 * if IPV6_V6ONLY flag, we discard datagrams destined to a 948 * v4 addr or v4-mapped addr 949 */ 950 if (addr->sa_family == AF_INET) { 951 return EINVAL; 952 } 953 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 954 return EINVAL; 955 } 956 } 957 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 958 if (!ip6_v6only) { 959 struct sockaddr_in sin; 960 961 /* convert v4-mapped into v4 addr and send */ 962 in6_sin6_2_sin(&sin, sin6); 963 return sctp_sendm(so, flags, m, (struct sockaddr *)&sin, 964 control, p); 965 } else { 966 /* mapped addresses aren't enabled */ 967 return EINVAL; 968 } 969 } 970#endif /* INET */ 971connected_type: 972 /* now what about control */ 973 if (control) { 974 if (inp->control) { 975 printf("huh? control set?\n"); 976 m_freem(inp->control); 977 inp->control = NULL; 978 } 979 inp->control = control; 980 } 981 /* Place the data */ 982 if (inp->pkt) { 983 SCTP_BUF_NEXT(inp->pkt_last) = m; 984 inp->pkt_last = m; 985 } else { 986 inp->pkt_last = inp->pkt = m; 987 } 988 if ( 989 /* FreeBSD and MacOSX uses a flag passed */ 990 ((flags & PRUS_MORETOCOME) == 0) 991 ) { 992 /* 993 * note with the current version this code will only be used 994 * by OpenBSD, NetBSD and FreeBSD have methods for 995 * re-defining sosend() to use sctp_sosend(). One can 996 * optionaly switch back to this code (by changing back the 997 * defininitions but this is not advisable. 998 */ 999 int ret; 1000 1001 ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); 1002 inp->pkt = NULL; 1003 inp->control = NULL; 1004 return (ret); 1005 } else { 1006 return (0); 1007 } 1008} 1009 1010static int 1011sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) 1012{ 1013 int s = splnet(); 1014 1015 int error = 0; 1016 struct sctp_inpcb *inp; 1017 struct in6pcb *inp6; 1018 struct sctp_tcb *stcb; 1019 1020#ifdef INET 1021 struct sockaddr_in6 *sin6; 1022 struct sockaddr_storage ss; 1023 1024#endif /* INET */ 1025 1026 inp6 = (struct in6pcb *)so->so_pcb; 1027 inp = (struct sctp_inpcb *)so->so_pcb; 1028 if (inp == 0) { 1029 splx(s); 1030 return (ECONNRESET); /* I made the same as TCP since we are 1031 * not setup? */ 1032 } 1033 SCTP_ASOC_CREATE_LOCK(inp); 1034 SCTP_INP_RLOCK(inp); 1035 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 1036 SCTP_PCB_FLAGS_UNBOUND) { 1037 /* Bind a ephemeral port */ 1038 SCTP_INP_RUNLOCK(inp); 1039 error = sctp6_bind(so, NULL, p); 1040 if (error) { 1041 splx(s); 1042 SCTP_ASOC_CREATE_UNLOCK(inp); 1043 1044 return (error); 1045 } 1046 SCTP_INP_RLOCK(inp); 1047 } 1048 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 1049 (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 1050 /* We are already connected AND the TCP model */ 1051 splx(s); 1052 SCTP_INP_RUNLOCK(inp); 1053 SCTP_ASOC_CREATE_UNLOCK(inp); 1054 return (EADDRINUSE); 1055 } 1056#ifdef INET 1057 sin6 = (struct sockaddr_in6 *)addr; 1058 if (SCTP_IPV6_V6ONLY(inp6)) { 1059 /* 1060 * if IPV6_V6ONLY flag, ignore connections destined to a v4 1061 * addr or v4-mapped addr 1062 */ 1063 if (addr->sa_family == AF_INET) { 1064 splx(s); 1065 SCTP_INP_RUNLOCK(inp); 1066 SCTP_ASOC_CREATE_UNLOCK(inp); 1067 return EINVAL; 1068 } 1069 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1070 splx(s); 1071 SCTP_INP_RUNLOCK(inp); 1072 SCTP_ASOC_CREATE_UNLOCK(inp); 1073 return EINVAL; 1074 } 1075 } 1076 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 1077 if (!ip6_v6only) { 1078 /* convert v4-mapped into v4 addr */ 1079 in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6); 1080 addr = (struct sockaddr *)&ss; 1081 } else { 1082 /* mapped addresses aren't enabled */ 1083 splx(s); 1084 SCTP_INP_RUNLOCK(inp); 1085 SCTP_ASOC_CREATE_UNLOCK(inp); 1086 return EINVAL; 1087 } 1088 } else 1089#endif /* INET */ 1090 addr = addr; /* for true v6 address case */ 1091 1092 /* Now do we connect? */ 1093 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1094 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1095 if (stcb) 1096 SCTP_TCB_UNLOCK(stcb); 1097 SCTP_INP_RUNLOCK(inp); 1098 } else { 1099 SCTP_INP_RUNLOCK(inp); 1100 SCTP_INP_WLOCK(inp); 1101 SCTP_INP_INCR_REF(inp); 1102 SCTP_INP_WUNLOCK(inp); 1103 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); 1104 if (stcb == NULL) { 1105 SCTP_INP_WLOCK(inp); 1106 SCTP_INP_DECR_REF(inp); 1107 SCTP_INP_WUNLOCK(inp); 1108 } 1109 } 1110 1111 if (stcb != NULL) { 1112 /* Already have or am bring up an association */ 1113 SCTP_ASOC_CREATE_UNLOCK(inp); 1114 SCTP_TCB_UNLOCK(stcb); 1115 splx(s); 1116 return (EALREADY); 1117 } 1118 /* We are GOOD to go */ 1119 stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0); 1120 SCTP_ASOC_CREATE_UNLOCK(inp); 1121 if (stcb == NULL) { 1122 /* Gak! no memory */ 1123 splx(s); 1124 return (error); 1125 } 1126 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1127 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1128 /* Set the connected flag so we can queue data */ 1129 soisconnecting(so); 1130 } 1131 stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 1132 SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1133 1134 /* initialize authentication parameters for the assoc */ 1135 sctp_initialize_auth_params(inp, stcb); 1136 1137 sctp_send_initiate(inp, stcb); 1138 SCTP_TCB_UNLOCK(stcb); 1139 splx(s); 1140 return error; 1141} 1142 1143static int 1144sctp6_getaddr(struct socket *so, struct sockaddr **addr) 1145{ 1146 struct sockaddr_in6 *sin6; 1147 1148 struct sctp_inpcb *inp; 1149 1150 int error; 1151 1152 1153 /* 1154 * Do the malloc first in case it blocks. 1155 */ 1156 SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 1157 sin6->sin6_family = AF_INET6; 1158 sin6->sin6_len = sizeof(*sin6); 1159 1160 inp = (struct sctp_inpcb *)so->so_pcb; 1161 if (inp == NULL) { 1162 SCTP_FREE_SONAME(sin6); 1163 return ECONNRESET; 1164 } 1165 SCTP_INP_RLOCK(inp); 1166 sin6->sin6_port = inp->sctp_lport; 1167 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1168 /* For the bound all case you get back 0 */ 1169 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1170 struct sctp_tcb *stcb; 1171 struct sockaddr_in6 *sin_a6; 1172 struct sctp_nets *net; 1173 int fnd; 1174 1175 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1176 if (stcb == NULL) { 1177 goto notConn6; 1178 } 1179 fnd = 0; 1180 sin_a6 = NULL; 1181 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1182 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1183 if (sin_a6 == NULL) 1184 /* this will make coverity happy */ 1185 continue; 1186 1187 if (sin_a6->sin6_family == AF_INET6) { 1188 fnd = 1; 1189 break; 1190 } 1191 } 1192 if ((!fnd) || (sin_a6 == NULL)) { 1193 /* punt */ 1194 goto notConn6; 1195 } 1196 sin6->sin6_addr = sctp_ipv6_source_address_selection( 1197 inp, stcb, (struct route *)&net->ro, net, 0); 1198 1199 } else { 1200 /* For the bound all case you get back 0 */ 1201 notConn6: 1202 memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); 1203 } 1204 } else { 1205 /* Take the first IPv6 address in the list */ 1206 struct sctp_laddr *laddr; 1207 int fnd = 0; 1208 1209 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1210 if (laddr->ifa->ifa_addr->sa_family == AF_INET6) { 1211 struct sockaddr_in6 *sin_a; 1212 1213 sin_a = (struct sockaddr_in6 *)laddr->ifa->ifa_addr; 1214 sin6->sin6_addr = sin_a->sin6_addr; 1215 fnd = 1; 1216 break; 1217 } 1218 } 1219 if (!fnd) { 1220 SCTP_FREE_SONAME(sin6); 1221 SCTP_INP_RUNLOCK(inp); 1222 return ENOENT; 1223 } 1224 } 1225 SCTP_INP_RUNLOCK(inp); 1226 /* Scoping things for v6 */ 1227 if ((error = sa6_recoverscope(sin6)) != 0) { 1228 SCTP_FREE_SONAME(sin6); 1229 return (error); 1230 } 1231 (*addr) = (struct sockaddr *)sin6; 1232 return (0); 1233} 1234 1235static int 1236sctp6_peeraddr(struct socket *so, struct sockaddr **addr) 1237{ 1238 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)*addr; 1239 1240 int fnd; 1241 struct sockaddr_in6 *sin_a6; 1242 struct sctp_inpcb *inp; 1243 struct sctp_tcb *stcb; 1244 struct sctp_nets *net; 1245 1246 int error; 1247 1248 1249 /* 1250 * Do the malloc first in case it blocks. 1251 */ 1252 inp = (struct sctp_inpcb *)so->so_pcb; 1253 if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 1254 /* UDP type and listeners will drop out here */ 1255 return (ENOTCONN); 1256 } 1257 SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); 1258 sin6->sin6_family = AF_INET6; 1259 sin6->sin6_len = sizeof(*sin6); 1260 1261 /* We must recapture incase we blocked */ 1262 inp = (struct sctp_inpcb *)so->so_pcb; 1263 if (inp == NULL) { 1264 SCTP_FREE_SONAME(sin6); 1265 return ECONNRESET; 1266 } 1267 SCTP_INP_RLOCK(inp); 1268 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1269 if (stcb) 1270 SCTP_TCB_LOCK(stcb); 1271 SCTP_INP_RUNLOCK(inp); 1272 if (stcb == NULL) { 1273 SCTP_FREE_SONAME(sin6); 1274 return ECONNRESET; 1275 } 1276 fnd = 0; 1277 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1278 sin_a6 = (struct sockaddr_in6 *)&net->ro._l_addr; 1279 if (sin_a6->sin6_family == AF_INET6) { 1280 fnd = 1; 1281 sin6->sin6_port = stcb->rport; 1282 sin6->sin6_addr = sin_a6->sin6_addr; 1283 break; 1284 } 1285 } 1286 SCTP_TCB_UNLOCK(stcb); 1287 if (!fnd) { 1288 /* No IPv4 address */ 1289 SCTP_FREE_SONAME(sin6); 1290 return ENOENT; 1291 } 1292 if ((error = sa6_recoverscope(sin6)) != 0) 1293 return (error); 1294 *addr = (struct sockaddr *)sin6; 1295 return (0); 1296} 1297 1298static int 1299sctp6_in6getaddr(struct socket *so, struct sockaddr **nam) 1300{ 1301 struct sockaddr *addr; 1302 1303 struct in6pcb *inp6 = sotoin6pcb(so); 1304 int error, s; 1305 1306 if (inp6 == NULL) 1307 return EINVAL; 1308 1309 s = splnet(); 1310 /* allow v6 addresses precedence */ 1311 error = sctp6_getaddr(so, nam); 1312 if (error) { 1313 /* try v4 next if v6 failed */ 1314 error = sctp_ingetaddr(so, nam); 1315 if (error) { 1316 splx(s); 1317 return (error); 1318 } 1319 addr = *nam; 1320 /* if I'm V6ONLY, convert it to v4-mapped */ 1321 if (SCTP_IPV6_V6ONLY(inp6)) { 1322 struct sockaddr_in6 sin6; 1323 1324 in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1325 memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1326 } 1327 } 1328 splx(s); 1329 return (error); 1330} 1331 1332 1333static int 1334sctp6_getpeeraddr(struct socket *so, struct sockaddr **nam) 1335{ 1336 struct sockaddr *addr = *nam; 1337 1338 struct in6pcb *inp6 = sotoin6pcb(so); 1339 int error, s; 1340 1341 if (inp6 == NULL) 1342 return EINVAL; 1343 1344 s = splnet(); 1345 /* allow v6 addresses precedence */ 1346 error = sctp6_peeraddr(so, nam); 1347 if (error) { 1348 /* try v4 next if v6 failed */ 1349 error = sctp_peeraddr(so, nam); 1350 if (error) { 1351 splx(s); 1352 return (error); 1353 } 1354 /* if I'm V6ONLY, convert it to v4-mapped */ 1355 if (SCTP_IPV6_V6ONLY(inp6)) { 1356 struct sockaddr_in6 sin6; 1357 1358 in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1359 memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1360 } 1361 } 1362 splx(s); 1363 return error; 1364} 1365 1366struct pr_usrreqs sctp6_usrreqs = { 1367 .pru_abort = sctp6_abort, 1368 .pru_accept = sctp_accept, 1369 .pru_attach = sctp6_attach, 1370 .pru_bind = sctp6_bind, 1371 .pru_connect = sctp6_connect, 1372 .pru_control = in6_control, 1373 .pru_close = sctp6_close, 1374 .pru_detach = sctp6_close, 1375 .pru_sopoll = sopoll_generic, 1376 .pru_disconnect = sctp6_disconnect, 1377 .pru_listen = sctp_listen, 1378 .pru_peeraddr = sctp6_getpeeraddr, 1379 .pru_send = sctp6_send, 1380 .pru_shutdown = sctp_shutdown, 1381 .pru_sockaddr = sctp6_in6getaddr, 1382 .pru_sosend = sctp_sosend, 1383 .pru_soreceive = sctp_soreceive 1384}; 1385