[BACK]Return to ip_carp.c CVS log [TXT][DIR] Up to [local] / sys / netinet

Annotation of sys/netinet/ip_carp.c, Revision 1.1

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

CVSweb