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