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

Cache object: f070c7641b69fa53b73906f6d9861856


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