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

Cache object: b5fd9c7677bd5f679ec5e75266cfcc7d


[ 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.