1 /* $OpenBSD: raw_ip6.c,v 1.184 2024/04/17 20:48:51 bluhm Exp $ */ 2 /* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 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. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1982, 1986, 1988, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 62 */ 63 64 #include "pf.h" 65 66 #include <sys/param.h> 67 #include <sys/malloc.h> 68 #include <sys/mbuf.h> 69 #include <sys/socket.h> 70 #include <sys/protosw.h> 71 #include <sys/socketvar.h> 72 #include <sys/errno.h> 73 #include <sys/systm.h> 74 #include <sys/sysctl.h> 75 76 #include <net/if.h> 77 #include <net/if_var.h> 78 #include <net/route.h> 79 80 #include <netinet/in.h> 81 #include <netinet6/in6_var.h> 82 #include <netinet/ip6.h> 83 #include <netinet6/ip6_var.h> 84 #ifdef MROUTING 85 #include <netinet6/ip6_mroute.h> 86 #endif 87 #include <netinet/icmp6.h> 88 #include <netinet/ip.h> 89 #include <netinet/in_pcb.h> 90 #include <netinet6/nd6.h> 91 #include <netinet6/ip6protosw.h> 92 #include <netinet6/raw_ip6.h> 93 94 #if NPF > 0 95 #include <net/pfvar.h> 96 #endif 97 98 #include <sys/stdarg.h> 99 100 /* 101 * Raw interface to IP6 protocol. 102 */ 103 104 struct inpcbtable rawin6pcbtable; 105 106 struct cpumem *rip6counters; 107 108 const struct pr_usrreqs rip6_usrreqs = { 109 .pru_attach = rip6_attach, 110 .pru_detach = rip6_detach, 111 .pru_lock = rip6_lock, 112 .pru_unlock = rip6_unlock, 113 .pru_locked = rip6_locked, 114 .pru_bind = rip6_bind, 115 .pru_connect = rip6_connect, 116 .pru_disconnect = rip6_disconnect, 117 .pru_shutdown = rip6_shutdown, 118 .pru_send = rip6_send, 119 .pru_control = in6_control, 120 .pru_sockaddr = in6_sockaddr, 121 .pru_peeraddr = in6_peeraddr, 122 }; 123 124 /* 125 * Initialize raw connection block queue. 126 */ 127 void 128 rip6_init(void) 129 { 130 in_pcbinit(&rawin6pcbtable, 1); 131 rip6counters = counters_alloc(rip6s_ncounters); 132 } 133 134 int 135 rip6_input(struct mbuf **mp, int *offp, int proto, int af) 136 { 137 struct mbuf *m = *mp; 138 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 139 struct inpcb *inp; 140 SIMPLEQ_HEAD(, inpcb) inpcblist; 141 struct in6_addr *key; 142 struct sockaddr_in6 rip6src; 143 uint8_t type; 144 145 KASSERT(af == AF_INET6); 146 147 if (proto == IPPROTO_ICMPV6) { 148 struct icmp6_hdr *icmp6; 149 150 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offp, 151 sizeof(*icmp6)); 152 if (icmp6 == NULL) 153 return IPPROTO_DONE; 154 type = icmp6->icmp6_type; 155 } else 156 rip6stat_inc(rip6s_ipackets); 157 158 memset(&rip6src, 0, sizeof(rip6src)); 159 rip6src.sin6_family = AF_INET6; 160 rip6src.sin6_len = sizeof(rip6src); 161 /* KAME hack: recover scopeid */ 162 in6_recoverscope(&rip6src, &ip6->ip6_src); 163 164 key = &ip6->ip6_dst; 165 #if NPF > 0 166 if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) { 167 struct pf_divert *divert; 168 169 divert = pf_find_divert(m); 170 KASSERT(divert != NULL); 171 switch (divert->type) { 172 case PF_DIVERT_TO: 173 key = &divert->addr.v6; 174 break; 175 case PF_DIVERT_REPLY: 176 break; 177 default: 178 panic("%s: unknown divert type %d, mbuf %p, divert %p", 179 __func__, divert->type, m, divert); 180 } 181 } 182 #endif 183 SIMPLEQ_INIT(&inpcblist); 184 rw_enter_write(&rawin6pcbtable.inpt_notify); 185 mtx_enter(&rawin6pcbtable.inpt_mtx); 186 TAILQ_FOREACH(inp, &rawin6pcbtable.inpt_queue, inp_queue) { 187 KASSERT(ISSET(inp->inp_flags, INP_IPV6)); 188 189 /* 190 * Packet must not be inserted after disconnected wakeup 191 * call. To avoid race, check again when holding receive 192 * buffer mutex. 193 */ 194 if (ISSET(READ_ONCE(inp->inp_socket->so_rcv.sb_state), 195 SS_CANTRCVMORE)) 196 continue; 197 if (rtable_l2(inp->inp_rtableid) != 198 rtable_l2(m->m_pkthdr.ph_rtableid)) 199 continue; 200 201 if ((inp->inp_ipv6.ip6_nxt || proto == IPPROTO_ICMPV6) && 202 inp->inp_ipv6.ip6_nxt != proto) 203 continue; 204 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) && 205 !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key)) 206 continue; 207 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) && 208 !IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, &ip6->ip6_src)) 209 continue; 210 if (proto == IPPROTO_ICMPV6 && inp->inp_icmp6filt) { 211 if (ICMP6_FILTER_WILLBLOCK(type, inp->inp_icmp6filt)) 212 continue; 213 } 214 if (proto != IPPROTO_ICMPV6 && inp->inp_cksum6 != -1) { 215 rip6stat_inc(rip6s_isum); 216 /* 217 * Although in6_cksum() does not need the position of 218 * the checksum field for verification, enforce that it 219 * is located within the packet. Userland has given 220 * a checksum offset, a packet too short for that is 221 * invalid. Avoid overflow with user supplied offset. 222 */ 223 if (m->m_pkthdr.len < *offp + 2 || 224 m->m_pkthdr.len - *offp - 2 < inp->inp_cksum6 || 225 in6_cksum(m, proto, *offp, 226 m->m_pkthdr.len - *offp)) { 227 rip6stat_inc(rip6s_badsum); 228 continue; 229 } 230 } 231 232 in_pcbref(inp); 233 SIMPLEQ_INSERT_TAIL(&inpcblist, inp, inp_notify); 234 } 235 mtx_leave(&rawin6pcbtable.inpt_mtx); 236 237 if (SIMPLEQ_EMPTY(&inpcblist)) { 238 struct counters_ref ref; 239 uint64_t *counters; 240 241 rw_exit_write(&rawin6pcbtable.inpt_notify); 242 243 if (proto != IPPROTO_ICMPV6) { 244 rip6stat_inc(rip6s_nosock); 245 if (m->m_flags & M_MCAST) 246 rip6stat_inc(rip6s_nosockmcast); 247 } 248 if (proto == IPPROTO_NONE || proto == IPPROTO_ICMPV6) { 249 m_freem(m); 250 } else { 251 int prvnxt = ip6_get_prevhdr(m, *offp); 252 253 icmp6_error(m, ICMP6_PARAM_PROB, 254 ICMP6_PARAMPROB_NEXTHEADER, prvnxt); 255 } 256 counters = counters_enter(&ref, ip6counters); 257 counters[ip6s_delivered]--; 258 counters_leave(&ref, ip6counters); 259 260 return IPPROTO_DONE; 261 } 262 263 while ((inp = SIMPLEQ_FIRST(&inpcblist)) != NULL) { 264 struct mbuf *n, *opts = NULL; 265 266 SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify); 267 if (SIMPLEQ_EMPTY(&inpcblist)) 268 n = m; 269 else 270 n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 271 if (n != NULL) { 272 struct socket *so = inp->inp_socket; 273 int ret = 0; 274 275 if (inp->inp_flags & IN6P_CONTROLOPTS) 276 ip6_savecontrol(inp, n, &opts); 277 /* strip intermediate headers */ 278 m_adj(n, *offp); 279 280 mtx_enter(&so->so_rcv.sb_mtx); 281 if (!ISSET(inp->inp_socket->so_rcv.sb_state, 282 SS_CANTRCVMORE)) { 283 ret = sbappendaddr(so, &so->so_rcv, 284 sin6tosa(&rip6src), n, opts); 285 } 286 mtx_leave(&so->so_rcv.sb_mtx); 287 288 if (ret == 0) { 289 m_freem(n); 290 m_freem(opts); 291 rip6stat_inc(rip6s_fullsock); 292 } else 293 sorwakeup(so); 294 } 295 in_pcbunref(inp); 296 } 297 rw_exit_write(&rawin6pcbtable.inpt_notify); 298 299 return IPPROTO_DONE; 300 } 301 302 void 303 rip6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d) 304 { 305 struct ip6_hdr *ip6; 306 struct ip6ctlparam *ip6cp = NULL; 307 struct sockaddr_in6 *sa6 = satosin6(sa); 308 const struct sockaddr_in6 *sa6_src = NULL; 309 void *cmdarg; 310 void (*notify)(struct inpcb *, int) = in_rtchange; 311 int nxt; 312 313 if (sa->sa_family != AF_INET6 || 314 sa->sa_len != sizeof(struct sockaddr_in6)) 315 return; 316 317 if ((unsigned)cmd >= PRC_NCMDS) 318 return; 319 if (PRC_IS_REDIRECT(cmd)) 320 notify = in_rtchange, d = NULL; 321 else if (cmd == PRC_HOSTDEAD) 322 d = NULL; 323 else if (cmd == PRC_MSGSIZE) 324 ; /* special code is present, see below */ 325 else if (inet6ctlerrmap[cmd] == 0) 326 return; 327 328 /* if the parameter is from icmp6, decode it. */ 329 if (d != NULL) { 330 ip6cp = (struct ip6ctlparam *)d; 331 ip6 = ip6cp->ip6c_ip6; 332 cmdarg = ip6cp->ip6c_cmdarg; 333 sa6_src = ip6cp->ip6c_src; 334 nxt = ip6cp->ip6c_nxt; 335 } else { 336 ip6 = NULL; 337 cmdarg = NULL; 338 sa6_src = &sa6_any; 339 nxt = -1; 340 } 341 342 if (ip6 && cmd == PRC_MSGSIZE) { 343 int valid = 0; 344 struct inpcb *inp; 345 346 /* 347 * Check to see if we have a valid raw IPv6 socket 348 * corresponding to the address in the ICMPv6 message 349 * payload, and the protocol (ip6_nxt) meets the socket. 350 * XXX chase extension headers, or pass final nxt value 351 * from icmp6_notify_error() 352 */ 353 inp = in6_pcblookup(&rawin6pcbtable, &sa6->sin6_addr, 0, 354 &sa6_src->sin6_addr, 0, rdomain); 355 356 if (inp && inp->inp_ipv6.ip6_nxt && 357 inp->inp_ipv6.ip6_nxt == nxt) 358 valid = 1; 359 360 /* 361 * Depending on the value of "valid" and routing table 362 * size (mtudisc_{hi,lo}wat), we will: 363 * - recalculate the new MTU and create the 364 * corresponding routing entry, or 365 * - ignore the MTU change notification. 366 */ 367 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 368 in_pcbunref(inp); 369 370 /* 371 * regardless of if we called icmp6_mtudisc_update(), 372 * we need to call in6_pcbnotify(), to notify path 373 * MTU change to the userland (2292bis-02), because 374 * some unconnected sockets may share the same 375 * destination and want to know the path MTU. 376 */ 377 } 378 379 in6_pcbnotify(&rawin6pcbtable, sa6, 0, 380 sa6_src, 0, rdomain, cmd, cmdarg, notify); 381 } 382 383 /* 384 * Generate IPv6 header and pass packet to ip6_output. 385 * Tack on options user may have setup with control call. 386 */ 387 int 388 rip6_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, 389 struct mbuf *control) 390 { 391 struct in6_addr *dst; 392 struct ip6_hdr *ip6; 393 struct inpcb *inp; 394 u_int plen = m->m_pkthdr.len; 395 int error = 0; 396 struct ip6_pktopts opt, *optp = NULL; 397 int type; /* for ICMPv6 output statistics only */ 398 int priv = 0; 399 int flags; 400 401 inp = sotoinpcb(so); 402 403 priv = 0; 404 if ((so->so_state & SS_PRIV) != 0) 405 priv = 1; 406 if (control) { 407 if ((error = ip6_setpktopts(control, &opt, 408 inp->inp_outputopts6, 409 priv, so->so_proto->pr_protocol)) != 0) 410 goto bad; 411 optp = &opt; 412 } else 413 optp = inp->inp_outputopts6; 414 415 if (dstaddr->sa_family != AF_INET6) { 416 error = EAFNOSUPPORT; 417 goto bad; 418 } 419 dst = &satosin6(dstaddr)->sin6_addr; 420 if (IN6_IS_ADDR_V4MAPPED(dst)) { 421 error = EADDRNOTAVAIL; 422 goto bad; 423 } 424 425 /* 426 * For an ICMPv6 packet, we should know its type and code 427 * to update statistics. 428 */ 429 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 430 struct icmp6_hdr *icmp6; 431 if (m->m_len < sizeof(struct icmp6_hdr) && 432 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 433 error = ENOBUFS; 434 goto bad; 435 } 436 icmp6 = mtod(m, struct icmp6_hdr *); 437 type = icmp6->icmp6_type; 438 } 439 440 M_PREPEND(m, sizeof(*ip6), M_DONTWAIT); 441 if (!m) { 442 error = ENOBUFS; 443 goto bad; 444 } 445 ip6 = mtod(m, struct ip6_hdr *); 446 447 /* 448 * Next header might not be ICMP6 but use its pseudo header anyway. 449 */ 450 ip6->ip6_dst = *dst; 451 452 /* KAME hack: embed scopeid */ 453 if (in6_embedscope(&ip6->ip6_dst, satosin6(dstaddr), 454 optp, inp->inp_moptions6) != 0) { 455 error = EINVAL; 456 goto bad; 457 } 458 459 /* 460 * Source address selection. 461 */ 462 { 463 const struct in6_addr *in6a; 464 465 error = in6_pcbselsrc(&in6a, satosin6(dstaddr), inp, optp); 466 if (error) 467 goto bad; 468 469 ip6->ip6_src = *in6a; 470 } 471 472 ip6->ip6_flow = inp->inp_flowinfo & IPV6_FLOWINFO_MASK; 473 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 474 ip6->ip6_vfc |= IPV6_VERSION; 475 #if 0 /* ip6_plen will be filled in ip6_output. */ 476 ip6->ip6_plen = htons((u_short)plen); 477 #endif 478 ip6->ip6_nxt = inp->inp_ipv6.ip6_nxt; 479 ip6->ip6_hlim = in6_selecthlim(inp); 480 481 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 482 inp->inp_cksum6 != -1) { 483 struct mbuf *n; 484 int off; 485 u_int16_t *sump; 486 int sumoff; 487 488 /* compute checksum */ 489 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 490 off = offsetof(struct icmp6_hdr, icmp6_cksum); 491 else 492 off = inp->inp_cksum6; 493 if (plen < 2 || plen - 2 < off) { 494 error = EINVAL; 495 goto bad; 496 } 497 off += sizeof(struct ip6_hdr); 498 499 n = m_pulldown(m, off, sizeof(*sump), &sumoff); 500 if (n == NULL) { 501 m = NULL; 502 error = ENOBUFS; 503 goto bad; 504 } 505 sump = (u_int16_t *)(mtod(n, caddr_t) + sumoff); 506 *sump = 0; 507 *sump = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 508 } 509 510 flags = 0; 511 if (inp->inp_flags & IN6P_MINMTU) 512 flags |= IPV6_MINMTU; 513 514 /* force routing table */ 515 m->m_pkthdr.ph_rtableid = inp->inp_rtableid; 516 517 #if NPF > 0 518 if (inp->inp_socket->so_state & SS_ISCONNECTED && 519 so->so_proto->pr_protocol != IPPROTO_ICMPV6) 520 pf_mbuf_link_inpcb(m, inp); 521 #endif 522 523 error = ip6_output(m, optp, &inp->inp_route, flags, 524 inp->inp_moptions6, &inp->inp_seclevel); 525 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 526 icmp6stat_inc(icp6s_outhist + type); 527 } else 528 rip6stat_inc(rip6s_opackets); 529 530 goto freectl; 531 532 bad: 533 m_freem(m); 534 535 freectl: 536 if (control) { 537 ip6_clearpktopts(&opt, -1); 538 m_freem(control); 539 } 540 return (error); 541 } 542 543 /* 544 * Raw IPv6 socket option processing. 545 */ 546 int 547 rip6_ctloutput(int op, struct socket *so, int level, int optname, 548 struct mbuf *m) 549 { 550 #ifdef MROUTING 551 int error; 552 #endif 553 554 switch (level) { 555 case IPPROTO_IPV6: 556 switch (optname) { 557 #ifdef MROUTING 558 case MRT6_INIT: 559 case MRT6_DONE: 560 case MRT6_ADD_MIF: 561 case MRT6_DEL_MIF: 562 case MRT6_ADD_MFC: 563 case MRT6_DEL_MFC: 564 if (op == PRCO_SETOPT) { 565 error = ip6_mrouter_set(optname, so, m); 566 } else if (op == PRCO_GETOPT) 567 error = ip6_mrouter_get(optname, so, m); 568 else 569 error = EINVAL; 570 return (error); 571 #endif 572 case IPV6_CHECKSUM: 573 return (ip6_raw_ctloutput(op, so, level, optname, m)); 574 default: 575 return (ip6_ctloutput(op, so, level, optname, m)); 576 } 577 578 case IPPROTO_ICMPV6: 579 /* 580 * XXX: is it better to call icmp6_ctloutput() directly 581 * from protosw? 582 */ 583 return (icmp6_ctloutput(op, so, level, optname, m)); 584 585 default: 586 return EINVAL; 587 } 588 } 589 590 extern u_long rip6_sendspace; 591 extern u_long rip6_recvspace; 592 593 int 594 rip6_attach(struct socket *so, int proto, int wait) 595 { 596 struct inpcb *inp; 597 int error; 598 599 if (so->so_pcb) 600 panic("%s", __func__); 601 if ((so->so_state & SS_PRIV) == 0) 602 return (EACCES); 603 if (proto < 0 || proto >= IPPROTO_MAX) 604 return EPROTONOSUPPORT; 605 606 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace))) 607 return error; 608 NET_ASSERT_LOCKED(); 609 if ((error = in_pcballoc(so, &rawin6pcbtable, wait))) 610 return error; 611 612 inp = sotoinpcb(so); 613 inp->inp_ipv6.ip6_nxt = proto; 614 inp->inp_cksum6 = -1; 615 616 inp->inp_icmp6filt = malloc(sizeof(struct icmp6_filter), M_PCB, 617 wait == M_WAIT ? M_WAITOK : M_NOWAIT); 618 if (inp->inp_icmp6filt == NULL) { 619 in_pcbdetach(inp); 620 return ENOMEM; 621 } 622 ICMP6_FILTER_SETPASSALL(inp->inp_icmp6filt); 623 return 0; 624 } 625 626 int 627 rip6_detach(struct socket *so) 628 { 629 struct inpcb *inp = sotoinpcb(so); 630 631 soassertlocked(so); 632 633 if (inp == NULL) 634 panic("%s", __func__); 635 #ifdef MROUTING 636 if (so == ip6_mrouter[inp->inp_rtableid]) 637 ip6_mrouter_done(so); 638 #endif 639 free(inp->inp_icmp6filt, M_PCB, sizeof(struct icmp6_filter)); 640 inp->inp_icmp6filt = NULL; 641 642 in_pcbdetach(inp); 643 644 return (0); 645 } 646 647 void 648 rip6_lock(struct socket *so) 649 { 650 struct inpcb *inp = sotoinpcb(so); 651 652 NET_ASSERT_LOCKED(); 653 mtx_enter(&inp->inp_mtx); 654 } 655 656 void 657 rip6_unlock(struct socket *so) 658 { 659 struct inpcb *inp = sotoinpcb(so); 660 661 NET_ASSERT_LOCKED(); 662 mtx_leave(&inp->inp_mtx); 663 } 664 665 int 666 rip6_locked(struct socket *so) 667 { 668 struct inpcb *inp = sotoinpcb(so); 669 670 return mtx_owned(&inp->inp_mtx); 671 } 672 673 int 674 rip6_bind(struct socket *so, struct mbuf *nam, struct proc *p) 675 { 676 struct inpcb *inp = sotoinpcb(so); 677 struct sockaddr_in6 *addr; 678 int error; 679 680 soassertlocked(so); 681 682 if ((error = in6_nam2sin6(nam, &addr))) 683 return (error); 684 685 /* 686 * Make sure to not enter in_pcblookup_local(), local ports 687 * are non-sensical for raw sockets. 688 */ 689 addr->sin6_port = 0; 690 691 if ((error = in6_pcbaddrisavail(inp, addr, 0, p))) 692 return (error); 693 694 mtx_enter(&rawin6pcbtable.inpt_mtx); 695 inp->inp_laddr6 = addr->sin6_addr; 696 mtx_leave(&rawin6pcbtable.inpt_mtx); 697 698 return (0); 699 } 700 701 int 702 rip6_connect(struct socket *so, struct mbuf *nam) 703 { 704 struct inpcb *inp = sotoinpcb(so); 705 struct sockaddr_in6 *addr; 706 const struct in6_addr *in6a; 707 int error; 708 709 soassertlocked(so); 710 711 if ((error = in6_nam2sin6(nam, &addr))) 712 return (error); 713 714 /* Source address selection. XXX: need pcblookup? */ 715 error = in6_pcbselsrc(&in6a, addr, inp, inp->inp_outputopts6); 716 if (error) 717 return (error); 718 719 mtx_enter(&rawin6pcbtable.inpt_mtx); 720 inp->inp_laddr6 = *in6a; 721 inp->inp_faddr6 = addr->sin6_addr; 722 mtx_leave(&rawin6pcbtable.inpt_mtx); 723 soisconnected(so); 724 725 return (0); 726 } 727 728 int 729 rip6_disconnect(struct socket *so) 730 { 731 struct inpcb *inp = sotoinpcb(so); 732 733 soassertlocked(so); 734 735 if ((so->so_state & SS_ISCONNECTED) == 0) 736 return (ENOTCONN); 737 738 soisdisconnected(so); 739 mtx_enter(&rawin6pcbtable.inpt_mtx); 740 inp->inp_faddr6 = in6addr_any; 741 mtx_leave(&rawin6pcbtable.inpt_mtx); 742 743 return (0); 744 } 745 746 int 747 rip6_shutdown(struct socket *so) 748 { 749 /* 750 * Mark the connection as being incapable of further input. 751 */ 752 soassertlocked(so); 753 socantsendmore(so); 754 return (0); 755 } 756 757 int 758 rip6_send(struct socket *so, struct mbuf *m, struct mbuf *nam, 759 struct mbuf *control) 760 { 761 struct inpcb *inp = sotoinpcb(so); 762 struct sockaddr_in6 dst; 763 int error; 764 765 soassertlocked(so); 766 767 /* 768 * Ship a packet out. The appropriate raw output 769 * routine handles any messaging necessary. 770 */ 771 772 /* always copy sockaddr to avoid overwrites */ 773 memset(&dst, 0, sizeof(dst)); 774 dst.sin6_family = AF_INET6; 775 dst.sin6_len = sizeof(dst); 776 if (so->so_state & SS_ISCONNECTED) { 777 if (nam) { 778 error = EISCONN; 779 goto out; 780 } 781 dst.sin6_addr = inp->inp_faddr6; 782 } else { 783 struct sockaddr_in6 *addr6; 784 785 if (nam == NULL) { 786 error = ENOTCONN; 787 goto out; 788 } 789 if ((error = in6_nam2sin6(nam, &addr6))) 790 goto out; 791 dst.sin6_addr = addr6->sin6_addr; 792 dst.sin6_scope_id = addr6->sin6_scope_id; 793 } 794 error = rip6_output(m, so, sin6tosa(&dst), control); 795 control = NULL; 796 m = NULL; 797 798 out: 799 m_freem(control); 800 m_freem(m); 801 802 return (error); 803 } 804 805 int 806 rip6_sysctl_rip6stat(void *oldp, size_t *oldplen, void *newp) 807 { 808 struct rip6stat rip6stat; 809 810 CTASSERT(sizeof(rip6stat) == rip6s_ncounters * sizeof(uint64_t)); 811 counters_read(rip6counters, (uint64_t *)&rip6stat, rip6s_ncounters, 812 NULL); 813 814 return (sysctl_rdstruct(oldp, oldplen, newp, 815 &rip6stat, sizeof(rip6stat))); 816 } 817 818 int 819 rip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 820 void *newp, size_t newlen) 821 { 822 /* All sysctl names at this level are terminal. */ 823 if (namelen != 1) 824 return ENOTDIR; 825 826 switch (name[0]) { 827 case RIPV6CTL_STATS: 828 return (rip6_sysctl_rip6stat(oldp, oldlenp, newp)); 829 default: 830 return (EOPNOTSUPP); 831 } 832 /* NOTREACHED */ 833 } 834