]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pim6sd/route.c
This commit was generated by cvs2svn to compensate for changes in r72562,
[FreeBSD/FreeBSD.git] / usr.sbin / pim6sd / route.c
1 /*
2  *  Copyright (c) 1998 by the University of Southern California.
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 Southern
13  *  California and/or Information Sciences Institute.
14  *  The name of the University of Southern California may not
15  *  be used to endorse or promote products derived from this software
16  *  without specific prior written permission.
17  *
18  *  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19  *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
20  *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21  *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
23  *  NON-INFRINGEMENT.
24  *
25  *  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  *
30  *  Other copyrights might apply to parts of this software and are so
31  *  noted when applicable.
32  */
33 /*
34  *  Questions concerning this software should be directed to
35  *  Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
36  *
37  */
38 /*
39  * This program has been derived from pim6dd.        
40  * The pim6dd program is covered by the license in the accompanying file
41  * named "LICENSE.pim6dd".
42  */
43 /*
44  * This program has been derived from pimd.        
45  * The pimd program is covered by the license in the accompanying file
46  * named "LICENSE.pimd".
47  *
48  * $FreeBSD$
49  */
50
51 #include <sys/types.h>
52 #include <syslog.h>
53 #include "pimd.h"
54 #include "vif.h"
55 #include "mrt.h"
56 #include "debug.h"
57 #include "pim6_proto.h"
58 #include "route.h"
59 #include "mld6.h"
60 #include "rp.h"
61 #include "kern.h"
62 #include "timer.h"
63 #include "inet6.h"
64 #include <netinet6/ip6_mroute.h>
65 #include <netinet/ip6.h>
66 #include "routesock.h"
67
68 static void process_cache_miss __P((struct mrt6msg * im));
69 static void process_wrong_iif __P((struct mrt6msg * im));
70 static void process_whole_pkt __P((char *buf));
71
72 u_int32         default_source_metric = UCAST_DEFAULT_SOURCE_METRIC;
73 u_int32         default_source_preference = UCAST_DEFAULT_SOURCE_PREFERENCE;
74
75
76 /* Return the iif for given address */
77
78 vifi_t
79 get_iif(address)
80     struct sockaddr_in6 *address;
81 {
82     struct rpfctl   rpfc;
83
84     k_req_incoming(address, &rpfc);
85     if (IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr))
86         return (NO_VIF);
87     return (rpfc.iif);
88 }
89
90 /* Return the PIM neighbor toward a source */
91 /*
92  * If route not found or if a local source or if a directly connected source,
93  * but is not PIM router, or if the first hop router is not a PIM router,
94  * then return NULL.
95  */
96 pim_nbr_entry_t *
97 find_pim6_nbr(source)
98     struct sockaddr_in6 *source;
99 {
100     struct rpfctl   rpfc;
101     pim_nbr_entry_t *pim_nbr;
102     struct sockaddr_in6 next_hop_router_addr;
103
104     if (local_address(source) != NO_VIF)
105         return (pim_nbr_entry_t *) NULL;
106     k_req_incoming(source, &rpfc);
107     if((IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr))
108         || (rpfc.iif == NO_VIF))
109         return (pim_nbr_entry_t *) NULL;
110     next_hop_router_addr = rpfc.rpfneighbor;
111     for (pim_nbr = uvifs[rpfc.iif].uv_pim_neighbors;
112          pim_nbr != (pim_nbr_entry_t *) NULL;
113          pim_nbr = pim_nbr->next)
114         if (inet6_equal(&pim_nbr->address,&next_hop_router_addr))
115             return (pim_nbr);
116     return (pim_nbr_entry_t *) NULL;
117 }
118
119
120 /*
121  * TODO: check again the exact setup if the source is local or directly
122  * connected!!! Yes Really for Ipv6!!
123  */
124 /*
125  * TODO: XXX: change the metric and preference for all (S,G) entries per
126  * source or RP?
127  */
128 /*
129  * TODO - If possible, this would be the place to correct set the source's
130  * preference and metric to that obtained from the kernel and/or unicast
131  * routing protocol.  For now, set it to the configured default for local
132  * pref/metric.
133  */
134
135 /*
136  * Set the iif, upstream router, preference and metric for the route toward
137  * the source. Return TRUE is the route was found, othewise FALSE. If
138  * srctype==PIM_IIF_SOURCE and if the source is directly connected then the
139  * "upstream" is set to NULL. If srcentry==PIM_IIF_RP, then "upstream" in
140  * case of directly connected "source" will be that "source" (if it is also
141  * PIM router).,
142  */
143 int
144 set_incoming(srcentry_ptr, srctype)
145     srcentry_t     *srcentry_ptr;
146     int             srctype;
147 {
148     struct rpfctl       rpfc;
149     struct sockaddr_in6 source = srcentry_ptr->address;
150     struct sockaddr_in6 neighbor_addr;
151     register struct uvif *v;
152     register pim_nbr_entry_t *n;
153
154     /* Preference will be 0 if directly connected */
155
156     srcentry_ptr->metric = 0;
157     srcentry_ptr->preference = 0;
158
159     if ((srcentry_ptr->incoming = local_address(&source)) != NO_VIF)
160     {
161         /* The source is a local address */
162         /* TODO: set the upstream to myself? */
163         srcentry_ptr->upstream = (pim_nbr_entry_t *) NULL;
164         return (TRUE);
165     }
166
167     if ((srcentry_ptr->incoming = find_vif_direct(&source)) != NO_VIF)
168     {
169         /*
170          * The source is directly connected. Check whether we are looking for
171          * real source or RP
172          */
173
174         if (srctype == PIM_IIF_SOURCE)
175         {
176             srcentry_ptr->upstream = (pim_nbr_entry_t *) NULL;
177             return (TRUE);
178         }
179         else
180         {
181             /* PIM_IIF_RP */
182             neighbor_addr = source;
183         }
184     }
185     else
186     {
187         /* TODO: probably need to check the case if the iif is disabled */
188         /* Use the lastest resource: the kernel unicast routing table */
189         k_req_incoming(&source, &rpfc);
190         if ((rpfc.iif == NO_VIF) ||
191             IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr))
192         {
193             /* couldn't find a route */
194             IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF)
195                 log(LOG_DEBUG, 0, "NO ROUTE found for %s",
196                     inet6_fmt(&source.sin6_addr));
197             return (FALSE);
198         }
199         srcentry_ptr->incoming = rpfc.iif;
200         neighbor_addr = rpfc.rpfneighbor;
201         /* set the preference for sources that aren't directly connected. */
202         v = &uvifs[srcentry_ptr->incoming];
203         srcentry_ptr->preference = v->uv_local_pref;
204         srcentry_ptr->metric = v->uv_local_metric;
205     }
206
207     /*
208      * The upstream router must be a (PIM router) neighbor, otherwise we are
209      * in big trouble ;-). 
210      * Yes but the neighbors are link-local and the rp is global ipv6..
211      */
212 /* WARNING WARNING WARNING WARNING */
213 /* If the router is directly connected to the RP and the RP is the BSR , the next hop is
214  * the globally reachable addresse of the RP : NOT link local neighbor but
215  * a ipv6 global neighbor... 
216  * the upstream router is the globally reachable router...
217  *
218  */
219 /* WARNING WARNING WARNING WARNING */
220
221     v = &uvifs[srcentry_ptr->incoming];
222     if (inet6_equal(&source,&neighbor_addr))
223     {
224         srcentry_ptr->upstream=v->uv_pim_neighbors;
225         return (TRUE);
226     }
227
228     for (n = v->uv_pim_neighbors; n != NULL; n = n->next)
229     {
230         if (inet6_lessthan(&neighbor_addr,&n->address))
231             continue;
232         if (inet6_equal(&neighbor_addr,&n->address))
233         {
234             /*
235              * The upstream router is found in the list of neighbors. We are
236              * safe!
237              */
238
239             srcentry_ptr->upstream = n;
240             IF_DEBUG(DEBUG_RPF)
241                 log(LOG_DEBUG, 0,
242                     "For src %s, iif is %d, next hop router is %s",
243                     inet6_fmt(&source.sin6_addr), srcentry_ptr->incoming,
244                     inet6_fmt(&neighbor_addr.sin6_addr));
245             return (TRUE);
246         }
247         else
248             break;
249     }
250
251     /* TODO: control the number of messages! */
252     log(LOG_INFO, 0,
253         "For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER",
254         inet6_fmt(&source.sin6_addr), srcentry_ptr->incoming,
255         inet6_fmt(&neighbor_addr.sin6_addr));
256
257     srcentry_ptr->upstream = (pim_nbr_entry_t *) NULL;
258
259     return (FALSE);
260 }
261
262
263 /*
264  * TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where
265  * we have source-specific Join/Prune.
266  */
267
268 void
269 add_leaf(vifi, source, group)
270     vifi_t          vifi;
271     struct sockaddr_in6 *source;
272     struct sockaddr_in6 *group;
273 {
274     mrtentry_t     *mrtentry_ptr;
275     if_set     old_oifs;
276     if_set     new_oifs;
277     if_set     new_leaves;
278
279
280     mrtentry_ptr = find_route(&sockaddr6_any, group, MRTF_WC, CREATE);
281
282     if (mrtentry_ptr == (mrtentry_t *) NULL)
283         return;
284
285     if ((mrtentry_ptr->incoming == vifi)
286         && (!(uvifs[vifi].uv_flags & VIFF_DR)))
287     {
288         /*
289          * The report is received on the iif for this routing entry and I am
290          * not the DR for that subnet. Ignore it.
291          */
292
293         if (mrtentry_ptr->flags & MRTF_NEW)
294             delete_mrtentry(mrtentry_ptr);
295         return;
296     }
297
298     IF_DEBUG(DEBUG_MRT)
299         log(LOG_DEBUG, 0, "Adding vif %d for group %s", vifi,
300             inet6_fmt(&group->sin6_addr));
301
302     if (IF_ISSET(vifi, &mrtentry_ptr->leaves))
303         return;                 /* Already a leaf */
304     calc_oifs(mrtentry_ptr, &old_oifs);
305     IF_COPY(&mrtentry_ptr->leaves, &new_leaves);
306     IF_SET(vifi, &new_leaves);  /* Add the leaf */
307     change_interfaces(mrtentry_ptr,
308                       mrtentry_ptr->incoming,
309                       &mrtentry_ptr->joined_oifs,
310                       &mrtentry_ptr->pruned_oifs,
311                       &new_leaves,
312                       &mrtentry_ptr->asserted_oifs, 0);
313     calc_oifs(mrtentry_ptr, &new_oifs);
314
315     if ((mrtentry_ptr->flags & MRTF_NEW)
316         || (IF_ISEMPTY(&old_oifs) && (!IF_ISEMPTY(&new_oifs))))
317     {
318
319         /*
320          * A new created entry or the oifs have changed from NULL to
321          * non-NULL.
322          */
323
324         mrtentry_ptr->flags &= ~MRTF_NEW;
325         FIRE_TIMER(mrtentry_ptr->jp_timer);     /* Timeout the Join/Prune
326                                                  * timer */
327         /*
328          * TODO: explicitly call the function below?
329          * send_pim6_join_prune(mrtentry_ptr->upstream->vifi,
330          * mrtentry_ptr->upstream, pim_join_prune_holdtime);
331          */
332     }
333 }
334
335
336 /*
337  * TODO: XXX: currently `source` is not used. To be used with IGMPv3 where we
338  * have source-specific joins/prunes.
339  */
340 void
341 delete_leaf(vifi, source, group)
342     vifi_t          vifi;
343     struct sockaddr_in6 *source;
344     struct sockaddr_in6 *group;
345 {
346     mrtentry_t     *mrtentry_ptr;
347     mrtentry_t     *mrtentry_srcs;
348     if_set                      new_oifs;
349     if_set     old_oifs;
350     if_set     new_leaves;
351
352     mrtentry_ptr = find_route(&sockaddr6_any, group, MRTF_WC, DONT_CREATE);
353     if (mrtentry_ptr == (mrtentry_t *) NULL)
354         return;
355
356     if (!IF_ISSET(vifi, &mrtentry_ptr->leaves))
357         return;                 /* This interface wasn't leaf */
358
359     calc_oifs(mrtentry_ptr, &old_oifs);
360     IF_COPY(&mrtentry_ptr->leaves, &new_leaves);
361     IF_CLR(vifi, &new_leaves);
362     change_interfaces(mrtentry_ptr,
363                       mrtentry_ptr->incoming,
364                       &mrtentry_ptr->joined_oifs,
365                       &mrtentry_ptr->pruned_oifs,
366                       &new_leaves,
367                       &mrtentry_ptr->asserted_oifs, 0);
368     calc_oifs(mrtentry_ptr, &new_oifs);
369     if ((!IF_ISEMPTY(&old_oifs)) && IF_ISEMPTY(&new_oifs))
370     {
371         /* The result oifs have changed from non-NULL to NULL */
372         FIRE_TIMER(mrtentry_ptr->jp_timer);     /* Timeout the Join/Prune
373                                                  * timer */
374         /*
375          * TODO: explicitly call the function?
376          * send_pim6_join_prune(mrtentry_ptr->upstream->vifi,
377          * mrtentry_ptr->upstream, pim_join_prune_holdtime);
378          */
379     }
380     /*
381      * Check all (S,G) entries and clear the inherited "leaf" flag. TODO:
382      * XXX: This won't work for IGMPv3, because there we don't know whether
383      * the (S,G) leaf oif was inherited from the (*,G) entry or was created
384      * by source specific IGMP join.
385      */
386     for (mrtentry_srcs = mrtentry_ptr->group->mrtlink;
387          mrtentry_srcs != (mrtentry_t *) NULL;
388          mrtentry_srcs = mrtentry_srcs->grpnext)
389     {
390         IF_COPY(&mrtentry_srcs->leaves, &new_leaves);
391         IF_CLR(vifi, &new_leaves);
392         change_interfaces(mrtentry_srcs,
393                           mrtentry_srcs->incoming,
394                           &mrtentry_srcs->joined_oifs,
395                           &mrtentry_srcs->pruned_oifs,
396                           &new_leaves,
397                           &mrtentry_srcs->asserted_oifs, 0);
398     }
399
400 }
401
402
403 void
404 calc_oifs(mrtentry_ptr, oifs_ptr)
405     mrtentry_t     *mrtentry_ptr;
406     if_set         *oifs_ptr;
407 {
408     if_set     oifs;
409     mrtentry_t     *grp_route;
410     mrtentry_t     *rp_route;
411
412     /*
413      * oifs = (((copied_outgoing + my_join) - my_prune) + my_leaves) -
414      * my_asserted_oifs - incoming_interface, i.e. `leaves` have higher
415      * priority than `prunes`, but lower priority than `asserted`. The
416      * incoming interface is always deleted from the oifs
417      */
418
419     if (mrtentry_ptr == (mrtentry_t *) NULL)
420     {
421         IF_ZERO(oifs_ptr);
422         return;
423     }
424     IF_ZERO(&oifs);
425     if (!(mrtentry_ptr->flags & MRTF_PMBR))
426     {
427         /* Either (*,G) or (S,G). Merge with the oifs from the (*,*,RP) */
428         if ((rp_route =
429              mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink)
430             != (mrtentry_t *) NULL)
431         {
432             IF_MERGE(&oifs, &rp_route->joined_oifs, &oifs);
433             IF_CLR_MASK(&oifs, &rp_route->pruned_oifs);
434             IF_MERGE(&oifs, &rp_route->leaves, &oifs);
435             IF_CLR_MASK(&oifs, &rp_route->asserted_oifs);
436         }
437     }
438     if (mrtentry_ptr->flags & MRTF_SG)
439     {
440         /* (S,G) entry. Merge with the oifs from (*,G) */
441         if ((grp_route = mrtentry_ptr->group->grp_route)
442             != (mrtentry_t *) NULL)
443         {
444             IF_MERGE(&oifs, &grp_route->joined_oifs, &oifs);
445             IF_CLR_MASK(&oifs, &grp_route->pruned_oifs);
446             IF_MERGE(&oifs, &grp_route->leaves, &oifs);
447             IF_CLR_MASK(&oifs, &grp_route->asserted_oifs);
448         }
449     }
450
451     /* Calculate my own stuff */
452     IF_MERGE(&oifs, &mrtentry_ptr->joined_oifs, &oifs);
453     IF_CLR_MASK(&oifs, &mrtentry_ptr->pruned_oifs);
454     IF_MERGE(&oifs, &mrtentry_ptr->leaves, &oifs);
455     IF_CLR_MASK(&oifs, &mrtentry_ptr->asserted_oifs);
456
457     IF_CLR(mrtentry_ptr->incoming, &oifs);
458     IF_COPY(&oifs, oifs_ptr);
459 }
460
461 /*
462  * Set the iif, join/prune/leaves/asserted interfaces. Calculate and set the
463  * oifs. Return 1 if oifs change from NULL to not-NULL. Return -1 if oifs
464  * change from non-NULL to NULL else return 0 If the iif change or if the
465  * oifs change from NULL to non-NULL or vice-versa, then schedule that
466  * mrtentry join/prune timer to timeout immediately.
467  */
468 int
469 change_interfaces(mrtentry_ptr, new_iif, new_joined_oifs_, new_pruned_oifs,
470                   new_leaves_, new_asserted_oifs, flags)
471     mrtentry_t     *mrtentry_ptr;
472     vifi_t          new_iif;
473     if_set      *new_joined_oifs_;
474     if_set     *new_pruned_oifs;
475     if_set     *new_leaves_;
476     if_set     *new_asserted_oifs;
477     u_int16         flags;
478 {
479     if_set         new_joined_oifs;     /* The oifs for that particular
480                                          * mrtentry */
481     if_set     old_joined_oifs;
482     if_set     old_pruned_oifs;
483     if_set     old_leaves;
484     if_set     new_leaves;
485     if_set     old_asserted_oifs;
486     if_set     new_real_oifs;   /* The result oifs */
487     if_set     old_real_oifs;
488     vifi_t          old_iif;
489     rpentry_t      *rpentry_ptr;
490     cand_rp_t      *cand_rp_ptr;
491     kernel_cache_t *kernel_cache_ptr;
492     rp_grp_entry_t *rp_grp_entry_ptr;
493     grpentry_t     *grpentry_ptr;
494     mrtentry_t     *mrtentry_srcs;
495     mrtentry_t     *mrtentry_wc;
496     mrtentry_t     *mrtentry_rp;
497     int             delete_mrtentry_flag;
498     int             return_value;
499     int             fire_timer_flag;
500
501     if (mrtentry_ptr == (mrtentry_t *) NULL)
502         return (0);
503
504     IF_COPY(new_joined_oifs_, &new_joined_oifs);
505     IF_COPY(new_leaves_, &new_leaves);
506
507     old_iif = mrtentry_ptr->incoming;
508     IF_COPY(&mrtentry_ptr->joined_oifs, &old_joined_oifs);
509     IF_COPY(&mrtentry_ptr->leaves, &old_leaves);
510     IF_COPY(&mrtentry_ptr->pruned_oifs, &old_pruned_oifs);
511     IF_COPY(&mrtentry_ptr->asserted_oifs, &old_asserted_oifs);
512
513     IF_COPY(&mrtentry_ptr->oifs, &old_real_oifs);
514
515     mrtentry_ptr->incoming = new_iif;
516     IF_COPY(&new_joined_oifs, &mrtentry_ptr->joined_oifs);
517     IF_COPY(new_pruned_oifs, &mrtentry_ptr->pruned_oifs);
518     IF_COPY(&new_leaves, &mrtentry_ptr->leaves);
519     IF_COPY(new_asserted_oifs, &mrtentry_ptr->asserted_oifs);
520     calc_oifs(mrtentry_ptr, &new_real_oifs);
521
522     if (IF_ISEMPTY(&old_real_oifs))
523     {
524         if (IF_ISEMPTY(&new_real_oifs))
525             return_value = 0;
526         else
527             return_value = 1;
528     }
529     else
530     {
531         if (IF_ISEMPTY(&new_real_oifs))
532             return_value = -1;
533         else
534             return_value = 0;
535     }
536
537     if ((IF_SAME(&new_real_oifs, &old_real_oifs))
538         && (new_iif == old_iif)
539         && !(flags & MFC_UPDATE_FORCE))
540         return 0;               /* Nothing to change */
541
542     if ((return_value != 0) || (new_iif != old_iif)
543         || (flags & MFC_UPDATE_FORCE))
544         FIRE_TIMER(mrtentry_ptr->jp_timer);
545
546     IF_COPY(&new_real_oifs, &mrtentry_ptr->oifs);
547
548     if (mrtentry_ptr->flags & MRTF_PMBR)
549     {
550         /* (*,*,RP) entry */
551         rpentry_ptr = mrtentry_ptr->source;
552         if (rpentry_ptr == (rpentry_t *) NULL)
553             return (0);         /* Shoudn't happen */
554         rpentry_ptr->incoming = new_iif;
555         cand_rp_ptr = rpentry_ptr->cand_rp;
556
557         if (IF_ISEMPTY(&new_real_oifs))
558         {
559             delete_mrtentry_flag = TRUE;
560         }
561         else
562         {
563             delete_mrtentry_flag = FALSE;
564 #ifdef RSRR
565             rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
566 #endif                          /* RSRR */
567         }
568
569         if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE)
570         {
571             /* Update the kernel MFC entries */
572             if (delete_mrtentry_flag == TRUE)
573                 /*
574                  * XXX: no need to send RSRR message. Will do it when delete
575                  * the mrtentry.
576                  */
577                 for (kernel_cache_ptr = mrtentry_ptr->kernel_cache;
578                      kernel_cache_ptr != (kernel_cache_t *) NULL;
579                      kernel_cache_ptr = kernel_cache_ptr->next)
580                     delete_mrtentry_all_kernel_cache(mrtentry_ptr);
581             else
582             {
583                 for (kernel_cache_ptr = mrtentry_ptr->kernel_cache;
584                      kernel_cache_ptr != (kernel_cache_t *) NULL;
585                      kernel_cache_ptr = kernel_cache_ptr->next)
586                     /* here mrtentry_ptr->source->address is the RP address */
587                     k_chg_mfc(mld6_socket, &kernel_cache_ptr->source,
588                               &kernel_cache_ptr->group, new_iif,
589                               &new_real_oifs, &mrtentry_ptr->source->address);
590             }
591         }
592
593         /*
594          * Update all (*,G) entries associated with this RP. The particular
595          * (*,G) outgoing are not changed, but the change in the (*,*,RP)
596          * oifs may have affect the real oifs.
597          */
598         fire_timer_flag = FALSE;
599         for (rp_grp_entry_ptr = cand_rp_ptr->rp_grp_next;
600              rp_grp_entry_ptr != (rp_grp_entry_t *) NULL;
601              rp_grp_entry_ptr = rp_grp_entry_ptr->rp_grp_next)
602         {
603             for (grpentry_ptr = rp_grp_entry_ptr->grplink;
604                  grpentry_ptr != (grpentry_t *) NULL;
605                  grpentry_ptr = grpentry_ptr->rpnext)
606             {
607                 if (grpentry_ptr->grp_route != (mrtentry_t *) NULL)
608                 {
609                     if (change_interfaces(grpentry_ptr->grp_route, new_iif,
610                                        &grpentry_ptr->grp_route->joined_oifs,
611                                        &grpentry_ptr->grp_route->pruned_oifs,
612                                           &grpentry_ptr->grp_route->leaves,
613                                      &grpentry_ptr->grp_route->asserted_oifs,
614                                           flags))
615                         fire_timer_flag = TRUE;
616                 }
617                 else
618                 {
619                     /* Change all (S,G) entries if no (*,G) */
620                     for (mrtentry_srcs = grpentry_ptr->mrtlink;
621                          mrtentry_srcs != (mrtentry_t *) NULL;
622                          mrtentry_srcs = mrtentry_srcs->grpnext)
623                     {
624                         if (mrtentry_srcs->flags & MRTF_RP)
625                         {
626                             if (change_interfaces(mrtentry_srcs, new_iif,
627                                                   &mrtentry_srcs->joined_oifs,
628                                                   &mrtentry_srcs->pruned_oifs,
629                                                   &mrtentry_srcs->leaves,
630                                                &mrtentry_srcs->asserted_oifs,
631                                                   flags))
632                                 fire_timer_flag = TRUE;
633                         }
634                         else
635                         {
636                             if (change_interfaces(mrtentry_srcs,
637                                                   mrtentry_srcs->incoming,
638                                                   &mrtentry_srcs->joined_oifs,
639                                                   &mrtentry_srcs->pruned_oifs,
640                                                   &mrtentry_srcs->leaves,
641                                                &mrtentry_srcs->asserted_oifs,
642                                                   flags))
643                                 fire_timer_flag = TRUE;
644                         }
645                     }
646                 }
647             }
648         }
649         if (fire_timer_flag == TRUE)
650             FIRE_TIMER(mrtentry_ptr->jp_timer);
651         if (delete_mrtentry_flag == TRUE)
652         {
653             /*
654              * TODO: XXX: trigger a Prune message? Don't delete now, it will
655              * be automatically timed out. If want to delete now, don't
656              * reference to it anymore! delete_mrtentry(mrtentry_ptr);
657              */
658         }
659         return (return_value);  /* (*,*,RP) */
660     }
661
662     if (mrtentry_ptr->flags & MRTF_WC)
663     {
664         /* (*,G) entry */
665         if (IF_ISEMPTY(&new_real_oifs))
666             delete_mrtentry_flag = TRUE;
667         else
668         {
669             delete_mrtentry_flag = FALSE;
670 #ifdef RSRR
671             rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
672 #endif                          /* RSRR */
673         }
674         if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE)
675         {
676             if (delete_mrtentry_flag == TRUE)
677                 delete_mrtentry_all_kernel_cache(mrtentry_ptr);
678             else
679             {
680                 for (kernel_cache_ptr = mrtentry_ptr->kernel_cache;
681                      kernel_cache_ptr != (kernel_cache_t *) NULL;
682                      kernel_cache_ptr = kernel_cache_ptr->next)
683                     k_chg_mfc(mld6_socket, &kernel_cache_ptr->source,
684                               &kernel_cache_ptr->group, new_iif,
685                               &new_real_oifs, &mrtentry_ptr->group->rpaddr);
686             }
687         }
688         /*
689          * Update all (S,G) entries for this group. For the (S,G)RPbit
690          * entries the iif is the iif toward the RP; The particular (S,G)
691          * oifs are not changed, but the change in the (*,G) oifs may affect
692          * the real oifs.
693          */
694         fire_timer_flag = FALSE;
695         for (mrtentry_srcs = mrtentry_ptr->group->mrtlink;
696              mrtentry_srcs != (mrtentry_t *) NULL;
697              mrtentry_srcs = mrtentry_srcs->grpnext)
698         {
699             if (mrtentry_srcs->flags & MRTF_RP)
700             {
701                 if (change_interfaces(mrtentry_srcs, new_iif,
702                                       &mrtentry_srcs->joined_oifs,
703                                       &mrtentry_srcs->pruned_oifs,
704                                       &mrtentry_srcs->leaves,
705                                       &mrtentry_srcs->asserted_oifs, flags))
706                     fire_timer_flag = TRUE;
707             }
708             else
709             {
710                 if (change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming,
711                                       &mrtentry_srcs->joined_oifs,
712                                       &mrtentry_srcs->pruned_oifs,
713                                       &mrtentry_srcs->leaves,
714                                       &mrtentry_srcs->asserted_oifs, flags))
715                     fire_timer_flag = TRUE;
716             }
717         }
718
719         if (fire_timer_flag == TRUE)
720             FIRE_TIMER(mrtentry_ptr->jp_timer);
721         if (delete_mrtentry_flag == TRUE)
722         {
723             /* TODO: XXX: the oifs are NULL. Send a Prune message? */
724         }
725         return (return_value);  /* (*,G) */
726     }
727
728     if (mrtentry_ptr->flags & MRTF_SG)
729     {
730         /* (S,G) entry */
731 #ifdef KERNEL_MFC_WC_G
732         if_set     tmp_oifs;
733         mrtentry_t     *mrtentry_tmp;
734 #endif                          /* KERNEL_MFC_WC_G */
735
736         mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
737         mrtentry_wc = mrtentry_ptr->group->grp_route;
738 #ifdef KERNEL_MFC_WC_G
739         /*
740          * Check whether (*,*,RP) or (*,G) have different (iif,oifs) from the
741          * (S,G). If "yes", then forbid creating (*,G) MFC.
742          */
743         for (mrtentry_tmp = mrtentry_rp; 1; mrtentry_tmp = mrtentry_wc)
744         {
745             for (; 1;)
746             {
747                 if (mrtentry_tmp == (mrtentry_t *) NULL)
748                     break;
749                 if (mrtentry_tmp->flags & MRTF_MFC_CLONE_SG)
750                     break;
751                 if (mrtentry_tmp->incoming != mrtentry_ptr->incoming)
752                 {
753                     delete_single_kernel_cache_addr(mrtentry_tmp, IN6ADDR_ANY_N,
754                                                 mrtentry_ptr->group->group);
755                     mrtentry_tmp->flags |= MRTF_MFC_CLONE_SG;
756                     break;
757                 }
758                 calc_oifs(mrtentry_tmp, &tmp_oifs);
759                 if (!(IF_SAME(&new_real_oifs, &tmp_oifs)))
760                     mrtentry_tmp->flags |= MRTF_MFC_CLONE_SG;
761                 break;
762             }
763             if (mrtentry_tmp == mrtentry_wc)
764                 break;
765         }
766 #endif                          /* KERNEL_MFC_WC_G */
767
768         if (IF_ISEMPTY(&new_real_oifs))
769             delete_mrtentry_flag = TRUE;
770         else
771         {
772             delete_mrtentry_flag = FALSE;
773 #ifdef RSRR
774             rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
775 #endif                          /* RSRR */
776         }
777         if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE)
778         {
779             if (delete_mrtentry_flag == TRUE)
780                 delete_mrtentry_all_kernel_cache(mrtentry_ptr);
781             else
782             {
783                 k_chg_mfc(mld6_socket, &mrtentry_ptr->source->address,
784                           &mrtentry_ptr->group->group, new_iif, &new_real_oifs,
785                           &mrtentry_ptr->group->rpaddr);
786             }
787         }
788         if (old_iif != new_iif)
789         {
790             if (new_iif == mrtentry_ptr->source->incoming)
791             {
792                 /*
793                  * For example, if this was (S,G)RPbit with iif toward the
794                  * RP, and now switch to the Shortest Path. The setup of
795                  * MRTF_SPT flag must be done by the external calling
796                  * function (triggered only by receiving of a data from the
797                  * source.)
798                  */
799                 mrtentry_ptr->flags &= ~MRTF_RP;
800                 /*
801                  * TODO: XXX: delete? Check again where will be the best
802                  * place to set it. mrtentry_ptr->flags |= MRTF_SPT;
803                  */
804             }
805             if (((mrtentry_wc != (mrtentry_t *) NULL)
806                  && (mrtentry_wc->incoming == new_iif))
807                 || ((mrtentry_rp != (mrtentry_t *) NULL)
808                     && (mrtentry_rp->incoming == new_iif)))
809             {
810                 /*
811                  * If the new iif points toward the RP, reset the SPT flag.
812                  * (PIM-SM-spec-10.ps pp. 11, 2.10, last sentence of first
813                  * paragraph.
814                  */
815                 /* TODO: XXX: check again! */
816
817                 mrtentry_ptr->flags &= ~MRTF_SPT;
818                 mrtentry_ptr->flags |= MRTF_RP;
819             }
820         }
821         /*
822          * TODO: XXX: if this is (S,G)RPbit entry and the oifs==(*,G)oifs,
823          * then delete the (S,G) entry?? The same if we have (*,*,RP) ?
824          */
825         if (delete_mrtentry_flag == TRUE)
826         {
827             /* TODO: XXX: the oifs are NULL. Send a Prune message ? */
828         }
829         /* TODO: XXX: have the feeling something is missing.... */
830         return (return_value);  /* (S,G) */
831     }
832     return (return_value);
833 }
834
835
836 /*
837  * TODO: implement it. Required to allow changing of the physical interfaces
838  * configuration without need to restart pimd.
839  */
840 int
841 delete_vif_from_mrt(vifi)
842     vifi_t          vifi;
843 {
844     return TRUE;
845 }
846
847
848 void 
849 process_kernel_call()
850 {
851     register struct mrt6msg *im;        /* igmpmsg control struct */
852
853     im = (struct mrt6msg *) mld6_recv_buf;
854
855     switch (im->im6_msgtype)
856     {
857     case MRT6MSG_NOCACHE:
858         process_cache_miss(im);
859         break;
860     case MRT6MSG_WRONGMIF:
861         process_wrong_iif(im);
862         break;
863     case MRT6MSG_WHOLEPKT:
864         process_whole_pkt(mld6_recv_buf);
865         break;
866     default:
867         IF_DEBUG(DEBUG_KERN)
868             log(LOG_DEBUG, 0, "Unknown kernel_call code");
869         break;
870     }
871 }
872
873
874 /*
875  * TODO: when cache miss, check the iif, because probably ASSERTS shoult take
876  * place
877  */
878
879 static void
880 process_cache_miss(im)
881     struct mrt6msg *im;
882 {
883     static struct sockaddr_in6 source = {sizeof(source) , AF_INET6 };
884     static struct sockaddr_in6 mfc_source = {sizeof(source) , AF_INET6 };
885     static struct sockaddr_in6 group = {sizeof(group) , AF_INET6 };
886
887     static struct sockaddr_in6 rp_addr = {sizeof(source) , AF_INET6 };
888     vifi_t          iif;
889     mrtentry_t     *mrtentry_ptr;
890     mrtentry_t     *mrtentry_rp;
891
892     /*
893      * When there is a cache miss, we check only the header of the packet
894      * (and only it should be sent up by the kernel.)
895      */
896     group.sin6_addr = im->im6_dst;
897     group.sin6_scope_id = inet6_uvif2scopeid(&group, &uvifs[im->im6_mif]);
898     source.sin6_addr = mfc_source.sin6_addr = im->im6_src;
899     source.sin6_scope_id = inet6_uvif2scopeid(&source, &uvifs[im->im6_mif]);
900     iif = im->im6_mif;
901
902     uvifs[iif].uv_cache_miss++;
903     IF_DEBUG(DEBUG_MFC)
904         log(LOG_DEBUG, 0, "Cache miss, src %s, dst %s, iif %d",
905             inet6_fmt(&source.sin6_addr), inet6_fmt(&group.sin6_addr), iif);
906
907     /*
908      * TODO: XXX: check whether the kernel generates cache miss for the LAN
909      * scoped addresses
910      */
911
912     /* Don't create routing entries for the LAN scoped addresses */
913
914     if (IN6_IS_ADDR_MC_NODELOCAL(&group.sin6_addr) ||/* sanity? */
915         IN6_IS_ADDR_MC_LINKLOCAL(&group.sin6_addr))
916             goto fail;
917
918     /* TODO: check if correct in case the source is one of my addresses */
919     /*
920      * If I am the DR for this source, create (S,G) and add the register_vif
921      * to the oifs.
922      */
923     if ((uvifs[iif].uv_flags & VIFF_DR)
924         && (find_vif_direct_local(&source) == iif))
925     {
926         mrtentry_ptr = find_route(&source, &group, MRTF_SG, CREATE);
927         if (mrtentry_ptr == (mrtentry_t *) NULL)
928         {
929             goto fail;
930         }
931
932         mrtentry_ptr->flags &= ~MRTF_NEW;
933
934         /* set reg_vif_num as outgoing interface ONLY if I am not the RP */
935
936         if (!inet6_equal(&mrtentry_ptr->group->rpaddr, &my_cand_rp_address))
937             IF_SET(reg_vif_num, &mrtentry_ptr->joined_oifs);
938         change_interfaces(mrtentry_ptr,
939                           mrtentry_ptr->incoming,
940                           &mrtentry_ptr->joined_oifs,
941                           &mrtentry_ptr->pruned_oifs,
942                           &mrtentry_ptr->leaves,
943                           &mrtentry_ptr->asserted_oifs, 0);
944     }
945     else
946     {
947         mrtentry_ptr = find_route(&source, &group,
948                                   MRTF_SG | MRTF_WC | MRTF_PMBR,
949                                   DONT_CREATE);
950         if (mrtentry_ptr == (mrtentry_t *) NULL)
951                 goto fail;
952     }
953
954     /*
955      * TODO: if there are too many cache miss for the same (S,G), install
956      * negative cache entry in the kernel (oif==NULL) to prevent too many
957      * upcalls.
958      */
959     if (mrtentry_ptr->incoming == iif)
960     {
961         if (!IF_ISEMPTY(&mrtentry_ptr->oifs))
962         {
963             if (mrtentry_ptr->flags & MRTF_SG)
964             {
965                 /* TODO: check that the RPbit is not set? */
966                 /* TODO: XXX: TIMER implem. dependency! */
967
968                 if (mrtentry_ptr->timer < pim_data_timeout)
969                     SET_TIMER(mrtentry_ptr->timer, pim_data_timeout);
970                 if (!(mrtentry_ptr->flags & MRTF_SPT))
971                 {
972                     if ((mrtentry_rp = mrtentry_ptr->group->grp_route) ==
973                         (mrtentry_t *) NULL)
974                         mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
975                     if (mrtentry_rp != (mrtentry_t *) NULL)
976                     {
977                         /*
978                          * Check if the (S,G) iif is different from the (*,G)
979                          * or (*,*,RP) iif
980                          */
981                         if ((mrtentry_ptr->incoming != mrtentry_rp->incoming)
982                         || (mrtentry_ptr->upstream != mrtentry_rp->upstream))
983                         {
984                             mrtentry_ptr->flags |= MRTF_SPT;
985                             mrtentry_ptr->flags &= ~MRTF_RP;
986                         }
987                     }
988                 }
989             }
990             if (mrtentry_ptr->flags & MRTF_PMBR)
991                 rp_addr = mrtentry_ptr->source->address;
992             else
993                 rp_addr = mrtentry_ptr->group->rpaddr;
994             mfc_source = source;
995 // TODO 
996 #ifdef KERNEL_MFC_WC_G
997             if (mrtentry_ptr->flags & (MRTF_WC | MRTF_PMBR))
998                 if (!(mrtentry_ptr->flags & MRTF_MFC_CLONE_SG))
999                     mfc_source = IN6ADDR_ANY_N;
1000 #endif                          /* KERNEL_MFC_WC_G */
1001
1002             add_kernel_cache(mrtentry_ptr, &mfc_source, &group, MFC_MOVE_FORCE);
1003             k_chg_mfc(mld6_socket, &mfc_source, &group, iif, &mrtentry_ptr->oifs,
1004                       &rp_addr);
1005             /*
1006              * TODO: XXX: No need for RSRR message, because nothing has
1007              * changed.
1008              */
1009         }
1010         return;                 /* iif match */
1011     }
1012
1013     /* The iif doesn't match */
1014     if (mrtentry_ptr->flags & MRTF_SG)
1015     {
1016         if (mrtentry_ptr->flags & MRTF_SPT)
1017             /* Arrived on wrong interface */
1018                 goto fail;
1019         if ((mrtentry_rp = mrtentry_ptr->group->grp_route) ==
1020             (mrtentry_t *) NULL)
1021             mrtentry_rp =
1022                 mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
1023         if (mrtentry_rp != (mrtentry_t *) NULL)
1024         {
1025             if (mrtentry_rp->incoming == iif)
1026             {
1027                 /* Forward on (*,G) or (*,*,RP) */
1028
1029 #ifdef KERNEL_MFC_WC_G
1030                 if (!(mrtentry_rp->flags & MRTF_MFC_CLONE_SG))
1031                     mfc_source = IN6ADDR_ANY_N;
1032 #endif                          /* KERNEL_MFC_WC_G */
1033
1034                 add_kernel_cache(mrtentry_rp, &mfc_source, &group, 0);
1035                 k_chg_mfc(mld6_socket, &mfc_source, &group, iif,
1036                           &mrtentry_rp->oifs, &mrtentry_ptr->group->rpaddr);
1037 #ifdef RSRR
1038                 rsrr_cache_send(mrtentry_rp, RSRR_NOTIFICATION_OK);
1039 #endif                          /* RSRR */
1040
1041                 return;
1042             }
1043         }
1044         goto fail;
1045     }
1046
1047   fail:
1048     uvifs[iif].uv_cache_notcreated++;
1049 }
1050
1051
1052 /*
1053  * A multicast packet has been received on wrong iif by the kernel. Check for
1054  * a matching entry. If there is (S,G) with reset SPTbit and the packet was
1055  * received on the iif toward the source, this completes the switch to the
1056  * shortest path and triggers (S,G) prune toward the RP (unless I am the RP).
1057  * Otherwise, if the packet's iif is in the oiflist of the routing entry,
1058  * trigger an Assert.
1059  */
1060
1061 static void
1062 process_wrong_iif(im)
1063     struct mrt6msg *im;
1064 {
1065     static struct sockaddr_in6 source= {sizeof(source) , AF_INET6};
1066     static struct sockaddr_in6 group = {sizeof(group) , AF_INET6};
1067     vifi_t          iif;
1068     mrtentry_t     *mrtentry_ptr;
1069
1070     group.sin6_addr = im->im6_dst;
1071     source.sin6_addr = im->im6_src;
1072     iif = im->im6_mif;
1073
1074
1075     /* Don't create routing entries for the LAN scoped addresses */
1076     if (IN6_IS_ADDR_MC_NODELOCAL(&group.sin6_addr) ||/* sanity? */
1077     IN6_IS_ADDR_MC_LINKLOCAL(&group.sin6_addr))
1078     return;
1079
1080
1081     /*
1082      * Ignore if it comes on register vif. register vif is neither SPT iif,
1083      * neither is used to send asserts out.
1084      */
1085     if (uvifs[iif].uv_flags & MIFF_REGISTER)
1086         return;
1087
1088     mrtentry_ptr = find_route(&source, &group, MRTF_SG | MRTF_WC | MRTF_PMBR,
1089                               DONT_CREATE);
1090     if (mrtentry_ptr == (mrtentry_t *)NULL)
1091             return;
1092
1093     /*
1094      * TODO: check again!
1095      */
1096     if (mrtentry_ptr->flags & MRTF_SG)
1097     {
1098         if (!(mrtentry_ptr->flags & MRTF_SPT))
1099         {
1100             if (mrtentry_ptr->source->incoming == iif)
1101             {
1102                 /* Switch to the Shortest Path */
1103                 mrtentry_ptr->flags |= MRTF_SPT;
1104                 mrtentry_ptr->flags &= ~MRTF_RP;
1105                 add_kernel_cache(mrtentry_ptr, &source, &group, MFC_MOVE_FORCE);
1106                 k_chg_mfc(mld6_socket, &source, &group, iif,
1107                           &mrtentry_ptr->oifs, &mrtentry_ptr->group->rpaddr);
1108                 FIRE_TIMER(mrtentry_ptr->jp_timer);
1109 #ifdef RSRR
1110                 rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
1111 #endif                          /* RSRR */
1112                 return;
1113             }
1114         }
1115     }
1116
1117     /* Trigger an Assert */
1118     if (IF_ISSET(iif, &mrtentry_ptr->oifs))
1119         send_pim6_assert(&source, &group, iif, mrtentry_ptr);
1120 }
1121
1122 /*
1123  * Receives whole packets from the register vif entries in the kernel, and
1124  * calls the send_pim_register procedure to encapsulate the packets and
1125  * unicasts them to the RP.
1126  */
1127 static void
1128 process_whole_pkt(buf)
1129     char *buf;
1130 {
1131
1132    send_pim6_register((char *) (buf + sizeof(struct mrt6msg)));
1133
1134 }
1135
1136
1137 mrtentry_t     *
1138 switch_shortest_path(source, group)
1139     struct sockaddr_in6         *source;
1140     struct sockaddr_in6         *group;
1141 {
1142     mrtentry_t     *mrtentry_ptr;
1143
1144     /* TODO: XXX: prepare and send immediately the (S,G) join? */
1145     if ((mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE)) !=
1146         (mrtentry_t *) NULL)
1147     {
1148         if (mrtentry_ptr->flags & MRTF_NEW)
1149         {
1150             mrtentry_ptr->flags &= ~MRTF_NEW;
1151         }
1152         else
1153         {
1154             if (mrtentry_ptr->flags & MRTF_RP)
1155             {
1156                 /*
1157                  * (S,G)RPbit with iif toward RP. Reset to (S,G) with iif
1158                  * toward S. Delete the kernel cache (if any), because
1159                  * change_interfaces() will reset it with iif toward S and no
1160                  * data will arrive from RP before the switch really occurs.
1161                  */
1162                 mrtentry_ptr->flags &= ~MRTF_RP;
1163                 mrtentry_ptr->incoming = mrtentry_ptr->source->incoming;
1164                 mrtentry_ptr->upstream = mrtentry_ptr->source->upstream;
1165                 delete_mrtentry_all_kernel_cache(mrtentry_ptr);
1166                 change_interfaces(mrtentry_ptr,
1167                                   mrtentry_ptr->incoming,
1168                                   &mrtentry_ptr->joined_oifs,
1169                                   &mrtentry_ptr->pruned_oifs,
1170                                   &mrtentry_ptr->leaves,
1171                                   &mrtentry_ptr->asserted_oifs, 0);
1172             }
1173         }
1174
1175         SET_TIMER(mrtentry_ptr->timer, pim_data_timeout);
1176         FIRE_TIMER(mrtentry_ptr->jp_timer);
1177     }
1178     return (mrtentry_ptr);
1179 }