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.182 2022/11/04 09:01:53 ozaki-r 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.182 2022/11/04 09:01:53 ozaki-r Exp $");
   66 
   67 #ifdef _KERNEL_OPT
   68 #include "opt_ipsec.h"
   69 #include "opt_net_mpsafe.h"
   70 #endif
   71 
   72 #include <sys/param.h>
   73 #include <sys/sysctl.h>
   74 #include <sys/mbuf.h>
   75 #include <sys/socket.h>
   76 #include <sys/protosw.h>
   77 #include <sys/socketvar.h>
   78 #include <sys/systm.h>
   79 #include <sys/proc.h>
   80 #include <sys/kauth.h>
   81 #include <sys/kmem.h>
   82 
   83 #include <net/if.h>
   84 #include <net/if_types.h>
   85 #include <net/net_stats.h>
   86 
   87 #include <netinet/in.h>
   88 #include <netinet/in_var.h>
   89 #include <netinet/ip6.h>
   90 #include <netinet6/ip6_var.h>
   91 #include <netinet6/ip6_private.h>
   92 #include <netinet6/ip6_mroute.h>
   93 #include <netinet/icmp6.h>
   94 #include <netinet6/icmp6_private.h>
   95 #include <netinet6/in6_pcb.h>
   96 #include <netinet6/ip6protosw.h>
   97 #include <netinet6/scope6_var.h>
   98 #include <netinet6/raw_ip6.h>
   99 
  100 #ifdef IPSEC
  101 #include <netipsec/ipsec.h>
  102 #include <netipsec/ipsec6.h>
  103 #endif
  104 
  105 #include "faith.h"
  106 #if defined(NFAITH) && 0 < NFAITH
  107 #include <net/if_faith.h>
  108 #endif
  109 
  110 extern struct inpcbtable rawcbtable;
  111 struct  inpcbtable raw6cbtable;
  112 #define ifatoia6(ifa)   ((struct in6_ifaddr *)(ifa))
  113 
  114 /*
  115  * Raw interface to IP6 protocol.
  116  */
  117 
  118 static percpu_t *rip6stat_percpu;
  119 
  120 #define RIP6_STATINC(x)         _NET_STATINC(rip6stat_percpu, x)
  121 
  122 static void sysctl_net_inet6_raw6_setup(struct sysctllog **);
  123 
  124 /*
  125  * Initialize raw connection block queue.
  126  */
  127 void
  128 rip6_init(void)
  129 {
  130 
  131         sysctl_net_inet6_raw6_setup(NULL);
  132         in6pcb_init(&raw6cbtable, 1, 1);
  133 
  134         rip6stat_percpu = percpu_alloc(sizeof(uint64_t) * RIP6_NSTATS);
  135 }
  136 
  137 static void
  138 rip6_sbappendaddr(struct inpcb *last, struct ip6_hdr *ip6,
  139     const struct sockaddr *sa, int hlen, struct mbuf *n)
  140 {
  141         struct mbuf *opts = NULL;
  142 
  143         if (last->inp_flags & IN6P_CONTROLOPTS)
  144                 ip6_savecontrol(last, &opts, ip6, n);
  145 
  146         m_adj(n, hlen);
  147 
  148         if (sbappendaddr(&last->inp_socket->so_rcv, sa, n, opts) == 0) {
  149                 soroverflow(last->inp_socket);
  150                 m_freem(n);
  151                 if (opts)
  152                         m_freem(opts);
  153                 RIP6_STATINC(RIP6_STAT_FULLSOCK);
  154         } else {
  155                 sorwakeup(last->inp_socket);
  156         }
  157 }
  158 
  159 /*
  160  * Setup generic address and protocol structures
  161  * for raw_input routine, then pass them along with
  162  * mbuf chain.
  163  */
  164 int
  165 rip6_input(struct mbuf **mp, int *offp, int proto)
  166 {
  167         struct mbuf *m = *mp;
  168         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
  169         struct inpcb *inp;
  170         struct inpcb *last = NULL;
  171         struct sockaddr_in6 rip6src;
  172         struct mbuf *n;
  173 
  174         RIP6_STATINC(RIP6_STAT_IPACKETS);
  175 
  176 #if defined(NFAITH) && 0 < NFAITH
  177         if (faithprefix(&ip6->ip6_dst)) {
  178                 /* send icmp6 host unreach? */
  179                 m_freem(m);
  180                 return IPPROTO_DONE;
  181         }
  182 #endif
  183 
  184         sockaddr_in6_init(&rip6src, &ip6->ip6_src, 0, 0, 0);
  185         if (sa6_recoverscope(&rip6src) != 0) {
  186                 /* XXX: should be impossible. */
  187                 m_freem(m);
  188                 return IPPROTO_DONE;
  189         }
  190 
  191         TAILQ_FOREACH(inp, &raw6cbtable.inpt_queue, inp_queue) {
  192                 if (inp->inp_af != AF_INET6)
  193                         continue;
  194                 if (in6p_ip6(inp).ip6_nxt &&
  195                     in6p_ip6(inp).ip6_nxt != proto)
  196                         continue;
  197                 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_laddr(inp)) &&
  198                     !IN6_ARE_ADDR_EQUAL(&in6p_laddr(inp), &ip6->ip6_dst))
  199                         continue;
  200                 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_faddr(inp)) &&
  201                     !IN6_ARE_ADDR_EQUAL(&in6p_faddr(inp), &ip6->ip6_src))
  202                         continue;
  203                 if (in6p_cksum(inp) != -1) {
  204                         RIP6_STATINC(RIP6_STAT_ISUM);
  205                         if (in6_cksum(m, proto, *offp,
  206                             m->m_pkthdr.len - *offp)) {
  207                                 RIP6_STATINC(RIP6_STAT_BADSUM);
  208                                 continue;
  209                         }
  210                 }
  211 
  212                 if (last == NULL) {
  213                         ;
  214                 }
  215 #ifdef IPSEC
  216                 else if (ipsec_used && ipsec_in_reject(m, last)) {
  217                         /* do not inject data into pcb */
  218                 }
  219 #endif
  220                 else if ((n = m_copypacket(m, M_DONTWAIT)) != NULL) {
  221                         rip6_sbappendaddr(last, ip6, sin6tosa(&rip6src),
  222                             *offp, n);
  223                 }
  224 
  225                 last = inp;
  226         }
  227 
  228 #ifdef IPSEC
  229         if (ipsec_used && last && ipsec_in_reject(m, last)) {
  230                 m_freem(m);
  231                 IP6_STATDEC(IP6_STAT_DELIVERED);
  232                 /* do not inject data into pcb */
  233         } else
  234 #endif
  235         if (last != NULL) {
  236                 rip6_sbappendaddr(last, ip6, sin6tosa(&rip6src), *offp, m);
  237         } else {
  238                 RIP6_STATINC(RIP6_STAT_NOSOCK);
  239                 if (m->m_flags & M_MCAST)
  240                         RIP6_STATINC(RIP6_STAT_NOSOCKMCAST);
  241                 if (proto == IPPROTO_NONE)
  242                         m_freem(m);
  243                 else {
  244                         int s;
  245                         struct ifnet *rcvif = m_get_rcvif(m, &s);
  246                         const int prvnxt = ip6_get_prevhdr(m, *offp);
  247                         in6_ifstat_inc(rcvif, ifs6_in_protounknown);
  248                         m_put_rcvif(rcvif, &s);
  249                         icmp6_error(m, ICMP6_PARAM_PROB,
  250                             ICMP6_PARAMPROB_NEXTHEADER,
  251                             prvnxt);
  252                 }
  253                 IP6_STATDEC(IP6_STAT_DELIVERED);
  254         }
  255         return IPPROTO_DONE;
  256 }
  257 
  258 void *
  259 rip6_ctlinput(int cmd, const struct sockaddr *sa, void *d)
  260 {
  261         struct ip6_hdr *ip6;
  262         struct ip6ctlparam *ip6cp = NULL;
  263         const struct sockaddr_in6 *sa6_src = NULL;
  264         void *cmdarg;
  265         void (*notify)(struct inpcb *, int) = in6pcb_rtchange;
  266         int nxt;
  267 
  268         if (sa->sa_family != AF_INET6 ||
  269             sa->sa_len != sizeof(struct sockaddr_in6))
  270                 return NULL;
  271 
  272         if ((unsigned)cmd >= PRC_NCMDS)
  273                 return NULL;
  274         if (PRC_IS_REDIRECT(cmd))
  275                 notify = in6pcb_rtchange, d = NULL;
  276         else if (cmd == PRC_HOSTDEAD)
  277                 d = NULL;
  278         else if (cmd == PRC_MSGSIZE)
  279                 ; /* special code is present, see below */
  280         else if (inet6ctlerrmap[cmd] == 0)
  281                 return NULL;
  282 
  283         /* if the parameter is from icmp6, decode it. */
  284         if (d != NULL) {
  285                 ip6cp = (struct ip6ctlparam *)d;
  286                 ip6 = ip6cp->ip6c_ip6;
  287                 cmdarg = ip6cp->ip6c_cmdarg;
  288                 sa6_src = ip6cp->ip6c_src;
  289                 nxt = ip6cp->ip6c_nxt;
  290         } else {
  291                 ip6 = NULL;
  292                 cmdarg = NULL;
  293                 sa6_src = &sa6_any;
  294                 nxt = -1;
  295         }
  296 
  297         if (ip6 && cmd == PRC_MSGSIZE) {
  298                 const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *)sa;
  299                 int valid = 0;
  300                 struct inpcb *inp;
  301 
  302                 /*
  303                  * Check to see if we have a valid raw IPv6 socket
  304                  * corresponding to the address in the ICMPv6 message
  305                  * payload, and the protocol (ip6_nxt) meets the socket.
  306                  * XXX chase extension headers, or pass final nxt value
  307                  * from icmp6_notify_error()
  308                  */
  309                 inp = NULL;
  310                 inp = in6pcb_lookup(&raw6cbtable, &sa6->sin6_addr, 0,
  311                                              (const struct in6_addr *)&sa6_src->sin6_addr, 0, 0, 0);
  312 #if 0
  313                 if (!inp) {
  314                         /*
  315                          * As the use of sendto(2) is fairly popular,
  316                          * we may want to allow non-connected pcb too.
  317                          * But it could be too weak against attacks...
  318                          * We should at least check if the local
  319                          * address (= s) is really ours.
  320                          */
  321                         inp = in6pcb_lookup_bound(&raw6cbtable,
  322                             &sa6->sin6_addr, 0, 0);
  323                 }
  324 #endif
  325 
  326                 if (inp && in6p_ip6(inp).ip6_nxt &&
  327                     in6p_ip6(inp).ip6_nxt == nxt)
  328                         valid++;
  329 
  330                 /*
  331                  * Depending on the value of "valid" and routing table
  332                  * size (mtudisc_{hi,lo}wat), we will:
  333                  * - recalculate the new MTU and create the
  334                  *   corresponding routing entry, or
  335                  * - ignore the MTU change notification.
  336                  */
  337                 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
  338 
  339                 /*
  340                  * regardless of if we called icmp6_mtudisc_update(),
  341                  * we need to call in6pcb_notify(), to notify path MTU
  342                  * change to the userland (RFC3542), because some
  343                  * unconnected sockets may share the same destination
  344                  * and want to know the path MTU.
  345                  */
  346         }
  347 
  348         (void) in6pcb_notify(&raw6cbtable, sa, 0,
  349             sin6tocsa(sa6_src), 0, cmd, cmdarg, notify);
  350         return NULL;
  351 }
  352 
  353 /*
  354  * Generate IPv6 header and pass packet to ip6_output.
  355  * Tack on options user may have setup with control call.
  356  */
  357 int
  358 rip6_output(struct mbuf *m, struct socket * const so,
  359     struct sockaddr_in6 * const dstsock, struct mbuf * const control)
  360 {
  361         struct in6_addr *dst;
  362         struct ip6_hdr *ip6;
  363         struct inpcb *inp;
  364         u_int   plen = m->m_pkthdr.len;
  365         int error = 0;
  366         struct ip6_pktopts opt, *optp = NULL;
  367         struct ifnet *oifp = NULL;
  368         int type, code;         /* for ICMPv6 output statistics only */
  369         int scope_ambiguous = 0;
  370         int bound = curlwp_bind();
  371         struct psref psref;
  372 
  373         inp = sotoinpcb(so);
  374 
  375         dst = &dstsock->sin6_addr;
  376         if (control) {
  377                 if ((error = ip6_setpktopts(control, &opt,
  378                     in6p_outputopts(inp),
  379                     kauth_cred_get(), so->so_proto->pr_protocol)) != 0) {
  380                         goto bad;
  381                 }
  382                 optp = &opt;
  383         } else
  384                 optp = in6p_outputopts(inp);
  385 
  386         /*
  387          * Check and convert scope zone ID into internal form.
  388          * XXX: we may still need to determine the zone later.
  389          */
  390         if (!(so->so_state & SS_ISCONNECTED)) {
  391                 if (dstsock->sin6_scope_id == 0 && !ip6_use_defzone)
  392                         scope_ambiguous = 1;
  393                 if ((error = sa6_embedscope(dstsock, ip6_use_defzone)) != 0)
  394                         goto bad;
  395         }
  396 
  397         /*
  398          * For an ICMPv6 packet, we should know its type and code
  399          * to update statistics.
  400          */
  401         if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
  402                 struct icmp6_hdr *icmp6;
  403                 if (m->m_len < sizeof(struct icmp6_hdr) &&
  404                     (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
  405                         error = ENOBUFS;
  406                         goto bad;
  407                 }
  408                 icmp6 = mtod(m, struct icmp6_hdr *);
  409                 type = icmp6->icmp6_type;
  410                 code = icmp6->icmp6_code;
  411         } else {
  412                 type = 0;
  413                 code = 0;
  414         }
  415 
  416         M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
  417         if (!m) {
  418                 error = ENOBUFS;
  419                 goto bad;
  420         }
  421         ip6 = mtod(m, struct ip6_hdr *);
  422 
  423         /*
  424          * Next header might not be ICMP6 but use its pseudo header anyway.
  425          */
  426         ip6->ip6_dst = *dst;
  427 
  428         /*
  429          * Source address selection.
  430          */
  431         error = in6_selectsrc(dstsock, optp, in6p_moptions(inp),
  432             &inp->inp_route, &in6p_laddr(inp), &oifp, &psref, &ip6->ip6_src);
  433         if (error != 0)
  434                 goto bad;
  435 
  436         if (oifp && scope_ambiguous) {
  437                 /*
  438                  * Application should provide a proper zone ID or the use of
  439                  * default zone IDs should be enabled.  Unfortunately, some
  440                  * applications do not behave as it should, so we need a
  441                  * workaround.  Even if an appropriate ID is not determined
  442                  * (when it's required), if we can determine the outgoing
  443                  * interface. determine the zone ID based on the interface.
  444                  */
  445                 error = in6_setscope(&dstsock->sin6_addr, oifp, NULL);
  446                 if (error != 0)
  447                         goto bad;
  448         }
  449         ip6->ip6_dst = dstsock->sin6_addr;
  450 
  451         /* fill in the rest of the IPv6 header fields */
  452         ip6->ip6_flow = in6p_flowinfo(inp) & IPV6_FLOWINFO_MASK;
  453         ip6->ip6_vfc  &= ~IPV6_VERSION_MASK;
  454         ip6->ip6_vfc  |= IPV6_VERSION;
  455         /* ip6_plen will be filled in ip6_output, so not fill it here. */
  456         ip6->ip6_nxt   = in6p_ip6(inp).ip6_nxt;
  457         ip6->ip6_hlim = in6pcb_selecthlim(inp, oifp);
  458 
  459         if_put(oifp, &psref);
  460         oifp = NULL;
  461 
  462         if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
  463             in6p_cksum(inp) != -1) {
  464                 const uint8_t nxt = ip6->ip6_nxt;
  465                 int off;
  466                 u_int16_t sum;
  467 
  468                 /* compute checksum */
  469                 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
  470                         off = offsetof(struct icmp6_hdr, icmp6_cksum);
  471                 else
  472                         off = in6p_cksum(inp);
  473                 if (plen < off + 1) {
  474                         error = EINVAL;
  475                         goto bad;
  476                 }
  477                 off += sizeof(struct ip6_hdr);
  478 
  479                 sum = 0;
  480                 m = m_copyback_cow(m, off, sizeof(sum), (void *)&sum,
  481                     M_DONTWAIT);
  482                 if (m == NULL) {
  483                         error = ENOBUFS;
  484                         goto bad;
  485                 }
  486                 sum = in6_cksum(m, nxt, sizeof(*ip6), plen);
  487                 m = m_copyback_cow(m, off, sizeof(sum), (void *)&sum,
  488                     M_DONTWAIT);
  489                 if (m == NULL) {
  490                         error = ENOBUFS;
  491                         goto bad;
  492                 }
  493         }
  494 
  495         {
  496                 struct ifnet *ret_oifp = NULL;
  497 
  498                 error = ip6_output(m, optp, &inp->inp_route, 0,
  499                     in6p_moptions(inp), inp, &ret_oifp);
  500                 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
  501                         if (ret_oifp)
  502                                 icmp6_ifoutstat_inc(ret_oifp, type, code);
  503                         ICMP6_STATINC(ICMP6_STAT_OUTHIST + type);
  504                 } else
  505                         RIP6_STATINC(RIP6_STAT_OPACKETS);
  506         }
  507 
  508         goto freectl;
  509 
  510  bad:
  511         if (m)
  512                 m_freem(m);
  513 
  514  freectl:
  515         if (control) {
  516                 ip6_clearpktopts(&opt, -1);
  517                 m_freem(control);
  518         }
  519         if_put(oifp, &psref);
  520         curlwp_bindx(bound);
  521         return error;
  522 }
  523 
  524 /*
  525  * Raw IPv6 socket option processing.
  526  */
  527 int
  528 rip6_ctloutput(int op, struct socket *so, struct sockopt *sopt)
  529 {
  530         int error = 0;
  531 
  532         if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) {
  533                 int optval;
  534 
  535                 /* need to fiddle w/ opt(IPPROTO_IPV6, IPV6_CHECKSUM)? */
  536                 if (op == PRCO_GETOPT) {
  537                         optval = 1;
  538                         error = sockopt_set(sopt, &optval, sizeof(optval));
  539                 } else if (op == PRCO_SETOPT) {
  540                         error = sockopt_getint(sopt, &optval);
  541                         if (error)
  542                                 goto out;
  543                         if (optval == 0)
  544                                 error = EINVAL;
  545                 }
  546 
  547                 goto out;
  548         } else if (sopt->sopt_level != IPPROTO_IPV6)
  549                 return ip6_ctloutput(op, so, sopt);
  550 
  551         switch (sopt->sopt_name) {
  552         case MRT6_INIT:
  553         case MRT6_DONE:
  554         case MRT6_ADD_MIF:
  555         case MRT6_DEL_MIF:
  556         case MRT6_ADD_MFC:
  557         case MRT6_DEL_MFC:
  558         case MRT6_PIM:
  559                 if (op == PRCO_SETOPT)
  560                         error = ip6_mrouter_set(so, sopt);
  561                 else if (op == PRCO_GETOPT)
  562                         error = ip6_mrouter_get(so, sopt);
  563                 else
  564                         error = EINVAL;
  565                 break;
  566         case IPV6_CHECKSUM:
  567                 return ip6_raw_ctloutput(op, so, sopt);
  568         default:
  569                 return ip6_ctloutput(op, so, sopt);
  570         }
  571  out:
  572         return error;
  573 }
  574 
  575 extern  u_long rip6_sendspace;
  576 extern  u_long rip6_recvspace;
  577 
  578 int
  579 rip6_attach(struct socket *so, int proto)
  580 {
  581         struct inpcb *inp;
  582         int s, error;
  583 
  584         KASSERT(sotoinpcb(so) == NULL);
  585         sosetlock(so);
  586 
  587         error = kauth_authorize_network(kauth_cred_get(),
  588             KAUTH_NETWORK_SOCKET, KAUTH_REQ_NETWORK_SOCKET_RAWSOCK,
  589             KAUTH_ARG(AF_INET6),
  590             KAUTH_ARG(SOCK_RAW),
  591             KAUTH_ARG(so->so_proto->pr_protocol));
  592         if (error) {
  593                 return error;
  594         }
  595         s = splsoftnet();
  596         error = soreserve(so, rip6_sendspace, rip6_recvspace);
  597         if (error) {
  598                 splx(s);
  599                 return error;
  600         }
  601         if ((error = inpcb_create(so, &raw6cbtable)) != 0) {
  602                 splx(s);
  603                 return error;
  604         }
  605         splx(s);
  606         inp = sotoinpcb(so);
  607         in6p_ip6(inp).ip6_nxt = proto;
  608         in6p_cksum(inp) = -1;
  609 
  610         in6p_icmp6filt(inp) = kmem_alloc(sizeof(struct icmp6_filter), KM_SLEEP);
  611         ICMP6_FILTER_SETPASSALL(in6p_icmp6filt(inp));
  612         KASSERT(solocked(so));
  613         return error;
  614 }
  615 
  616 static void
  617 rip6_detach(struct socket *so)
  618 {
  619         struct inpcb *inp = sotoinpcb(so);
  620 
  621         KASSERT(solocked(so));
  622         KASSERT(inp != NULL);
  623 
  624         if (so == ip6_mrouter) {
  625                 ip6_mrouter_done();
  626         }
  627         /* xxx: RSVP */
  628         if (in6p_icmp6filt(inp) != NULL) {
  629                 kmem_free(in6p_icmp6filt(inp), sizeof(struct icmp6_filter));
  630                 in6p_icmp6filt(inp) = NULL;
  631         }
  632         inpcb_destroy(inp);
  633 }
  634 
  635 static int
  636 rip6_accept(struct socket *so, struct sockaddr *nam)
  637 {
  638         KASSERT(solocked(so));
  639 
  640         return EOPNOTSUPP;
  641 }
  642 
  643 static int
  644 rip6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
  645 {
  646         struct inpcb *inp = sotoinpcb(so);
  647         struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
  648         struct ifaddr *ifa = NULL;
  649         int error = 0;
  650         int s;
  651 
  652         KASSERT(solocked(so));
  653         KASSERT(inp != NULL);
  654         KASSERT(nam != NULL);
  655 
  656         if (addr->sin6_len != sizeof(*addr))
  657                 return EINVAL;
  658         if (IFNET_READER_EMPTY() || addr->sin6_family != AF_INET6)
  659                 return EADDRNOTAVAIL;
  660 
  661         if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0)
  662                 return error;
  663 
  664         /*
  665          * we don't support mapped address here, it would confuse
  666          * users so reject it
  667          */
  668         if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr))
  669                 return EADDRNOTAVAIL;
  670         s = pserialize_read_enter();
  671         if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
  672             (ifa = ifa_ifwithaddr(sin6tosa(addr))) == NULL) {
  673                 error = EADDRNOTAVAIL;
  674                 goto out;
  675         }
  676         if (ifa && (ifatoia6(ifa))->ia6_flags &
  677             (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED)) {
  678                 error = EADDRNOTAVAIL;
  679                 goto out;
  680         }
  681 
  682         in6p_laddr(inp) = addr->sin6_addr;
  683         error = 0;
  684 out:
  685         pserialize_read_exit(s);
  686         return error;
  687 }
  688 
  689 static int
  690 rip6_listen(struct socket *so, struct lwp *l)
  691 {
  692         KASSERT(solocked(so));
  693 
  694         return EOPNOTSUPP;
  695 }
  696 
  697 static int
  698 rip6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
  699 {
  700         struct inpcb *inp = sotoinpcb(so);
  701         struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
  702         struct in6_addr in6a;
  703         struct ifnet *ifp = NULL;
  704         int scope_ambiguous = 0;
  705         int error = 0;
  706         struct psref psref;
  707         int bound;
  708 
  709         KASSERT(solocked(so));
  710         KASSERT(inp != NULL);
  711         KASSERT(nam != NULL);
  712 
  713         if (IFNET_READER_EMPTY())
  714                 return EADDRNOTAVAIL;
  715         if (addr->sin6_family != AF_INET6)
  716                 return EAFNOSUPPORT;
  717         if (addr->sin6_len != sizeof(*addr))
  718                 return EINVAL;
  719 
  720         /*
  721          * Application should provide a proper zone ID or the use of
  722          * default zone IDs should be enabled.  Unfortunately, some
  723          * applications do not behave as it should, so we need a
  724          * workaround.  Even if an appropriate ID is not determined,
  725          * we'll see if we can determine the outgoing interface.  If we
  726          * can, determine the zone ID based on the interface below.
  727          */
  728         if (addr->sin6_scope_id == 0 && !ip6_use_defzone)
  729                 scope_ambiguous = 1;
  730         if ((error = sa6_embedscope(addr, ip6_use_defzone)) != 0)
  731                 return error;
  732 
  733         bound = curlwp_bind();
  734         /* Source address selection. XXX: need pcblookup? */
  735         error = in6_selectsrc(addr, in6p_outputopts(inp),
  736             in6p_moptions(inp), &inp->inp_route,
  737             &in6p_laddr(inp), &ifp, &psref, &in6a);
  738         if (error != 0)
  739                 goto out;
  740         /* XXX: see above */
  741         if (ifp && scope_ambiguous &&
  742             (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
  743                 goto out;
  744         }
  745         in6p_laddr(inp) = in6a;
  746         in6p_faddr(inp) = addr->sin6_addr;
  747         soisconnected(so);
  748 out:
  749         if_put(ifp, &psref);
  750         curlwp_bindx(bound);
  751         return error;
  752 }
  753 
  754 static int
  755 rip6_connect2(struct socket *so, struct socket *so2)
  756 {
  757         KASSERT(solocked(so));
  758 
  759         return EOPNOTSUPP;
  760 }
  761 
  762 static int
  763 rip6_disconnect(struct socket *so)
  764 {
  765         struct inpcb *inp = sotoinpcb(so);
  766 
  767         KASSERT(solocked(so));
  768         KASSERT(inp != NULL);
  769 
  770         if ((so->so_state & SS_ISCONNECTED) == 0)
  771                 return ENOTCONN;
  772 
  773         in6p_faddr(inp) = in6addr_any;
  774         so->so_state &= ~SS_ISCONNECTED;        /* XXX */
  775         return 0;
  776 }
  777 
  778 static int
  779 rip6_shutdown(struct socket *so)
  780 {
  781         KASSERT(solocked(so));
  782 
  783         /*
  784          * Mark the connection as being incapable of further input.
  785          */
  786         socantsendmore(so);
  787         return 0;
  788 }
  789 
  790 static int
  791 rip6_abort(struct socket *so)
  792 {
  793         KASSERT(solocked(so));
  794 
  795         soisdisconnected(so);
  796         rip6_detach(so);
  797         return 0;
  798 }
  799 
  800 static int
  801 rip6_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
  802 {
  803         return in6_control(so, cmd, nam, ifp);
  804 }
  805 
  806 static int
  807 rip6_stat(struct socket *so, struct stat *ub)
  808 {
  809         KASSERT(solocked(so));
  810 
  811         /* stat: don't bother with a blocksize */
  812         return 0;
  813 }
  814 
  815 static int
  816 rip6_peeraddr(struct socket *so, struct sockaddr *nam)
  817 {
  818         KASSERT(solocked(so));
  819         KASSERT(sotoinpcb(so) != NULL);
  820         KASSERT(nam != NULL);
  821 
  822         in6pcb_fetch_peeraddr(sotoinpcb(so), (struct sockaddr_in6 *)nam);
  823         return 0;
  824 }
  825 
  826 static int
  827 rip6_sockaddr(struct socket *so, struct sockaddr *nam)
  828 {
  829         KASSERT(solocked(so));
  830         KASSERT(sotoinpcb(so) != NULL);
  831         KASSERT(nam != NULL);
  832 
  833         in6pcb_fetch_sockaddr(sotoinpcb(so), (struct sockaddr_in6 *)nam);
  834         return 0;
  835 }
  836 
  837 static int
  838 rip6_rcvd(struct socket *so, int flags, struct lwp *l)
  839 {
  840         KASSERT(solocked(so));
  841 
  842         return EOPNOTSUPP;
  843 }
  844 
  845 static int
  846 rip6_recvoob(struct socket *so, struct mbuf *m, int flags)
  847 {
  848         KASSERT(solocked(so));
  849 
  850         return EOPNOTSUPP;
  851 }
  852 
  853 static int
  854 rip6_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
  855     struct mbuf *control, struct lwp *l)
  856 {
  857         struct inpcb *inp = sotoinpcb(so);
  858         struct sockaddr_in6 tmp;
  859         struct sockaddr_in6 *dst;
  860         int error = 0;
  861 
  862         KASSERT(solocked(so));
  863         KASSERT(inp != NULL);
  864         KASSERT(m != NULL);
  865 
  866         /*
  867          * Ship a packet out. The appropriate raw output
  868          * routine handles any messaging necessary.
  869          */
  870 
  871         /* always copy sockaddr to avoid overwrites */
  872         if (so->so_state & SS_ISCONNECTED) {
  873                 if (nam) {
  874                         error = EISCONN;
  875                         goto release;
  876                 }
  877                 /* XXX */
  878                 sockaddr_in6_init(&tmp, &in6p_faddr(inp), 0, 0, 0);
  879                 dst = &tmp;
  880         } else {
  881                 if (nam == NULL) {
  882                         error = ENOTCONN;
  883                         goto release;
  884                 }
  885                 tmp = *(struct sockaddr_in6 *)nam;
  886                 dst = &tmp;
  887 
  888                 if (dst->sin6_family != AF_INET6) {
  889                         error = EAFNOSUPPORT;
  890                         goto release;
  891                 }
  892                 if (dst->sin6_len != sizeof(*dst)) {
  893                         error = EINVAL;
  894                         goto release;
  895                 }
  896         }
  897         error = rip6_output(m, so, dst, control);
  898         m = NULL;
  899 
  900 release:
  901         if (m)
  902                 m_freem(m);
  903 
  904         return error;
  905 }
  906 
  907 static int
  908 rip6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
  909 {
  910         KASSERT(solocked(so));
  911 
  912         m_freem(m);
  913         m_freem(control);
  914 
  915         return EOPNOTSUPP;
  916 }
  917 
  918 static int
  919 rip6_purgeif(struct socket *so, struct ifnet *ifp)
  920 {
  921 
  922         mutex_enter(softnet_lock);
  923         in6pcb_purgeif0(&raw6cbtable, ifp);
  924 #ifdef NET_MPSAFE
  925         mutex_exit(softnet_lock);
  926 #endif
  927         in6_purgeif(ifp);
  928 #ifdef NET_MPSAFE
  929         mutex_enter(softnet_lock);
  930 #endif
  931         in6pcb_purgeif(&raw6cbtable, ifp);
  932         mutex_exit(softnet_lock);
  933 
  934         return 0;
  935 }
  936 
  937 static int
  938 sysctl_net_inet6_raw6_stats(SYSCTLFN_ARGS)
  939 {
  940 
  941         return (NETSTAT_SYSCTL(rip6stat_percpu, RIP6_NSTATS));
  942 }
  943 
  944 static void
  945 sysctl_net_inet6_raw6_setup(struct sysctllog **clog)
  946 {
  947 
  948         sysctl_createv(clog, 0, NULL, NULL,
  949                        CTLFLAG_PERMANENT,
  950                        CTLTYPE_NODE, "inet6", NULL,
  951                        NULL, 0, NULL, 0,
  952                        CTL_NET, PF_INET6, CTL_EOL);
  953         sysctl_createv(clog, 0, NULL, NULL,
  954                        CTLFLAG_PERMANENT,
  955                        CTLTYPE_NODE, "raw6",
  956                        SYSCTL_DESCR("Raw IPv6 settings"),
  957                        NULL, 0, NULL, 0,
  958                        CTL_NET, PF_INET6, IPPROTO_RAW, CTL_EOL);
  959 
  960         sysctl_createv(clog, 0, NULL, NULL,
  961                        CTLFLAG_PERMANENT,
  962                        CTLTYPE_STRUCT, "pcblist",
  963                        SYSCTL_DESCR("Raw IPv6 control block list"),
  964                        sysctl_inpcblist, 0, &raw6cbtable, 0,
  965                        CTL_NET, PF_INET6, IPPROTO_RAW,
  966                        CTL_CREATE, CTL_EOL);
  967         sysctl_createv(clog, 0, NULL, NULL,
  968                        CTLFLAG_PERMANENT,
  969                        CTLTYPE_STRUCT, "stats",
  970                        SYSCTL_DESCR("Raw IPv6 statistics"),
  971                        sysctl_net_inet6_raw6_stats, 0, NULL, 0,
  972                        CTL_NET, PF_INET6, IPPROTO_RAW, RAW6CTL_STATS,
  973                        CTL_EOL);
  974 }
  975 
  976 PR_WRAP_USRREQS(rip6)
  977 #define rip6_attach             rip6_attach_wrapper
  978 #define rip6_detach             rip6_detach_wrapper
  979 #define rip6_accept             rip6_accept_wrapper
  980 #define rip6_bind               rip6_bind_wrapper
  981 #define rip6_listen             rip6_listen_wrapper
  982 #define rip6_connect            rip6_connect_wrapper
  983 #define rip6_connect2           rip6_connect2_wrapper
  984 #define rip6_disconnect         rip6_disconnect_wrapper
  985 #define rip6_shutdown           rip6_shutdown_wrapper
  986 #define rip6_abort              rip6_abort_wrapper
  987 #define rip6_ioctl              rip6_ioctl_wrapper
  988 #define rip6_stat               rip6_stat_wrapper
  989 #define rip6_peeraddr           rip6_peeraddr_wrapper
  990 #define rip6_sockaddr           rip6_sockaddr_wrapper
  991 #define rip6_rcvd               rip6_rcvd_wrapper
  992 #define rip6_recvoob            rip6_recvoob_wrapper
  993 #define rip6_send               rip6_send_wrapper
  994 #define rip6_sendoob            rip6_sendoob_wrapper
  995 #define rip6_purgeif            rip6_purgeif_wrapper
  996 
  997 const struct pr_usrreqs rip6_usrreqs = {
  998         .pr_attach      = rip6_attach,
  999         .pr_detach      = rip6_detach,
 1000         .pr_accept      = rip6_accept,
 1001         .pr_bind        = rip6_bind,
 1002         .pr_listen      = rip6_listen,
 1003         .pr_connect     = rip6_connect,
 1004         .pr_connect2    = rip6_connect2,
 1005         .pr_disconnect  = rip6_disconnect,
 1006         .pr_shutdown    = rip6_shutdown,
 1007         .pr_abort       = rip6_abort,
 1008         .pr_ioctl       = rip6_ioctl,
 1009         .pr_stat        = rip6_stat,
 1010         .pr_peeraddr    = rip6_peeraddr,
 1011         .pr_sockaddr    = rip6_sockaddr,
 1012         .pr_rcvd        = rip6_rcvd,
 1013         .pr_recvoob     = rip6_recvoob,
 1014         .pr_send        = rip6_send,
 1015         .pr_sendoob     = rip6_sendoob,
 1016         .pr_purgeif     = rip6_purgeif,
 1017 };

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.