190075Sobrien/* $OpenBSD: raw_ip6.c,v 1.184 2024/04/17 20:48:51 bluhm Exp $ */ 290075Sobrien/* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $ */ 3169689Skan 490075Sobrien/* 590075Sobrien * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 690075Sobrien * All rights reserved. 790075Sobrien * 890075Sobrien * Redistribution and use in source and binary forms, with or without 9132718Skan * modification, are permitted provided that the following conditions 1090075Sobrien * are met: 11132718Skan * 1. Redistributions of source code must retain the above copyright 12132718Skan * notice, this list of conditions and the following disclaimer. 13132718Skan * 2. Redistributions in binary form must reproduce the above copyright 14132718Skan * notice, this list of conditions and the following disclaimer in the 1590075Sobrien * documentation and/or other materials provided with the distribution. 16132718Skan * 3. Neither the name of the project nor the names of its contributors 17132718Skan * may be used to endorse or promote products derived from this software 18132718Skan * without specific prior written permission. 19132718Skan * 2090075Sobrien * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2590075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2690075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2790075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2890075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30169689Skan * SUCH DAMAGE. 31169689Skan */ 32117395Skan 33117395Skan/* 34117395Skan * Copyright (c) 1982, 1986, 1988, 1993 35117395Skan * The Regents of the University of California. All rights reserved. 36169689Skan * 37169689Skan * Redistribution and use in source and binary forms, with or without 38169689Skan * modification, are permitted provided that the following conditions 39169689Skan * are met: 40169689Skan * 1. Redistributions of source code must retain the above copyright 41117395Skan * notice, this list of conditions and the following disclaimer. 42117395Skan * 2. Redistributions in binary form must reproduce the above copyright 43117395Skan * notice, this list of conditions and the following disclaimer in the 44117395Skan * documentation and/or other materials provided with the distribution. 45117395Skan * 3. Neither the name of the University nor the names of its contributors 46117395Skan * may be used to endorse or promote products derived from this software 47117395Skan * without specific prior written permission. 48117395Skan * 49117395Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50117395Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51117395Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52117395Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53117395Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54117395Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55117395Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56117395Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57117395Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58117395Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59117395Skan * SUCH DAMAGE. 60117395Skan * 61169689Skan * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 62117395Skan */ 63117395Skan 64117395Skan#include "pf.h" 65117395Skan 66169689Skan#include <sys/param.h> 67117395Skan#include <sys/malloc.h> 68117395Skan#include <sys/mbuf.h> 69117395Skan#include <sys/socket.h> 70117395Skan#include <sys/protosw.h> 71169689Skan#include <sys/socketvar.h> 72169689Skan#include <sys/errno.h> 73169689Skan#include <sys/systm.h> 74169689Skan#include <sys/sysctl.h> 75169689Skan 76169689Skan#include <net/if.h> 77169689Skan#include <net/if_var.h> 78169689Skan#include <net/route.h> 79169689Skan 80169689Skan#include <netinet/in.h> 81117395Skan#include <netinet6/in6_var.h> 82117395Skan#include <netinet/ip6.h> 83169689Skan#include <netinet6/ip6_var.h> 84169689Skan#ifdef MROUTING 85169689Skan#include <netinet6/ip6_mroute.h> 86169689Skan#endif 87169689Skan#include <netinet/icmp6.h> 88169689Skan#include <netinet/ip.h> 89169689Skan#include <netinet/in_pcb.h> 90169689Skan#include <netinet6/nd6.h> 91169689Skan#include <netinet6/ip6protosw.h> 92169689Skan#include <netinet6/raw_ip6.h> 9390075Sobrien 94169689Skan#if NPF > 0 95169689Skan#include <net/pfvar.h> 96169689Skan#endif 97169689Skan 98169689Skan#include <sys/stdarg.h> 99169689Skan 100169689Skan/* 101169689Skan * Raw interface to IP6 protocol. 102169689Skan */ 103169689Skan 104169689Skanstruct inpcbtable rawin6pcbtable; 105169689Skan 10690075Sobrienstruct cpumem *rip6counters; 10790075Sobrien 10890075Sobrienconst struct pr_usrreqs rip6_usrreqs = { 10990075Sobrien .pru_attach = rip6_attach, 11090075Sobrien .pru_detach = rip6_detach, 11190075Sobrien .pru_lock = rip6_lock, 11290075Sobrien .pru_unlock = rip6_unlock, 11390075Sobrien .pru_locked = rip6_locked, 11490075Sobrien .pru_bind = rip6_bind, 11590075Sobrien .pru_connect = rip6_connect, 11690075Sobrien .pru_disconnect = rip6_disconnect, 11790075Sobrien .pru_shutdown = rip6_shutdown, 11890075Sobrien .pru_send = rip6_send, 119117395Skan .pru_control = in6_control, 12090075Sobrien .pru_sockaddr = in6_sockaddr, 121117395Skan .pru_peeraddr = in6_peeraddr, 122117395Skan}; 123117395Skan 12490075Sobrien/* 125117395Skan * Initialize raw connection block queue. 12690075Sobrien */ 127132718Skanvoid 12890075Sobrienrip6_init(void) 129117395Skan{ 130117395Skan in_pcbinit(&rawin6pcbtable, 1); 13190075Sobrien rip6counters = counters_alloc(rip6s_ncounters); 132132718Skan} 13390075Sobrien 13490075Sobrienint 13590075Sobrienrip6_input(struct mbuf **mp, int *offp, int proto, int af) 13690075Sobrien{ 13790075Sobrien struct mbuf *m = *mp; 13890075Sobrien struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 139169689Skan struct inpcb *inp; 140117395Skan SIMPLEQ_HEAD(, inpcb) inpcblist; 141117395Skan struct in6_addr *key; 142117395Skan struct sockaddr_in6 rip6src; 143117395Skan uint8_t type; 14490075Sobrien 14590075Sobrien KASSERT(af == AF_INET6); 14690075Sobrien 14790075Sobrien if (proto == IPPROTO_ICMPV6) { 14890075Sobrien struct icmp6_hdr *icmp6; 14990075Sobrien 15090075Sobrien IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offp, 15190075Sobrien sizeof(*icmp6)); 15290075Sobrien if (icmp6 == NULL) 15390075Sobrien return IPPROTO_DONE; 154132718Skan type = icmp6->icmp6_type; 15590075Sobrien } else 15690075Sobrien rip6stat_inc(rip6s_ipackets); 15790075Sobrien 15890075Sobrien memset(&rip6src, 0, sizeof(rip6src)); 15990075Sobrien rip6src.sin6_family = AF_INET6; 16090075Sobrien rip6src.sin6_len = sizeof(rip6src); 16190075Sobrien /* KAME hack: recover scopeid */ 16290075Sobrien in6_recoverscope(&rip6src, &ip6->ip6_src); 16390075Sobrien 16490075Sobrien key = &ip6->ip6_dst; 16590075Sobrien#if NPF > 0 16690075Sobrien if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) { 16790075Sobrien struct pf_divert *divert; 16890075Sobrien 16990075Sobrien divert = pf_find_divert(m); 17090075Sobrien KASSERT(divert != NULL); 17190075Sobrien switch (divert->type) { 17290075Sobrien case PF_DIVERT_TO: 17390075Sobrien key = &divert->addr.v6; 17490075Sobrien break; 175169689Skan case PF_DIVERT_REPLY: 176169689Skan break; 177169689Skan default: 178169689Skan panic("%s: unknown divert type %d, mbuf %p, divert %p", 179169689Skan __func__, divert->type, m, divert); 180169689Skan } 181169689Skan } 182169689Skan#endif 183132718Skan SIMPLEQ_INIT(&inpcblist); 184132718Skan rw_enter_write(&rawin6pcbtable.inpt_notify); 185169689Skan mtx_enter(&rawin6pcbtable.inpt_mtx); 18690075Sobrien TAILQ_FOREACH(inp, &rawin6pcbtable.inpt_queue, inp_queue) { 18790075Sobrien KASSERT(ISSET(inp->inp_flags, INP_IPV6)); 188169689Skan 189169689Skan /* 190169689Skan * Packet must not be inserted after disconnected wakeup 191169689Skan * call. To avoid race, check again when holding receive 192169689Skan * buffer mutex. 193169689Skan */ 19490075Sobrien if (ISSET(READ_ONCE(inp->inp_socket->so_rcv.sb_state), 195169689Skan SS_CANTRCVMORE)) 196169689Skan continue; 197169689Skan if (rtable_l2(inp->inp_rtableid) != 198169689Skan rtable_l2(m->m_pkthdr.ph_rtableid)) 199169689Skan continue; 200169689Skan 201169689Skan if ((inp->inp_ipv6.ip6_nxt || proto == IPPROTO_ICMPV6) && 202169689Skan inp->inp_ipv6.ip6_nxt != proto) 203169689Skan continue; 20490075Sobrien if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) && 20590075Sobrien !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key)) 206132718Skan continue; 207132718Skan if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) && 208132718Skan !IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, &ip6->ip6_src)) 209132718Skan continue; 210132718Skan if (proto == IPPROTO_ICMPV6 && inp->inp_icmp6filt) { 211132718Skan if (ICMP6_FILTER_WILLBLOCK(type, inp->inp_icmp6filt)) 212169689Skan continue; 213169689Skan } 214169689Skan if (proto != IPPROTO_ICMPV6 && inp->inp_cksum6 != -1) { 215169689Skan rip6stat_inc(rip6s_isum); 216132718Skan /* 217132718Skan * Although in6_cksum() does not need the position of 218132718Skan * the checksum field for verification, enforce that it 219132718Skan * is located within the packet. Userland has given 220169689Skan * a checksum offset, a packet too short for that is 221169689Skan * invalid. Avoid overflow with user supplied offset. 222169689Skan */ 223169689Skan if (m->m_pkthdr.len < *offp + 2 || 224169689Skan m->m_pkthdr.len - *offp - 2 < inp->inp_cksum6 || 225132718Skan in6_cksum(m, proto, *offp, 226169689Skan m->m_pkthdr.len - *offp)) { 227169689Skan rip6stat_inc(rip6s_badsum); 22890075Sobrien continue; 229169689Skan } 230169689Skan } 231169689Skan 232169689Skan in_pcbref(inp); 233169689Skan SIMPLEQ_INSERT_TAIL(&inpcblist, inp, inp_notify); 234169689Skan } 235169689Skan mtx_leave(&rawin6pcbtable.inpt_mtx); 23690075Sobrien 23790075Sobrien if (SIMPLEQ_EMPTY(&inpcblist)) { 238169689Skan struct counters_ref ref; 23990075Sobrien uint64_t *counters; 240169689Skan 241169689Skan rw_exit_write(&rawin6pcbtable.inpt_notify); 242132718Skan 24390075Sobrien if (proto != IPPROTO_ICMPV6) { 244169689Skan rip6stat_inc(rip6s_nosock); 245169689Skan if (m->m_flags & M_MCAST) 246132718Skan rip6stat_inc(rip6s_nosockmcast); 247132718Skan } 248132718Skan if (proto == IPPROTO_NONE || proto == IPPROTO_ICMPV6) { 249132718Skan m_freem(m); 250132718Skan } else { 251132718Skan int prvnxt = ip6_get_prevhdr(m, *offp); 252132718Skan 253169689Skan icmp6_error(m, ICMP6_PARAM_PROB, 254169689Skan ICMP6_PARAMPROB_NEXTHEADER, prvnxt); 255169689Skan } 25690075Sobrien counters = counters_enter(&ref, ip6counters); 25790075Sobrien counters[ip6s_delivered]--; 25890075Sobrien counters_leave(&ref, ip6counters); 259132718Skan 26090075Sobrien return IPPROTO_DONE; 26190075Sobrien } 262132718Skan 26390075Sobrien while ((inp = SIMPLEQ_FIRST(&inpcblist)) != NULL) { 26490075Sobrien struct mbuf *n, *opts = NULL; 265132718Skan 26690075Sobrien SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify); 267169689Skan if (SIMPLEQ_EMPTY(&inpcblist)) 268169689Skan n = m; 269169689Skan else 270169689Skan n = m_copym(m, 0, M_COPYALL, M_NOWAIT); 271169689Skan if (n != NULL) { 272169689Skan struct socket *so = inp->inp_socket; 273169689Skan int ret = 0; 274169689Skan 275169689Skan if (inp->inp_flags & IN6P_CONTROLOPTS) 276169689Skan ip6_savecontrol(inp, n, &opts); 277169689Skan /* strip intermediate headers */ 27890075Sobrien m_adj(n, *offp); 27990075Sobrien 280169689Skan mtx_enter(&so->so_rcv.sb_mtx); 281169689Skan if (!ISSET(inp->inp_socket->so_rcv.sb_state, 282169689Skan SS_CANTRCVMORE)) { 283169689Skan ret = sbappendaddr(so, &so->so_rcv, 284169689Skan sin6tosa(&rip6src), n, opts); 285169689Skan } 286169689Skan mtx_leave(&so->so_rcv.sb_mtx); 287169689Skan 288169689Skan if (ret == 0) { 289169689Skan m_freem(n); 290169689Skan m_freem(opts); 291169689Skan rip6stat_inc(rip6s_fullsock); 292169689Skan } else 293169689Skan sorwakeup(so); 294132718Skan } 295132718Skan in_pcbunref(inp); 296169689Skan } 297169689Skan rw_exit_write(&rawin6pcbtable.inpt_notify); 298169689Skan 299169689Skan return IPPROTO_DONE; 300169689Skan} 301169689Skan 30290075Sobrienvoid 303169689Skanrip6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d) 304169689Skan{ 305169689Skan struct ip6_hdr *ip6; 306169689Skan struct ip6ctlparam *ip6cp = NULL; 307169689Skan struct sockaddr_in6 *sa6 = satosin6(sa); 308169689Skan const struct sockaddr_in6 *sa6_src = NULL; 30990075Sobrien void *cmdarg; 31090075Sobrien void (*notify)(struct inpcb *, int) = in_rtchange; 311169689Skan int nxt; 312169689Skan 313169689Skan if (sa->sa_family != AF_INET6 || 314169689Skan sa->sa_len != sizeof(struct sockaddr_in6)) 31590075Sobrien return; 31690075Sobrien 317169689Skan if ((unsigned)cmd >= PRC_NCMDS) 31890075Sobrien return; 31990075Sobrien if (PRC_IS_REDIRECT(cmd)) 320169689Skan notify = in_rtchange, d = NULL; 321169689Skan else if (cmd == PRC_HOSTDEAD) 322169689Skan d = NULL; 32390075Sobrien else if (cmd == PRC_MSGSIZE) 32490075Sobrien ; /* special code is present, see below */ 32590075Sobrien else if (inet6ctlerrmap[cmd] == 0) 32690075Sobrien return; 32790075Sobrien 32890075Sobrien /* if the parameter is from icmp6, decode it. */ 32990075Sobrien if (d != NULL) { 330169689Skan ip6cp = (struct ip6ctlparam *)d; 33190075Sobrien ip6 = ip6cp->ip6c_ip6; 332132718Skan cmdarg = ip6cp->ip6c_cmdarg; 333169689Skan sa6_src = ip6cp->ip6c_src; 334132718Skan nxt = ip6cp->ip6c_nxt; 335132718Skan } else { 336132718Skan ip6 = NULL; 337132718Skan cmdarg = NULL; 33890075Sobrien sa6_src = &sa6_any; 339132718Skan nxt = -1; 34090075Sobrien } 341169689Skan 342132718Skan if (ip6 && cmd == PRC_MSGSIZE) { 343132718Skan int valid = 0; 344169689Skan struct inpcb *inp; 345169689Skan 34690075Sobrien /* 347169689Skan * Check to see if we have a valid raw IPv6 socket 348169689Skan * corresponding to the address in the ICMPv6 message 349169689Skan * payload, and the protocol (ip6_nxt) meets the socket. 350169689Skan * XXX chase extension headers, or pass final nxt value 351169689Skan * from icmp6_notify_error() 352169689Skan */ 353169689Skan inp = in6_pcblookup(&rawin6pcbtable, &sa6->sin6_addr, 0, 35490075Sobrien &sa6_src->sin6_addr, 0, rdomain); 355169689Skan 35690075Sobrien if (inp && inp->inp_ipv6.ip6_nxt && 35790075Sobrien inp->inp_ipv6.ip6_nxt == nxt) 35890075Sobrien valid = 1; 35990075Sobrien 36090075Sobrien /* 36190075Sobrien * Depending on the value of "valid" and routing table 36290075Sobrien * size (mtudisc_{hi,lo}wat), we will: 36390075Sobrien * - recalculate the new MTU and create the 36490075Sobrien * corresponding routing entry, or 36590075Sobrien * - ignore the MTU change notification. 36690075Sobrien */ 36790075Sobrien icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); 36890075Sobrien in_pcbunref(inp); 36990075Sobrien 37090075Sobrien /* 37190075Sobrien * regardless of if we called icmp6_mtudisc_update(), 37290075Sobrien * we need to call in6_pcbnotify(), to notify path 37390075Sobrien * MTU change to the userland (2292bis-02), because 37490075Sobrien * some unconnected sockets may share the same 37590075Sobrien * destination and want to know the path MTU. 37690075Sobrien */ 377169689Skan } 37890075Sobrien 37990075Sobrien in6_pcbnotify(&rawin6pcbtable, sa6, 0, 38090075Sobrien sa6_src, 0, rdomain, cmd, cmdarg, notify); 38190075Sobrien} 38290075Sobrien 383169689Skan/* 38490075Sobrien * Generate IPv6 header and pass packet to ip6_output. 38590075Sobrien * Tack on options user may have setup with control call. 38690075Sobrien */ 38790075Sobrienint 38890075Sobrienrip6_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr, 38990075Sobrien struct mbuf *control) 39090075Sobrien{ 39190075Sobrien struct in6_addr *dst; 39290075Sobrien struct ip6_hdr *ip6; 39390075Sobrien struct inpcb *inp; 39490075Sobrien u_int plen = m->m_pkthdr.len; 39590075Sobrien int error = 0; 39690075Sobrien struct ip6_pktopts opt, *optp = NULL; 39790075Sobrien int type; /* for ICMPv6 output statistics only */ 39890075Sobrien int priv = 0; 39990075Sobrien int flags; 40090075Sobrien 40190075Sobrien inp = sotoinpcb(so); 40290075Sobrien 40390075Sobrien priv = 0; 40490075Sobrien if ((so->so_state & SS_PRIV) != 0) 40590075Sobrien priv = 1; 40690075Sobrien if (control) { 407169689Skan if ((error = ip6_setpktopts(control, &opt, 40890075Sobrien inp->inp_outputopts6, 40990075Sobrien priv, so->so_proto->pr_protocol)) != 0) 41090075Sobrien goto bad; 411169689Skan optp = &opt; 412169689Skan } else 413169689Skan optp = inp->inp_outputopts6; 414169689Skan 415169689Skan if (dstaddr->sa_family != AF_INET6) { 41690075Sobrien error = EAFNOSUPPORT; 41790075Sobrien goto bad; 41890075Sobrien } 41990075Sobrien dst = &satosin6(dstaddr)->sin6_addr; 42090075Sobrien if (IN6_IS_ADDR_V4MAPPED(dst)) { 421169689Skan error = EADDRNOTAVAIL; 42290075Sobrien goto bad; 42390075Sobrien } 42490075Sobrien 42590075Sobrien /* 42690075Sobrien * For an ICMPv6 packet, we should know its type and code 42790075Sobrien * to update statistics. 42890075Sobrien */ 42990075Sobrien if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 43090075Sobrien struct icmp6_hdr *icmp6; 43190075Sobrien if (m->m_len < sizeof(struct icmp6_hdr) && 43290075Sobrien (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) { 43390075Sobrien error = ENOBUFS; 43490075Sobrien goto bad; 43590075Sobrien } 43690075Sobrien icmp6 = mtod(m, struct icmp6_hdr *); 43790075Sobrien type = icmp6->icmp6_type; 43890075Sobrien } 43990075Sobrien 44090075Sobrien M_PREPEND(m, sizeof(*ip6), M_DONTWAIT); 441132718Skan if (!m) { 442132718Skan error = ENOBUFS; 443117395Skan goto bad; 44490075Sobrien } 44590075Sobrien ip6 = mtod(m, struct ip6_hdr *); 44690075Sobrien 447169689Skan /* 448169689Skan * Next header might not be ICMP6 but use its pseudo header anyway. 449169689Skan */ 450169689Skan ip6->ip6_dst = *dst; 451169689Skan 45290075Sobrien /* KAME hack: embed scopeid */ 45390075Sobrien if (in6_embedscope(&ip6->ip6_dst, satosin6(dstaddr), 454169689Skan optp, inp->inp_moptions6) != 0) { 455132718Skan error = EINVAL; 456169689Skan goto bad; 457169689Skan } 45890075Sobrien 45990075Sobrien /* 46090075Sobrien * Source address selection. 46190075Sobrien */ 46290075Sobrien { 46390075Sobrien const struct in6_addr *in6a; 46490075Sobrien 46590075Sobrien error = in6_pcbselsrc(&in6a, satosin6(dstaddr), inp, optp); 46690075Sobrien if (error) 46790075Sobrien goto bad; 468169689Skan 46990075Sobrien ip6->ip6_src = *in6a; 470132718Skan } 471132718Skan 472132718Skan ip6->ip6_flow = inp->inp_flowinfo & IPV6_FLOWINFO_MASK; 473132718Skan ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 474132718Skan ip6->ip6_vfc |= IPV6_VERSION; 475132718Skan#if 0 /* ip6_plen will be filled in ip6_output. */ 476132718Skan ip6->ip6_plen = htons((u_short)plen); 47790075Sobrien#endif 478132718Skan ip6->ip6_nxt = inp->inp_ipv6.ip6_nxt; 479169689Skan ip6->ip6_hlim = in6_selecthlim(inp); 48090075Sobrien 481169689Skan if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 || 482169689Skan inp->inp_cksum6 != -1) { 483169689Skan struct mbuf *n; 48490075Sobrien int off; 48590075Sobrien u_int16_t *sump; 48690075Sobrien int sumoff; 48790075Sobrien 48890075Sobrien /* compute checksum */ 48990075Sobrien if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) 490169689Skan off = offsetof(struct icmp6_hdr, icmp6_cksum); 491169689Skan else 49290075Sobrien off = inp->inp_cksum6; 49390075Sobrien if (plen < 2 || plen - 2 < off) { 49490075Sobrien error = EINVAL; 495117395Skan goto bad; 49690075Sobrien } 497132718Skan off += sizeof(struct ip6_hdr); 49890075Sobrien 49990075Sobrien n = m_pulldown(m, off, sizeof(*sump), &sumoff); 50090075Sobrien if (n == NULL) { 50190075Sobrien m = NULL; 50290075Sobrien error = ENOBUFS; 503117395Skan goto bad; 50490075Sobrien } 50590075Sobrien sump = (u_int16_t *)(mtod(n, caddr_t) + sumoff); 506169689Skan *sump = 0; 507169689Skan *sump = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); 508169689Skan } 509169689Skan 510182907Sobrien flags = 0; 511169689Skan if (inp->inp_flags & IN6P_MINMTU) 512169689Skan flags |= IPV6_MINMTU; 513169689Skan 514169689Skan /* force routing table */ 515169689Skan m->m_pkthdr.ph_rtableid = inp->inp_rtableid; 516169689Skan 517169689Skan#if NPF > 0 518169689Skan if (inp->inp_socket->so_state & SS_ISCONNECTED && 519169689Skan so->so_proto->pr_protocol != IPPROTO_ICMPV6) 520169689Skan pf_mbuf_link_inpcb(m, inp); 521169689Skan#endif 522169689Skan 523169689Skan error = ip6_output(m, optp, &inp->inp_route, flags, 524169689Skan inp->inp_moptions6, &inp->inp_seclevel); 525169689Skan if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { 526169689Skan icmp6stat_inc(icp6s_outhist + type); 52790075Sobrien } else 52890075Sobrien rip6stat_inc(rip6s_opackets); 52990075Sobrien 53090075Sobrien goto freectl; 53190075Sobrien 53290075Sobrien bad: 53390075Sobrien m_freem(m); 53490075Sobrien 53590075Sobrien freectl: 53690075Sobrien if (control) { 53790075Sobrien ip6_clearpktopts(&opt, -1); 538169689Skan m_freem(control); 53990075Sobrien } 54090075Sobrien return (error); 54190075Sobrien} 54290075Sobrien 54390075Sobrien/* 54490075Sobrien * Raw IPv6 socket option processing. 54590075Sobrien */ 54690075Sobrienint 54790075Sobrienrip6_ctloutput(int op, struct socket *so, int level, int optname, 54890075Sobrien struct mbuf *m) 54990075Sobrien{ 55090075Sobrien#ifdef MROUTING 55190075Sobrien int error; 55290075Sobrien#endif 55390075Sobrien 55490075Sobrien switch (level) { 55590075Sobrien case IPPROTO_IPV6: 55690075Sobrien switch (optname) { 55790075Sobrien#ifdef MROUTING 55890075Sobrien case MRT6_INIT: 55990075Sobrien case MRT6_DONE: 56090075Sobrien case MRT6_ADD_MIF: 56190075Sobrien case MRT6_DEL_MIF: 56290075Sobrien case MRT6_ADD_MFC: 56390075Sobrien case MRT6_DEL_MFC: 564132718Skan if (op == PRCO_SETOPT) { 565132718Skan error = ip6_mrouter_set(optname, so, m); 566132718Skan } else if (op == PRCO_GETOPT) 567132718Skan error = ip6_mrouter_get(optname, so, m); 568132718Skan else 569169689Skan error = EINVAL; 570169689Skan return (error); 571169689Skan#endif 572169689Skan case IPV6_CHECKSUM: 573169689Skan return (ip6_raw_ctloutput(op, so, level, optname, m)); 57490075Sobrien default: 57590075Sobrien return (ip6_ctloutput(op, so, level, optname, m)); 57690075Sobrien } 57790075Sobrien 57890075Sobrien case IPPROTO_ICMPV6: 57990075Sobrien /* 58090075Sobrien * XXX: is it better to call icmp6_ctloutput() directly 58190075Sobrien * from protosw? 58290075Sobrien */ 58390075Sobrien return (icmp6_ctloutput(op, so, level, optname, m)); 58490075Sobrien 58590075Sobrien default: 58690075Sobrien return EINVAL; 58790075Sobrien } 58890075Sobrien} 58990075Sobrien 59090075Sobrienextern u_long rip6_sendspace; 59190075Sobrienextern u_long rip6_recvspace; 59290075Sobrien 59390075Sobrienint 59490075Sobrienrip6_attach(struct socket *so, int proto, int wait) 59590075Sobrien{ 59690075Sobrien struct inpcb *inp; 59790075Sobrien int error; 598169689Skan 599169689Skan if (so->so_pcb) 600169689Skan panic("%s", __func__); 601169689Skan if ((so->so_state & SS_PRIV) == 0) 602169689Skan return (EACCES); 603132718Skan if (proto < 0 || proto >= IPPROTO_MAX) 604132718Skan return EPROTONOSUPPORT; 605169689Skan 606169689Skan if ((error = soreserve(so, rip6_sendspace, rip6_recvspace))) 607169689Skan return error; 608169689Skan NET_ASSERT_LOCKED(); 609169689Skan if ((error = in_pcballoc(so, &rawin6pcbtable, wait))) 610169689Skan return error; 611169689Skan 612169689Skan inp = sotoinpcb(so); 613169689Skan inp->inp_ipv6.ip6_nxt = proto; 61490075Sobrien inp->inp_cksum6 = -1; 61590075Sobrien 61690075Sobrien inp->inp_icmp6filt = malloc(sizeof(struct icmp6_filter), M_PCB, 61790075Sobrien wait == M_WAIT ? M_WAITOK : M_NOWAIT); 61890075Sobrien if (inp->inp_icmp6filt == NULL) { 61990075Sobrien in_pcbdetach(inp); 62090075Sobrien return ENOMEM; 62190075Sobrien } 622169689Skan ICMP6_FILTER_SETPASSALL(inp->inp_icmp6filt); 623132718Skan return 0; 62490075Sobrien} 62590075Sobrien 62690075Sobrienint 62790075Sobrienrip6_detach(struct socket *so) 62890075Sobrien{ 629132718Skan struct inpcb *inp = sotoinpcb(so); 630132718Skan 631132718Skan soassertlocked(so); 632132718Skan 633132718Skan if (inp == NULL) 634169689Skan panic("%s", __func__); 635169689Skan#ifdef MROUTING 636169689Skan if (so == ip6_mrouter[inp->inp_rtableid]) 637169689Skan ip6_mrouter_done(so); 638169689Skan#endif 639169689Skan free(inp->inp_icmp6filt, M_PCB, sizeof(struct icmp6_filter)); 64090075Sobrien inp->inp_icmp6filt = NULL; 64190075Sobrien 64290075Sobrien in_pcbdetach(inp); 64390075Sobrien 64490075Sobrien return (0); 64590075Sobrien} 64690075Sobrien 64790075Sobrienvoid 64890075Sobrienrip6_lock(struct socket *so) 64990075Sobrien{ 650169689Skan struct inpcb *inp = sotoinpcb(so); 65190075Sobrien 652169689Skan NET_ASSERT_LOCKED(); 653169689Skan mtx_enter(&inp->inp_mtx); 65490075Sobrien} 65590075Sobrien 656132718Skanvoid 657132718Skanrip6_unlock(struct socket *so) 65890075Sobrien{ 659132718Skan struct inpcb *inp = sotoinpcb(so); 660132718Skan 661132718Skan NET_ASSERT_LOCKED(); 662132718Skan mtx_leave(&inp->inp_mtx); 663132718Skan} 664132718Skan 665132718Skanint 666132718Skanrip6_locked(struct socket *so) 667132718Skan{ 668132718Skan struct inpcb *inp = sotoinpcb(so); 669132718Skan 670132718Skan return mtx_owned(&inp->inp_mtx); 671132718Skan} 672132718Skan 673169689Skanint 674132718Skanrip6_bind(struct socket *so, struct mbuf *nam, struct proc *p) 675169689Skan{ 676132718Skan struct inpcb *inp = sotoinpcb(so); 677169689Skan struct sockaddr_in6 *addr; 678169689Skan int error; 679169689Skan 680169689Skan soassertlocked(so); 681169689Skan 682169689Skan if ((error = in6_nam2sin6(nam, &addr))) 683169689Skan return (error); 684169689Skan 685169689Skan /* 686132718Skan * Make sure to not enter in_pcblookup_local(), local ports 687169689Skan * are non-sensical for raw sockets. 688169689Skan */ 689169689Skan addr->sin6_port = 0; 690169689Skan 691169689Skan if ((error = in6_pcbaddrisavail(inp, addr, 0, p))) 692169689Skan return (error); 693169689Skan 694169689Skan mtx_enter(&rawin6pcbtable.inpt_mtx); 695169689Skan inp->inp_laddr6 = addr->sin6_addr; 696132718Skan mtx_leave(&rawin6pcbtable.inpt_mtx); 697132718Skan 698132718Skan return (0); 699132718Skan} 700132718Skan 701132718Skanint 702132718Skanrip6_connect(struct socket *so, struct mbuf *nam) 703132718Skan{ 704132718Skan struct inpcb *inp = sotoinpcb(so); 705132718Skan struct sockaddr_in6 *addr; 706132718Skan const struct in6_addr *in6a; 707169689Skan int error; 708132718Skan 709132718Skan soassertlocked(so); 710132718Skan 711132718Skan if ((error = in6_nam2sin6(nam, &addr))) 712132718Skan return (error); 713132718Skan 714132718Skan /* Source address selection. XXX: need pcblookup? */ 715132718Skan error = in6_pcbselsrc(&in6a, addr, inp, inp->inp_outputopts6); 716132718Skan if (error) 717132718Skan return (error); 718132718Skan 719132718Skan mtx_enter(&rawin6pcbtable.inpt_mtx); 72090075Sobrien inp->inp_laddr6 = *in6a; 72190075Sobrien inp->inp_faddr6 = addr->sin6_addr; 72290075Sobrien mtx_leave(&rawin6pcbtable.inpt_mtx); 72390075Sobrien soisconnected(so); 72490075Sobrien 72590075Sobrien return (0); 72690075Sobrien} 72790075Sobrien 728169689Skanint 729169689Skanrip6_disconnect(struct socket *so) 730169689Skan{ 731169689Skan struct inpcb *inp = sotoinpcb(so); 732169689Skan 733169689Skan soassertlocked(so); 73490075Sobrien 73590075Sobrien if ((so->so_state & SS_ISCONNECTED) == 0) 73690075Sobrien return (ENOTCONN); 737169689Skan 738169689Skan soisdisconnected(so); 73990075Sobrien mtx_enter(&rawin6pcbtable.inpt_mtx); 74090075Sobrien inp->inp_faddr6 = in6addr_any; 74190075Sobrien mtx_leave(&rawin6pcbtable.inpt_mtx); 742169689Skan 743132718Skan return (0); 74490075Sobrien} 74590075Sobrien 74690075Sobrienint 74790075Sobrienrip6_shutdown(struct socket *so) 74890075Sobrien{ 74990075Sobrien /* 75090075Sobrien * Mark the connection as being incapable of further input. 75190075Sobrien */ 75290075Sobrien soassertlocked(so); 75390075Sobrien socantsendmore(so); 75490075Sobrien return (0); 75590075Sobrien} 75690075Sobrien 75790075Sobrienint 758132718Skanrip6_send(struct socket *so, struct mbuf *m, struct mbuf *nam, 75990075Sobrien struct mbuf *control) 76090075Sobrien{ 761117395Skan struct inpcb *inp = sotoinpcb(so); 76290075Sobrien struct sockaddr_in6 dst; 763169689Skan int error; 764169689Skan 765117395Skan soassertlocked(so); 766117395Skan 76790075Sobrien /* 76890075Sobrien * Ship a packet out. The appropriate raw output 769117395Skan * routine handles any messaging necessary. 770117395Skan */ 77190075Sobrien 77290075Sobrien /* always copy sockaddr to avoid overwrites */ 77390075Sobrien memset(&dst, 0, sizeof(dst)); 77490075Sobrien dst.sin6_family = AF_INET6; 77590075Sobrien dst.sin6_len = sizeof(dst); 776132718Skan if (so->so_state & SS_ISCONNECTED) { 77790075Sobrien if (nam) { 77890075Sobrien error = EISCONN; 77990075Sobrien goto out; 78090075Sobrien } 78190075Sobrien dst.sin6_addr = inp->inp_faddr6; 78290075Sobrien } else { 78390075Sobrien struct sockaddr_in6 *addr6; 78490075Sobrien 785132718Skan if (nam == NULL) { 786132718Skan error = ENOTCONN; 78790075Sobrien goto out; 788132718Skan } 789132718Skan if ((error = in6_nam2sin6(nam, &addr6))) 79090075Sobrien goto out; 791169689Skan dst.sin6_addr = addr6->sin6_addr; 792169689Skan dst.sin6_scope_id = addr6->sin6_scope_id; 793169689Skan } 794169689Skan error = rip6_output(m, so, sin6tosa(&dst), control); 795169689Skan control = NULL; 796169689Skan m = NULL; 797169689Skan 798169689Skanout: 799169689Skan m_freem(control); 800169689Skan m_freem(m); 801169689Skan 80290075Sobrien return (error); 803169689Skan} 804169689Skan 80590075Sobrienint 80690075Sobrienrip6_sysctl_rip6stat(void *oldp, size_t *oldplen, void *newp) 80790075Sobrien{ 80890075Sobrien struct rip6stat rip6stat; 80990075Sobrien 81090075Sobrien CTASSERT(sizeof(rip6stat) == rip6s_ncounters * sizeof(uint64_t)); 81190075Sobrien counters_read(rip6counters, (uint64_t *)&rip6stat, rip6s_ncounters, 81290075Sobrien NULL); 81390075Sobrien 81490075Sobrien return (sysctl_rdstruct(oldp, oldplen, newp, 81590075Sobrien &rip6stat, sizeof(rip6stat))); 81690075Sobrien} 817132718Skan 81890075Sobrienint 81990075Sobrienrip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 82090075Sobrien void *newp, size_t newlen) 82190075Sobrien{ 82290075Sobrien /* All sysctl names at this level are terminal. */ 82390075Sobrien if (namelen != 1) 82490075Sobrien return ENOTDIR; 825132718Skan 82690075Sobrien switch (name[0]) { 82790075Sobrien case RIPV6CTL_STATS: 82890075Sobrien return (rip6_sysctl_rip6stat(oldp, oldlenp, newp)); 82990075Sobrien default: 83090075Sobrien return (EOPNOTSUPP); 83190075Sobrien } 83290075Sobrien /* NOTREACHED */ 83390075Sobrien} 83490075Sobrien