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