2 * Copyright (c) 1998 by the University of Southern California.
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.
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
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.
30 * Other copyrights might apply to parts of this software and are so
31 * noted when applicable.
34 * Questions concerning this software should be directed to
35 * Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
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".
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".
50 * Part of this program has been derived from mrouted.
51 * The mrouted program is covered by the license in the accompanying file
52 * named "LICENSE.mrouted".
54 * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
55 * Leland Stanford Junior University.
60 #include <sys/ioctl.h>
73 #include "mld6_proto.h"
74 #include "pim6_proto.h"
79 struct uvif uvifs[MAXMIFS]; /*the list of virtualsinterfaces */
80 vifi_t numvifs; /*total number of interface */
82 vifi_t reg_vif_num; /*register interface*/
83 int phys_vif; /* An enabled vif that has a global address */
89 int init_reg_vif __P((void));
90 void start_all_vifs __P((void));
91 void start_vif __P((vifi_t vifi));
92 void stop_vif __P((vifi_t vivi));
93 int update_reg_vif __P((vifi_t register_vifi));
95 extern int cfparse __P((int, int));
104 reg_vif_num = NO_VIF;
107 * Configure the vifs based on the interface configuration of
108 * the kernel and the contents of the configuration file.
109 * (Open a UDP socket for ioctl use in the config procedures if
110 * the kernel can't handle IOCTL's on the MLD socket.)
112 #ifdef IOCTL_OK_ON_RAW_SOCKET
113 udp_socket = mld6_socket;
115 if ((udp_socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
116 log(LOG_ERR, errno, "UDP6 socket");
119 /* clean all the interfaces ... */
121 for(vifi = 0,v=uvifs; vifi < MAXVIFS; ++ vifi, ++v)
123 memset(v,0,sizeof(*v)); /* everything is zeroed => NULL , pointer NULL , addrANY ...) */
124 v->uv_metric = DEFAULT_METRIC;
125 v->uv_rate_limit = DEFAULT_PHY_RATE_LIMIT;
126 strncpy(v->uv_name,"",IFNAMSIZ);
127 v->uv_local_pref = default_source_preference;
128 v->uv_local_metric = default_source_metric;
131 log(LOG_DEBUG,0,"Interfaces world initialized...");
133 log(LOG_DEBUG,0,"Getting vifs from kernel");
134 config_vifs_from_kernel();
135 if (max_global_address() == NULL)
136 log(LOG_ERR, 0, "There's no global address");
138 log(LOG_DEBUG,0,"Getting vifs from %s",configfilename);
140 /* read config from file */
141 if (cfparse(1, 0) != 0)
142 log(LOG_ERR, 0, "fatal error in parsing the config file");
147 for( vifi = 0, v = uvifs ; vifi < numvifs ; ++ vifi,++v)
149 if(v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
151 if(v->uv_linklocal == NULL)
152 log(LOG_ERR,0,"there is no link-local address on vif %s",v->uv_name);
153 if (phys_vif == -1) {
157 * If this vif has a global address, set its id
160 for(p = v->uv_addrs; p; p = p->pa_next) {
161 if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
162 !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr)) {
170 if (enabled_vifs < 2)
171 log(LOG_ERR,0,"can't forward: %s",
172 enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif" );
174 memset(&if_nullset,0,sizeof(if_nullset));
175 k_init_pim(mld6_socket);
176 IF_DEBUG(DEBUG_PIM_DETAIL)
177 log(LOG_DEBUG,0,"Pim kernel initialization done");
180 /* Add a dummy virtual interface to support Registers in the kernel. */
192 if (( numvifs+1 ) == MAXVIFS )
194 /* Exit the program! The PIM router must have a Register vif */
196 "cannot install the Register vif: too many interfaces");
197 /* To make lint happy */
202 * So far in PIM we need only one register vif and we save its number in
203 * the global reg_vif_num.
207 reg_vif_num = numvifs;
209 /* Use the address of the first available physical interface to
210 * create the register vif.
213 for(i =0 ; i < numvifs ; i++)
215 if(uvifs[i].uv_flags & (VIFF_DOWN | VIFF_DISABLED | MIFF_REGISTER))
222 log(LOG_ERR, 0, "No physical interface enabled");
227 memcpy(v,&uvifs[i],sizeof(*v));
228 strncpy(v->uv_name,"register_mif0",IFNAMSIZ);
229 v->uv_flags = MIFF_REGISTER;
231 #ifdef PIM_EXPERIMENTAL
232 v->uv_flags |= MIFF_REGISTER_KERNEL_ENCAP;
236 log(LOG_DEBUG,0,"Interface %s (subnet %s) ,installed on vif #%u - rate = %d",
237 v->uv_name,net6name(&v->uv_prefix.sin6_addr,&v->uv_subnetmask),
238 reg_vif_num,v->uv_rate_limit);
245 void start_all_vifs()
252 /* Start first the NON-REGISTER vifs */
254 for(action=0; ;action = MIFF_REGISTER )
256 for(vifi= 0,v = uvifs;vifi < numvifs ; ++vifi, ++v)
258 if (( v->uv_flags & MIFF_REGISTER ) ^ action )
259 /* If starting non-registers but the vif is a register
260 * or if starting registers, but the interface is not
261 * a register, then just continue.
265 if ( v->uv_flags & (VIFF_DISABLED | VIFF_DOWN ))
269 if ( v-> uv_flags & VIFF_DISABLED)
270 log(LOG_DEBUG,0,"%s is DISABLED ; vif #%u out of service",v->uv_name,vifi);
272 log(LOG_DEBUG,0,"%s is DOWN ; vif #%u out of service",v->uv_name,vifi);
278 if ( action == MIFF_REGISTER)
284 * Initialize the vif and add to the kernel. The vif can be either
285 * physical, register or tunnel (tunnels will be used in the future
286 * when this code becomes PIM multicast boarder router.
290 void start_vif (vifi_t vifi)
296 /* Initialy no router on any vif */
298 if( v-> uv_flags & MIFF_REGISTER)
299 v->uv_flags = v->uv_flags & ~VIFF_DOWN;
302 v->uv_flags = (v->uv_flags | VIFF_DR | VIFF_NONBRS) & ~ VIFF_DOWN;
303 v->uv_pim_hello_timer = 1 + RANDOM() % pim_hello_period;
304 v->uv_jp_timer = 1 + RANDOM() % pim_join_prune_period;
307 /* Tell kernel to add, i.e. start this vif */
309 k_add_vif(mld6_socket,vifi,&uvifs[vifi]);
311 log(LOG_DEBUG,0,"%s comes up ,vif #%u now in service",v->uv_name,vifi);
313 if (!(v->uv_flags & MIFF_REGISTER)) {
315 * Join the PIM multicast group on the interface.
317 k_join(mld6_socket, &allpim6routers_group.sin6_addr,
321 * Join the ALL-ROUTERS multicast group on the interface.
322 * This allows mtrace requests to loop back if they are run
323 * on the multicast router.this allow receiving mld6 messages too.
325 k_join(mld6_socket, &allrouters_group.sin6_addr, v->uv_ifindex);
328 * Until neighbors are discovered, assume responsibility for sending
329 * periodic group membership queries to the subnet. Send the first
332 v->uv_flags |= VIFF_QUERIER;
333 if (!v->uv_querier) {
334 v->uv_querier = (struct listaddr *)malloc(sizeof(struct listaddr));
335 memset(v->uv_querier, 0, sizeof(struct listaddr));
337 v->uv_querier->al_addr = v->uv_linklocal->pa_addr;
338 v->uv_querier->al_timer = MLD6_OTHER_QUERIER_PRESENT_INTERVAL;
339 time(&v->uv_querier->al_ctime); /* reset timestamp */
343 * Send a probe via the new vif to look for neighbors.
345 send_pim6_hello(v, pim_hello_holdtime);
350 * Stop a vif (either physical interface, tunnel or
351 * register.) If we are running only PIM we don't have tunnels.
355 void stop_vif( vifi_t vifi )
359 register pim_nbr_entry_t *n;
360 register pim_nbr_entry_t *next;
365 * TODO: make sure that the kernel viftable is
366 * consistent with the daemon table
370 if( !( v->uv_flags&MIFF_REGISTER ) )
372 k_leave( mld6_socket , &allpim6routers_group.sin6_addr , v->uv_ifindex );
373 k_leave( mld6_socket , &allrouters_group.sin6_addr , v->uv_ifindex );
375 * Discard all group addresses. (No need to tell kernel;
376 * the k_del_vif() call will clean up kernel state.)
379 while( v->uv_groups!=NULL )
382 v->uv_groups=a->al_next;
388 * TODO: inform (eventually) the neighbors I am going down by sending
389 * PIM_HELLO with holdtime=0 so someone else should become a DR.
391 /* TODO: dummy! Implement it!! Any problems if don't use it? */
392 delete_vif_from_mrt(vifi);
395 * Delete the interface from the kernel's vif structure.
398 k_del_vif( mld6_socket , vifi );
399 v->uv_flags=(v->uv_flags & ~VIFF_DR & ~VIFF_QUERIER & ~VIFF_NONBRS) | VIFF_DOWN;
400 if( !(v->uv_flags & MIFF_REGISTER ))
402 RESET_TIMER(v->uv_pim_hello_timer);
403 RESET_TIMER(v->uv_jp_timer);
404 RESET_TIMER(v->uv_gq_timer);
406 for( n=v->uv_pim_neighbors ; n!=NULL ; n = next )
408 next=n->next; /* Free the space for each neighbour */
411 v->uv_pim_neighbors=NULL;
415 /* TODO: currently not used */
416 /* The Access Control List (list with the scoped addresses) */
418 while( v->uv_acl!=NULL )
421 v->uv_acl=acl->acl_next;
428 log( LOG_DEBUG ,0,"%s goes down , vif #%u out of service" , v->uv_name , vifi);
432 * Update the register vif in the multicast routing daemon and the
433 * kernel because the interface used initially to get its local address
434 * is DOWN. register_vifi is the index to the Register vif which needs
435 * to be updated. As a result the Register vif has a new uv_lcl_addr and
436 * is UP (virtually :))
439 update_reg_vif( vifi_t register_vifi )
441 register struct uvif *v;
442 register vifi_t vifi;
444 /* Find the first useable vif with solid physical background */
445 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
446 if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL
449 /* Found. Stop the bogus Register vif first */
450 stop_vif(register_vifi);
451 uvifs[register_vifi].uv_linklocal->pa_addr =
452 uvifs[vifi].uv_linklocal->pa_addr;
453 start_vif(register_vifi);
454 IF_DEBUG(DEBUG_PIM_REGISTER | DEBUG_IF)
455 log(LOG_NOTICE, 0, "%s has come up; vif #%u now in service",
456 uvifs[register_vifi].uv_name, register_vifi);
460 log(LOG_WARNING, 0, "Cannot start Register vif: %s",
461 uvifs[vifi].uv_name);
466 * return the max global Ipv6 address of an UP and ENABLED interface
467 * other than the MIFF_REGISTER interface.
469 struct sockaddr_in6 *
475 struct phaddr *pmax = NULL;
477 for(vifi=0,v=uvifs;vifi< numvifs;++vifi,++v)
479 if(v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
482 * take first the max global address of the interface
483 * (without link local) => aliasing
485 for(p=v->uv_addrs;p!=NULL;p=p->pa_next)
488 * If this is the first global address, take it anyway.
491 if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
492 !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
496 if (inet6_lessthan(&pmax->pa_addr,
498 !IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
499 !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
505 return(pmax ? &pmax->pa_addr : NULL);
508 struct sockaddr_in6 *
512 struct uvif *v = &uvifs[vifi];
515 for (p = v->uv_addrs; p; p = p->pa_next) {
516 if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr) &&
517 !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr))
525 * Check if the interface exists in the mif table. If true
526 * return the highest address of the interface else return NULL.
528 struct sockaddr_in6 *
529 local_iface(char *ifname)
531 register struct uvif *v;
534 struct phaddr *pmax = NULL;
536 for(vifi=0,v=uvifs;vifi<numvifs;++vifi,++v)
538 if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
540 if(EQUAL(v->uv_name, ifname))
542 for(p=v->uv_addrs; p!=NULL; p=p->pa_next)
544 if (!IN6_IS_ADDR_LINKLOCAL(&p->pa_addr.sin6_addr)&&
545 !IN6_IS_ADDR_SITELOCAL(&p->pa_addr.sin6_addr)) {
547 * If this is the first global address
548 * or larger than the current MAX global
549 * address, remember it.
552 inet6_lessthan(&pmax->pa_addr,
558 return(&pmax->pa_addr);
566 * See if any interfaces have changed from up state to down, or vice versa,
567 * including any non-multicast-capable interfaces that are in use as local
568 * tunnel end-points. Ignore interfaces that have been administratively
574 register vifi_t vifi;
575 register struct uvif *v;
577 static int checking_vifs=0;
580 * XXX: TODO: True only for DVMRP?? Check.
581 * If we get an error while checking, (e.g. two interfaces go down
582 * at once, and we decide to send a prune out one of the failed ones)
583 * then don't go into an infinite loop!
591 /* TODO: Check all potential interfaces!!! */
592 /* Check the physical and tunnels only */
593 for( vifi=0 , v=uvifs ; vifi<numvifs ; ++vifi , ++v )
595 if( v->uv_flags & ( VIFF_DISABLED|MIFF_REGISTER ) )
598 strncpy( ifr.ifr_name , v->uv_name , IFNAMSIZ );
600 /* get the interface flags */
601 if( ioctl( udp_socket , SIOCGIFFLAGS , (char *)&ifr )<0 )
603 "check_vif_state: ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
605 if( v->uv_flags & VIFF_DOWN )
607 if ( ifr.ifr_flags & IFF_UP )
616 if( !( ifr.ifr_flags & IFF_UP ))
619 "%s has gone down ; vif #%u taken out of service",
627 /* Check the register(s) vif(s) */
628 for( vifi=0 , v=uvifs ; vifi<numvifs ; ++vifi , ++v )
630 register vifi_t vifi2;
631 register struct uvif *v2;
634 if( !(v->uv_flags & MIFF_REGISTER ) )
640 /* Find a physical vif with the same IP address as the
643 for( vifi2=0 , v2=uvifs ; vifi2<numvifs ; ++vifi2 , ++v2 )
645 if( v2->uv_flags & ( VIFF_DISABLED|VIFF_DOWN|VIFF_TUNNEL|MIFF_REGISTER ))
647 if( IN6_ARE_ADDR_EQUAL( &v->uv_linklocal->pa_addr.sin6_addr,
648 &v2->uv_linklocal->pa_addr.sin6_addr ))
655 /* The physical interface with the IP address as the Register
656 * vif is probably DOWN. Get a replacement.
658 update_reg_vif( vifi );
665 * If the source is directly connected to us, find the vif number for
666 * the corresponding physical interface (tunnels excluded).
667 * Local addresses are excluded.
668 * Return the vif number or NO_VIF if not found.
673 struct sockaddr_in6 *src;
676 register struct uvif *v;
677 register struct phaddr *p;
679 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v)
681 if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL|MIFF_REGISTER))
683 for (p = v->uv_addrs; p; p = p->pa_next)
685 if (inet6_equal(src, &p->pa_addr))
687 if (inet6_match_prefix(src, &p->pa_prefix, &p->pa_subnetmask))
696 * Checks if src is local address. If "yes" return the vif index,
697 * otherwise return value is NO_VIF.
702 struct sockaddr_in6 *src;
705 register struct uvif *v;
706 register struct phaddr *p;
708 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
709 if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | MIFF_REGISTER))
711 for (p = v->uv_addrs; p; p = p->pa_next) {
712 if (inet6_equal(src, &p->pa_addr))
716 /* Returning NO_VIF means not a local address */
722 * If the source is directly connected, or is local address,
723 * find the vif number for the corresponding physical interface
724 * (tunnels excluded).
725 * Return the vif number or NO_VIF if not found.
729 find_vif_direct_local(src)
730 struct sockaddr_in6 *src;
733 register struct uvif *v;
734 register struct phaddr *p;
737 for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
738 if (v->uv_flags & (VIFF_DISABLED | VIFF_DOWN | VIFF_TUNNEL |MIFF_REGISTER))
740 for (p = v->uv_addrs; p; p = p->pa_next) {
741 if (inet6_equal(src, &p->pa_addr) ||
742 inet6_match_prefix(src, &p->pa_prefix, &p->pa_subnetmask))
750 vif_forwarder(if_set *p1 , if_set *p2)
754 for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
756 if (p1->ifs_bits[idx] & p2->ifs_bits[idx])
761 /* (p1 & p2) is empty. We're not the forwarder */
766 vif_and(if_set *p1 , if_set *p2, if_set *result)
772 for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
774 result->ifs_bits[idx] = p1->ifs_bits[idx] & p2->ifs_bits[idx];
781 vif_xor(if_set *p1 , if_set *p2, if_set *result)
787 for(idx=0 ; idx < sizeof(*p1)/sizeof(fd_mask) ; idx++)
789 result->ifs_bits[idx] =
790 p1->ifs_bits[idx] ^ p2->ifs_bits[idx];
804 for (vifi = 0, v=uvifs; vifi < numvifs; ++vifi, ++v) {
805 if (!(v->uv_flags & VIFF_DOWN)) {
818 for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v) {
819 if (strcasecmp(v->uv_name, ifname) == 0)