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

Cache object: 08858a30249675bae61670ee5ee270b3


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