source: pkg/security/vinnie/main/pimd/trunk/mrt.c @ 7297

Revision 7297, 42.0 KB checked in by alanbach-guest, 2 years ago (diff)
  • Added pimd to Vinnie security
Line 
1/*
2 * Copyright (c) 1998-2001
3 * University of Southern California/Information Sciences Institute.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the project nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30/*
31 *  $Id: mrt.c,v 1.27 2001/09/10 20:31:36 pavlin Exp $
32 */
33
34
35#include "defs.h"
36
37
38srcentry_t              *srclist;
39grpentry_t              *grplist;
40
41/*
42 * Local functions definition
43 */
44static srcentry_t *create_srcentry  (u_int32 source);
45static int        search_srclist    (u_int32 source, srcentry_t **sourceEntry);
46static int        search_srcmrtlink (srcentry_t *srcentry_ptr, u_int32 group, mrtentry_t **mrtPtr);
47static void       insert_srcmrtlink (mrtentry_t *elementPtr, mrtentry_t *insertPtr, srcentry_t *srcListPtr);
48static grpentry_t *create_grpentry  (u_int32 group);
49static int        search_grplist    (u_int32 group, grpentry_t **groupEntry);
50static int        search_grpmrtlink (grpentry_t *grpentry_ptr, u_int32 source, mrtentry_t **mrtPtr);
51static void       insert_grpmrtlink (mrtentry_t *elementPtr, mrtentry_t *insertPtr, grpentry_t *grpListPtr);
52static mrtentry_t *alloc_mrtentry   (srcentry_t *srcentry_ptr, grpentry_t *grpentry_ptr);
53static mrtentry_t *create_mrtentry  (srcentry_t *srcentry_ptr, grpentry_t *grpentry_ptr, u_int16 flags);
54static void       move_kernel_cache (mrtentry_t *mrtentry_ptr, u_int16 flags);
55
56void init_pim_mrt(void)
57{
58    /* TODO: delete any existing routing table */
59
60    /* Initialize the source list */
61    /* The first entry has address 'INADDR_ANY' and is not used */
62    /* The order is the smallest address first. */
63    srclist             = (srcentry_t *)malloc(sizeof(srcentry_t));
64    if (!srclist)
65        logit(LOG_ERR, 0, "Ran out of memory in init_pim_mrt()");
66    srclist->next       = NULL;
67    srclist->prev       = NULL;
68    srclist->address    = INADDR_ANY_N;
69    srclist->mrtlink    = NULL;
70    srclist->incoming   = NO_VIF;
71    srclist->upstream   = NULL;
72    srclist->metric     = 0;
73    srclist->preference = 0;
74    RESET_TIMER(srclist->timer);
75    srclist->cand_rp    = NULL;
76
77    /* Initialize the group list */
78    /* The first entry has address 'INADDR_ANY' and is not used */
79    /* The order is the smallest address first. */
80    grplist             = (grpentry_t *)malloc(sizeof(grpentry_t));
81    if (!grplist)
82        logit(LOG_ERR, 0, "Ran out of memory in init_pim_mrt()");
83    grplist->next       = NULL;
84    grplist->prev       = NULL;
85    grplist->rpnext     = NULL;
86    grplist->rpprev     = NULL;
87    grplist->group      = INADDR_ANY_N;
88    grplist->rpaddr     = INADDR_ANY_N;
89    grplist->mrtlink    = NULL;
90    grplist->active_rp_grp = NULL;
91    grplist->grp_route   = NULL;
92}
93
94
95grpentry_t *find_group(u_int32 group)
96{
97    grpentry_t *grpentry_ptr;
98
99    if (!IN_MULTICAST(ntohl(group)))
100        return NULL;
101
102    if (search_grplist(group, &grpentry_ptr) == TRUE) {
103        /* Group found! */
104        return grpentry_ptr;
105    }
106    return NULL;
107}
108
109
110srcentry_t *find_source(u_int32 source)
111{
112    srcentry_t *srcentry_ptr;
113
114    if (!inet_valid_host(source))
115        return NULL;
116
117    if (search_srclist(source, &srcentry_ptr) == TRUE) {
118        /* Source found! */
119        return srcentry_ptr;
120    }
121    return NULL;
122}
123
124
125mrtentry_t *find_route(u_int32 source, u_int32 group, u_int16 flags, char create)
126{
127    srcentry_t *srcentry_ptr         = NULL;
128    grpentry_t *grpentry_ptr         = NULL;
129    mrtentry_t *mrtentry_ptr         = NULL;
130    mrtentry_t *mrtentry_ptr_wc      = NULL;
131    mrtentry_t *mrtentry_ptr_pmbr    = NULL;
132    mrtentry_t *mrtentry_ptr_2       = NULL;
133    rpentry_t  *rpentry_ptr          = NULL;
134    rp_grp_entry_t *rp_grp_entry_ptr = NULL;
135
136    if (flags & (MRTF_SG | MRTF_WC)) {
137        if (!IN_MULTICAST(ntohl(group)))
138            return NULL;
139    }
140
141    if (flags & MRTF_SG) {
142        if (!inet_valid_host(source))
143            return NULL;
144    }
145
146    if (create == DONT_CREATE) {
147        if (flags & (MRTF_SG | MRTF_WC)) {
148            if (search_grplist(group, &grpentry_ptr) == FALSE) {
149                /* Group not found. Return the (*,*,RP) entry */
150                if (flags & MRTF_PMBR) {
151                    rpentry_ptr = rp_match(group);
152                    if (rpentry_ptr)
153                        return rpentry_ptr->mrtlink;
154                }
155
156                return NULL;
157            }
158
159            /* Search for the source */
160            if (flags & MRTF_SG) {
161                if (search_grpmrtlink(grpentry_ptr, source, &mrtentry_ptr) == TRUE) {
162                    /* Exact (S,G) entry found */
163                    return mrtentry_ptr;
164                }
165            }
166
167            /* No (S,G) entry. Return the (*,G) entry (if exist) */
168            if ((flags & MRTF_WC) && grpentry_ptr->grp_route)
169                return grpentry_ptr->grp_route;
170        }
171
172        /* Return the (*,*,RP) entry */
173        if (flags & MRTF_PMBR) {
174            rpentry_ptr = NULL;
175            if (group != INADDR_ANY_N)
176                rpentry_ptr = rp_match(group);
177            else if (source != INADDR_ANY_N)
178                rpentry_ptr = rp_find(source);
179
180            if (rpentry_ptr)
181                return rpentry_ptr->mrtlink;
182        }
183
184        return NULL;
185    }
186
187
188    /* Creation allowed */
189
190    if (flags & (MRTF_SG | MRTF_WC)) {
191        grpentry_ptr = create_grpentry(group);
192        if (!grpentry_ptr)
193            return NULL;
194
195        if (!grpentry_ptr->active_rp_grp) {
196            rp_grp_entry_ptr = rp_grp_match(group);
197            if (!rp_grp_entry_ptr) {
198                if (!grpentry_ptr->mrtlink && !grpentry_ptr->grp_route) {
199                    /* New created grpentry. Delete it. */
200                    delete_grpentry(grpentry_ptr);
201                }
202
203                return NULL;
204            }
205
206            rpentry_ptr = rp_grp_entry_ptr->rp->rpentry;
207            grpentry_ptr->active_rp_grp = rp_grp_entry_ptr;
208            grpentry_ptr->rpaddr = rpentry_ptr->address;
209
210            /* Link to the top of the rp_grp_chain */
211            grpentry_ptr->rpnext = rp_grp_entry_ptr->grplink;
212            rp_grp_entry_ptr->grplink = grpentry_ptr;
213            if (grpentry_ptr->rpnext)
214                grpentry_ptr->rpnext->rpprev = grpentry_ptr;
215        }
216        else {
217            rpentry_ptr = grpentry_ptr->active_rp_grp->rp->rpentry;
218        }
219    }
220
221    mrtentry_ptr_wc = mrtentry_ptr_pmbr = NULL;
222
223    if (flags & MRTF_WC) {
224        /* Setup the (*,G) routing entry */
225        mrtentry_ptr_wc = create_mrtentry(NULL, grpentry_ptr, MRTF_WC);
226        if (!mrtentry_ptr_wc) {
227            if (!grpentry_ptr->mrtlink) {
228                /* New created grpentry. Delete it. */
229                delete_grpentry(grpentry_ptr);
230            }
231
232            return NULL;
233        }
234
235        if (mrtentry_ptr_wc->flags & MRTF_NEW) {
236            mrtentry_ptr_pmbr = rpentry_ptr->mrtlink;
237            /* Copy the oif list from the (*,*,RP) entry */
238            if (mrtentry_ptr_pmbr) {
239                VOIF_COPY(mrtentry_ptr_pmbr, mrtentry_ptr_wc);
240            }
241            mrtentry_ptr_wc->incoming = rpentry_ptr->incoming;
242            mrtentry_ptr_wc->upstream = rpentry_ptr->upstream;
243            mrtentry_ptr_wc->metric   = rpentry_ptr->metric;
244            mrtentry_ptr_wc->preference = rpentry_ptr->preference;
245            move_kernel_cache(mrtentry_ptr_wc, 0);
246#ifdef RSRR
247            rsrr_cache_bring_up(mrtentry_ptr_wc);
248#endif /* RSRR */
249        }
250
251        if (!(flags & MRTF_SG)) {
252            return mrtentry_ptr_wc;
253        }
254    }
255
256    if (flags & MRTF_SG) {
257        /* Setup the (S,G) routing entry */
258        srcentry_ptr = create_srcentry(source);
259        if (!srcentry_ptr) {
260            /* TODO: XXX: The MRTF_NEW flag check may be misleading?? check */
261            if ((!grpentry_ptr->grp_route || (grpentry_ptr->grp_route && (grpentry_ptr->grp_route->flags & MRTF_NEW)))
262                && !grpentry_ptr->mrtlink) {
263                /* New created grpentry. Delete it. */
264                delete_grpentry(grpentry_ptr);
265            }
266
267            return NULL;
268        }
269
270        mrtentry_ptr = create_mrtentry(srcentry_ptr, grpentry_ptr, MRTF_SG);
271        if (!mrtentry_ptr) {
272            if ((!grpentry_ptr->grp_route
273                 || (grpentry_ptr->grp_route && (grpentry_ptr->grp_route->flags & MRTF_NEW)))
274                && !grpentry_ptr->mrtlink) {
275                /* New created grpentry. Delete it. */
276                delete_grpentry(grpentry_ptr);
277            }
278            if (!srcentry_ptr->mrtlink) {
279                /* New created srcentry. Delete it. */
280                delete_srcentry(srcentry_ptr);
281            }
282
283            return NULL;
284        }
285
286        if (mrtentry_ptr->flags & MRTF_NEW) {
287            mrtentry_ptr_2 = grpentry_ptr->grp_route;
288            if (!mrtentry_ptr_2) {
289                mrtentry_ptr_2 = rpentry_ptr->mrtlink;
290            }
291            /* Copy the oif list from the existing (*,G) or (*,*,RP) entry */
292            if (mrtentry_ptr_2) {
293                VOIF_COPY(mrtentry_ptr_2, mrtentry_ptr);
294                if (flags & MRTF_RP) {
295                    /* ~(S,G) prune entry */
296                    mrtentry_ptr->incoming = mrtentry_ptr_2->incoming;
297                    mrtentry_ptr->upstream = mrtentry_ptr_2->upstream;
298                    mrtentry_ptr->metric   = mrtentry_ptr_2->metric;
299                    mrtentry_ptr->preference = mrtentry_ptr_2->preference;
300                    mrtentry_ptr->flags |= MRTF_RP;
301                }
302            }
303            if (!(mrtentry_ptr->flags & MRTF_RP)) {
304                mrtentry_ptr->incoming = srcentry_ptr->incoming;
305                mrtentry_ptr->upstream = srcentry_ptr->upstream;
306                mrtentry_ptr->metric   = srcentry_ptr->metric;
307                mrtentry_ptr->preference = srcentry_ptr->preference;
308            }
309            move_kernel_cache(mrtentry_ptr, 0);
310#ifdef RSRR
311            rsrr_cache_bring_up(mrtentry_ptr);
312#endif /* RSRR */
313        }
314
315        return mrtentry_ptr;
316    }
317
318    if (flags & MRTF_PMBR) {
319        /* Get/return the (*,*,RP) routing entry */
320        if (group != INADDR_ANY_N) {
321            rpentry_ptr = rp_match(group);
322        } else if (source != INADDR_ANY_N) {
323            rpentry_ptr = rp_find(source);
324            if (!rpentry_ptr)
325                return NULL;
326        } else {
327            return NULL; /* source == group == INADDR_ANY */
328        }
329
330        if (rpentry_ptr->mrtlink)
331            return rpentry_ptr->mrtlink;
332
333        mrtentry_ptr = create_mrtentry(rpentry_ptr, NULL, MRTF_PMBR);
334        if (!mrtentry_ptr)
335            return NULL;
336
337        mrtentry_ptr->incoming = rpentry_ptr->incoming;
338        mrtentry_ptr->upstream = rpentry_ptr->upstream;
339        mrtentry_ptr->metric   = rpentry_ptr->metric;
340        mrtentry_ptr->preference = rpentry_ptr->preference;
341
342        return mrtentry_ptr;
343    }
344
345    return NULL;
346}
347
348
349void delete_srcentry(srcentry_t *srcentry_ptr)
350{
351    mrtentry_t *ptr;
352    mrtentry_t *next;
353
354    if (!srcentry_ptr)
355        return;
356
357    /* TODO: XXX: the first entry is unused and always there */
358    srcentry_ptr->prev->next =  srcentry_ptr->next;
359    if (srcentry_ptr->next)
360        srcentry_ptr->next->prev = srcentry_ptr->prev;
361
362    for (ptr = srcentry_ptr->mrtlink; ptr; ptr = next) {
363        next = ptr->srcnext;
364        if (ptr->flags & MRTF_KERNEL_CACHE)
365            /* Delete the kernel cache first */
366            delete_mrtentry_all_kernel_cache(ptr);
367
368        if (ptr->grpprev) {
369            ptr->grpprev->grpnext = ptr->grpnext;
370        } else {
371            ptr->group->mrtlink = ptr->grpnext;
372            if (!ptr->grpnext && !ptr->group->grp_route) {
373                /* Delete the group entry if it has no (*,G) routing entry */
374                delete_grpentry(ptr->group);
375            }
376        }
377
378        if (ptr->grpnext)
379            ptr->grpnext->grpprev = ptr->grpprev;
380
381        FREE_MRTENTRY(ptr);
382    }
383
384    free((char *)srcentry_ptr);
385}
386
387
388void delete_grpentry(grpentry_t *grpentry_ptr)
389{
390    mrtentry_t *ptr;
391    mrtentry_t *next;
392
393    if (!grpentry_ptr)
394        return;
395
396    /* TODO: XXX: the first entry is unused and always there */
397    grpentry_ptr->prev->next = grpentry_ptr->next;
398    if (grpentry_ptr->next)
399        grpentry_ptr->next->prev = grpentry_ptr->prev;
400
401    if (grpentry_ptr->grp_route) {
402        if (grpentry_ptr->grp_route->flags & MRTF_KERNEL_CACHE)
403            delete_mrtentry_all_kernel_cache(grpentry_ptr->grp_route);
404        FREE_MRTENTRY(grpentry_ptr->grp_route);
405    }
406
407    /* Delete from the rp_grp_entry chain */
408    if (grpentry_ptr->active_rp_grp != NULL) {
409        if (grpentry_ptr->rpnext != NULL)
410            grpentry_ptr->rpnext->rpprev = grpentry_ptr->rpprev;
411
412        if (grpentry_ptr->rpprev != NULL)
413            grpentry_ptr->rpprev->rpnext = grpentry_ptr->rpnext;
414        else
415            grpentry_ptr->active_rp_grp->grplink = grpentry_ptr->rpnext;
416    }
417
418    for (ptr = grpentry_ptr->mrtlink; ptr; ptr = next) {
419        next = ptr->grpnext;
420        if (ptr->flags & MRTF_KERNEL_CACHE)
421            /* Delete the kernel cache first */
422            delete_mrtentry_all_kernel_cache(ptr);
423
424        if (ptr->srcprev) {
425            ptr->srcprev->srcnext = ptr->srcnext;
426        } else {
427            ptr->source->mrtlink = ptr->srcnext;
428            if (!ptr->srcnext) {
429                /* Delete the srcentry if this was the last routing entry */
430                delete_srcentry(ptr->source);
431            }
432        }
433
434        if (ptr->srcnext)
435            ptr->srcnext->srcprev = ptr->srcprev;
436
437        FREE_MRTENTRY(ptr);
438    }
439
440    free((char *)grpentry_ptr);
441}
442
443
444void delete_mrtentry(mrtentry_t *mrtentry_ptr)
445{
446    grpentry_t *grpentry_ptr;
447    mrtentry_t *mrtentry_wc;
448    mrtentry_t *mrtentry_rp;
449
450    if (mrtentry_ptr == NULL)
451        return;
452
453    /* Delete the kernel cache first */
454    if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE)
455        delete_mrtentry_all_kernel_cache(mrtentry_ptr);
456
457#ifdef RSRR
458    /* Tell the reservation daemon */
459    rsrr_cache_clean(mrtentry_ptr);
460#endif /* RSRR */
461
462    if (mrtentry_ptr->flags & MRTF_PMBR) {
463        /* (*,*,RP) mrtentry */
464        mrtentry_ptr->source->mrtlink = NULL;
465    } else if (mrtentry_ptr->flags & MRTF_SG) {
466        /* (S,G) mrtentry */
467
468        /* Delete from the grpentry MRT chain */
469        if (mrtentry_ptr->grpprev != NULL) {
470            mrtentry_ptr->grpprev->grpnext = mrtentry_ptr->grpnext;
471        } else {
472            mrtentry_ptr->group->mrtlink = mrtentry_ptr->grpnext;
473            if (mrtentry_ptr->grpnext == NULL) {
474                /* All (S,G) MRT entries are gone. Allow creating (*,G) MFC
475                 * entries.
476                 */
477                mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
478                mrtentry_wc = mrtentry_ptr->group->grp_route;
479                if (mrtentry_rp != NULL)
480                    mrtentry_rp->flags &= ~MRTF_MFC_CLONE_SG;
481
482                if (mrtentry_wc != NULL) {
483                    mrtentry_wc->flags &= ~MRTF_MFC_CLONE_SG;
484                } else {
485                    /* Delete the group entry if it has no (*,G)
486                     * routing entry
487                     */
488                    delete_grpentry(mrtentry_ptr->group);
489                }
490            }
491        }
492        if (mrtentry_ptr->grpnext != NULL)
493            mrtentry_ptr->grpnext->grpprev = mrtentry_ptr->grpprev;
494
495        /* Delete from the srcentry MRT chain */
496        if (mrtentry_ptr->srcprev != NULL) {
497            mrtentry_ptr->srcprev->srcnext = mrtentry_ptr->srcnext;
498        } else {
499            mrtentry_ptr->source->mrtlink = mrtentry_ptr->srcnext;
500            if (mrtentry_ptr->srcnext == NULL) {
501                /* Delete the srcentry if this was the last routing entry */
502                delete_srcentry(mrtentry_ptr->source);
503            }
504        }
505
506        if (mrtentry_ptr->srcnext != NULL)
507            mrtentry_ptr->srcnext->srcprev = mrtentry_ptr->srcprev;
508    } else {
509        /* This mrtentry should be (*,G) */
510        grpentry_ptr = mrtentry_ptr->group;
511        grpentry_ptr->grp_route = NULL;
512
513        if (grpentry_ptr->mrtlink == NULL)
514            /* Delete the group entry if it has no (S,G) entries */
515            delete_grpentry(grpentry_ptr);
516    }
517
518    FREE_MRTENTRY(mrtentry_ptr);
519}
520
521
522static int search_srclist(u_int32 source, srcentry_t **sourceEntry)
523{
524    srcentry_t *s_prev,*s;
525    u_int32 source_h = ntohl(source);
526
527    for (s_prev = srclist, s = s_prev->next; s != NULL; s_prev = s, s = s->next) {
528        /* The srclist is ordered with the smallest addresses first.
529         * The first entry is not used.
530         */
531        if (ntohl(s->address) < source_h)
532            continue;
533
534        if (s->address == source) {
535            *sourceEntry = s;
536            return TRUE;
537        }
538        break;
539    }
540    *sourceEntry = s_prev;   /* The insertion point is between s_prev and s */
541
542    return FALSE;
543}
544
545
546static int search_grplist(u_int32 group, grpentry_t **groupEntry)
547{
548    grpentry_t *g_prev, *g;
549    u_int32 group_h = ntohl(group);
550
551    for (g_prev = grplist, g = g_prev->next; g != NULL; g_prev = g, g = g->next) {
552        /* The grplist is ordered with the smallest address first.
553         * The first entry is not used.
554         */
555        if (ntohl(g->group) < group_h)
556            continue;
557        if (g->group == group) {
558            *groupEntry = g;
559            return TRUE;
560        }
561        break;
562    }
563    *groupEntry = g_prev;    /* The insertion point is between g_prev and g */
564
565    return FALSE;
566}
567
568
569static srcentry_t *create_srcentry(u_int32 source)
570{
571    srcentry_t *srcentry_ptr;
572    srcentry_t *srcentry_prev;
573
574    if (search_srclist(source, &srcentry_prev) == TRUE)
575        return srcentry_prev;
576
577    srcentry_ptr = (srcentry_t *)malloc(sizeof(srcentry_t));
578    if (!srcentry_ptr) {
579        logit(LOG_WARNING, 0, "Memory allocation error for srcentry %s",
580              inet_fmt(source, s1, sizeof(s1)));
581        return NULL;
582    }
583
584    srcentry_ptr->address = source;
585    /*
586     * Free the memory if there is error getting the iif and
587     * the next hop (upstream) router.
588     */
589    if (set_incoming(srcentry_ptr, PIM_IIF_SOURCE) == FALSE) {
590        free((char *)srcentry_ptr);
591        return NULL;
592    }
593
594    RESET_TIMER(srcentry_ptr->timer);
595    srcentry_ptr->mrtlink = NULL;
596    srcentry_ptr->cand_rp = NULL;
597    srcentry_ptr->next    = srcentry_prev->next;
598    srcentry_prev->next   = srcentry_ptr;
599    srcentry_ptr->prev    = srcentry_prev;
600    if (srcentry_ptr->next)
601        srcentry_ptr->next->prev = srcentry_ptr;
602
603    IF_DEBUG(DEBUG_MFC) {
604        logit(LOG_DEBUG, 0, "create source entry, source %s",
605              inet_fmt(source, s1, sizeof(s1)));
606    }
607
608    return srcentry_ptr;
609}
610
611
612static grpentry_t *create_grpentry(u_int32 group)
613{
614    grpentry_t *grpentry_ptr;
615    grpentry_t *grpentry_prev;
616
617    /* If already exists, return it.  Otheriwse search_grplist() returns the
618     * insertion point in grpentry_prev. */
619    if (search_grplist(group, &grpentry_prev) == TRUE)
620        return grpentry_prev;
621
622    grpentry_ptr = (grpentry_t *)malloc(sizeof(grpentry_t));
623    if (!grpentry_ptr) {
624        logit(LOG_WARNING, 0, "Memory allocation error for grpentry %s",
625              inet_fmt(group, s1, sizeof(s1)));
626        return NULL;
627    }
628
629    /*
630     * TODO: XXX: Note that this is NOT a (*,G) routing entry, but simply
631     * a group entry, probably used to search the routing table (to find
632     * (S,G) entries for example.)
633     * To become (*,G) routing entry, we must setup grpentry_ptr->grp_route
634     */
635    grpentry_ptr->group         = group;
636    grpentry_ptr->rpaddr        = INADDR_ANY_N;
637    grpentry_ptr->mrtlink       = NULL;
638    grpentry_ptr->active_rp_grp = NULL;
639    grpentry_ptr->grp_route     = NULL;
640    grpentry_ptr->rpnext        = NULL;
641    grpentry_ptr->rpprev        = NULL;
642
643    /* Now it is safe to include the new group entry */
644    grpentry_ptr->next          = grpentry_prev->next;
645    grpentry_prev->next         = grpentry_ptr;
646    grpentry_ptr->prev          = grpentry_prev;
647    if (grpentry_ptr->next)
648        grpentry_ptr->next->prev = grpentry_ptr;
649
650    IF_DEBUG(DEBUG_MFC) {
651        logit(LOG_DEBUG, 0, "create group entry, group %s", inet_fmt(group, s1, sizeof(s1)));
652    }
653
654    return grpentry_ptr;
655}
656
657
658/*
659 * Return TRUE if the entry is found and then *mrtPtr is set to point to that
660 * entry. Otherwise return FALSE and *mrtPtr points the previous entry
661 * (or NULL if first in the chain.
662 */
663static int search_srcmrtlink(srcentry_t *srcentry_ptr, u_int32 group, mrtentry_t **mrtPtr)
664{
665    mrtentry_t *mrtentry_ptr;
666    mrtentry_t *m_prev = NULL;
667    u_int32 group_h = ntohl(group);
668
669    for (mrtentry_ptr = srcentry_ptr->mrtlink;
670         mrtentry_ptr != NULL;
671         m_prev = mrtentry_ptr, mrtentry_ptr = mrtentry_ptr->srcnext) {
672        /* The entries are ordered with the smaller group address first.
673         * The addresses are in network order.
674         */
675        if (ntohl(mrtentry_ptr->group->group) < group_h)
676            continue;
677
678        if (mrtentry_ptr->group->group == group) {
679            *mrtPtr = mrtentry_ptr;
680            return TRUE;
681        }
682
683        break;
684    }
685
686    *mrtPtr = m_prev;
687
688    return FALSE;
689}
690
691
692/*
693 * Return TRUE if the entry is found and then *mrtPtr is set to point to that
694 * entry. Otherwise return FALSE and *mrtPtr points the previous entry
695 * (or NULL if first in the chain.
696 */
697static int search_grpmrtlink(grpentry_t *grpentry_ptr, u_int32 source, mrtentry_t **mrtPtr)
698{
699    mrtentry_t *mrtentry_ptr;
700    mrtentry_t *m_prev = NULL;
701    u_int32 source_h = ntohl(source);
702
703    for (mrtentry_ptr = grpentry_ptr->mrtlink;
704         mrtentry_ptr != NULL;
705         m_prev = mrtentry_ptr, mrtentry_ptr = mrtentry_ptr->grpnext) {
706        /* The entries are ordered with the smaller source address first.
707         * The addresses are in network order.
708         */
709        if (ntohl(mrtentry_ptr->source->address) < source_h)
710            continue;
711
712        if (source == mrtentry_ptr->source->address) {
713            *mrtPtr = mrtentry_ptr;
714            return TRUE;
715        }
716
717        break;
718    }
719
720    *mrtPtr = m_prev;
721
722    return FALSE;
723}
724
725
726static void insert_srcmrtlink(mrtentry_t *mrtentry_new, mrtentry_t *mrtentry_prev, srcentry_t *srcentry_ptr)
727{
728    if (mrtentry_prev == NULL) {
729        /* Has to be insert as the head entry for this source */
730        mrtentry_new->srcnext = srcentry_ptr->mrtlink;
731        mrtentry_new->srcprev = NULL;
732        srcentry_ptr->mrtlink = mrtentry_new;
733    } else {
734        /* Insert right after the mrtentry_prev */
735        mrtentry_new->srcnext = mrtentry_prev->srcnext;
736        mrtentry_new->srcprev = mrtentry_prev;
737        mrtentry_prev->srcnext = mrtentry_new;
738    }
739
740    if (mrtentry_new->srcnext != NULL)
741        mrtentry_new->srcnext->srcprev = mrtentry_new;
742}
743
744
745static void insert_grpmrtlink(mrtentry_t *mrtentry_new, mrtentry_t *mrtentry_prev, grpentry_t *grpentry_ptr)
746{
747    if (mrtentry_prev == NULL) {
748        /* Has to be insert as the head entry for this group */
749        mrtentry_new->grpnext = grpentry_ptr->mrtlink;
750        mrtentry_new->grpprev = NULL;
751        grpentry_ptr->mrtlink = mrtentry_new;
752    } else {
753        /* Insert right after the mrtentry_prev */
754        mrtentry_new->grpnext = mrtentry_prev->grpnext;
755        mrtentry_new->grpprev = mrtentry_prev;
756        mrtentry_prev->grpnext = mrtentry_new;
757    }
758
759    if (mrtentry_new->grpnext != NULL)
760        mrtentry_new->grpnext->grpprev = mrtentry_new;
761}
762
763
764static mrtentry_t *alloc_mrtentry(srcentry_t *srcentry_ptr, grpentry_t *grpentry_ptr)
765{
766    mrtentry_t *mrtentry_ptr;
767    u_int16 i, *i_ptr;
768    u_int8  vif_numbers;
769
770    mrtentry_ptr = (mrtentry_t *)malloc(sizeof(mrtentry_t));
771    if (mrtentry_ptr == NULL) {
772        logit(LOG_WARNING, 0, "alloc_mrtentry(): out of memory");
773        return NULL;
774    }
775
776    /*
777     * grpnext, grpprev, srcnext, srcprev will be setup when we link the
778     * mrtentry to the source and group chains
779     */
780    mrtentry_ptr->source  = srcentry_ptr;
781    mrtentry_ptr->group   = grpentry_ptr;
782    mrtentry_ptr->incoming = NO_VIF;
783    VIFM_CLRALL(mrtentry_ptr->joined_oifs);
784    VIFM_CLRALL(mrtentry_ptr->leaves);
785    VIFM_CLRALL(mrtentry_ptr->pruned_oifs);
786    VIFM_CLRALL(mrtentry_ptr->asserted_oifs);
787    VIFM_CLRALL(mrtentry_ptr->oifs);
788    mrtentry_ptr->upstream = NULL;
789    mrtentry_ptr->metric = 0;
790    mrtentry_ptr->preference = 0;
791    mrtentry_ptr->pmbr_addr = INADDR_ANY_N;
792#ifdef RSRR
793    mrtentry_ptr->rsrr_cache = NULL;
794#endif /* RSRR */
795
796    /* XXX: TODO: if we are short in memory, we can reserve as few as possible
797     * space for vif timers (per group and/or routing entry), but then everytime
798     * when a new interfaces is configured, the router will be restarted and
799     * will delete the whole routing table. The "memory is cheap" solution is
800     * to reserve timer space for all potential vifs in advance and then no
801     * need to delete the routing table and disturb the forwarding.
802     */
803#ifdef SAVE_MEMORY
804    mrtentry_ptr->vif_timers = (u_int16 *)malloc(sizeof(u_int16) * numvifs);
805    mrtentry_ptr->vif_deletion_delay = (u_int16 *)malloc(sizeof(u_int16) * numvifs);
806    vif_numbers = numvifs;
807#else
808    mrtentry_ptr->vif_timers = (u_int16 *)malloc(sizeof(u_int16) * total_interfaces);
809    mrtentry_ptr->vif_deletion_delay = (u_int16 *)malloc(sizeof(u_int16) * total_interfaces);
810    vif_numbers = total_interfaces;
811#endif /* SAVE_MEMORY */
812    if ((mrtentry_ptr->vif_timers == NULL) ||
813        (mrtentry_ptr->vif_deletion_delay == NULL)) {
814        logit(LOG_WARNING, 0, "alloc_mrtentry(): out of memory");
815        FREE_MRTENTRY(mrtentry_ptr);
816        return NULL;
817    }
818
819    /* Reset the timers */
820    for (i = 0, i_ptr = mrtentry_ptr->vif_timers; i < vif_numbers; i++, i_ptr++) {
821        RESET_TIMER(*i_ptr);
822    }
823    for (i = 0, i_ptr = mrtentry_ptr->vif_deletion_delay; i < vif_numbers; i++, i_ptr++) {
824        RESET_TIMER(*i_ptr);
825    }
826
827    mrtentry_ptr->flags = MRTF_NEW;
828    RESET_TIMER(mrtentry_ptr->timer);
829    RESET_TIMER(mrtentry_ptr->jp_timer);
830    RESET_TIMER(mrtentry_ptr->rs_timer);
831    RESET_TIMER(mrtentry_ptr->assert_timer);
832    RESET_TIMER(mrtentry_ptr->assert_rate_timer);
833    mrtentry_ptr->kernel_cache = NULL;
834
835    return mrtentry_ptr;
836}
837
838
839static mrtentry_t *create_mrtentry(srcentry_t *srcentry_ptr, grpentry_t *grpentry_ptr, u_int16 flags)
840{
841    mrtentry_t *r_new;
842    mrtentry_t *r_grp_insert, *r_src_insert; /* pointers to insert */
843    u_int32 source;
844    u_int32 group;
845
846    if (flags & MRTF_SG) {
847        /* (S,G) entry */
848        source = srcentry_ptr->address;
849        group  = grpentry_ptr->group;
850
851        if (search_grpmrtlink(grpentry_ptr, source, &r_grp_insert) == TRUE) {
852            return r_grp_insert;
853        }
854        if (search_srcmrtlink(srcentry_ptr, group, &r_src_insert) == TRUE) {
855            /*
856             * Hmmm, search_grpmrtlink() didn't find the entry, but
857             * search_srcmrtlink() did find it! Shoudn't happen. Panic!
858             */
859            logit(LOG_ERR, 0, "MRT inconsistency for src %s and grp %s\n",
860                  inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)));
861            /* not reached but to make lint happy */
862            return NULL;
863        }
864        /*
865         * Create and insert in group mrtlink and source mrtlink chains.
866         */
867        r_new = alloc_mrtentry(srcentry_ptr, grpentry_ptr);
868        if (r_new == NULL)
869            return NULL;
870        /*
871         * r_new has to be insert right after r_grp_insert in the
872         * grp mrtlink chain and right after r_src_insert in the
873         * src mrtlink chain
874         */
875        insert_grpmrtlink(r_new, r_grp_insert, grpentry_ptr);
876        insert_srcmrtlink(r_new, r_src_insert, srcentry_ptr);
877        r_new->flags |= MRTF_SG;
878        return r_new;
879    }
880
881    if (flags & MRTF_WC) {
882        /* (*,G) entry */
883        if (grpentry_ptr->grp_route != NULL)
884            return grpentry_ptr->grp_route;
885        r_new = alloc_mrtentry(srcentry_ptr, grpentry_ptr);
886        if (r_new == NULL)
887            return NULL;
888        grpentry_ptr->grp_route = r_new;
889        r_new->flags |= (MRTF_WC | MRTF_RP);
890        return r_new;
891    }
892
893    if (flags & MRTF_PMBR) {
894        /* (*,*,RP) entry */
895        if (srcentry_ptr->mrtlink != NULL)
896            return srcentry_ptr->mrtlink;
897        r_new = alloc_mrtentry(srcentry_ptr, grpentry_ptr);
898        if (r_new == NULL)
899            return NULL;
900        srcentry_ptr->mrtlink = r_new;
901        r_new->flags |= (MRTF_PMBR | MRTF_RP);
902        return r_new;
903    }
904
905    return NULL;
906}
907
908
909/*
910 * Delete all kernel cache for this mrtentry
911 */
912void delete_mrtentry_all_kernel_cache(mrtentry_t *mrtentry_ptr)
913{
914    kernel_cache_t *kernel_cache_prev;
915    kernel_cache_t *kernel_cache_ptr;
916
917    if (!(mrtentry_ptr->flags & MRTF_KERNEL_CACHE)) {
918        return;
919    }
920
921    /* Free all kernel_cache entries */
922    for (kernel_cache_ptr = mrtentry_ptr->kernel_cache; kernel_cache_ptr != NULL; ) {
923        kernel_cache_prev        = kernel_cache_ptr;
924        kernel_cache_ptr         = kernel_cache_ptr->next;
925        k_del_mfc(igmp_socket, kernel_cache_prev->source,
926                  kernel_cache_prev->group);
927        free((char *)kernel_cache_prev);
928    }
929    mrtentry_ptr->kernel_cache = NULL;
930
931    /* turn off the cache flag(s) */
932    mrtentry_ptr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
933}
934
935
936void delete_single_kernel_cache(mrtentry_t *mrtentry_ptr, kernel_cache_t *kernel_cache_ptr)
937{
938    if (kernel_cache_ptr->prev == NULL) {
939        mrtentry_ptr->kernel_cache = kernel_cache_ptr->next;
940        if (mrtentry_ptr->kernel_cache == NULL)
941            mrtentry_ptr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
942    } else {
943        kernel_cache_ptr->prev->next = kernel_cache_ptr->next;
944    }
945
946    if (kernel_cache_ptr->next != NULL)
947        kernel_cache_ptr->next->prev = kernel_cache_ptr->prev;
948
949    IF_DEBUG(DEBUG_MFC) {
950        logit(LOG_DEBUG, 0, "Deleting MFC entry for source %s and group %s",
951              inet_fmt(kernel_cache_ptr->source, s1, sizeof(s1)),
952              inet_fmt(kernel_cache_ptr->group, s2, sizeof(s2)));
953    }
954
955    k_del_mfc(igmp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group);
956    free((char *)kernel_cache_ptr);
957}
958
959
960void delete_single_kernel_cache_addr(mrtentry_t *mrtentry_ptr, u_int32 source, u_int32 group)
961{
962    u_int32 source_h;
963    u_int32 group_h;
964    kernel_cache_t *kernel_cache_ptr;
965
966    if (mrtentry_ptr == NULL)
967        return;
968
969    source_h = ntohl(source);
970    group_h  = ntohl(group);
971
972    /* Find the exact (S,G) kernel_cache entry */
973    for (kernel_cache_ptr = mrtentry_ptr->kernel_cache;
974         kernel_cache_ptr != NULL;
975         kernel_cache_ptr = kernel_cache_ptr->next) {
976        if (ntohl(kernel_cache_ptr->group) < group_h)
977            continue;
978        if (ntohl(kernel_cache_ptr->group) > group_h)
979            return;     /* Not found */
980        if (ntohl(kernel_cache_ptr->source) < source_h)
981            continue;
982        if (ntohl(kernel_cache_ptr->source) > source_h)
983            return;     /* Not found */
984
985        /* Found exact match */
986        break;
987    }
988
989    if (kernel_cache_ptr == NULL)
990        return;
991
992    /* Found. Delete it */
993    if (kernel_cache_ptr->prev == NULL) {
994        mrtentry_ptr->kernel_cache = kernel_cache_ptr->next;
995        if (mrtentry_ptr->kernel_cache == NULL)
996            mrtentry_ptr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
997    } else{
998        kernel_cache_ptr->prev->next = kernel_cache_ptr->next;
999    }
1000
1001    if (kernel_cache_ptr->next != NULL)
1002        kernel_cache_ptr->next->prev = kernel_cache_ptr->prev;
1003
1004    IF_DEBUG(DEBUG_MFC) {
1005        logit(LOG_DEBUG, 0, "Deleting MFC entry for source %s and group %s",
1006              inet_fmt(kernel_cache_ptr->source, s1, sizeof(s1)),
1007              inet_fmt(kernel_cache_ptr->group, s2, sizeof(s2)));
1008    }
1009
1010    k_del_mfc(igmp_socket, kernel_cache_ptr->source, kernel_cache_ptr->group);
1011    free((char *)kernel_cache_ptr);
1012}
1013
1014
1015/*
1016 * Installs kernel cache for (source, group). Assumes mrtentry_ptr
1017 * is the correct entry.
1018 */
1019void add_kernel_cache(mrtentry_t *mrtentry_ptr, u_int32 source, u_int32 group, u_int16 flags)
1020{
1021    u_int32 source_h;
1022    u_int32 group_h;
1023    kernel_cache_t *kernel_cache_next;
1024    kernel_cache_t *kernel_cache_prev;
1025    kernel_cache_t *kernel_cache_new;
1026
1027    if (mrtentry_ptr == NULL)
1028        return;
1029
1030    move_kernel_cache(mrtentry_ptr, flags);
1031
1032    if (mrtentry_ptr->flags & MRTF_SG) {
1033        /* (S,G) */
1034        if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE)
1035            return;
1036
1037        kernel_cache_new = (kernel_cache_t *)malloc(sizeof(kernel_cache_t));
1038        kernel_cache_new->next = NULL;
1039        kernel_cache_new->prev = NULL;
1040        kernel_cache_new->source = source;
1041        kernel_cache_new->group = group;
1042        kernel_cache_new->sg_count.pktcnt = 0;
1043        kernel_cache_new->sg_count.bytecnt = 0;
1044        kernel_cache_new->sg_count.wrong_if = 0;
1045        mrtentry_ptr->kernel_cache = kernel_cache_new;
1046        mrtentry_ptr->flags |= MRTF_KERNEL_CACHE;
1047
1048        return;
1049    }
1050
1051    source_h = ntohl(source);
1052    group_h = ntohl(group);
1053    kernel_cache_prev = NULL;
1054
1055    for (kernel_cache_next = mrtentry_ptr->kernel_cache;
1056         kernel_cache_next != NULL;
1057         kernel_cache_prev = kernel_cache_next,
1058             kernel_cache_next = kernel_cache_next->next) {
1059        if (ntohl(kernel_cache_next->group) < group_h)
1060            continue;
1061        if (ntohl(kernel_cache_next->group) > group_h)
1062            break;
1063        if (ntohl(kernel_cache_next->source) < source_h)
1064            continue;
1065        if (ntohl(kernel_cache_next->source) > source_h)
1066            break;
1067
1068        /* Found exact match. Nothing to change. */
1069        return;
1070    }
1071
1072    /*
1073     * The new entry must be placed between kernel_cache_prev and
1074     * kernel_cache_next
1075     */
1076    kernel_cache_new = (kernel_cache_t *)malloc(sizeof(kernel_cache_t));
1077    if (kernel_cache_prev != NULL)
1078        kernel_cache_prev->next = kernel_cache_new;
1079    else
1080        mrtentry_ptr->kernel_cache = kernel_cache_new;
1081
1082    if (kernel_cache_next != NULL)
1083        kernel_cache_next->prev = kernel_cache_new;
1084
1085    kernel_cache_new->prev = kernel_cache_prev;
1086    kernel_cache_new->next = kernel_cache_next;
1087    kernel_cache_new->source = source;
1088    kernel_cache_new->group = group;
1089    kernel_cache_new->sg_count.pktcnt = 0;
1090    kernel_cache_new->sg_count.bytecnt = 0;
1091    kernel_cache_new->sg_count.wrong_if = 0;
1092    mrtentry_ptr->flags |= MRTF_KERNEL_CACHE;
1093}
1094
1095/*
1096 * Bring the kernel cache "UP": from the (*,*,RP) to (*,G) or (S,G)
1097 */
1098static void move_kernel_cache(mrtentry_t *mrtentry_ptr, u_int16 flags)
1099{
1100    kernel_cache_t *kernel_cache_ptr;
1101    kernel_cache_t *insert_kernel_cache_ptr;
1102    kernel_cache_t *first_kernel_cache_ptr;
1103    kernel_cache_t *last_kernel_cache_ptr;
1104    kernel_cache_t *prev_kernel_cache_ptr;
1105    mrtentry_t     *mrtentry_pmbr;
1106    mrtentry_t     *mrtentry_rp;
1107    u_int32 group_h;
1108    u_int32 source_h;
1109    int found;
1110
1111    if (mrtentry_ptr == NULL)
1112        return;
1113
1114    if (mrtentry_ptr->flags & MRTF_PMBR)
1115        return;
1116
1117    if (mrtentry_ptr->flags & MRTF_WC) {
1118        /* Move the cache info from (*,*,RP) to (*,G) */
1119        group_h = ntohl(mrtentry_ptr->group->group);
1120        mrtentry_pmbr =
1121            mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
1122        if (mrtentry_pmbr == NULL)
1123            return;    /* Nothing to move */
1124
1125        first_kernel_cache_ptr = last_kernel_cache_ptr = NULL;
1126        for (kernel_cache_ptr = mrtentry_pmbr->kernel_cache;
1127             kernel_cache_ptr != NULL;
1128             kernel_cache_ptr = kernel_cache_ptr->next) {
1129            /*
1130             * The order is: (1) smaller group;
1131             *               (2) smaller source within group
1132             */
1133            if (ntohl(kernel_cache_ptr->group) < group_h)
1134                continue;
1135
1136            if (ntohl(kernel_cache_ptr->group) != group_h)
1137                break;
1138
1139            /* Select the kernel_cache entries to move  */
1140            if (first_kernel_cache_ptr == NULL) {
1141                first_kernel_cache_ptr = last_kernel_cache_ptr =
1142                    kernel_cache_ptr;
1143            } else {
1144                last_kernel_cache_ptr = kernel_cache_ptr;
1145            }
1146        }
1147
1148        if (first_kernel_cache_ptr != NULL) {
1149            /* Fix the old chain */
1150            if (first_kernel_cache_ptr->prev != NULL) {
1151                first_kernel_cache_ptr->prev->next =
1152                    last_kernel_cache_ptr->next;
1153            } else {
1154                mrtentry_pmbr->kernel_cache = last_kernel_cache_ptr->next;
1155            }
1156
1157            if (last_kernel_cache_ptr->next != NULL)
1158                last_kernel_cache_ptr->next->prev = first_kernel_cache_ptr->prev;
1159
1160            if (mrtentry_pmbr->kernel_cache == NULL)
1161                mrtentry_pmbr->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
1162
1163            /* Insert in the new place */
1164            prev_kernel_cache_ptr = NULL;
1165            last_kernel_cache_ptr->next = NULL;
1166            mrtentry_ptr->flags |= MRTF_KERNEL_CACHE;
1167
1168            for (kernel_cache_ptr = mrtentry_ptr->kernel_cache;
1169                 kernel_cache_ptr != NULL; ) {
1170                if (first_kernel_cache_ptr == NULL)
1171                    break;  /* All entries have been inserted */
1172
1173                if (ntohl(kernel_cache_ptr->source) >
1174                    ntohl(first_kernel_cache_ptr->source)) {
1175                    /* Insert the entry before kernel_cache_ptr */
1176                    insert_kernel_cache_ptr = first_kernel_cache_ptr;
1177                    first_kernel_cache_ptr = first_kernel_cache_ptr->next;
1178
1179                    if (kernel_cache_ptr->prev != NULL)
1180                        kernel_cache_ptr->prev->next = insert_kernel_cache_ptr;
1181                    else
1182                        mrtentry_ptr->kernel_cache = insert_kernel_cache_ptr;
1183
1184                    insert_kernel_cache_ptr->prev = kernel_cache_ptr->prev;
1185                    insert_kernel_cache_ptr->next = kernel_cache_ptr;
1186                    kernel_cache_ptr->prev = insert_kernel_cache_ptr;
1187                }
1188                prev_kernel_cache_ptr = kernel_cache_ptr;
1189                kernel_cache_ptr = kernel_cache_ptr->next;
1190            }
1191
1192            if (first_kernel_cache_ptr != NULL) {
1193                /* Place all at the end after prev_kernel_cache_ptr */
1194                if (prev_kernel_cache_ptr != NULL)
1195                    prev_kernel_cache_ptr->next = first_kernel_cache_ptr;
1196                else
1197                    mrtentry_ptr->kernel_cache = first_kernel_cache_ptr;
1198
1199                first_kernel_cache_ptr->prev = prev_kernel_cache_ptr;
1200            }
1201        }
1202
1203        return;
1204    }
1205
1206    if (mrtentry_ptr->flags & MRTF_SG) {
1207        /* (S,G) entry. Move the whole group cache from (*,*,RP) to (*,G) and
1208         * then get the necessary entry from (*,G).
1209         * TODO: Not optimized! The particular entry is moved first to (*,G),
1210         * then we have to search again (*,G) to find it and move to (S,G).
1211         */
1212        /* TODO: XXX: No need for this? Thinking.... */
1213/*      move_kernel_cache(mrtentry_ptr->group->grp_route, flags); */
1214        if ((mrtentry_rp = mrtentry_ptr->group->grp_route) == NULL)
1215            mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
1216
1217        if (mrtentry_rp == NULL)
1218            return;
1219
1220        if (mrtentry_rp->incoming != mrtentry_ptr->incoming) {
1221            /* XXX: the (*,*,RP) (or (*,G)) iif is different from the
1222             * (S,G) iif. No need to move the cache, because (S,G) don't
1223             * need it. After the first packet arrives on the shortest path,
1224             * the correct cache entry will be created.
1225             * If (flags & MFC_MOVE_FORCE) then we must move the cache.
1226             * This usually happens when switching to the shortest path.
1227             * The calling function will immediately call k_chg_mfc()
1228             * to modify the kernel cache.
1229             */
1230            if (!(flags & MFC_MOVE_FORCE))
1231                return;
1232        }
1233
1234        /* Find the exact entry */
1235        source_h = ntohl(mrtentry_ptr->source->address);
1236        group_h  = ntohl(mrtentry_ptr->group->group);
1237        found = FALSE;
1238        for (kernel_cache_ptr = mrtentry_rp->kernel_cache;
1239             kernel_cache_ptr != NULL;
1240             kernel_cache_ptr = kernel_cache_ptr->next) {
1241            if (ntohl(kernel_cache_ptr->group) < group_h)
1242                continue;
1243
1244            if (ntohl(kernel_cache_ptr->group) > group_h)
1245                break;
1246
1247            if (ntohl(kernel_cache_ptr->source) < source_h)
1248                continue;
1249
1250            if (ntohl(kernel_cache_ptr->source) > source_h)
1251                break;
1252
1253            /* We found it! */
1254            if (kernel_cache_ptr->prev != NULL){
1255                kernel_cache_ptr->prev->next = kernel_cache_ptr->next;
1256            } else {
1257                mrtentry_rp->kernel_cache = kernel_cache_ptr->next;
1258            }
1259
1260            if (kernel_cache_ptr->next != NULL)
1261                kernel_cache_ptr->next->prev = kernel_cache_ptr->prev;
1262
1263            found = TRUE;
1264
1265            break;
1266        }
1267
1268        if (found == TRUE) {
1269            if (mrtentry_rp->kernel_cache == NULL)
1270                mrtentry_rp->flags &= ~(MRTF_KERNEL_CACHE | MRTF_MFC_CLONE_SG);
1271
1272            if (mrtentry_ptr->kernel_cache != NULL)
1273                free ((char *)mrtentry_ptr->kernel_cache);
1274
1275            mrtentry_ptr->flags |= MRTF_KERNEL_CACHE;
1276            mrtentry_ptr->kernel_cache = kernel_cache_ptr;
1277            kernel_cache_ptr->prev = NULL;
1278            kernel_cache_ptr->next = NULL;
1279        }
1280    }
1281}
1282
1283/**
1284 * Local Variables:
1285 *  version-control: t
1286 *  indent-tabs-mode: t
1287 *  c-file-style: "ellemtel"
1288 *  c-basic-offset: 4
1289 * End:
1290 */
Note: See TracBrowser for help on using the repository browser.