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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 4b052f1c0ba267c24350f0ce5afe0a7e


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