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