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