Annotation of embedaddon/mrouted/route.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: 
                     12: /*
                     13:  * Private macros.
                     14:  */
                     15: #define MAX_NUM_RT   4096
                     16: 
                     17: /*
                     18:  * Private types.
                     19:  */
                     20: struct newrt {
                     21:        u_int32 mask;
                     22:        u_int32 origin;
                     23:        int metric;
                     24:        int pad;
                     25: };
                     26: 
                     27: struct blaster_hdr {
                     28:     u_int32    bh_src;
                     29:     u_int32    bh_dst;
                     30:     u_int32    bh_level;
                     31:     int                bh_datalen;
                     32: };
                     33: 
                     34: /*
                     35:  * Exported variables.
                     36:  */
                     37: int routes_changed;                    /* 1=>some routes have changed */
                     38: int delay_change_reports;              /* 1=>postpone change reports  */
                     39: unsigned int nroutes;                  /* current number of route entries  */
                     40: struct rtentry *routing_table;         /* pointer to list of route entries */
                     41: 
                     42: /*
                     43:  * Private variables.
                     44:  */
                     45: static struct rtentry *rtp;            /* pointer to a route entry         */
                     46: static struct rtentry *rt_end;         /* pointer to last route entry      */
                     47: 
                     48: /*
                     49:  * Private functions.
                     50:  */
                     51: static int  init_children_and_leaves (struct rtentry *r, vifi_t parent, int first);
                     52: static int  find_route               (u_int32 origin, u_int32 mask);
                     53: static void create_route             (u_int32 origin, u_int32 mask);
                     54: static void discard_route            (struct rtentry *this);
                     55: static int  compare_rts              (const void *rt1, const void *rt2);
                     56: static int  report_chunk             (int, struct rtentry *start_rt, vifi_t vifi, u_int32 dst);
                     57: static void queue_blaster_report     (vifi_t vifi, u_int32 src, u_int32 dst, char *p, size_t datalen, u_int32 level);
                     58: static void process_blaster_report   (void *vifip);
                     59: 
                     60: #ifdef SNMP
                     61: #include <sys/types.h>
                     62: #include "snmp.h"
                     63: 
                     64: /*
                     65:  * Return pointer to a specific route entry.  This must be a separate
                     66:  * function from find_route() which modifies rtp.
                     67:  */
                     68: struct rtentry *snmp_find_route(u_int32 src, u_int32 mask)
                     69: {
                     70:     struct rtentry *rt;
                     71: 
                     72:    for (rt = routing_table; rt; rt = rt->rt_next) {
                     73:       if (src == rt->rt_origin && mask == rt->rt_originmask)
                     74:          return rt;
                     75:    }
                     76: 
                     77:    return NULL;
                     78: }
                     79: 
                     80: /*
                     81:  * Find next route entry > specification 
                     82:  */
                     83: int next_route(struct rtentry **rtpp, u_int32 src, u_int32 mask)
                     84: {
                     85:    struct rtentry *rt, *rbest = NULL;
                     86: 
                     87:    /* Among all entries > spec, find "lowest" one in order */
                     88:    for (rt = routing_table; rt; rt=rt->rt_next) {
                     89:       if ((ntohl(rt->rt_origin) > ntohl(src) 
                     90:           || (ntohl(rt->rt_origin) == ntohl(src) 
                     91:              && ntohl(rt->rt_originmask) > ntohl(mask)))
                     92:        && (!rbest || (ntohl(rt->rt_origin) < ntohl(rbest->rt_origin))
                     93:           || (ntohl(rt->rt_origin) == ntohl(rbest->rt_origin)
                     94:              && ntohl(rt->rt_originmask) < ntohl(rbest->rt_originmask))))
                     95:                rbest = rt;
                     96:    }
                     97:    (*rtpp) = rbest;
                     98: 
                     99:    return (*rtpp)!=0;
                    100: }
                    101: 
                    102: /*
                    103:  * Given a routing table entry, and a vifi, find the next vifi/entry
                    104:  */
                    105: int next_route_child(struct rtentry **rtpp, u_int32 src, u_int32 mask, vifi_t vifi)
                    106: {
                    107:    /* Get (S,M) entry */
                    108:    if (!((*rtpp) = snmp_find_route(src, mask)))
                    109:       if (!next_route(rtpp, src, mask))
                    110:          return 0;
                    111: 
                    112:    /* Continue until we get one with a valid next vif */
                    113:    do {
                    114:       for (; (*rtpp)->rt_children && *vifi<numvifs; (*vifi)++)
                    115:          if (VIFM_ISSET(*vifi, (*rtpp)->rt_children))
                    116:             return 1;
                    117:       *vifi = 0;
                    118:    } while (next_route(rtpp, (*rtpp)->rt_origin, (*rtpp)->rt_originmask));
                    119: 
                    120:    return 0;
                    121: }
                    122: #endif /* SNMP */
                    123: 
                    124: /*
                    125:  * Initialize the routing table and associated variables.
                    126:  */
                    127: void init_routes(void)
                    128: {
                    129:     routing_table        = NULL;
                    130:     rt_end              = NULL;
                    131:     nroutes             = 0;
                    132:     routes_changed       = FALSE;
                    133:     delay_change_reports = FALSE;
                    134: }
                    135: 
                    136: 
                    137: /*
                    138:  * Initialize the children bits for route 'r', along with the
                    139:  * associated dominant and subordinate data structures.
                    140:  * If first is set, initialize dominants, otherwise keep old
                    141:  * dominants on non-parent interfaces.
                    142:  * XXX Does this need a return value?
                    143:  */
                    144: static int init_children_and_leaves(struct rtentry *r, vifi_t parent, int first)
                    145: {
                    146:     vifi_t vifi;
                    147:     struct uvif *v;
                    148:     vifbitmap_t old_children;
                    149:     nbrbitmap_t old_subords;
                    150: 
                    151:     VIFM_COPY(r->rt_children, old_children);
                    152:     NBRM_COPY(r->rt_subordinates, old_subords);
                    153: 
                    154:     VIFM_CLRALL(r->rt_children);
                    155: 
                    156:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                    157:        if (first || vifi == parent)
                    158:            r->rt_dominants[vifi] = 0;
                    159:        if (vifi == parent || uvifs[vifi].uv_flags & VIFF_NOFLOOD ||
                    160:                AVOID_TRANSIT(vifi, r) || (!first && r->rt_dominants[vifi]))
                    161:            NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
                    162:        else
                    163:            NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
                    164: 
                    165:        if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED)) &&
                    166:                !(!first && r->rt_dominants[vifi])) {
                    167:            VIFM_SET(vifi, r->rt_children);
                    168:        }
                    169:     }
                    170: 
                    171:     return (!VIFM_SAME(r->rt_children, old_children) ||
                    172:            !NBRM_SAME(r->rt_subordinates, old_subords));
                    173: }
                    174: 
                    175: 
                    176: /*
                    177:  * A new vif has come up -- update the children bitmaps in all route
                    178:  * entries to take that into account.
                    179:  */
                    180: void add_vif_to_routes(vifi_t vifi)
                    181: {
                    182:     struct rtentry *r;
                    183:     struct uvif *v;
                    184: 
                    185:     v = &uvifs[vifi];
                    186:     for (r = routing_table; r != NULL; r = r->rt_next) {
                    187:        if (r->rt_metric != UNREACHABLE &&
                    188:            !VIFM_ISSET(vifi, r->rt_children)) {
                    189:            VIFM_SET(vifi, r->rt_children);
                    190:            r->rt_dominants[vifi] = 0;
                    191:            /*XXX isn't uv_nbrmap going to be empty?*/
                    192:            NBRM_CLRMASK(r->rt_subordinates, v->uv_nbrmap);
                    193:            update_table_entry(r, r->rt_gateway);
                    194:        }
                    195:     }
                    196: }
                    197: 
                    198: 
                    199: /*
                    200:  * A vif has gone down -- expire all routes that have that vif as parent,
                    201:  * and update the children bitmaps in all other route entries to take into
                    202:  * account the failed vif.
                    203:  */
                    204: void delete_vif_from_routes(vifi_t vifi)
                    205: {
                    206:     struct rtentry *r;
                    207: 
                    208:     for (r = routing_table; r != NULL; r = r->rt_next) {
                    209:        if (r->rt_metric != UNREACHABLE) {
                    210:            if (vifi == r->rt_parent) {
                    211:                del_table_entry(r, 0, DEL_ALL_ROUTES);
                    212:                r->rt_timer    = ROUTE_EXPIRE_TIME;
                    213:                r->rt_metric   = UNREACHABLE;
                    214:                r->rt_flags   |= RTF_CHANGED;
                    215:                routes_changed = TRUE;
                    216:            }
                    217:            else if (VIFM_ISSET(vifi, r->rt_children)) {
                    218:                VIFM_CLR(vifi, r->rt_children);
                    219:                NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
                    220:                update_table_entry(r, r->rt_gateway);
                    221:            }
                    222:            else {
                    223:                r->rt_dominants[vifi] = 0;
                    224:            }
                    225:        }
                    226:     }
                    227: }
                    228: 
                    229: 
                    230: /*
                    231:  * A new neighbor has come up.  If we're flooding on the neighbor's
                    232:  * vif, mark that neighbor as subordinate for all routes whose parent
                    233:  * is not this vif.
                    234:  */
                    235: void add_neighbor_to_routes(vifi_t vifi, u_int index)
                    236: {
                    237:     struct rtentry *r;
                    238:     struct uvif *v;
                    239: 
                    240:     v = &uvifs[vifi];
                    241:     if (v->uv_flags & VIFF_NOFLOOD)
                    242:        return;
                    243:     for (r = routing_table; r != NULL; r = r->rt_next) {
                    244:        if (r->rt_metric != UNREACHABLE && r->rt_parent != vifi &&
                    245:                !AVOID_TRANSIT(vifi, r)) {
                    246:            NBRM_SET(index, r->rt_subordinates);
                    247:            update_table_entry(r, r->rt_gateway);
                    248:        }
                    249:     }
                    250: }
                    251: 
                    252: 
                    253: /*
                    254:  * A neighbor has failed or become unreachable.  If that neighbor was
                    255:  * considered a dominant or subordinate router in any route entries,
                    256:  * take appropriate action.  Expire all routes this neighbor advertised
                    257:  * to us.
                    258:  */
                    259: void delete_neighbor_from_routes(u_int32 addr, vifi_t vifi, u_int index)
                    260: {
                    261:     struct rtentry *r;
                    262:     struct uvif *v;
                    263: 
                    264:     v = &uvifs[vifi];
                    265:     for (r = routing_table; r != NULL; r = r->rt_next) {
                    266:        if (r->rt_metric != UNREACHABLE) {
                    267:            if (r->rt_parent == vifi && r->rt_gateway == addr) {
                    268:                del_table_entry(r, 0, DEL_ALL_ROUTES);
                    269:                r->rt_timer    = ROUTE_EXPIRE_TIME;
                    270:                r->rt_metric   = UNREACHABLE;
                    271:                r->rt_flags   |= RTF_CHANGED;
                    272:                routes_changed = TRUE;
                    273:            } else if (r->rt_dominants[vifi] == addr) {
                    274:                VIFM_SET(vifi, r->rt_children);
                    275:                r->rt_dominants[vifi] = 0;
                    276:                if ((uvifs[vifi].uv_flags & VIFF_NOFLOOD) ||
                    277:                                AVOID_TRANSIT(vifi, r))
                    278:                    NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
                    279:                else
                    280:                    NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
                    281:                update_table_entry(r, r->rt_gateway);
                    282:            } else if (NBRM_ISSET(index, r->rt_subordinates)) {
                    283:                NBRM_CLR(index, r->rt_subordinates);
                    284:                update_table_entry(r, r->rt_gateway);
                    285:            }
                    286:        }
                    287:     }
                    288: }
                    289: 
                    290: 
                    291: /*
                    292:  * Prepare for a sequence of ordered route updates by initializing a pointer
                    293:  * to the start of the routing table.  The pointer is used to remember our
                    294:  * position in the routing table in order to avoid searching from the
                    295:  * beginning for each update; this relies on having the route reports in
                    296:  * a single message be in the same order as the route entries in the routing
                    297:  * table.
                    298:  */
                    299: void start_route_updates(void)
                    300: {
                    301:     rtp = routing_table;
                    302: }
                    303: 
                    304: 
                    305: /*
                    306:  * Starting at the route entry following the one to which 'rtp' points,
                    307:  * look for a route entry matching the specified origin and mask.  If a
                    308:  * match is found, return TRUE and leave 'rtp' pointing at the found entry.
                    309:  * If no match is found, return FALSE and leave 'rtp' pointing to the route
                    310:  * entry preceding the point at which the new origin should be inserted.
                    311:  * This code is optimized for the normal case in which the first entry to
                    312:  * be examined is the matching entry.
                    313:  */
                    314: static int find_route(u_int32 origin, u_int32 mask)
                    315: {
                    316:     struct rtentry *r;
                    317: 
                    318:     r = rtp;
                    319:     while (r != NULL) {
                    320:        if (origin == r->rt_origin && mask == r->rt_originmask) {
                    321:            rtp = r;
                    322:            return TRUE;
                    323:        }
                    324:        if (ntohl(mask) < ntohl(r->rt_originmask) ||
                    325:            (mask == r->rt_originmask &&
                    326:             ntohl(origin) < ntohl(r->rt_origin))) {
                    327:            rtp = r;
                    328:            r = r->rt_next;
                    329:        } else {
                    330:            break;
                    331:        }
                    332:     }
                    333:     return FALSE;
                    334: }
                    335: 
                    336: /*
                    337:  * Create a new routing table entry for the specified origin and link it into
                    338:  * the routing table.  The shared variable 'rtp' is assumed to point to the
                    339:  * routing entry after which the new one should be inserted.  It is left
                    340:  * pointing to the new entry.
                    341:  *
                    342:  * Only the origin, originmask, originwidth and flags fields are initialized
                    343:  * in the new route entry; the caller is responsible for filling in the rest.
                    344:  */
                    345: static void create_route(u_int32 origin, u_int32 mask)
                    346: {
                    347:     size_t len;
                    348:     struct rtentry *this;
                    349: 
                    350:     this = (struct rtentry *)malloc(sizeof(struct rtentry));
                    351:     if (!this) {
                    352:        logit(LOG_ERR, errno, "route.c:create_route() - Failed allocating struct rtentry.\n");
                    353:        return;         /* NOTREACHED */
                    354:     }
                    355:     memset(this, 0, sizeof(struct rtentry));
                    356: 
                    357:     len = numvifs * sizeof(u_int32);
                    358:     this->rt_dominants = (u_int32 *)malloc(len);
                    359:     if (!this->rt_dominants) {
                    360:        logit(LOG_ERR, errno, "route.c:create_route() - Failed allocating struct rtentry.\n");
                    361:        free(this);
                    362:        return;         /* NOTREACHED */
                    363:     }
                    364:     memset(this->rt_dominants, 0, len);
                    365: 
                    366:     this->rt_origin     = origin;
                    367:     this->rt_originmask = mask;
                    368:     if      (((char *)&mask)[3] != 0) this->rt_originwidth = 4;
                    369:     else if (((char *)&mask)[2] != 0) this->rt_originwidth = 3;
                    370:     else if (((char *)&mask)[1] != 0) this->rt_originwidth = 2;
                    371:     else                              this->rt_originwidth = 1;
                    372:     this->rt_flags = 0;
                    373:     this->rt_groups = NULL;
                    374: 
                    375:     VIFM_CLRALL(this->rt_children);
                    376:     NBRM_CLRALL(this->rt_subordinates);
                    377:     NBRM_CLRALL(this->rt_subordadv);
                    378: 
                    379:     /* Link in 'this', where rtp points */
                    380:     if (rtp) {
                    381:        this->rt_prev = rtp;
                    382:        this->rt_next = rtp->rt_next;
                    383:        if (this->rt_next)
                    384:            (this->rt_next)->rt_prev = this;
                    385:        else
                    386:            rt_end = this;
                    387:        rtp->rt_next = this;
                    388:     } else {
                    389:        routing_table = this;
                    390:        rt_end = this;
                    391:     }
                    392: 
                    393:     rtp = this;
                    394:     ++nroutes;
                    395: }
                    396: 
                    397: 
                    398: /*
                    399:  * Discard the routing table entry following the one to which 'this' points.
                    400:  *         [.|prev|.]--->[.|this|.]<---[.|next|.]
                    401:  */
                    402: static void discard_route(struct rtentry *this)
                    403: {
                    404:     struct rtentry *prev, *next;
                    405: 
                    406:     if (!this)
                    407:        return;
                    408: 
                    409:     /* Find previous and next link */
                    410:     prev = this->rt_prev;
                    411:     next = this->rt_next;
                    412: 
                    413:     /* Unlink 'this' */
                    414:     if (prev)
                    415:        prev->rt_next = next;   /* Handles case when 'this' is last link. */
                    416:     else
                    417:        routing_table = next;   /* 'this' is first link. */
                    418:     if (next)
                    419:        next->rt_prev = prev;
                    420: 
                    421:     /* Update the books */
                    422:     uvifs[this->rt_parent].uv_nroutes--;
                    423:     /*???nbr???.al_nroutes--;*/
                    424:     --nroutes;
                    425: 
                    426:     /* Update meta pointers */
                    427:     if (rtp == this)
                    428:        rtp = next;
                    429:     if (rt_end == this)
                    430:        rt_end = next;
                    431: 
                    432:     free(this->rt_dominants);
                    433:     free(this);
                    434: }
                    435: 
                    436: 
                    437: /*
                    438:  * Process a route report for a single origin, creating or updating the
                    439:  * corresponding routing table entry if necessary.  'src' is either the
                    440:  * address of a neighboring router from which the report arrived, or zero
                    441:  * to indicate a change of status of one of our own interfaces.
                    442:  */
                    443: void update_route(u_int32 origin, u_int32 mask, u_int metric, u_int32 src, vifi_t vifi, struct listaddr *n)
                    444: {
                    445:     register struct rtentry *r;
                    446:     u_int adj_metric;
                    447: 
                    448:     /*
                    449:      * Compute an adjusted metric, taking into account the cost of the
                    450:      * subnet or tunnel over which the report arrived, and normalizing
                    451:      * all unreachable/poisoned metrics into a single value.
                    452:      */
                    453:     if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) {
                    454:        logit(LOG_WARNING, 0, "%s reports out-of-range metric %u for origin %s",
                    455:            inet_fmt(src, s1, sizeof(s1)), metric, inet_fmts(origin, mask, s2, sizeof(s2)));
                    456:        return;
                    457:     }
                    458:     adj_metric = metric + uvifs[vifi].uv_metric;
                    459:     if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE;
                    460: 
                    461:     /*
                    462:      * Look up the reported origin in the routing table.
                    463:      */
                    464:     if (!find_route(origin, mask)) {
                    465:        /*
                    466:         * Not found.
                    467:         * Don't create a new entry if the report says it's unreachable,
                    468:         * or if the reported origin and mask are invalid.
                    469:         */
                    470:        if (adj_metric == UNREACHABLE) {
                    471:            return;
                    472:        }
                    473:        if (src != 0 && !inet_valid_subnet(origin, mask)) {
                    474:            logit(LOG_WARNING, 0, "%s reports an invalid origin (%s) and/or mask (%08x)",
                    475:                  inet_fmt(src, s1, sizeof(s1)), inet_fmt(origin, s2, sizeof(s2)), ntohl(mask));
                    476:            return;
                    477:        }
                    478: 
                    479:        IF_DEBUG(DEBUG_RTDETAIL) {
                    480:            logit(LOG_DEBUG, 0, "%s advertises new route %s",
                    481:                  inet_fmt(src, s1, sizeof(s1)), inet_fmts(origin, mask, s2, sizeof(s2)));
                    482:        }
                    483: 
                    484:        /*
                    485:         * OK, create the new routing entry.  'rtp' will be left pointing
                    486:         * to the new entry.
                    487:         */
                    488:        create_route(origin, mask);
                    489:        uvifs[vifi].uv_nroutes++;
                    490:        /*n->al_nroutes++;*/
                    491: 
                    492:        rtp->rt_metric = UNREACHABLE;   /* temporary; updated below */
                    493:     }
                    494: 
                    495:     /*
                    496:      * We now have a routing entry for the reported origin.  Update it?
                    497:      */
                    498:     r = rtp;
                    499:     if (r->rt_metric == UNREACHABLE) {
                    500:        /*
                    501:         * The routing entry is for a formerly-unreachable or new origin.
                    502:         * If the report claims reachability, update the entry to use
                    503:         * the reported route.
                    504:         */
                    505:        if (adj_metric == UNREACHABLE)
                    506:            return;
                    507: 
                    508:        IF_DEBUG(DEBUG_RTDETAIL) {
                    509:            logit(LOG_DEBUG, 0, "%s advertises %s with adj_metric %d (ours was %d)",
                    510:                  inet_fmt(src, s1, sizeof(s1)), inet_fmts(origin, mask, s2, sizeof(s2)),
                    511:                  adj_metric, r->rt_metric);
                    512:        }
                    513: 
                    514:        /*
                    515:         * Now "steal away" any sources that belong under this route
                    516:         * by deleting any cache entries they might have created
                    517:         * and allowing the kernel to re-request them.
                    518:         *
                    519:         * If we haven't performed final initialization yet and are
                    520:         * just collecting the routing table, we can't have any
                    521:         * sources so we don't perform this step.
                    522:         */
                    523:        if (did_final_init)
                    524:            steal_sources(rtp);
                    525: 
                    526:        r->rt_parent   = vifi;
                    527:        r->rt_gateway  = src;
                    528:        init_children_and_leaves(r, vifi, 1);
                    529: 
                    530:        r->rt_timer    = 0;
                    531:        r->rt_metric   = adj_metric;
                    532:        r->rt_flags   |= RTF_CHANGED;
                    533:        routes_changed = TRUE;
                    534:        update_table_entry(r, r->rt_gateway);
                    535:     } else if (src == r->rt_gateway) {
                    536:        /*
                    537:         * The report has come either from the interface directly-connected
                    538:         * to the origin subnet (src and r->rt_gateway both equal zero) or
                    539:         * from the gateway we have chosen as the best first-hop gateway back
                    540:         * towards the origin (src and r->rt_gateway not equal zero).  Reset
                    541:         * the route timer and, if the reported metric has changed, update
                    542:         * our entry accordingly.
                    543:         */
                    544:        r->rt_timer = 0;
                    545: 
                    546:        IF_DEBUG(DEBUG_RTDETAIL) {
                    547:            logit(LOG_DEBUG, 0, "%s (current parent) advertises %s with adj_metric %d (ours was %d)",
                    548:                  inet_fmt(src, s1, sizeof(s1)), inet_fmts(origin, mask, s2, sizeof(s2)),
                    549:                  adj_metric, r->rt_metric);
                    550:        }
                    551: 
                    552:        if (adj_metric == r->rt_metric)
                    553:            return;
                    554: 
                    555:        if (adj_metric == UNREACHABLE) {
                    556:            del_table_entry(r, 0, DEL_ALL_ROUTES);
                    557:            r->rt_timer = ROUTE_EXPIRE_TIME;
                    558:        }
                    559:        r->rt_metric   = adj_metric;
                    560:        r->rt_flags   |= RTF_CHANGED;
                    561:        routes_changed = TRUE;
                    562:     } else if (src == 0 ||
                    563:               (r->rt_gateway != 0 &&
                    564:                (adj_metric < r->rt_metric ||
                    565:                 (adj_metric == r->rt_metric &&
                    566:                  (ntohl(src) < ntohl(r->rt_gateway) ||
                    567:                   r->rt_timer >= ROUTE_SWITCH_TIME))))) {
                    568:        /*
                    569:         * The report is for an origin we consider reachable; the report
                    570:         * comes either from one of our own interfaces or from a gateway
                    571:         * other than the one we have chosen as the best first-hop gateway
                    572:         * back towards the origin.  If the source of the update is one of
                    573:         * our own interfaces, or if the origin is not a directly-connected
                    574:         * subnet and the reported metric for that origin is better than
                    575:         * what our routing entry says, update the entry to use the new
                    576:         * gateway and metric.  We also switch gateways if the reported
                    577:         * metric is the same as the one in the route entry and the gateway
                    578:         * associated with the route entry has not been heard from recently,
                    579:         * or if the metric is the same but the reporting gateway has a lower
                    580:         * IP address than the gateway associated with the route entry.
                    581:         * Did you get all that?
                    582:         */
                    583:        u_int32 old_gateway;
                    584:        vifi_t old_parent;
                    585: 
                    586:        old_gateway = r->rt_gateway;
                    587:        old_parent = r->rt_parent;
                    588:        r->rt_gateway = src;
                    589:        r->rt_parent = vifi;
                    590: 
                    591:        IF_DEBUG(DEBUG_RTDETAIL) {
                    592:            logit(LOG_DEBUG, 0, "%s (new parent) on vif %d advertises %s with adj_metric %d (old parent was %s on vif %d, metric %d)",
                    593:                  inet_fmt(src, s1, sizeof(s1)), vifi, inet_fmts(origin, mask, s2, sizeof(s2)),
                    594:                  adj_metric, inet_fmt(old_gateway, s3, sizeof(s3)), old_parent, r->rt_metric);
                    595:        }
                    596: 
                    597:        if (old_parent != vifi) {
                    598:            init_children_and_leaves(r, vifi, 0);
                    599:            uvifs[old_parent].uv_nroutes--;
                    600:            uvifs[vifi].uv_nroutes++;
                    601:        }
                    602:        if (old_gateway != src) {
                    603:            update_table_entry(r, old_gateway);
                    604:            /*???old_gateway???->al_nroutes--;*/
                    605:            /*n->al_nroutes++;*/
                    606:        }
                    607:        r->rt_timer    = 0;
                    608:        r->rt_metric   = adj_metric;
                    609:        r->rt_flags   |= RTF_CHANGED;
                    610:        routes_changed = TRUE;
                    611:     } else if (vifi != r->rt_parent) {
                    612:        /*
                    613:         * The report came from a vif other than the route's parent vif.
                    614:         * Update the children info, if necessary.
                    615:         */
                    616:        if (AVOID_TRANSIT(vifi, r)) {
                    617:            /*
                    618:             * The route's parent is a vif from which we're not supposed
                    619:             * to transit onto this vif.  Simply ignore the update.
                    620:             */
                    621:            IF_DEBUG(DEBUG_RTDETAIL) {
                    622:                logit(LOG_DEBUG, 0, "%s on vif %d advertises %s with metric %d (ignored due to NOTRANSIT)",
                    623:                      inet_fmt(src, s1, sizeof(s1)), vifi, inet_fmts(origin, mask, s2, sizeof(s2)), metric);
                    624:            }
                    625:        } else if (VIFM_ISSET(vifi, r->rt_children)) {
                    626:            /*
                    627:             * Vif is a child vif for this route.
                    628:             */
                    629:            if (metric  < r->rt_metric ||
                    630:                (metric == r->rt_metric &&
                    631:                 ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) {
                    632:                /*
                    633:                 * Neighbor has lower metric to origin (or has same metric
                    634:                 * and lower IP address) -- it becomes the dominant router,
                    635:                 * and vif is no longer a child for me.
                    636:                 */
                    637:                VIFM_CLR(vifi, r->rt_children);
                    638:                r->rt_dominants[vifi] = src;
                    639:                /* XXX
                    640:                 * We don't necessarily want to forget about subordinateness
                    641:                 * so that we can become the dominant quickly if the current
                    642:                 * dominant fails.
                    643:                 */
                    644:                NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
                    645:                update_table_entry(r, r->rt_gateway);
                    646:                IF_DEBUG(DEBUG_RTDETAIL) {
                    647:                    logit(LOG_DEBUG, 0, "%s on vif %d becomes dominant for %s with metric %d",
                    648:                          inet_fmt(src, s1, sizeof(s1)), vifi, inet_fmts(origin, mask, s2, sizeof(s2)),
                    649:                          metric);
                    650:                }
                    651:            } else if (metric > UNREACHABLE) {  /* "poisoned reverse" */
                    652:                /*
                    653:                 * Neighbor considers this vif to be on path to route's
                    654:                 * origin; record this neighbor as subordinate
                    655:                 */
                    656:                if (!NBRM_ISSET(n->al_index, r->rt_subordinates)) {
                    657:                    IF_DEBUG(DEBUG_RTDETAIL) {
                    658:                        logit(LOG_DEBUG, 0, "%s on vif %d becomes subordinate for %s with poison-reverse metric %d",
                    659:                              inet_fmt(src, s1, sizeof(s1)), vifi, inet_fmts(origin, mask, s2, sizeof(s2)),
                    660:                              metric - UNREACHABLE);
                    661:                    }
                    662:                    NBRM_SET(n->al_index, r->rt_subordinates);
                    663:                    update_table_entry(r, r->rt_gateway);
                    664:                } else {
                    665:                    IF_DEBUG(DEBUG_RTDETAIL) {
                    666:                        logit(LOG_DEBUG, 0, "%s on vif %d confirms subordinateness for %s with poison-reverse metric %d",
                    667:                              inet_fmt(src, s1, sizeof(s1)), vifi, inet_fmts(origin, mask, s2, sizeof(s2)),
                    668:                              metric - UNREACHABLE);
                    669:                    }
                    670:                }
                    671:                NBRM_SET(n->al_index, r->rt_subordadv);
                    672:            } else if (NBRM_ISSET(n->al_index, r->rt_subordinates)) {
                    673:                /*
                    674:                 * Current subordinate no longer considers this vif to be on
                    675:                 * path to route's origin; it is no longer a subordinate
                    676:                 * router.
                    677:                 */
                    678:                IF_DEBUG(DEBUG_RTDETAIL) {
                    679:                    logit(LOG_DEBUG, 0, "%s on vif %d is no longer a subordinate for %s with metric %d",
                    680:                          inet_fmt(src, s1, sizeof(s1)), vifi, inet_fmts(origin, mask, s2, sizeof(s2)),
                    681:                          metric);
                    682:                }
                    683:                NBRM_CLR(n->al_index, r->rt_subordinates);
                    684:                update_table_entry(r, r->rt_gateway);
                    685:            }
                    686:        } else if (src == r->rt_dominants[vifi] &&
                    687:                   (metric  > r->rt_metric ||
                    688:                    (metric == r->rt_metric &&
                    689:                     ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) {
                    690:            /*
                    691:             * Current dominant no longer has a lower metric to origin
                    692:             * (or same metric and lower IP address); we adopt the vif
                    693:             * as our own child.
                    694:             */
                    695:            IF_DEBUG(DEBUG_RTDETAIL) {
                    696:                logit(LOG_DEBUG, 0, "%s (current dominant) on vif %d is no longer dominant for %s with metric %d",
                    697:                      inet_fmt(src, s1, sizeof(s1)), vifi, inet_fmts(origin, mask, s2, sizeof(s2)),
                    698:                      metric);
                    699:            }
                    700: 
                    701:            VIFM_SET(vifi, r->rt_children);
                    702:            r->rt_dominants[vifi] = 0;
                    703: 
                    704:            if (uvifs[vifi].uv_flags & VIFF_NOFLOOD)
                    705:                NBRM_CLRMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
                    706:            else
                    707:                NBRM_SETMASK(r->rt_subordinates, uvifs[vifi].uv_nbrmap);
                    708: 
                    709:            if (metric > UNREACHABLE) {
                    710:                NBRM_SET(n->al_index, r->rt_subordinates);
                    711:                NBRM_SET(n->al_index, r->rt_subordadv);
                    712:            }
                    713:            update_table_entry(r, r->rt_gateway);
                    714:        } else {
                    715:            IF_DEBUG(DEBUG_RTDETAIL) {
                    716:                logit(LOG_DEBUG, 0, "%s on vif %d advertises %s with metric %d (ignored)",
                    717:                      inet_fmt(src, s1, sizeof(s1)), vifi, inet_fmts(origin, mask, s2, sizeof(s2)),
                    718:                      metric);
                    719:            }
                    720:        }
                    721:     }
                    722: }
                    723: 
                    724: 
                    725: /*
                    726:  * On every timer interrupt, advance the timer in each routing entry.
                    727:  */
                    728: void age_routes(void)
                    729: {
                    730:     struct rtentry *r, *next;
                    731:     extern u_long virtual_time;                /* from main.c */
                    732: 
                    733:     r = routing_table;
                    734:     while (r != NULL) {
                    735:        next = r->rt_next;
                    736: 
                    737:        if ((r->rt_timer += TIMER_INTERVAL) >= ROUTE_DISCARD_TIME) {
                    738:            /*
                    739:             * Time to garbage-collect the route entry.
                    740:             */
                    741:            del_table_entry(r, 0, DEL_ALL_ROUTES);
                    742:            discard_route(r);
                    743:        }
                    744:        else if (r->rt_timer >= ROUTE_EXPIRE_TIME &&
                    745:                 r->rt_metric != UNREACHABLE) {
                    746:            /*
                    747:             * Time to expire the route entry.  If the gateway is zero,
                    748:             * i.e., it is a route to a directly-connected subnet, just
                    749:             * set the timer back to zero; such routes expire only when
                    750:             * the interface to the subnet goes down.
                    751:             */
                    752:            if (r->rt_gateway == 0) {
                    753:                r->rt_timer = 0;
                    754:            }
                    755:            else {
                    756:                del_table_entry(r, 0, DEL_ALL_ROUTES);
                    757:                r->rt_metric   = UNREACHABLE;
                    758:                r->rt_flags   |= RTF_CHANGED;
                    759:                routes_changed = TRUE;
                    760:            }
                    761:        }
                    762:        else if (virtual_time % (ROUTE_REPORT_INTERVAL * 2) == 0) {
                    763:            /*
                    764:             * Time out subordinateness that hasn't been reported in
                    765:             * the last 2 intervals.
                    766:             */
                    767:            if (!NBRM_SAME(r->rt_subordinates, r->rt_subordadv)) {
                    768:                IF_DEBUG(DEBUG_ROUTE) {
                    769:                    logit(LOG_DEBUG, 0, "rt %s sub 0x%08x%08x subadv 0x%08x%08x metric %d",
                    770:                          RT_FMT(r, s1), r->rt_subordinates.hi, r->rt_subordinates.lo,
                    771:                          r->rt_subordadv.hi, r->rt_subordadv.lo, r->rt_metric);
                    772:                }
                    773:                NBRM_MASK(r->rt_subordinates, r->rt_subordadv);
                    774:                update_table_entry(r, r->rt_gateway);
                    775:            }
                    776:            NBRM_CLRALL(r->rt_subordadv);
                    777:        }
                    778: 
                    779:        r = next;
                    780:     }
                    781: }
                    782: 
                    783: 
                    784: /*
                    785:  * Mark all routes as unreachable.  This function is called only from
                    786:  * hup() in preparation for informing all neighbors that we are going
                    787:  * off the air.  For consistency, we ought also to delete all reachable
                    788:  * route entries from the kernel, but since we are about to exit we rely
                    789:  * on the kernel to do its own cleanup -- no point in making all those
                    790:  * expensive kernel calls now.
                    791:  */
                    792: void expire_all_routes(void)
                    793: {
                    794:     struct rtentry *r;
                    795: 
                    796:     for (r = routing_table; r != NULL; r = r->rt_next) {
                    797:        r->rt_metric   = UNREACHABLE;
                    798:        r->rt_flags   |= RTF_CHANGED;
                    799:        routes_changed = TRUE;
                    800:     }
                    801: }
                    802: 
                    803: 
                    804: /*
                    805:  * Delete all the routes in the routing table.
                    806:  */
                    807: void free_all_routes(void)
                    808: {
                    809:     struct rtentry *r, *next;
                    810: 
                    811:     r = routing_table;
                    812:     while (r != NULL) {
                    813:        next = r->rt_next;
                    814:        discard_route(r);
                    815:        r = next;
                    816:     }
                    817: }
                    818: 
                    819: 
                    820: /*
                    821:  * Process an incoming neighbor probe message.
                    822:  */
                    823: void accept_probe(u_int32 src, u_int32 dst, char *p, size_t datalen, u_int32 level)
                    824: {
                    825:     vifi_t vifi;
                    826:     static struct listaddr *unknowns = NULL;
                    827: 
                    828:     if ((vifi = find_vif(src, dst)) == NO_VIF) {
                    829:        struct listaddr *a, **prev;
                    830:        struct listaddr *match = NULL;
                    831:        time_t now = time(0);
                    832: 
                    833:        for (prev = &unknowns, a = *prev; a; a = *prev) {
                    834:            if (a->al_addr == src)
                    835:                match = a;
                    836:            if (a->al_ctime + 2 * a->al_timer < (u_long)now) {
                    837:                /* We haven't heard from it in a long time */
                    838:                *prev = a->al_next;
                    839:                free(a);
                    840:            } else {
                    841:                prev = &a->al_next;
                    842:            }
                    843:        }
                    844:        if (match == NULL) {
                    845:            match = *prev = (struct listaddr *)malloc(sizeof(struct listaddr));
                    846:            if (match == NULL) {
                    847:                logit(LOG_ERR, 0, "Malloc failed in route.c:accept_probe()\n");
                    848:                return;         /* NOTREACHED */
                    849:            }
                    850: 
                    851:            match->al_next = NULL;
                    852:            match->al_addr = src;
                    853:            match->al_timer = OLD_NEIGHBOR_EXPIRE_TIME;
                    854:            match->al_ctime = now - match->al_timer;
                    855:        }
                    856: 
                    857:        if (match->al_ctime + match->al_timer <= (u_long)now) {
                    858:            logit(LOG_WARNING, 0, "Ignoring probe from non-neighbor %s, check for misconfigured tunnel or routing on %s",
                    859:                  inet_fmt(src, s1, sizeof(s1)), s1);
                    860:            match->al_timer *= 2;
                    861:        } else {
                    862:            IF_DEBUG(DEBUG_PEER) {
                    863:                logit(LOG_DEBUG, 0, "Ignoring probe from non-neighbor %s (%d seconds until next warning)",
                    864:                      inet_fmt(src, s1, sizeof(s1)), match->al_ctime + match->al_timer - now);
                    865:            }
                    866:        }
                    867: 
                    868:        return;
                    869:     }
                    870: 
                    871:     update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level);
                    872: }
                    873: 
                    874: static int compare_rts(const void *rt1, const void *rt2)
                    875: {
                    876:     struct newrt *r1 = (struct newrt *)rt1;
                    877:     struct newrt *r2 = (struct newrt *)rt2;
                    878:     u_int32 m1 = ntohl(r1->mask);
                    879:     u_int32 m2 = ntohl(r2->mask);
                    880:     u_int32 o1, o2;
                    881: 
                    882:     if (m1 > m2)
                    883:        return -1;
                    884:     if (m1 < m2)
                    885:        return 1;
                    886: 
                    887:     /* masks are equal */
                    888:     o1 = ntohl(r1->origin);
                    889:     o2 = ntohl(r2->origin);
                    890:     if (o1 > o2)
                    891:        return -1;
                    892:     if (o1 < o2)
                    893:        return 1;
                    894: 
                    895:     return 0;
                    896: }
                    897: 
                    898: void blaster_alloc(vifi_t vifi)
                    899: {
                    900:     struct uvif *v;
                    901: 
                    902:     v = &uvifs[vifi];
                    903:     if (v->uv_blasterbuf)
                    904:        free(v->uv_blasterbuf);
                    905: 
                    906:     v->uv_blasterlen = 64 * 1024;
                    907:     v->uv_blasterbuf = malloc(v->uv_blasterlen);
                    908:     v->uv_blastercur = v->uv_blasterend = v->uv_blasterbuf;
                    909:     if (v->uv_blastertimer)
                    910:        timer_clearTimer(v->uv_blastertimer);
                    911:     v->uv_blastertimer = 0;
                    912: }
                    913: 
                    914: /*
                    915:  * Queue a route report from a route-blaster.
                    916:  * If the timer isn't running to process these reports,
                    917:  * start it.
                    918:  */
                    919: static void queue_blaster_report(vifi_t vifi, u_int32 src, u_int32 dst, char *p, size_t datalen, u_int32 level)
                    920: {
                    921:     struct blaster_hdr *bh;
                    922:     struct uvif *v;
                    923:     int bblen = sizeof(*bh) + ((datalen + 3) & ~3);
                    924: 
                    925:     v = &uvifs[vifi];
                    926:     if (v->uv_blasterend - v->uv_blasterbuf + bblen > v->uv_blasterlen) {
                    927:        int end = v->uv_blasterend - v->uv_blasterbuf;
                    928:        int cur = v->uv_blastercur - v->uv_blasterbuf;
                    929: 
                    930:        v->uv_blasterlen *= 2;
                    931:        IF_DEBUG(DEBUG_IF) {
                    932:            logit(LOG_DEBUG, 0, "Increasing blasterbuf to %d bytes", v->uv_blasterlen);
                    933:        }
                    934: 
                    935:        v->uv_blasterbuf = realloc(v->uv_blasterbuf, v->uv_blasterlen);
                    936:        if (v->uv_blasterbuf == NULL) {
                    937:            logit(LOG_WARNING, ENOMEM, "Turning off blaster on vif %d", vifi);
                    938:            v->uv_blasterlen = 0;
                    939:            v->uv_blasterend = v->uv_blastercur = NULL;
                    940:            v->uv_flags &= ~VIFF_BLASTER;
                    941:            return;
                    942:        }
                    943:        v->uv_blasterend = v->uv_blasterbuf + end;
                    944:        v->uv_blastercur = v->uv_blasterbuf + cur;
                    945:     }
                    946:     bh = (struct blaster_hdr *)v->uv_blasterend;
                    947:     bh->bh_src = src;
                    948:     bh->bh_dst = dst;
                    949:     bh->bh_level = level;
                    950:     bh->bh_datalen = datalen;
                    951:     memmove((char *)(bh + 1), p, datalen);
                    952:     v->uv_blasterend += bblen;
                    953: 
                    954:     if (v->uv_blastertimer == 0) {
                    955:        int *i;
                    956: 
                    957:        i = (int *)malloc(sizeof(int *));
                    958:        if (i == NULL) {
                    959:            logit(LOG_ERR, 0, "Malloc failed in route.c:queue_blaster_report()\n");
                    960:            return;             /* NOTREACHED */
                    961:        }
                    962: 
                    963:        *i = vifi;
                    964:        v->uv_blastertimer = timer_setTimer(5, process_blaster_report, i);
                    965:     }
                    966: }
                    967: 
                    968: /*
                    969:  * Periodic process; process up to 5 of the routes in the route-blaster
                    970:  * queue.  If there are more routes remaining, reschedule myself to run
                    971:  * in 1 second.
                    972:  */
                    973: static void process_blaster_report(void *vifip)
                    974: {
                    975:     vifi_t vifi = *(int *)vifip;
                    976:     struct uvif *v;
                    977:     struct blaster_hdr *bh;
                    978:     int i;
                    979: 
                    980:     IF_DEBUG(DEBUG_ROUTE) {
                    981:        logit(LOG_DEBUG, 0, "Processing vif %d blasted routes", vifi);
                    982:     }
                    983: 
                    984:     v = &uvifs[vifi];
                    985:     for (i = 0; i < 5; i++) {
                    986:        if (v->uv_blastercur >= v->uv_blasterend)
                    987:                break;
                    988: 
                    989:        bh = (struct blaster_hdr *)v->uv_blastercur;
                    990:        v->uv_blastercur += sizeof(*bh) + ((bh->bh_datalen + 3) & ~3);
                    991: 
                    992:        accept_report(bh->bh_src, bh->bh_dst, (char *)(bh + 1), -bh->bh_datalen, bh->bh_level);
                    993:     }
                    994: 
                    995:     if (v->uv_blastercur >= v->uv_blasterend) {
                    996:        v->uv_blastercur = v->uv_blasterbuf;
                    997:        v->uv_blasterend = v->uv_blasterbuf;
                    998:        v->uv_blastertimer = 0;
                    999:        free(vifip);
                   1000: 
                   1001:        IF_DEBUG(DEBUG_ROUTE) {
                   1002:            logit(LOG_DEBUG, 0, "Finish processing vif %d blaster", vifi);
                   1003:        }
                   1004:     } else {
                   1005:        IF_DEBUG(DEBUG_ROUTE) {
                   1006:            logit(LOG_DEBUG, 0, "More blasted routes to come on vif %d", vifi);
                   1007:        }
                   1008:        v->uv_blastertimer = timer_setTimer(1, process_blaster_report, vifip);
                   1009:     }
                   1010: }
                   1011: 
                   1012: /*
                   1013:  * Process an incoming route report message.
                   1014:  * If the report arrived on a vif marked as a "blaster", then just
                   1015:  * queue it and return; queue_blaster_report() will schedule it for
                   1016:  * processing later.  If datalen is negative, then this is actually
                   1017:  * a queued report so actually process it instead of queueing it.
                   1018:  */
                   1019: void accept_report(u_int32 src, u_int32 dst, char *p, size_t datalen, u_int32 level)
                   1020: {
                   1021:     vifi_t vifi;
                   1022:     size_t width, i, nrt = 0;
                   1023:     int metric;
                   1024:     u_int32 mask;
                   1025:     u_int32 origin;
                   1026:     static struct newrt rt[MAX_NUM_RT]; /* Use heap instead of stack */
                   1027:     struct listaddr *nbr;
                   1028: 
                   1029:     /*
                   1030:      * Emulate a stack variable.  We use the heap insted of the stack
                   1031:      * to prevent stack overflow on systems that cannot do stack realloc
                   1032:      * at runtime, e.g., non-MMU Linux systems.
                   1033:      */
                   1034:     memset(rt, 0, MAX_NUM_RT * sizeof(rt[0]));
                   1035: 
                   1036:     if ((vifi = find_vif(src, dst)) == NO_VIF) {
                   1037:        logit(LOG_INFO, 0, "Ignoring route report from non-neighbor %s",
                   1038:              inet_fmt(src, s1, sizeof(s1)));
                   1039:        return;
                   1040:     }
                   1041: 
                   1042:     if (uvifs[vifi].uv_flags & VIFF_BLASTER) {
                   1043:        if (datalen > 0) {
                   1044:            queue_blaster_report(vifi, src, dst, p, datalen, level);
                   1045:            return;
                   1046:        } else {
                   1047:            datalen = -datalen;
                   1048:        }
                   1049:     }
                   1050: 
                   1051:     nbr = update_neighbor(vifi, src, DVMRP_REPORT, NULL, 0, level);
                   1052:     if (!nbr)
                   1053:        return;
                   1054: 
                   1055:     if (datalen > 2 * 4096) {
                   1056:        logit(LOG_INFO, 0, "Ignoring oversized (%d bytes) route report from %s",
                   1057:              datalen, inet_fmt(src, s1, sizeof(s1)));
                   1058:        return;
                   1059:     }
                   1060: 
                   1061:     while (datalen > 0  && nrt < MAX_NUM_RT) { /* Loop through per-mask lists. */
                   1062:        if (datalen < 3) {
                   1063:            logit(LOG_WARNING, 0, "Received truncated route report from %s", 
                   1064:                  inet_fmt(src, s1, sizeof(s1)));
                   1065:            return;
                   1066:        }
                   1067: 
                   1068:        ((u_char *)&mask)[0] = 0xff;            width = 1;
                   1069:        if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
                   1070:        if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
                   1071:        if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
                   1072:        if (!inet_valid_mask(ntohl(mask))) {
                   1073:            logit(LOG_WARNING, 0, "%s reports bogus netmask 0x%08x (%s)",
                   1074:                  inet_fmt(src, s1, sizeof(s1)), ntohl(mask), inet_fmt(mask, s2, sizeof(s2)));
                   1075:            return;
                   1076:        }
                   1077:        datalen -= 3;
                   1078: 
                   1079:        do {                    /* Loop through (origin, metric) pairs */
                   1080:            if (datalen < width + 1) {
                   1081:                logit(LOG_WARNING, 0, "Received truncated route report from %s", 
                   1082:                      inet_fmt(src, s1, sizeof(s1)));
                   1083:                return;
                   1084:            }
                   1085:            origin = 0;
                   1086:            for (i = 0; i < width; ++i)
                   1087:                ((char *)&origin)[i] = *p++;
                   1088:            metric = *p++;
                   1089:            datalen -= width + 1;
                   1090:            rt[nrt].mask   = mask;
                   1091:            rt[nrt].origin = origin;
                   1092:            rt[nrt].metric = (metric & 0x7f);
                   1093:            ++nrt;
                   1094:        } while (!(metric & 0x80) && nrt < MAX_NUM_RT);
                   1095:     }
                   1096: 
                   1097:     qsort((char *)rt, nrt, sizeof(rt[0]), compare_rts);
                   1098:     start_route_updates();
                   1099: 
                   1100:     /*
                   1101:      * If the last entry is default, change mask from 0xff000000 to 0
                   1102:      */
                   1103:     if (nrt > 0 && rt[nrt - 1].origin == 0)
                   1104:        rt[nrt - 1].mask = 0;
                   1105: 
                   1106:     IF_DEBUG(DEBUG_ROUTE) {
                   1107:        logit(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
                   1108:              inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
                   1109:     }
                   1110: 
                   1111:     for (i = 0; i < nrt; ++i) {
                   1112:        if (i > 0 && rt[i].origin == rt[i - 1].origin && rt[i].mask == rt[i - 1].mask) {
                   1113:            logit(LOG_WARNING, 0, "%s reports duplicate route for %s",
                   1114:                   inet_fmt(src, s1, sizeof(s1)), inet_fmts(rt[i].origin, rt[i].mask, s2, sizeof(s2)));
                   1115:            continue;
                   1116:        }
                   1117:        /* Only filter non-poisoned updates. */
                   1118:        if (uvifs[vifi].uv_filter && rt[i].metric < UNREACHABLE) {
                   1119:            struct vf_element *vfe;
                   1120:            int match = 0;
                   1121: 
                   1122:            for (vfe = uvifs[vifi].uv_filter->vf_filter; vfe; vfe = vfe->vfe_next) {
                   1123:                if (vfe->vfe_flags & VFEF_EXACT) {
                   1124:                    if ((vfe->vfe_addr == rt[i].origin) && (vfe->vfe_mask == rt[i].mask)) {
                   1125:                        match = 1;
                   1126:                        break;
                   1127:                    }
                   1128:                } else {
                   1129:                    if ((rt[i].origin & vfe->vfe_mask) == vfe->vfe_addr) {
                   1130:                        match = 1;
                   1131:                        break;
                   1132:                    }
                   1133:                }
                   1134:            }
                   1135:            if ((uvifs[vifi].uv_filter->vf_type == VFT_ACCEPT && match == 0) ||
                   1136:                (uvifs[vifi].uv_filter->vf_type == VFT_DENY && match == 1)) {
                   1137:                IF_DEBUG(DEBUG_ROUTE) {
                   1138:                    logit(LOG_DEBUG, 0, "%s skipped on vif %d because it %s %s",
                   1139:                          inet_fmts(rt[i].origin, rt[i].mask, s1, sizeof(s1)),
                   1140:                          vifi, match ? "matches" : "doesn't match",
                   1141:                          match ? inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s2, sizeof(s2))
                   1142:                          : "the filter");
                   1143:                }
                   1144: #if 0
                   1145:                rt[i].metric += vfe->vfe_addmetric;
                   1146:                if (rt[i].metric > UNREACHABLE)
                   1147: #endif
                   1148:                    rt[i].metric = UNREACHABLE;
                   1149:            }
                   1150:        }
                   1151:        update_route(rt[i].origin, rt[i].mask, rt[i].metric, src, vifi, nbr);
                   1152:     }
                   1153: 
                   1154:     if (routes_changed && !delay_change_reports)
                   1155:        report_to_all_neighbors(CHANGED_ROUTES);
                   1156: }
                   1157: 
                   1158: 
                   1159: /*
                   1160:  * Send a route report message to destination 'dst', via virtual interface
                   1161:  * 'vifi'.  'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
                   1162:  */
                   1163: void report(int which_routes, vifi_t vifi, u_int32 dst)
                   1164: {
                   1165:     struct rtentry *this;
                   1166:     int i;
                   1167: 
                   1168:     this = rt_end;
                   1169:     while (this && this != routing_table) {
                   1170:        i = report_chunk(which_routes, this, vifi, dst);
                   1171:        while (i-- > 0)
                   1172:            this = this->rt_prev;
                   1173:     }
                   1174: }
                   1175: 
                   1176: 
                   1177: /*
                   1178:  * Send a route report message to all neighboring routers.
                   1179:  * 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
                   1180:  */
                   1181: void report_to_all_neighbors(int which_routes)
                   1182: {
                   1183:     vifi_t vifi;
                   1184:     struct uvif *v;
                   1185:     struct rtentry *r;
                   1186:     int routes_changed_before;
                   1187: 
                   1188:     /*
                   1189:      * Remember the state of the global routes_changed flag before
                   1190:      * generating the reports, and clear the flag.
                   1191:      */
                   1192:     routes_changed_before = routes_changed;
                   1193:     routes_changed = FALSE;
                   1194: 
                   1195: 
                   1196:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                   1197:        if (!NBRM_ISEMPTY(v->uv_nbrmap)) {
                   1198:            report(which_routes, vifi, v->uv_dst_addr);
                   1199:        }
                   1200:     }
                   1201: 
                   1202:     /*
                   1203:      * If there were changed routes before we sent the reports AND
                   1204:      * if no new changes occurred while sending the reports, clear
                   1205:      * the change flags in the individual route entries.  If changes
                   1206:      * did occur while sending the reports, new reports will be
                   1207:      * generated at the next timer interrupt.
                   1208:      */
                   1209:     if (routes_changed_before && !routes_changed) {
                   1210:        for (r = routing_table; r != NULL; r = r->rt_next) {
                   1211:            r->rt_flags &= ~RTF_CHANGED;
                   1212:        }
                   1213:     }
                   1214: 
                   1215:     /*
                   1216:      * Set a flag to inhibit further reports of changed routes until the
                   1217:      * next timer interrupt.  This is to alleviate update storms.
                   1218:      */
                   1219:     delay_change_reports = TRUE;
                   1220: }
                   1221: 
                   1222: /*
                   1223:  * Send a route report message to destination 'dst', via virtual interface
                   1224:  * 'vifi'.  'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
                   1225:  */
                   1226: static int report_chunk(int which_routes, struct rtentry *start_rt, vifi_t vifi, u_int32 UNUSED dst)
                   1227: {
                   1228:     struct rtentry *r;
                   1229:     char *p;
                   1230:     int i;
                   1231:     size_t nrt = 0;
                   1232:     struct uvif *v = &uvifs[vifi];
                   1233:     int datalen = 0;
                   1234:     int width = 0;
                   1235:     u_int32 mask = 0;
                   1236:     u_int32 src;
                   1237:     int admetric = v->uv_admetric;
                   1238:     int metric;
                   1239: 
                   1240:     src = v->uv_lcl_addr;
                   1241:     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
                   1242: 
                   1243:     for (r = start_rt; r != routing_table; r = r->rt_prev) {
                   1244:        if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED)) {
                   1245:            nrt++;
                   1246:            continue;
                   1247:        }
                   1248: 
                   1249:        /*
                   1250:         * Do not poison-reverse a route for a directly-connected
                   1251:         * subnetwork on that subnetwork.  This can cause loops when
                   1252:         * some router on the subnetwork is misconfigured.
                   1253:         */
                   1254:        if (r->rt_gateway == 0 && r->rt_parent == vifi) {
                   1255:            nrt++;
                   1256:            continue;
                   1257:        }
                   1258: 
                   1259:        if (v->uv_filter && v->uv_filter->vf_flags & VFF_BIDIR) {
                   1260:            struct vf_element *vfe;
                   1261:            int match = 0;
                   1262: 
                   1263:            for (vfe = v->uv_filter->vf_filter; vfe; vfe = vfe->vfe_next) {
                   1264:                if (vfe->vfe_flags & VFEF_EXACT) {
                   1265:                    if ((vfe->vfe_addr == r->rt_origin) &&
                   1266:                        (vfe->vfe_mask == r->rt_originmask)) {
                   1267:                            match = 1;
                   1268:                            break;
                   1269:                    }
                   1270:                } else {
                   1271:                    if ((r->rt_origin & vfe->vfe_mask) == vfe->vfe_addr) {
                   1272:                            match = 1;
                   1273:                            break;
                   1274:                    }
                   1275:                }
                   1276:            }
                   1277:            if ((v->uv_filter->vf_type == VFT_ACCEPT && match == 0) ||
                   1278:                (v->uv_filter->vf_type == VFT_DENY && match == 1)) {
                   1279:                IF_DEBUG(DEBUG_ROUTE) {
                   1280:                    logit(LOG_DEBUG, 0, "%s not reported on vif %d because it %s %s",
                   1281:                          RT_FMT(r, s1), vifi, match ? "matches" : "doesn't match",
                   1282:                          match ? inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s2, sizeof(s2))
                   1283:                          : "the filter");
                   1284:                }
                   1285:                nrt++;
                   1286:                continue;
                   1287:            }
                   1288:        }
                   1289: 
                   1290:        /*
                   1291:         * If there is no room for this route in the current message,
                   1292:         * send it & return how many routes we sent.
                   1293:         */
                   1294:        if (datalen + ((r->rt_originmask == mask)
                   1295:                       ? (width + 1)
                   1296:                       : (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
                   1297:            *(p-1) |= 0x80;
                   1298:            send_on_vif(v, 0, DVMRP_REPORT, datalen);
                   1299: 
                   1300:            return nrt;
                   1301:        }
                   1302: 
                   1303:        if (r->rt_originmask != mask || datalen == 0) {
                   1304:            mask  = r->rt_originmask;
                   1305:            width = r->rt_originwidth;
                   1306:            if (datalen != 0) *(p-1) |= 0x80;
                   1307:            *p++ = ((char *)&mask)[1];
                   1308:            *p++ = ((char *)&mask)[2];
                   1309:            *p++ = ((char *)&mask)[3];
                   1310:            datalen += 3;
                   1311:        }
                   1312:        for (i = 0; i < width; ++i)
                   1313:            *p++ = ((char *)&(r->rt_origin))[i];
                   1314: 
                   1315:        metric = r->rt_metric + admetric;
                   1316:        if (metric > UNREACHABLE)
                   1317:            metric = UNREACHABLE;
                   1318: 
                   1319:        if (r->rt_parent != vifi && AVOID_TRANSIT(vifi, r))
                   1320:            metric = UNREACHABLE;
                   1321: 
                   1322:        *p++ = (r->rt_parent == vifi && metric != UNREACHABLE)
                   1323:            ? (char)(metric + UNREACHABLE) /* "poisoned reverse" */
                   1324:            : (char)(metric);
                   1325:        ++nrt;
                   1326:        datalen += width + 1;
                   1327:     }
                   1328:     if (datalen != 0) {
                   1329:        *(p-1) |= 0x80;
                   1330:        send_on_vif(v, 0, DVMRP_REPORT, datalen);
                   1331:     }
                   1332: 
                   1333:     return nrt;
                   1334: }
                   1335: 
                   1336: /*
                   1337:  * send the next chunk of our routing table to all neighbors.
                   1338:  * return the length of the smallest chunk we sent out.
                   1339:  */
                   1340: int report_next_chunk(void)
                   1341: {
                   1342:     vifi_t vifi;
                   1343:     struct uvif *v;
                   1344:     struct rtentry *sr;
                   1345:     int i, n = 0, min = 20000;
                   1346:     static int start_rt;
                   1347: 
                   1348:     if (nroutes <= 0)
                   1349:        return 0;
                   1350: 
                   1351:     /*
                   1352:      * find this round's starting route.
                   1353:      */
                   1354:     for (sr = rt_end, i = start_rt; sr && --i >= 0; ) {
                   1355:        sr = sr->rt_prev;
                   1356:        if (sr == routing_table)
                   1357:            sr = rt_end;
                   1358:     }
                   1359: 
                   1360:     /*
                   1361:      * send one chunk of routes starting at this round's start to
                   1362:      * all our neighbors.
                   1363:      */
                   1364:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
                   1365:        if (!NBRM_ISEMPTY(v->uv_nbrmap)) {
                   1366:            n = report_chunk(ALL_ROUTES, sr, vifi, v->uv_dst_addr);
                   1367:            if (n < min)
                   1368:                min = n;
                   1369:        }
                   1370:     }
                   1371:     if (min == 20000)
                   1372:        min = 0;        /* Neighborless router didn't send any routes */
                   1373: 
                   1374:     n = min;
                   1375:     IF_DEBUG(DEBUG_ROUTE) {
                   1376:        logit(LOG_INFO, 0, "update %d starting at %d of %d",
                   1377:              n, (nroutes - start_rt), nroutes);
                   1378:     }
                   1379: 
                   1380:     start_rt = (start_rt + n) % nroutes;
                   1381: 
                   1382:     return n;
                   1383: }
                   1384: 
                   1385: 
                   1386: /*
                   1387:  * Print the contents of the routing table on file 'fp'.
                   1388:  */
                   1389: void dump_routes(FILE *fp)
                   1390: {
                   1391:     struct rtentry *r;
                   1392:     vifi_t i;
                   1393: 
                   1394:     fprintf(fp, "Multicast Routing Table (%u entr%s)\n", nroutes, nroutes == 1 ? "y" : "ies");
                   1395:     fputs(" Origin-Subnet      From-Gateway    Metric Tmr Fl In-Vif  Out-Vifs\n", fp);
                   1396: 
                   1397:     for (r = routing_table; r; r = r->rt_next) {
                   1398:        fprintf(fp, " %-18s %-15s ",
                   1399:                inet_fmts(r->rt_origin, r->rt_originmask, s1, sizeof(s1)),
                   1400:                (r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway, s2, sizeof(s2)));
                   1401: 
                   1402:        fprintf(fp, (r->rt_metric == UNREACHABLE) ? "  NR " : "%4u ",
                   1403:                r->rt_metric);
                   1404: 
                   1405:        fprintf(fp, "  %3u %c%c %3u   ", r->rt_timer,
                   1406:                (r->rt_flags & RTF_CHANGED) ? 'C' : '.',
                   1407:                (r->rt_flags & RTF_HOLDDOWN) ? 'H' : '.',
                   1408:                r->rt_parent);
                   1409: 
                   1410:        for (i = 0; i < numvifs; ++i) {
                   1411:            struct listaddr *n;
                   1412:            char l = '[';
                   1413: 
                   1414:            if (VIFM_ISSET(i, r->rt_children)) {
                   1415:                if ((uvifs[i].uv_flags & VIFF_TUNNEL) &&
                   1416:                    !NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates))
                   1417:                        /* Don't print out parenthood of a leaf tunnel. */
                   1418:                        continue;
                   1419: 
                   1420:                fprintf(fp, " %u", i);
                   1421:                if (!NBRM_ISSETMASK(uvifs[i].uv_nbrmap, r->rt_subordinates))
                   1422:                    fprintf(fp, "*");
                   1423: 
                   1424:                for (n = uvifs[i].uv_neighbors; n; n = n->al_next) {
                   1425:                    if (NBRM_ISSET(n->al_index, r->rt_subordinates)) {
                   1426:                        fprintf(fp, "%c%d", l, n->al_index);
                   1427:                        l = ',';
                   1428:                    }
                   1429:                }
                   1430: 
                   1431:                if (l == ',')
                   1432:                    fprintf(fp, "]");
                   1433:            }
                   1434:        }
                   1435:        fprintf(fp, "\n");
                   1436:     }
                   1437:     fprintf(fp, "\n");
                   1438: }
                   1439: 
                   1440: struct rtentry *determine_route(u_int32 src)
                   1441: {
                   1442:     struct rtentry *rt;
                   1443: 
                   1444:     for (rt = routing_table; rt != NULL; rt = rt->rt_next) {
                   1445:        if (rt->rt_origin == (src & rt->rt_originmask) &&
                   1446:            rt->rt_metric != UNREACHABLE) 
                   1447:            break;
                   1448:     }
                   1449: 
                   1450:     return rt;
                   1451: }
                   1452: 
                   1453: /**
                   1454:  * Local Variables:
                   1455:  *  version-control: t
                   1456:  *  indent-tabs-mode: t
                   1457:  *  c-file-style: "ellemtel"
                   1458:  *  c-basic-offset: 4
                   1459:  * End:
                   1460:  */

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