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

Cache object: 3d3b21326baacc57ad96ed5b67a9f30f


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