The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/raw_ip6.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: raw_ip6.c,v 1.71 2005/03/11 06:16:16 atatat Exp $      */
    2 /*      $KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei 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 <sys/cdefs.h>
   65 __KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.71 2005/03/11 06:16:16 atatat Exp $");
   66 
   67 #include "opt_ipsec.h"
   68 
   69 #include <sys/param.h>
   70 #include <sys/sysctl.h>
   71 #include <sys/malloc.h>
   72 #include <sys/mbuf.h>
   73 #include <sys/socket.h>
   74 #include <sys/protosw.h>
   75 #include <sys/socketvar.h>
   76 #include <sys/errno.h>
   77 #include <sys/systm.h>
   78 #include <sys/proc.h>
   79 
   80 #include <net/if.h>
   81 #include <net/route.h>
   82 #include <net/if_types.h>
   83 
   84 #include <netinet/in.h>
   85 #include <netinet/in_var.h>
   86 #include <netinet/ip6.h>
   87 #include <netinet6/ip6_var.h>
   88 #include <netinet6/ip6_mroute.h>
   89 #include <netinet/icmp6.h>
   90 #include <netinet6/in6_pcb.h>
   91 #include <netinet6/nd6.h>
   92 #include <netinet6/ip6protosw.h>
   93 #ifdef ENABLE_DEFAULT_SCOPE
   94 #include <netinet6/scope6_var.h>
   95 #endif
   96 #include <netinet6/raw_ip6.h>
   97 
   98 #ifdef IPSEC
   99 #include <netinet6/ipsec.h>
  100 #endif /* IPSEC */
  101 
  102 #include <machine/stdarg.h>
  103 
  104 #include "faith.h"
  105 #if defined(NFAITH) && 0 < NFAITH
  106 #include <net/if_faith.h>
  107 #endif
  108 
  109 extern struct inpcbtable rawcbtable;
  110 struct  inpcbtable raw6cbtable;
  111 #define ifatoia6(ifa)   ((struct in6_ifaddr *)(ifa))
  112 
  113 /*
  114  * Raw interface to IP6 protocol.
  115  */
  116 
  117 struct rip6stat rip6stat;
  118 
  119 /*
  120  * Initialize raw connection block queue.
  121  */
  122 void
  123 rip6_init()
  124 {
  125 
  126         in6_pcbinit(&raw6cbtable, 1, 1);
  127 }
  128 
  129 /*
  130  * Setup generic address and protocol structures
  131  * for raw_input routine, then pass them along with
  132  * mbuf chain.
  133  */
  134 int
  135 rip6_input(mp, offp, proto)
  136         struct  mbuf **mp;
  137         int     *offp, proto;
  138 {
  139         struct mbuf *m = *mp;
  140         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
  141         struct inpcb_hdr *inph;
  142         struct in6pcb *in6p;
  143         struct in6pcb *last = NULL;
  144         struct sockaddr_in6 rip6src;
  145         struct mbuf *opts = NULL;
  146 
  147         rip6stat.rip6s_ipackets++;
  148 
  149 #if defined(NFAITH) && 0 < NFAITH
  150         if (faithprefix(&ip6->ip6_dst)) {
  151                 /* send icmp6 host unreach? */
  152                 m_freem(m);
  153                 return IPPROTO_DONE;
  154         }
  155 #endif
  156 
  157         /* Be proactive about malicious use of IPv4 mapped address */
  158         if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
  159             IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
  160                 /* XXX stat */
  161                 m_freem(m);
  162                 return IPPROTO_DONE;
  163         }
  164 
  165         bzero(&rip6src, sizeof(rip6src));
  166         rip6src.sin6_len = sizeof(struct sockaddr_in6);
  167         rip6src.sin6_family = AF_INET6;
  168         /* KAME hack: recover scopeid */
  169         (void)in6_recoverscope(&rip6src, &ip6->ip6_src, m->m_pkthdr.rcvif);
  170 
  171         CIRCLEQ_FOREACH(inph, &raw6cbtable.inpt_queue, inph_queue) {
  172                 in6p = (struct in6pcb *)inph;
  173                 if (in6p->in6p_af != AF_INET6)
  174                         continue;
  175                 if (in6p->in6p_ip6.ip6_nxt &&
  176                     in6p->in6p_ip6.ip6_nxt != proto)
  177                         continue;
  178                 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
  179                     !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
  180                         continue;
  181                 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
  182                     !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
  183                         continue;
  184                 if (in6p->in6p_cksum != -1) {
  185                         rip6stat.rip6s_isum++;
  186                         if (in6_cksum(m, proto, *offp,
  187                             m->m_pkthdr.len - *offp)) {
  188                                 rip6stat.rip6s_badsum++;
  189                                 continue;
  190                         }
  191                 }
  192                 if (last) {
  193                         struct  mbuf *n;
  194 
  195 #ifdef IPSEC
  196                         /*
  197                          * Check AH/ESP integrity.
  198                          */
  199                         if (ipsec6_in_reject(m, last)) {
  200                                 ipsec6stat.in_polvio++;
  201                                 /* do not inject data into pcb */
  202                         } else
  203 #endif /* IPSEC */
  204                         if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
  205                                 if (last->in6p_flags & IN6P_CONTROLOPTS)
  206                                         ip6_savecontrol(last, &opts, ip6, n);
  207                                 /* strip intermediate headers */
  208                                 m_adj(n, *offp);
  209                                 if (sbappendaddr(&last->in6p_socket->so_rcv,
  210                                     (struct sockaddr *)&rip6src, n, opts) == 0) {
  211                                         /* should notify about lost packet */
  212                                         m_freem(n);
  213                                         if (opts)
  214                                                 m_freem(opts);
  215                                         rip6stat.rip6s_fullsock++;
  216                                 } else
  217                                         sorwakeup(last->in6p_socket);
  218                                 opts = NULL;
  219                         }
  220                 }
  221                 last = in6p;
  222         }
  223 #ifdef IPSEC
  224         /*
  225          * Check AH/ESP integrity.
  226          */
  227         if (last && ipsec6_in_reject(m, last)) {
  228                 m_freem(m);
  229                 ipsec6stat.in_polvio++;
  230                 ip6stat.ip6s_delivered--;
  231                 /* do not inject data into pcb */
  232         } else
  233 #endif /* IPSEC */
  234         if (last) {
  235                 if (last->in6p_flags & IN6P_CONTROLOPTS)
  236                         ip6_savecontrol(last, &opts, ip6, m);
  237                 /* strip intermediate headers */
  238                 m_adj(m, *offp);
  239                 if (sbappendaddr(&last->in6p_socket->so_rcv,
  240                     (struct sockaddr *)&rip6src, m, opts) == 0) {
  241                         m_freem(m);
  242                         if (opts)
  243                                 m_freem(opts);
  244                         rip6stat.rip6s_fullsock++;
  245                 } else
  246                         sorwakeup(last->in6p_socket);
  247         } else {
  248                 rip6stat.rip6s_nosock++;
  249                 if (m->m_flags & M_MCAST)
  250                         rip6stat.rip6s_nosockmcast++;
  251                 if (proto == IPPROTO_NONE)
  252                         m_freem(m);
  253                 else {
  254                         u_int8_t *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
  255                         in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_protounknown);
  256                         icmp6_error(m, ICMP6_PARAM_PROB,
  257                             ICMP6_PARAMPROB_NEXTHEADER,
  258                             prvnxtp - mtod(m, u_int8_t *));
  259                 }
  260                 ip6stat.ip6s_delivered--;
  261         }
  262         return IPPROTO_DONE;
  263 }
  264 
  265 void
  266 rip6_ctlinput(cmd, sa, d)
  267         int cmd;
  268         struct sockaddr *sa;
  269         void *d;
  270 {
  271         struct ip6_hdr *ip6;
  272         struct ip6ctlparam *ip6cp = NULL;
  273         const struct sockaddr_in6 *sa6_src = NULL;
  274         void *cmdarg;
  275         void (*notify) __P((struct in6pcb *, int)) = in6_rtchange;
  276         int nxt;
  277 
  278         if (sa->sa_family != AF_INET6 ||
  279             sa->sa_len != sizeof(struct sockaddr_in6))
  280                 return;
  281 
  282         if ((unsigned)cmd >= PRC_NCMDS)
  283                 return;
  284         if (PRC_IS_REDIRECT(cmd))
  285                 notify = in6_rtchange, d = NULL;
  286         else if (cmd == PRC_HOSTDEAD)
  287                 d = NULL;
  288         else if (cmd == PRC_MSGSIZE)
  289                 ; /* special code is present, see below */
  290         else if (inet6ctlerrmap[cmd] == 0)
  291                 return;
  292 
  293         /* if the parameter is from icmp6, decode it. */
  294         if (d != NULL) {
  295                 ip6cp = (struct ip6ctlparam *)d;
  296                 ip6 = ip6cp->ip6c_ip6;
  297                 cmdarg = ip6cp->ip6c_cmdarg;
  298                 sa6_src = ip6cp->ip6c_src;
  299                 nxt = ip6cp->ip6c_nxt;
  300         } else {
  301                 ip6 = NULL;
  302                 cmdarg = NULL;
  303                 sa6_src = &sa6_any;
  304                 nxt = -1;
  305         }
  306 
  307         if (ip6 && cmd == PRC_MSGSIZE) {
  308                 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
  309                 int valid = 0;
  310                 struct in6pcb *in6p;
  311 
  312                 /*
  313                  * Check to see if we have a valid raw IPv6 socket
  314                  * corresponding to the address in the ICMPv6 message
  315                  * payload, and the protocol (ip6_nxt) meets the socket.
  316                  * XXX chase extension headers, or pass final nxt value
  317                  * from icmp6_notify_error()
  318                  */
  319                 in6p = NULL;
  320                 in6p = in6_pcblookup_connect(&raw6cbtable, &sa6->sin6_addr, 0,
  321                     (struct in6_addr *)&sa6_src->sin6_addr, 0, 0);
  322 #if 0
  323                 if (!in6p) {
  324                         /*
  325                          * As the use of sendto(2) is fairly popular,
  326                          * we may want to allow non-connected pcb too.
  327                          * But it could be too weak against attacks...
  328                          * We should at least check if the local
  329                          * address (= s) is really ours.
  330                          */
  331                         in6p = in6_pcblookup_bind(&raw6cbtable,
  332                             &sa6->sin6_addr, 0, 0))
  333                 }
  334 #endif
  335 
  336                 if (in6p && in6p->in6p_ip6.ip6_nxt &&
  337                     in6p->in6p_ip6.ip6_nxt == nxt)
  338                         valid++;
  339 
  340                 /*
  341                  * Depending on the value of "valid" and routing table
  342                  * size (mtudisc_{hi,lo}wat), we will:
  343                  * - recalculate the new MTU and create the
  344                  *   corresponding routing entry, or
  345                  * - ignore the MTU change notification.
  346                  */
  347                 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
  348 
  349                 /*
  350                  * regardless of if we called icmp6_mtudisc_update(),
  351                  * we need to call in6_pcbnotify(), to notify path
  352                  * MTU change to the userland (2292bis-02), because
  353                  * some unconnected sockets may share the same
  354                  * destination and want to know the path MTU.
  355                  */
  356         }
  357 
  358         (void) in6_pcbnotify(&raw6cbtable, sa, 0,
  359             (struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
  360 }
  361 
  362 /*
  363  * Generate IPv6 header and pass packet to ip6_output.
  364  * Tack on options user may have setup with control call.
  365  */
  366 int
  367 #if __STDC__
  368 rip6_output(struct mbuf *m, ...)
  369 #else
  370 rip6_output(m, va_alist)
  371         struct mbuf *m;
  372         va_dcl
  373 #endif
  374 {
  375         struct socket *so;
  376         struct sockaddr_in6 *dstsock;
  377         struct mbuf *control;
  378         struct in6_addr *dst;
  379         struct ip6_hdr *ip6;
  380         struct in6pcb *in6p;
  381         u_int   plen = m->m_pkthdr.len;
  382         int error = 0;
  383         struct ip6_pktopts opt, *optp = NULL, *origoptp;
  384         struct ifnet *oifp = NULL;
  385         int type, code;         /* for ICMPv6 output statistics only */
  386         int priv = 0;
  387         va_list ap;
  388         int flags;
  389 
  390         va_start(ap, m);
  391         so = va_arg(ap, struct socket *);
  392         dstsock = va_arg(ap, struct sockaddr_in6 *);
  393         control = va_arg(ap, struct mbuf *);
  394         va_end(ap);
  395 
  396         in6p = sotoin6pcb(so);
  397 
  398         priv = 0;
  399     {
  400         struct proc *p = curproc;       /* XXX */
  401 
  402         if (p && !suser(p->p_ucred, &p->p_acflag))
  403                 priv = 1;
  404     }
  405         dst = &dstsock->sin6_addr;
  406         if (control) {
  407                 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
  408                         goto bad;
  409                 optp = &opt;
  410         } else
  411                 optp = in6p->in6p_outputopts;
  412 
  413         /*
  414          * For an ICMPv6 packet, we should know its type and code
  415          * to update statistics.
  416          */
  417         if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
  418                 struct icmp6_hdr *icmp6;
  419                 if (m->m_len < sizeof(struct icmp6_hdr) &&
  420                     (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
  421                         error = ENOBUFS;
  422                         goto bad;
  423                 }
  424                 icmp6 = mtod(m, struct icmp6_hdr *);
  425                 type = icmp6->icmp6_type;
  426                 code = icmp6->icmp6_code;
  427         } else {
  428                 type = 0;
  429                 code = 0;
  430         }
  431 
  432         M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
  433         if (!m) {
  434                 error = ENOBUFS;
  435                 goto bad;
  436         }
  437         ip6 = mtod(m, struct ip6_hdr *);
  438 
  439         /*
  440          * Next header might not be ICMP6 but use its pseudo header anyway.
  441          */
  442         ip6->ip6_dst = *dst;
  443 
  444         /* KAME hack: embed scopeid */
  445         origoptp = in6p->in6p_outputopts;
  446         in6p->in6p_outputopts = optp;
  447         if (in6_embedscope(&ip6->ip6_dst, dstsock, in6p, &oifp) != 0) {
  448                 error = EINVAL;
  449                 goto bad;
  450         }
  451         in6p->in6p_outputopts = origoptp;
  452 
  453         /*
  454          * Source address selection.
  455          */
  456         {
  457                 struct in6_addr *in6a;
  458 
  459                 if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
  460                     &in6p->in6p_route, &in6p->in6p_laddr, &error)) == 0) {
  461                         if (error == 0)
  462                                 error = EADDRNOTAVAIL;
  463                         goto bad;
  464                 }
  465                 ip6->ip6_src = *in6a;
  466                 if (in6p->in6p_route.ro_rt) {
  467                         /* what if oifp contradicts ? */
  468                         oifp = ifindex2ifnet[in6p->in6p_route.ro_rt->rt_ifp->if_index];
  469                 }
  470         }
  471 
  472         ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
  473         ip6->ip6_vfc  &= ~IPV6_VERSION_MASK;
  474         ip6->ip6_vfc  |= IPV6_VERSION;
  475 #if 0                           /* ip6_plen will be filled in ip6_output. */
  476         ip6->ip6_plen  = htons((u_int16_t)plen);
  477 #endif
  478         ip6->ip6_nxt   = in6p->in6p_ip6.ip6_nxt;
  479         ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
  480 
  481         if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
  482             in6p->in6p_cksum != -1) {
  483                 int off;
  484                 u_int16_t sum;
  485 
  486                 /* compute checksum */
  487                 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
  488                         off = offsetof(struct icmp6_hdr, icmp6_cksum);
  489                 else
  490                         off = in6p->in6p_cksum;
  491                 if (plen < off + 1) {
  492                         error = EINVAL;
  493                         goto bad;
  494                 }
  495                 off += sizeof(struct ip6_hdr);
  496 
  497                 sum = 0;
  498                 m = m_copyback_cow(m, off, sizeof(sum), (caddr_t)&sum,
  499                     M_DONTWAIT);
  500                 if (m == NULL) {
  501                         error = ENOBUFS;
  502                         goto bad;
  503                 }
  504                 sum = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
  505                 m = m_copyback_cow(m, off, sizeof(sum), (caddr_t)&sum,
  506                     M_DONTWAIT);
  507                 if (m == NULL) {
  508                         error = ENOBUFS;
  509                         goto bad;
  510                 }
  511         }
  512 
  513         flags = 0;
  514         if (in6p->in6p_flags & IN6P_MINMTU)
  515                 flags |= IPV6_MINMTU;
  516 
  517         error = ip6_output(m, optp, &in6p->in6p_route, flags,
  518             in6p->in6p_moptions, so, &oifp);
  519         if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
  520                 if (oifp)
  521                         icmp6_ifoutstat_inc(oifp, type, code);
  522                 icmp6stat.icp6s_outhist[type]++;
  523         } else
  524                 rip6stat.rip6s_opackets++;
  525 
  526         goto freectl;
  527 
  528  bad:
  529         if (m)
  530                 m_freem(m);
  531 
  532  freectl:
  533         if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt)
  534                 RTFREE(optp->ip6po_route.ro_rt);
  535         if (control)
  536                 m_freem(control);
  537         return (error);
  538 }
  539 
  540 /*
  541  * Raw IPv6 socket option processing.
  542  */
  543 int
  544 rip6_ctloutput(op, so, level, optname, mp)
  545         int op;
  546         struct socket *so;
  547         int level, optname;
  548         struct mbuf **mp;
  549 {
  550         int error = 0;
  551 
  552         switch (level) {
  553         case IPPROTO_IPV6:
  554                 switch (optname) {
  555                 case MRT6_INIT:
  556                 case MRT6_DONE:
  557                 case MRT6_ADD_MIF:
  558                 case MRT6_DEL_MIF:
  559                 case MRT6_ADD_MFC:
  560                 case MRT6_DEL_MFC:
  561                 case MRT6_PIM:
  562                         if (op == PRCO_SETOPT) {
  563                                 error = ip6_mrouter_set(optname, so, *mp);
  564                                 if (*mp)
  565                                         (void)m_free(*mp);
  566                         } else if (op == PRCO_GETOPT)
  567                                 error = ip6_mrouter_get(optname, so, mp);
  568                         else
  569                                 error = EINVAL;
  570                         return (error);
  571                 case IPV6_CHECKSUM:
  572                         return (ip6_raw_ctloutput(op, so, level, optname, mp));
  573                 default:
  574                         return (ip6_ctloutput(op, so, level, optname, mp));
  575                 }
  576 
  577         case IPPROTO_ICMPV6:
  578                 /*
  579                  * XXX: is it better to call icmp6_ctloutput() directly
  580                  * from protosw?
  581                  */
  582                 return (icmp6_ctloutput(op, so, level, optname, mp));
  583 
  584         default:
  585                 if (op == PRCO_SETOPT && *mp)
  586                         m_free(*mp);
  587                 return EINVAL;
  588         }
  589 }
  590 
  591 extern  u_long rip6_sendspace;
  592 extern  u_long rip6_recvspace;
  593 
  594 int
  595 rip6_usrreq(so, req, m, nam, control, p)
  596         struct socket *so;
  597         int req;
  598         struct mbuf *m, *nam, *control;
  599         struct proc *p;
  600 {
  601         struct in6pcb *in6p = sotoin6pcb(so);
  602         int s;
  603         int error = 0;
  604         int priv;
  605 
  606         priv = 0;
  607         if (p && !suser(p->p_ucred, &p->p_acflag))
  608                 priv++;
  609 
  610         if (req == PRU_CONTROL)
  611                 return (in6_control(so, (u_long)m, (caddr_t)nam,
  612                     (struct ifnet *)control, p));
  613 
  614         if (req == PRU_PURGEIF) {
  615                 in6_pcbpurgeif0(&raw6cbtable, (struct ifnet *)control);
  616                 in6_purgeif((struct ifnet *)control);
  617                 in6_pcbpurgeif(&raw6cbtable, (struct ifnet *)control);
  618                 return (0);
  619         }
  620 
  621         switch (req) {
  622         case PRU_ATTACH:
  623                 if (in6p)
  624                         panic("rip6_attach");
  625                 if (!priv) {
  626                         error = EACCES;
  627                         break;
  628                 }
  629                 s = splsoftnet();
  630                 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)) != 0) {
  631                         splx(s);
  632                         break;
  633                 }
  634                 if ((error = in6_pcballoc(so, &raw6cbtable)) != 0)
  635                 {
  636                         splx(s);
  637                         break;
  638                 }
  639                 splx(s);
  640                 in6p = sotoin6pcb(so);
  641                 in6p->in6p_ip6.ip6_nxt = (long)nam;
  642                 in6p->in6p_cksum = -1;
  643 
  644                 MALLOC(in6p->in6p_icmp6filt, struct icmp6_filter *,
  645                     sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
  646                 if (in6p->in6p_icmp6filt == NULL) {
  647                         in6_pcbdetach(in6p);
  648                         error = ENOMEM;
  649                         break;
  650                 }
  651                 ICMP6_FILTER_SETPASSALL(in6p->in6p_icmp6filt);
  652                 break;
  653 
  654         case PRU_DISCONNECT:
  655                 if ((so->so_state & SS_ISCONNECTED) == 0) {
  656                         error = ENOTCONN;
  657                         break;
  658                 }
  659                 in6p->in6p_faddr = in6addr_any;
  660                 so->so_state &= ~SS_ISCONNECTED;        /* XXX */
  661                 break;
  662 
  663         case PRU_ABORT:
  664                 soisdisconnected(so);
  665                 /* Fallthrough */
  666         case PRU_DETACH:
  667                 if (in6p == 0)
  668                         panic("rip6_detach");
  669                 if (so == ip6_mrouter)
  670                         ip6_mrouter_done();
  671                 /* xxx: RSVP */
  672                 if (in6p->in6p_icmp6filt) {
  673                         FREE(in6p->in6p_icmp6filt, M_PCB);
  674                         in6p->in6p_icmp6filt = NULL;
  675                 }
  676                 in6_pcbdetach(in6p);
  677                 break;
  678 
  679         case PRU_BIND:
  680             {
  681                 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
  682                 struct ifaddr *ia = NULL;
  683 
  684                 if (nam->m_len != sizeof(*addr)) {
  685                         error = EINVAL;
  686                         break;
  687                 }
  688                 if ((ifnet.tqh_first == 0) || (addr->sin6_family != AF_INET6)) {
  689                         error = EADDRNOTAVAIL;
  690                         break;
  691                 }
  692 #ifdef ENABLE_DEFAULT_SCOPE
  693                 if (addr->sin6_scope_id == 0)   /* not change if specified  */
  694                         addr->sin6_scope_id =
  695                             scope6_addr2default(&addr->sin6_addr);
  696 #endif
  697                 /* KAME hack: embed scopeid */
  698                 if (in6_embedscope(&addr->sin6_addr, addr, in6p, NULL) != 0)
  699                         return EINVAL;
  700 #ifndef SCOPEDROUTING
  701                 addr->sin6_scope_id = 0; /* for ifa_ifwithaddr */
  702 #endif
  703 
  704                 /*
  705                  * we don't support mapped address here, it would confuse
  706                  * users so reject it
  707                  */
  708                 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) {
  709                         error = EADDRNOTAVAIL;
  710                         break;
  711                 }
  712                 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
  713                     (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0) {
  714                         error = EADDRNOTAVAIL;
  715                         break;
  716                 }
  717                 if (ia && ((struct in6_ifaddr *)ia)->ia6_flags &
  718                     (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
  719                      IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
  720                         error = EADDRNOTAVAIL;
  721                         break;
  722                 }
  723                 in6p->in6p_laddr = addr->sin6_addr;
  724                 break;
  725             }
  726 
  727         case PRU_CONNECT:
  728         {
  729                 struct sockaddr_in6 *addr = mtod(nam, struct sockaddr_in6 *);
  730                 struct in6_addr *in6a = NULL;
  731 #ifdef ENABLE_DEFAULT_SCOPE
  732                 struct sockaddr_in6 sin6;
  733 #endif
  734 
  735                 if (nam->m_len != sizeof(*addr)) {
  736                         error = EINVAL;
  737                         break;
  738                 }
  739                 if (ifnet.tqh_first == 0)
  740                 {
  741                         error = EADDRNOTAVAIL;
  742                         break;
  743                 }
  744                 if (addr->sin6_family != AF_INET6) {
  745                         error = EAFNOSUPPORT;
  746                         break;
  747                 }
  748 
  749 #ifdef ENABLE_DEFAULT_SCOPE
  750                 if (addr->sin6_scope_id == 0) {
  751                         /* protect *addr */
  752                         sin6 = *addr;
  753                         addr = &sin6;
  754                         addr->sin6_scope_id =
  755                             scope6_addr2default(&addr->sin6_addr);
  756                 }
  757 #endif
  758 
  759                 /* Source address selection. XXX: need pcblookup? */
  760                 in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
  761                     in6p->in6p_moptions, &in6p->in6p_route,
  762                     &in6p->in6p_laddr, &error);
  763                 if (in6a == NULL) {
  764                         if (error == 0)
  765                                 error = EADDRNOTAVAIL;
  766                         break;
  767                 }
  768                 in6p->in6p_laddr = *in6a;
  769                 in6p->in6p_faddr = addr->sin6_addr;
  770                 soisconnected(so);
  771                 break;
  772         }
  773 
  774         case PRU_CONNECT2:
  775                 error = EOPNOTSUPP;
  776                 break;
  777 
  778         /*
  779          * Mark the connection as being incapable of futther input.
  780          */
  781         case PRU_SHUTDOWN:
  782                 socantsendmore(so);
  783                 break;
  784         /*
  785          * Ship a packet out. The appropriate raw output
  786          * routine handles any messaging necessary.
  787          */
  788         case PRU_SEND:
  789         {
  790                 struct sockaddr_in6 tmp;
  791                 struct sockaddr_in6 *dst;
  792 
  793                 /* always copy sockaddr to avoid overwrites */
  794                 if (so->so_state & SS_ISCONNECTED) {
  795                         if (nam) {
  796                                 error = EISCONN;
  797                                 break;
  798                         }
  799                         /* XXX */
  800                         bzero(&tmp, sizeof(tmp));
  801                         tmp.sin6_family = AF_INET6;
  802                         tmp.sin6_len = sizeof(struct sockaddr_in6);
  803                         bcopy(&in6p->in6p_faddr, &tmp.sin6_addr,
  804                             sizeof(struct in6_addr));
  805                         dst = &tmp;
  806                 } else {
  807                         if (nam == NULL) {
  808                                 error = ENOTCONN;
  809                                 break;
  810                         }
  811                         if (nam->m_len != sizeof(tmp)) {
  812                                 error = EINVAL;
  813                                 break;
  814                         }
  815 
  816                         tmp = *mtod(nam, struct sockaddr_in6 *);
  817                         dst = &tmp;
  818 
  819                         if (dst->sin6_family != AF_INET6) {
  820                                 error = EAFNOSUPPORT;
  821                                 break;
  822                         }
  823                 }
  824 #ifdef ENABLE_DEFAULT_SCOPE
  825                 if (dst->sin6_scope_id == 0) {
  826                         dst->sin6_scope_id =
  827                             scope6_addr2default(&dst->sin6_addr);
  828                 }
  829 #endif
  830                 error = rip6_output(m, so, dst, control);
  831                 m = NULL;
  832                 break;
  833         }
  834 
  835         case PRU_SENSE:
  836                 /*
  837                  * stat: don't bother with a blocksize
  838                  */
  839                 return (0);
  840         /*
  841          * Not supported.
  842          */
  843         case PRU_RCVOOB:
  844         case PRU_RCVD:
  845         case PRU_LISTEN:
  846         case PRU_ACCEPT:
  847         case PRU_SENDOOB:
  848                 error = EOPNOTSUPP;
  849                 break;
  850 
  851         case PRU_SOCKADDR:
  852                 in6_setsockaddr(in6p, nam);
  853                 break;
  854 
  855         case PRU_PEERADDR:
  856                 in6_setpeeraddr(in6p, nam);
  857                 break;
  858 
  859         default:
  860                 panic("rip6_usrreq");
  861         }
  862         if (m != NULL)
  863                 m_freem(m);
  864         return (error);
  865 }
  866 
  867 SYSCTL_SETUP(sysctl_net_inet6_raw6_setup, "sysctl net.inet6.raw6 subtree setup")
  868 {
  869 
  870         sysctl_createv(clog, 0, NULL, NULL,
  871                        CTLFLAG_PERMANENT,
  872                        CTLTYPE_NODE, "net", NULL,
  873                        NULL, 0, NULL, 0,
  874                        CTL_NET, CTL_EOL);
  875         sysctl_createv(clog, 0, NULL, NULL,
  876                        CTLFLAG_PERMANENT,
  877                        CTLTYPE_NODE, "inet6", NULL,
  878                        NULL, 0, NULL, 0,
  879                        CTL_NET, PF_INET6, CTL_EOL);
  880         sysctl_createv(clog, 0, NULL, NULL,
  881                        CTLFLAG_PERMANENT,
  882                        CTLTYPE_NODE, "raw6",
  883                        SYSCTL_DESCR("Raw IPv6 settings"),
  884                        NULL, 0, NULL, 0,
  885                        CTL_NET, PF_INET6, IPPROTO_RAW, CTL_EOL);
  886 
  887         sysctl_createv(clog, 0, NULL, NULL,
  888                        CTLFLAG_PERMANENT,
  889                        CTLTYPE_STRUCT, "pcblist",
  890                        SYSCTL_DESCR("Raw IPv6 control block list"),
  891                        sysctl_inpcblist, 0, &raw6cbtable, 0,
  892                        CTL_NET, PF_INET6, IPPROTO_RAW,
  893                        CTL_CREATE, CTL_EOL);
  894 }

Cache object: f32482ecaaf41bee6c292c089202d3d0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.