1 /* $KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $ */ 2 /* $NetBSD: sctp6_usrreq.c,v 1.26 2024/07/06 10:09:15 andvar Exp $ */ 3 4 /* 5 * Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Cisco Systems, Inc. 19 * 4. Neither the name of the project nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY CISCO SYSTEMS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL CISCO SYSTEMS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: sctp6_usrreq.c,v 1.26 2024/07/06 10:09:15 andvar Exp $"); 37 38 #ifdef _KERNEL_OPT 39 #include "opt_inet.h" 40 #include "opt_ipsec.h" 41 #include "opt_sctp.h" 42 #include "opt_net_mpsafe.h" 43 #endif /* _KERNEL_OPT */ 44 45 #include <sys/param.h> 46 #include <sys/kernel.h> 47 #include <sys/mbuf.h> 48 #include <sys/domain.h> 49 #include <sys/protosw.h> 50 #include <sys/socket.h> 51 #include <sys/malloc.h> 52 #include <sys/socketvar.h> 53 #include <sys/sysctl.h> 54 #include <sys/errno.h> 55 #include <sys/stat.h> 56 #include <sys/systm.h> 57 #include <sys/syslog.h> 58 #include <sys/proc.h> 59 #include <net/if.h> 60 #include <net/route.h> 61 #include <net/if_types.h> 62 #include <netinet/in.h> 63 #include <netinet/in_systm.h> 64 #include <netinet/ip.h> 65 #include <netinet/in_pcb.h> 66 #include <netinet/in_var.h> 67 #include <netinet/ip_var.h> 68 #include <netinet/sctp_pcb.h> 69 #include <netinet/sctp_header.h> 70 #include <netinet/sctp_var.h> 71 #include <netinet/sctputil.h> 72 #include <netinet/sctp_output.h> 73 #include <netinet/sctp_input.h> 74 #include <netinet/sctp_asconf.h> 75 #include <netinet/sctp_route.h> 76 #include <netinet6/ip6_var.h> 77 #include <netinet6/scope6_var.h> 78 #include <netinet/ip6.h> 79 #include <netinet6/in6_pcb.h> 80 #include <netinet/icmp6.h> 81 #include <netinet6/sctp6_var.h> 82 #include <netinet6/ip6protosw.h> 83 84 #ifdef IPSEC 85 #include <netipsec/ipsec.h> 86 #include <netipsec/ipsec6.h> 87 #endif /*IPSEC*/ 88 89 #if defined(NFAITH) && NFAITH > 0 90 #include <net/if_faith.h> 91 #endif 92 93 #if defined(HAVE_NRL_INPCB) || defined(__FreeBSD__) 94 #ifndef in6pcb 95 #define in6pcb inpcb 96 #endif 97 #ifndef sotoin6pcb 98 #define sotoin6pcb sotoinpcb 99 #endif 100 #endif 101 102 #ifdef SCTP_DEBUG 103 extern u_int32_t sctp_debug_on; 104 #endif 105 106 static int sctp6_detach(struct socket *so); 107 108 extern int sctp_no_csum_on_loopback; 109 110 int 111 sctp6_input(struct mbuf **mp, int *offp, int proto) 112 { 113 struct mbuf *m = *mp; 114 struct ip6_hdr *ip6; 115 struct sctphdr *sh; 116 struct sctp_inpcb *in6p = NULL; 117 struct sctp_nets *net; 118 int refcount_up = 0; 119 u_int32_t check, calc_check; 120 struct inpcb *in6p_ip; 121 struct sctp_chunkhdr *ch; 122 struct mbuf *opts = NULL; 123 int length, mlen, offset, iphlen; 124 u_int8_t ecn_bits; 125 struct sctp_tcb *stcb = NULL; 126 int off = *offp; 127 int s; 128 129 ip6 = mtod(m, struct ip6_hdr *); 130 /* Ensure that (sctphdr + sctp_chunkhdr) in a row. */ 131 IP6_EXTHDR_GET(sh, struct sctphdr *, m, off, sizeof(*sh) + sizeof(*ch)); 132 if (sh == NULL) { 133 sctp_pegs[SCTP_HDR_DROPS]++; 134 return IPPROTO_DONE; 135 } 136 ch = (struct sctp_chunkhdr *)((vaddr_t)sh + sizeof(struct sctphdr)); 137 138 iphlen = off; 139 offset = iphlen + sizeof(*sh) + sizeof(*ch); 140 141 #if defined(NFAITH) && NFAITH > 0 142 if (faithprefix(&ip6->ip6_dst)) 143 goto bad; 144 #endif /* NFAITH defined and > 0 */ 145 sctp_pegs[SCTP_INPKTS]++; 146 #ifdef SCTP_DEBUG 147 if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 148 printf("V6 input gets a packet iphlen:%d pktlen:%d\n", iphlen, m->m_pkthdr.len); 149 } 150 #endif 151 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { 152 /* No multi-cast support in SCTP */ 153 sctp_pegs[SCTP_IN_MCAST]++; 154 goto bad; 155 } 156 /* destination port of 0 is illegal, based on RFC2960. */ 157 if (sh->dest_port == 0) 158 goto bad; 159 if ((sctp_no_csum_on_loopback == 0) || 160 (m_get_rcvif_NOMPSAFE(m) == NULL) || 161 (m_get_rcvif_NOMPSAFE(m)->if_type != IFT_LOOP)) { 162 /* we do NOT validate things from the loopback if the 163 * sysctl is set to 1. 164 */ 165 check = sh->checksum; /* save incoming checksum */ 166 if ((check == 0) && (sctp_no_csum_on_loopback)) { 167 /* special hook for where we got a local address 168 * somehow routed across a non IFT_LOOP type interface 169 */ 170 if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &ip6->ip6_dst)) 171 goto sctp_skip_csum; 172 } 173 sh->checksum = 0; /* prepare for calc */ 174 calc_check = sctp_calculate_sum(m, &mlen, iphlen); 175 if (calc_check != check) { 176 #ifdef SCTP_DEBUG 177 if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 178 printf("Bad CSUM on SCTP packet calc_check:%x check:%x m:%p mlen:%d iphlen:%d\n", 179 calc_check, check, m, 180 mlen, iphlen); 181 } 182 #endif 183 stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), 184 sh, ch, &in6p, &net); 185 /* in6p's ref-count increased && stcb locked */ 186 if ((in6p) && (stcb)) { 187 sctp_send_packet_dropped(stcb, net, m, iphlen, 1); 188 sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, 2); 189 } else if ((in6p != NULL) && (stcb == NULL)) { 190 refcount_up = 1; 191 } 192 sctp_pegs[SCTP_BAD_CSUM]++; 193 goto bad; 194 } 195 sh->checksum = calc_check; 196 } else { 197 sctp_skip_csum: 198 mlen = m->m_pkthdr.len; 199 } 200 net = NULL; 201 /* 202 * Locate pcb and tcb for datagram 203 * sctp_findassociation_addr() wants IP/SCTP/first chunk header... 204 */ 205 #ifdef SCTP_DEBUG 206 if (sctp_debug_on & SCTP_DEBUG_INPUT1) { 207 printf("V6 Find the association\n"); 208 } 209 #endif 210 stcb = sctp_findassociation_addr(m, iphlen, offset - sizeof(*ch), 211 sh, ch, &in6p, &net); 212 /* in6p's ref-count increased */ 213 if (in6p == NULL) { 214 struct sctp_init_chunk *init_chk, chunk_buf; 215 216 sctp_pegs[SCTP_NOPORTS]++; 217 if (ch->chunk_type == SCTP_INITIATION) { 218 /* we do a trick here to get the INIT tag, 219 * dig in and get the tag from the INIT and 220 * put it in the common header. 221 */ 222 init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 223 iphlen + sizeof(*sh), sizeof(*init_chk), 224 (u_int8_t *)&chunk_buf); 225 sh->v_tag = init_chk->init.initiate_tag; 226 } 227 sctp_send_abort(m, iphlen, sh, 0, NULL); 228 goto bad; 229 } else if (stcb == NULL) { 230 refcount_up = 1; 231 } 232 in6p_ip = (struct inpcb *)in6p; 233 #ifdef IPSEC 234 /* 235 * Check AH/ESP integrity. 236 */ 237 if (ipsec_used && ipsec_in_reject(m, in6p_ip)) { 238 /* XXX */ 239 #if 0 240 /* FIX ME: need to find right stat */ 241 ipsec6stat.in_polvio++; 242 #endif 243 goto bad; 244 } 245 #endif /*IPSEC*/ 246 247 /* 248 * Construct sockaddr format source address. 249 * Stuff source address and datagram in user buffer. 250 */ 251 if ((in6p->ip_inp.inp.inp_flags & INP_CONTROLOPTS) 252 #ifndef __OpenBSD__ 253 || (in6p->sctp_socket->so_options & SO_TIMESTAMP) 254 #endif 255 ) { 256 #if defined(__FreeBSD__) || defined(__APPLE__) 257 #if (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version < 501113) || defined(__APPLE__) 258 ip6_savecontrol(in6p_ip, &opts, ip6, m); 259 #elif __FreeBSD_version >= 440000 || (defined(SCTP_BASE_FREEBSD) && __FreeBSD_version >= 501113) 260 ip6_savecontrol(in6p_ip, m, &opts); 261 #else 262 ip6_savecontrol(in6p_ip, m, &opts, NULL); 263 #endif 264 #elif defined(__NetBSD__) 265 ip6_savecontrol(in6p_ip, &opts, ip6, m); 266 #else 267 ip6_savecontrol(in6p_ip, m, &opts); 268 #endif 269 } 270 271 /* 272 * CONTROL chunk processing 273 */ 274 length = ntohs(ip6->ip6_plen) + iphlen; 275 offset -= sizeof(*ch); 276 ecn_bits = ((ntohl(ip6->ip6_flow) >> 20) & 0x000000ff); 277 s = splsoftnet(); 278 (void)sctp_common_input_processing(&m, iphlen, offset, length, sh, ch, 279 in6p, stcb, net, ecn_bits); 280 /* inp's ref-count reduced && stcb unlocked */ 281 splx(s); 282 /* XXX this stuff below gets moved to appropriate parts later... */ 283 m_freem(m); 284 m_freem(opts); 285 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 293 return IPPROTO_DONE; 294 295 bad: 296 if (stcb) { 297 SCTP_TCB_UNLOCK(stcb); 298 } 299 300 if ((in6p) && refcount_up){ 301 /* reduce ref-count */ 302 SCTP_INP_WLOCK(in6p); 303 SCTP_INP_DECR_REF(in6p); 304 SCTP_INP_WUNLOCK(in6p); 305 } 306 m_freem(m); 307 m_freem(opts); 308 return IPPROTO_DONE; 309 } 310 311 312 static void 313 sctp6_notify_mbuf(struct sctp_inpcb *inp, 314 struct icmp6_hdr *icmp6, 315 struct sctphdr *sh, 316 struct sctp_tcb *stcb, 317 struct sctp_nets *net) 318 { 319 unsigned int nxtsz; 320 321 if ((inp == NULL) || (stcb == NULL) || (net == NULL) || 322 (icmp6 == NULL) || (sh == NULL)) { 323 goto out; 324 } 325 326 /* First do we even look at it? */ 327 if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) 328 goto out; 329 330 if (icmp6->icmp6_type != ICMP6_PACKET_TOO_BIG) { 331 /* not PACKET TO BIG */ 332 goto out; 333 } 334 /* 335 * ok we need to look closely. We could even get smarter and 336 * look at anyone that we sent to in case we get a different 337 * ICMP that tells us there is no way to reach a host, but for 338 * this impl, all we care about is MTU discovery. 339 */ 340 nxtsz = ntohl(icmp6->icmp6_mtu); 341 /* Stop any PMTU timer */ 342 sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 343 344 /* Adjust destination size limit */ 345 if (net->mtu > nxtsz) { 346 net->mtu = nxtsz; 347 } 348 /* now what about the ep? */ 349 if (stcb->asoc.smallest_mtu > nxtsz) { 350 struct sctp_tmit_chunk *chk; 351 struct sctp_stream_out *strm; 352 /* Adjust that too */ 353 stcb->asoc.smallest_mtu = nxtsz; 354 /* now off to subtract IP_DF flag if needed */ 355 356 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { 357 if ((chk->send_size+IP_HDR_SIZE) > nxtsz) { 358 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 359 } 360 } 361 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 362 if ((chk->send_size+IP_HDR_SIZE) > nxtsz) { 363 /* 364 * For this guy we also mark for immediate 365 * resend since we sent to big of chunk 366 */ 367 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 368 if (chk->sent != SCTP_DATAGRAM_RESEND) 369 stcb->asoc.sent_queue_retran_cnt++; 370 chk->sent = SCTP_DATAGRAM_RESEND; 371 chk->rec.data.doing_fast_retransmit = 0; 372 373 chk->sent = SCTP_DATAGRAM_RESEND; 374 /* Clear any time so NO RTT is being done */ 375 chk->sent_rcv_time.tv_sec = 0; 376 chk->sent_rcv_time.tv_usec = 0; 377 stcb->asoc.total_flight -= chk->send_size; 378 net->flight_size -= chk->send_size; 379 } 380 } 381 TAILQ_FOREACH(strm, &stcb->asoc.out_wheel, next_spoke) { 382 TAILQ_FOREACH(chk, &strm->outqueue, sctp_next) { 383 if ((chk->send_size+IP_HDR_SIZE) > nxtsz) { 384 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 385 } 386 } 387 } 388 } 389 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, NULL); 390 out: 391 if (inp) { 392 /* reduce inp's ref-count */ 393 SCTP_INP_WLOCK(inp); 394 SCTP_INP_DECR_REF(inp); 395 SCTP_INP_WUNLOCK(inp); 396 } 397 if (stcb) { 398 SCTP_TCB_UNLOCK(stcb); 399 } 400 } 401 402 403 void * 404 sctp6_ctlinput(int cmd, const struct sockaddr *pktdst, void *d) 405 { 406 struct sctphdr sh; 407 struct ip6ctlparam *ip6cp = NULL; 408 int s, cm; 409 410 if (pktdst->sa_family != AF_INET6 || 411 pktdst->sa_len != sizeof(struct sockaddr_in6)) 412 return NULL; 413 414 if ((unsigned)cmd >= PRC_NCMDS) 415 return NULL; 416 if (PRC_IS_REDIRECT(cmd)) { 417 d = NULL; 418 } else if (inet6ctlerrmap[cmd] == 0) { 419 return NULL; 420 } 421 422 /* if the parameter is from icmp6, decode it. */ 423 if (d != NULL) { 424 ip6cp = (struct ip6ctlparam *)d; 425 } else { 426 ip6cp = (struct ip6ctlparam *)NULL; 427 } 428 429 if (ip6cp) { 430 /* 431 * XXX: We assume that when IPV6 is non NULL, 432 * M and OFF are valid. 433 */ 434 /* check if we can safely examine src and dst ports */ 435 struct sctp_inpcb *inp; 436 struct sctp_tcb *stcb; 437 struct sctp_nets *net; 438 struct sockaddr_in6 final; 439 440 if (ip6cp->ip6c_m == NULL || 441 (size_t)ip6cp->ip6c_m->m_pkthdr.len < (ip6cp->ip6c_off + sizeof(sh))) 442 return NULL; 443 444 memset(&sh, 0, sizeof(sh)); 445 memset(&final, 0, sizeof(final)); 446 inp = NULL; 447 net = NULL; 448 m_copydata(ip6cp->ip6c_m, ip6cp->ip6c_off, sizeof(sh), 449 (void *)&sh); 450 ip6cp->ip6c_src->sin6_port = sh.src_port; 451 final.sin6_len = sizeof(final); 452 final.sin6_family = AF_INET6; 453 final.sin6_addr = ((const struct sockaddr_in6 *)pktdst)->sin6_addr; 454 final.sin6_port = sh.dest_port; 455 s = splsoftnet(); 456 stcb = sctp_findassociation_addr_sa(sin6tosa(ip6cp->ip6c_src), 457 sin6tosa(&final), 458 &inp, &net, 1); 459 /* inp's ref-count increased && stcb locked */ 460 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { 461 if (cmd == PRC_MSGSIZE) { 462 sctp6_notify_mbuf(inp, 463 ip6cp->ip6c_icmp6, 464 &sh, 465 stcb, 466 net); 467 /* inp's ref-count reduced && stcb unlocked */ 468 } else { 469 if (cmd == PRC_HOSTDEAD) { 470 cm = EHOSTUNREACH; 471 } else { 472 cm = inet6ctlerrmap[cmd]; 473 } 474 sctp_notify(inp, cm, &sh, sin6tosa(&final), 475 stcb, net); 476 /* inp's ref-count reduced && stcb unlocked */ 477 } 478 } else { 479 if (PRC_IS_REDIRECT(cmd) && inp) { 480 in6pcb_rtchange((struct inpcb *)inp, inet6ctlerrmap[cmd]); 481 } 482 if (inp) { 483 /* reduce inp's ref-count */ 484 SCTP_INP_WLOCK(inp); 485 SCTP_INP_DECR_REF(inp); 486 SCTP_INP_WUNLOCK(inp); 487 } 488 if (stcb) { 489 SCTP_TCB_UNLOCK(stcb); 490 } 491 } 492 splx(s); 493 } 494 return NULL; 495 } 496 497 /* 498 * this routine can probably be collapsed into the one in sctp_userreq.c 499 * since they do the same thing and now we lookup with a sockaddr 500 */ 501 #ifdef __FreeBSD__ 502 static int 503 sctp6_getcred(SYSCTL_HANDLER_ARGS) 504 { 505 struct sockaddr_in6 addrs[2]; 506 struct sctp_inpcb *inp; 507 struct sctp_nets *net; 508 struct sctp_tcb *stcb; 509 int error, s; 510 511 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 512 error = suser(req->td); 513 #else 514 error = suser(req->p); 515 #endif 516 if (error) 517 return (error); 518 519 if (req->newlen != sizeof(addrs)) 520 return (EINVAL); 521 if (req->oldlen != sizeof(struct ucred)) 522 return (EINVAL); 523 error = SYSCTL_IN(req, addrs, sizeof(addrs)); 524 if (error) 525 return (error); 526 s = splsoftnet(); 527 528 stcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]), 529 sin6tosa(&addrs[1]), 530 &inp, &net, 1); 531 if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { 532 error = ENOENT; 533 if (inp) { 534 SCTP_INP_WLOCK(inp); 535 SCTP_INP_DECR_REF(inp); 536 SCTP_INP_WUNLOCK(inp); 537 } 538 goto out; 539 } 540 error = SYSCTL_OUT(req, inp->sctp_socket->so_cred, 541 sizeof(struct ucred)); 542 543 SCTP_TCB_UNLOCK (stcb); 544 out: 545 splx(s); 546 return (error); 547 } 548 549 SYSCTL_PROC(_net_inet6_sctp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 550 0, 0, 551 sctp6_getcred, "S,ucred", "Get the ucred of a SCTP6 connection"); 552 553 #endif 554 555 /* This is the same as the sctp_abort() could be made common */ 556 static int 557 sctp6_abort(struct socket *so) 558 { 559 int s; 560 struct sctp_inpcb *inp; 561 562 KASSERT(solocked(so)); 563 564 s = splsoftnet(); 565 inp = (struct sctp_inpcb *)so->so_pcb; 566 if (inp == 0) 567 return EINVAL; /* ??? possible? panic instead? */ 568 soisdisconnected(so); 569 sctp_inpcb_free(inp, 1); 570 splx(s); 571 return 0; 572 } 573 574 static int 575 sctp6_attach(struct socket *so, int proto) 576 { 577 struct in6pcb *inp6; 578 int error; 579 struct sctp_inpcb *inp; 580 581 sosetlock(so); 582 inp = (struct sctp_inpcb *)so->so_pcb; 583 if (inp != NULL) 584 return EINVAL; 585 586 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 587 error = soreserve(so, sctp_sendspace, sctp_recvspace); 588 if (error) 589 return error; 590 } 591 error = sctp_inpcb_alloc(so); 592 if (error) 593 return error; 594 inp = (struct sctp_inpcb *)so->so_pcb; 595 inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_V6; /* I'm v6! */ 596 inp6 = (struct in6pcb *)inp; 597 598 inp->inp_vflag |= INP_IPV6; 599 if (ip6_v6only) { 600 inp6->in6p_flags |= IN6P_IPV6_V6ONLY; 601 } 602 so->so_send = sctp_sosend; 603 604 #ifdef IPSEC 605 inp6->in6p_af = proto; 606 #endif 607 inp6->in6p_hops = -1; /* use kernel default */ 608 inp6->in6p_cksum = -1; /* just to be sure */ 609 #ifdef INET 610 /* 611 * XXX: ugly!! 612 * IPv4 TTL initialization is necessary for an IPv6 socket as well, 613 * because the socket may be bound to an IPv6 wildcard address, 614 * which may match an IPv4-mapped IPv6 address. 615 */ 616 inp->inp_ip_ttl = ip_defttl; 617 #endif 618 /* 619 * Hmm what about the IPSEC stuff that is missing here but 620 * in sctp_attach()? 621 */ 622 return 0; 623 } 624 625 static int 626 sctp6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 627 { 628 struct sctp_inpcb *inp; 629 struct in6pcb *inp6; 630 int error; 631 632 KASSERT(solocked(so)); 633 634 inp = (struct sctp_inpcb *)so->so_pcb; 635 if (inp == 0) 636 return EINVAL; 637 638 inp6 = (struct in6pcb *)inp; 639 inp->inp_vflag &= ~INP_IPV4; 640 inp->inp_vflag |= INP_IPV6; 641 642 if (nam != NULL && (inp6->in6p_flags & IN6P_IPV6_V6ONLY) == 0) { 643 if (nam->sa_family == AF_INET) { 644 /* binding v4 addr to v6 socket, so reset flags */ 645 inp->inp_vflag |= INP_IPV4; 646 inp->inp_vflag &= ~INP_IPV6; 647 } else { 648 struct sockaddr_in6 *sin6_p; 649 sin6_p = (struct sockaddr_in6 *)nam; 650 651 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) { 652 inp->inp_vflag |= INP_IPV4; 653 } 654 else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { 655 struct sockaddr_in sin; 656 in6_sin6_2_sin(&sin, sin6_p); 657 inp->inp_vflag |= INP_IPV4; 658 inp->inp_vflag &= ~INP_IPV6; 659 error = sctp_inpcb_bind(so, (struct sockaddr *)&sin, l); 660 return error; 661 } 662 } 663 } else if (nam != NULL) { 664 /* IPV6_V6ONLY socket */ 665 if (nam->sa_family == AF_INET) { 666 /* can't bind v4 addr to v6 only socket! */ 667 return EINVAL; 668 } else { 669 struct sockaddr_in6 *sin6_p; 670 sin6_p = (struct sockaddr_in6 *)nam; 671 672 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) 673 /* can't bind v4-mapped addrs either! */ 674 /* NOTE: we don't support SIIT */ 675 return EINVAL; 676 } 677 } 678 error = sctp_inpcb_bind(so, nam, l); 679 return error; 680 } 681 682 /*This could be made common with sctp_detach() since they are identical */ 683 static int 684 sctp6_detach(struct socket *so) 685 { 686 struct sctp_inpcb *inp; 687 688 inp = (struct sctp_inpcb *)so->so_pcb; 689 if (inp == 0) 690 return EINVAL; 691 692 if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || 693 (so->so_rcv.sb_cc > 0)) 694 sctp_inpcb_free(inp, 1); 695 else 696 sctp_inpcb_free(inp, 0); 697 return 0; 698 } 699 700 static int 701 sctp6_disconnect(struct socket *so) 702 { 703 struct sctp_inpcb *inp; 704 705 inp = (struct sctp_inpcb *)so->so_pcb; 706 if (inp == NULL) { 707 return (ENOTCONN); 708 } 709 if (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 710 if (LIST_EMPTY(&inp->sctp_asoc_list)) { 711 /* No connection */ 712 return (ENOTCONN); 713 } else { 714 int some_on_streamwheel = 0; 715 struct sctp_association *asoc; 716 struct sctp_tcb *stcb; 717 718 stcb = LIST_FIRST(&inp->sctp_asoc_list); 719 if (stcb == NULL) { 720 return (EINVAL); 721 } 722 asoc = &stcb->asoc; 723 if (!TAILQ_EMPTY(&asoc->out_wheel)) { 724 /* Check to see if some data queued */ 725 struct sctp_stream_out *outs; 726 TAILQ_FOREACH(outs, &asoc->out_wheel, 727 next_spoke) { 728 if (!TAILQ_EMPTY(&outs->outqueue)) { 729 some_on_streamwheel = 1; 730 break; 731 } 732 } 733 } 734 735 if (TAILQ_EMPTY(&asoc->send_queue) && 736 TAILQ_EMPTY(&asoc->sent_queue) && 737 (some_on_streamwheel == 0)) { 738 /* nothing queued to send, so I'm done... */ 739 if ((SCTP_GET_STATE(asoc) != 740 SCTP_STATE_SHUTDOWN_SENT) && 741 (SCTP_GET_STATE(asoc) != 742 SCTP_STATE_SHUTDOWN_ACK_SENT)) { 743 /* only send SHUTDOWN the first time */ 744 #ifdef SCTP_DEBUG 745 if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { 746 printf("%s:%d sends a shutdown\n", 747 __FILE__, 748 __LINE__ 749 ); 750 } 751 #endif 752 sctp_send_shutdown(stcb, stcb->asoc.primary_destination); 753 sctp_chunk_output(stcb->sctp_ep, stcb, 1); 754 asoc->state = SCTP_STATE_SHUTDOWN_SENT; 755 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, 756 stcb->sctp_ep, stcb, 757 asoc->primary_destination); 758 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, 759 stcb->sctp_ep, stcb, 760 asoc->primary_destination); 761 } 762 } else { 763 /* 764 * we still got (or just got) data to send, 765 * so set SHUTDOWN_PENDING 766 */ 767 /* 768 * XXX sockets draft says that MSG_EOF should 769 * be sent with no data. currently, we will 770 * allow user data to be sent first and move 771 * to SHUTDOWN-PENDING 772 */ 773 asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; 774 } 775 return (0); 776 } 777 } else { 778 /* UDP model does not support this */ 779 return EOPNOTSUPP; 780 } 781 } 782 783 static int 784 sctp6_recvoob(struct socket *so, struct mbuf *m, int flags) 785 { 786 KASSERT(solocked(so)); 787 788 return EOPNOTSUPP; 789 } 790 791 static int 792 sctp6_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, 793 struct mbuf *control, struct lwp *l) 794 { 795 struct sctp_inpcb *inp; 796 struct in6pcb *inp6; 797 #ifdef INET 798 struct sockaddr_in6 *sin6; 799 #endif /* INET */ 800 /* No SPL needed since sctp_output does this */ 801 802 inp = (struct sctp_inpcb *)so->so_pcb; 803 if (inp == NULL) { 804 m_freem(control); 805 control = NULL; 806 m_freem(m); 807 return EINVAL; 808 } 809 inp6 = (struct in6pcb *)inp; 810 /* For the TCP model we may get a NULL addr, if we 811 * are a connected socket thats ok. 812 */ 813 if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) && 814 (nam == NULL)) { 815 goto connected_type; 816 } 817 if (nam == NULL) { 818 m_freem(m); 819 m_freem(control); 820 control = NULL; 821 return (EDESTADDRREQ); 822 } 823 824 #ifdef INET 825 sin6 = (struct sockaddr_in6 *)nam; 826 /* 827 * XXX XXX XXX Check sin6->sin6_len? 828 */ 829 if (inp6->in6p_flags & IN6P_IPV6_V6ONLY) { 830 /* 831 * if IPV6_V6ONLY flag, we discard datagrams 832 * destined to a v4 addr or v4-mapped addr 833 */ 834 if (nam->sa_family == AF_INET) { 835 return EINVAL; 836 } 837 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 838 return EINVAL; 839 } 840 } 841 842 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 843 if (!ip6_v6only) { 844 struct sockaddr_in sin; 845 /* convert v4-mapped into v4 addr and send */ 846 in6_sin6_2_sin(&sin, sin6); 847 return sctp_send(so, m, (struct sockaddr *)&sin, 848 control, l); 849 } else { 850 /* mapped addresses aren't enabled */ 851 return EINVAL; 852 } 853 } 854 #endif /* INET */ 855 connected_type: 856 /* now what about control */ 857 if (control) { 858 if (inp->control) { 859 printf("huh? control set?\n"); 860 m_freem(inp->control); 861 inp->control = NULL; 862 } 863 inp->control = control; 864 } 865 /* add it in possibly */ 866 if ((inp->pkt) && 867 (inp->pkt->m_flags & M_PKTHDR)) { 868 struct mbuf *x; 869 int c_len; 870 871 c_len = 0; 872 /* How big is it */ 873 for (x=m;x;x = x->m_next) { 874 c_len += x->m_len; 875 } 876 inp->pkt->m_pkthdr.len += c_len; 877 } 878 /* Place the data */ 879 if (inp->pkt) { 880 inp->pkt_last->m_next = m; 881 inp->pkt_last = m; 882 } else { 883 inp->pkt_last = inp->pkt = m; 884 } 885 if ((so->so_state & SS_MORETOCOME) == 0) { 886 /* 887 * note with the current version this code will only be 888 * used by OpenBSD, NetBSD and FreeBSD have methods for 889 * re-defining sosend() to use sctp_sosend(). One can 890 * optionally switch back to this code (by changing back 891 * the definitions but this is not advisable. 892 */ 893 int ret; 894 ret = sctp_output(inp, inp->pkt , nam, inp->control, l, 0); 895 inp->pkt = NULL; 896 inp->control = NULL; 897 return (ret); 898 } else { 899 return (0); 900 } 901 } 902 903 static int 904 sctp6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 905 { 906 KASSERT(solocked(so)); 907 908 m_freem(m); 909 m_freem(control); 910 911 return EOPNOTSUPP; 912 } 913 914 static int 915 sctp6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 916 { 917 int error = 0; 918 struct sctp_inpcb *inp; 919 struct in6pcb *inp6; 920 struct sctp_tcb *stcb; 921 #ifdef INET 922 struct sockaddr_in6 *sin6; 923 struct sockaddr_storage ss; 924 #endif /* INET */ 925 926 inp6 = (struct in6pcb *)so->so_pcb; 927 inp = (struct sctp_inpcb *)so->so_pcb; 928 if (inp == 0) { 929 return (ECONNRESET); /* I made the same as TCP since 930 * we are not setup? */ 931 } 932 SCTP_ASOC_CREATE_LOCK(inp); 933 SCTP_INP_RLOCK(inp); 934 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 935 SCTP_PCB_FLAGS_UNBOUND) { 936 /* Bind a ephemeral port */ 937 SCTP_INP_RUNLOCK(inp); 938 error = sctp6_bind(so, NULL, l); 939 if (error) { 940 SCTP_ASOC_CREATE_UNLOCK(inp); 941 942 return (error); 943 } 944 SCTP_INP_RLOCK(inp); 945 } 946 947 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 948 (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { 949 /* We are already connected AND the TCP model */ 950 SCTP_INP_RUNLOCK(inp); 951 SCTP_ASOC_CREATE_UNLOCK(inp); 952 return (EADDRINUSE); 953 } 954 955 #ifdef INET 956 sin6 = (struct sockaddr_in6 *)nam; 957 958 /* 959 * XXX XXX XXX Check sin6->sin6_len? 960 */ 961 962 if (inp6->in6p_flags & IN6P_IPV6_V6ONLY) { 963 /* 964 * if IPV6_V6ONLY flag, ignore connections 965 * destined to a v4 addr or v4-mapped addr 966 */ 967 if (nam->sa_family == AF_INET) { 968 SCTP_INP_RUNLOCK(inp); 969 SCTP_ASOC_CREATE_UNLOCK(inp); 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 return EINVAL; 976 } 977 } 978 979 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 980 if (!ip6_v6only) { 981 /* convert v4-mapped into v4 addr */ 982 in6_sin6_2_sin((struct sockaddr_in *)&ss, sin6); 983 nam = (struct sockaddr *)&ss; 984 } else { 985 /* mapped addresses aren't enabled */ 986 SCTP_INP_RUNLOCK(inp); 987 SCTP_ASOC_CREATE_UNLOCK(inp); 988 return EINVAL; 989 } 990 } 991 #endif /* INET */ 992 993 /* Now do we connect? */ 994 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 995 stcb = LIST_FIRST(&inp->sctp_asoc_list); 996 if (stcb) { 997 SCTP_TCB_UNLOCK (stcb); 998 } 999 SCTP_INP_RUNLOCK(inp); 1000 } else { 1001 SCTP_INP_RUNLOCK(inp); 1002 SCTP_INP_WLOCK(inp); 1003 SCTP_INP_INCR_REF(inp); 1004 SCTP_INP_WUNLOCK(inp); 1005 stcb = sctp_findassociation_ep_addr(&inp, nam, NULL, NULL, NULL); 1006 if (stcb == NULL) { 1007 SCTP_INP_WLOCK(inp); 1008 SCTP_INP_DECR_REF(inp); 1009 SCTP_INP_WUNLOCK(inp); 1010 } 1011 } 1012 1013 if (stcb != NULL) { 1014 /* Already have or am bring up an association */ 1015 SCTP_ASOC_CREATE_UNLOCK(inp); 1016 SCTP_TCB_UNLOCK (stcb); 1017 return (EALREADY); 1018 } 1019 /* We are GOOD to go */ 1020 stcb = sctp_aloc_assoc(inp, nam, 1, &error, 0); 1021 SCTP_ASOC_CREATE_UNLOCK(inp); 1022 if (stcb == NULL) { 1023 /* Gak! no memory */ 1024 return (error); 1025 } 1026 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { 1027 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; 1028 /* Set the connected flag so we can queue data */ 1029 soisconnecting(so); 1030 } 1031 stcb->asoc.state = SCTP_STATE_COOKIE_WAIT; 1032 SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); 1033 sctp_send_initiate(inp, stcb); 1034 SCTP_TCB_UNLOCK (stcb); 1035 return error; 1036 } 1037 1038 static int 1039 sctp6_connect2(struct socket *so, struct socket *so2) 1040 { 1041 KASSERT(solocked(so)); 1042 1043 return EOPNOTSUPP; 1044 } 1045 1046 static int 1047 sctp6_getaddr(struct socket *so, struct sockaddr *nam) 1048 { 1049 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; 1050 struct sctp_inpcb *inp; 1051 int error; 1052 1053 /* 1054 * Do the malloc first in case it blocks. 1055 */ 1056 memset(sin6, 0, sizeof(*sin6)); 1057 sin6->sin6_family = AF_INET6; 1058 sin6->sin6_len = sizeof(*sin6); 1059 1060 inp = (struct sctp_inpcb *)so->so_pcb; 1061 if (inp == NULL) { 1062 return ECONNRESET; 1063 } 1064 1065 sin6->sin6_port = inp->sctp_lport; 1066 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 1067 /* For the bound all case you get back 0 */ 1068 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { 1069 struct sctp_tcb *stcb; 1070 const struct sockaddr_in6 *sin_a6; 1071 struct sctp_nets *net; 1072 int fnd; 1073 1074 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1075 if (stcb == NULL) { 1076 goto notConn6; 1077 } 1078 fnd = 0; 1079 sin_a6 = NULL; 1080 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1081 sin_a6 = (const struct sockaddr_in6 *)rtcache_getdst(&net->ro); 1082 if (sin_a6->sin6_family == AF_INET6) { 1083 fnd = 1; 1084 break; 1085 } 1086 } 1087 if ((!fnd) || (sin_a6 == NULL)) { 1088 /* punt */ 1089 goto notConn6; 1090 } 1091 sin6->sin6_addr = sctp_ipv6_source_address_selection( 1092 inp, stcb, &net->ro, net, 0); 1093 1094 } else { 1095 /* For the bound all case you get back 0 */ 1096 notConn6: 1097 memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); 1098 } 1099 } else { 1100 /* Take the first IPv6 address in the list */ 1101 struct sctp_laddr *laddr; 1102 int fnd = 0; 1103 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 1104 if (laddr->ifa->ifa_addr->sa_family == AF_INET6) { 1105 struct sockaddr_in6 *sin_a; 1106 sin_a = (struct sockaddr_in6 *)laddr->ifa->ifa_addr; 1107 sin6->sin6_addr = sin_a->sin6_addr; 1108 fnd = 1; 1109 break; 1110 } 1111 } 1112 if (!fnd) { 1113 return ENOENT; 1114 } 1115 } 1116 /* Scoping things for v6 */ 1117 if ((error = sa6_recoverscope(sin6)) != 0) 1118 return (error); 1119 1120 return (0); 1121 } 1122 1123 static int 1124 sctp6_peeraddr(struct socket *so, struct sockaddr *nam) 1125 { 1126 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam; 1127 int fnd, error; 1128 const struct sockaddr_in6 *sin_a6; 1129 struct sctp_inpcb *inp; 1130 struct sctp_tcb *stcb; 1131 struct sctp_nets *net; 1132 /* 1133 * Do the malloc first in case it blocks. 1134 */ 1135 inp = (struct sctp_inpcb *)so->so_pcb; 1136 if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 1137 /* UDP type and listeners will drop out here */ 1138 return (ENOTCONN); 1139 } 1140 memset(sin6, 0, sizeof(*sin6)); 1141 sin6->sin6_family = AF_INET6; 1142 sin6->sin6_len = sizeof(*sin6); 1143 1144 /* We must recapture incase we blocked */ 1145 inp = (struct sctp_inpcb *)so->so_pcb; 1146 if (inp == NULL) { 1147 return ECONNRESET; 1148 } 1149 stcb = LIST_FIRST(&inp->sctp_asoc_list); 1150 if (stcb == NULL) { 1151 return ECONNRESET; 1152 } 1153 fnd = 0; 1154 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 1155 sin_a6 = (const struct sockaddr_in6 *)rtcache_getdst(&net->ro); 1156 if (sin_a6->sin6_family == AF_INET6) { 1157 fnd = 1; 1158 sin6->sin6_port = stcb->rport; 1159 sin6->sin6_addr = sin_a6->sin6_addr; 1160 break; 1161 } 1162 } 1163 if (!fnd) { 1164 /* No IPv4 address */ 1165 return ENOENT; 1166 } 1167 if ((error = sa6_recoverscope(sin6)) != 0) 1168 return (error); 1169 1170 return (0); 1171 } 1172 1173 static int 1174 sctp6_sockaddr(struct socket *so, struct sockaddr *nam) 1175 { 1176 struct in6pcb *inp6 = sotoin6pcb(so); 1177 int error; 1178 1179 if (inp6 == NULL) 1180 return EINVAL; 1181 1182 /* allow v6 addresses precedence */ 1183 error = sctp6_getaddr(so, nam); 1184 if (error) { 1185 /* try v4 next if v6 failed */ 1186 error = sctp_sockaddr(so, nam); 1187 if (error) { 1188 return (error); 1189 } 1190 1191 /* if I'm V6ONLY, convert it to v4-mapped */ 1192 if (inp6->in6p_flags & IN6P_IPV6_V6ONLY) { 1193 struct sockaddr_in6 sin6; 1194 in6_sin_2_v4mapsin6((struct sockaddr_in *)nam, &sin6); 1195 memcpy(nam, &sin6, sizeof(struct sockaddr_in6)); 1196 } 1197 } 1198 return (error); 1199 } 1200 1201 #if 0 1202 static int 1203 sctp6_getpeeraddr(struct socket *so, struct sockaddr *nam) 1204 { 1205 struct in6pcb *inp6 = sotoin6pcb(so); 1206 int error; 1207 1208 if (inp6 == NULL) 1209 return EINVAL; 1210 1211 /* allow v6 addresses precedence */ 1212 error = sctp6_peeraddr(so, nam); 1213 if (error) { 1214 /* try v4 next if v6 failed */ 1215 error = sctp_peeraddr(so, nam); 1216 if (error) { 1217 return (error); 1218 } 1219 /* if I'm V6ONLY, convert it to v4-mapped */ 1220 if ((inp6->in6p_flags & IN6P_IPV6_V6ONLY)) { 1221 struct sockaddr_in6 sin6; 1222 in6_sin_2_v4mapsin6((struct sockaddr_in *)addr, &sin6); 1223 memcpy(addr, &sin6, sizeof(struct sockaddr_in6)); 1224 } 1225 } 1226 return error; 1227 } 1228 #endif 1229 1230 static int 1231 sctp6_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 1232 { 1233 int error = 0; 1234 int family; 1235 1236 if (cmd == SIOCCONNECTX) { 1237 solock(so); 1238 error = sctp_do_connect_x(so, nam, curlwp, 0); 1239 sounlock(so); 1240 } else if (cmd == SIOCCONNECTXDEL) { 1241 solock(so); 1242 error = sctp_do_connect_x(so, nam, curlwp, 1); 1243 sounlock(so); 1244 } else { 1245 family = so->so_proto->pr_domain->dom_family; 1246 switch (family) { 1247 #ifdef INET 1248 case PF_INET: 1249 error = in_control(so, cmd, nam, ifp); 1250 break; 1251 #endif 1252 #ifdef INET6 1253 case PF_INET6: 1254 error = in6_control(so, cmd, nam, ifp); 1255 break; 1256 #endif 1257 default: 1258 error = EAFNOSUPPORT; 1259 } 1260 } 1261 return (error); 1262 } 1263 1264 static int 1265 sctp6_accept(struct socket *so, struct sockaddr *nam) 1266 { 1267 return sctp_accept(so, nam); 1268 } 1269 1270 static int 1271 sctp6_stat(struct socket *so, struct stat *ub) 1272 { 1273 return 0; 1274 } 1275 1276 static int 1277 sctp6_listen(struct socket *so, struct lwp *l) 1278 { 1279 return sctp_listen(so, l); 1280 } 1281 1282 static int 1283 sctp6_shutdown(struct socket *so) 1284 { 1285 return sctp_shutdown(so); 1286 } 1287 1288 static int 1289 sctp6_rcvd(struct socket *so, int flags, struct lwp *l) 1290 { 1291 KASSERT(solocked(so)); 1292 1293 return sctp_rcvd(so, flags, l); 1294 } 1295 1296 static int 1297 sctp6_purgeif(struct socket *so, struct ifnet *ifp) 1298 { 1299 struct ifaddr *ifa; 1300 /* FIXME NOMPSAFE */ 1301 IFADDR_READER_FOREACH(ifa, ifp) { 1302 if (ifa->ifa_addr->sa_family == PF_INET6) { 1303 sctp_delete_ip_address(ifa); 1304 } 1305 } 1306 1307 #ifndef NET_MPSAFE 1308 mutex_enter(softnet_lock); 1309 #endif 1310 in6_purgeif(ifp); 1311 #ifndef NET_MPSAFE 1312 mutex_exit(softnet_lock); 1313 #endif 1314 1315 return 0; 1316 } 1317 1318 PR_WRAP_USRREQS(sctp6) 1319 #define sctp6_attach sctp6_attach_wrapper 1320 #define sctp6_detach sctp6_detach_wrapper 1321 #define sctp6_accept sctp6_accept_wrapper 1322 #define sctp6_bind sctp6_bind_wrapper 1323 #define sctp6_listen sctp6_listen_wrapper 1324 #define sctp6_connect sctp6_connect_wrapper 1325 #define sctp6_connect2 sctp6_connect2_wrapper 1326 #define sctp6_disconnect sctp6_disconnect_wrapper 1327 #define sctp6_shutdown sctp6_shutdown_wrapper 1328 #define sctp6_abort sctp6_abort_wrapper 1329 #define sctp6_ioctl sctp6_ioctl_wrapper 1330 #define sctp6_stat sctp6_stat_wrapper 1331 #define sctp6_peeraddr sctp6_peeraddr_wrapper 1332 #define sctp6_sockaddr sctp6_sockaddr_wrapper 1333 #define sctp6_rcvd sctp6_rcvd_wrapper 1334 #define sctp6_recvoob sctp6_recvoob_wrapper 1335 #define sctp6_send sctp6_send_wrapper 1336 #define sctp6_sendoob sctp6_sendoob_wrapper 1337 #define sctp6_purgeif sctp6_purgeif_wrapper 1338 1339 const struct pr_usrreqs sctp6_usrreqs = { 1340 .pr_attach = sctp6_attach, 1341 .pr_detach = sctp6_detach, 1342 .pr_accept = sctp6_accept, 1343 .pr_bind = sctp6_bind, 1344 .pr_listen = sctp6_listen, 1345 .pr_connect = sctp6_connect, 1346 .pr_connect2 = sctp6_connect2, 1347 .pr_disconnect = sctp6_disconnect, 1348 .pr_shutdown = sctp6_shutdown, 1349 .pr_abort = sctp6_abort, 1350 .pr_ioctl = sctp6_ioctl, 1351 .pr_stat = sctp6_stat, 1352 .pr_peeraddr = sctp6_peeraddr, 1353 .pr_sockaddr = sctp6_sockaddr, 1354 .pr_rcvd = sctp6_rcvd, 1355 .pr_recvoob = sctp6_recvoob, 1356 .pr_send = sctp6_send, 1357 .pr_sendoob = sctp6_sendoob, 1358 .pr_purgeif = sctp6_purgeif, 1359 }; 1360