Annotation of embedaddon/mrouted/vif.c, revision 1.1.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>