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/netinet/ip_carp.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: ip_carp.c,v 1.10 2006/11/16 01:33:45 christos Exp $    */
    2 /*      $OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $   */
    3 
    4 /*
    5  * Copyright (c) 2002 Michael Shalayeff. All rights reserved.
    6  * Copyright (c) 2003 Ryan McBride. 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  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
   21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   23  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   26  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   27  * THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 
   30 /*
   31  * TODO:
   32  *      - iface reconfigure
   33  *      - support for hardware checksum calculations;
   34  *
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/proc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/socket.h>
   41 #include <sys/socketvar.h>
   42 #include <sys/callout.h>
   43 #include <sys/ioctl.h>
   44 #include <sys/errno.h>
   45 #include <sys/device.h>
   46 #include <sys/time.h>
   47 #include <sys/kernel.h>
   48 #include <sys/kauth.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/ucred.h>
   51 #include <sys/syslog.h>
   52 #include <sys/acct.h>
   53 
   54 #include <machine/cpu.h>
   55 
   56 #include <net/if.h>
   57 #include <net/pfil.h>
   58 #include <net/if_types.h>
   59 #include <net/if_ether.h>
   60 #include <net/route.h>
   61 #include <net/netisr.h>
   62 #include <netinet/if_inarp.h>
   63 
   64 #include <machine/stdarg.h>
   65 
   66 #if NFDDI > 0
   67 #include <net/if_fddi.h>
   68 #endif
   69 #if NTOKEN > 0
   70 #include <net/if_token.h>
   71 #endif
   72 
   73 #ifdef INET
   74 #include <netinet/in.h>
   75 #include <netinet/in_systm.h>
   76 #include <netinet/in_var.h>
   77 #include <netinet/ip.h>
   78 #include <netinet/ip_var.h>
   79 
   80 #include <net/if_dl.h>
   81 #endif
   82 
   83 #ifdef INET6
   84 #include <netinet/icmp6.h>
   85 #include <netinet/ip6.h>
   86 #include <netinet6/ip6_var.h>
   87 #include <netinet6/nd6.h>
   88 #endif
   89 
   90 #include "bpfilter.h"
   91 #if NBPFILTER > 0
   92 #include <net/bpf.h>
   93 #endif
   94 
   95 #include <sys/sha1.h>
   96 
   97 #include <netinet/ip_carp.h>
   98 
   99 struct carp_mc_entry {
  100         LIST_ENTRY(carp_mc_entry)       mc_entries;
  101         union {
  102                 struct ether_multi      *mcu_enm;
  103         } mc_u;
  104         struct sockaddr_storage         mc_addr;
  105 };
  106 #define mc_enm  mc_u.mcu_enm
  107 
  108 struct carp_softc {
  109         struct ethercom sc_ac;
  110 #define sc_if           sc_ac.ec_if
  111 #define sc_carpdev      sc_ac.ec_if.if_carpdev
  112         int ah_cookie;
  113         int lh_cookie;
  114         struct ip_moptions sc_imo;
  115 #ifdef INET6
  116         struct ip6_moptions sc_im6o;
  117 #endif /* INET6 */
  118         TAILQ_ENTRY(carp_softc) sc_list;
  119 
  120         enum { INIT = 0, BACKUP, MASTER }       sc_state;
  121 
  122         int sc_suppress;
  123         int sc_bow_out;
  124 
  125         int sc_sendad_errors;
  126 #define CARP_SENDAD_MAX_ERRORS  3
  127         int sc_sendad_success;
  128 #define CARP_SENDAD_MIN_SUCCESS 3
  129 
  130         int sc_vhid;
  131         int sc_advskew;
  132         int sc_naddrs;
  133         int sc_naddrs6;
  134         int sc_advbase;         /* seconds */
  135         int sc_init_counter;
  136         u_int64_t sc_counter;
  137 
  138         /* authentication */
  139 #define CARP_HMAC_PAD   64
  140         unsigned char sc_key[CARP_KEY_LEN];
  141         unsigned char sc_pad[CARP_HMAC_PAD];
  142         SHA1_CTX sc_sha1;
  143         u_int32_t sc_hashkey[2];
  144 
  145         struct callout sc_ad_tmo;       /* advertisement timeout */
  146         struct callout sc_md_tmo;       /* master down timeout */
  147         struct callout sc_md6_tmo;      /* master down timeout */
  148 
  149         LIST_HEAD(__carp_mchead, carp_mc_entry) carp_mc_listhead;
  150 };
  151 
  152 int carp_suppress_preempt = 0;
  153 int carp_opts[CARPCTL_MAXID] = { 0, 1, 0, 0, 0 };       /* XXX for now */
  154 struct carpstats carpstats;
  155 
  156 struct carp_if {
  157         TAILQ_HEAD(, carp_softc) vhif_vrs;
  158         int vhif_nvrs;
  159 
  160         struct ifnet *vhif_ifp;
  161 };
  162 
  163 #define CARP_LOG(sc, s)                                                 \
  164         if (carp_opts[CARPCTL_LOG]) {                                   \
  165                 if (sc)                                                 \
  166                         log(LOG_INFO, "%s: ",                           \
  167                             (sc)->sc_if.if_xname);                      \
  168                 else                                                    \
  169                         log(LOG_INFO, "carp: ");                        \
  170                 addlog s;                                               \
  171                 addlog("\n");                                           \
  172         }
  173 
  174 void    carp_hmac_prepare(struct carp_softc *);
  175 void    carp_hmac_generate(struct carp_softc *, u_int32_t *,
  176             unsigned char *);
  177 int     carp_hmac_verify(struct carp_softc *, u_int32_t *,
  178             unsigned char *);
  179 void    carp_setroute(struct carp_softc *, int);
  180 void    carp_proto_input_c(struct mbuf *, struct carp_header *, sa_family_t);
  181 void    carpattach(int);
  182 void    carpdetach(struct carp_softc *);
  183 int     carp_prepare_ad(struct mbuf *, struct carp_softc *,
  184             struct carp_header *);
  185 void    carp_send_ad_all(void);
  186 void    carp_send_ad(void *);
  187 void    carp_send_arp(struct carp_softc *);
  188 void    carp_master_down(void *);
  189 int     carp_ioctl(struct ifnet *, u_long, caddr_t);
  190 void    carp_start(struct ifnet *);
  191 void    carp_setrun(struct carp_softc *, sa_family_t);
  192 void    carp_set_state(struct carp_softc *, int);
  193 int     carp_addrcount(struct carp_if *, struct in_ifaddr *, int);
  194 enum    { CARP_COUNT_MASTER, CARP_COUNT_RUNNING };
  195 
  196 void    carp_multicast_cleanup(struct carp_softc *);
  197 int     carp_set_ifp(struct carp_softc *, struct ifnet *);
  198 void    carp_set_enaddr(struct carp_softc *);
  199 void    carp_addr_updated(void *);
  200 u_int32_t       carp_hash(struct carp_softc *, u_char *);
  201 int     carp_set_addr(struct carp_softc *, struct sockaddr_in *);
  202 int     carp_join_multicast(struct carp_softc *);
  203 #ifdef INET6
  204 void    carp_send_na(struct carp_softc *);
  205 int     carp_set_addr6(struct carp_softc *, struct sockaddr_in6 *);
  206 int     carp_join_multicast6(struct carp_softc *);
  207 #endif
  208 int     carp_clone_create(struct if_clone *, int);
  209 int     carp_clone_destroy(struct ifnet *);
  210 int     carp_ether_addmulti(struct carp_softc *, struct ifreq *);
  211 int     carp_ether_delmulti(struct carp_softc *, struct ifreq *);
  212 void    carp_ether_purgemulti(struct carp_softc *);
  213 
  214 struct if_clone carp_cloner =
  215     IF_CLONE_INITIALIZER("carp", carp_clone_create, carp_clone_destroy);
  216 
  217 static __inline u_int16_t
  218 carp_cksum(struct mbuf *m, int len)
  219 {
  220         return (in_cksum(m, len));
  221 }
  222 
  223 void
  224 carp_hmac_prepare(struct carp_softc *sc)
  225 {
  226         u_int8_t carp_version = CARP_VERSION, type = CARP_ADVERTISEMENT;
  227         u_int8_t vhid = sc->sc_vhid & 0xff;
  228         SHA1_CTX sha1ctx;
  229         u_int32_t kmd[5];
  230         struct ifaddr *ifa;
  231         int i, found;
  232         struct in_addr last, cur, in;
  233 #ifdef INET6
  234         struct in6_addr last6, cur6, in6;
  235 #endif /* INET6 */
  236 
  237         /* compute ipad from key */
  238         bzero(sc->sc_pad, sizeof(sc->sc_pad));
  239         bcopy(sc->sc_key, sc->sc_pad, sizeof(sc->sc_key));
  240         for (i = 0; i < sizeof(sc->sc_pad); i++)
  241                 sc->sc_pad[i] ^= 0x36;
  242 
  243         /* precompute first part of inner hash */
  244         SHA1Init(&sc->sc_sha1);
  245         SHA1Update(&sc->sc_sha1, sc->sc_pad, sizeof(sc->sc_pad));
  246         SHA1Update(&sc->sc_sha1, (void *)&carp_version, sizeof(carp_version));
  247         SHA1Update(&sc->sc_sha1, (void *)&type, sizeof(type));
  248 
  249         /* generate a key for the arpbalance hash, before the vhid is hashed */
  250         bcopy(&sc->sc_sha1, &sha1ctx, sizeof(sha1ctx));
  251         SHA1Final((unsigned char *)kmd, &sha1ctx);
  252         sc->sc_hashkey[0] = kmd[0] ^ kmd[1];
  253         sc->sc_hashkey[1] = kmd[2] ^ kmd[3];
  254 
  255         /* the rest of the precomputation */
  256         SHA1Update(&sc->sc_sha1, (void *)&vhid, sizeof(vhid));
  257 
  258         /* Hash the addresses from smallest to largest, not interface order */
  259 #ifdef INET
  260         cur.s_addr = 0;
  261         do {
  262                 found = 0;
  263                 last = cur;
  264                 cur.s_addr = 0xffffffff;
  265                 TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
  266                         in.s_addr = ifatoia(ifa)->ia_addr.sin_addr.s_addr;
  267                         if (ifa->ifa_addr->sa_family == AF_INET &&
  268                             ntohl(in.s_addr) > ntohl(last.s_addr) &&
  269                             ntohl(in.s_addr) < ntohl(cur.s_addr)) {
  270                                 cur.s_addr = in.s_addr;
  271                                 found++;
  272                         }
  273                 }
  274                 if (found)
  275                         SHA1Update(&sc->sc_sha1, (void *)&cur, sizeof(cur));
  276         } while (found);
  277 #endif /* INET */
  278 
  279 #ifdef INET6
  280         memset(&cur6, 0x00, sizeof(cur6));
  281         do {
  282                 found = 0;
  283                 last6 = cur6;
  284                 memset(&cur6, 0xff, sizeof(cur6));
  285                 TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
  286                         in6 = ifatoia6(ifa)->ia_addr.sin6_addr;
  287                         if (IN6_IS_ADDR_LINKLOCAL(&in6))
  288                                 in6.s6_addr16[1] = 0;
  289                         if (ifa->ifa_addr->sa_family == AF_INET6 &&
  290                             memcmp(&in6, &last6, sizeof(in6)) > 0 &&
  291                             memcmp(&in6, &cur6, sizeof(in6)) < 0) {
  292                                 cur6 = in6;
  293                                 found++;
  294                         }
  295                 }
  296                 if (found)
  297                         SHA1Update(&sc->sc_sha1, (void *)&cur6, sizeof(cur6));
  298         } while (found);
  299 #endif /* INET6 */
  300 
  301         /* convert ipad to opad */
  302         for (i = 0; i < sizeof(sc->sc_pad); i++)
  303                 sc->sc_pad[i] ^= 0x36 ^ 0x5c;
  304 }
  305 
  306 void
  307 carp_hmac_generate(struct carp_softc *sc, u_int32_t counter[2],
  308     unsigned char md[20])
  309 {
  310         SHA1_CTX sha1ctx;
  311 
  312         /* fetch first half of inner hash */
  313         bcopy(&sc->sc_sha1, &sha1ctx, sizeof(sha1ctx));
  314 
  315         SHA1Update(&sha1ctx, (void *)counter, sizeof(sc->sc_counter));
  316         SHA1Final(md, &sha1ctx);
  317 
  318         /* outer hash */
  319         SHA1Init(&sha1ctx);
  320         SHA1Update(&sha1ctx, sc->sc_pad, sizeof(sc->sc_pad));
  321         SHA1Update(&sha1ctx, md, 20);
  322         SHA1Final(md, &sha1ctx);
  323 }
  324 
  325 int
  326 carp_hmac_verify(struct carp_softc *sc, u_int32_t counter[2],
  327     unsigned char md[20])
  328 {
  329         unsigned char md2[20];
  330 
  331         carp_hmac_generate(sc, counter, md2);
  332 
  333         return (bcmp(md, md2, sizeof(md2)));
  334 }
  335 
  336 void
  337 carp_setroute(struct carp_softc *sc, int cmd)
  338 {
  339         struct ifaddr *ifa;
  340         int s;
  341 
  342         s = splsoftnet();
  343         TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
  344                 switch (ifa->ifa_addr->sa_family) {
  345                 case AF_INET: {
  346                         int count = 0;
  347                         struct sockaddr sa;
  348                         struct rtentry *rt;
  349                         struct radix_node_head *rnh =
  350                             rt_tables[ifa->ifa_addr->sa_family];
  351                         struct radix_node *rn;
  352                         int hr_otherif, nr_ourif;
  353 
  354                         /*
  355                          * Avoid screwing with the routes if there are other
  356                          * carp interfaces which are master and have the same
  357                          * address.
  358                          */
  359                         if (sc->sc_carpdev != NULL &&
  360                             sc->sc_carpdev->if_carp != NULL) {
  361                                 count = carp_addrcount(
  362                                     (struct carp_if *)sc->sc_carpdev->if_carp,
  363                                     ifatoia(ifa), CARP_COUNT_MASTER);
  364                                 if ((cmd == RTM_ADD && count != 1) ||
  365                                     (cmd == RTM_DELETE && count != 0))
  366                                         continue;
  367                         }
  368 
  369                         /* Remove the existing host route, if any */
  370                         rtrequest(RTM_DELETE, ifa->ifa_addr,
  371                             ifa->ifa_addr, ifa->ifa_netmask,
  372                             RTF_HOST, NULL);
  373 
  374                         /* Check for our address on another interface */
  375                         rn = rnh->rnh_matchaddr(ifa->ifa_addr, rnh);
  376                         rt = (struct rtentry *)rn;
  377                         hr_otherif = (rt && rt->rt_ifp != &sc->sc_if &&
  378                             rt->rt_flags & (RTF_CLONING|RTF_CLONED));
  379 
  380                         /* Check for a network route on our interface */
  381                         bcopy(ifa->ifa_addr, &sa, sizeof(sa));
  382                         satosin(&sa)->sin_addr.s_addr = satosin(ifa->ifa_netmask
  383                             )->sin_addr.s_addr & satosin(&sa)->sin_addr.s_addr;
  384                         rn = rnh->rnh_lookup(&sa, ifa->ifa_netmask, rnh);
  385                         rt = (struct rtentry *)rn;
  386                         nr_ourif = (rt && rt->rt_ifp == &sc->sc_if);
  387 
  388                         switch (cmd) {
  389                         case RTM_ADD:
  390                                 if (hr_otherif) {
  391                                         ifa->ifa_rtrequest = NULL;
  392                                         ifa->ifa_flags &= ~RTF_CLONING;
  393 
  394                                         rtrequest(RTM_ADD, ifa->ifa_addr,
  395                                             ifa->ifa_addr, ifa->ifa_netmask,
  396                                             RTF_UP | RTF_HOST, NULL);
  397                                 }
  398                                 if (!hr_otherif || nr_ourif || !rt) {
  399                                         if (nr_ourif && !(rt->rt_flags &
  400                                             RTF_CLONING))
  401                                                 rtrequest(RTM_DELETE, &sa,
  402                                                     ifa->ifa_addr,
  403                                                     ifa->ifa_netmask, 0, NULL);
  404 
  405                                         ifa->ifa_rtrequest = arp_rtrequest;
  406                                         ifa->ifa_flags |= RTF_CLONING;
  407 
  408                                         if (rtrequest(RTM_ADD, ifa->ifa_addr,
  409                                             ifa->ifa_addr, ifa->ifa_netmask, 0,
  410                                             NULL) == 0)
  411                                                 ifa->ifa_flags |= IFA_ROUTE;
  412                                 }
  413                                 break;
  414                         case RTM_DELETE:
  415                                 break;
  416                         default:
  417                                 break;
  418                         }
  419                         break;
  420                 }
  421 
  422 #ifdef INET6
  423                 case AF_INET6:
  424                         if (cmd == RTM_ADD)
  425                                 in6_ifaddloop(ifa);
  426                         else
  427                                 in6_ifremloop(ifa);
  428                         break;
  429 #endif /* INET6 */
  430                 default:
  431                         break;
  432                 }
  433         }
  434         splx(s);
  435 }
  436 
  437 /*
  438  * process input packet.
  439  * we have rearranged checks order compared to the rfc,
  440  * but it seems more efficient this way or not possible otherwise.
  441  */
  442 void
  443 carp_proto_input(struct mbuf *m, ...)
  444 {
  445         struct ip *ip = mtod(m, struct ip *);
  446         struct carp_softc *sc = NULL;
  447         struct carp_header *ch;
  448         int iplen, len, hlen;
  449         va_list ap;
  450 
  451         va_start(ap, m);
  452         hlen = va_arg(ap, int);
  453         va_end(ap);
  454 
  455         carpstats.carps_ipackets++;
  456 
  457         if (!carp_opts[CARPCTL_ALLOW]) {
  458                 m_freem(m);
  459                 return;
  460         }
  461 
  462         /* check if received on a valid carp interface */
  463         if (m->m_pkthdr.rcvif->if_type != IFT_CARP) {
  464                 carpstats.carps_badif++;
  465                 CARP_LOG(sc, ("packet received on non-carp interface: %s",
  466                     m->m_pkthdr.rcvif->if_xname));
  467                 m_freem(m);
  468                 return;
  469         }
  470 
  471         /* verify that the IP TTL is 255.  */
  472         if (ip->ip_ttl != CARP_DFLTTL) {
  473                 carpstats.carps_badttl++;
  474                 CARP_LOG(sc, ("received ttl %d != %d on %s", ip->ip_ttl,
  475                     CARP_DFLTTL, m->m_pkthdr.rcvif->if_xname));
  476                 m_freem(m);
  477                 return;
  478         }
  479 
  480         /*
  481          * verify that the received packet length is
  482          * equal to the CARP header
  483          */
  484         iplen = ip->ip_hl << 2;
  485         len = iplen + sizeof(*ch);
  486         if (len > m->m_pkthdr.len) {
  487                 carpstats.carps_badlen++;
  488                 CARP_LOG(sc, ("packet too short %d on %s", m->m_pkthdr.len,
  489                     m->m_pkthdr.rcvif->if_xname));
  490                 m_freem(m);
  491                 return;
  492         }
  493 
  494         if ((m = m_pullup(m, len)) == NULL) {
  495                 carpstats.carps_hdrops++;
  496                 return;
  497         }
  498         ip = mtod(m, struct ip *);
  499         ch = (struct carp_header *)((char *)ip + iplen);
  500         /* verify the CARP checksum */
  501         m->m_data += iplen;
  502         if (carp_cksum(m, len - iplen)) {
  503                 carpstats.carps_badsum++;
  504                 CARP_LOG(sc, ("checksum failed on %s",
  505                     m->m_pkthdr.rcvif->if_xname));
  506                 m_freem(m);
  507                 return;
  508         }
  509         m->m_data -= iplen;
  510 
  511         carp_proto_input_c(m, ch, AF_INET);
  512 }
  513 
  514 #ifdef INET6
  515 int
  516 carp6_proto_input(struct mbuf **mp, int *offp, int proto)
  517 {
  518         struct mbuf *m = *mp;
  519         struct carp_softc *sc = NULL;
  520         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
  521         struct carp_header *ch;
  522         u_int len;
  523 
  524         carpstats.carps_ipackets6++;
  525 
  526         if (!carp_opts[CARPCTL_ALLOW]) {
  527                 m_freem(m);
  528                 return (IPPROTO_DONE);
  529         }
  530 
  531         /* check if received on a valid carp interface */
  532         if (m->m_pkthdr.rcvif->if_type != IFT_CARP) {
  533                 carpstats.carps_badif++;
  534                 CARP_LOG(sc, ("packet received on non-carp interface: %s",
  535                     m->m_pkthdr.rcvif->if_xname));
  536                 m_freem(m);
  537                 return (IPPROTO_DONE);
  538         }
  539 
  540         /* verify that the IP TTL is 255 */
  541         if (ip6->ip6_hlim != CARP_DFLTTL) {
  542                 carpstats.carps_badttl++;
  543                 CARP_LOG(sc, ("received ttl %d != %d on %s", ip6->ip6_hlim,
  544                     CARP_DFLTTL, m->m_pkthdr.rcvif->if_xname));
  545                 m_freem(m);
  546                 return (IPPROTO_DONE);
  547         }
  548 
  549         /* verify that we have a complete carp packet */
  550         len = m->m_len;
  551         IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch));
  552         if (ch == NULL) {
  553                 carpstats.carps_badlen++;
  554                 CARP_LOG(sc, ("packet size %u too small", len));
  555                 return (IPPROTO_DONE);
  556         }
  557 
  558 
  559         /* verify the CARP checksum */
  560         m->m_data += *offp;
  561         if (carp_cksum(m, sizeof(*ch))) {
  562                 carpstats.carps_badsum++;
  563                 CARP_LOG(sc, ("checksum failed, on %s",
  564                     m->m_pkthdr.rcvif->if_xname));
  565                 m_freem(m);
  566                 return (IPPROTO_DONE);
  567         }
  568         m->m_data -= *offp;
  569 
  570         carp_proto_input_c(m, ch, AF_INET6);
  571         return (IPPROTO_DONE);
  572 }
  573 #endif /* INET6 */
  574 
  575 void
  576 carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
  577 {
  578         struct carp_softc *sc;
  579         u_int64_t tmp_counter;
  580         struct timeval sc_tv, ch_tv;
  581 
  582         TAILQ_FOREACH(sc, &((struct carp_if *)
  583             m->m_pkthdr.rcvif->if_carpdev->if_carp)->vhif_vrs, sc_list)
  584                 if (sc->sc_vhid == ch->carp_vhid)
  585                         break;
  586 
  587         if (!sc || (sc->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
  588             (IFF_UP|IFF_RUNNING)) {
  589                 carpstats.carps_badvhid++;
  590                 m_freem(m);
  591                 return;
  592         }
  593 
  594         /*
  595          * Check if our own advertisement was duplicated
  596          * from a non simplex interface.
  597          * XXX If there is no address on our physical interface
  598          * there is no way to distinguish our ads from the ones
  599          * another carp host might have sent us.
  600          */
  601         if ((sc->sc_carpdev->if_flags & IFF_SIMPLEX) == 0) {
  602                 struct sockaddr sa;
  603                 struct ifaddr *ifa;
  604 
  605                 bzero(&sa, sizeof(sa));
  606                 sa.sa_family = af;
  607                 ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
  608 
  609                 if (ifa && af == AF_INET) {
  610                         struct ip *ip = mtod(m, struct ip *);
  611                         if (ip->ip_src.s_addr ==
  612                                         ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
  613                                 m_freem(m);
  614                                 return;
  615                         }
  616                 }
  617 #ifdef INET6
  618                 if (ifa && af == AF_INET6) {
  619                         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
  620                         struct in6_addr in6_src, in6_found;
  621 
  622                         in6_src = ip6->ip6_src;
  623                         in6_found = ifatoia6(ifa)->ia_addr.sin6_addr;
  624                         if (IN6_IS_ADDR_LINKLOCAL(&in6_src))
  625                                 in6_src.s6_addr16[1] = 0;
  626                         if (IN6_IS_ADDR_LINKLOCAL(&in6_found))
  627                                 in6_found.s6_addr16[1] = 0;
  628                         if (IN6_ARE_ADDR_EQUAL(&in6_src, &in6_found)) {
  629                                 m_freem(m);
  630                                 return;
  631                         }
  632                 }
  633 #endif /* INET6 */
  634         }
  635 
  636         microtime(&sc->sc_if.if_lastchange);
  637         sc->sc_if.if_ipackets++;
  638         sc->sc_if.if_ibytes += m->m_pkthdr.len;
  639 
  640         /* verify the CARP version. */
  641         if (ch->carp_version != CARP_VERSION) {
  642                 carpstats.carps_badver++;
  643                 sc->sc_if.if_ierrors++;
  644                 CARP_LOG(sc, ("invalid version %d != %d",
  645                     ch->carp_version, CARP_VERSION));
  646                 m_freem(m);
  647                 return;
  648         }
  649 
  650         /* verify the hash */
  651         if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) {
  652                 carpstats.carps_badauth++;
  653                 sc->sc_if.if_ierrors++;
  654                 CARP_LOG(sc, ("incorrect hash"));
  655                 m_freem(m);
  656                 return;
  657         }
  658 
  659         tmp_counter = ntohl(ch->carp_counter[0]);
  660         tmp_counter = tmp_counter<<32;
  661         tmp_counter += ntohl(ch->carp_counter[1]);
  662 
  663         /* XXX Replay protection goes here */
  664 
  665         sc->sc_init_counter = 0;
  666         sc->sc_counter = tmp_counter;
  667 
  668 
  669         sc_tv.tv_sec = sc->sc_advbase;
  670         if (carp_suppress_preempt && sc->sc_advskew <  240)
  671                 sc_tv.tv_usec = 240 * 1000000 / 256;
  672         else
  673                 sc_tv.tv_usec = sc->sc_advskew * 1000000 / 256;
  674         ch_tv.tv_sec = ch->carp_advbase;
  675         ch_tv.tv_usec = ch->carp_advskew * 1000000 / 256;
  676 
  677         switch (sc->sc_state) {
  678         case INIT:
  679                 break;
  680         case MASTER:
  681                 /*
  682                  * If we receive an advertisement from a backup who's going to
  683                  * be more frequent than us, go into BACKUP state.
  684                  */
  685                 if (timercmp(&sc_tv, &ch_tv, >) ||
  686                     timercmp(&sc_tv, &ch_tv, ==)) {
  687                         callout_stop(&sc->sc_ad_tmo);
  688                         carp_set_state(sc, BACKUP);
  689                         carp_setrun(sc, 0);
  690                         carp_setroute(sc, RTM_DELETE);
  691                 }
  692                 break;
  693         case BACKUP:
  694                 /*
  695                  * If we're pre-empting masters who advertise slower than us,
  696                  * and this one claims to be slower, treat him as down.
  697                  */
  698                 if (carp_opts[CARPCTL_PREEMPT] && timercmp(&sc_tv, &ch_tv, <)) {
  699                         carp_master_down(sc);
  700                         break;
  701                 }
  702 
  703                 /*
  704                  *  If the master is going to advertise at such a low frequency
  705                  *  that he's guaranteed to time out, we'd might as well just
  706                  *  treat him as timed out now.
  707                  */
  708                 sc_tv.tv_sec = sc->sc_advbase * 3;
  709                 if (timercmp(&sc_tv, &ch_tv, <)) {
  710                         carp_master_down(sc);
  711                         break;
  712                 }
  713 
  714                 /*
  715                  * Otherwise, we reset the counter and wait for the next
  716                  * advertisement.
  717                  */
  718                 carp_setrun(sc, af);
  719                 break;
  720         }
  721 
  722         m_freem(m);
  723         return;
  724 }
  725 
  726 /*
  727  * Interface side of the CARP implementation.
  728  */
  729 
  730 /* ARGSUSED */
  731 void
  732 carpattach(int n)
  733 {
  734         if_clone_attach(&carp_cloner);
  735 }
  736 
  737 int
  738 carp_clone_create(struct if_clone *ifc, int unit)
  739 {
  740         extern int ifqmaxlen;
  741         struct carp_softc *sc;
  742         struct ifnet *ifp;
  743 
  744         sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
  745         if (!sc)
  746                 return (ENOMEM);
  747         bzero(sc, sizeof(*sc));
  748 
  749         sc->sc_suppress = 0;
  750         sc->sc_advbase = CARP_DFLTINTV;
  751         sc->sc_vhid = -1;       /* required setting */
  752         sc->sc_advskew = 0;
  753         sc->sc_init_counter = 1;
  754         sc->sc_naddrs = sc->sc_naddrs6 = 0;
  755 #ifdef INET6
  756         sc->sc_im6o.im6o_multicast_hlim = CARP_DFLTTL;
  757 #endif /* INET6 */
  758 
  759         callout_init(&sc->sc_ad_tmo);
  760         callout_init(&sc->sc_md_tmo);
  761         callout_init(&sc->sc_md6_tmo);
  762 
  763         callout_setfunc(&sc->sc_ad_tmo, carp_send_ad, sc);
  764         callout_setfunc(&sc->sc_md_tmo, carp_master_down, sc);
  765         callout_setfunc(&sc->sc_md6_tmo, carp_master_down, sc);
  766 
  767         LIST_INIT(&sc->carp_mc_listhead);
  768         ifp = &sc->sc_if;
  769         ifp->if_softc = sc;
  770         snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
  771             unit);
  772         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  773         ifp->if_ioctl = carp_ioctl;
  774         ifp->if_start = carp_start;
  775         ifp->if_output = carp_output;
  776         ifp->if_type = IFT_CARP;
  777         ifp->if_addrlen = ETHER_ADDR_LEN;
  778         ifp->if_hdrlen = ETHER_HDR_LEN;
  779         ifp->if_mtu = ETHERMTU;
  780         IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
  781         IFQ_SET_READY(&ifp->if_snd);
  782         if_attach(ifp);
  783 
  784         if_alloc_sadl(ifp);
  785         ifp->if_broadcastaddr = etherbroadcastaddr;
  786         carp_set_enaddr(sc);
  787         LIST_INIT(&sc->sc_ac.ec_multiaddrs);
  788 #if NBPFILTER > 0
  789         bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN);
  790 #endif
  791         return (0);
  792 }
  793 
  794 int
  795 carp_clone_destroy(struct ifnet *ifp)
  796 {
  797         carpdetach(ifp->if_softc);
  798         ether_ifdetach(ifp);
  799         if_detach(ifp);
  800         free(ifp->if_softc, M_DEVBUF);
  801 
  802         return (0);
  803 }
  804 
  805 void
  806 carpdetach(struct carp_softc *sc)
  807 {
  808         struct carp_if *cif;
  809         int s;
  810 
  811         callout_stop(&sc->sc_ad_tmo);
  812         callout_stop(&sc->sc_md_tmo);
  813         callout_stop(&sc->sc_md6_tmo);
  814 
  815         if (sc->sc_suppress)
  816                 carp_suppress_preempt--;
  817         sc->sc_suppress = 0;
  818 
  819         if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS)
  820                 carp_suppress_preempt--;
  821         sc->sc_sendad_errors = 0;
  822 
  823         carp_set_state(sc, INIT);
  824         sc->sc_if.if_flags &= ~IFF_UP;
  825         carp_setrun(sc, 0);
  826         carp_multicast_cleanup(sc);
  827 
  828         s = splnet();
  829         if (sc->sc_carpdev != NULL) {
  830                 /* XXX linkstatehook removal */
  831                 cif = (struct carp_if *)sc->sc_carpdev->if_carp;
  832                 TAILQ_REMOVE(&cif->vhif_vrs, sc, sc_list);
  833                 if (!--cif->vhif_nvrs) {
  834                         ifpromisc(sc->sc_carpdev, 0);
  835                         sc->sc_carpdev->if_carp = NULL;
  836                         FREE(cif, M_IFADDR);
  837                 }
  838         }
  839         sc->sc_carpdev = NULL;
  840         splx(s);
  841 }
  842 
  843 /* Detach an interface from the carp. */
  844 void
  845 carp_ifdetach(struct ifnet *ifp)
  846 {
  847         struct carp_softc *sc, *nextsc;
  848         struct carp_if *cif = (struct carp_if *)ifp->if_carp;
  849 
  850         for (sc = TAILQ_FIRST(&cif->vhif_vrs); sc; sc = nextsc) {
  851                 nextsc = TAILQ_NEXT(sc, sc_list);
  852                 carpdetach(sc);
  853         }
  854 }
  855 
  856 int
  857 carp_prepare_ad(struct mbuf *m, struct carp_softc *sc,
  858     struct carp_header *ch)
  859 {
  860         if (sc->sc_init_counter) {
  861                 /* this could also be seconds since unix epoch */
  862                 sc->sc_counter = arc4random();
  863                 sc->sc_counter = sc->sc_counter << 32;
  864                 sc->sc_counter += arc4random();
  865         } else
  866                 sc->sc_counter++;
  867 
  868         ch->carp_counter[0] = htonl((sc->sc_counter>>32)&0xffffffff);
  869         ch->carp_counter[1] = htonl(sc->sc_counter&0xffffffff);
  870 
  871         carp_hmac_generate(sc, ch->carp_counter, ch->carp_md);
  872 
  873         return (0);
  874 }
  875 
  876 void
  877 carp_send_ad_all(void)
  878 {
  879         struct ifnet *ifp;
  880         struct carp_if *cif;
  881         struct carp_softc *vh;
  882 
  883         TAILQ_FOREACH(ifp, &ifnet, if_list) {
  884                 if (ifp->if_carp == NULL || ifp->if_type == IFT_CARP)
  885                         continue;
  886 
  887                 cif = (struct carp_if *)ifp->if_carp;
  888                 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
  889                         if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
  890                             (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER)
  891                                 carp_send_ad(vh);
  892                 }
  893         }
  894 }
  895 
  896 
  897 void
  898 carp_send_ad(void *v)
  899 {
  900         struct carp_header ch;
  901         struct timeval tv;
  902         struct carp_softc *sc = v;
  903         struct carp_header *ch_ptr;
  904         struct mbuf *m;
  905         int error, len, advbase, advskew, s;
  906         struct ifaddr *ifa;
  907         struct sockaddr sa;
  908 
  909         s = splsoftnet();
  910 
  911         advbase = advskew = 0; /* Sssssh compiler */
  912         if (sc->sc_carpdev == NULL) {
  913                 sc->sc_if.if_oerrors++;
  914                 goto retry_later;
  915         }
  916 
  917         /* bow out if we've gone to backup (the carp interface is going down) */
  918         if (sc->sc_bow_out) {
  919                 sc->sc_bow_out = 0;
  920                 advbase = 255;
  921                 advskew = 255;
  922         } else {
  923                 advbase = sc->sc_advbase;
  924                 if (!carp_suppress_preempt || sc->sc_advskew > 240)
  925                         advskew = sc->sc_advskew;
  926                 else
  927                         advskew = 240;
  928                 tv.tv_sec = advbase;
  929                 tv.tv_usec = advskew * 1000000 / 256;
  930         }
  931 
  932         ch.carp_version = CARP_VERSION;
  933         ch.carp_type = CARP_ADVERTISEMENT;
  934         ch.carp_vhid = sc->sc_vhid;
  935         ch.carp_advbase = advbase;
  936         ch.carp_advskew = advskew;
  937         ch.carp_authlen = 7;    /* XXX DEFINE */
  938         ch.carp_pad1 = 0;       /* must be zero */
  939         ch.carp_cksum = 0;
  940 
  941 
  942 #ifdef INET
  943         if (sc->sc_naddrs) {
  944                 struct ip *ip;
  945 
  946                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
  947                 if (m == NULL) {
  948                         sc->sc_if.if_oerrors++;
  949                         carpstats.carps_onomem++;
  950                         /* XXX maybe less ? */
  951                         goto retry_later;
  952                 }
  953                 len = sizeof(*ip) + sizeof(ch);
  954                 m->m_pkthdr.len = len;
  955                 m->m_pkthdr.rcvif = NULL;
  956                 m->m_len = len;
  957                 MH_ALIGN(m, m->m_len);
  958                 m->m_flags |= M_MCAST;
  959                 ip = mtod(m, struct ip *);
  960                 ip->ip_v = IPVERSION;
  961                 ip->ip_hl = sizeof(*ip) >> 2;
  962                 ip->ip_tos = IPTOS_LOWDELAY;
  963                 ip->ip_len = htons(len);
  964                 ip->ip_id = htons(ip_randomid());
  965                 ip->ip_off = htons(IP_DF);
  966                 ip->ip_ttl = CARP_DFLTTL;
  967                 ip->ip_p = IPPROTO_CARP;
  968                 ip->ip_sum = 0;
  969 
  970                 bzero(&sa, sizeof(sa));
  971                 sa.sa_family = AF_INET;
  972                 ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
  973                 if (ifa == NULL)
  974                         ip->ip_src.s_addr = 0;
  975                 else
  976                         ip->ip_src.s_addr =
  977                             ifatoia(ifa)->ia_addr.sin_addr.s_addr;
  978                 ip->ip_dst.s_addr = INADDR_CARP_GROUP;
  979 
  980                 ch_ptr = (struct carp_header *)(&ip[1]);
  981                 bcopy(&ch, ch_ptr, sizeof(ch));
  982                 if (carp_prepare_ad(m, sc, ch_ptr))
  983                         goto retry_later;
  984 
  985                 m->m_data += sizeof(*ip);
  986                 ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip));
  987                 m->m_data -= sizeof(*ip);
  988 
  989                 microtime(&sc->sc_if.if_lastchange);
  990                 sc->sc_if.if_opackets++;
  991                 sc->sc_if.if_obytes += len;
  992                 carpstats.carps_opackets++;
  993 
  994                 error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo,
  995                     NULL);
  996                 if (error) {
  997                         if (error == ENOBUFS)
  998                                 carpstats.carps_onomem++;
  999                         else
 1000                                 CARP_LOG(sc, ("ip_output failed: %d", error));
 1001                         sc->sc_if.if_oerrors++;
 1002                         if (sc->sc_sendad_errors < INT_MAX)
 1003                                 sc->sc_sendad_errors++;
 1004                         if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) {
 1005                                 carp_suppress_preempt++;
 1006                                 if (carp_suppress_preempt == 1)
 1007                                         carp_send_ad_all();
 1008                         }
 1009                         sc->sc_sendad_success = 0;
 1010                 } else {
 1011                         if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
 1012                                 if (++sc->sc_sendad_success >=
 1013                                     CARP_SENDAD_MIN_SUCCESS) {
 1014                                         carp_suppress_preempt--;
 1015                                         sc->sc_sendad_errors = 0;
 1016                                 }
 1017                         } else
 1018                                 sc->sc_sendad_errors = 0;
 1019                 }
 1020         }
 1021 #endif /* INET */
 1022 #ifdef INET6
 1023         if (sc->sc_naddrs6) {
 1024                 struct ip6_hdr *ip6;
 1025 
 1026                 MGETHDR(m, M_DONTWAIT, MT_HEADER);
 1027                 if (m == NULL) {
 1028                         sc->sc_if.if_oerrors++;
 1029                         carpstats.carps_onomem++;
 1030                         /* XXX maybe less ? */
 1031                         goto retry_later;
 1032                 }
 1033                 len = sizeof(*ip6) + sizeof(ch);
 1034                 m->m_pkthdr.len = len;
 1035                 m->m_pkthdr.rcvif = NULL;
 1036                 m->m_len = len;
 1037                 MH_ALIGN(m, m->m_len);
 1038                 m->m_flags |= M_MCAST;
 1039                 ip6 = mtod(m, struct ip6_hdr *);
 1040                 bzero(ip6, sizeof(*ip6));
 1041                 ip6->ip6_vfc |= IPV6_VERSION;
 1042                 ip6->ip6_hlim = CARP_DFLTTL;
 1043                 ip6->ip6_nxt = IPPROTO_CARP;
 1044 
 1045                 /* set the source address */
 1046                 bzero(&sa, sizeof(sa));
 1047                 sa.sa_family = AF_INET6;
 1048                 ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
 1049                 if (ifa == NULL)        /* This should never happen with IPv6 */
 1050                         bzero(&ip6->ip6_src, sizeof(struct in6_addr));
 1051                 else
 1052                         bcopy(ifatoia6(ifa)->ia_addr.sin6_addr.s6_addr,
 1053                             &ip6->ip6_src, sizeof(struct in6_addr));
 1054                 /* set the multicast destination */
 1055 
 1056                 ip6->ip6_dst.s6_addr8[0] = 0xff;
 1057                 ip6->ip6_dst.s6_addr8[1] = 0x02;
 1058                 ip6->ip6_dst.s6_addr8[15] = 0x12;
 1059 
 1060                 ch_ptr = (struct carp_header *)(&ip6[1]);
 1061                 bcopy(&ch, ch_ptr, sizeof(ch));
 1062                 if (carp_prepare_ad(m, sc, ch_ptr))
 1063                         goto retry_later;
 1064 
 1065                 m->m_data += sizeof(*ip6);
 1066                 ch_ptr->carp_cksum = carp_cksum(m, len - sizeof(*ip6));
 1067                 m->m_data -= sizeof(*ip6);
 1068 
 1069                 microtime(&sc->sc_if.if_lastchange);
 1070                 sc->sc_if.if_opackets++;
 1071                 sc->sc_if.if_obytes += len;
 1072                 carpstats.carps_opackets6++;
 1073 
 1074                 error = ip6_output(m, NULL, NULL, 0, &sc->sc_im6o, NULL, NULL);
 1075                 if (error) {
 1076                         if (error == ENOBUFS)
 1077                                 carpstats.carps_onomem++;
 1078                         else
 1079                                 CARP_LOG(sc, ("ip6_output failed: %d", error));
 1080                         sc->sc_if.if_oerrors++;
 1081                         if (sc->sc_sendad_errors < INT_MAX)
 1082                                 sc->sc_sendad_errors++;
 1083                         if (sc->sc_sendad_errors == CARP_SENDAD_MAX_ERRORS) {
 1084                                 carp_suppress_preempt++;
 1085                                 if (carp_suppress_preempt == 1)
 1086                                         carp_send_ad_all();
 1087                         }
 1088                         sc->sc_sendad_success = 0;
 1089                 } else {
 1090                         if (sc->sc_sendad_errors >= CARP_SENDAD_MAX_ERRORS) {
 1091                                 if (++sc->sc_sendad_success >=
 1092                                     CARP_SENDAD_MIN_SUCCESS) {
 1093                                         carp_suppress_preempt--;
 1094                                         sc->sc_sendad_errors = 0;
 1095                                 }
 1096                         } else
 1097                                 sc->sc_sendad_errors = 0;
 1098                 }
 1099         }
 1100 #endif /* INET6 */
 1101 
 1102 retry_later:
 1103         splx(s);
 1104         if (advbase != 255 || advskew != 255)
 1105                 callout_schedule(&sc->sc_ad_tmo, tvtohz(&tv));
 1106 }
 1107 
 1108 /*
 1109  * Broadcast a gratuitous ARP request containing
 1110  * the virtual router MAC address for each IP address
 1111  * associated with the virtual router.
 1112  */
 1113 void
 1114 carp_send_arp(struct carp_softc *sc)
 1115 {
 1116         struct ifaddr *ifa;
 1117         struct in_addr *in;
 1118         int s = splsoftnet();
 1119 
 1120         TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
 1121 
 1122                 if (ifa->ifa_addr->sa_family != AF_INET)
 1123                         continue;
 1124 
 1125                 in = &ifatoia(ifa)->ia_addr.sin_addr;
 1126                 arprequest(sc->sc_carpdev, in, in, LLADDR(sc->sc_if.if_sadl));
 1127                 DELAY(1000);    /* XXX */
 1128         }
 1129         splx(s);
 1130 }
 1131 
 1132 #ifdef INET6
 1133 void
 1134 carp_send_na(struct carp_softc *sc)
 1135 {
 1136         struct ifaddr *ifa;
 1137         struct in6_addr *in6;
 1138         static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
 1139         int s = splsoftnet();
 1140 
 1141         TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
 1142 
 1143                 if (ifa->ifa_addr->sa_family != AF_INET6)
 1144                         continue;
 1145 
 1146                 in6 = &ifatoia6(ifa)->ia_addr.sin6_addr;
 1147                 nd6_na_output(sc->sc_carpdev, &mcast, in6,
 1148                     ND_NA_FLAG_OVERRIDE, 1, NULL);
 1149                 DELAY(1000);    /* XXX */
 1150         }
 1151         splx(s);
 1152 }
 1153 #endif /* INET6 */
 1154 
 1155 /*
 1156  * Based on bridge_hash() in if_bridge.c
 1157  */
 1158 #define mix(a,b,c) \
 1159         do {                                            \
 1160                 a -= b; a -= c; a ^= (c >> 13);         \
 1161                 b -= c; b -= a; b ^= (a << 8);          \
 1162                 c -= a; c -= b; c ^= (b >> 13);         \
 1163                 a -= b; a -= c; a ^= (c >> 12);         \
 1164                 b -= c; b -= a; b ^= (a << 16);         \
 1165                 c -= a; c -= b; c ^= (b >> 5);          \
 1166                 a -= b; a -= c; a ^= (c >> 3);          \
 1167                 b -= c; b -= a; b ^= (a << 10);         \
 1168                 c -= a; c -= b; c ^= (b >> 15);         \
 1169         } while (0)
 1170 
 1171 u_int32_t
 1172 carp_hash(struct carp_softc *sc, u_char *src)
 1173 {
 1174         u_int32_t a = 0x9e3779b9, b = sc->sc_hashkey[0], c = sc->sc_hashkey[1];
 1175 
 1176         c += sc->sc_key[3] << 24;
 1177         c += sc->sc_key[2] << 16;
 1178         c += sc->sc_key[1] << 8;
 1179         c += sc->sc_key[0];
 1180         b += src[5] << 8;
 1181         b += src[4];
 1182         a += src[3] << 24;
 1183         a += src[2] << 16;
 1184         a += src[1] << 8;
 1185         a += src[0];
 1186 
 1187         mix(a, b, c);
 1188         return (c);
 1189 }
 1190 
 1191 int
 1192 carp_addrcount(struct carp_if *cif, struct in_ifaddr *ia, int type)
 1193 {
 1194         struct carp_softc *vh;
 1195         struct ifaddr *ifa;
 1196         int count = 0;
 1197 
 1198         TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
 1199                 if ((type == CARP_COUNT_RUNNING &&
 1200                     (vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
 1201                     (IFF_UP|IFF_RUNNING)) ||
 1202                     (type == CARP_COUNT_MASTER && vh->sc_state == MASTER)) {
 1203                         TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) {
 1204                                 if (ifa->ifa_addr->sa_family == AF_INET &&
 1205                                     ia->ia_addr.sin_addr.s_addr ==
 1206                                     ifatoia(ifa)->ia_addr.sin_addr.s_addr)
 1207                                         count++;
 1208                         }
 1209                 }
 1210         }
 1211         return (count);
 1212 }
 1213 
 1214 int
 1215 carp_iamatch(struct in_ifaddr *ia, u_char *src,
 1216     u_int32_t *count, u_int32_t index)
 1217 {
 1218         struct carp_softc *sc = ia->ia_ifp->if_softc;
 1219 
 1220         if (carp_opts[CARPCTL_ARPBALANCE]) {
 1221                 /*
 1222                  * We use the source ip to decide which virtual host should
 1223                  * handle the request. If we're master of that virtual host,
 1224                  * then we respond, otherwise, just drop the arp packet on
 1225                  * the floor.
 1226                  */
 1227 
 1228                 /* Count the elegible carp interfaces with this address */
 1229                 if (*count == 0)
 1230                         *count = carp_addrcount(
 1231                             (struct carp_if *)ia->ia_ifp->if_carpdev->if_carp,
 1232                             ia, CARP_COUNT_RUNNING);
 1233 
 1234                 /* This should never happen, but... */
 1235                 if (*count == 0)
 1236                         return (0);
 1237 
 1238                 if (carp_hash(sc, src) % *count == index - 1 &&
 1239                     sc->sc_state == MASTER) {
 1240                         return (1);
 1241                 }
 1242         } else {
 1243                 if (sc->sc_state == MASTER)
 1244                         return (1);
 1245         }
 1246 
 1247         return (0);
 1248 }
 1249 
 1250 #ifdef INET6
 1251 struct ifaddr *
 1252 carp_iamatch6(void *v, struct in6_addr *taddr)
 1253 {
 1254         struct carp_if *cif = v;
 1255         struct carp_softc *vh;
 1256         struct ifaddr *ifa;
 1257 
 1258         TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
 1259                 TAILQ_FOREACH(ifa, &vh->sc_if.if_addrlist, ifa_list) {
 1260                         if (IN6_ARE_ADDR_EQUAL(taddr,
 1261                             &ifatoia6(ifa)->ia_addr.sin6_addr) &&
 1262                             ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
 1263                             (IFF_UP|IFF_RUNNING)) && vh->sc_state == MASTER)
 1264                                 return (ifa);
 1265                 }
 1266         }
 1267 
 1268         return (NULL);
 1269 }
 1270 #endif /* INET6 */
 1271 
 1272 struct ifnet *
 1273 carp_ourether(void *v, struct ether_header *eh, u_char iftype, int src)
 1274 {
 1275         struct carp_if *cif = (struct carp_if *)v;
 1276         struct carp_softc *vh;
 1277         u_int8_t *ena;
 1278 
 1279         if (src)
 1280                 ena = (u_int8_t *)&eh->ether_shost;
 1281         else
 1282                 ena = (u_int8_t *)&eh->ether_dhost;
 1283 
 1284         switch (iftype) {
 1285         case IFT_ETHER:
 1286         case IFT_FDDI:
 1287                 if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1)
 1288                         return (NULL);
 1289                 break;
 1290         case IFT_ISO88025:
 1291                 if (ena[0] != 3 || ena[1] || ena[4] || ena[5])
 1292                         return (NULL);
 1293                 break;
 1294         default:
 1295                 return (NULL);
 1296                 break;
 1297         }
 1298 
 1299         TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list)
 1300                 if ((vh->sc_if.if_flags & (IFF_UP|IFF_RUNNING)) ==
 1301                     (IFF_UP|IFF_RUNNING) && vh->sc_state == MASTER &&
 1302                     !bcmp(ena, LLADDR(vh->sc_if.if_sadl),
 1303                     ETHER_ADDR_LEN)) {
 1304                         return (&vh->sc_if);
 1305                     }
 1306 
 1307         return (NULL);
 1308 }
 1309 
 1310 int
 1311 carp_input(struct mbuf *m, u_int8_t *shost, u_int8_t *dhost, u_int16_t etype)
 1312 {
 1313         struct ether_header eh;
 1314         struct carp_if *cif = (struct carp_if *)m->m_pkthdr.rcvif->if_carp;
 1315         struct ifnet *ifp;
 1316 
 1317         bcopy(shost, &eh.ether_shost, sizeof(eh.ether_shost));
 1318         bcopy(dhost, &eh.ether_dhost, sizeof(eh.ether_dhost));
 1319         eh.ether_type = etype;
 1320 
 1321         if (m->m_flags & (M_BCAST|M_MCAST)) {
 1322                 struct carp_softc *vh;
 1323                 struct mbuf *m0;
 1324 
 1325                 /*
 1326                  * XXX Should really check the list of multicast addresses
 1327                  * for each CARP interface _before_ copying.
 1328                  */
 1329                 TAILQ_FOREACH(vh, &cif->vhif_vrs, sc_list) {
 1330                         m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
 1331                         if (m0 == NULL)
 1332                                 continue;
 1333                         m0->m_pkthdr.rcvif = &vh->sc_if;
 1334                         ether_input(&vh->sc_if, m0);
 1335                 }
 1336                 return (1);
 1337         }
 1338 
 1339         ifp = carp_ourether(cif, &eh, m->m_pkthdr.rcvif->if_type, 0);
 1340         if (ifp == NULL) {
 1341                 return (1);
 1342         }
 1343 
 1344         m->m_pkthdr.rcvif = ifp;
 1345 
 1346 #if NBPFILTER > 0
 1347         if (ifp->if_bpf)
 1348                 bpf_mtap(ifp->if_bpf, m);
 1349 #endif
 1350         ifp->if_ipackets++;
 1351         ether_input(ifp, m);
 1352         return (0);
 1353 }
 1354 
 1355 void
 1356 carp_master_down(void *v)
 1357 {
 1358         struct carp_softc *sc = v;
 1359 
 1360         switch (sc->sc_state) {
 1361         case INIT:
 1362                 printf("%s: master_down event in INIT state\n",
 1363                     sc->sc_if.if_xname);
 1364                 break;
 1365         case MASTER:
 1366                 break;
 1367         case BACKUP:
 1368                 carp_set_state(sc, MASTER);
 1369                 carp_send_ad(sc);
 1370                 carp_send_arp(sc);
 1371 #ifdef INET6
 1372                 carp_send_na(sc);
 1373 #endif /* INET6 */
 1374                 carp_setrun(sc, 0);
 1375                 carp_setroute(sc, RTM_ADD);
 1376                 break;
 1377         }
 1378 }
 1379 
 1380 /*
 1381  * When in backup state, af indicates whether to reset the master down timer
 1382  * for v4 or v6. If it's set to zero, reset the ones which are already pending.
 1383  */
 1384 void
 1385 carp_setrun(struct carp_softc *sc, sa_family_t af)
 1386 {
 1387         struct timeval tv;
 1388 
 1389         if (sc->sc_carpdev == NULL) {
 1390                 sc->sc_if.if_flags &= ~IFF_RUNNING;
 1391                 carp_set_state(sc, INIT);
 1392                 return;
 1393         }
 1394 
 1395         if (sc->sc_if.if_flags & IFF_UP && sc->sc_vhid > 0 &&
 1396             (sc->sc_naddrs || sc->sc_naddrs6) && !sc->sc_suppress) {
 1397                 sc->sc_if.if_flags |= IFF_RUNNING;
 1398         } else {
 1399                 sc->sc_if.if_flags &= ~IFF_RUNNING;
 1400                 carp_setroute(sc, RTM_DELETE);
 1401                 return;
 1402         }
 1403 
 1404         switch (sc->sc_state) {
 1405         case INIT:
 1406                 carp_set_state(sc, BACKUP);
 1407                 carp_setroute(sc, RTM_DELETE);
 1408                 carp_setrun(sc, 0);
 1409                 break;
 1410         case BACKUP:
 1411                 callout_stop(&sc->sc_ad_tmo);
 1412                 tv.tv_sec = 3 * sc->sc_advbase;
 1413                 tv.tv_usec = sc->sc_advskew * 1000000 / 256;
 1414                 switch (af) {
 1415 #ifdef INET
 1416                 case AF_INET:
 1417                         callout_schedule(&sc->sc_md_tmo, tvtohz(&tv));
 1418                         break;
 1419 #endif /* INET */
 1420 #ifdef INET6
 1421                 case AF_INET6:
 1422                         callout_schedule(&sc->sc_md6_tmo, tvtohz(&tv));
 1423                         break;
 1424 #endif /* INET6 */
 1425                 default:
 1426                         if (sc->sc_naddrs)
 1427                                 callout_schedule(&sc->sc_md_tmo, tvtohz(&tv));
 1428                         if (sc->sc_naddrs6)
 1429                                 callout_schedule(&sc->sc_md6_tmo, tvtohz(&tv));
 1430                         break;
 1431                 }
 1432                 break;
 1433         case MASTER:
 1434                 tv.tv_sec = sc->sc_advbase;
 1435                 tv.tv_usec = sc->sc_advskew * 1000000 / 256;
 1436                 callout_schedule(&sc->sc_ad_tmo, tvtohz(&tv));
 1437                 break;
 1438         }
 1439 }
 1440 
 1441 void
 1442 carp_multicast_cleanup(struct carp_softc *sc)
 1443 {
 1444         struct ip_moptions *imo = &sc->sc_imo;
 1445 #ifdef INET6
 1446         struct ip6_moptions *im6o = &sc->sc_im6o;
 1447 #endif
 1448         u_int16_t n = imo->imo_num_memberships;
 1449 
 1450         /* Clean up our own multicast memberships */
 1451         while (n-- > 0) {
 1452                 if (imo->imo_membership[n] != NULL) {
 1453                         in_delmulti(imo->imo_membership[n]);
 1454                         imo->imo_membership[n] = NULL;
 1455                 }
 1456         }
 1457         imo->imo_num_memberships = 0;
 1458         imo->imo_multicast_ifp = NULL;
 1459 
 1460 #ifdef INET6
 1461         while (!LIST_EMPTY(&im6o->im6o_memberships)) {
 1462                 struct in6_multi_mship *imm =
 1463                     LIST_FIRST(&im6o->im6o_memberships);
 1464 
 1465                 LIST_REMOVE(imm, i6mm_chain);
 1466                 in6_leavegroup(imm);
 1467         }
 1468         im6o->im6o_multicast_ifp = NULL;
 1469 #endif
 1470 
 1471         /* And any other multicast memberships */
 1472         carp_ether_purgemulti(sc);
 1473 }
 1474 
 1475 int
 1476 carp_set_ifp(struct carp_softc *sc, struct ifnet *ifp)
 1477 {
 1478         struct carp_if *cif, *ncif = NULL;
 1479         struct carp_softc *vr, *after = NULL;
 1480         int myself = 0, error = 0;
 1481         int s;
 1482 
 1483         if (ifp == sc->sc_carpdev)
 1484                 return (0);
 1485 
 1486         if (ifp != NULL) {
 1487                 if ((ifp->if_flags & IFF_MULTICAST) == 0)
 1488                         return (EADDRNOTAVAIL);
 1489 
 1490                 if (ifp->if_type == IFT_CARP)
 1491                         return (EINVAL);
 1492 
 1493                 if (ifp->if_carp == NULL) {
 1494                         MALLOC(ncif, struct carp_if *, sizeof(*cif),
 1495                             M_IFADDR, M_NOWAIT);
 1496                         if (ncif == NULL)
 1497                                 return (ENOBUFS);
 1498                         if ((error = ifpromisc(ifp, 1))) {
 1499                                 FREE(ncif, M_IFADDR);
 1500                                 return (error);
 1501                         }
 1502 
 1503                         ncif->vhif_ifp = ifp;
 1504                         TAILQ_INIT(&ncif->vhif_vrs);
 1505                 } else {
 1506                         cif = (struct carp_if *)ifp->if_carp;
 1507                         TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
 1508                                 if (vr != sc && vr->sc_vhid == sc->sc_vhid)
 1509                                         return (EINVAL);
 1510                 }
 1511 
 1512                 /* detach from old interface */
 1513                 if (sc->sc_carpdev != NULL)
 1514                         carpdetach(sc);
 1515 
 1516                 /* join multicast groups */
 1517                 if (sc->sc_naddrs < 0 &&
 1518                     (error = carp_join_multicast(sc)) != 0) {
 1519                         if (ncif != NULL)
 1520                                 FREE(ncif, M_IFADDR);
 1521                         return (error);
 1522                 }
 1523 
 1524 #ifdef INET6
 1525                 if (sc->sc_naddrs6 < 0 &&
 1526                     (error = carp_join_multicast6(sc)) != 0) {
 1527                         if (ncif != NULL)
 1528                                 FREE(ncif, M_IFADDR);
 1529                         carp_multicast_cleanup(sc);
 1530                         return (error);
 1531                 }
 1532 #endif
 1533 
 1534                 /* attach carp interface to physical interface */
 1535                 if (ncif != NULL)
 1536                         ifp->if_carp = (caddr_t)ncif;
 1537                 sc->sc_carpdev = ifp;
 1538                 cif = (struct carp_if *)ifp->if_carp;
 1539                 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list) {
 1540                         if (vr == sc)
 1541                                 myself = 1;
 1542                         if (vr->sc_vhid < sc->sc_vhid)
 1543                                 after = vr;
 1544                 }
 1545 
 1546                 if (!myself) {
 1547                         /* We're trying to keep things in order */
 1548                         if (after == NULL) {
 1549                                 TAILQ_INSERT_TAIL(&cif->vhif_vrs, sc, sc_list);
 1550                         } else {
 1551                                 TAILQ_INSERT_AFTER(&cif->vhif_vrs, after,
 1552                                     sc, sc_list);
 1553                         }
 1554                         cif->vhif_nvrs++;
 1555                 }
 1556                 if (sc->sc_naddrs || sc->sc_naddrs6)
 1557                         sc->sc_if.if_flags |= IFF_UP;
 1558                 carp_set_enaddr(sc);
 1559                 s = splnet();
 1560                 /* XXX linkstatehooks establish */
 1561                 carp_carpdev_state(ifp);
 1562                 splx(s);
 1563         } else {
 1564                 carpdetach(sc);
 1565                 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
 1566         }
 1567         return (0);
 1568 }
 1569 
 1570 void
 1571 carp_set_enaddr(struct carp_softc *sc)
 1572 {
 1573         if (sc->sc_carpdev && sc->sc_carpdev->if_type == IFT_ISO88025) {
 1574                 LLADDR(sc->sc_if.if_sadl)[0] = 3;
 1575                 LLADDR(sc->sc_if.if_sadl)[1] = 0;
 1576                 LLADDR(sc->sc_if.if_sadl)[2] = 0x40 >> (sc->sc_vhid - 1);
 1577                 LLADDR(sc->sc_if.if_sadl)[3] = 0x40000 >> (sc->sc_vhid - 1);
 1578                 LLADDR(sc->sc_if.if_sadl)[4] = 0;
 1579                 LLADDR(sc->sc_if.if_sadl)[5] = 0;
 1580         } else {
 1581                 LLADDR(sc->sc_if.if_sadl)[0] = 0;
 1582                 LLADDR(sc->sc_if.if_sadl)[1] = 0;
 1583                 LLADDR(sc->sc_if.if_sadl)[2] = 0x5e;
 1584                 LLADDR(sc->sc_if.if_sadl)[3] = 0;
 1585                 LLADDR(sc->sc_if.if_sadl)[4] = 1;
 1586                 LLADDR(sc->sc_if.if_sadl)[5] = sc->sc_vhid;
 1587         }
 1588 }
 1589 
 1590 void
 1591 carp_addr_updated(void *v)
 1592 {
 1593         struct carp_softc *sc = (struct carp_softc *) v;
 1594         struct ifaddr *ifa;
 1595         int new_naddrs = 0, new_naddrs6 = 0;
 1596 
 1597         TAILQ_FOREACH(ifa, &sc->sc_if.if_addrlist, ifa_list) {
 1598                 if (ifa->ifa_addr->sa_family == AF_INET)
 1599                         new_naddrs++;
 1600                 else if (ifa->ifa_addr->sa_family == AF_INET6)
 1601                         new_naddrs6++;
 1602         }
 1603 
 1604         /* Handle a callback after SIOCDIFADDR */
 1605         if (new_naddrs < sc->sc_naddrs || new_naddrs6 < sc->sc_naddrs6) {
 1606                 struct in_addr mc_addr;
 1607                 struct in_multi *inm;
 1608 
 1609                 sc->sc_naddrs = new_naddrs;
 1610                 sc->sc_naddrs6 = new_naddrs6;
 1611 
 1612                 /* Re-establish multicast membership removed by in_control */
 1613                 mc_addr.s_addr = INADDR_CARP_GROUP;
 1614                 IN_LOOKUP_MULTI(mc_addr, &sc->sc_if, inm);
 1615                 if (inm == NULL) {
 1616                         bzero(&sc->sc_imo, sizeof(sc->sc_imo));
 1617 
 1618                         if (sc->sc_carpdev != NULL && sc->sc_naddrs > 0)
 1619                                 carp_join_multicast(sc);
 1620                 }
 1621 
 1622                 if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) {
 1623                         sc->sc_if.if_flags &= ~IFF_UP;
 1624                         carp_set_state(sc, INIT);
 1625                 } else
 1626                         carp_hmac_prepare(sc);
 1627         }
 1628 
 1629         carp_setrun(sc, 0);
 1630 }
 1631 
 1632 int
 1633 carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
 1634 {
 1635         struct ifnet *ifp = sc->sc_carpdev;
 1636         struct in_ifaddr *ia, *ia_if;
 1637         int error = 0;
 1638 
 1639         if (sin->sin_addr.s_addr == 0) {
 1640                 if (!(sc->sc_if.if_flags & IFF_UP))
 1641                         carp_set_state(sc, INIT);
 1642                 if (sc->sc_naddrs)
 1643                         sc->sc_if.if_flags |= IFF_UP;
 1644                 carp_setrun(sc, 0);
 1645                 return (0);
 1646         }
 1647 
 1648         /* we have to do this by hand to ensure we don't match on ourselves */
 1649         ia_if = NULL;
 1650         for (ia = TAILQ_FIRST(&in_ifaddrhead); ia;
 1651             ia = TAILQ_NEXT(ia, ia_list)) {
 1652 
 1653                 /* and, yeah, we need a multicast-capable iface too */
 1654                 if (ia->ia_ifp != &sc->sc_if &&
 1655                     ia->ia_ifp->if_type != IFT_CARP &&
 1656                     (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
 1657                     (sin->sin_addr.s_addr & ia->ia_subnetmask) ==
 1658                     ia->ia_subnet) {
 1659                         if (!ia_if)
 1660                                 ia_if = ia;
 1661                 }
 1662         }
 1663 
 1664         if (ia_if) {
 1665                 ia = ia_if;
 1666                 if (ifp) {
 1667                         if (ifp != ia->ia_ifp)
 1668                                 return (EADDRNOTAVAIL);
 1669                 } else {
 1670                         ifp = ia->ia_ifp;
 1671                 }
 1672         }
 1673 
 1674         if ((error = carp_set_ifp(sc, ifp)))
 1675                 return (error);
 1676 
 1677         if (sc->sc_carpdev == NULL)
 1678                 return (EADDRNOTAVAIL);
 1679 
 1680         if (sc->sc_naddrs == 0 && (error = carp_join_multicast(sc)) != 0)
 1681                 return (error);
 1682 
 1683         sc->sc_naddrs++;
 1684         if (sc->sc_carpdev != NULL)
 1685                 sc->sc_if.if_flags |= IFF_UP;
 1686 
 1687         carp_set_state(sc, INIT);
 1688         carp_setrun(sc, 0);
 1689 
 1690         /*
 1691          * Hook if_addrhooks so that we get a callback after in_ifinit has run,
 1692          * to correct any inappropriate routes that it inserted.
 1693          */
 1694         if (sc->ah_cookie == 0) {
 1695                 /* XXX link address hook */
 1696         }
 1697 
 1698         return (0);
 1699 }
 1700 
 1701 int
 1702 carp_join_multicast(struct carp_softc *sc)
 1703 {
 1704         struct ip_moptions *imo = &sc->sc_imo, tmpimo;
 1705         struct in_addr addr;
 1706 
 1707         bzero(&tmpimo, sizeof(tmpimo));
 1708         addr.s_addr = INADDR_CARP_GROUP;
 1709         if ((tmpimo.imo_membership[0] =
 1710             in_addmulti(&addr, &sc->sc_if)) == NULL) {
 1711                 return (ENOBUFS);
 1712         }
 1713 
 1714         imo->imo_membership[0] = tmpimo.imo_membership[0];
 1715         imo->imo_num_memberships = 1;
 1716         imo->imo_multicast_ifp = &sc->sc_if;
 1717         imo->imo_multicast_ttl = CARP_DFLTTL;
 1718         imo->imo_multicast_loop = 0;
 1719         return (0);
 1720 }
 1721 
 1722 
 1723 #ifdef INET6
 1724 int
 1725 carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
 1726 {
 1727         struct ifnet *ifp = sc->sc_carpdev;
 1728         struct in6_ifaddr *ia, *ia_if;
 1729         int error = 0;
 1730 
 1731         if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
 1732                 if (!(sc->sc_if.if_flags & IFF_UP))
 1733                         carp_set_state(sc, INIT);
 1734                 if (sc->sc_naddrs6)
 1735                         sc->sc_if.if_flags |= IFF_UP;
 1736                 carp_setrun(sc, 0);
 1737                 return (0);
 1738         }
 1739 
 1740         /* we have to do this by hand to ensure we don't match on ourselves */
 1741         ia_if = NULL;
 1742         for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
 1743                 int i;
 1744 
 1745                 for (i = 0; i < 4; i++) {
 1746                         if ((sin6->sin6_addr.s6_addr32[i] &
 1747                             ia->ia_prefixmask.sin6_addr.s6_addr32[i]) !=
 1748                             (ia->ia_addr.sin6_addr.s6_addr32[i] &
 1749                             ia->ia_prefixmask.sin6_addr.s6_addr32[i]))
 1750                                 break;
 1751                 }
 1752                 /* and, yeah, we need a multicast-capable iface too */
 1753                 if (ia->ia_ifp != &sc->sc_if &&
 1754                     ia->ia_ifp->if_type != IFT_CARP &&
 1755                     (ia->ia_ifp->if_flags & IFF_MULTICAST) &&
 1756                     (i == 4)) {
 1757                         if (!ia_if)
 1758                                 ia_if = ia;
 1759                 }
 1760         }
 1761 
 1762         if (ia_if) {
 1763                 ia = ia_if;
 1764                 if (sc->sc_carpdev) {
 1765                         if (sc->sc_carpdev != ia->ia_ifp)
 1766                                 return (EADDRNOTAVAIL);
 1767                 } else {
 1768                         ifp = ia->ia_ifp;
 1769                 }
 1770         }
 1771 
 1772         if ((error = carp_set_ifp(sc, ifp)))
 1773                 return (error);
 1774 
 1775         if (sc->sc_carpdev == NULL)
 1776                 return (EADDRNOTAVAIL);
 1777 
 1778         if (sc->sc_naddrs6 == 0 && (error = carp_join_multicast6(sc)) != 0)
 1779                 return (error);
 1780 
 1781         sc->sc_naddrs6++;
 1782         if (sc->sc_carpdev != NULL)
 1783                 sc->sc_if.if_flags |= IFF_UP;
 1784         carp_set_state(sc, INIT);
 1785         carp_setrun(sc, 0);
 1786 
 1787         return (0);
 1788 }
 1789 
 1790 int
 1791 carp_join_multicast6(struct carp_softc *sc)
 1792 {
 1793         struct in6_multi_mship *imm, *imm2;
 1794         struct ip6_moptions *im6o = &sc->sc_im6o;
 1795         struct sockaddr_in6 addr6;
 1796         int error;
 1797 
 1798         /* Join IPv6 CARP multicast group */
 1799         bzero(&addr6, sizeof(addr6));
 1800         addr6.sin6_family = AF_INET6;
 1801         addr6.sin6_len = sizeof(addr6);
 1802         addr6.sin6_addr.s6_addr16[0] = htons(0xff02);
 1803         addr6.sin6_addr.s6_addr16[1] = htons(sc->sc_if.if_index);
 1804         addr6.sin6_addr.s6_addr8[15] = 0x12;
 1805         if ((imm = in6_joingroup(&sc->sc_if,
 1806             &addr6.sin6_addr, &error, 0)) == NULL) {
 1807                 return (error);
 1808         }
 1809         /* join solicited multicast address */
 1810         bzero(&addr6.sin6_addr, sizeof(addr6.sin6_addr));
 1811         addr6.sin6_addr.s6_addr16[0] = htons(0xff02);
 1812         addr6.sin6_addr.s6_addr16[1] = htons(sc->sc_if.if_index);
 1813         addr6.sin6_addr.s6_addr32[1] = 0;
 1814         addr6.sin6_addr.s6_addr32[2] = htonl(1);
 1815         addr6.sin6_addr.s6_addr32[3] = 0;
 1816         addr6.sin6_addr.s6_addr8[12] = 0xff;
 1817         if ((imm2 = in6_joingroup(&sc->sc_if,
 1818             &addr6.sin6_addr, &error, 0)) == NULL) {
 1819                 in6_leavegroup(imm);
 1820                 return (error);
 1821         }
 1822 
 1823         /* apply v6 multicast membership */
 1824         im6o->im6o_multicast_ifp = &sc->sc_if;
 1825         if (imm)
 1826                 LIST_INSERT_HEAD(&im6o->im6o_memberships, imm,
 1827                     i6mm_chain);
 1828         if (imm2)
 1829                 LIST_INSERT_HEAD(&im6o->im6o_memberships, imm2,
 1830                     i6mm_chain);
 1831 
 1832         return (0);
 1833 }
 1834 
 1835 #endif /* INET6 */
 1836 
 1837 int
 1838 carp_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
 1839 {
 1840         struct lwp *l = curlwp;         /* XXX */
 1841         struct carp_softc *sc = ifp->if_softc, *vr;
 1842         struct carpreq carpr;
 1843         struct ifaddr *ifa;
 1844         struct ifreq *ifr;
 1845         struct ifnet *cdev = NULL;
 1846         int error = 0;
 1847 
 1848         ifa = (struct ifaddr *)addr;
 1849         ifr = (struct ifreq *)addr;
 1850 
 1851         switch (cmd) {
 1852         case SIOCSIFADDR:
 1853                 switch (ifa->ifa_addr->sa_family) {
 1854 #ifdef INET
 1855                 case AF_INET:
 1856                         sc->sc_if.if_flags |= IFF_UP;
 1857                         bcopy(ifa->ifa_addr, ifa->ifa_dstaddr,
 1858                             sizeof(struct sockaddr));
 1859                         error = carp_set_addr(sc, satosin(ifa->ifa_addr));
 1860                         break;
 1861 #endif /* INET */
 1862 #ifdef INET6
 1863                 case AF_INET6:
 1864                         sc->sc_if.if_flags|= IFF_UP;
 1865                         error = carp_set_addr6(sc, satosin6(ifa->ifa_addr));
 1866                         break;
 1867 #endif /* INET6 */
 1868                 default:
 1869                         error = EAFNOSUPPORT;
 1870                         break;
 1871                 }
 1872                 break;
 1873 
 1874         case SIOCSIFFLAGS:
 1875                 if (sc->sc_state != INIT && !(ifr->ifr_flags & IFF_UP)) {
 1876                         callout_stop(&sc->sc_ad_tmo);
 1877                         callout_stop(&sc->sc_md_tmo);
 1878                         callout_stop(&sc->sc_md6_tmo);
 1879                         if (sc->sc_state == MASTER) {
 1880                                 /* we need the interface up to bow out */
 1881                                 sc->sc_if.if_flags |= IFF_UP;
 1882                                 sc->sc_bow_out = 1;
 1883                                 carp_send_ad(sc);
 1884                         }
 1885                         sc->sc_if.if_flags &= ~IFF_UP;
 1886                         carp_set_state(sc, INIT);
 1887                         carp_setrun(sc, 0);
 1888                 } else if (sc->sc_state == INIT && (ifr->ifr_flags & IFF_UP)) {
 1889                         sc->sc_if.if_flags |= IFF_UP;
 1890                         carp_setrun(sc, 0);
 1891                 }
 1892                 break;
 1893 
 1894         case SIOCSVH:
 1895                 if (l == NULL)
 1896                         break;
 1897                 if ((error = kauth_authorize_network(l->l_cred,
 1898                     KAUTH_NETWORK_INTERFACE,
 1899                     KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
 1900                     NULL)) != 0)
 1901                         break;
 1902                 if ((error = copyin(ifr->ifr_data, &carpr, sizeof carpr)))
 1903                         break;
 1904                 error = 1;
 1905                 if (carpr.carpr_carpdev[0] != '\0' &&
 1906                     (cdev = ifunit(carpr.carpr_carpdev)) == NULL)
 1907                         return (EINVAL);
 1908                 if ((error = carp_set_ifp(sc, cdev)))
 1909                         return (error);
 1910                 if (sc->sc_state != INIT && carpr.carpr_state != sc->sc_state) {
 1911                         switch (carpr.carpr_state) {
 1912                         case BACKUP:
 1913                                 callout_stop(&sc->sc_ad_tmo);
 1914                                 carp_set_state(sc, BACKUP);
 1915                                 carp_setrun(sc, 0);
 1916                                 carp_setroute(sc, RTM_DELETE);
 1917                                 break;
 1918                         case MASTER:
 1919                                 carp_master_down(sc);
 1920                                 break;
 1921                         default:
 1922                                 break;
 1923                         }
 1924                 }
 1925                 if (carpr.carpr_vhid > 0) {
 1926                         if (carpr.carpr_vhid > 255) {
 1927                                 error = EINVAL;
 1928                                 break;
 1929                         }
 1930                         if (sc->sc_carpdev) {
 1931                                 struct carp_if *cif;
 1932                                 cif = (struct carp_if *)sc->sc_carpdev->if_carp;
 1933                                 TAILQ_FOREACH(vr, &cif->vhif_vrs, sc_list)
 1934                                         if (vr != sc &&
 1935                                             vr->sc_vhid == carpr.carpr_vhid)
 1936                                                 return (EINVAL);
 1937                         }
 1938                         sc->sc_vhid = carpr.carpr_vhid;
 1939                         carp_set_enaddr(sc);
 1940                         carp_set_state(sc, INIT);
 1941                         error--;
 1942                 }
 1943                 if (carpr.carpr_advbase > 0 || carpr.carpr_advskew > 0) {
 1944                         if (carpr.carpr_advskew > 254) {
 1945                                 error = EINVAL;
 1946                                 break;
 1947                         }
 1948                         if (carpr.carpr_advbase > 255) {
 1949                                 error = EINVAL;
 1950                                 break;
 1951                         }
 1952                         sc->sc_advbase = carpr.carpr_advbase;
 1953                         sc->sc_advskew = carpr.carpr_advskew;
 1954                         error--;
 1955                 }
 1956                 bcopy(carpr.carpr_key, sc->sc_key, sizeof(sc->sc_key));
 1957                 if (error > 0)
 1958                         error = EINVAL;
 1959                 else {
 1960                         error = 0;
 1961                         carp_setrun(sc, 0);
 1962                 }
 1963                 break;
 1964 
 1965         case SIOCGVH:
 1966                 bzero(&carpr, sizeof(carpr));
 1967                 if (sc->sc_carpdev != NULL)
 1968                         strlcpy(carpr.carpr_carpdev, sc->sc_carpdev->if_xname,
 1969                             IFNAMSIZ);
 1970                 carpr.carpr_state = sc->sc_state;
 1971                 carpr.carpr_vhid = sc->sc_vhid;
 1972                 carpr.carpr_advbase = sc->sc_advbase;
 1973                 carpr.carpr_advskew = sc->sc_advskew;
 1974 
 1975                 if ((l == NULL) || (error = kauth_authorize_network(l->l_cred,
 1976                     KAUTH_NETWORK_INTERFACE,
 1977                     KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
 1978                     NULL)) != 0)
 1979                         bcopy(sc->sc_key, carpr.carpr_key,
 1980                             sizeof(carpr.carpr_key));
 1981                 error = copyout(&carpr, ifr->ifr_data, sizeof(carpr));
 1982                 break;
 1983 
 1984         case SIOCADDMULTI:
 1985                 error = carp_ether_addmulti(sc, ifr);
 1986                 break;
 1987 
 1988         case SIOCDELMULTI:
 1989                 error = carp_ether_delmulti(sc, ifr);
 1990                 break;
 1991 
 1992         default:
 1993                 error = EINVAL;
 1994         }
 1995 
 1996         carp_hmac_prepare(sc);
 1997         return (error);
 1998 }
 1999 
 2000 
 2001 /*
 2002  * Start output on carp interface. This function should never be called.
 2003  */
 2004 void
 2005 carp_start(struct ifnet *ifp)
 2006 {
 2007 #ifdef DEBUG
 2008         printf("%s: start called\n", ifp->if_xname);
 2009 #endif
 2010 }
 2011 
 2012 int
 2013 carp_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
 2014     struct rtentry *rt)
 2015 {
 2016         struct carp_softc *sc = ((struct carp_softc *)ifp->if_softc);
 2017 
 2018         if (sc->sc_carpdev != NULL && sc->sc_state == MASTER) {
 2019                 return (sc->sc_carpdev->if_output(ifp, m, sa, rt));
 2020         } else {
 2021                 m_freem(m);
 2022                 return (ENETUNREACH);
 2023         }
 2024 }
 2025 
 2026 void
 2027 carp_set_state(struct carp_softc *sc, int state)
 2028 {
 2029         if (sc->sc_state == state)
 2030                 return;
 2031 
 2032         sc->sc_state = state;
 2033         switch (state) {
 2034         case BACKUP:
 2035                 sc->sc_if.if_link_state = LINK_STATE_DOWN;
 2036                 break;
 2037         case MASTER:
 2038                 sc->sc_if.if_link_state = LINK_STATE_UP;
 2039                 break;
 2040         default:
 2041                 sc->sc_if.if_link_state = LINK_STATE_UNKNOWN;
 2042                 break;
 2043         }
 2044         rt_ifmsg(&sc->sc_if);
 2045 }
 2046 
 2047 void
 2048 carp_carpdev_state(void *v)
 2049 {
 2050         struct carp_if *cif;
 2051         struct carp_softc *sc;
 2052         struct ifnet *ifp = v;
 2053 
 2054         if (ifp->if_type == IFT_CARP)
 2055                 return;
 2056 
 2057         cif = (struct carp_if *)ifp->if_carp;
 2058 
 2059         TAILQ_FOREACH(sc, &cif->vhif_vrs, sc_list) {
 2060                 int suppressed = sc->sc_suppress;
 2061 
 2062                 if (sc->sc_carpdev->if_link_state == LINK_STATE_DOWN ||
 2063                     !(sc->sc_carpdev->if_flags & IFF_UP)) {
 2064                         sc->sc_if.if_flags &= ~IFF_RUNNING;
 2065                         callout_stop(&sc->sc_ad_tmo);
 2066                         callout_stop(&sc->sc_md_tmo);
 2067                         callout_stop(&sc->sc_md6_tmo);
 2068                         carp_set_state(sc, INIT);
 2069                         sc->sc_suppress = 1;
 2070                         carp_setrun(sc, 0);
 2071                         if (!suppressed) {
 2072                                 carp_suppress_preempt++;
 2073                                 if (carp_suppress_preempt == 1)
 2074                                         carp_send_ad_all();
 2075                         }
 2076                 } else {
 2077                         carp_set_state(sc, INIT);
 2078                         sc->sc_suppress = 0;
 2079                         carp_setrun(sc, 0);
 2080                         if (suppressed)
 2081                                 carp_suppress_preempt--;
 2082                 }
 2083         }
 2084 }
 2085 
 2086 int
 2087 carp_ether_addmulti(struct carp_softc *sc, struct ifreq *ifr)
 2088 {
 2089         struct ifnet *ifp;
 2090         struct carp_mc_entry *mc;
 2091         u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
 2092         int error;
 2093 
 2094         ifp = sc->sc_carpdev;
 2095         if (ifp == NULL)
 2096                 return (EINVAL);
 2097 
 2098         error = ether_addmulti(ifr, &sc->sc_ac);
 2099         if (error != ENETRESET)
 2100                 return (error);
 2101 
 2102         /*
 2103          * This is new multicast address.  We have to tell parent
 2104          * about it.  Also, remember this multicast address so that
 2105          * we can delete them on unconfigure.
 2106          */
 2107         MALLOC(mc, struct carp_mc_entry *, sizeof(struct carp_mc_entry),
 2108             M_DEVBUF, M_NOWAIT);
 2109         if (mc == NULL) {
 2110                 error = ENOMEM;
 2111                 goto alloc_failed;
 2112         }
 2113 
 2114         /*
 2115          * As ether_addmulti() returns ENETRESET, following two
 2116          * statement shouldn't fail.
 2117          */
 2118         (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
 2119         ETHER_LOOKUP_MULTI(addrlo, addrhi, &sc->sc_ac, mc->mc_enm);
 2120         memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
 2121         LIST_INSERT_HEAD(&sc->carp_mc_listhead, mc, mc_entries);
 2122 
 2123         error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr);
 2124         if (error != 0)
 2125                 goto ioctl_failed;
 2126 
 2127         return (error);
 2128 
 2129  ioctl_failed:
 2130         LIST_REMOVE(mc, mc_entries);
 2131         FREE(mc, M_DEVBUF);
 2132  alloc_failed:
 2133         (void)ether_delmulti(ifr, &sc->sc_ac);
 2134 
 2135         return (error);
 2136 }
 2137 
 2138 int
 2139 carp_ether_delmulti(struct carp_softc *sc, struct ifreq *ifr)
 2140 {
 2141         struct ifnet *ifp;
 2142         struct ether_multi *enm;
 2143         struct carp_mc_entry *mc;
 2144         u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
 2145         int error;
 2146 
 2147         ifp = sc->sc_carpdev;
 2148         if (ifp == NULL)
 2149                 return (EINVAL);
 2150 
 2151         /*
 2152          * Find a key to lookup carp_mc_entry.  We have to do this
 2153          * before calling ether_delmulti for obvious reason.
 2154          */
 2155         if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
 2156                 return (error);
 2157         ETHER_LOOKUP_MULTI(addrlo, addrhi, &sc->sc_ac, enm);
 2158         if (enm == NULL)
 2159                 return (EINVAL);
 2160 
 2161         LIST_FOREACH(mc, &sc->carp_mc_listhead, mc_entries)
 2162                 if (mc->mc_enm == enm)
 2163                         break;
 2164 
 2165         /* We won't delete entries we didn't add */
 2166         if (mc == NULL)
 2167                 return (EINVAL);
 2168 
 2169         error = ether_delmulti(ifr, &sc->sc_ac);
 2170         if (error != ENETRESET)
 2171                 return (error);
 2172 
 2173         /* We no longer use this multicast address.  Tell parent so. */
 2174         error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
 2175         if (error == 0) {
 2176                 /* And forget about this address. */
 2177                 LIST_REMOVE(mc, mc_entries);
 2178                 FREE(mc, M_DEVBUF);
 2179         } else
 2180                 (void)ether_addmulti(ifr, &sc->sc_ac);
 2181         return (error);
 2182 }
 2183 
 2184 /*
 2185  * Delete any multicast address we have asked to add from parent
 2186  * interface.  Called when the carp is being unconfigured.
 2187  */
 2188 void
 2189 carp_ether_purgemulti(struct carp_softc *sc)
 2190 {
 2191         struct ifnet *ifp = sc->sc_carpdev;             /* Parent. */
 2192         struct carp_mc_entry *mc;
 2193         union {
 2194                 struct ifreq ifreq;
 2195                 struct {
 2196                         char ifr_name[IFNAMSIZ];
 2197                         struct sockaddr_storage ifr_ss;
 2198                 } ifreq_storage;
 2199         } u;
 2200         struct ifreq *ifr = &u.ifreq;
 2201 
 2202         if (ifp == NULL)
 2203                 return;
 2204 
 2205         memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
 2206         while ((mc = LIST_FIRST(&sc->carp_mc_listhead)) != NULL) {
 2207                 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
 2208                 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
 2209                 LIST_REMOVE(mc, mc_entries);
 2210                 FREE(mc, M_DEVBUF);
 2211         }
 2212 }
 2213 
 2214 SYSCTL_SETUP(sysctl_net_inet_carp_setup, "sysctl net.inet.carp subtree setup")
 2215 {
 2216 
 2217         sysctl_createv(clog, 0, NULL, NULL,
 2218                        CTLFLAG_PERMANENT,
 2219                        CTLTYPE_NODE, "net", NULL,
 2220                        NULL, 0, NULL, 0,
 2221                        CTL_NET, CTL_EOL);
 2222         sysctl_createv(clog, 0, NULL, NULL,
 2223                        CTLFLAG_PERMANENT,
 2224                        CTLTYPE_NODE, "inet", NULL,
 2225                        NULL, 0, NULL, 0,
 2226                        CTL_NET, PF_INET, CTL_EOL);
 2227         sysctl_createv(clog, 0, NULL, NULL,
 2228                        CTLFLAG_PERMANENT,
 2229                        CTLTYPE_NODE, "carp",
 2230                        SYSCTL_DESCR("CARP related settings"),
 2231                        NULL, 0, NULL, 0,
 2232                        CTL_NET, PF_INET, IPPROTO_CARP, CTL_EOL);
 2233 
 2234         sysctl_createv(clog, 0, NULL, NULL,
 2235                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 2236                        CTLTYPE_INT, "preempt",
 2237                        SYSCTL_DESCR("Enable CARP Preempt"),
 2238                        NULL, 0, &carp_opts[CARPCTL_PREEMPT], 0,
 2239                        CTL_NET, PF_INET, IPPROTO_CARP,
 2240                        CTL_CREATE, CTL_EOL);
 2241         sysctl_createv(clog, 0, NULL, NULL,
 2242                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 2243                        CTLTYPE_INT, "arpbalance",
 2244                        SYSCTL_DESCR("Enable ARP balancing"),
 2245                        NULL, 0, &carp_opts[CARPCTL_ARPBALANCE], 0,
 2246                        CTL_NET, PF_INET, IPPROTO_CARP,
 2247                        CTL_CREATE, CTL_EOL);
 2248         sysctl_createv(clog, 0, NULL, NULL,
 2249                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 2250                        CTLTYPE_INT, "allow",
 2251                        SYSCTL_DESCR("Enable CARP"),
 2252                        NULL, 0, &carp_opts[CARPCTL_ALLOW], 0,
 2253                        CTL_NET, PF_INET, IPPROTO_CARP,
 2254                        CTL_CREATE, CTL_EOL);
 2255         sysctl_createv(clog, 0, NULL, NULL,
 2256                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 2257                        CTLTYPE_INT, "log",
 2258                        SYSCTL_DESCR("CARP logging"),
 2259                        NULL, 0, &carp_opts[CARPCTL_LOG], 0,
 2260                        CTL_NET, PF_INET, IPPROTO_CARP,
 2261                        CTL_CREATE, CTL_EOL);
 2262         sysctl_createv(clog, 0, NULL, NULL,
 2263                        CTLFLAG_PERMANENT,
 2264                        CTLTYPE_STRUCT, "stats",
 2265                        SYSCTL_DESCR("CARP statistics"),
 2266                        NULL, 0, &carpstats, sizeof(carpstats),
 2267                        CTL_NET, PF_INET, IPPROTO_CARP, CARPCTL_STATS,
 2268                        CTL_EOL);
 2269 }

Cache object: c981ebf1359bda053215d41a61807b01


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