The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/raw_ip6.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of the project nor the names of its contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 /*-
   31  * Copyright (c) 1982, 1986, 1988, 1993
   32  *      The Regents of the University of California.
   33  * All rights reserved.
   34  *
   35  * Redistribution and use in source and binary forms, with or without
   36  * modification, are permitted provided that the following conditions
   37  * are met:
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  * 4. Neither the name of the University nor the names of its contributors
   44  *    may be used to endorse or promote products derived from this software
   45  *    without specific prior written permission.
   46  *
   47  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   57  * SUCH DAMAGE.
   58  *
   59  *      @(#)raw_ip.c    8.2 (Berkeley) 1/4/94
   60  */
   61 
   62 #include <sys/cdefs.h>
   63 __FBSDID("$FreeBSD: stable/11/sys/netinet6/raw_ip6.c 347688 2019-05-16 11:20:02Z tuexen $");
   64 
   65 #include "opt_ipsec.h"
   66 #include "opt_inet6.h"
   67 
   68 #include <sys/param.h>
   69 #include <sys/errno.h>
   70 #include <sys/jail.h>
   71 #include <sys/kernel.h>
   72 #include <sys/lock.h>
   73 #include <sys/malloc.h>
   74 #include <sys/mbuf.h>
   75 #include <sys/priv.h>
   76 #include <sys/proc.h>
   77 #include <sys/protosw.h>
   78 #include <sys/signalvar.h>
   79 #include <sys/socket.h>
   80 #include <sys/socketvar.h>
   81 #include <sys/sx.h>
   82 #include <sys/syslog.h>
   83 
   84 #include <net/if.h>
   85 #include <net/if_var.h>
   86 #include <net/if_types.h>
   87 #include <net/route.h>
   88 #include <net/vnet.h>
   89 
   90 #include <netinet/in.h>
   91 #include <netinet/in_var.h>
   92 #include <netinet/in_systm.h>
   93 #include <netinet/in_pcb.h>
   94 
   95 #include <netinet/icmp6.h>
   96 #include <netinet/ip6.h>
   97 #include <netinet/ip_var.h>
   98 #include <netinet6/ip6protosw.h>
   99 #include <netinet6/ip6_mroute.h>
  100 #include <netinet6/in6_pcb.h>
  101 #include <netinet6/ip6_var.h>
  102 #include <netinet6/nd6.h>
  103 #include <netinet6/raw_ip6.h>
  104 #include <netinet6/scope6_var.h>
  105 #include <netinet6/send.h>
  106 
  107 #include <netipsec/ipsec_support.h>
  108 
  109 #include <machine/stdarg.h>
  110 
  111 #define satosin6(sa)    ((struct sockaddr_in6 *)(sa))
  112 #define ifatoia6(ifa)   ((struct in6_ifaddr *)(ifa))
  113 
  114 /*
  115  * Raw interface to IP6 protocol.
  116  */
  117 
  118 VNET_DECLARE(struct inpcbhead, ripcb);
  119 VNET_DECLARE(struct inpcbinfo, ripcbinfo);
  120 #define V_ripcb                         VNET(ripcb)
  121 #define V_ripcbinfo                     VNET(ripcbinfo)
  122 
  123 extern u_long   rip_sendspace;
  124 extern u_long   rip_recvspace;
  125 
  126 VNET_PCPUSTAT_DEFINE(struct rip6stat, rip6stat);
  127 VNET_PCPUSTAT_SYSINIT(rip6stat);
  128 
  129 #ifdef VIMAGE
  130 VNET_PCPUSTAT_SYSUNINIT(rip6stat);
  131 #endif /* VIMAGE */
  132 
  133 /*
  134  * Hooks for multicast routing. They all default to NULL, so leave them not
  135  * initialized and rely on BSS being set to 0.
  136  */
  137 
  138 /*
  139  * The socket used to communicate with the multicast routing daemon.
  140  */
  141 VNET_DEFINE(struct socket *, ip6_mrouter);
  142 
  143 /*
  144  * The various mrouter functions.
  145  */
  146 int (*ip6_mrouter_set)(struct socket *, struct sockopt *);
  147 int (*ip6_mrouter_get)(struct socket *, struct sockopt *);
  148 int (*ip6_mrouter_done)(void);
  149 int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *);
  150 int (*mrt6_ioctl)(u_long, caddr_t);
  151 
  152 /*
  153  * Setup generic address and protocol structures for raw_input routine, then
  154  * pass them along with mbuf chain.
  155  */
  156 int
  157 rip6_input(struct mbuf **mp, int *offp, int proto)
  158 {
  159         struct ifnet *ifp;
  160         struct mbuf *m = *mp;
  161         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
  162         struct inpcb *in6p;
  163         struct inpcb *last = NULL;
  164         struct mbuf *opts = NULL;
  165         struct sockaddr_in6 fromsa;
  166 
  167         RIP6STAT_INC(rip6s_ipackets);
  168 
  169         init_sin6(&fromsa, m); /* general init */
  170 
  171         ifp = m->m_pkthdr.rcvif;
  172 
  173         INP_INFO_RLOCK(&V_ripcbinfo);
  174         LIST_FOREACH(in6p, &V_ripcb, inp_list) {
  175                 /* XXX inp locking */
  176                 if ((in6p->inp_vflag & INP_IPV6) == 0)
  177                         continue;
  178                 if (in6p->inp_ip_p &&
  179                     in6p->inp_ip_p != proto)
  180                         continue;
  181                 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
  182                     !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
  183                         continue;
  184                 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
  185                     !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
  186                         continue;
  187                 if (jailed_without_vnet(in6p->inp_cred)) {
  188                         /*
  189                          * Allow raw socket in jail to receive multicast;
  190                          * assume process had PRIV_NETINET_RAW at attach,
  191                          * and fall through into normal filter path if so.
  192                          */
  193                         if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
  194                             prison_check_ip6(in6p->inp_cred,
  195                             &ip6->ip6_dst) != 0)
  196                                 continue;
  197                 }
  198                 INP_RLOCK(in6p);
  199                 if (in6p->in6p_cksum != -1) {
  200                         RIP6STAT_INC(rip6s_isum);
  201                         if (m->m_pkthdr.len - (*offp + in6p->in6p_cksum) < 2 ||
  202                             in6_cksum(m, proto, *offp,
  203                             m->m_pkthdr.len - *offp)) {
  204                                 INP_RUNLOCK(in6p);
  205                                 RIP6STAT_INC(rip6s_badsum);
  206                                 continue;
  207                         }
  208                 }
  209                 /*
  210                  * If this raw socket has multicast state, and we
  211                  * have received a multicast, check if this socket
  212                  * should receive it, as multicast filtering is now
  213                  * the responsibility of the transport layer.
  214                  */
  215                 if (in6p->in6p_moptions &&
  216                     IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
  217                         /*
  218                          * If the incoming datagram is for MLD, allow it
  219                          * through unconditionally to the raw socket.
  220                          *
  221                          * Use the M_RTALERT_MLD flag to check for MLD
  222                          * traffic without having to inspect the mbuf chain
  223                          * more deeply, as all MLDv1/v2 host messages MUST
  224                          * contain the Router Alert option.
  225                          *
  226                          * In the case of MLDv1, we may not have explicitly
  227                          * joined the group, and may have set IFF_ALLMULTI
  228                          * on the interface. im6o_mc_filter() may discard
  229                          * control traffic we actually need to see.
  230                          *
  231                          * Userland multicast routing daemons should continue
  232                          * filter the control traffic appropriately.
  233                          */
  234                         int blocked;
  235 
  236                         blocked = MCAST_PASS;
  237                         if ((m->m_flags & M_RTALERT_MLD) == 0) {
  238                                 struct sockaddr_in6 mcaddr;
  239 
  240                                 bzero(&mcaddr, sizeof(struct sockaddr_in6));
  241                                 mcaddr.sin6_len = sizeof(struct sockaddr_in6);
  242                                 mcaddr.sin6_family = AF_INET6;
  243                                 mcaddr.sin6_addr = ip6->ip6_dst;
  244 
  245                                 blocked = im6o_mc_filter(in6p->in6p_moptions,
  246                                     ifp,
  247                                     (struct sockaddr *)&mcaddr,
  248                                     (struct sockaddr *)&fromsa);
  249                         }
  250                         if (blocked != MCAST_PASS) {
  251                                 IP6STAT_INC(ip6s_notmember);
  252                                 INP_RUNLOCK(in6p);
  253                                 continue;
  254                         }
  255                 }
  256                 if (last != NULL) {
  257                         struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
  258 
  259 #if defined(IPSEC) || defined(IPSEC_SUPPORT)
  260                         /*
  261                          * Check AH/ESP integrity.
  262                          */
  263                         if (IPSEC_ENABLED(ipv6)) {
  264                                 if (n != NULL &&
  265                                     IPSEC_CHECK_POLICY(ipv6, n, last) != 0) {
  266                                         m_freem(n);
  267                                         /* Do not inject data into pcb. */
  268                                         n = NULL;
  269                                 }
  270                         }
  271 #endif /* IPSEC */
  272                         if (n) {
  273                                 if (last->inp_flags & INP_CONTROLOPTS ||
  274                                     last->inp_socket->so_options & SO_TIMESTAMP)
  275                                         ip6_savecontrol(last, n, &opts);
  276                                 /* strip intermediate headers */
  277                                 m_adj(n, *offp);
  278                                 if (sbappendaddr(&last->inp_socket->so_rcv,
  279                                                 (struct sockaddr *)&fromsa,
  280                                                  n, opts) == 0) {
  281                                         m_freem(n);
  282                                         if (opts)
  283                                                 m_freem(opts);
  284                                         RIP6STAT_INC(rip6s_fullsock);
  285                                 } else
  286                                         sorwakeup(last->inp_socket);
  287                                 opts = NULL;
  288                         }
  289                         INP_RUNLOCK(last);
  290                 }
  291                 last = in6p;
  292         }
  293         INP_INFO_RUNLOCK(&V_ripcbinfo);
  294 #if defined(IPSEC) || defined(IPSEC_SUPPORT)
  295         /*
  296          * Check AH/ESP integrity.
  297          */
  298         if (IPSEC_ENABLED(ipv6) && last != NULL &&
  299             IPSEC_CHECK_POLICY(ipv6, m, last) != 0) {
  300                 m_freem(m);
  301                 IP6STAT_DEC(ip6s_delivered);
  302                 /* Do not inject data into pcb. */
  303                 INP_RUNLOCK(last);
  304         } else
  305 #endif /* IPSEC */
  306         if (last != NULL) {
  307                 if (last->inp_flags & INP_CONTROLOPTS ||
  308                     last->inp_socket->so_options & SO_TIMESTAMP)
  309                         ip6_savecontrol(last, m, &opts);
  310                 /* Strip intermediate headers. */
  311                 m_adj(m, *offp);
  312                 if (sbappendaddr(&last->inp_socket->so_rcv,
  313                     (struct sockaddr *)&fromsa, m, opts) == 0) {
  314                         m_freem(m);
  315                         if (opts)
  316                                 m_freem(opts);
  317                         RIP6STAT_INC(rip6s_fullsock);
  318                 } else
  319                         sorwakeup(last->inp_socket);
  320                 INP_RUNLOCK(last);
  321         } else {
  322                 RIP6STAT_INC(rip6s_nosock);
  323                 if (m->m_flags & M_MCAST)
  324                         RIP6STAT_INC(rip6s_nosockmcast);
  325                 if (proto == IPPROTO_NONE)
  326                         m_freem(m);
  327                 else
  328                         icmp6_error(m, ICMP6_PARAM_PROB,
  329                             ICMP6_PARAMPROB_NEXTHEADER,
  330                             ip6_get_prevhdr(m, *offp));
  331                 IP6STAT_DEC(ip6s_delivered);
  332         }
  333         return (IPPROTO_DONE);
  334 }
  335 
  336 void
  337 rip6_ctlinput(int cmd, struct sockaddr *sa, void *d)
  338 {
  339         struct ip6_hdr *ip6;
  340         struct mbuf *m;
  341         int off = 0;
  342         struct ip6ctlparam *ip6cp = NULL;
  343         const struct sockaddr_in6 *sa6_src = NULL;
  344         void *cmdarg;
  345         struct inpcb *(*notify)(struct inpcb *, int) = in6_rtchange;
  346 
  347         if (sa->sa_family != AF_INET6 ||
  348             sa->sa_len != sizeof(struct sockaddr_in6))
  349                 return;
  350 
  351         if ((unsigned)cmd >= PRC_NCMDS)
  352                 return;
  353         if (PRC_IS_REDIRECT(cmd))
  354                 notify = in6_rtchange, d = NULL;
  355         else if (cmd == PRC_HOSTDEAD)
  356                 d = NULL;
  357         else if (inet6ctlerrmap[cmd] == 0)
  358                 return;
  359 
  360         /*
  361          * If the parameter is from icmp6, decode it.
  362          */
  363         if (d != NULL) {
  364                 ip6cp = (struct ip6ctlparam *)d;
  365                 m = ip6cp->ip6c_m;
  366                 ip6 = ip6cp->ip6c_ip6;
  367                 off = ip6cp->ip6c_off;
  368                 cmdarg = ip6cp->ip6c_cmdarg;
  369                 sa6_src = ip6cp->ip6c_src;
  370         } else {
  371                 m = NULL;
  372                 ip6 = NULL;
  373                 cmdarg = NULL;
  374                 sa6_src = &sa6_any;
  375         }
  376 
  377         (void) in6_pcbnotify(&V_ripcbinfo, sa, 0,
  378             (const struct sockaddr *)sa6_src, 0, cmd, cmdarg, notify);
  379 }
  380 
  381 /*
  382  * Generate IPv6 header and pass packet to ip6_output.  Tack on options user
  383  * may have setup with control call.
  384  */
  385 int
  386 rip6_output(struct mbuf *m, struct socket *so, ...)
  387 {
  388         struct mbuf *control;
  389         struct m_tag *mtag;
  390         struct sockaddr_in6 *dstsock;
  391         struct in6_addr *dst;
  392         struct ip6_hdr *ip6;
  393         struct inpcb *in6p;
  394         u_int   plen = m->m_pkthdr.len;
  395         int error = 0;
  396         struct ip6_pktopts opt, *optp;
  397         struct ifnet *oifp = NULL;
  398         int type = 0, code = 0;         /* for ICMPv6 output statistics only */
  399         int scope_ambiguous = 0;
  400         int use_defzone = 0;
  401         int hlim = 0;
  402         struct in6_addr in6a;
  403         va_list ap;
  404 
  405         va_start(ap, so);
  406         dstsock = va_arg(ap, struct sockaddr_in6 *);
  407         control = va_arg(ap, struct mbuf *);
  408         va_end(ap);
  409 
  410         in6p = sotoinpcb(so);
  411         INP_WLOCK(in6p);
  412 
  413         dst = &dstsock->sin6_addr;
  414         if (control != NULL) {
  415                 if ((error = ip6_setpktopts(control, &opt,
  416                     in6p->in6p_outputopts, so->so_cred,
  417                     so->so_proto->pr_protocol)) != 0) {
  418                         goto bad;
  419                 }
  420                 optp = &opt;
  421         } else
  422                 optp = in6p->in6p_outputopts;
  423 
  424         /*
  425          * Check and convert scope zone ID into internal form.
  426          *
  427          * XXX: we may still need to determine the zone later.
  428          */
  429         if (!(so->so_state & SS_ISCONNECTED)) {
  430                 if (!optp || !optp->ip6po_pktinfo ||
  431                     !optp->ip6po_pktinfo->ipi6_ifindex)
  432                         use_defzone = V_ip6_use_defzone;
  433                 if (dstsock->sin6_scope_id == 0 && !use_defzone)
  434                         scope_ambiguous = 1;
  435                 if ((error = sa6_embedscope(dstsock, use_defzone)) != 0)
  436                         goto bad;
  437         }
  438 
  439         /*
  440          * For an ICMPv6 packet, we should know its type and code to update
  441          * statistics.
  442          */
  443         if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
  444                 struct icmp6_hdr *icmp6;
  445                 if (m->m_len < sizeof(struct icmp6_hdr) &&
  446                     (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
  447                         error = ENOBUFS;
  448                         goto bad;
  449                 }
  450                 icmp6 = mtod(m, struct icmp6_hdr *);
  451                 type = icmp6->icmp6_type;
  452                 code = icmp6->icmp6_code;
  453         }
  454 
  455         M_PREPEND(m, sizeof(*ip6), M_NOWAIT);
  456         if (m == NULL) {
  457                 error = ENOBUFS;
  458                 goto bad;
  459         }
  460         ip6 = mtod(m, struct ip6_hdr *);
  461 
  462         /*
  463          * Source address selection.
  464          */
  465         error = in6_selectsrc_socket(dstsock, optp, in6p, so->so_cred,
  466             scope_ambiguous, &in6a, &hlim);
  467 
  468         if (error)
  469                 goto bad;
  470         error = prison_check_ip6(in6p->inp_cred, &in6a);
  471         if (error != 0)
  472                 goto bad;
  473         ip6->ip6_src = in6a;
  474 
  475         ip6->ip6_dst = dstsock->sin6_addr;
  476 
  477         /*
  478          * Fill in the rest of the IPv6 header fields.
  479          */
  480         ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
  481             (in6p->inp_flow & IPV6_FLOWINFO_MASK);
  482         ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
  483             (IPV6_VERSION & IPV6_VERSION_MASK);
  484 
  485         /*
  486          * ip6_plen will be filled in ip6_output, so not fill it here.
  487          */
  488         ip6->ip6_nxt = in6p->inp_ip_p;
  489         ip6->ip6_hlim = hlim;
  490 
  491         if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
  492             in6p->in6p_cksum != -1) {
  493                 struct mbuf *n;
  494                 int off;
  495                 u_int16_t *p;
  496 
  497                 /* Compute checksum. */
  498                 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
  499                         off = offsetof(struct icmp6_hdr, icmp6_cksum);
  500                 else
  501                         off = in6p->in6p_cksum;
  502                 if (plen < off + 2) {
  503                         error = EINVAL;
  504                         goto bad;
  505                 }
  506                 off += sizeof(struct ip6_hdr);
  507 
  508                 n = m;
  509                 while (n && n->m_len <= off) {
  510                         off -= n->m_len;
  511                         n = n->m_next;
  512                 }
  513                 if (!n)
  514                         goto bad;
  515                 p = (u_int16_t *)(mtod(n, caddr_t) + off);
  516                 *p = 0;
  517                 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
  518         }
  519 
  520         /*
  521          * Send RA/RS messages to user land for protection, before sending
  522          * them to rtadvd/rtsol.
  523          */
  524         if ((send_sendso_input_hook != NULL) &&
  525             so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
  526                 switch (type) {
  527                 case ND_ROUTER_ADVERT:
  528                 case ND_ROUTER_SOLICIT:
  529                         mtag = m_tag_get(PACKET_TAG_ND_OUTGOING,
  530                                 sizeof(unsigned short), M_NOWAIT);
  531                         if (mtag == NULL)
  532                                 goto bad;
  533                         m_tag_prepend(m, mtag);
  534                 }
  535         }
  536 
  537         error = ip6_output(m, optp, NULL, 0, in6p->in6p_moptions, &oifp, in6p);
  538         if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
  539                 if (oifp)
  540                         icmp6_ifoutstat_inc(oifp, type, code);
  541                 ICMP6STAT_INC(icp6s_outhist[type]);
  542         } else
  543                 RIP6STAT_INC(rip6s_opackets);
  544 
  545         goto freectl;
  546 
  547  bad:
  548         if (m)
  549                 m_freem(m);
  550 
  551  freectl:
  552         if (control != NULL) {
  553                 ip6_clearpktopts(&opt, -1);
  554                 m_freem(control);
  555         }
  556         INP_WUNLOCK(in6p);
  557         return (error);
  558 }
  559 
  560 /*
  561  * Raw IPv6 socket option processing.
  562  */
  563 int
  564 rip6_ctloutput(struct socket *so, struct sockopt *sopt)
  565 {
  566         struct inpcb *inp;
  567         int error;
  568 
  569         if (sopt->sopt_level == IPPROTO_ICMPV6)
  570                 /*
  571                  * XXX: is it better to call icmp6_ctloutput() directly
  572                  * from protosw?
  573                  */
  574                 return (icmp6_ctloutput(so, sopt));
  575         else if (sopt->sopt_level != IPPROTO_IPV6) {
  576                 if (sopt->sopt_level == SOL_SOCKET &&
  577                     sopt->sopt_name == SO_SETFIB) {
  578                         inp = sotoinpcb(so);
  579                         INP_WLOCK(inp);
  580                         inp->inp_inc.inc_fibnum = so->so_fibnum;
  581                         INP_WUNLOCK(inp);
  582                         return (0);
  583                 }
  584                 return (EINVAL);
  585         }
  586 
  587         error = 0;
  588 
  589         switch (sopt->sopt_dir) {
  590         case SOPT_GET:
  591                 switch (sopt->sopt_name) {
  592                 case MRT6_INIT:
  593                 case MRT6_DONE:
  594                 case MRT6_ADD_MIF:
  595                 case MRT6_DEL_MIF:
  596                 case MRT6_ADD_MFC:
  597                 case MRT6_DEL_MFC:
  598                 case MRT6_PIM:
  599                         error = ip6_mrouter_get ?  ip6_mrouter_get(so, sopt) :
  600                             EOPNOTSUPP;
  601                         break;
  602                 case IPV6_CHECKSUM:
  603                         error = ip6_raw_ctloutput(so, sopt);
  604                         break;
  605                 default:
  606                         error = ip6_ctloutput(so, sopt);
  607                         break;
  608                 }
  609                 break;
  610 
  611         case SOPT_SET:
  612                 switch (sopt->sopt_name) {
  613                 case MRT6_INIT:
  614                 case MRT6_DONE:
  615                 case MRT6_ADD_MIF:
  616                 case MRT6_DEL_MIF:
  617                 case MRT6_ADD_MFC:
  618                 case MRT6_DEL_MFC:
  619                 case MRT6_PIM:
  620                         error = ip6_mrouter_set ?  ip6_mrouter_set(so, sopt) :
  621                             EOPNOTSUPP;
  622                         break;
  623                 case IPV6_CHECKSUM:
  624                         error = ip6_raw_ctloutput(so, sopt);
  625                         break;
  626                 default:
  627                         error = ip6_ctloutput(so, sopt);
  628                         break;
  629                 }
  630                 break;
  631         }
  632 
  633         return (error);
  634 }
  635 
  636 static int
  637 rip6_attach(struct socket *so, int proto, struct thread *td)
  638 {
  639         struct inpcb *inp;
  640         struct icmp6_filter *filter;
  641         int error;
  642 
  643         inp = sotoinpcb(so);
  644         KASSERT(inp == NULL, ("rip6_attach: inp != NULL"));
  645 
  646         error = priv_check(td, PRIV_NETINET_RAW);
  647         if (error)
  648                 return (error);
  649         error = soreserve(so, rip_sendspace, rip_recvspace);
  650         if (error)
  651                 return (error);
  652         filter = malloc(sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
  653         if (filter == NULL)
  654                 return (ENOMEM);
  655         INP_INFO_WLOCK(&V_ripcbinfo);
  656         error = in_pcballoc(so, &V_ripcbinfo);
  657         if (error) {
  658                 INP_INFO_WUNLOCK(&V_ripcbinfo);
  659                 free(filter, M_PCB);
  660                 return (error);
  661         }
  662         inp = (struct inpcb *)so->so_pcb;
  663         INP_INFO_WUNLOCK(&V_ripcbinfo);
  664         inp->inp_vflag |= INP_IPV6;
  665         inp->inp_ip_p = (long)proto;
  666         inp->in6p_hops = -1;    /* use kernel default */
  667         inp->in6p_cksum = -1;
  668         inp->in6p_icmp6filt = filter;
  669         ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
  670         INP_WUNLOCK(inp);
  671         return (0);
  672 }
  673 
  674 static void
  675 rip6_detach(struct socket *so)
  676 {
  677         struct inpcb *inp;
  678 
  679         inp = sotoinpcb(so);
  680         KASSERT(inp != NULL, ("rip6_detach: inp == NULL"));
  681 
  682         if (so == V_ip6_mrouter && ip6_mrouter_done)
  683                 ip6_mrouter_done();
  684         /* xxx: RSVP */
  685         INP_INFO_WLOCK(&V_ripcbinfo);
  686         INP_WLOCK(inp);
  687         free(inp->in6p_icmp6filt, M_PCB);
  688         in_pcbdetach(inp);
  689         in_pcbfree(inp);
  690         INP_INFO_WUNLOCK(&V_ripcbinfo);
  691 }
  692 
  693 /* XXXRW: This can't ever be called. */
  694 static void
  695 rip6_abort(struct socket *so)
  696 {
  697         struct inpcb *inp;
  698 
  699         inp = sotoinpcb(so);
  700         KASSERT(inp != NULL, ("rip6_abort: inp == NULL"));
  701 
  702         soisdisconnected(so);
  703 }
  704 
  705 static void
  706 rip6_close(struct socket *so)
  707 {
  708         struct inpcb *inp;
  709 
  710         inp = sotoinpcb(so);
  711         KASSERT(inp != NULL, ("rip6_close: inp == NULL"));
  712 
  713         soisdisconnected(so);
  714 }
  715 
  716 static int
  717 rip6_disconnect(struct socket *so)
  718 {
  719         struct inpcb *inp;
  720 
  721         inp = sotoinpcb(so);
  722         KASSERT(inp != NULL, ("rip6_disconnect: inp == NULL"));
  723 
  724         if ((so->so_state & SS_ISCONNECTED) == 0)
  725                 return (ENOTCONN);
  726         inp->in6p_faddr = in6addr_any;
  727         rip6_abort(so);
  728         return (0);
  729 }
  730 
  731 static int
  732 rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  733 {
  734         struct inpcb *inp;
  735         struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
  736         struct ifaddr *ifa = NULL;
  737         int error = 0;
  738 
  739         inp = sotoinpcb(so);
  740         KASSERT(inp != NULL, ("rip6_bind: inp == NULL"));
  741 
  742         if (nam->sa_len != sizeof(*addr))
  743                 return (EINVAL);
  744         if ((error = prison_check_ip6(td->td_ucred, &addr->sin6_addr)) != 0)
  745                 return (error);
  746         if (TAILQ_EMPTY(&V_ifnet) || addr->sin6_family != AF_INET6)
  747                 return (EADDRNOTAVAIL);
  748         if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
  749                 return (error);
  750 
  751         if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
  752             (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL)
  753                 return (EADDRNOTAVAIL);
  754         if (ifa != NULL &&
  755             ((struct in6_ifaddr *)ifa)->ia6_flags &
  756             (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
  757              IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
  758                 ifa_free(ifa);
  759                 return (EADDRNOTAVAIL);
  760         }
  761         if (ifa != NULL)
  762                 ifa_free(ifa);
  763         INP_INFO_WLOCK(&V_ripcbinfo);
  764         INP_WLOCK(inp);
  765         inp->in6p_laddr = addr->sin6_addr;
  766         INP_WUNLOCK(inp);
  767         INP_INFO_WUNLOCK(&V_ripcbinfo);
  768         return (0);
  769 }
  770 
  771 static int
  772 rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  773 {
  774         struct inpcb *inp;
  775         struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
  776         struct in6_addr in6a;
  777         int error = 0, scope_ambiguous = 0;
  778 
  779         inp = sotoinpcb(so);
  780         KASSERT(inp != NULL, ("rip6_connect: inp == NULL"));
  781 
  782         if (nam->sa_len != sizeof(*addr))
  783                 return (EINVAL);
  784         if (TAILQ_EMPTY(&V_ifnet))
  785                 return (EADDRNOTAVAIL);
  786         if (addr->sin6_family != AF_INET6)
  787                 return (EAFNOSUPPORT);
  788 
  789         /*
  790          * Application should provide a proper zone ID or the use of default
  791          * zone IDs should be enabled.  Unfortunately, some applications do
  792          * not behave as it should, so we need a workaround.  Even if an
  793          * appropriate ID is not determined, we'll see if we can determine
  794          * the outgoing interface.  If we can, determine the zone ID based on
  795          * the interface below.
  796          */
  797         if (addr->sin6_scope_id == 0 && !V_ip6_use_defzone)
  798                 scope_ambiguous = 1;
  799         if ((error = sa6_embedscope(addr, V_ip6_use_defzone)) != 0)
  800                 return (error);
  801 
  802         INP_INFO_WLOCK(&V_ripcbinfo);
  803         INP_WLOCK(inp);
  804         /* Source address selection. XXX: need pcblookup? */
  805         error = in6_selectsrc_socket(addr, inp->in6p_outputopts,
  806             inp, so->so_cred, scope_ambiguous, &in6a, NULL);
  807         if (error) {
  808                 INP_WUNLOCK(inp);
  809                 INP_INFO_WUNLOCK(&V_ripcbinfo);
  810                 return (error);
  811         }
  812 
  813         inp->in6p_faddr = addr->sin6_addr;
  814         inp->in6p_laddr = in6a;
  815         soisconnected(so);
  816         INP_WUNLOCK(inp);
  817         INP_INFO_WUNLOCK(&V_ripcbinfo);
  818         return (0);
  819 }
  820 
  821 static int
  822 rip6_shutdown(struct socket *so)
  823 {
  824         struct inpcb *inp;
  825 
  826         inp = sotoinpcb(so);
  827         KASSERT(inp != NULL, ("rip6_shutdown: inp == NULL"));
  828 
  829         INP_WLOCK(inp);
  830         socantsendmore(so);
  831         INP_WUNLOCK(inp);
  832         return (0);
  833 }
  834 
  835 static int
  836 rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
  837     struct mbuf *control, struct thread *td)
  838 {
  839         struct inpcb *inp;
  840         struct sockaddr_in6 tmp;
  841         struct sockaddr_in6 *dst;
  842         int ret;
  843 
  844         inp = sotoinpcb(so);
  845         KASSERT(inp != NULL, ("rip6_send: inp == NULL"));
  846 
  847         /* Always copy sockaddr to avoid overwrites. */
  848         /* Unlocked read. */
  849         if (so->so_state & SS_ISCONNECTED) {
  850                 if (nam) {
  851                         m_freem(m);
  852                         return (EISCONN);
  853                 }
  854                 /* XXX */
  855                 bzero(&tmp, sizeof(tmp));
  856                 tmp.sin6_family = AF_INET6;
  857                 tmp.sin6_len = sizeof(struct sockaddr_in6);
  858                 INP_RLOCK(inp);
  859                 bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
  860                     sizeof(struct in6_addr));
  861                 INP_RUNLOCK(inp);
  862                 dst = &tmp;
  863         } else {
  864                 if (nam == NULL) {
  865                         m_freem(m);
  866                         return (ENOTCONN);
  867                 }
  868                 if (nam->sa_len != sizeof(struct sockaddr_in6)) {
  869                         m_freem(m);
  870                         return (EINVAL);
  871                 }
  872                 tmp = *(struct sockaddr_in6 *)nam;
  873                 dst = &tmp;
  874 
  875                 if (dst->sin6_family == AF_UNSPEC) {
  876                         /*
  877                          * XXX: we allow this case for backward
  878                          * compatibility to buggy applications that
  879                          * rely on old (and wrong) kernel behavior.
  880                          */
  881                         log(LOG_INFO, "rip6 SEND: address family is "
  882                             "unspec. Assume AF_INET6\n");
  883                         dst->sin6_family = AF_INET6;
  884                 } else if (dst->sin6_family != AF_INET6) {
  885                         m_freem(m);
  886                         return(EAFNOSUPPORT);
  887                 }
  888         }
  889         ret = rip6_output(m, so, dst, control);
  890         return (ret);
  891 }
  892 
  893 struct pr_usrreqs rip6_usrreqs = {
  894         .pru_abort =            rip6_abort,
  895         .pru_attach =           rip6_attach,
  896         .pru_bind =             rip6_bind,
  897         .pru_connect =          rip6_connect,
  898         .pru_control =          in6_control,
  899         .pru_detach =           rip6_detach,
  900         .pru_disconnect =       rip6_disconnect,
  901         .pru_peeraddr =         in6_getpeeraddr,
  902         .pru_send =             rip6_send,
  903         .pru_shutdown =         rip6_shutdown,
  904         .pru_sockaddr =         in6_getsockaddr,
  905         .pru_close =            rip6_close,
  906 };

Cache object: 635e507d47f7d7d4a693ea4186f0d2c0


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