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