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

Cache object: c99c8b43584329f9cc07f53c2e45808c


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