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