LCOV - code coverage report
Current view: top level - netinet6 - raw_ip6.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 339 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 10 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13