1 /* $OpenBSD: raw_ip6.c,v 1.186 2024/11/08 10:24:13 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_bind = rip6_bind, 112 .pru_connect = rip6_connect, 113 .pru_disconnect = rip6_disconnect, 114 .pru_shutdown = rip6_shutdown, 115 .pru_send = rip6_send, 116 .pru_control = in6_control, 117 .pru_sockaddr = in6_sockaddr, 118 .pru_peeraddr = in6_peeraddr, 119 }; 120 121 void rip6_sbappend(struct inpcb *, struct mbuf *, struct ip6_hdr *, int, 122 struct sockaddr_in6 *); 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_iterator iter = { .inp_table = NULL }; 140 struct inpcb *inp, *last; 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 mtx_enter(&rawin6pcbtable.inpt_mtx); 184 last = inp = NULL; 185 while ((inp = in_pcb_iterator(&rawin6pcbtable, inp, &iter)) != NULL) { 186 KASSERT(ISSET(inp->inp_flags, INP_IPV6)); 187 188 /* 189 * Packet must not be inserted after disconnected wakeup 190 * call. To avoid race, check again when holding receive 191 * buffer mutex. 192 */ 193 if (ISSET(READ_ONCE(inp->inp_socket->so_rcv.sb_state), 194 SS_CANTRCVMORE)) 195 continue; 196 if (rtable_l2(inp->inp_rtableid) != 197 rtable_l2(m->m_pkthdr.ph_rtableid)) 198 continue; 199 200 if ((inp->inp_ipv6.ip6_nxt || proto == IPPROTO_ICMPV6) && 201 inp->inp_ipv6.ip6_nxt != proto) 202 continue; 203 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) && 204 !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key)) 205 continue; 206 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) && 207 !IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, &ip6->ip6_src)) 208 continue; 209 if (proto == IPPROTO_ICMPV6 && inp->inp_icmp6filt) { 210 if (ICMP6_FILTER_WILLBLOCK(type, inp->inp_icmp6filt)) 211 continue; 212 } 213 if (proto != IPPROTO_ICMPV6 && inp->inp_cksum6 != -1) { 214 rip6stat_inc(rip6s_isum); 215 /* 216 * Although in6_cksum() does not need the position of 217 * the checksum field for verification, enforce that it 218 * is located within the packet. Userland has given 219 * a checksum offset, a packet too short for that is 220 * invalid. Avoid overflow with user supplied offset. 221 */ 222 if (m->m_pkthdr.len < *offp + 2 || 223 m->m_pkthdr.len - *offp - 2 < inp->inp_cksum6 || 224 in6_cksum(m, proto, *offp, 225 m->m_pkthdr.len - *offp)) { 226 rip6stat_inc(rip6s_badsum); 227 continue; 228 } 229 } 230 231 if (last != NULL) { 232 struct mbuf *n; 233 234 mtx_leave(&rawin6pcbtable.inpt_mtx); 235 236 n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 237 if (n != NULL) 238 rip6_sbappend(last, n, ip6, *offp, &rip6src); 239 in_pcbunref(last); 240 241 mtx_enter(&rawin6pcbtable.inpt_mtx); 242 } 243 last = in_pcbref(inp); 244 } 245 mtx_leave(&rawin6pcbtable.inpt_mtx); 246 247 if (last == NULL) { 248 struct counters_ref ref; 249 uint64_t *counters; 250 251 if (proto != IPPROTO_ICMPV6) { 252 rip6stat_inc(rip6s_nosock); 253 if (m->m_flags & M_MCAST) 254 rip6stat_inc(rip6s_nosockmcast); 255 } 256 if (proto == IPPROTO_NONE || proto == IPPROTO_ICMPV6) { 257 m_freem(m); 258 } else { 259 int prvnxt = ip6_get_prevhdr(m, *offp); 260 261 icmp6_error(m, ICMP6_PARAM_PROB, 262 ICMP6_PARAMPROB_NEXTHEADER, prvnxt); 263 } 264 counters = counters_enter(&ref, ip6counters); 265 counters[ip6s_delivered]--; 266 counters_leave(&ref, ip6counters); 267 268 return IPPROTO_DONE; 269 } 270 271 rip6_sbappend(last, m, ip6, *offp, &rip6src); 272 in_pcbunref(last); 273 274 return IPPROTO_DONE; 275 } 276 277 void 278 rip6_sbappend(struct inpcb *inp, struct mbuf *m, struct ip6_hdr *ip6, int hlen, 279 struct sockaddr_in6 *rip6src) 280 { 281 struct socket *so = inp->inp_socket; 282 struct mbuf *opts = NULL; 283 int ret = 0; 284 285 if (inp->inp_flags & IN6P_CONTROLOPTS) 286 ip6_savecontrol(inp, m, &opts); 287 /* strip intermediate headers */ 288 m_adj(m, hlen); 289 290 mtx_enter(&so->so_rcv.sb_mtx); 291 if (!ISSET(inp->inp_socket->so_rcv.sb_state, SS_CANTRCVMORE)) 292 ret = sbappendaddr(so, &so->so_rcv, sin6tosa(rip6src), m, opts); 293 mtx_leave(&so->so_rcv.sb_mtx); 294 295 if (ret == 0) { 296 m_freem(m); 297 m_freem(opts); 298 rip6stat_inc(rip6s_fullsock); 299 } else 300 sorwakeup(so); 301 } 302 303 void 304 rip6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d) 305 { 306 struct ip6_hdr *ip6; 307 struct ip6ctlparam *ip6cp = NULL; 308 struct sockaddr_in6 *sa6 = satosin6(sa); 309 const struct sockaddr_in6 *sa6_src = NULL; 310 void *cmdarg; 311 void (*notify)(struct inpcb *, int) = in_rtchange; 312 int nxt; 313 314 if (sa->sa_family != AF_INET6 || 315 sa->sa_len != sizeof(struct sockaddr_in6)) 316 return; 317 318 if ((unsigned)cmd >= PRC_NCMDS) 319 return; 320 if (PRC_IS_REDIRECT(cmd)) 321 notify = in_rtchange, d = NULL; 322 else if (cmd == PRC_HOSTDEAD) 323 d = NULL; 324 else if (cmd == PRC_MSGSIZE) 325 ; /* special code is present, see below */ 326 else if (inet6ctlerrmap[cmd] == 0) 327 return; 328 329 /* if the parameter is from icmp6, decode it. */ 330 if (d != NULL) { 331 ip6cp = (struct ip6ctlparam *)d; 332 ip6 = ip6cp->ip6c_ip6; 333 cmdarg = ip6cp->ip6c_cmdarg; 334 sa6_src = ip6cp->ip6c_src; 335 nxt = ip6cp->ip6c_nxt; 336 } else { 337 ip6 = NULL; 338 cmdarg = NULL; 339 sa6_src = &sa6_any; 340 nxt = -1; 341 } 342 343 if (ip6 && cmd == PRC_MSGSIZE) { 344 int valid = 0; 345 struct inpcb *inp; 346 347 /* 348 * Check to see if we have a valid raw IPv6 socket 349 * corresponding to the address in the ICMPv6 message 350 * payload, and the protocol (ip6_nxt) meets the socket. 351 * XXX chase extension headers, or pass final nxt value 352 * from icmp6_notify_error() 353 */ 354 inp = in6_pcblookup(&rawin6pcbtable, &sa6->sin6_addr, 0, 355 &sa6_src->sin6_addr, 0, rdomain); 356 357 if (inp && inp->inp_ipv6.ip6_nxt && 358 inp->inp_ipv6.ip6_nxt == nxt) 359 valid = 1; 360 361 /* 362 * Depending on the value of "valid" and routing table 363 * size (mtudisc_{hi,lo}wat), we will: 364 * - recalculate the new MTU and create the 365 * corresponding routing entry, or 366 * - ignore the MTU change notification. 367 */ 368 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 369 in_pcbunref(inp); 370 371 /* 372 * regardless of if we called icmp6_mtudisc_update(), 373 * we need to call in6_pcbnotify(), to notify path 374 * MTU change to the userland (2292bis-02), because 375 * some unconnected sockets may share the same 376 * destination and want to know the path MTU. 377 */ 378 } 379 380 in6_pcbnotify(&rawin6pcbtable, sa6, 0, 381 sa6_src, 0, rdomain, cmd, cmdarg, notify); 382 } 383 384 /* 385 * Generate IPv6 header and pass packet to ip6_output. 386 * Tack on options user may have setup with control call. 387 */ 388 int 389 rip6_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, 390 struct mbuf *control) 391 { 392 struct in6_addr *dst; 393 struct ip6_hdr *ip6; 394 struct inpcb *inp; 395 u_int plen = m->m_pkthdr.len; 396 int error = 0; 397 struct ip6_pktopts opt, *optp = NULL; 398 int type; /* for ICMPv6 output statistics only */ 399 int priv = 0; 400 int flags; 401 402 inp = sotoinpcb(so); 403 404 priv = 0; 405 if ((so->so_state & SS_PRIV) != 0) 406 priv = 1; 407 if (control) { 408 if ((error = ip6_setpktopts(control, &opt, 409 inp->inp_outputopts6, 410 priv, so->so_proto->pr_protocol)) != 0) 411 goto bad; 412 optp = &opt; 413 } else 414 optp = inp->inp_outputopts6; 415 416 if (dstaddr->sa_family != AF_INET6) { 417 error = EAFNOSUPPORT; 418 goto bad; 419 } 420 dst = &satosin6(dstaddr)->sin6_addr; 421 if (IN6_IS_ADDR_V4MAPPED(dst)) { 422 error = EADDRNOTAVAIL; 423 goto bad; 424 } 425 426 /* 427 * For an ICMPv6 packet, we should know its type and code 428 * to update statistics. 429 */ 430 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 431 struct icmp6_hdr *icmp6; 432 if (m->m_len < sizeof(struct icmp6_hdr) && 433 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 434 error = ENOBUFS; 435 goto bad; 436 } 437 icmp6 = mtod(m, struct icmp6_hdr *); 438 type = icmp6->icmp6_type; 439 } 440 441 M_PREPEND(m, sizeof(*ip6), M_DONTWAIT); 442 if (!m) { 443 error = ENOBUFS; 444 goto bad; 445 } 446 ip6 = mtod(m, struct ip6_hdr *); 447 448 /* 449 * Next header might not be ICMP6 but use its pseudo header anyway. 450 */ 451 ip6->ip6_dst = *dst; 452 453 /* KAME hack: embed scopeid */ 454 if (in6_embedscope(&ip6->ip6_dst, satosin6(dstaddr), 455 optp, inp->inp_moptions6) != 0) { 456 error = EINVAL; 457 goto bad; 458 } 459 460 /* 461 * Source address selection. 462 */ 463 { 464 const struct in6_addr *in6a; 465 466 error = in6_pcbselsrc(&in6a, satosin6(dstaddr), inp, optp); 467 if (error) 468 goto bad; 469 470 ip6->ip6_src = *in6a; 471 } 472 473 ip6->ip6_flow = inp->inp_flowinfo & IPV6_FLOWINFO_MASK; 474 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 475 ip6->ip6_vfc |= IPV6_VERSION; 476 #if 0 /* ip6_plen will be filled in ip6_output. */ 477 ip6->ip6_plen = htons((u_short)plen); 478 #endif 479 ip6->ip6_nxt = inp->inp_ipv6.ip6_nxt; 480 ip6->ip6_hlim = in6_selecthlim(inp); 481 482 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 483 inp->inp_cksum6 != -1) { 484 struct mbuf *n; 485 int off; 486 u_int16_t *sump; 487 int sumoff; 488 489 /* compute checksum */ 490 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 491 off = offsetof(struct icmp6_hdr, icmp6_cksum); 492 else 493 off = inp->inp_cksum6; 494 if (plen < 2 || plen - 2 < off) { 495 error = EINVAL; 496 goto bad; 497 } 498 off += sizeof(struct ip6_hdr); 499 500 n = m_pulldown(m, off, sizeof(*sump), &sumoff); 501 if (n == NULL) { 502 m = NULL; 503 error = ENOBUFS; 504 goto bad; 505 } 506 sump = (u_int16_t *)(mtod(n, caddr_t) + sumoff); 507 *sump = 0; 508 *sump = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 509 } 510 511 flags = 0; 512 if (inp->inp_flags & IN6P_MINMTU) 513 flags |= IPV6_MINMTU; 514 515 /* force routing table */ 516 m->m_pkthdr.ph_rtableid = inp->inp_rtableid; 517 518 #if NPF > 0 519 if (inp->inp_socket->so_state & SS_ISCONNECTED && 520 so->so_proto->pr_protocol != IPPROTO_ICMPV6) 521 pf_mbuf_link_inpcb(m, inp); 522 #endif 523 524 error = ip6_output(m, optp, &inp->inp_route, flags, 525 inp->inp_moptions6, &inp->inp_seclevel); 526 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 527 icmp6stat_inc(icp6s_outhist + type); 528 } else 529 rip6stat_inc(rip6s_opackets); 530 531 goto freectl; 532 533 bad: 534 m_freem(m); 535 536 freectl: 537 if (control) { 538 ip6_clearpktopts(&opt, -1); 539 m_freem(control); 540 } 541 return (error); 542 } 543 544 /* 545 * Raw IPv6 socket option processing. 546 */ 547 int 548 rip6_ctloutput(int op, struct socket *so, int level, int optname, 549 struct mbuf *m) 550 { 551 #ifdef MROUTING 552 int error; 553 #endif 554 555 switch (level) { 556 case IPPROTO_IPV6: 557 switch (optname) { 558 #ifdef MROUTING 559 case MRT6_INIT: 560 case MRT6_DONE: 561 case MRT6_ADD_MIF: 562 case MRT6_DEL_MIF: 563 case MRT6_ADD_MFC: 564 case MRT6_DEL_MFC: 565 if (op == PRCO_SETOPT) { 566 error = ip6_mrouter_set(optname, so, m); 567 } else if (op == PRCO_GETOPT) 568 error = ip6_mrouter_get(optname, so, m); 569 else 570 error = EINVAL; 571 return (error); 572 #endif 573 case IPV6_CHECKSUM: 574 return (ip6_raw_ctloutput(op, so, level, optname, m)); 575 default: 576 return (ip6_ctloutput(op, so, level, optname, m)); 577 } 578 579 case IPPROTO_ICMPV6: 580 /* 581 * XXX: is it better to call icmp6_ctloutput() directly 582 * from protosw? 583 */ 584 return (icmp6_ctloutput(op, so, level, optname, m)); 585 586 default: 587 return EINVAL; 588 } 589 } 590 591 extern u_long rip6_sendspace; 592 extern u_long rip6_recvspace; 593 594 int 595 rip6_attach(struct socket *so, int proto, int wait) 596 { 597 struct inpcb *inp; 598 int error; 599 600 if (so->so_pcb) 601 panic("%s", __func__); 602 if ((so->so_state & SS_PRIV) == 0) 603 return (EACCES); 604 if (proto < 0 || proto >= IPPROTO_MAX) 605 return EPROTONOSUPPORT; 606 607 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace))) 608 return error; 609 NET_ASSERT_LOCKED(); 610 if ((error = in_pcballoc(so, &rawin6pcbtable, wait))) 611 return error; 612 613 inp = sotoinpcb(so); 614 inp->inp_ipv6.ip6_nxt = proto; 615 inp->inp_cksum6 = -1; 616 617 inp->inp_icmp6filt = malloc(sizeof(struct icmp6_filter), M_PCB, 618 wait == M_WAIT ? M_WAITOK : M_NOWAIT); 619 if (inp->inp_icmp6filt == NULL) { 620 in_pcbdetach(inp); 621 return ENOMEM; 622 } 623 ICMP6_FILTER_SETPASSALL(inp->inp_icmp6filt); 624 return 0; 625 } 626 627 int 628 rip6_detach(struct socket *so) 629 { 630 struct inpcb *inp = sotoinpcb(so); 631 632 soassertlocked(so); 633 634 if (inp == NULL) 635 panic("%s", __func__); 636 #ifdef MROUTING 637 if (so == ip6_mrouter[inp->inp_rtableid]) 638 ip6_mrouter_done(so); 639 #endif 640 free(inp->inp_icmp6filt, M_PCB, sizeof(struct icmp6_filter)); 641 inp->inp_icmp6filt = NULL; 642 643 in_pcbdetach(inp); 644 645 return (0); 646 } 647 648 int 649 rip6_bind(struct socket *so, struct mbuf *nam, struct proc *p) 650 { 651 struct inpcb *inp = sotoinpcb(so); 652 struct sockaddr_in6 *addr; 653 int error; 654 655 soassertlocked(so); 656 657 if ((error = in6_nam2sin6(nam, &addr))) 658 return (error); 659 660 /* 661 * Make sure to not enter in_pcblookup_local(), local ports 662 * are non-sensical for raw sockets. 663 */ 664 addr->sin6_port = 0; 665 666 if ((error = in6_pcbaddrisavail(inp, addr, 0, p))) 667 return (error); 668 669 mtx_enter(&rawin6pcbtable.inpt_mtx); 670 inp->inp_laddr6 = addr->sin6_addr; 671 mtx_leave(&rawin6pcbtable.inpt_mtx); 672 673 return (0); 674 } 675 676 int 677 rip6_connect(struct socket *so, struct mbuf *nam) 678 { 679 struct inpcb *inp = sotoinpcb(so); 680 struct sockaddr_in6 *addr; 681 const struct in6_addr *in6a; 682 int error; 683 684 soassertlocked(so); 685 686 if ((error = in6_nam2sin6(nam, &addr))) 687 return (error); 688 689 /* Source address selection. XXX: need pcblookup? */ 690 error = in6_pcbselsrc(&in6a, addr, inp, inp->inp_outputopts6); 691 if (error) 692 return (error); 693 694 mtx_enter(&rawin6pcbtable.inpt_mtx); 695 inp->inp_laddr6 = *in6a; 696 inp->inp_faddr6 = addr->sin6_addr; 697 mtx_leave(&rawin6pcbtable.inpt_mtx); 698 soisconnected(so); 699 700 return (0); 701 } 702 703 int 704 rip6_disconnect(struct socket *so) 705 { 706 struct inpcb *inp = sotoinpcb(so); 707 708 soassertlocked(so); 709 710 if ((so->so_state & SS_ISCONNECTED) == 0) 711 return (ENOTCONN); 712 713 soisdisconnected(so); 714 mtx_enter(&rawin6pcbtable.inpt_mtx); 715 inp->inp_faddr6 = in6addr_any; 716 mtx_leave(&rawin6pcbtable.inpt_mtx); 717 718 return (0); 719 } 720 721 int 722 rip6_shutdown(struct socket *so) 723 { 724 /* 725 * Mark the connection as being incapable of further input. 726 */ 727 soassertlocked(so); 728 socantsendmore(so); 729 return (0); 730 } 731 732 int 733 rip6_send(struct socket *so, struct mbuf *m, struct mbuf *nam, 734 struct mbuf *control) 735 { 736 struct inpcb *inp = sotoinpcb(so); 737 struct sockaddr_in6 dst; 738 int error; 739 740 soassertlocked(so); 741 742 /* 743 * Ship a packet out. The appropriate raw output 744 * routine handles any messaging necessary. 745 */ 746 747 /* always copy sockaddr to avoid overwrites */ 748 memset(&dst, 0, sizeof(dst)); 749 dst.sin6_family = AF_INET6; 750 dst.sin6_len = sizeof(dst); 751 if (so->so_state & SS_ISCONNECTED) { 752 if (nam) { 753 error = EISCONN; 754 goto out; 755 } 756 dst.sin6_addr = inp->inp_faddr6; 757 } else { 758 struct sockaddr_in6 *addr6; 759 760 if (nam == NULL) { 761 error = ENOTCONN; 762 goto out; 763 } 764 if ((error = in6_nam2sin6(nam, &addr6))) 765 goto out; 766 dst.sin6_addr = addr6->sin6_addr; 767 dst.sin6_scope_id = addr6->sin6_scope_id; 768 } 769 error = rip6_output(m, so, sin6tosa(&dst), control); 770 control = NULL; 771 m = NULL; 772 773 out: 774 m_freem(control); 775 m_freem(m); 776 777 return (error); 778 } 779 780 int 781 rip6_sysctl_rip6stat(void *oldp, size_t *oldplen, void *newp) 782 { 783 struct rip6stat rip6stat; 784 785 CTASSERT(sizeof(rip6stat) == rip6s_ncounters * sizeof(uint64_t)); 786 counters_read(rip6counters, (uint64_t *)&rip6stat, rip6s_ncounters, 787 NULL); 788 789 return (sysctl_rdstruct(oldp, oldplen, newp, 790 &rip6stat, sizeof(rip6stat))); 791 } 792 793 int 794 rip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 795 void *newp, size_t newlen) 796 { 797 /* All sysctl names at this level are terminal. */ 798 if (namelen != 1) 799 return ENOTDIR; 800 801 switch (name[0]) { 802 case RIPV6CTL_STATS: 803 return (rip6_sysctl_rip6stat(oldp, oldlenp, newp)); 804 default: 805 return (EOPNOTSUPP); 806 } 807 /* NOTREACHED */ 808 } 809