Annotation of embedaddon/pimdd/mrt.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *  Copyright (c) 1998 by the University of Oregon.
        !             3:  *  All rights reserved.
        !             4:  *
        !             5:  *  Permission to use, copy, modify, and distribute this software and
        !             6:  *  its documentation in source and binary forms for lawful
        !             7:  *  purposes and without fee is hereby granted, provided
        !             8:  *  that the above copyright notice appear in all copies and that both
        !             9:  *  the copyright notice and this permission notice appear in supporting
        !            10:  *  documentation, and that any documentation, advertising materials,
        !            11:  *  and other materials related to such distribution and use acknowledge
        !            12:  *  that the software was developed by the University of Oregon.
        !            13:  *  The name of the University of Oregon may not be used to endorse or 
        !            14:  *  promote products derived from this software without specific prior 
        !            15:  *  written permission.
        !            16:  *
        !            17:  *  THE UNIVERSITY OF OREGON DOES NOT MAKE ANY REPRESENTATIONS
        !            18:  *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
        !            19:  *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
        !            20:  *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            21:  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND 
        !            22:  *  NON-INFRINGEMENT.
        !            23:  *
        !            24:  *  IN NO EVENT SHALL UO, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
        !            25:  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
        !            26:  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
        !            27:  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            28:  *
        !            29:  *  Other copyrights might apply to parts of this software and are so
        !            30:  *  noted when applicable.
        !            31:  */
        !            32: /*
        !            33:  *  Questions concerning this software should be directed to 
        !            34:  *  Kurt Windisch (kurtw@antc.uoregon.edu)
        !            35:  *
        !            36:  *  $Id: mrt.c,v 1.16 1998/12/22 21:50:17 kurtw Exp $
        !            37:  */
        !            38: /*
        !            39:  * Part of this program has been derived from PIM sparse-mode pimd.
        !            40:  * The pimd program is covered by the license in the accompanying file
        !            41:  * named "LICENSE.pimd".
        !            42:  *  
        !            43:  * The pimd program is COPYRIGHT 1998 by University of Southern California.
        !            44:  *
        !            45:  * Part of this program has been derived from mrouted.
        !            46:  * The mrouted program is covered by the license in the accompanying file
        !            47:  * named "LICENSE.mrouted".
        !            48:  * 
        !            49:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
        !            50:  * Leland Stanford Junior University.
        !            51:  *
        !            52:  */
        !            53: 
        !            54: #include "defs.h"
        !            55: 
        !            56: srcentry_t             *srclist;
        !            57: grpentry_t             *grplist;
        !            58: 
        !            59: /*
        !            60:  * Local functions definition
        !            61:  */
        !            62: static srcentry_t *create_srcentry     __P((u_int32 source));
        !            63: static int        search_srclist       __P((u_int32 source,
        !            64:                                            srcentry_t **sourceEntry));
        !            65: static int        search_srcmrtlink    __P((srcentry_t *srcentry_ptr,
        !            66:                                            u_int32 group,
        !            67:                                            mrtentry_t **mrtPtr));
        !            68: static void       insert_srcmrtlink    __P((mrtentry_t *elementPtr,
        !            69:                                            mrtentry_t *insertPtr,
        !            70:                                            srcentry_t *srcListPtr));
        !            71: static grpentry_t *create_grpentry     __P((u_int32 group));
        !            72: static int        search_grplist       __P((u_int32 group,
        !            73:                                            grpentry_t **groupEntry));
        !            74: static int        search_grpmrtlink    __P((grpentry_t *grpentry_ptr,
        !            75:                                            u_int32 source,
        !            76:                                            mrtentry_t **mrtPtr));
        !            77: static void       insert_grpmrtlink    __P((mrtentry_t *elementPtr,
        !            78:                                            mrtentry_t *insertPtr,
        !            79:                                            grpentry_t *grpListPtr));
        !            80: static mrtentry_t *alloc_mrtentry      __P((srcentry_t *srcentry_ptr,
        !            81:                                            grpentry_t *grpentry_ptr));
        !            82: static mrtentry_t *create_mrtentry     __P((srcentry_t *srcentry_ptr,
        !            83:                                            grpentry_t *grpentry_ptr,
        !            84:                                            u_int16 flags));
        !            85: 
        !            86: 
        !            87: void 
        !            88: init_pim_mrt()
        !            89: {
        !            90: 
        !            91:     /* TODO: delete any existing routing table */
        !            92: 
        !            93:     /* Initialize the source list */
        !            94:     /* The first entry has address 'INADDR_ANY' and is not used */
        !            95:     /* The order is the smallest address first. */
        !            96:     srclist            = (srcentry_t *)malloc(sizeof(srcentry_t));
        !            97:     srclist->next       = (srcentry_t *)NULL;
        !            98:     srclist->prev       = (srcentry_t *)NULL;
        !            99:     srclist->address   = INADDR_ANY_N;
        !           100:     srclist->mrtlink    = (mrtentry_t *)NULL;
        !           101:     srclist->incoming   = NO_VIF;
        !           102:     srclist->upstream   = (pim_nbr_entry_t *)NULL;
        !           103:     srclist->metric     = 0;
        !           104:     srclist->preference = 0;
        !           105:     RESET_TIMER(srclist->timer);
        !           106:     
        !           107:     /* Initialize the group list */
        !           108:     /* The first entry has address 'INADDR_ANY' and is not used */
        !           109:     /* The order is the smallest address first. */
        !           110:     grplist            = (grpentry_t *)malloc(sizeof(grpentry_t));
        !           111:     grplist->next       = (grpentry_t *)NULL;
        !           112:     grplist->prev       = (grpentry_t *)NULL;
        !           113:     grplist->group     = INADDR_ANY_N;
        !           114:     grplist->mrtlink    = (mrtentry_t *)NULL;
        !           115: }
        !           116: 
        !           117: 
        !           118: grpentry_t*
        !           119: find_group(group)
        !           120:     u_int32 group;
        !           121: {
        !           122:     grpentry_t *grpentry_ptr;
        !           123: 
        !           124:     if (!IN_MULTICAST(ntohl(group)))
        !           125:        return (grpentry_t *)NULL;
        !           126:     
        !           127:     if (search_grplist(group, &grpentry_ptr) == TRUE) {
        !           128:        /* Group found! */
        !           129:        return (grpentry_ptr);
        !           130:     }
        !           131:     return (grpentry_t *)NULL;
        !           132: }
        !           133: 
        !           134: 
        !           135: srcentry_t *
        !           136: find_source(source)
        !           137:     u_int32 source;
        !           138: {
        !           139:     srcentry_t *srcentry_ptr;
        !           140: 
        !           141:     if (!inet_valid_host(source))
        !           142:        return (srcentry_t *)NULL;
        !           143:     
        !           144:     if (search_srclist(source, &srcentry_ptr) == TRUE) {
        !           145:        /* Source found! */
        !           146:        return (srcentry_ptr);
        !           147:     }
        !           148:     return (srcentry_t *)NULL;
        !           149: }
        !           150: 
        !           151: 
        !           152: mrtentry_t *
        !           153: find_route(source, group, flags, create)
        !           154:     u_int32 source, group;
        !           155:     u_int16 flags;
        !           156:     char create;
        !           157: {
        !           158:     srcentry_t *srcentry_ptr;
        !           159:     grpentry_t *grpentry_ptr;
        !           160:     mrtentry_t *mrtentry_ptr;
        !           161: 
        !           162:     if (!IN_MULTICAST(ntohl(group)))
        !           163:        return (mrtentry_t *)NULL;
        !           164:     
        !           165:     if (!inet_valid_host(source))
        !           166:        return (mrtentry_t *)NULL;
        !           167:     
        !           168:     if (create == DONT_CREATE) {
        !           169:        if (search_grplist(group, &grpentry_ptr) == FALSE) 
        !           170:            return (mrtentry_t *)NULL;
        !           171:        /* Search for the source */
        !           172:        if (search_grpmrtlink(grpentry_ptr, source,
        !           173:                              &mrtentry_ptr) == TRUE) {
        !           174:            /* Exact (S,G) entry found */
        !           175:            return (mrtentry_ptr);
        !           176:        }
        !           177:        return (mrtentry_t *)NULL;
        !           178:     }
        !           179: 
        !           180: 
        !           181:     /* Creation allowed */
        !           182: 
        !           183:     grpentry_ptr = create_grpentry(group);
        !           184:     if (grpentry_ptr == (grpentry_t *)NULL) {
        !           185:        return (mrtentry_t *)NULL;
        !           186:     }
        !           187: 
        !           188:     /* Setup the (S,G) routing entry */
        !           189:     srcentry_ptr = create_srcentry(source);
        !           190:     if (srcentry_ptr == (srcentry_t *)NULL) {
        !           191:        if (grpentry_ptr->mrtlink == (mrtentry_t *)NULL) {
        !           192:            /* New created grpentry. Delete it. */
        !           193:            delete_grpentry(grpentry_ptr);
        !           194:        }
        !           195:        return (mrtentry_t *)NULL;
        !           196:     }
        !           197: 
        !           198:     mrtentry_ptr = create_mrtentry(srcentry_ptr, grpentry_ptr, MRTF_SG);
        !           199:     if (mrtentry_ptr == (mrtentry_t *)NULL) {
        !           200:        if (grpentry_ptr->mrtlink == (mrtentry_t *)NULL) {
        !           201:            /* New created grpentry. Delete it. */
        !           202:            delete_grpentry(grpentry_ptr);
        !           203:        }
        !           204:        if (srcentry_ptr->mrtlink == (mrtentry_t *)NULL) {
        !           205:            /* New created srcentry. Delete it. */
        !           206:            delete_srcentry(srcentry_ptr);
        !           207:        }
        !           208:        return (mrtentry_t *)NULL;
        !           209:     }
        !           210:     
        !           211:     if (mrtentry_ptr->flags & MRTF_NEW) {
        !           212:        /* The mrtentry pref/metric should be the pref/metric of the 
        !           213:         * _upstream_ assert winner. Since this isn't known now, 
        !           214:         * set it to the config'ed default
        !           215:         */
        !           216:        mrtentry_ptr->incoming = srcentry_ptr->incoming;
        !           217:        mrtentry_ptr->upstream = srcentry_ptr->upstream;
        !           218:        mrtentry_ptr->metric   = srcentry_ptr->metric;
        !           219:        mrtentry_ptr->preference = srcentry_ptr->preference;
        !           220:     }
        !           221:     
        !           222:     return (mrtentry_ptr);
        !           223: }
        !           224: 
        !           225: 
        !           226: void
        !           227: delete_srcentry(srcentry_ptr)
        !           228:     srcentry_t *srcentry_ptr;
        !           229: {
        !           230:     mrtentry_t *mrtentry_ptr;
        !           231:     mrtentry_t *mrtentry_next;
        !           232: 
        !           233:     if (srcentry_ptr == (srcentry_t *)NULL)
        !           234:        return;
        !           235:     /* TODO: XXX: the first entry is unused and always there */
        !           236:     srcentry_ptr->prev->next =         srcentry_ptr->next;
        !           237:     if (srcentry_ptr->next != (srcentry_t *)NULL)
        !           238:        srcentry_ptr->next->prev = srcentry_ptr->prev;
        !           239:     
        !           240:     for (mrtentry_ptr = srcentry_ptr->mrtlink;
        !           241:         mrtentry_ptr != (mrtentry_t *)NULL;
        !           242:         mrtentry_ptr = mrtentry_next) {
        !           243:        mrtentry_next = mrtentry_ptr->srcnext;
        !           244:        if (mrtentry_ptr->grpprev != (mrtentry_t *)NULL)
        !           245:            mrtentry_ptr->grpprev->grpnext = mrtentry_ptr->grpnext;
        !           246:        else {
        !           247:            mrtentry_ptr->group->mrtlink = mrtentry_ptr->grpnext;
        !           248:            if (mrtentry_ptr->grpnext == (mrtentry_t *)NULL) {
        !           249:                /* Delete the group entry */
        !           250:                delete_grpentry(mrtentry_ptr->group);
        !           251:            }
        !           252:        }
        !           253:        if (mrtentry_ptr->grpnext != (mrtentry_t *)NULL)
        !           254:            mrtentry_ptr->grpnext->grpprev = mrtentry_ptr->grpprev;
        !           255:        FREE_MRTENTRY(mrtentry_ptr);
        !           256:     }
        !           257:     free((char *)srcentry_ptr);
        !           258: }
        !           259: 
        !           260: 
        !           261: void
        !           262: delete_grpentry(grpentry_ptr)
        !           263:     grpentry_t *grpentry_ptr;
        !           264: {
        !           265:     mrtentry_t *mrtentry_ptr;
        !           266:     mrtentry_t *mrtentry_next;
        !           267:     
        !           268:     if (grpentry_ptr == (grpentry_t *)NULL)
        !           269:        return;
        !           270:     /* TODO: XXX: the first entry is unused and always there */
        !           271:     grpentry_ptr->prev->next = grpentry_ptr->next;
        !           272:     if (grpentry_ptr->next != (grpentry_t *)NULL)
        !           273:        grpentry_ptr->next->prev = grpentry_ptr->prev;
        !           274:     
        !           275:     for (mrtentry_ptr = grpentry_ptr->mrtlink;
        !           276:         mrtentry_ptr != (mrtentry_t *)NULL;
        !           277:         mrtentry_ptr = mrtentry_next) {
        !           278:        mrtentry_next = mrtentry_ptr->grpnext;
        !           279:        if (mrtentry_ptr->srcprev != (mrtentry_t *)NULL)
        !           280:            mrtentry_ptr->srcprev->srcnext = mrtentry_ptr->srcnext;
        !           281:        else {
        !           282:            mrtentry_ptr->source->mrtlink = mrtentry_ptr->srcnext;
        !           283:            if (mrtentry_ptr->srcnext == (mrtentry_t *)NULL) {
        !           284:                /* Delete the srcentry if this was the last routing entry */
        !           285:                delete_srcentry(mrtentry_ptr->source);
        !           286:            }
        !           287:        }
        !           288:        if (mrtentry_ptr->srcnext != (mrtentry_t *)NULL)
        !           289:            mrtentry_ptr->srcnext->srcprev = mrtentry_ptr->srcprev;
        !           290:        FREE_MRTENTRY(mrtentry_ptr);
        !           291:     }
        !           292:     free((char *)grpentry_ptr);
        !           293: }
        !           294: 
        !           295: 
        !           296: void
        !           297: delete_mrtentry(mrtentry_ptr)
        !           298:     mrtentry_t *mrtentry_ptr;
        !           299: {
        !           300:     if (mrtentry_ptr == (mrtentry_t *)NULL)
        !           301:        return;
        !           302: 
        !           303:     /* Delete the kernel cache first */
        !           304:     k_del_mfc(igmp_socket, mrtentry_ptr->source->address,
        !           305:                  mrtentry_ptr->group->group);
        !           306: 
        !           307: #ifdef RSRR
        !           308:     /* Tell the reservation daemon */
        !           309:     rsrr_cache_clean(mrtentry_ptr);
        !           310: #endif /* RSRR */
        !           311: 
        !           312:    /* (S,G) mrtentry */
        !           313:     /* Delete from the grpentry MRT chain */
        !           314:     if (mrtentry_ptr->grpprev != (mrtentry_t *)NULL)
        !           315:        mrtentry_ptr->grpprev->grpnext = mrtentry_ptr->grpnext;
        !           316:     else {
        !           317:        mrtentry_ptr->group->mrtlink = mrtentry_ptr->grpnext;
        !           318:        if (mrtentry_ptr->grpnext == (mrtentry_t *)NULL) {
        !           319:            /* Delete the group entry */
        !           320:            delete_grpentry(mrtentry_ptr->group);
        !           321:        }
        !           322:     }
        !           323:        
        !           324:     if (mrtentry_ptr->grpnext != (mrtentry_t *)NULL)
        !           325:        mrtentry_ptr->grpnext->grpprev = mrtentry_ptr->grpprev;
        !           326:     
        !           327:     /* Delete from the srcentry MRT chain */
        !           328:     if (mrtentry_ptr->srcprev != (mrtentry_t *)NULL)
        !           329:        mrtentry_ptr->srcprev->srcnext = mrtentry_ptr->srcnext;
        !           330:     else {
        !           331:        mrtentry_ptr->source->mrtlink = mrtentry_ptr->srcnext;
        !           332:        if (mrtentry_ptr->srcnext == (mrtentry_t *)NULL) {
        !           333:            /* Delete the srcentry if this was the last routing entry */
        !           334:            delete_srcentry(mrtentry_ptr->source);
        !           335:        }
        !           336:     }
        !           337:     if (mrtentry_ptr->srcnext != (mrtentry_t *)NULL)
        !           338:        mrtentry_ptr->srcnext->srcprev = mrtentry_ptr->srcprev;
        !           339: 
        !           340:     FREE_MRTENTRY(mrtentry_ptr);
        !           341: }
        !           342: 
        !           343: 
        !           344: static int
        !           345: search_srclist(source, sourceEntry)
        !           346:     u_int32 source;
        !           347:     register srcentry_t **sourceEntry;
        !           348: {
        !           349:     register srcentry_t *s_prev,*s;
        !           350:     u_int32 source_h = ntohl(source);
        !           351:     
        !           352:     for (s_prev = srclist, s = s_prev->next; s != (srcentry_t *)NULL;
        !           353:         s_prev = s, s = s->next) {
        !           354:        /* The srclist is ordered with the smallest addresses first.
        !           355:         * The first entry is not used.
        !           356:         */
        !           357:        if (ntohl(s->address) < source_h)
        !           358:            continue;
        !           359:        if (s->address == source) {
        !           360:            *sourceEntry = s;
        !           361:            return(TRUE);
        !           362:        }
        !           363:        break;  
        !           364:     }
        !           365:     *sourceEntry = s_prev;   /* The insertion point is between s_prev and s */
        !           366:     return(FALSE);
        !           367: }
        !           368: 
        !           369: 
        !           370: static int
        !           371: search_grplist(group, groupEntry)
        !           372:     u_int32 group;
        !           373:     register grpentry_t **groupEntry;
        !           374: {
        !           375:     register grpentry_t *g_prev, *g;
        !           376:     u_int32 group_h = ntohl(group);
        !           377:     
        !           378:     for (g_prev = grplist, g = g_prev->next; g != (grpentry_t *)NULL;
        !           379:         g_prev = g, g = g->next) {
        !           380:        /* The grplist is ordered with the smallest address first.
        !           381:         * The first entry is not used.
        !           382:         */
        !           383:        if (ntohl(g->group) < group_h)
        !           384:            continue;
        !           385:        if (g->group == group) {
        !           386:            *groupEntry = g;
        !           387:            return(TRUE);
        !           388:        }
        !           389:        break;
        !           390:     }
        !           391:     *groupEntry = g_prev;    /* The insertion point is between g_prev and g */
        !           392:     return(FALSE);
        !           393: }
        !           394: 
        !           395: 
        !           396: static srcentry_t *
        !           397: create_srcentry(source)
        !           398:     u_int32 source;
        !           399: {
        !           400:     register srcentry_t *srcentry_ptr;
        !           401:     srcentry_t *srcentry_prev;
        !           402: 
        !           403:     if (search_srclist(source, &srcentry_prev) == TRUE)
        !           404:        return (srcentry_prev);
        !           405:     
        !           406:     srcentry_ptr = (srcentry_t *)malloc(sizeof(srcentry_t));
        !           407:     if (srcentry_ptr == (srcentry_t *)NULL) {
        !           408:        log(LOG_WARNING, 0, "Memory allocation error for srcentry %s",
        !           409:            inet_fmt(source, s1));
        !           410:        return (srcentry_t *)NULL;
        !           411:     }
        !           412: 
        !           413:     srcentry_ptr->address = source;
        !           414:     /*
        !           415:      * Free the memory if there is error getting the iif and
        !           416:      * the next hop (upstream) router.
        !           417:      */ 
        !           418:     if (set_incoming(srcentry_ptr, PIM_IIF_SOURCE) == FALSE) {
        !           419:        free((char *)srcentry_ptr);
        !           420:        return (srcentry_t *)NULL;
        !           421:     }
        !           422:     srcentry_ptr->mrtlink = (mrtentry_t *)NULL;
        !           423:     RESET_TIMER(srcentry_ptr->timer);
        !           424:     srcentry_ptr->next = srcentry_prev->next;
        !           425:     srcentry_prev->next = srcentry_ptr;
        !           426:     srcentry_ptr->prev = srcentry_prev;
        !           427:     if (srcentry_ptr->next != (srcentry_t *)NULL)
        !           428:        srcentry_ptr->next->prev = srcentry_ptr;
        !           429:     
        !           430:     IF_DEBUG(DEBUG_MFC)
        !           431:        log(LOG_DEBUG, 0, "create source entry, source %s",
        !           432:            inet_fmt(source, s1));
        !           433:     return (srcentry_ptr);
        !           434: }
        !           435: 
        !           436: 
        !           437: static grpentry_t *
        !           438: create_grpentry(group)
        !           439:     u_int32 group;
        !           440: {
        !           441:     register grpentry_t *grpentry_ptr;
        !           442:     grpentry_t *grpentry_prev;
        !           443: 
        !           444:     if (search_grplist(group, &grpentry_prev) == TRUE)
        !           445:        return (grpentry_prev);
        !           446:     
        !           447:     grpentry_ptr = (grpentry_t *)malloc(sizeof(grpentry_t));
        !           448:     if (grpentry_ptr == (grpentry_t *)NULL) {
        !           449:        log(LOG_WARNING, 0, "Memory allocation error for grpentry %s",
        !           450:            inet_fmt(group, s1));
        !           451:        return (grpentry_t *)NULL;
        !           452:     }
        !           453: 
        !           454:     grpentry_ptr->group                = group;
        !           455:     grpentry_ptr->mrtlink       = (mrtentry_t *)NULL;
        !           456: 
        !           457:     /* Now it is safe to include the new group entry */
        !           458:     grpentry_ptr->next         = grpentry_prev->next;
        !           459:     grpentry_prev->next         = grpentry_ptr;
        !           460:     grpentry_ptr->prev          = grpentry_prev;
        !           461:     if (grpentry_ptr->next != (grpentry_t *)NULL)
        !           462:        grpentry_ptr->next->prev = grpentry_ptr;
        !           463:     
        !           464:     IF_DEBUG(DEBUG_MFC)
        !           465:        log(LOG_DEBUG, 0, "create group entry, group %s", inet_fmt(group, s1));
        !           466:     return(grpentry_ptr);
        !           467: }
        !           468: 
        !           469: 
        !           470: /*
        !           471:  * Return TRUE if the entry is found and then *mrtPtr is set to point to that
        !           472:  * entry. Otherwise return FALSE and *mrtPtr points the the previous entry
        !           473:  * (or NULL if first in the chain.
        !           474:  */
        !           475: static int
        !           476: search_srcmrtlink(srcentry_ptr, group, mrtPtr)
        !           477:     srcentry_t *srcentry_ptr;  
        !           478:     u_int32 group;
        !           479:     mrtentry_t **mrtPtr;
        !           480: {
        !           481:     register mrtentry_t *mrtentry_ptr;
        !           482:     register mrtentry_t *m_prev = (mrtentry_t *)NULL;
        !           483:     u_int32 group_h = ntohl(group);
        !           484:     
        !           485:     for(mrtentry_ptr = srcentry_ptr->mrtlink;
        !           486:        mrtentry_ptr != (mrtentry_t *)NULL;
        !           487:        m_prev = mrtentry_ptr, mrtentry_ptr = mrtentry_ptr->srcnext) {
        !           488:        /* The entries are ordered with the smaller group address first.
        !           489:         * The addresses are in network order.
        !           490:         */
        !           491:        if (ntohl(mrtentry_ptr->group->group) < group_h)
        !           492:            continue;
        !           493:        if (mrtentry_ptr->group->group == group) {
        !           494:            *mrtPtr = mrtentry_ptr;
        !           495:            return(TRUE);
        !           496:        }
        !           497:        break;
        !           498:     }
        !           499:     *mrtPtr = m_prev;
        !           500:     return(FALSE);
        !           501: }
        !           502: 
        !           503: 
        !           504: /*
        !           505:  * Return TRUE if the entry is found and then *mrtPtr is set to point to that
        !           506:  * entry. Otherwise return FALSE and *mrtPtr points the the previous entry
        !           507:  * (or NULL if first in the chain.
        !           508:  */
        !           509: static int
        !           510: search_grpmrtlink(grpentry_ptr, source, mrtPtr)
        !           511:     grpentry_t *grpentry_ptr;
        !           512:     u_int32 source;
        !           513:     mrtentry_t **mrtPtr;
        !           514: {
        !           515:     register mrtentry_t *mrtentry_ptr;
        !           516:     register mrtentry_t *m_prev = (mrtentry_t *)NULL;
        !           517:     u_int32 source_h = ntohl(source);
        !           518:     
        !           519:     for (mrtentry_ptr = grpentry_ptr->mrtlink;
        !           520:         mrtentry_ptr != (mrtentry_t *)NULL;
        !           521:         m_prev = mrtentry_ptr, mrtentry_ptr = mrtentry_ptr->grpnext) {
        !           522:        /* The entries are ordered with the smaller source address first.
        !           523:         * The addresses are in network order.
        !           524:         */
        !           525:        if (ntohl(mrtentry_ptr->source->address) < source_h)
        !           526:            continue;
        !           527:        if (source == mrtentry_ptr->source->address) {
        !           528:            *mrtPtr = mrtentry_ptr;
        !           529:            return(TRUE);
        !           530:        }
        !           531:        break;
        !           532:     }
        !           533:     *mrtPtr = m_prev;
        !           534:     return(FALSE);
        !           535: }
        !           536: 
        !           537: 
        !           538: static void
        !           539: insert_srcmrtlink(mrtentry_new, mrtentry_prev, srcentry_ptr)
        !           540:     mrtentry_t *mrtentry_new;
        !           541:     mrtentry_t *mrtentry_prev;
        !           542:     srcentry_t *srcentry_ptr;
        !           543: {
        !           544:     if (mrtentry_prev == (mrtentry_t *)NULL) {
        !           545:        /* Has to be insert as the head entry for this source */
        !           546:        mrtentry_new->srcnext = srcentry_ptr->mrtlink;
        !           547:        mrtentry_new->srcprev = (mrtentry_t *)NULL;
        !           548:        srcentry_ptr->mrtlink = mrtentry_new;
        !           549:     }
        !           550:     else {
        !           551:        /* Insert right after the mrtentry_prev */
        !           552:        mrtentry_new->srcnext = mrtentry_prev->srcnext;
        !           553:        mrtentry_new->srcprev = mrtentry_prev;
        !           554:        mrtentry_prev->srcnext = mrtentry_new;
        !           555:     }
        !           556:     if (mrtentry_new->srcnext != (mrtentry_t *)NULL)
        !           557:        mrtentry_new->srcnext->srcprev = mrtentry_new;
        !           558: }
        !           559: 
        !           560: 
        !           561: static void
        !           562: insert_grpmrtlink(mrtentry_new, mrtentry_prev, grpentry_ptr)
        !           563:     mrtentry_t *mrtentry_new;
        !           564:     mrtentry_t *mrtentry_prev;
        !           565:     grpentry_t *grpentry_ptr;
        !           566: {
        !           567:     if (mrtentry_prev == (mrtentry_t *)NULL) {
        !           568:        /* Has to be insert as the head entry for this group */
        !           569:        mrtentry_new->grpnext = grpentry_ptr->mrtlink;
        !           570:        mrtentry_new->grpprev = (mrtentry_t *)NULL;
        !           571:        grpentry_ptr->mrtlink = mrtentry_new;
        !           572:     }
        !           573:     else {
        !           574:        /* Insert right after the mrtentry_prev */
        !           575:        mrtentry_new->grpnext = mrtentry_prev->grpnext;
        !           576:        mrtentry_new->grpprev = mrtentry_prev;
        !           577:        mrtentry_prev->grpnext = mrtentry_new;
        !           578:     }
        !           579:     if (mrtentry_new->grpnext != (mrtentry_t *)NULL)
        !           580:        mrtentry_new->grpnext->grpprev = mrtentry_new;
        !           581: }
        !           582: 
        !           583: 
        !           584: static mrtentry_t *
        !           585: alloc_mrtentry(srcentry_ptr, grpentry_ptr)
        !           586:     srcentry_t *srcentry_ptr;
        !           587:     grpentry_t *grpentry_ptr;
        !           588: {
        !           589:     register mrtentry_t *mrtentry_ptr;
        !           590:     u_int16 i, *i_ptr;
        !           591:     u_long  *il_ptr;
        !           592:     u_int8  vif_numbers;
        !           593:     
        !           594:     mrtentry_ptr = (mrtentry_t *)malloc(sizeof(mrtentry_t));
        !           595:     if (mrtentry_ptr == (mrtentry_t *)NULL) {
        !           596:        log(LOG_WARNING, 0, "alloc_mrtentry(): out of memory");
        !           597:        return (mrtentry_t *)NULL;
        !           598:     }
        !           599:     
        !           600:     /*
        !           601:      * grpnext, grpprev, srcnext, srcprev will be setup when we link the
        !           602:      * mrtentry to the source and group chains
        !           603:      */
        !           604:     mrtentry_ptr->source  = srcentry_ptr;
        !           605:     mrtentry_ptr->group   = grpentry_ptr;
        !           606:     mrtentry_ptr->incoming = NO_VIF;
        !           607:     VIFM_CLRALL(mrtentry_ptr->leaves);
        !           608:     VIFM_CLRALL(mrtentry_ptr->pruned_oifs);
        !           609:     VIFM_CLRALL(mrtentry_ptr->oifs);
        !           610:     mrtentry_ptr->upstream = (pim_nbr_entry_t *)NULL;
        !           611:     mrtentry_ptr->metric = 0;
        !           612:     mrtentry_ptr->preference = 0;
        !           613: #ifdef RSRR
        !           614:     mrtentry_ptr->rsrr_cache = (struct rsrr_cache *)NULL;
        !           615: #endif /* RSRR */
        !           616: 
        !           617: /*
        !           618:  * XXX: TODO: if we are short in memory, we can reserve as few as possible
        !           619:  * space for vif timers (per group and/or routing entry), but then everytime
        !           620:  * when a new interfaces is configured, the router will be restarted and
        !           621:  * will delete the whole routing table. The "memory is cheap" solution is
        !           622:  * to reserve timer space for all potential vifs in advance and then no
        !           623:  * need to delete the routing table and disturb the forwarding.
        !           624:  */
        !           625: #ifdef SAVE_MEMORY
        !           626:     mrtentry_ptr->prune_timers = (u_int16 *)malloc(sizeof(u_int16) * numvifs);
        !           627:     mrtentry_ptr->prune_delay_timerids = 
        !           628:        (u_long *)malloc(sizeof(u_long) * numvifs);
        !           629:     mrtentry_ptr->last_assert = (u_long *)malloc(sizeof(u_long) * numvifs);
        !           630:     mrtentry_ptr->last_prune = (u_long *)malloc(sizeof(u_long) * numvifs);
        !           631:     vif_numbers = numvifs;
        !           632: #else
        !           633:     mrtentry_ptr->prune_timers =
        !           634:        (u_int16 *)malloc(sizeof(u_int16) * total_interfaces);
        !           635:     mrtentry_ptr->prune_delay_timerids =
        !           636:        (u_long *)malloc(sizeof(u_long) * total_interfaces);
        !           637:     mrtentry_ptr->last_assert =
        !           638:        (u_long *)malloc(sizeof(u_long) * total_interfaces);
        !           639:     mrtentry_ptr->last_prune =
        !           640:        (u_long *)malloc(sizeof(u_long) * total_interfaces);
        !           641:     vif_numbers = total_interfaces;
        !           642: #endif /* SAVE_MEMORY */
        !           643:     if ((mrtentry_ptr->prune_timers == (u_int16 *)NULL) ||
        !           644:        (mrtentry_ptr->prune_delay_timerids == (u_long *)NULL) ||
        !           645:        (mrtentry_ptr->last_assert == (u_long *)NULL) ||
        !           646:        (mrtentry_ptr->last_prune == (u_long *)NULL)) {
        !           647:        log(LOG_WARNING, 0, "alloc_mrtentry(): out of memory");
        !           648:        FREE_MRTENTRY(mrtentry_ptr);
        !           649:        return (mrtentry_t *)NULL;
        !           650:     }
        !           651:     /* Reset the timers */
        !           652:     for (i = 0, i_ptr = mrtentry_ptr->prune_timers; i < vif_numbers;
        !           653:         i++, i_ptr++)
        !           654:        RESET_TIMER(*i_ptr);
        !           655:     for (i = 0, il_ptr = mrtentry_ptr->prune_delay_timerids; i < vif_numbers;
        !           656:         i++, il_ptr++)
        !           657:        RESET_TIMER(*il_ptr);
        !           658:     for (i = 0, il_ptr = mrtentry_ptr->last_assert; i < vif_numbers;
        !           659:         i++, il_ptr++)
        !           660:        RESET_TIMER(*il_ptr);
        !           661:     for (i = 0, il_ptr = mrtentry_ptr->last_prune; i < vif_numbers;
        !           662:         i++, il_ptr++)
        !           663:        RESET_TIMER(*il_ptr);
        !           664: 
        !           665:     mrtentry_ptr->flags = MRTF_NEW;
        !           666:     RESET_TIMER(mrtentry_ptr->timer);
        !           667:     mrtentry_ptr->join_delay_timerid = 0;
        !           668:     RESET_TIMER(mrtentry_ptr->assert_timer);
        !           669:     mrtentry_ptr->graft = (pim_graft_entry_t *)NULL;
        !           670: 
        !           671:     return(mrtentry_ptr);
        !           672: }
        !           673: 
        !           674: 
        !           675: static mrtentry_t *
        !           676: create_mrtentry(srcentry_ptr, grpentry_ptr, flags)
        !           677:     srcentry_t *srcentry_ptr;
        !           678:     grpentry_t *grpentry_ptr;
        !           679:     u_int16 flags;
        !           680: {
        !           681:     mrtentry_t *r_new;
        !           682:     mrtentry_t *r_grp_insert, *r_src_insert; /* pointers to insert */
        !           683:     u_int32 source;
        !           684:     u_int32 group;
        !           685: 
        !           686:     /* (S,G) entry */
        !           687:     source = srcentry_ptr->address;
        !           688:     group  = grpentry_ptr->group;
        !           689:     
        !           690:     if (search_grpmrtlink(grpentry_ptr, source, &r_grp_insert) == TRUE) {
        !           691:        return(r_grp_insert);
        !           692:     }
        !           693:     if (search_srcmrtlink(srcentry_ptr, group, &r_src_insert) == TRUE) {
        !           694:        /*
        !           695:         * Hmmm, search_grpmrtlink() didn't find the entry, but
        !           696:         * search_srcmrtlink() did find it! Shoudn't happen. Panic!
        !           697:         */
        !           698:        log(LOG_ERR, 0, "MRT inconsistency for src %s and grp %s\n",
        !           699:            inet_fmt(source, s1), inet_fmt(group, s2));
        !           700:        /* not reached but to make lint happy */
        !           701:        return (mrtentry_t *)NULL;
        !           702:     }
        !           703:     /*
        !           704:      * Create and insert in group mrtlink and source mrtlink chains.
        !           705:      */
        !           706:     r_new = alloc_mrtentry(srcentry_ptr, grpentry_ptr);
        !           707:     if (r_new == (mrtentry_t *)NULL)
        !           708:        return (mrtentry_t *)NULL;
        !           709:     /*
        !           710:      * r_new has to be insert right after r_grp_insert in the
        !           711:      * grp mrtlink chain and right after r_src_insert in the 
        !           712:      * src mrtlink chain
        !           713:      */
        !           714:     insert_grpmrtlink(r_new, r_grp_insert, grpentry_ptr);
        !           715:     insert_srcmrtlink(r_new, r_src_insert, srcentry_ptr);
        !           716:     r_new->flags |= MRTF_SG;
        !           717:     return (r_new);
        !           718: }

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