Annotation of embedaddon/mrouted/vif.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * The mrouted program is covered by the license in the accompanying file
        !             3:  * named "LICENSE".  Use of the mrouted program represents acceptance of
        !             4:  * the terms and conditions listed in that file.
        !             5:  *
        !             6:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
        !             7:  * Leland Stanford Junior University.
        !             8:  */
        !             9: 
        !            10: #include "defs.h"
        !            11: #include <fcntl.h>
        !            12: 
        !            13: /*
        !            14:  * Exported variables.
        !            15:  */
        !            16: struct uvif    uvifs[MAXVIFS]; /* array of virtual interfaces              */
        !            17: vifi_t         numvifs;        /* number of vifs in use                    */
        !            18: int            vifs_down;      /* 1=>some interfaces are down              */
        !            19: int            phys_vif;       /* An enabled vif                           */
        !            20: int            udp_socket;     /* Since the honkin' kernel doesn't support */
        !            21:                                /* ioctls on raw IP sockets, we need a UDP  */
        !            22:                                /* socket as well as our IGMP (raw) socket. */
        !            23:                                /* How dumb.                                */
        !            24: int            vifs_with_neighbors;    /* == 1 if I am a leaf              */
        !            25: 
        !            26: /*
        !            27:  * Private variables.
        !            28:  */
        !            29: struct listaddr        *nbrs[MAXNBRS]; /* array of neighbors                       */
        !            30: 
        !            31: typedef struct {
        !            32:         vifi_t  vifi;
        !            33:         struct listaddr *g;
        !            34:        int    q_time;
        !            35: } cbk_t;
        !            36: 
        !            37: /*
        !            38:  * Forward declarations.
        !            39:  */
        !            40: static void start_vif(vifi_t vifi);
        !            41: static void start_vif2(vifi_t vifi);
        !            42: static void stop_vif(vifi_t vifi);
        !            43: static void age_old_hosts(void);
        !            44: static void send_probe_on_vif(struct uvif *v);
        !            45: static void send_query(struct uvif *v);
        !            46: static int info_version(u_char *p);
        !            47: static void DelVif(void *arg);
        !            48: static int SetTimer(vifi_t vifi, struct listaddr *g);
        !            49: static int DeleteTimer(int id);
        !            50: static void SendQuery(void *arg);
        !            51: static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time);
        !            52: 
        !            53: /*
        !            54:  * Initialize the virtual interfaces, but do not install
        !            55:  * them in the kernel.  Start routing on all vifs that are
        !            56:  * not down or disabled.
        !            57:  */
        !            58: void init_vifs(void)
        !            59: {
        !            60:     vifi_t vifi;
        !            61:     struct uvif *v;
        !            62:     int enabled_vifs, enabled_phyints;
        !            63:     extern char *configfilename;
        !            64: 
        !            65:     numvifs = 0;
        !            66:     vifs_with_neighbors = 0;
        !            67:     vifs_down = FALSE;
        !            68: 
        !            69:     /*
        !            70:      * Configure the vifs based on the interface configuration of the
        !            71:      * the kernel and the contents of the configuration file.
        !            72:      * (Open a UDP socket for ioctl use in the config procedures if
        !            73:      * the kernel can't handle IOCTL's on the IGMP socket.)
        !            74:      */
        !            75: #ifdef IOCTL_OK_ON_RAW_SOCKET
        !            76:     udp_socket = igmp_socket;
        !            77: #else
        !            78:     if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        !            79:        logit(LOG_ERR, errno, "UDP socket");
        !            80: #endif
        !            81:     logit(LOG_INFO,0,"Getting vifs from kernel interfaces");
        !            82:     config_vifs_from_kernel();
        !            83:     logit(LOG_INFO,0,"Getting vifs from %s",configfilename);
        !            84:     config_vifs_from_file();
        !            85: 
        !            86:     /*
        !            87:      * Quit if there are fewer than two enabled vifs.
        !            88:      */
        !            89:     enabled_vifs    = 0;
        !            90:     enabled_phyints = 0;
        !            91:     phys_vif       = -1;
        !            92:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        !            93:        if (!(v->uv_flags & VIFF_DISABLED)) {
        !            94:            ++enabled_vifs;
        !            95:            if (!(v->uv_flags & VIFF_TUNNEL)) {
        !            96:                if (phys_vif == -1)
        !            97:                    phys_vif = vifi;
        !            98:                ++enabled_phyints;
        !            99:            }
        !           100:        }
        !           101:     }
        !           102:     if (enabled_vifs < 2)
        !           103:        logit(LOG_ERR, 0, "Cannot forward: %s",
        !           104:            enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
        !           105: 
        !           106:     if (enabled_phyints == 0)
        !           107:        logit(LOG_WARNING, 0, "No enabled interfaces, forwarding via tunnels only");
        !           108: 
        !           109:     logit(LOG_INFO, 0, "Installing vifs in mrouted...");
        !           110:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        !           111:        if (!(v->uv_flags & VIFF_DISABLED)) {
        !           112:            if (!(v->uv_flags & VIFF_DOWN)) {
        !           113:                if (v->uv_flags & VIFF_TUNNEL)
        !           114:                    logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
        !           115:                          inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
        !           116:                          inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)));
        !           117:                else
        !           118:                    logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
        !           119:                          inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
        !           120:                start_vif2(vifi);
        !           121:            } else logit(LOG_INFO, 0,
        !           122:                     "%s is not yet up; vif #%u not in service",
        !           123:                     v->uv_name, vifi);
        !           124:        }
        !           125:     }
        !           126: }
        !           127: 
        !           128: /*
        !           129:  * Initialize the passed vif with all appropriate default values.
        !           130:  * "t" is true if a tunnel, or false if a phyint.
        !           131:  */
        !           132: void zero_vif(struct uvif *v, int t)
        !           133: {
        !           134:     v->uv_flags                = 0;
        !           135:     v->uv_metric       = DEFAULT_METRIC;
        !           136:     v->uv_admetric     = 0;
        !           137:     v->uv_threshold    = DEFAULT_THRESHOLD;
        !           138:     v->uv_rate_limit   = t ? DEFAULT_TUN_RATE_LIMIT : DEFAULT_PHY_RATE_LIMIT;
        !           139:     v->uv_lcl_addr     = 0;
        !           140:     v->uv_rmt_addr     = 0;
        !           141:     v->uv_dst_addr     = t ? 0 : dvmrp_group;
        !           142:     v->uv_subnet       = 0;
        !           143:     v->uv_subnetmask   = 0;
        !           144:     v->uv_subnetbcast  = 0;
        !           145:     v->uv_name[0]      = '\0';
        !           146:     v->uv_groups       = NULL;
        !           147:     v->uv_neighbors    = NULL;
        !           148:     NBRM_CLRALL(v->uv_nbrmap);
        !           149:     v->uv_querier      = NULL;
        !           150:     v->uv_igmpv1_warn  = 0;
        !           151:     v->uv_prune_lifetime = 0;
        !           152:     v->uv_leaf_timer   = 0;
        !           153:     v->uv_acl          = NULL;
        !           154:     v->uv_addrs                = NULL;
        !           155:     v->uv_filter       = NULL;
        !           156:     v->uv_blasterbuf   = NULL;
        !           157:     v->uv_blastercur   = NULL;
        !           158:     v->uv_blasterend   = NULL;
        !           159:     v->uv_blasterlen   = 0;
        !           160:     v->uv_blastertimer = 0;
        !           161:     v->uv_nbrup                = 0;
        !           162:     v->uv_icmp_warn    = 0;
        !           163:     v->uv_nroutes      = 0;
        !           164: }
        !           165: 
        !           166: /*
        !           167:  * Start routing on all virtual interfaces that are not down or
        !           168:  * administratively disabled.
        !           169:  */
        !           170: void init_installvifs(void)
        !           171: {
        !           172:     vifi_t vifi;
        !           173:     struct uvif *v;
        !           174: 
        !           175:     logit(LOG_INFO, 0, "Installing vifs in kernel...");
        !           176:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        !           177:        if (!(v->uv_flags & VIFF_DISABLED)) {
        !           178:            if (!(v->uv_flags & VIFF_DOWN)) {
        !           179:                if (v->uv_flags & VIFF_TUNNEL) {
        !           180:                    logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
        !           181:                          inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
        !           182:                          inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)));
        !           183:                } else {
        !           184:                    logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
        !           185:                          inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
        !           186:                }
        !           187:                k_add_vif(vifi, &uvifs[vifi]);
        !           188:            } else {
        !           189:                logit(LOG_INFO, 0, "%s is not yet up; vif #%u not in service",
        !           190:                      v->uv_name, vifi);
        !           191:            }
        !           192:        }
        !           193:     }
        !           194: }
        !           195: 
        !           196: /*
        !           197:  * See if any interfaces have changed from up state to down, or vice versa,
        !           198:  * including any non-multicast-capable interfaces that are in use as local
        !           199:  * tunnel end-points.  Ignore interfaces that have been administratively
        !           200:  * disabled.
        !           201:  */
        !           202: void check_vif_state(void)
        !           203: {
        !           204:     register vifi_t vifi;
        !           205:     register struct uvif *v;
        !           206:     struct ifreq ifr;
        !           207:     static int checking_vifs = 0;
        !           208: 
        !           209:     /*
        !           210:      * If we get an error while checking, (e.g. two interfaces go down
        !           211:      * at once, and we decide to send a prune out one of the failed ones)
        !           212:      * then don't go into an infinite loop!
        !           213:      */
        !           214:     if (checking_vifs)
        !           215:        return;
        !           216: 
        !           217:     vifs_down = FALSE;
        !           218:     checking_vifs = 1;
        !           219:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        !           220: 
        !           221:        if (v->uv_flags & VIFF_DISABLED) continue;
        !           222: 
        !           223:        strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
        !           224:        if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
        !           225:            logit(LOG_ERR, errno, "Failed ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
        !           226: 
        !           227:        if (v->uv_flags & VIFF_DOWN) {
        !           228:            if (ifr.ifr_flags & IFF_UP) {
        !           229:                logit(LOG_NOTICE, 0, "%s has come up; vif #%u now in service",
        !           230:                      v->uv_name, vifi);
        !           231:                v->uv_flags &= ~VIFF_DOWN;
        !           232:                start_vif(vifi);
        !           233:            }
        !           234:            else vifs_down = TRUE;
        !           235:        }
        !           236:        else {
        !           237:            if (!(ifr.ifr_flags & IFF_UP)) {
        !           238:                logit(LOG_NOTICE, 0, "%s has gone down; vif #%u taken out of service",
        !           239:                    v->uv_name, vifi);
        !           240:                stop_vif(vifi);
        !           241:                v->uv_flags |= VIFF_DOWN;
        !           242:                vifs_down = TRUE;
        !           243:            }
        !           244:        }
        !           245:     }
        !           246:     checking_vifs = 0;
        !           247: }
        !           248: 
        !           249: /*
        !           250:  * Send a DVMRP message on the specified vif.  If DVMRP messages are
        !           251:  * to be encapsulated and sent "inside" the tunnel, use the special
        !           252:  * encapsulator.  If it's not a tunnel or DVMRP messages are to be
        !           253:  * sent "beside" the tunnel, as required by earlier versions of mrouted,
        !           254:  * then just send the message.
        !           255:  */
        !           256: void send_on_vif(struct uvif *v, u_int32 dst, int code, size_t datalen)
        !           257: {
        !           258:     u_int32 group = htonl(MROUTED_LEVEL | 
        !           259:                        ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS));
        !           260: 
        !           261:     /*
        !           262:      * The UNIX kernel will not decapsulate unicasts.
        !           263:      * Therefore, we don't send encapsulated unicasts.
        !           264:      */
        !           265:     if ((v->uv_flags & (VIFF_TUNNEL|VIFF_OTUNNEL)) == VIFF_TUNNEL &&
        !           266:        ((dst == 0) || IN_MULTICAST(ntohl(dst))))
        !           267:        send_ipip(v->uv_lcl_addr, dst ? dst : dvmrp_group, IGMP_DVMRP,
        !           268:                                                code, group, datalen, v);
        !           269:     else
        !           270:        send_igmp(v->uv_lcl_addr, dst ? dst : v->uv_dst_addr, IGMP_DVMRP,
        !           271:                                                code, group, datalen);
        !           272: }
        !           273: 
        !           274: 
        !           275: /*
        !           276:  * Send a probe message on vif v
        !           277:  */
        !           278: static void send_probe_on_vif(struct uvif *v)
        !           279: {
        !           280:     char *p;
        !           281:     size_t datalen = 0;
        !           282:     struct listaddr *nbr;
        !           283:     int i;
        !           284: 
        !           285:     if ((v->uv_flags & VIFF_PASSIVE && v->uv_neighbors == NULL) ||
        !           286:        (v->uv_flags & VIFF_FORCE_LEAF))
        !           287:        return;
        !           288: 
        !           289:     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
        !           290: 
        !           291:     for (i = 0; i < 4; i++)
        !           292:        *p++ = ((char *)&(dvmrp_genid))[i];
        !           293:     datalen += 4;
        !           294: 
        !           295:     /*
        !           296:      * add the neighbor list on the interface to the message
        !           297:      */
        !           298:     nbr = v->uv_neighbors;
        !           299: 
        !           300:     while (nbr) {
        !           301:        for (i = 0; i < 4; i++)
        !           302:            *p++ = ((char *)&nbr->al_addr)[i];
        !           303:        datalen +=4;
        !           304:        nbr = nbr->al_next;
        !           305:     }
        !           306: 
        !           307:     send_on_vif(v, 0, DVMRP_PROBE, datalen);
        !           308: }
        !           309: 
        !           310: static void send_query(struct uvif *v)
        !           311: {
        !           312:     IF_DEBUG(DEBUG_IGMP) {
        !           313:        logit(LOG_DEBUG, 0, "Sending %squery on vif %d",
        !           314:              (v->uv_flags & VIFF_IGMPV1) ? "v1 " : "",
        !           315:              v - uvifs);
        !           316:     }
        !           317: 
        !           318:     send_igmp(v->uv_lcl_addr, allhosts_group,
        !           319:                IGMP_MEMBERSHIP_QUERY, 
        !           320:                (v->uv_flags & VIFF_IGMPV1) ? 0 :
        !           321:                IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
        !           322: }
        !           323: 
        !           324: /*
        !           325:  * Add a vifi to the kernel and start routing on it.
        !           326:  */
        !           327: static void start_vif(vifi_t vifi)
        !           328: {
        !           329:     /*
        !           330:      * Install the interface in the kernel's vif structure.
        !           331:      */
        !           332:     k_add_vif(vifi, &uvifs[vifi]);
        !           333: 
        !           334:     start_vif2(vifi);
        !           335: }
        !           336: 
        !           337: /*
        !           338:  * Add a vifi to all the user-level data structures but don't add
        !           339:  * it to the kernel yet.
        !           340:  */
        !           341: static void start_vif2(vifi_t vifi)
        !           342: {
        !           343:     struct uvif *v;
        !           344:     u_int32 src;
        !           345:     struct phaddr *p;
        !           346: 
        !           347:     v   = &uvifs[vifi];
        !           348:     src = v->uv_lcl_addr;
        !           349: 
        !           350:     /*
        !           351:      * Update the existing route entries to take into account the new vif.
        !           352:      */
        !           353:     add_vif_to_routes(vifi);
        !           354: 
        !           355:     if (!(v->uv_flags & VIFF_TUNNEL)) {
        !           356:        /*
        !           357:         * Join the DVMRP multicast group on the interface.
        !           358:         * (This is not strictly necessary, since the kernel promiscuously
        !           359:         * receives IGMP packets addressed to ANY IP multicast group while
        !           360:         * multicast routing is enabled.  However, joining the group allows
        !           361:         * this host to receive non-IGMP packets as well, such as 'pings'.)
        !           362:         */
        !           363:        k_join(dvmrp_group, src);
        !           364: 
        !           365:        /*
        !           366:         * Join the ALL-ROUTERS multicast group on the interface.
        !           367:         * This allows mtrace requests to loop back if they are run
        !           368:         * on the multicast router.
        !           369:         */
        !           370:        k_join(allrtrs_group, src);
        !           371: 
        !           372:        /*
        !           373:         * Install an entry in the routing table for the subnet to which
        !           374:         * the interface is connected.
        !           375:         */
        !           376:        start_route_updates();
        !           377:        update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi, NULL);
        !           378:        for (p = v->uv_addrs; p; p = p->pa_next) {
        !           379:            start_route_updates();
        !           380:            update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi, NULL);
        !           381:        }
        !           382: 
        !           383:        /*
        !           384:         * Until neighbors are discovered, assume responsibility for sending
        !           385:         * periodic group membership queries to the subnet.  Send the first
        !           386:         * query.
        !           387:         */
        !           388:        v->uv_flags |= VIFF_QUERIER;
        !           389:        IF_DEBUG(DEBUG_IGMP) {
        !           390:            logit(LOG_DEBUG, 0, "Assuming querier duties on vif %d", vifi);
        !           391:        }
        !           392:        send_query(v);
        !           393:     }
        !           394: 
        !           395:     v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
        !           396: 
        !           397:     /*
        !           398:      * Send a probe via the new vif to look for neighbors.
        !           399:      */
        !           400:     send_probe_on_vif(v);
        !           401: }
        !           402: 
        !           403: /*
        !           404:  * Stop routing on the specified virtual interface.
        !           405:  */
        !           406: static void stop_vif(vifi_t vifi)
        !           407: {
        !           408:     struct uvif *v;
        !           409:     struct listaddr *a;
        !           410:     struct phaddr *p;
        !           411: 
        !           412:     v = &uvifs[vifi];
        !           413: 
        !           414:     if (!(v->uv_flags & VIFF_TUNNEL)) {
        !           415:        /*
        !           416:         * Depart from the DVMRP multicast group on the interface.
        !           417:         */
        !           418:        k_leave(dvmrp_group, v->uv_lcl_addr);
        !           419: 
        !           420:        /*
        !           421:         * Depart from the ALL-ROUTERS multicast group on the interface.
        !           422:         */
        !           423:        k_leave(allrtrs_group, v->uv_lcl_addr);
        !           424: 
        !           425:        /*
        !           426:         * Update the entry in the routing table for the subnet to which
        !           427:         * the interface is connected, to take into account the interface
        !           428:         * failure.
        !           429:         */
        !           430:        start_route_updates();
        !           431:        update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi, NULL);
        !           432:        for (p = v->uv_addrs; p; p = p->pa_next) {
        !           433:            start_route_updates();
        !           434:            update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi, NULL);
        !           435:        }
        !           436: 
        !           437:        /*
        !           438:         * Discard all group addresses.  (No need to tell kernel;
        !           439:         * the k_del_vif() call, below, will clean up kernel state.)
        !           440:         */
        !           441:        while (v->uv_groups != NULL) {
        !           442:            a = v->uv_groups;
        !           443:            v->uv_groups = a->al_next;
        !           444:            free((char *)a);
        !           445:        }
        !           446: 
        !           447:        IF_DEBUG(DEBUG_IGMP) {
        !           448:            logit(LOG_DEBUG, 0, "Releasing querier duties on vif %d", vifi);
        !           449:        }
        !           450:        v->uv_flags &= ~VIFF_QUERIER;
        !           451:     }
        !           452: 
        !           453:     /*
        !           454:      * Update the existing route entries to take into account the vif failure.
        !           455:      */
        !           456:     delete_vif_from_routes(vifi);
        !           457: 
        !           458:     /*
        !           459:      * Delete the interface from the kernel's vif structure.
        !           460:      */
        !           461:     k_del_vif(vifi, v);
        !           462: 
        !           463:     /*
        !           464:      * Discard all neighbor addresses.
        !           465:      */
        !           466:     if (!NBRM_ISEMPTY(v->uv_nbrmap))
        !           467:        vifs_with_neighbors--;
        !           468: 
        !           469:     while (v->uv_neighbors != NULL) {
        !           470:        a = v->uv_neighbors;
        !           471:        v->uv_neighbors = a->al_next;
        !           472:        nbrs[a->al_index] = NULL;
        !           473:        free((char *)a);
        !           474:     }
        !           475:     NBRM_CLRALL(v->uv_nbrmap);
        !           476: }
        !           477: 
        !           478: 
        !           479: /*
        !           480:  * stop routing on all vifs
        !           481:  */
        !           482: void stop_all_vifs(void)
        !           483: {
        !           484:     vifi_t vifi;
        !           485:     struct uvif *v;
        !           486:     struct listaddr *a;
        !           487:     struct vif_acl *acl;
        !           488: 
        !           489:     for (vifi = 0; vifi < numvifs; vifi++) {
        !           490:        v = &uvifs[vifi];
        !           491:        while (v->uv_groups != NULL) {
        !           492:            a = v->uv_groups;
        !           493:            v->uv_groups = a->al_next;
        !           494:            free((char *)a);
        !           495:        }
        !           496:        while (v->uv_neighbors != NULL) {
        !           497:            a = v->uv_neighbors;
        !           498:            v->uv_neighbors = a->al_next;
        !           499:            nbrs[a->al_index] = NULL;
        !           500:            free((char *)a);
        !           501:        }
        !           502:        while (v->uv_acl != NULL) {
        !           503:            acl = v->uv_acl;
        !           504:            v->uv_acl = acl->acl_next;
        !           505:            free((char *)acl);
        !           506:        }
        !           507:     }
        !           508: }
        !           509: 
        !           510: 
        !           511: /*
        !           512:  * Find the virtual interface from which an incoming packet arrived,
        !           513:  * based on the packet's source and destination IP addresses.
        !           514:  */
        !           515: vifi_t find_vif(u_int32 src, u_int32 dst)
        !           516: {
        !           517:     vifi_t vifi;
        !           518:     struct uvif *v;
        !           519:     struct phaddr *p;
        !           520: 
        !           521:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        !           522:        if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
        !           523:            if (v->uv_flags & VIFF_TUNNEL) {
        !           524:                if (src == v->uv_rmt_addr && (dst == v->uv_lcl_addr ||
        !           525:                                              dst == dvmrp_group))
        !           526:                    return(vifi);
        !           527:            }
        !           528:            else {
        !           529:                if ((src & v->uv_subnetmask) == v->uv_subnet &&
        !           530:                    ((v->uv_subnetmask == 0xffffffff) ||
        !           531:                     (src != v->uv_subnetbcast)))
        !           532:                    return(vifi);
        !           533:                for (p=v->uv_addrs; p; p=p->pa_next) {
        !           534:                    if ((src & p->pa_subnetmask) == p->pa_subnet &&
        !           535:                        ((p->pa_subnetmask == 0xffffffff) ||
        !           536:                         (src != p->pa_subnetbcast)))
        !           537:                        return(vifi);
        !           538:                }
        !           539:            }
        !           540:        }
        !           541:     }
        !           542:     return (NO_VIF);
        !           543: }
        !           544: 
        !           545: static void age_old_hosts(void)
        !           546: {
        !           547:     vifi_t vifi;
        !           548:     struct uvif *v;
        !           549:     struct listaddr *g;
        !           550: 
        !           551:     /*
        !           552:      * Decrement the old-hosts-present timer for each
        !           553:      * active group on each vif.
        !           554:      */
        !           555:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
        !           556:         for (g = v->uv_groups; g != NULL; g = g->al_next)
        !           557:            if (g->al_old)
        !           558:                g->al_old--;
        !           559: }
        !           560: 
        !           561: 
        !           562: /*
        !           563:  * Send group membership queries on each interface for which I am querier.
        !           564:  * Note that technically, there should be a timer per interface, as the
        !           565:  * dynamics of querier election can cause the "right" time to send a
        !           566:  * query to be different on different interfaces.  However, this simple
        !           567:  * implementation only ever sends queries sooner than the "right" time,
        !           568:  * so can not cause loss of membership (but can send more packets than
        !           569:  * necessary)
        !           570:  */
        !           571: void query_groups(void)
        !           572: {
        !           573:     vifi_t vifi;
        !           574:     struct uvif *v;
        !           575: 
        !           576:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
        !           577:        if (v->uv_flags & VIFF_QUERIER) {
        !           578:            send_query(v);
        !           579:        }
        !           580:     }
        !           581:     age_old_hosts();
        !           582: }
        !           583: 
        !           584: /*
        !           585:  * Process an incoming host membership query.  Warn about
        !           586:  * IGMP version mismatches, perform querier election, and
        !           587:  * handle group-specific queries when we're not the querier.
        !           588:  */
        !           589: void accept_membership_query(u_int32 src, u_int32 dst, u_int32 group, int tmo)
        !           590: {
        !           591:     vifi_t vifi;
        !           592:     struct uvif *v;
        !           593: 
        !           594:     vifi = find_vif(src, dst);
        !           595:     if (vifi == NO_VIF || (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
        !           596:        logit(LOG_INFO, 0, "Ignoring group membership query from non-adjacent host %s",
        !           597:              inet_fmt(src, s1, sizeof(s1)));
        !           598:        return;
        !           599:     }
        !           600: 
        !           601:     v = &uvifs[vifi];
        !           602:     if ((tmo == 0 && !(v->uv_flags & VIFF_IGMPV1)) ||
        !           603:        (tmo != 0 &&  (v->uv_flags & VIFF_IGMPV1))) {
        !           604:        int i;
        !           605: 
        !           606:        /*
        !           607:         * Exponentially back-off warning rate
        !           608:         */
        !           609:        i = ++v->uv_igmpv1_warn;
        !           610:        while (i && !(i & 1))
        !           611:            i >>= 1;
        !           612: 
        !           613:        if (i == 1) {
        !           614:            logit(LOG_WARNING, 0, "Received IGMP%s report from %s on vif %d, %s",
        !           615:                  tmo == 0 ? "v1" : "v2", inet_fmt(src, s1, sizeof(s1)), vifi,
        !           616:                  tmo == 0 ? "please configure vif for IGMPv1" : "but I am configured for IGMPv1");
        !           617:        }
        !           618:     }
        !           619: 
        !           620:     if (v->uv_querier == NULL || v->uv_querier->al_addr != src) {
        !           621:        /*
        !           622:         * This might be:
        !           623:         * - A query from a new querier, with a lower source address
        !           624:         *   than the current querier (who might be me)
        !           625:         * - A query from a new router that just started up and doesn't
        !           626:         *   know who the querier is.
        !           627:         */
        !           628:        if (ntohl(src) < (v->uv_querier ? ntohl(v->uv_querier->al_addr) : ntohl(v->uv_lcl_addr))) {
        !           629:            IF_DEBUG(DEBUG_IGMP) {
        !           630:                logit(LOG_DEBUG, 0, "New querier %s (was %s) on vif %d", inet_fmt(src, s1, sizeof(s1)),
        !           631:                      v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2, sizeof(s2)) : "me", vifi);
        !           632:            }
        !           633: 
        !           634:            if (!v->uv_querier) {
        !           635:                v->uv_querier = (struct listaddr *)malloc(sizeof(struct listaddr));
        !           636:                v->uv_flags &= ~VIFF_QUERIER;
        !           637:            }
        !           638: 
        !           639:            if (v->uv_querier) {
        !           640:                time(&v->uv_querier->al_ctime);
        !           641:                v->uv_querier->al_addr = src;
        !           642:            }
        !           643:        } else {
        !           644:            IF_DEBUG(DEBUG_IGMP) {
        !           645:                logit(LOG_DEBUG, 0, "Ignoring query from %s; querier on vif %d is still %s",
        !           646:                      inet_fmt(src, s1, sizeof(s1)), vifi,
        !           647:                      v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2, sizeof(s2)) : "me");
        !           648:            }
        !           649:            return;
        !           650:        }
        !           651:     }
        !           652: 
        !           653:     /*
        !           654:      * Reset the timer since we've received a query.
        !           655:      */
        !           656:     if (v->uv_querier && src == v->uv_querier->al_addr)
        !           657:         v->uv_querier->al_timer = 0;
        !           658: 
        !           659:     /*
        !           660:      * If this is a Group-Specific query which we did not source,
        !           661:      * we must set our membership timer to [Last Member Query Count] *
        !           662:      * the [Max Response Time] in the packet.
        !           663:      */
        !           664:     if (!(v->uv_flags & (VIFF_IGMPV1|VIFF_QUERIER))
        !           665:        && group != 0 && src != v->uv_lcl_addr) {
        !           666:        struct listaddr *g;
        !           667: 
        !           668:        IF_DEBUG(DEBUG_IGMP) {
        !           669:            logit(LOG_DEBUG, 0, "Group-specific membership query for %s from %s on vif %d, timer %d",
        !           670:                  inet_fmt(group, s2, sizeof(s2)),
        !           671:                  inet_fmt(src, s1, sizeof(s1)), vifi, tmo);
        !           672:        }
        !           673:        
        !           674:        for (g = v->uv_groups; g != NULL; g = g->al_next) {
        !           675:            if (group == g->al_addr && g->al_query == 0) {
        !           676:                /* setup a timeout to remove the group membership */
        !           677:                if (g->al_timerid)
        !           678:                    g->al_timerid = DeleteTimer(g->al_timerid);
        !           679: 
        !           680:                /* use al_query to record our presence in last-member state */
        !           681:                g->al_timer = IGMP_LAST_MEMBER_QUERY_COUNT * tmo / IGMP_TIMER_SCALE;
        !           682:                g->al_query = -1;
        !           683:                g->al_timerid = SetTimer(vifi, g);
        !           684: 
        !           685:                IF_DEBUG(DEBUG_IGMP) {
        !           686:                    logit(LOG_DEBUG, 0, "Timer for grp %s on vif %d set to %d",
        !           687:                          inet_fmt(group, s2, sizeof(s2)), vifi, g->al_timer);
        !           688:                }
        !           689:                break;
        !           690:            }
        !           691:        }
        !           692:     }
        !           693: }
        !           694: 
        !           695: /*
        !           696:  * Process an incoming group membership report.
        !           697:  */
        !           698: void accept_group_report(u_int32 src, u_int32 dst, u_int32 group, int r_type)
        !           699: {
        !           700:     vifi_t vifi;
        !           701:     struct uvif *v;
        !           702:     struct listaddr *g;
        !           703: 
        !           704:     if ((vifi = find_vif(src, dst)) == NO_VIF ||
        !           705:        (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
        !           706:        logit(LOG_INFO, 0, "Ignoring group membership report from non-adjacent host %s",
        !           707:              inet_fmt(src, s1, sizeof(s1)));
        !           708:        return;
        !           709:     }
        !           710: 
        !           711:     v = &uvifs[vifi];
        !           712: 
        !           713:     /*
        !           714:      * Look for the group in our group list; if found, reset its timer.
        !           715:      */
        !           716:     for (g = v->uv_groups; g != NULL; g = g->al_next) {
        !           717:        if (group == g->al_addr) {
        !           718:            if (r_type == IGMP_V1_MEMBERSHIP_REPORT)
        !           719:                g->al_old = OLD_AGE_THRESHOLD;
        !           720: 
        !           721:            g->al_reporter = src;
        !           722: 
        !           723:            /** delete old timers, set a timer for expiration **/
        !           724:            g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL;
        !           725:            if (g->al_query)
        !           726:                g->al_query = DeleteTimer(g->al_query);
        !           727:            if (g->al_timerid)
        !           728:                g->al_timerid = DeleteTimer(g->al_timerid);
        !           729:            g->al_timerid = SetTimer(vifi, g);  
        !           730:            break;
        !           731:        }
        !           732:     }
        !           733: 
        !           734:     /*
        !           735:      * If not found, add it to the list and update kernel cache.
        !           736:      */
        !           737:     if (g == NULL) {
        !           738:        g = (struct listaddr *)malloc(sizeof(struct listaddr));
        !           739:        if (g == NULL) {
        !           740:            logit(LOG_ERR, 0, "Malloc failed in vif.c:accept_group_report()\n"); /* FATAL! */
        !           741:            return;             /* NOTREACHED */
        !           742:        }
        !           743: 
        !           744:        g->al_addr   = group;
        !           745:        if (r_type == IGMP_V1_MEMBERSHIP_REPORT)
        !           746:            g->al_old = OLD_AGE_THRESHOLD;
        !           747:        else
        !           748:            g->al_old = 0;
        !           749: 
        !           750:        /** set a timer for expiration **/
        !           751:         g->al_query    = 0;
        !           752:        g->al_timer     = IGMP_GROUP_MEMBERSHIP_INTERVAL;
        !           753:        g->al_reporter  = src;
        !           754:        g->al_timerid   = SetTimer(vifi, g);
        !           755:        g->al_next      = v->uv_groups;
        !           756:        v->uv_groups    = g;
        !           757:        time(&g->al_ctime);
        !           758: 
        !           759:        update_lclgrp(vifi, group);
        !           760:     }
        !           761: 
        !           762:     /* 
        !           763:      * Check if a graft is necessary for this group
        !           764:      */
        !           765:     chkgrp_graft(vifi, group);
        !           766: }
        !           767: 
        !           768: /*
        !           769:  * Process an incoming IGMPv2 Leave Group message.
        !           770:  */
        !           771: void accept_leave_message(u_int32 src, u_int32 dst, u_int32 group)
        !           772: {
        !           773:     vifi_t vifi;
        !           774:     struct uvif *v;
        !           775:     struct listaddr *g;
        !           776: 
        !           777:     if ((vifi = find_vif(src, dst)) == NO_VIF ||
        !           778:        (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
        !           779:        logit(LOG_INFO, 0, "Ignoring group leave report from non-adjacent host %s",
        !           780:              inet_fmt(src, s1, sizeof(s1)));
        !           781:        return;
        !           782:     }
        !           783: 
        !           784:     v = &uvifs[vifi];
        !           785: 
        !           786:     if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1))
        !           787:        return;
        !           788: 
        !           789:     /*
        !           790:      * Look for the group in our group list in order to set up a short-timeout
        !           791:      * query.
        !           792:      */
        !           793:     for (g = v->uv_groups; g != NULL; g = g->al_next) {
        !           794:        if (group == g->al_addr) {
        !           795:            IF_DEBUG(DEBUG_IGMP) {
        !           796:                logit(LOG_DEBUG, 0, "[vif.c, _accept_leave_message] %d %d \n",
        !           797:                      g->al_old, g->al_query);
        !           798:            }
        !           799: 
        !           800:            /* Ignore the leave message if there are old hosts present */
        !           801:            if (g->al_old)
        !           802:                return;
        !           803: 
        !           804:            /* still waiting for a reply to a query, ignore the leave */
        !           805:            if (g->al_query)
        !           806:                return;
        !           807: 
        !           808:            /** delete old timer set a timer for expiration **/
        !           809:            if (g->al_timerid)
        !           810:                g->al_timerid = DeleteTimer(g->al_timerid);
        !           811: 
        !           812: #if IGMP_LAST_MEMBER_QUERY_COUNT != 2
        !           813: This code needs to be updated to keep a counter of the number
        !           814: of queries remaining.
        !           815: #endif
        !           816:            /** send a group specific querry **/
        !           817:            g->al_timer = IGMP_LAST_MEMBER_QUERY_INTERVAL *
        !           818:                        (IGMP_LAST_MEMBER_QUERY_COUNT + 1);
        !           819:            send_igmp(v->uv_lcl_addr, g->al_addr,
        !           820:                        IGMP_MEMBERSHIP_QUERY, 
        !           821:                        IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE,
        !           822:                        g->al_addr, 0);
        !           823:            g->al_query = SetQueryTimer(g, vifi,
        !           824:                        IGMP_LAST_MEMBER_QUERY_INTERVAL,
        !           825:                        IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE);
        !           826:            g->al_timerid = SetTimer(vifi, g);  
        !           827:            break;
        !           828:        }
        !           829:     }
        !           830: }
        !           831: 
        !           832: 
        !           833: /*
        !           834:  * Send a periodic probe on all vifs.
        !           835:  * Useful to determine one-way interfaces.
        !           836:  * Detect neighbor loss faster.
        !           837:  */
        !           838: void probe_for_neighbors(void)
        !           839: {
        !           840:     vifi_t vifi;
        !           841:     struct uvif *v;
        !           842: 
        !           843:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
        !           844:        if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
        !           845:            send_probe_on_vif(v);
        !           846:        }
        !           847:     }
        !           848: }
        !           849: 
        !           850: 
        !           851: /*
        !           852:  * Send a list of all of our neighbors to the requestor, `src'.
        !           853:  */
        !           854: void accept_neighbor_request(u_int32 src, u_int32 UNUSED dst)
        !           855: {
        !           856:     vifi_t vifi;
        !           857:     struct uvif *v;
        !           858:     u_char *p, *ncount;
        !           859:     struct listaddr *la;
        !           860:     int        datalen;
        !           861:     u_int32 temp_addr, them = src;
        !           862: 
        !           863: #define PUT_ADDR(a)    temp_addr = ntohl(a); \
        !           864:                        *p++ = temp_addr >> 24; \
        !           865:                        *p++ = (temp_addr >> 16) & 0xFF; \
        !           866:                        *p++ = (temp_addr >> 8) & 0xFF; \
        !           867:                        *p++ = temp_addr & 0xFF;
        !           868: 
        !           869:     p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
        !           870:     datalen = 0;
        !           871: 
        !           872:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
        !           873:        if (v->uv_flags & VIFF_DISABLED)
        !           874:            continue;
        !           875: 
        !           876:        ncount = 0;
        !           877: 
        !           878:        for (la = v->uv_neighbors; la; la = la->al_next) {
        !           879: 
        !           880:            /* Make sure that there's room for this neighbor... */
        !           881:            if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
        !           882:                send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
        !           883:                          htonl(MROUTED_LEVEL), datalen);
        !           884:                p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
        !           885:                datalen = 0;
        !           886:                ncount = 0;
        !           887:            }
        !           888: 
        !           889:            /* Put out the header for this neighbor list... */
        !           890:            if (ncount == 0) {
        !           891:                PUT_ADDR(v->uv_lcl_addr);
        !           892:                *p++ = v->uv_metric;
        !           893:                *p++ = v->uv_threshold;
        !           894:                ncount = p;
        !           895:                *p++ = 0;
        !           896:                datalen += 4 + 3;
        !           897:            }
        !           898: 
        !           899:            PUT_ADDR(la->al_addr);
        !           900:            datalen += 4;
        !           901:            (*ncount)++;
        !           902:        }
        !           903:     }
        !           904: 
        !           905:     if (datalen != 0)
        !           906:        send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
        !           907:                        htonl(MROUTED_LEVEL), datalen);
        !           908: }
        !           909: 
        !           910: /*
        !           911:  * Send a list of all of our neighbors to the requestor, `src'.
        !           912:  */
        !           913: void accept_neighbor_request2(u_int32 src, u_int32 UNUSED dst)
        !           914: {
        !           915:     vifi_t vifi;
        !           916:     struct uvif *v;
        !           917:     u_char *p, *ncount;
        !           918:     struct listaddr *la;
        !           919:     int        datalen;
        !           920:     u_int32 them = src;
        !           921: 
        !           922:     p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
        !           923:     datalen = 0;
        !           924: 
        !           925:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
        !           926:        register u_int16_t vflags = v->uv_flags;
        !           927:        register u_char rflags = 0;
        !           928:        if (vflags & VIFF_TUNNEL)
        !           929:            rflags |= DVMRP_NF_TUNNEL;
        !           930:        if (vflags & VIFF_SRCRT)
        !           931:            rflags |= DVMRP_NF_SRCRT;
        !           932:        if (vflags & VIFF_DOWN)
        !           933:            rflags |= DVMRP_NF_DOWN;
        !           934:        if (vflags & VIFF_DISABLED)
        !           935:            rflags |= DVMRP_NF_DISABLED;
        !           936:        if (vflags & VIFF_QUERIER)
        !           937:            rflags |= DVMRP_NF_QUERIER;
        !           938:        if (vflags & VIFF_LEAF)
        !           939:            rflags |= DVMRP_NF_LEAF;
        !           940:        ncount = 0;
        !           941:        la = v->uv_neighbors;
        !           942:        if (la == NULL) {
        !           943:            /*
        !           944:             * include down & disabled interfaces and interfaces on
        !           945:             * leaf nets.
        !           946:             */
        !           947:            if (rflags & DVMRP_NF_TUNNEL)
        !           948:                rflags |= DVMRP_NF_DOWN;
        !           949:            if (datalen > MAX_DVMRP_DATA_LEN - 12) {
        !           950:                send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
        !           951:                          htonl(MROUTED_LEVEL), datalen);
        !           952:                p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
        !           953:                datalen = 0;
        !           954:            }
        !           955:            *(u_int*)p = v->uv_lcl_addr;
        !           956:            p += 4;
        !           957:            *p++ = v->uv_metric;
        !           958:            *p++ = v->uv_threshold;
        !           959:            *p++ = rflags;
        !           960:            *p++ = 1;
        !           961:            *(u_int*)p =  v->uv_rmt_addr;
        !           962:            p += 4;
        !           963:            datalen += 12;
        !           964:        } else {
        !           965:            for ( ; la; la = la->al_next) {
        !           966:                /* Make sure that there's room for this neighbor... */
        !           967:                if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
        !           968:                    send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
        !           969:                              htonl(MROUTED_LEVEL), datalen);
        !           970:                    p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
        !           971:                    datalen = 0;
        !           972:                    ncount = 0;
        !           973:                }
        !           974:                /* Put out the header for this neighbor list... */
        !           975:                if (ncount == 0) {
        !           976:                    /* If it's a one-way tunnel, mark it down. */
        !           977:                    if (rflags & DVMRP_NF_TUNNEL && la->al_flags & NBRF_ONEWAY)
        !           978:                        rflags |= DVMRP_NF_DOWN;
        !           979:                    *(u_int*)p = v->uv_lcl_addr;
        !           980:                    p += 4;
        !           981:                    *p++ = v->uv_metric;
        !           982:                    *p++ = v->uv_threshold;
        !           983:                    *p++ = rflags;
        !           984:                    ncount = p;
        !           985:                    *p++ = 0;
        !           986:                    datalen += 4 + 4;
        !           987:                }
        !           988:                /* Don't report one-way peering on phyint at all */
        !           989:                if (!(rflags & DVMRP_NF_TUNNEL) && la->al_flags & NBRF_ONEWAY)
        !           990:                    continue;
        !           991:                *(u_int*)p = la->al_addr;
        !           992:                p += 4;
        !           993:                datalen += 4;
        !           994:                (*ncount)++;
        !           995:            }
        !           996:            if (*ncount == 0) {
        !           997:                *(u_int*)p = v->uv_rmt_addr;
        !           998:                p += 4;
        !           999:                datalen += 4;
        !          1000:                (*ncount)++;
        !          1001:            }
        !          1002:        }
        !          1003:     }
        !          1004:     if (datalen != 0)
        !          1005:        send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
        !          1006:                htonl(MROUTED_LEVEL), datalen);
        !          1007: }
        !          1008: 
        !          1009: void accept_info_request(u_int32 src, u_int32 UNUSED dst, u_char *p, size_t datalen)
        !          1010: {
        !          1011:     u_char *q;
        !          1012:     int len;
        !          1013:     int outlen = 0;
        !          1014: 
        !          1015:     q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
        !          1016: 
        !          1017:     /* To be general, this must deal properly with breaking up over-sized
        !          1018:      * packets.  That implies passing a length to each function, and
        !          1019:      * allowing each function to request to be called again.  Right now,
        !          1020:      * we're only implementing the one thing we are positive will fit into
        !          1021:      * a single packet, so we wimp out.
        !          1022:      */
        !          1023:     while (datalen > 0) {
        !          1024:        len = 0;
        !          1025:        switch (*p) {
        !          1026:            case DVMRP_INFO_VERSION:
        !          1027:                len = info_version(q);
        !          1028:                break;
        !          1029: 
        !          1030:            case DVMRP_INFO_NEIGHBORS:
        !          1031:            default:
        !          1032:                logit(LOG_INFO, 0, "Ignoring unknown info type %d", *p);
        !          1033:                break;
        !          1034:        }
        !          1035:        *(q+1) = len++;
        !          1036:        outlen += len * 4;
        !          1037:        q += len * 4;
        !          1038:        len = (*(p+1) + 1) * 4;
        !          1039:        p += len;
        !          1040:        datalen -= len;
        !          1041:     }
        !          1042: 
        !          1043:     if (outlen != 0)
        !          1044:        send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY,
        !          1045:                        htonl(MROUTED_LEVEL), outlen);
        !          1046: }
        !          1047: 
        !          1048: /*
        !          1049:  * Information response -- return version string
        !          1050:  */
        !          1051: static int info_version(u_char *p)
        !          1052: {
        !          1053:     int len;
        !          1054: 
        !          1055:     *p++ = DVMRP_INFO_VERSION;
        !          1056:     p++;       /* skip over length */
        !          1057:     *p++ = 0;  /* zero out */
        !          1058:     *p++ = 0;  /* reserved fields */
        !          1059:     /* XXX: We use sizeof(versionstring) instead of the available 
        !          1060:      *      space in send_buf[] because that buffer is 8192 bytes.
        !          1061:      *      It is not very likely our versionstring will ever be
        !          1062:      *      as long as 100 bytes, but it's better to limit the amount
        !          1063:      *      of data copied to send_buf since we do not want to risk
        !          1064:      *      sending MAX size frames. */
        !          1065:     len = strlcpy((char *)p, versionstring, sizeof(versionstring));
        !          1066: 
        !          1067:     return ((len + 3) / 4);
        !          1068: }
        !          1069: 
        !          1070: /*
        !          1071:  * Process an incoming neighbor-list message.
        !          1072:  */
        !          1073: void accept_neighbors(u_int32_t src, u_int32_t dst, u_char UNUSED *p, size_t UNUSED datalen, u_int32_t UNUSED level)
        !          1074: {
        !          1075:     logit(LOG_INFO, 0, "Ignoring spurious DVMRP neighbor list from %s to %s",
        !          1076:          inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !          1077: }
        !          1078: 
        !          1079: 
        !          1080: /*
        !          1081:  * Process an incoming neighbor-list message.
        !          1082:  */
        !          1083: void accept_neighbors2(u_int32 src, u_int32 dst, u_char UNUSED *p, size_t UNUSED datalen, u_int32 UNUSED level)
        !          1084: {
        !          1085:     IF_DEBUG(DEBUG_PKT) {
        !          1086:        logit(LOG_DEBUG, 0, "Ignoring spurious DVMRP neighbor list2 from %s to %s",
        !          1087:              inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !          1088:     }
        !          1089: }
        !          1090: 
        !          1091: /*
        !          1092:  * Process an incoming info reply message.
        !          1093:  */
        !          1094: void accept_info_reply(u_int32 src, u_int32 dst, u_char UNUSED *p, size_t UNUSED datalen)
        !          1095: {
        !          1096:     IF_DEBUG(DEBUG_PKT) {
        !          1097:        logit(LOG_DEBUG, 0, "Ignoring spurious DVMRP info reply from %s to %s",
        !          1098:              inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
        !          1099:     }
        !          1100: }
        !          1101: 
        !          1102: 
        !          1103: /*
        !          1104:  * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
        !          1105:  * 'msgtype' is the type of DVMRP message received from the neighbor.
        !          1106:  * Return the neighbor entry if 'addr' is a valid neighbor, FALSE otherwise.
        !          1107:  */
        !          1108: struct listaddr *update_neighbor(vifi_t vifi, u_int32 addr, int msgtype, char *p, size_t datalen, u_int32 level)
        !          1109: {
        !          1110:     struct uvif *v;
        !          1111:     struct listaddr *n;
        !          1112:     int pv = level & 0xff;
        !          1113:     int mv = (level >> 8) & 0xff;
        !          1114:     int has_genid = 0;
        !          1115:     int in_router_list = 0;
        !          1116:     int dvmrpspec = 0;
        !          1117:     u_int32 genid;
        !          1118:     u_int32 send_tables = 0;
        !          1119:     size_t i;
        !          1120:     int do_reset = FALSE;
        !          1121: 
        !          1122:     v = &uvifs[vifi];
        !          1123: 
        !          1124:     /*
        !          1125:      * Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
        !          1126:      * IT IS ASSUMED that this was preceded by a call to find_vif(), which
        !          1127:      * checks that 'addr' is either a valid remote tunnel endpoint or a
        !          1128:      * non-broadcast address belonging to a directly-connected subnet.
        !          1129:      * Therefore, here we check only that 'addr' is not our own address
        !          1130:      * (due to an impostor or erroneous loopback) or an address of the form
        !          1131:      * {subnet,0} ("the unknown host").  These checks are not performed in
        !          1132:      * find_vif() because those types of address are acceptable for some
        !          1133:      * types of IGMP message (such as group membership reports).
        !          1134:      */
        !          1135:     if (!(v->uv_flags & VIFF_TUNNEL) && (addr == v->uv_lcl_addr || addr == v->uv_subnet )) {
        !          1136:        logit(LOG_WARNING, 0, "Received DVMRP message from %s: %s",
        !          1137:              (addr == v->uv_lcl_addr) ? "self (check device loopback)" : "'the unknown host'",
        !          1138:              inet_fmt(addr, s1, sizeof(s1)));
        !          1139:        return NULL;
        !          1140:     }
        !          1141: 
        !          1142:     /*
        !          1143:      * Ignore all neighbors on vifs forced into leaf mode
        !          1144:      */
        !          1145:     if (v->uv_flags & VIFF_FORCE_LEAF) {
        !          1146:        return NULL;
        !          1147:     }
        !          1148: 
        !          1149:     /*
        !          1150:      * mrouted's version 3.3 and later include the generation ID
        !          1151:      * and the list of neighbors on the vif in their probe messages.
        !          1152:      */
        !          1153:     if (msgtype == DVMRP_PROBE && ((pv == 3 && mv > 2) ||
        !          1154:                                   (pv > 3 && pv < 10))) {
        !          1155:        u_int32 router;
        !          1156: 
        !          1157:        IF_DEBUG(DEBUG_PEER) {
        !          1158:            logit(LOG_DEBUG, 0, "Checking probe from %s (%d.%d) on vif %d",
        !          1159:                  inet_fmt(addr, s1, sizeof(s1)), pv, mv, vifi);
        !          1160:        }
        !          1161: 
        !          1162:        if (datalen < 4) {
        !          1163:            logit(LOG_WARNING, 0, "Received truncated probe message from %s (len %d)",
        !          1164:                  inet_fmt(addr, s1, sizeof(s1)), datalen);
        !          1165:            return NULL;
        !          1166:        }
        !          1167: 
        !          1168:        has_genid = 1;
        !          1169: 
        !          1170:        for (i = 0; i < 4; i++)
        !          1171:          ((char *)&genid)[i] = *p++;
        !          1172:        datalen -= 4;
        !          1173: 
        !          1174:        while (datalen > 0) {
        !          1175:            if (datalen < 4) {
        !          1176:                logit(LOG_WARNING, 0, "Received truncated probe message from %s (len %d)",
        !          1177:                      inet_fmt(addr, s1, sizeof(s1)), datalen);
        !          1178:                return NULL;
        !          1179:            }
        !          1180: 
        !          1181:            for (i = 0; i < 4; i++)
        !          1182:              ((char *)&router)[i] = *p++;
        !          1183:            datalen -= 4;
        !          1184: 
        !          1185:            if (router == v->uv_lcl_addr) {
        !          1186:                in_router_list = 1;
        !          1187:                break;
        !          1188:            }
        !          1189:        }
        !          1190:     }
        !          1191: 
        !          1192:     if ((pv == 3 && mv == 255) || (pv > 3 && pv < 10))
        !          1193:        dvmrpspec = 1;
        !          1194: 
        !          1195:     /*
        !          1196:      * Look for addr in list of neighbors.
        !          1197:      */
        !          1198:     for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
        !          1199:        if (addr == n->al_addr) {
        !          1200:            break;
        !          1201:        }
        !          1202:     }
        !          1203: 
        !          1204:     if (n == NULL) {
        !          1205:        /*
        !          1206:         * New neighbor.
        !          1207:         *
        !          1208:         * If this neighbor follows the DVMRP spec, start the probe
        !          1209:         * handshake.  If not, then it doesn't require the probe
        !          1210:         * handshake, so establish the peering immediately.
        !          1211:         */
        !          1212:        if (dvmrpspec && (msgtype != DVMRP_PROBE))
        !          1213:            return NULL;
        !          1214: 
        !          1215:        for (i = 0; i < MAXNBRS; i++)
        !          1216:            if (nbrs[i] == NULL)
        !          1217:                break;
        !          1218: 
        !          1219:        if (i == MAXNBRS) {
        !          1220:            /* XXX This is a severe new restriction. */
        !          1221:            /* XXX want extensible bitmaps! */
        !          1222:            logit(LOG_ERR, 0, "Cannot handle %dth neighbor %s on vif %d!",
        !          1223:                  MAXNBRS, inet_fmt(addr, s1, sizeof(s1)), vifi);
        !          1224:            return NULL;        /* NOTREACHED */
        !          1225:        }
        !          1226: 
        !          1227:        /*
        !          1228:         * Add it to our list of neighbors.
        !          1229:         */
        !          1230:        IF_DEBUG(DEBUG_PEER) {
        !          1231:            logit(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x idx %d",
        !          1232:                  inet_fmt(addr, s1, sizeof(s1)), vifi, level & 0xff, (level >> 8) & 0xff,
        !          1233:                  (level >> 16) & 0xff, i);
        !          1234:        }
        !          1235: 
        !          1236:        n = (struct listaddr *)malloc(sizeof(struct listaddr));
        !          1237:        if (n == NULL) {
        !          1238:            logit(LOG_ERR, 0, "Malloc failed in vif.c:update_neighbor()\n"); /* FATAL! */
        !          1239:            return NULL;        /* NOTREACHED */
        !          1240:        }
        !          1241: 
        !          1242:        n->al_addr      = addr;
        !          1243:        n->al_pv        = pv;
        !          1244:        n->al_mv        = mv;
        !          1245:        n->al_genid     = has_genid ? genid : 0;
        !          1246:        n->al_index     = i;
        !          1247:        nbrs[i] = n;
        !          1248: 
        !          1249:        time(&n->al_ctime);
        !          1250:        n->al_timer     = 0;
        !          1251:        n->al_flags     = has_genid ? NBRF_GENID : 0;
        !          1252:        n->al_next      = v->uv_neighbors;
        !          1253:        v->uv_neighbors = n;
        !          1254: 
        !          1255:        /*
        !          1256:         * If we are not configured to peer with non-pruning routers,
        !          1257:         * check the deprecated "I-know-how-to-prune" bit.  This bit
        !          1258:         * was MBZ in early mrouted implementations (<3.5) and is required
        !          1259:         * to be set by the DVMRPv3 specification.
        !          1260:         */
        !          1261:        if (!(v->uv_flags & VIFF_ALLOW_NONPRUNERS) &&
        !          1262:            !((level & 0x020000) || (pv == 3 && mv < 5))) {
        !          1263:            n->al_flags |= NBRF_TOOOLD;
        !          1264:        }
        !          1265: 
        !          1266:        /*
        !          1267:         * If this router implements the DVMRPv3 spec, then don't peer
        !          1268:         * with him if we haven't yet established a bidirectional connection.
        !          1269:         */
        !          1270:        if (dvmrpspec) {
        !          1271:            if (!in_router_list) {
        !          1272:                IF_DEBUG(DEBUG_PEER) {
        !          1273:                    logit(LOG_DEBUG, 0, "Waiting for probe from %s with my addr",
        !          1274:                          inet_fmt(addr, s1, sizeof(s1)));
        !          1275:                }
        !          1276:                n->al_flags |= NBRF_WAITING;
        !          1277:                return NULL;
        !          1278:            }
        !          1279:        }
        !          1280: 
        !          1281:        if (n->al_flags & NBRF_DONTPEER) {
        !          1282:            IF_DEBUG(DEBUG_PEER) {
        !          1283:                logit(LOG_DEBUG, 0, "Not peering with %s on vif %d because %x",
        !          1284:                      inet_fmt(addr, s1, sizeof(s1)), vifi, n->al_flags & NBRF_DONTPEER);
        !          1285:            }
        !          1286:            return NULL;
        !          1287:        }
        !          1288: 
        !          1289:        /*
        !          1290:         * If we thought that we had no neighbors on this vif, send a route
        !          1291:         * report to the vif.  If this is just a new neighbor on the same
        !          1292:         * vif, send the route report just to the new neighbor.
        !          1293:         */
        !          1294:        if (NBRM_ISEMPTY(v->uv_nbrmap)) {
        !          1295:            send_tables = v->uv_dst_addr;
        !          1296:            vifs_with_neighbors++;
        !          1297:        } else {
        !          1298:            send_tables = addr;
        !          1299:        }
        !          1300: 
        !          1301: 
        !          1302:        NBRM_SET(i, v->uv_nbrmap);
        !          1303:        add_neighbor_to_routes(vifi, i);
        !          1304:     } else {
        !          1305:        /*
        !          1306:         * Found it.  Reset its timer.
        !          1307:         */
        !          1308:        n->al_timer = 0;
        !          1309: 
        !          1310:        if (n->al_flags & NBRF_WAITING && msgtype == DVMRP_PROBE) {
        !          1311:            n->al_flags &= ~NBRF_WAITING;
        !          1312:            if (!in_router_list) {
        !          1313:                logit(LOG_WARNING, 0, "Possible one-way peering with %s on vif %d",
        !          1314:                      inet_fmt(addr, s1, sizeof(s1)), vifi);
        !          1315:                n->al_flags |= NBRF_ONEWAY;
        !          1316:                return NULL;
        !          1317:            } else {
        !          1318:                if (NBRM_ISEMPTY(v->uv_nbrmap)) {
        !          1319:                    send_tables = v->uv_dst_addr;
        !          1320:                    vifs_with_neighbors++;
        !          1321:                } else {
        !          1322:                    send_tables = addr;
        !          1323:                }
        !          1324:                NBRM_SET(n->al_index, v->uv_nbrmap);
        !          1325:                add_neighbor_to_routes(vifi, n->al_index);
        !          1326:                IF_DEBUG(DEBUG_PEER) {
        !          1327:                    logit(LOG_DEBUG, 0, "%s on vif %d exits WAITING",
        !          1328:                          inet_fmt(addr, s1, sizeof(s1)), vifi);
        !          1329:                }
        !          1330:            }
        !          1331:        }
        !          1332: 
        !          1333:        if (n->al_flags & NBRF_ONEWAY && msgtype == DVMRP_PROBE) {
        !          1334:            if (in_router_list) {
        !          1335:                if (NBRM_ISEMPTY(v->uv_nbrmap))
        !          1336:                    vifs_with_neighbors++;
        !          1337:                NBRM_SET(n->al_index, v->uv_nbrmap);
        !          1338:                add_neighbor_to_routes(vifi, n->al_index);
        !          1339:                logit(LOG_NOTICE, 0, "Peering with %s on vif %d is no longer one-way",
        !          1340:                        inet_fmt(addr, s1, sizeof(s1)), vifi);
        !          1341:                n->al_flags &= ~NBRF_ONEWAY;
        !          1342:            } else {
        !          1343:                /* XXX rate-limited warning message? */
        !          1344:                IF_DEBUG(DEBUG_PEER) {
        !          1345:                    logit(LOG_DEBUG, 0, "%s on vif %d is still ONEWAY",
        !          1346:                          inet_fmt(addr, s1, sizeof(s1)), vifi);
        !          1347:                }
        !          1348:            }
        !          1349:        }
        !          1350: 
        !          1351:        /*
        !          1352:         * When peering with a genid-capable but pre-DVMRP spec peer,
        !          1353:         * we might bring up the peering with a route report and not
        !          1354:         * remember his genid.  Assume that he doesn't send a route
        !          1355:         * report and then reboot before sending a probe.
        !          1356:         */
        !          1357:        if (has_genid && !(n->al_flags & NBRF_GENID)) {
        !          1358:            n->al_flags |= NBRF_GENID;
        !          1359:            n->al_genid = genid;
        !          1360:        }
        !          1361: 
        !          1362:        /*
        !          1363:         * update the neighbors version and protocol number and genid
        !          1364:         * if changed => router went down and came up, 
        !          1365:         * so take action immediately.
        !          1366:         */
        !          1367:        if ((n->al_pv != pv) ||
        !          1368:            (n->al_mv != mv) ||
        !          1369:            (has_genid && n->al_genid != genid)) {
        !          1370: 
        !          1371:            do_reset = TRUE;
        !          1372:            IF_DEBUG(DEBUG_PEER) {
        !          1373:                logit(LOG_DEBUG, 0, "Version/genid change neighbor %s [old:%d.%d/%8x, new:%d.%d/%8x]",
        !          1374:                      inet_fmt(addr, s1, sizeof(s1)),
        !          1375:                      n->al_pv, n->al_mv, n->al_genid, pv, mv, genid);
        !          1376:            }
        !          1377: 
        !          1378:            n->al_pv = pv;
        !          1379:            n->al_mv = mv;
        !          1380:            n->al_genid = genid;
        !          1381:            time(&n->al_ctime);
        !          1382:        }
        !          1383: 
        !          1384:        if ((pv == 3 && mv > 2) || (pv > 3 && pv < 10)) {
        !          1385:            if (!(n->al_flags & VIFF_ONEWAY) && has_genid && !in_router_list &&
        !          1386:                                (time(NULL) - n->al_ctime > 20)) {
        !          1387:                if (NBRM_ISSET(n->al_index, v->uv_nbrmap)) {
        !          1388:                    NBRM_CLR(n->al_index, v->uv_nbrmap);
        !          1389:                    if (NBRM_ISEMPTY(v->uv_nbrmap))
        !          1390:                        vifs_with_neighbors--;
        !          1391:                }
        !          1392:                delete_neighbor_from_routes(addr, vifi, n->al_index);
        !          1393:                reset_neighbor_state(vifi, addr);
        !          1394:                logit(LOG_WARNING, 0, "Peering with %s on vif %d is one-way",
        !          1395:                      inet_fmt(addr, s1, sizeof(s1)), vifi);
        !          1396:                n->al_flags |= NBRF_ONEWAY;
        !          1397:            }
        !          1398:        }
        !          1399: 
        !          1400:        if (n->al_flags & NBRF_DONTPEER) {
        !          1401:            IF_DEBUG(DEBUG_PEER) {
        !          1402:                logit(LOG_DEBUG, 0, "Not peering with %s on vif %d because %x",
        !          1403:                      inet_fmt(addr, s1, sizeof(s1)), vifi, n->al_flags & NBRF_DONTPEER);
        !          1404:            }
        !          1405:            return NULL;
        !          1406:        }
        !          1407: 
        !          1408:        /* check "leaf" flag */
        !          1409:     }
        !          1410:     if (do_reset) {
        !          1411:        reset_neighbor_state(vifi, addr);
        !          1412:        if (!send_tables)
        !          1413:            send_tables = addr;
        !          1414:     }
        !          1415:     if (send_tables) {
        !          1416:        send_probe_on_vif(v);
        !          1417:        report(ALL_ROUTES, vifi, send_tables);
        !          1418:     }
        !          1419:     v->uv_leaf_timer = 0;
        !          1420:     v->uv_flags &= ~VIFF_LEAF;
        !          1421: 
        !          1422:     return n;
        !          1423: }
        !          1424: 
        !          1425: 
        !          1426: /*
        !          1427:  * On every timer interrupt, advance the timer in each neighbor and
        !          1428:  * group entry on every vif.
        !          1429:  */
        !          1430: void age_vifs(void)
        !          1431: {
        !          1432:     vifi_t vifi;
        !          1433:     struct uvif *v;
        !          1434:     struct listaddr *a, *prev_a;
        !          1435:     u_int32 addr;
        !          1436: 
        !          1437:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
        !          1438:        if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) {
        !          1439:                v->uv_flags |= VIFF_LEAF;
        !          1440:        }
        !          1441: 
        !          1442:        for (prev_a = (struct listaddr *)&(v->uv_neighbors),
        !          1443:             a = v->uv_neighbors;
        !          1444:             a != NULL;
        !          1445:             prev_a = a, a = a->al_next) {
        !          1446:            u_long exp_time;
        !          1447:            int idx;
        !          1448: 
        !          1449:            if (((a->al_pv == 3) && (a->al_mv >= 3)) ||
        !          1450:                ((a->al_pv > 3) && (a->al_pv < 10)))
        !          1451:                exp_time = NEIGHBOR_EXPIRE_TIME;
        !          1452:            else
        !          1453:                exp_time = OLD_NEIGHBOR_EXPIRE_TIME;
        !          1454: 
        !          1455:            if ((a->al_timer += TIMER_INTERVAL) < exp_time)
        !          1456:                continue;
        !          1457: 
        !          1458:            IF_DEBUG(DEBUG_PEER) {
        !          1459:                logit(LOG_DEBUG, 0, "Neighbor %s (%d.%d) expired after %d seconds",
        !          1460:                      inet_fmt(a->al_addr, s1, sizeof(s1)), a->al_pv, a->al_mv, exp_time);
        !          1461:            }
        !          1462: 
        !          1463:            /*
        !          1464:             * Neighbor has expired; delete it from the neighbor list,
        !          1465:             * delete it from the 'dominants' and 'subordinates arrays of
        !          1466:             * any route entries.
        !          1467:             */
        !          1468:            NBRM_CLR(a->al_index, v->uv_nbrmap);
        !          1469:            nbrs[a->al_index] = NULL;   /* XXX is it a good idea to reuse indxs? */
        !          1470:            idx = a->al_index;
        !          1471:            addr = a->al_addr;
        !          1472:            prev_a->al_next = a->al_next;
        !          1473:            free((char *)a);
        !          1474:            a = prev_a;/*XXX use ** */
        !          1475: 
        !          1476:            delete_neighbor_from_routes(addr, vifi, idx);
        !          1477:            reset_neighbor_state(vifi, addr);
        !          1478: 
        !          1479:            if (NBRM_ISEMPTY(v->uv_nbrmap))
        !          1480:                vifs_with_neighbors--;
        !          1481: 
        !          1482:            v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
        !          1483:        }
        !          1484: 
        !          1485:        if (v->uv_querier &&
        !          1486:            (v->uv_querier->al_timer += TIMER_INTERVAL) >
        !          1487:                IGMP_OTHER_QUERIER_PRESENT_INTERVAL) {
        !          1488:            /*
        !          1489:             * The current querier has timed out.  We must become the
        !          1490:             * querier.
        !          1491:             */
        !          1492:            IF_DEBUG(DEBUG_IGMP) {
        !          1493:                logit(LOG_DEBUG, 0, "Querier %s timed out",
        !          1494:                      inet_fmt(v->uv_querier->al_addr, s1, sizeof(s1)));
        !          1495:            }
        !          1496:            free(v->uv_querier);
        !          1497:            v->uv_querier = NULL;
        !          1498:            v->uv_flags |= VIFF_QUERIER;
        !          1499:            send_query(v);
        !          1500:        }
        !          1501:     }
        !          1502: }
        !          1503: 
        !          1504: /*
        !          1505:  * Returns the neighbor info struct for a given neighbor
        !          1506:  */
        !          1507: struct listaddr *neighbor_info(vifi_t vifi, u_int32 addr)
        !          1508: {
        !          1509:     struct listaddr *u;
        !          1510: 
        !          1511:     for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
        !          1512:        if (u->al_addr == addr)
        !          1513:            return u;
        !          1514: 
        !          1515:     return NULL;
        !          1516: }
        !          1517: 
        !          1518: static struct vnflags {
        !          1519:        int     vn_flag;
        !          1520:        char   *vn_name;
        !          1521: } vifflags[] = {
        !          1522:        { VIFF_DOWN,            "down" },
        !          1523:        { VIFF_DISABLED,        "disabled" },
        !          1524:        { VIFF_QUERIER,         "querier" },
        !          1525:        { VIFF_ONEWAY,          "one-way" },
        !          1526:        { VIFF_LEAF,            "leaf" },
        !          1527:        { VIFF_IGMPV1,          "IGMPv1" },
        !          1528:        { VIFF_REXMIT_PRUNES,   "rexmit_prunes" },
        !          1529:        { VIFF_PASSIVE,         "passive" },
        !          1530:        { VIFF_ALLOW_NONPRUNERS,"allow_nonpruners" },
        !          1531:        { VIFF_NOFLOOD,         "noflood" },
        !          1532:        { VIFF_NOTRANSIT,       "notransit" },
        !          1533:        { VIFF_BLASTER,         "blaster" },
        !          1534:        { VIFF_FORCE_LEAF,      "force_leaf" },
        !          1535:        { VIFF_OTUNNEL,         "old-tunnel" },
        !          1536: };
        !          1537: 
        !          1538: static struct vnflags nbrflags[] = {
        !          1539:        { NBRF_LEAF,            "leaf" },
        !          1540:        { NBRF_GENID,           "have-genid" },
        !          1541:        { NBRF_WAITING,         "waiting" },
        !          1542:        { NBRF_ONEWAY,          "one-way" },
        !          1543:        { NBRF_TOOOLD,          "too old" },
        !          1544:        { NBRF_TOOMANYROUTES,   "too many routes" },
        !          1545:        { NBRF_NOTPRUNING,      "not pruning?" },
        !          1546: };
        !          1547: 
        !          1548: /*
        !          1549:  * Print the contents of the uvifs array on file 'fp'.
        !          1550:  */
        !          1551: void dump_vifs(FILE *fp)
        !          1552: {
        !          1553:     vifi_t vifi;
        !          1554:     struct uvif *v;
        !          1555:     struct listaddr *a;
        !          1556:     struct phaddr *p;
        !          1557:     struct vif_acl *acl;
        !          1558:     size_t i;
        !          1559:     struct sioc_vif_req v_req;
        !          1560:     time_t now;
        !          1561:     char *label;
        !          1562: 
        !          1563:     time(&now);
        !          1564:     fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors);
        !          1565: 
        !          1566:     if (vifs_with_neighbors == 1)
        !          1567:        fprintf(fp,"[This host is a leaf]\n\n");
        !          1568: 
        !          1569:     fprintf(fp,
        !          1570:     "\nVirtual Interface Table\n%s",
        !          1571:     "Vif  Name  Local-Address                               ");
        !          1572:     fprintf(fp,
        !          1573:     "M  Thr  Rate   Flags\n");
        !          1574: 
        !          1575:     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
        !          1576: 
        !          1577:        fprintf(fp, "%2u %6s  %-15s %6s: %-18s %2u %3u  %5u  ",
        !          1578:                vifi,
        !          1579:                v->uv_name,
        !          1580:                inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
        !          1581:                (v->uv_flags & VIFF_TUNNEL) ?
        !          1582:                        "tunnel":
        !          1583:                        "subnet",
        !          1584:                (v->uv_flags & VIFF_TUNNEL) ?
        !          1585:                        inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)) :
        !          1586:                        inet_fmts(v->uv_subnet, v->uv_subnetmask, s3, sizeof(s3)),
        !          1587:                v->uv_metric,
        !          1588:                v->uv_threshold,
        !          1589:                v->uv_rate_limit);
        !          1590: 
        !          1591:        for (i = 0; i < sizeof(vifflags) / sizeof(struct vnflags); i++)
        !          1592:                if (v->uv_flags & vifflags[i].vn_flag)
        !          1593:                        fprintf(fp, " %s", vifflags[i].vn_name);
        !          1594: 
        !          1595:        fprintf(fp, "\n");
        !          1596:        /*
        !          1597:        fprintf(fp, "                          #routes: %d\n", v->uv_nroutes);
        !          1598:        */
        !          1599:        if (v->uv_admetric != 0)
        !          1600:            fprintf(fp, "                                        advert-metric %2u\n",
        !          1601:                v->uv_admetric);
        !          1602: 
        !          1603:        label = "alternate subnets:";
        !          1604:        for (p = v->uv_addrs; p; p = p->pa_next) {
        !          1605:            fprintf(fp, "                %18s %s\n", label,
        !          1606:                        inet_fmts(p->pa_subnet, p->pa_subnetmask, s1, sizeof(s1)));
        !          1607:            label = "";
        !          1608:        }
        !          1609: 
        !          1610:        label = "peers:";
        !          1611:        for (a = v->uv_neighbors; a != NULL; a = a->al_next) {
        !          1612:            fprintf(fp, "                            %6s %s (%d.%d) [%d]",
        !          1613:                    label, inet_fmt(a->al_addr, s1, sizeof(s1)), a->al_pv, a->al_mv,
        !          1614:                    a->al_index);
        !          1615:            for (i = 0; i < sizeof(nbrflags) / sizeof(struct vnflags); i++)
        !          1616:                    if (a->al_flags & nbrflags[i].vn_flag)
        !          1617:                            fprintf(fp, " %s", nbrflags[i].vn_name);
        !          1618:            fprintf(fp, " up %s\n", scaletime(now - a->al_ctime));
        !          1619:            /*fprintf(fp, " #routes %d\n", a->al_nroutes);*/
        !          1620:            label = "";
        !          1621:        }
        !          1622: 
        !          1623:        label = "group host (time left):";
        !          1624:        for (a = v->uv_groups; a != NULL; a = a->al_next) {
        !          1625:            fprintf(fp, "           %23s %-15s %-15s (%s)\n",
        !          1626:                    label,
        !          1627:                    inet_fmt(a->al_addr, s1, sizeof(s1)),
        !          1628:                    inet_fmt(a->al_reporter, s2, sizeof(s2)),
        !          1629:                    scaletime(timer_leftTimer(a->al_timerid)));
        !          1630:            label = "";
        !          1631:        }
        !          1632:        label = "boundaries:";
        !          1633:        for (acl = v->uv_acl; acl != NULL; acl = acl->acl_next) {
        !          1634:            fprintf(fp, "                       %11s %-18s\n", label,
        !          1635:                        inet_fmts(acl->acl_addr, acl->acl_mask, s1, sizeof(s1)));
        !          1636:            label = "";
        !          1637:        }
        !          1638:        if (v->uv_filter) {
        !          1639:            struct vf_element *vfe;
        !          1640:            char lbuf[100];
        !          1641: 
        !          1642:            snprintf(lbuf, sizeof(lbuf), "%5s %7s filter:",
        !          1643:                     v->uv_filter->vf_flags & VFF_BIDIR  ? "bidir"  : "     ",
        !          1644:                     v->uv_filter->vf_type == VFT_ACCEPT ? "accept" : "deny");
        !          1645:            label = lbuf;
        !          1646:            for (vfe = v->uv_filter->vf_filter;
        !          1647:                 vfe != NULL; vfe = vfe->vfe_next) {
        !          1648:                fprintf(fp, "           %23s %-18s%s\n",
        !          1649:                        label,
        !          1650:                        inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s1, sizeof(s1)),
        !          1651:                        vfe->vfe_flags & VFEF_EXACT ? " (exact)" : "");
        !          1652:                label = "";
        !          1653:            }
        !          1654:        }
        !          1655:        if (!(v->uv_flags & (VIFF_TUNNEL|VIFF_DOWN|VIFF_DISABLED))) {
        !          1656:            fprintf(fp, "                     IGMP querier: ");
        !          1657:            if (v->uv_querier == NULL)
        !          1658:                if (v->uv_flags & VIFF_QUERIER)
        !          1659:                    fprintf(fp, "%-18s (this system)\n",
        !          1660:                                    inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
        !          1661:                else
        !          1662:                    fprintf(fp, "NONE - querier election failure?\n");
        !          1663:            else
        !          1664:                fprintf(fp, "%-18s up %s last heard %s ago\n",
        !          1665:                        inet_fmt(v->uv_querier->al_addr, s1, sizeof(s1)),
        !          1666:                        scaletime(now - v->uv_querier->al_ctime),
        !          1667:                        scaletime(v->uv_querier->al_timer));
        !          1668:        }
        !          1669:        if (v->uv_flags & VIFF_BLASTER)
        !          1670:            fprintf(fp, "                  blasterbuf size: %dk\n",
        !          1671:                        v->uv_blasterlen / 1024);
        !          1672:        fprintf(fp, "                      Nbr bitmaps: 0x%08lx%08lx\n",/*XXX*/
        !          1673:                        v->uv_nbrmap.hi, v->uv_nbrmap.lo);
        !          1674:        if (v->uv_prune_lifetime != 0)
        !          1675:            fprintf(fp, "                   Prune Lifetime: %d seconds\n",
        !          1676:                                            v->uv_prune_lifetime);
        !          1677: 
        !          1678:        v_req.vifi = vifi;
        !          1679:        if (did_final_init) {
        !          1680:            if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) {
        !          1681:                logit(LOG_WARNING, errno, "Failed ioctl SIOCGETVIFCNT on vif %d", vifi);
        !          1682:            } else {
        !          1683:                fprintf(fp, "                   pkts/bytes in : %lu/%lu\n",
        !          1684:                        v_req.icount, v_req.ibytes);
        !          1685:                fprintf(fp, "                   pkts/bytes out: %lu/%lu\n",
        !          1686:                        v_req.ocount, v_req.obytes);
        !          1687:            }
        !          1688:        }
        !          1689:        fprintf(fp, "\n");
        !          1690:     }
        !          1691:     fprintf(fp, "\n");
        !          1692: }
        !          1693: 
        !          1694: /*
        !          1695:  * Time out record of a group membership on a vif
        !          1696:  */
        !          1697: static void DelVif(void *arg)
        !          1698: {
        !          1699:     cbk_t *cbk = (cbk_t *)arg;
        !          1700:     vifi_t vifi = cbk->vifi;
        !          1701:     struct uvif *v = &uvifs[vifi];
        !          1702:     struct listaddr *a, **anp, *g = cbk->g;
        !          1703: 
        !          1704:     /*
        !          1705:      * Group has expired
        !          1706:      * delete all kernel cache entries with this group
        !          1707:      */
        !          1708:     if (g->al_query)
        !          1709:        DeleteTimer(g->al_query);
        !          1710: 
        !          1711:     delete_lclgrp(vifi, g->al_addr);
        !          1712: 
        !          1713:     anp = &(v->uv_groups);
        !          1714:     while ((a = *anp) != NULL) {
        !          1715:        if (a == g) {
        !          1716:            *anp = a->al_next;
        !          1717:            free((char *)a);
        !          1718:        } else {
        !          1719:            anp = &a->al_next;
        !          1720:        }
        !          1721:     }
        !          1722: 
        !          1723:     free(cbk);
        !          1724: }
        !          1725: 
        !          1726: /*
        !          1727:  * Set a timer to delete the record of a group membership on a vif.
        !          1728:  */
        !          1729: static int SetTimer(vifi_t vifi, struct listaddr *g)
        !          1730: {
        !          1731:     cbk_t *cbk;
        !          1732: 
        !          1733:     cbk = (cbk_t *)malloc(sizeof(cbk_t));
        !          1734:     if (!cbk) {
        !          1735:        logit(LOG_ERR, 0, "Malloc failed in vif.c:SetTimer()\n");
        !          1736:        return -1;              /* NOTREACHED */
        !          1737:     }
        !          1738: 
        !          1739:     cbk->g = g;
        !          1740:     cbk->vifi = vifi;
        !          1741: 
        !          1742:     return timer_setTimer(g->al_timer, DelVif, cbk);
        !          1743: }
        !          1744: 
        !          1745: /*
        !          1746:  * Delete a timer that was set above.
        !          1747:  */
        !          1748: static int DeleteTimer(int id)
        !          1749: {
        !          1750:     timer_clearTimer(id);
        !          1751: 
        !          1752:     return 0;
        !          1753: }
        !          1754: 
        !          1755: /*
        !          1756:  * Send a group-specific query.
        !          1757:  */
        !          1758: static void SendQuery(void *arg)
        !          1759: {
        !          1760:     cbk_t *cbk = (cbk_t *)arg;
        !          1761:     struct uvif *v = &uvifs[cbk->vifi];
        !          1762: 
        !          1763:     send_igmp(v->uv_lcl_addr, cbk->g->al_addr, IGMP_MEMBERSHIP_QUERY,
        !          1764:              cbk->q_time, cbk->g->al_addr, 0);
        !          1765:     cbk->g->al_query = 0;
        !          1766:     free(cbk);
        !          1767: }
        !          1768: 
        !          1769: /*
        !          1770:  * Set a timer to send a group-specific query.
        !          1771:  */
        !          1772: static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time)
        !          1773: {
        !          1774:     cbk_t *cbk;
        !          1775: 
        !          1776:     cbk = (cbk_t *)malloc(sizeof(cbk_t));
        !          1777:     if (!cbk) {
        !          1778:        logit(LOG_WARNING, 0, "Malloc failed in vif.c:setQueryTimer()\n");
        !          1779:        return -1;
        !          1780:     }
        !          1781: 
        !          1782:     cbk->g = g;
        !          1783:     cbk->q_time = q_time;
        !          1784:     cbk->vifi = vifi;
        !          1785: 
        !          1786:     return timer_setTimer(to_expire, SendQuery, cbk);
        !          1787: }
        !          1788: 
        !          1789: /**
        !          1790:  * Local Variables:
        !          1791:  *  version-control: t
        !          1792:  *  indent-tabs-mode: t
        !          1793:  *  c-file-style: "ellemtel"
        !          1794:  *  c-basic-offset: 4
        !          1795:  * End:
        !          1796:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>