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

Cache object: 47f890b0737b6c1f268e0232f3269153


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