Home | History | Annotate | Line # | Download | only in mrouted
vif.c revision 1.13
      1  1.13    itojun /*	$NetBSD: vif.c,v 1.13 2003/05/16 18:10:38 itojun Exp $	*/
      2   1.5   thorpej 
      3   1.1    brezak /*
      4   1.1    brezak  * The mrouted program is covered by the license in the accompanying file
      5   1.1    brezak  * named "LICENSE".  Use of the mrouted program represents acceptance of
      6   1.1    brezak  * the terms and conditions listed in that file.
      7   1.1    brezak  *
      8   1.1    brezak  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
      9   1.1    brezak  * Leland Stanford Junior University.
     10   1.1    brezak  */
     11   1.1    brezak 
     12   1.1    brezak 
     13   1.1    brezak #include "defs.h"
     14   1.6   mycroft #include <fcntl.h>
     15   1.1    brezak 
     16   1.1    brezak /*
     17   1.1    brezak  * Exported variables.
     18   1.1    brezak  */
     19   1.6   mycroft struct uvif	uvifs[MAXVIFS];	/* array of virtual interfaces		    */
     20   1.6   mycroft vifi_t		numvifs;	/* number of vifs in use	    	    */
     21   1.6   mycroft int		vifs_down;	/* 1=>some interfaces are down	    	    */
     22   1.6   mycroft int		phys_vif;	/* An enabled vif		    	    */
     23   1.1    brezak int		udp_socket;	/* Since the honkin' kernel doesn't support */
     24   1.1    brezak 				/* ioctls on raw IP sockets, we need a UDP  */
     25   1.1    brezak 				/* socket as well as our IGMP (raw) socket. */
     26   1.1    brezak 				/* How dumb.                                */
     27   1.4   mycroft int		vifs_with_neighbors;	/* == 1 if I am a leaf		    */
     28   1.1    brezak 
     29   1.6   mycroft typedef struct {
     30   1.6   mycroft         vifi_t  vifi;
     31   1.6   mycroft         struct listaddr *g;
     32   1.6   mycroft 	int    q_time;
     33   1.6   mycroft } cbk_t;
     34   1.6   mycroft 
     35   1.1    brezak /*
     36   1.1    brezak  * Forward declarations.
     37   1.1    brezak  */
     38  1.10       wiz static void start_vif(vifi_t vifi);
     39  1.10       wiz static void start_vif2(vifi_t vifi);
     40  1.10       wiz static void stop_vif(vifi_t vifi);
     41  1.10       wiz static void age_old_hosts(void);
     42  1.10       wiz static void send_probe_on_vif(struct uvif *v);
     43  1.13    itojun static int info_version(char *p, size_t);
     44  1.10       wiz static void DelVif(void *arg);
     45  1.10       wiz static int SetTimer(vifi_t vifi, struct listaddr *g);
     46  1.10       wiz static int DeleteTimer(int id);
     47  1.10       wiz static void SendQuery(void *arg);
     48  1.10       wiz static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire,
     49  1.10       wiz 			 int q_time);
     50   1.6   mycroft 
     51   1.1    brezak 
     52   1.1    brezak /*
     53   1.6   mycroft  * Initialize the virtual interfaces, but do not install
     54   1.6   mycroft  * them in the kernel.  Start routing on all vifs that are
     55   1.6   mycroft  * not down or disabled.
     56   1.1    brezak  */
     57   1.4   mycroft void
     58  1.10       wiz init_vifs(void)
     59   1.1    brezak {
     60   1.1    brezak     vifi_t vifi;
     61   1.1    brezak     struct uvif *v;
     62   1.1    brezak     int enabled_vifs, enabled_phyints;
     63   1.4   mycroft     extern char *configfilename;
     64   1.1    brezak 
     65   1.1    brezak     numvifs = 0;
     66   1.6   mycroft     vifs_with_neighbors = 0;
     67   1.1    brezak     vifs_down = FALSE;
     68   1.1    brezak 
     69   1.1    brezak     /*
     70   1.1    brezak      * Configure the vifs based on the interface configuration of the
     71   1.1    brezak      * the kernel and the contents of the configuration file.
     72   1.1    brezak      * (Open a UDP socket for ioctl use in the config procedures.)
     73   1.1    brezak      */
     74   1.1    brezak     if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
     75  1.12       wiz 	logit(LOG_ERR, errno, "UDP socket");
     76  1.12       wiz     logit(LOG_INFO,0,"Getting vifs from kernel interfaces");
     77   1.1    brezak     config_vifs_from_kernel();
     78  1.12       wiz     logit(LOG_INFO,0,"Getting vifs from %s",configfilename);
     79   1.1    brezak     config_vifs_from_file();
     80   1.1    brezak 
     81   1.1    brezak     /*
     82   1.1    brezak      * Quit if there are fewer than two enabled vifs.
     83   1.1    brezak      */
     84   1.1    brezak     enabled_vifs    = 0;
     85   1.1    brezak     enabled_phyints = 0;
     86   1.6   mycroft     phys_vif	    = -1;
     87   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
     88   1.1    brezak 	if (!(v->uv_flags & VIFF_DISABLED)) {
     89   1.1    brezak 	    ++enabled_vifs;
     90   1.6   mycroft 	    if (!(v->uv_flags & VIFF_TUNNEL)) {
     91   1.6   mycroft     	    	if (phys_vif == -1)
     92   1.6   mycroft     	    	    phys_vif = vifi;
     93   1.1    brezak 		++enabled_phyints;
     94   1.6   mycroft 	    }
     95   1.1    brezak 	}
     96   1.1    brezak     }
     97   1.1    brezak     if (enabled_vifs < 2)
     98  1.12       wiz 	logit(LOG_ERR, 0, "can't forward: %s",
     99   1.1    brezak 	    enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
    100   1.1    brezak 
    101   1.1    brezak     if (enabled_phyints == 0)
    102  1.12       wiz 	logit(LOG_WARNING, 0,
    103   1.1    brezak 	    "no enabled interfaces, forwarding via tunnels only");
    104   1.1    brezak 
    105  1.12       wiz     logit(LOG_INFO, 0, "Installing vifs in mrouted...");
    106   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
    107   1.1    brezak 	if (!(v->uv_flags & VIFF_DISABLED)) {
    108   1.4   mycroft 	    if (!(v->uv_flags & VIFF_DOWN)) {
    109   1.4   mycroft 		if (v->uv_flags & VIFF_TUNNEL)
    110  1.12       wiz 		    logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
    111  1.13    itojun 				inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
    112  1.13    itojun 				inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)));
    113   1.4   mycroft 		else
    114  1.12       wiz 		    logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
    115  1.13    itojun 				inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
    116   1.6   mycroft 		start_vif2(vifi);
    117  1.12       wiz 	    } else logit(LOG_INFO, 0,
    118   1.4   mycroft 		     "%s is not yet up; vif #%u not in service",
    119   1.4   mycroft 		     v->uv_name, vifi);
    120   1.1    brezak 	}
    121   1.1    brezak     }
    122   1.1    brezak }
    123   1.1    brezak 
    124   1.6   mycroft /*
    125   1.6   mycroft  * Start routing on all virtual interfaces that are not down or
    126   1.6   mycroft  * administratively disabled.
    127   1.6   mycroft  */
    128   1.6   mycroft void
    129  1.10       wiz init_installvifs(void)
    130   1.6   mycroft {
    131   1.6   mycroft     vifi_t vifi;
    132   1.6   mycroft     struct uvif *v;
    133   1.6   mycroft 
    134  1.12       wiz     logit(LOG_INFO, 0, "Installing vifs in kernel...");
    135   1.6   mycroft     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
    136   1.6   mycroft 	if (!(v->uv_flags & VIFF_DISABLED)) {
    137   1.6   mycroft 	    if (!(v->uv_flags & VIFF_DOWN)) {
    138   1.6   mycroft 		if (v->uv_flags & VIFF_TUNNEL)
    139  1.12       wiz 		    logit(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
    140  1.13    itojun 				inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
    141  1.13    itojun 				inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)));
    142   1.6   mycroft 		else
    143  1.12       wiz 		    logit(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
    144  1.13    itojun 				inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)));
    145   1.6   mycroft 		k_add_vif(vifi, &uvifs[vifi]);
    146  1.12       wiz 	    } else logit(LOG_INFO, 0,
    147   1.6   mycroft 		     "%s is not yet up; vif #%u not in service",
    148   1.6   mycroft 		     v->uv_name, vifi);
    149   1.6   mycroft 	}
    150   1.6   mycroft     }
    151   1.6   mycroft }
    152   1.1    brezak 
    153   1.1    brezak /*
    154   1.1    brezak  * See if any interfaces have changed from up state to down, or vice versa,
    155   1.1    brezak  * including any non-multicast-capable interfaces that are in use as local
    156   1.1    brezak  * tunnel end-points.  Ignore interfaces that have been administratively
    157   1.1    brezak  * disabled.
    158   1.1    brezak  */
    159   1.4   mycroft void
    160  1.10       wiz check_vif_state(void)
    161   1.1    brezak {
    162  1.10       wiz     vifi_t vifi;
    163  1.10       wiz     struct uvif *v;
    164   1.1    brezak     struct ifreq ifr;
    165   1.1    brezak 
    166   1.1    brezak     vifs_down = FALSE;
    167   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
    168   1.1    brezak 
    169   1.1    brezak 	if (v->uv_flags & VIFF_DISABLED) continue;
    170   1.1    brezak 
    171   1.1    brezak 	strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
    172   1.1    brezak 	if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
    173  1.12       wiz 	    logit(LOG_ERR, errno,
    174   1.1    brezak 		"ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
    175   1.1    brezak 
    176   1.1    brezak 	if (v->uv_flags & VIFF_DOWN) {
    177   1.1    brezak 	    if (ifr.ifr_flags & IFF_UP) {
    178   1.1    brezak 		v->uv_flags &= ~VIFF_DOWN;
    179   1.1    brezak 		start_vif(vifi);
    180  1.12       wiz 		logit(LOG_INFO, 0,
    181   1.1    brezak 		    "%s has come up; vif #%u now in service",
    182   1.1    brezak 		    v->uv_name, vifi);
    183   1.1    brezak 	    }
    184   1.1    brezak 	    else vifs_down = TRUE;
    185   1.1    brezak 	}
    186   1.1    brezak 	else {
    187   1.1    brezak 	    if (!(ifr.ifr_flags & IFF_UP)) {
    188   1.1    brezak 		stop_vif(vifi);
    189   1.1    brezak 		v->uv_flags |= VIFF_DOWN;
    190  1.12       wiz 		logit(LOG_INFO, 0,
    191   1.1    brezak 		    "%s has gone down; vif #%u taken out of service",
    192   1.1    brezak 		    v->uv_name, vifi);
    193   1.1    brezak 		vifs_down = TRUE;
    194   1.1    brezak 	    }
    195   1.1    brezak 	}
    196   1.1    brezak     }
    197   1.1    brezak }
    198   1.1    brezak 
    199   1.4   mycroft /*
    200   1.4   mycroft  * Send a probe message on vif v
    201   1.4   mycroft  */
    202   1.6   mycroft static void
    203  1.10       wiz send_probe_on_vif(struct uvif *v)
    204   1.4   mycroft {
    205  1.10       wiz     char *p;
    206  1.10       wiz     int datalen = 0;
    207   1.4   mycroft     struct listaddr *nbr;
    208   1.4   mycroft     int i;
    209   1.4   mycroft 
    210   1.4   mycroft     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
    211   1.4   mycroft 
    212   1.4   mycroft     for (i = 0; i < 4; i++)
    213   1.4   mycroft 	*p++ = ((char *)&(dvmrp_genid))[i];
    214   1.4   mycroft     datalen += 4;
    215   1.4   mycroft 
    216   1.4   mycroft     /*
    217   1.4   mycroft      * add the neighbor list on the interface to the message
    218   1.4   mycroft      */
    219   1.4   mycroft     nbr = v->uv_neighbors;
    220   1.4   mycroft 
    221   1.4   mycroft     while (nbr) {
    222   1.4   mycroft 	for (i = 0; i < 4; i++)
    223   1.4   mycroft 	    *p++ = ((char *)&nbr->al_addr)[i];
    224   1.4   mycroft 	datalen +=4;
    225   1.4   mycroft 	nbr = nbr->al_next;
    226   1.4   mycroft     }
    227   1.4   mycroft 
    228   1.4   mycroft     send_igmp(v->uv_lcl_addr,
    229   1.4   mycroft 	      (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
    230   1.4   mycroft 	      : dvmrp_group,
    231   1.4   mycroft 	      IGMP_DVMRP, DVMRP_PROBE,
    232   1.4   mycroft 	      htonl(MROUTED_LEVEL |
    233   1.4   mycroft 	      ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS)),
    234   1.4   mycroft 	      datalen);
    235   1.4   mycroft }
    236   1.1    brezak 
    237   1.1    brezak /*
    238   1.6   mycroft  * Add a vifi to the kernel and start routing on it.
    239   1.1    brezak  */
    240   1.4   mycroft static void
    241  1.10       wiz start_vif(vifi_t vifi)
    242   1.1    brezak {
    243   1.6   mycroft     /*
    244   1.6   mycroft      * Install the interface in the kernel's vif structure.
    245   1.6   mycroft      */
    246   1.6   mycroft     k_add_vif(vifi, &uvifs[vifi]);
    247   1.6   mycroft 
    248   1.6   mycroft     start_vif2(vifi);
    249   1.6   mycroft }
    250   1.6   mycroft 
    251   1.6   mycroft /*
    252   1.6   mycroft  * Add a vifi to all the user-level data structures but don't add
    253   1.6   mycroft  * it to the kernel yet.
    254   1.6   mycroft  */
    255   1.6   mycroft static void
    256  1.10       wiz start_vif2(vifi_t vifi)
    257   1.6   mycroft {
    258   1.1    brezak     struct uvif *v;
    259   1.4   mycroft     u_int32_t src;
    260   1.4   mycroft     struct phaddr *p;
    261   1.1    brezak 
    262   1.1    brezak     v   = &uvifs[vifi];
    263   1.1    brezak     src = v->uv_lcl_addr;
    264   1.1    brezak 
    265   1.1    brezak     /*
    266   1.1    brezak      * Update the existing route entries to take into account the new vif.
    267   1.1    brezak      */
    268   1.1    brezak     add_vif_to_routes(vifi);
    269   1.1    brezak 
    270   1.1    brezak     if (!(v->uv_flags & VIFF_TUNNEL)) {
    271   1.1    brezak 	/*
    272   1.1    brezak 	 * Join the DVMRP multicast group on the interface.
    273   1.1    brezak 	 * (This is not strictly necessary, since the kernel promiscuously
    274   1.1    brezak 	 * receives IGMP packets addressed to ANY IP multicast group while
    275   1.1    brezak 	 * multicast routing is enabled.  However, joining the group allows
    276   1.1    brezak 	 * this host to receive non-IGMP packets as well, such as 'pings'.)
    277   1.1    brezak 	 */
    278   1.1    brezak 	k_join(dvmrp_group, src);
    279   1.1    brezak 
    280   1.1    brezak 	/*
    281   1.4   mycroft 	 * Join the ALL-ROUTERS multicast group on the interface.
    282   1.4   mycroft 	 * This allows mtrace requests to loop back if they are run
    283   1.4   mycroft 	 * on the multicast router.
    284   1.4   mycroft 	 */
    285   1.4   mycroft 	k_join(allrtrs_group, src);
    286   1.4   mycroft 
    287   1.4   mycroft 	/*
    288   1.1    brezak 	 * Install an entry in the routing table for the subnet to which
    289   1.1    brezak 	 * the interface is connected.
    290   1.1    brezak 	 */
    291   1.1    brezak 	start_route_updates();
    292   1.1    brezak 	update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi);
    293   1.4   mycroft 	for (p = v->uv_addrs; p; p = p->pa_next) {
    294   1.4   mycroft 	    start_route_updates();
    295   1.6   mycroft 	    update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi);
    296   1.4   mycroft 	}
    297   1.1    brezak 
    298   1.1    brezak 	/*
    299   1.1    brezak 	 * Until neighbors are discovered, assume responsibility for sending
    300   1.1    brezak 	 * periodic group membership queries to the subnet.  Send the first
    301   1.1    brezak 	 * query.
    302   1.1    brezak 	 */
    303   1.1    brezak 	v->uv_flags |= VIFF_QUERIER;
    304   1.4   mycroft 	send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY,
    305   1.6   mycroft 	      (v->uv_flags & VIFF_IGMPV1) ? 0 :
    306   1.6   mycroft 	      IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
    307   1.4   mycroft 	age_old_hosts();
    308   1.1    brezak     }
    309   1.1    brezak 
    310   1.4   mycroft     v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
    311   1.4   mycroft 
    312   1.1    brezak     /*
    313   1.1    brezak      * Send a probe via the new vif to look for neighbors.
    314   1.1    brezak      */
    315   1.4   mycroft     send_probe_on_vif(v);
    316   1.1    brezak }
    317   1.1    brezak 
    318   1.1    brezak /*
    319   1.1    brezak  * Stop routing on the specified virtual interface.
    320   1.1    brezak  */
    321   1.4   mycroft static void
    322  1.10       wiz stop_vif(vifi_t vifi)
    323   1.1    brezak {
    324   1.1    brezak     struct uvif *v;
    325   1.1    brezak     struct listaddr *a;
    326   1.4   mycroft     struct phaddr *p;
    327   1.1    brezak 
    328   1.1    brezak     v = &uvifs[vifi];
    329   1.1    brezak 
    330   1.1    brezak     if (!(v->uv_flags & VIFF_TUNNEL)) {
    331   1.1    brezak 	/*
    332   1.1    brezak 	 * Depart from the DVMRP multicast group on the interface.
    333   1.1    brezak 	 */
    334   1.1    brezak 	k_leave(dvmrp_group, v->uv_lcl_addr);
    335   1.1    brezak 
    336   1.1    brezak 	/*
    337   1.4   mycroft 	 * Depart from the ALL-ROUTERS multicast group on the interface.
    338   1.4   mycroft 	 */
    339   1.4   mycroft 	k_leave(allrtrs_group, v->uv_lcl_addr);
    340   1.4   mycroft 
    341   1.4   mycroft 	/*
    342   1.1    brezak 	 * Update the entry in the routing table for the subnet to which
    343   1.1    brezak 	 * the interface is connected, to take into account the interface
    344   1.1    brezak 	 * failure.
    345   1.1    brezak 	 */
    346   1.1    brezak 	start_route_updates();
    347   1.1    brezak 	update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi);
    348   1.4   mycroft 	for (p = v->uv_addrs; p; p = p->pa_next) {
    349   1.4   mycroft 	    start_route_updates();
    350   1.6   mycroft 	    update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi);
    351   1.4   mycroft 	}
    352   1.1    brezak 
    353   1.1    brezak 	/*
    354   1.1    brezak 	 * Discard all group addresses.  (No need to tell kernel;
    355   1.1    brezak 	 * the k_del_vif() call, below, will clean up kernel state.)
    356   1.1    brezak 	 */
    357   1.1    brezak 	while (v->uv_groups != NULL) {
    358   1.1    brezak 	    a = v->uv_groups;
    359   1.1    brezak 	    v->uv_groups = a->al_next;
    360   1.1    brezak 	    free((char *)a);
    361   1.1    brezak 	}
    362   1.1    brezak 
    363   1.1    brezak 	v->uv_flags &= ~VIFF_QUERIER;
    364   1.1    brezak     }
    365   1.1    brezak 
    366   1.1    brezak     /*
    367   1.1    brezak      * Update the existing route entries to take into account the vif failure.
    368   1.1    brezak      */
    369   1.1    brezak     delete_vif_from_routes(vifi);
    370   1.1    brezak 
    371   1.1    brezak     /*
    372   1.1    brezak      * Delete the interface from the kernel's vif structure.
    373   1.1    brezak      */
    374   1.1    brezak     k_del_vif(vifi);
    375   1.1    brezak 
    376   1.1    brezak     /*
    377   1.1    brezak      * Discard all neighbor addresses.
    378   1.1    brezak      */
    379   1.4   mycroft     if (v->uv_neighbors)
    380   1.4   mycroft 	vifs_with_neighbors--;
    381   1.4   mycroft 
    382   1.1    brezak     while (v->uv_neighbors != NULL) {
    383   1.1    brezak 	a = v->uv_neighbors;
    384   1.1    brezak 	v->uv_neighbors = a->al_next;
    385   1.1    brezak 	free((char *)a);
    386   1.1    brezak     }
    387   1.1    brezak }
    388   1.1    brezak 
    389   1.1    brezak 
    390   1.1    brezak /*
    391   1.4   mycroft  * stop routing on all vifs
    392   1.4   mycroft  */
    393   1.4   mycroft void
    394  1.10       wiz stop_all_vifs(void)
    395   1.4   mycroft {
    396   1.4   mycroft     vifi_t vifi;
    397   1.4   mycroft     struct uvif *v;
    398   1.4   mycroft     struct listaddr *a;
    399   1.4   mycroft     struct vif_acl *acl;
    400   1.4   mycroft 
    401   1.4   mycroft     for (vifi = 0; vifi < numvifs; vifi++) {
    402   1.4   mycroft 	v = &uvifs[vifi];
    403   1.4   mycroft 	while (v->uv_groups != NULL) {
    404   1.4   mycroft 	    a = v->uv_groups;
    405   1.4   mycroft 	    v->uv_groups = a->al_next;
    406   1.4   mycroft 	    free((char *)a);
    407   1.4   mycroft 	}
    408   1.4   mycroft 	while (v->uv_neighbors != NULL) {
    409   1.4   mycroft 	    a = v->uv_neighbors;
    410   1.4   mycroft 	    v->uv_neighbors = a->al_next;
    411   1.4   mycroft 	    free((char *)a);
    412   1.4   mycroft 	}
    413   1.4   mycroft 	while (v->uv_acl != NULL) {
    414   1.4   mycroft 	    acl = v->uv_acl;
    415   1.4   mycroft 	    v->uv_acl = acl->acl_next;
    416   1.4   mycroft 	    free((char *)acl);
    417   1.4   mycroft 	}
    418   1.4   mycroft     }
    419   1.4   mycroft }
    420   1.4   mycroft 
    421   1.4   mycroft 
    422   1.4   mycroft /*
    423   1.1    brezak  * Find the virtual interface from which an incoming packet arrived,
    424   1.1    brezak  * based on the packet's source and destination IP addresses.
    425   1.1    brezak  */
    426   1.4   mycroft vifi_t
    427  1.10       wiz find_vif(u_int32_t src, u_int32_t dst)
    428  1.10       wiz {
    429  1.10       wiz     vifi_t vifi;
    430  1.10       wiz     struct uvif *v;
    431  1.10       wiz     struct phaddr *p;
    432   1.1    brezak 
    433   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
    434   1.1    brezak 	if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
    435   1.1    brezak 	    if (v->uv_flags & VIFF_TUNNEL) {
    436   1.1    brezak 		if (src == v->uv_rmt_addr && dst == v->uv_lcl_addr)
    437   1.1    brezak 		    return(vifi);
    438   1.1    brezak 	    }
    439   1.1    brezak 	    else {
    440   1.1    brezak 		if ((src & v->uv_subnetmask) == v->uv_subnet &&
    441   1.6   mycroft 		    ((v->uv_subnetmask == 0xffffffff) ||
    442   1.6   mycroft 		     (src != v->uv_subnetbcast)))
    443   1.1    brezak 		    return(vifi);
    444   1.4   mycroft 		for (p=v->uv_addrs; p; p=p->pa_next) {
    445   1.6   mycroft 		    if ((src & p->pa_subnetmask) == p->pa_subnet &&
    446   1.6   mycroft 			((p->pa_subnetmask == 0xffffffff) ||
    447   1.6   mycroft 			 (src != p->pa_subnetbcast)))
    448   1.4   mycroft 			return(vifi);
    449   1.4   mycroft 		}
    450   1.1    brezak 	    }
    451   1.1    brezak 	}
    452   1.1    brezak     }
    453   1.1    brezak     return (NO_VIF);
    454   1.1    brezak }
    455   1.1    brezak 
    456   1.4   mycroft static void
    457  1.10       wiz age_old_hosts(void)
    458   1.4   mycroft {
    459  1.10       wiz     vifi_t vifi;
    460  1.10       wiz     struct uvif *v;
    461  1.10       wiz     struct listaddr *g;
    462   1.6   mycroft 
    463   1.6   mycroft     /*
    464   1.6   mycroft      * Decrement the old-hosts-present timer for each
    465   1.6   mycroft      * active group on each vif.
    466   1.6   mycroft      */
    467   1.6   mycroft     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
    468   1.6   mycroft         for (g = v->uv_groups; g != NULL; g = g->al_next)
    469   1.6   mycroft 	    if (g->al_old)
    470   1.6   mycroft 		g->al_old--;
    471   1.4   mycroft }
    472   1.4   mycroft 
    473   1.1    brezak 
    474   1.1    brezak /*
    475   1.1    brezak  * Send group membership queries to all subnets for which I am querier.
    476   1.1    brezak  */
    477   1.4   mycroft void
    478  1.10       wiz query_groups(void)
    479   1.1    brezak {
    480  1.10       wiz     vifi_t vifi;
    481  1.10       wiz     struct uvif *v;
    482   1.1    brezak 
    483   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
    484   1.1    brezak 	if (v->uv_flags & VIFF_QUERIER) {
    485   1.1    brezak 	    send_igmp(v->uv_lcl_addr, allhosts_group,
    486   1.4   mycroft 		      IGMP_HOST_MEMBERSHIP_QUERY,
    487   1.6   mycroft 		      (v->uv_flags & VIFF_IGMPV1) ? 0 :
    488   1.4   mycroft 		      IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
    489   1.1    brezak 	}
    490   1.1    brezak     }
    491   1.4   mycroft     age_old_hosts();
    492   1.1    brezak }
    493   1.1    brezak 
    494   1.4   mycroft /*
    495   1.4   mycroft  * Process an incoming host membership query
    496   1.4   mycroft  */
    497   1.4   mycroft void
    498  1.10       wiz accept_membership_query(u_int32_t src, u_int32_t dst, u_int32_t group, int tmo)
    499   1.4   mycroft {
    500  1.10       wiz     vifi_t vifi;
    501  1.10       wiz     struct uvif *v;
    502   1.4   mycroft 
    503   1.4   mycroft     if ((vifi = find_vif(src, dst)) == NO_VIF ||
    504   1.4   mycroft 	(uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
    505  1.12       wiz 	logit(LOG_INFO, 0,
    506   1.4   mycroft 	    "ignoring group membership query from non-adjacent host %s",
    507  1.13    itojun 	    inet_fmt(src, s1, sizeof(s1)));
    508   1.4   mycroft 	return;
    509   1.4   mycroft     }
    510   1.4   mycroft 
    511   1.4   mycroft     v = &uvifs[vifi];
    512   1.4   mycroft 
    513   1.6   mycroft     /*
    514   1.6   mycroft      * If we consider ourselves the querier for this vif, but hear a
    515   1.4   mycroft      * query from a router with a lower IP address, yield to them.
    516   1.4   mycroft      *
    517   1.4   mycroft      * This is done here as well as in the neighbor discovery in case
    518   1.4   mycroft      * there is a querier that doesn't speak DVMRP.
    519   1.6   mycroft      *
    520   1.6   mycroft      * XXX If this neighbor doesn't speak DVMRP, then we need to create
    521   1.6   mycroft      * some neighbor state for him so that we can time him out!
    522   1.4   mycroft      */
    523   1.4   mycroft     if ((v->uv_flags & VIFF_QUERIER) &&
    524   1.4   mycroft 	(ntohl(src) < ntohl(v->uv_lcl_addr))) {
    525   1.6   mycroft 	    v->uv_flags &= ~VIFF_QUERIER;
    526   1.4   mycroft 
    527   1.4   mycroft     }
    528   1.4   mycroft }
    529   1.1    brezak 
    530   1.1    brezak /*
    531   1.1    brezak  * Process an incoming group membership report.
    532   1.1    brezak  */
    533   1.4   mycroft void
    534  1.10       wiz accept_group_report(u_int32_t src, u_int32_t dst, u_int32_t group, int r_type)
    535  1.10       wiz {
    536  1.10       wiz     vifi_t vifi;
    537  1.10       wiz     struct uvif *v;
    538  1.10       wiz     struct listaddr *g;
    539   1.1    brezak 
    540   1.1    brezak     if ((vifi = find_vif(src, dst)) == NO_VIF ||
    541   1.1    brezak 	(uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
    542  1.12       wiz 	logit(LOG_INFO, 0,
    543   1.1    brezak 	    "ignoring group membership report from non-adjacent host %s",
    544  1.13    itojun 	    inet_fmt(src, s1, sizeof(s1)));
    545   1.1    brezak 	return;
    546   1.1    brezak     }
    547   1.1    brezak 
    548   1.1    brezak     v = &uvifs[vifi];
    549   1.1    brezak 
    550   1.1    brezak     /*
    551   1.1    brezak      * Look for the group in our group list; if found, reset its timer.
    552   1.1    brezak      */
    553   1.1    brezak     for (g = v->uv_groups; g != NULL; g = g->al_next) {
    554   1.1    brezak 	if (group == g->al_addr) {
    555   1.6   mycroft 	    if (r_type == IGMP_v1_HOST_MEMBERSHIP_REPORT)
    556   1.6   mycroft 		g->al_old = OLD_AGE_THRESHOLD;
    557   1.6   mycroft #ifdef SNMP
    558   1.6   mycroft 	    g->al_genid = src;
    559   1.6   mycroft #endif /* SNMP */
    560   1.4   mycroft 
    561   1.6   mycroft 	    /** delete old timers, set a timer for expiration **/
    562   1.6   mycroft 	    g->al_timer = GROUP_EXPIRE_TIME;
    563   1.4   mycroft 	    if (g->al_query)
    564   1.4   mycroft 		g->al_query = DeleteTimer(g->al_query);
    565   1.4   mycroft 	    if (g->al_timerid)
    566   1.4   mycroft 		g->al_timerid = DeleteTimer(g->al_timerid);
    567   1.4   mycroft 	    g->al_timerid = SetTimer(vifi, g);
    568   1.1    brezak 	    break;
    569   1.1    brezak 	}
    570   1.1    brezak     }
    571   1.1    brezak 
    572   1.1    brezak     /*
    573   1.4   mycroft      * If not found, add it to the list and update kernel cache.
    574   1.1    brezak      */
    575   1.1    brezak     if (g == NULL) {
    576   1.1    brezak 	g = (struct listaddr *)malloc(sizeof(struct listaddr));
    577   1.1    brezak 	if (g == NULL)
    578  1.12       wiz 	    logit(LOG_ERR, 0, "ran out of memory");    /* fatal */
    579   1.1    brezak 
    580   1.1    brezak 	g->al_addr   = group;
    581   1.6   mycroft 	if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT)
    582   1.4   mycroft 	    g->al_old = 0;
    583   1.6   mycroft 	else
    584   1.6   mycroft 	    g->al_old = OLD_AGE_THRESHOLD;
    585   1.6   mycroft #ifdef SNMP
    586   1.6   mycroft 	g->al_genid = src;
    587   1.6   mycroft #endif
    588   1.4   mycroft 
    589   1.4   mycroft 	/** set a timer for expiration **/
    590   1.4   mycroft         g->al_query = 0;
    591   1.4   mycroft 	g->al_timer  = GROUP_EXPIRE_TIME;
    592   1.4   mycroft 	time(&g->al_ctime);
    593   1.4   mycroft 	g->al_timerid = SetTimer(vifi, g);
    594   1.1    brezak 	g->al_next   = v->uv_groups;
    595   1.1    brezak 	v->uv_groups = g;
    596   1.1    brezak 
    597   1.4   mycroft 	update_lclgrp(vifi, group);
    598   1.4   mycroft     }
    599   1.4   mycroft 
    600   1.4   mycroft     /*
    601   1.4   mycroft      * Check if a graft is necessary for this group
    602   1.4   mycroft      */
    603   1.4   mycroft     chkgrp_graft(vifi, group);
    604   1.4   mycroft }
    605   1.4   mycroft 
    606   1.4   mycroft 
    607   1.4   mycroft void
    608  1.10       wiz accept_leave_message(u_int32_t src, u_int32_t dst, u_int32_t group)
    609   1.4   mycroft {
    610  1.10       wiz     vifi_t vifi;
    611  1.10       wiz     struct uvif *v;
    612  1.10       wiz     struct listaddr *g;
    613   1.4   mycroft 
    614   1.4   mycroft     if ((vifi = find_vif(src, dst)) == NO_VIF ||
    615   1.4   mycroft 	(uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
    616  1.12       wiz 	logit(LOG_INFO, 0,
    617   1.4   mycroft 	    "ignoring group leave report from non-adjacent host %s",
    618  1.13    itojun 	    inet_fmt(src, s1, sizeof(s1)));
    619   1.4   mycroft 	return;
    620   1.4   mycroft     }
    621   1.4   mycroft 
    622   1.4   mycroft     v = &uvifs[vifi];
    623   1.4   mycroft 
    624   1.6   mycroft     if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1))
    625   1.4   mycroft 	return;
    626   1.4   mycroft 
    627   1.4   mycroft     /*
    628   1.4   mycroft      * Look for the group in our group list in order to set up a short-timeout
    629   1.4   mycroft      * query.
    630   1.4   mycroft      */
    631   1.4   mycroft     for (g = v->uv_groups; g != NULL; g = g->al_next) {
    632   1.4   mycroft 	if (group == g->al_addr) {
    633  1.12       wiz 	    logit(LOG_DEBUG, 0,
    634   1.8  augustss 		"[vif.c, _accept_leave_message] %d %ld\n",
    635   1.4   mycroft 		g->al_old, g->al_query);
    636   1.4   mycroft 
    637   1.4   mycroft 	    /* Ignore the leave message if there are old hosts present */
    638   1.4   mycroft 	    if (g->al_old)
    639   1.4   mycroft 		return;
    640   1.4   mycroft 
    641   1.4   mycroft 	    /* still waiting for a reply to a query, ignore the leave */
    642   1.4   mycroft 	    if (g->al_query)
    643   1.4   mycroft 		return;
    644   1.4   mycroft 
    645   1.4   mycroft 	    /** delete old timer set a timer for expiration **/
    646   1.4   mycroft 	    if (g->al_timerid)
    647   1.4   mycroft 		g->al_timerid = DeleteTimer(g->al_timerid);
    648   1.4   mycroft 
    649   1.4   mycroft 	    /** send a group specific querry **/
    650   1.4   mycroft 	    g->al_timer = LEAVE_EXPIRE_TIME;
    651   1.4   mycroft 	    send_igmp(v->uv_lcl_addr, g->al_addr,
    652   1.4   mycroft 		      IGMP_HOST_MEMBERSHIP_QUERY,
    653   1.4   mycroft 		      LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE,
    654   1.4   mycroft 		      g->al_addr, 0);
    655   1.4   mycroft 	    g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3,
    656   1.4   mycroft 			 	LEAVE_EXPIRE_TIME / 3 * IGMP_TIMER_SCALE);
    657   1.4   mycroft 	    g->al_timerid = SetTimer(vifi, g);
    658   1.4   mycroft 	    break;
    659   1.4   mycroft 	}
    660   1.1    brezak     }
    661   1.1    brezak }
    662   1.1    brezak 
    663   1.1    brezak 
    664   1.1    brezak /*
    665   1.4   mycroft  * Send a periodic probe on all vifs.
    666   1.4   mycroft  * Useful to determine one-way interfaces.
    667   1.4   mycroft  * Detect neighbor loss faster.
    668   1.1    brezak  */
    669   1.4   mycroft void
    670  1.10       wiz probe_for_neighbors(void)
    671   1.1    brezak {
    672  1.10       wiz     vifi_t vifi;
    673  1.10       wiz     struct uvif *v;
    674   1.1    brezak 
    675   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
    676   1.4   mycroft 	if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
    677   1.4   mycroft 	    send_probe_on_vif(v);
    678   1.1    brezak 	}
    679   1.1    brezak     }
    680   1.1    brezak }
    681   1.1    brezak 
    682   1.1    brezak 
    683   1.1    brezak /*
    684   1.1    brezak  * Send a list of all of our neighbors to the requestor, `src'.
    685   1.1    brezak  */
    686   1.4   mycroft void
    687  1.10       wiz accept_neighbor_request(u_int32_t src, u_int32_t dst)
    688   1.1    brezak {
    689   1.1    brezak     vifi_t vifi;
    690   1.1    brezak     struct uvif *v;
    691   1.1    brezak     u_char *p, *ncount;
    692   1.1    brezak     struct listaddr *la;
    693   1.1    brezak     int	datalen;
    694   1.4   mycroft     u_int32_t temp_addr, us, them = src;
    695   1.1    brezak 
    696   1.1    brezak     /* Determine which of our addresses to use as the source of our response
    697   1.1    brezak      * to this query.
    698   1.1    brezak      */
    699   1.1    brezak     if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
    700   1.1    brezak 	int udp;		/* find best interface to reply on */
    701   1.1    brezak 	struct sockaddr_in addr;
    702   1.1    brezak 	int addrlen = sizeof(addr);
    703   1.1    brezak 
    704   1.9    itojun 	memset(&addr, 0, sizeof(addr));
    705   1.1    brezak 	addr.sin_family = AF_INET;
    706   1.4   mycroft #if (defined(BSD) && (BSD >= 199103))
    707   1.4   mycroft 	addr.sin_len = sizeof addr;
    708   1.4   mycroft #endif
    709   1.1    brezak 	addr.sin_addr.s_addr = dst;
    710   1.1    brezak 	addr.sin_port = htons(2000); /* any port over 1024 will do... */
    711   1.1    brezak 	if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
    712   1.1    brezak 	    || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
    713   1.1    brezak 	    || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
    714  1.12       wiz 	    logit(LOG_WARNING, errno, "Determining local address");
    715   1.1    brezak 	    close(udp);
    716   1.1    brezak 	    return;
    717   1.1    brezak 	}
    718   1.1    brezak 	close(udp);
    719   1.1    brezak 	us = addr.sin_addr.s_addr;
    720   1.1    brezak     } else			/* query sent to us alone */
    721   1.1    brezak 	us = dst;
    722   1.1    brezak 
    723   1.1    brezak #define PUT_ADDR(a)	temp_addr = ntohl(a); \
    724   1.1    brezak 			*p++ = temp_addr >> 24; \
    725   1.1    brezak 			*p++ = (temp_addr >> 16) & 0xFF; \
    726   1.1    brezak 			*p++ = (temp_addr >> 8) & 0xFF; \
    727   1.1    brezak 			*p++ = temp_addr & 0xFF;
    728   1.1    brezak 
    729   1.1    brezak     p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
    730   1.1    brezak     datalen = 0;
    731   1.1    brezak 
    732   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
    733   1.1    brezak 	if (v->uv_flags & VIFF_DISABLED)
    734   1.1    brezak 	    continue;
    735   1.1    brezak 
    736   1.1    brezak 	ncount = 0;
    737   1.1    brezak 
    738   1.1    brezak 	for (la = v->uv_neighbors; la; la = la->al_next) {
    739   1.1    brezak 
    740   1.1    brezak 	    /* Make sure that there's room for this neighbor... */
    741   1.1    brezak 	    if (datalen + (ncount == 0 ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
    742   1.1    brezak 		send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
    743   1.1    brezak 			  htonl(MROUTED_LEVEL), datalen);
    744   1.1    brezak 		p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
    745   1.1    brezak 		datalen = 0;
    746   1.1    brezak 		ncount = 0;
    747   1.1    brezak 	    }
    748   1.1    brezak 
    749   1.1    brezak 	    /* Put out the header for this neighbor list... */
    750   1.1    brezak 	    if (ncount == 0) {
    751   1.1    brezak 		PUT_ADDR(v->uv_lcl_addr);
    752   1.1    brezak 		*p++ = v->uv_metric;
    753   1.1    brezak 		*p++ = v->uv_threshold;
    754   1.1    brezak 		ncount = p;
    755   1.1    brezak 		*p++ = 0;
    756   1.1    brezak 		datalen += 4 + 3;
    757   1.1    brezak 	    }
    758   1.1    brezak 
    759   1.1    brezak 	    PUT_ADDR(la->al_addr);
    760   1.1    brezak 	    datalen += 4;
    761   1.1    brezak 	    (*ncount)++;
    762   1.1    brezak 	}
    763   1.1    brezak     }
    764   1.1    brezak 
    765   1.1    brezak     if (datalen != 0)
    766   1.1    brezak 	send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS, htonl(MROUTED_LEVEL),
    767   1.1    brezak 		  datalen);
    768   1.1    brezak }
    769   1.1    brezak 
    770   1.1    brezak /*
    771   1.1    brezak  * Send a list of all of our neighbors to the requestor, `src'.
    772   1.1    brezak  */
    773   1.4   mycroft void
    774  1.10       wiz accept_neighbor_request2(u_int32_t src, u_int32_t dst)
    775   1.1    brezak {
    776   1.1    brezak     vifi_t vifi;
    777   1.1    brezak     struct uvif *v;
    778   1.1    brezak     u_char *p, *ncount;
    779   1.1    brezak     struct listaddr *la;
    780   1.1    brezak     int	datalen;
    781   1.4   mycroft     u_int32_t us, them = src;
    782   1.1    brezak 
    783   1.1    brezak     /* Determine which of our addresses to use as the source of our response
    784   1.1    brezak      * to this query.
    785   1.1    brezak      */
    786   1.1    brezak     if (IN_MULTICAST(ntohl(dst))) { /* query sent to a multicast group */
    787   1.1    brezak 	int udp;		/* find best interface to reply on */
    788   1.1    brezak 	struct sockaddr_in addr;
    789   1.1    brezak 	int addrlen = sizeof(addr);
    790   1.1    brezak 
    791   1.9    itojun 	memset(&addr, 0, sizeof(addr));
    792   1.1    brezak 	addr.sin_family = AF_INET;
    793   1.4   mycroft #if (defined(BSD) && (BSD >= 199103))
    794   1.4   mycroft 	addr.sin_len = sizeof addr;
    795   1.4   mycroft #endif
    796   1.1    brezak 	addr.sin_addr.s_addr = dst;
    797   1.1    brezak 	addr.sin_port = htons(2000); /* any port over 1024 will do... */
    798   1.1    brezak 	if ((udp = socket(AF_INET, SOCK_DGRAM, 0)) < 0
    799   1.1    brezak 	    || connect(udp, (struct sockaddr *) &addr, sizeof(addr)) < 0
    800   1.1    brezak 	    || getsockname(udp, (struct sockaddr *) &addr, &addrlen) < 0) {
    801  1.12       wiz 	    logit(LOG_WARNING, errno, "Determining local address");
    802   1.1    brezak 	    close(udp);
    803   1.1    brezak 	    return;
    804   1.1    brezak 	}
    805   1.1    brezak 	close(udp);
    806   1.1    brezak 	us = addr.sin_addr.s_addr;
    807   1.1    brezak     } else			/* query sent to us alone */
    808   1.1    brezak 	us = dst;
    809   1.1    brezak 
    810   1.1    brezak     p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
    811   1.1    brezak     datalen = 0;
    812   1.1    brezak 
    813   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
    814  1.10       wiz 	u_short vflags = v->uv_flags;
    815  1.10       wiz 	u_char rflags = 0;
    816   1.1    brezak 	if (vflags & VIFF_TUNNEL)
    817   1.1    brezak 	    rflags |= DVMRP_NF_TUNNEL;
    818   1.3    brezak 	if (vflags & VIFF_SRCRT)
    819   1.3    brezak 	    rflags |= DVMRP_NF_SRCRT;
    820   1.1    brezak 	if (vflags & VIFF_DOWN)
    821   1.1    brezak 	    rflags |= DVMRP_NF_DOWN;
    822   1.1    brezak 	if (vflags & VIFF_DISABLED)
    823   1.1    brezak 	    rflags |= DVMRP_NF_DISABLED;
    824   1.1    brezak 	if (vflags & VIFF_QUERIER)
    825   1.1    brezak 	    rflags |= DVMRP_NF_QUERIER;
    826   1.4   mycroft 	if (vflags & VIFF_LEAF)
    827   1.4   mycroft 	    rflags |= DVMRP_NF_LEAF;
    828   1.1    brezak 	ncount = 0;
    829   1.1    brezak 	la = v->uv_neighbors;
    830   1.1    brezak 	if (la == NULL) {
    831   1.4   mycroft 	    /*
    832   1.4   mycroft 	     * include down & disabled interfaces and interfaces on
    833   1.4   mycroft 	     * leaf nets.
    834   1.4   mycroft 	     */
    835   1.4   mycroft 	    if (rflags & DVMRP_NF_TUNNEL)
    836   1.4   mycroft 		rflags |= DVMRP_NF_DOWN;
    837   1.4   mycroft 	    if (datalen > MAX_DVMRP_DATA_LEN - 12) {
    838   1.4   mycroft 		send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
    839   1.4   mycroft 			  htonl(MROUTED_LEVEL), datalen);
    840   1.4   mycroft 		p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
    841   1.4   mycroft 		datalen = 0;
    842   1.4   mycroft 	    }
    843   1.4   mycroft 	    *(u_int*)p = v->uv_lcl_addr;
    844   1.4   mycroft 	    p += 4;
    845   1.4   mycroft 	    *p++ = v->uv_metric;
    846   1.4   mycroft 	    *p++ = v->uv_threshold;
    847   1.4   mycroft 	    *p++ = rflags;
    848   1.4   mycroft 	    *p++ = 1;
    849   1.4   mycroft 	    *(u_int*)p =  v->uv_rmt_addr;
    850   1.4   mycroft 	    p += 4;
    851   1.4   mycroft 	    datalen += 12;
    852   1.1    brezak 	} else {
    853   1.1    brezak 	    for ( ; la; la = la->al_next) {
    854   1.1    brezak 		/* Make sure that there's room for this neighbor... */
    855   1.1    brezak 		if (datalen + (ncount == 0 ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
    856   1.1    brezak 		    send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
    857   1.1    brezak 			      htonl(MROUTED_LEVEL), datalen);
    858   1.1    brezak 		    p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
    859   1.1    brezak 		    datalen = 0;
    860   1.1    brezak 		    ncount = 0;
    861   1.1    brezak 		}
    862   1.1    brezak 		/* Put out the header for this neighbor list... */
    863   1.1    brezak 		if (ncount == 0) {
    864   1.1    brezak 		    *(u_int*)p = v->uv_lcl_addr;
    865   1.1    brezak 		    p += 4;
    866   1.1    brezak 		    *p++ = v->uv_metric;
    867   1.1    brezak 		    *p++ = v->uv_threshold;
    868   1.1    brezak 		    *p++ = rflags;
    869   1.1    brezak 		    ncount = p;
    870   1.1    brezak 		    *p++ = 0;
    871   1.1    brezak 		    datalen += 4 + 4;
    872   1.1    brezak 		}
    873   1.1    brezak 		*(u_int*)p = la->al_addr;
    874   1.1    brezak 		p += 4;
    875   1.1    brezak 		datalen += 4;
    876   1.1    brezak 		(*ncount)++;
    877   1.1    brezak 	    }
    878   1.1    brezak 	}
    879   1.1    brezak     }
    880   1.1    brezak     if (datalen != 0)
    881   1.1    brezak 	send_igmp(us, them, IGMP_DVMRP, DVMRP_NEIGHBORS2, htonl(MROUTED_LEVEL),
    882   1.1    brezak 		  datalen);
    883   1.1    brezak }
    884   1.1    brezak 
    885   1.6   mycroft void
    886  1.10       wiz accept_info_request(u_int32_t src, u_int32_t dst, u_char *p, int datalen)
    887   1.6   mycroft {
    888   1.6   mycroft     u_char *q;
    889   1.6   mycroft     int len;
    890   1.6   mycroft     int outlen = 0;
    891   1.6   mycroft 
    892   1.6   mycroft     q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
    893   1.6   mycroft 
    894   1.6   mycroft     /* To be general, this must deal properly with breaking up over-sized
    895   1.6   mycroft      * packets.  That implies passing a length to each function, and
    896   1.6   mycroft      * allowing each function to request to be called again.  Right now,
    897   1.6   mycroft      * we're only implementing the one thing we are positive will fit into
    898   1.6   mycroft      * a single packet, so we wimp out.
    899   1.6   mycroft      */
    900   1.6   mycroft     while (datalen > 0) {
    901   1.6   mycroft 	len = 0;
    902   1.6   mycroft 	switch (*p) {
    903   1.6   mycroft 	    case DVMRP_INFO_VERSION:
    904  1.13    itojun 		len = info_version(q,
    905  1.13    itojun 		    send_buflen - MIN_IP_HEADER_LEN - IGMP_MINLEN);
    906   1.6   mycroft 		break;
    907   1.6   mycroft 
    908   1.6   mycroft 	    case DVMRP_INFO_NEIGHBORS:
    909   1.6   mycroft 	    default:
    910  1.12       wiz 		logit(LOG_INFO, 0, "ignoring unknown info type %d", *p);
    911   1.6   mycroft 		break;
    912   1.6   mycroft 	}
    913   1.6   mycroft 	*(q+1) = len++;
    914   1.6   mycroft 	outlen += len * 4;
    915   1.6   mycroft 	q += len * 4;
    916   1.6   mycroft 	len = (*(p+1) + 1) * 4;
    917   1.6   mycroft 	p += len;
    918   1.6   mycroft 	datalen -= len;
    919   1.6   mycroft     }
    920   1.6   mycroft 
    921   1.6   mycroft     if (outlen != 0)
    922   1.6   mycroft 	send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY,
    923   1.6   mycroft 			htonl(MROUTED_LEVEL), outlen);
    924   1.6   mycroft }
    925   1.6   mycroft 
    926   1.6   mycroft /*
    927   1.6   mycroft  * Information response -- return version string
    928   1.6   mycroft  */
    929   1.6   mycroft static int
    930  1.13    itojun info_version(char *p, size_t l)
    931   1.6   mycroft {
    932   1.6   mycroft     int len;
    933   1.6   mycroft     extern char versionstring[];
    934   1.6   mycroft 
    935  1.13    itojun     if (l < 4 + strlen(versionstring) + 1)
    936  1.13    itojun        return -1;
    937  1.13    itojun     p[0] = DVMRP_INFO_VERSION;
    938  1.13    itojun     /* skip over length */
    939  1.13    itojun     p[2] = 0;	/* zero out */
    940  1.13    itojun     p[3] = 0;	/* reserved fields */
    941  1.13    itojun     strlcpy(p + 4, versionstring, l - 4);	/* XXX strncpy!!! */
    942   1.6   mycroft 
    943   1.6   mycroft     len = strlen(versionstring);
    944   1.6   mycroft     return ((len + 3) / 4);
    945   1.6   mycroft }
    946   1.1    brezak 
    947   1.1    brezak /*
    948   1.1    brezak  * Process an incoming neighbor-list message.
    949   1.1    brezak  */
    950   1.4   mycroft void
    951  1.10       wiz accept_neighbors(u_int32_t src, u_int32_t dst, u_char *p, int datalen,
    952  1.10       wiz 		 u_int32_t level)
    953   1.1    brezak {
    954  1.12       wiz     logit(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s",
    955  1.13    itojun 	inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
    956   1.1    brezak }
    957   1.1    brezak 
    958   1.4   mycroft 
    959   1.1    brezak /*
    960   1.1    brezak  * Process an incoming neighbor-list message.
    961   1.1    brezak  */
    962   1.4   mycroft void
    963  1.10       wiz accept_neighbors2(u_int32_t src, u_int32_t dst, u_char *p, int datalen,
    964  1.10       wiz 		  u_int32_t level)
    965   1.1    brezak {
    966  1.12       wiz     logit(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s",
    967  1.13    itojun 	inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
    968   1.1    brezak }
    969   1.1    brezak 
    970   1.6   mycroft /*
    971   1.6   mycroft  * Process an incoming info reply message.
    972   1.6   mycroft  */
    973   1.6   mycroft void
    974  1.10       wiz accept_info_reply(u_int32_t src, u_int32_t dst, u_char *p, int datalen)
    975   1.6   mycroft {
    976  1.12       wiz     logit(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s",
    977  1.13    itojun 	inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)));
    978   1.6   mycroft }
    979   1.6   mycroft 
    980   1.1    brezak 
    981   1.1    brezak /*
    982   1.1    brezak  * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
    983   1.1    brezak  * 'msgtype' is the type of DVMRP message received from the neighbor.
    984   1.1    brezak  * Return TRUE if 'addr' is a valid neighbor, FALSE otherwise.
    985   1.1    brezak  */
    986   1.4   mycroft int
    987  1.10       wiz update_neighbor(vifi_t vifi, u_int32_t addr, int msgtype, char *p, int datalen, u_int32_t level)
    988   1.1    brezak {
    989  1.10       wiz     struct uvif *v;
    990  1.10       wiz     struct listaddr *n;
    991   1.4   mycroft     u_int32_t genid = 0;
    992   1.4   mycroft     u_int32_t router;
    993   1.6   mycroft     u_int32_t send_tables = 0;
    994   1.6   mycroft     int do_reset = FALSE;
    995   1.4   mycroft     int nflags;
    996   1.1    brezak 
    997   1.1    brezak     v = &uvifs[vifi];
    998   1.4   mycroft     nflags = (level >> 16) & 0xff;
    999   1.1    brezak 
   1000   1.1    brezak     /*
   1001   1.1    brezak      * Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
   1002   1.1    brezak      * IT IS ASSUMED that this was preceded by a call to find_vif(), which
   1003   1.1    brezak      * checks that 'addr' is either a valid remote tunnel endpoint or a
   1004   1.1    brezak      * non-broadcast address belonging to a directly-connected subnet.
   1005   1.1    brezak      * Therefore, here we check only that 'addr' is not our own address
   1006   1.1    brezak      * (due to an impostor or erroneous loopback) or an address of the form
   1007   1.1    brezak      * {subnet,0} ("the unknown host").  These checks are not performed in
   1008   1.1    brezak      * find_vif() because those types of address are acceptable for some
   1009   1.1    brezak      * types of IGMP message (such as group membership reports).
   1010   1.1    brezak      */
   1011   1.1    brezak     if (!(v->uv_flags & VIFF_TUNNEL) &&
   1012   1.1    brezak 	(addr == v->uv_lcl_addr ||
   1013   1.1    brezak 	 addr == v->uv_subnet )) {
   1014  1.12       wiz 	logit(LOG_WARNING, 0,
   1015   1.1    brezak 	    "received DVMRP message from 'the unknown host' or self: %s",
   1016  1.13    itojun 	    inet_fmt(addr, s1, sizeof(s1)));
   1017   1.1    brezak 	return (FALSE);
   1018   1.1    brezak     }
   1019   1.1    brezak 
   1020   1.1    brezak     /*
   1021   1.6   mycroft      * Look for addr in list of neighbors.
   1022   1.6   mycroft      */
   1023   1.6   mycroft     for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
   1024   1.6   mycroft 	if (addr == n->al_addr) {
   1025   1.6   mycroft 	    break;
   1026   1.6   mycroft 	}
   1027   1.6   mycroft     }
   1028   1.6   mycroft 
   1029   1.6   mycroft     /*
   1030   1.6   mycroft      * Found it.  Reset its timer, and check for a version change
   1031   1.1    brezak      */
   1032   1.6   mycroft     if (n) {
   1033   1.6   mycroft 	n->al_timer = 0;
   1034   1.6   mycroft 
   1035   1.6   mycroft 	/*
   1036   1.6   mycroft 	 * update the neighbors version and protocol number
   1037   1.6   mycroft 	 * if changed => router went down and came up,
   1038   1.6   mycroft 	 * so take action immediately.
   1039   1.6   mycroft 	 */
   1040   1.6   mycroft 	if ((n->al_pv != (level & 0xff)) ||
   1041   1.6   mycroft 	    (n->al_mv != ((level >> 8) & 0xff))) {
   1042   1.6   mycroft 
   1043   1.6   mycroft 	    do_reset = TRUE;
   1044  1.12       wiz 	    logit(LOG_DEBUG, 0,
   1045   1.6   mycroft 		"version change neighbor %s [old:%d.%d, new:%d.%d]",
   1046  1.13    itojun 		inet_fmt(addr, s1, sizeof(s1)),
   1047   1.6   mycroft 		n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff);
   1048   1.6   mycroft 
   1049   1.6   mycroft 	    n->al_pv = level & 0xff;
   1050   1.6   mycroft 	    n->al_mv = (level >> 8) & 0xff;
   1051   1.6   mycroft 	}
   1052   1.6   mycroft     } else {
   1053   1.6   mycroft 	/*
   1054   1.6   mycroft 	 * If not found, add it to the list.  If the neighbor has a lower
   1055   1.6   mycroft 	 * IP address than me, yield querier duties to it.
   1056   1.6   mycroft 	 */
   1057  1.12       wiz 	logit(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x",
   1058  1.13    itojun 	    inet_fmt(addr, s1, sizeof(s1)), vifi,
   1059  1.13    itojun 	    level & 0xff, (level >> 8) & 0xff, (level >> 16) & 0xff);
   1060   1.6   mycroft 
   1061   1.6   mycroft 	n = (struct listaddr *)malloc(sizeof(struct listaddr));
   1062   1.6   mycroft 	if (n == NULL)
   1063  1.12       wiz 	    logit(LOG_ERR, 0, "ran out of memory");    /* fatal */
   1064   1.6   mycroft 
   1065   1.6   mycroft 	n->al_addr      = addr;
   1066   1.6   mycroft 	n->al_pv	= level & 0xff;
   1067   1.6   mycroft 	n->al_mv	= (level >> 8) & 0xff;
   1068   1.6   mycroft 	n->al_genid	= 0;
   1069   1.6   mycroft 
   1070   1.6   mycroft 	time(&n->al_ctime);
   1071   1.6   mycroft 	n->al_timer     = 0;
   1072   1.6   mycroft 	n->al_next      = v->uv_neighbors;
   1073   1.1    brezak 
   1074   1.6   mycroft 	/*
   1075   1.6   mycroft 	 * If we thought that we had no neighbors on this vif, send a route
   1076   1.6   mycroft 	 * report to the vif.  If this is just a new neighbor on the same
   1077   1.6   mycroft 	 * vif, send the route report just to the new neighbor.
   1078   1.6   mycroft 	 */
   1079   1.6   mycroft 	if (v->uv_neighbors == NULL) {
   1080   1.6   mycroft 	    send_tables = (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group;
   1081   1.6   mycroft 	    vifs_with_neighbors++;
   1082   1.6   mycroft 	} else {
   1083   1.6   mycroft 	    send_tables = addr;
   1084   1.6   mycroft 	}
   1085   1.6   mycroft 
   1086   1.6   mycroft 	v->uv_neighbors = n;
   1087   1.6   mycroft 
   1088   1.6   mycroft 	if (!(v->uv_flags & VIFF_TUNNEL) &&
   1089   1.6   mycroft 	    ntohl(addr) < ntohl(v->uv_lcl_addr))
   1090   1.6   mycroft 	    v->uv_flags &= ~VIFF_QUERIER;
   1091   1.6   mycroft     }
   1092   1.1    brezak 
   1093   1.1    brezak     /*
   1094   1.6   mycroft      * Check if the router gen-ids are the same.
   1095   1.4   mycroft      * Need to reset the prune state of the router if not.
   1096   1.6   mycroft      * Also check for one-way interfaces by seeing if we are in our
   1097   1.6   mycroft      * neighbor's list of known routers.
   1098   1.4   mycroft      */
   1099   1.4   mycroft     if (msgtype == DVMRP_PROBE) {
   1100   1.4   mycroft 
   1101   1.4   mycroft 	/* Check genid neighbor flag.  Also check version number; 3.3 and
   1102   1.4   mycroft 	 * 3.4 didn't set this flag. */
   1103   1.4   mycroft 	if ((((level >> 16) & 0xff) & NF_GENID) ||
   1104   1.4   mycroft 	    (((level & 0xff) == 3) && (((level >> 8) & 0xff) > 2))) {
   1105   1.4   mycroft 
   1106   1.4   mycroft 	    int i;
   1107   1.4   mycroft 
   1108   1.4   mycroft 	    if (datalen < 4) {
   1109  1.12       wiz 		logit(LOG_WARNING, 0,
   1110   1.4   mycroft 		    "received truncated probe message from %s (len %d)",
   1111  1.13    itojun 		    inet_fmt(addr, s1, sizeof(s1)), datalen);
   1112   1.4   mycroft 		return (FALSE);
   1113   1.4   mycroft 	    }
   1114   1.4   mycroft 
   1115   1.4   mycroft 	    for (i = 0; i < 4; i++)
   1116   1.4   mycroft 	      ((char *)&genid)[i] = *p++;
   1117   1.6   mycroft 	    datalen -= 4;
   1118   1.6   mycroft 
   1119   1.6   mycroft 	    if (n->al_genid == 0)
   1120   1.6   mycroft 		n->al_genid = genid;
   1121   1.6   mycroft 	    else if (n->al_genid != genid) {
   1122  1.12       wiz 		logit(LOG_DEBUG, 0,
   1123   1.6   mycroft 		    "new genid neigbor %s on vif %d [old:%x, new:%x]",
   1124  1.13    itojun 		    inet_fmt(addr, s1, sizeof(s1)), vifi, n->al_genid, genid);
   1125   1.6   mycroft 
   1126   1.6   mycroft 		n->al_genid = genid;
   1127   1.6   mycroft 		do_reset = TRUE;
   1128   1.6   mycroft 	    }
   1129   1.4   mycroft 
   1130   1.4   mycroft 	    /*
   1131   1.4   mycroft 	     * loop through router list and check for one-way ifs.
   1132   1.4   mycroft 	     */
   1133   1.4   mycroft 
   1134   1.6   mycroft 	    v->uv_flags |= VIFF_ONEWAY;
   1135   1.4   mycroft 
   1136   1.4   mycroft 	    while (datalen > 0) {
   1137   1.4   mycroft 		if (datalen < 4) {
   1138  1.12       wiz 		    logit(LOG_WARNING, 0,
   1139   1.4   mycroft 			"received truncated probe message from %s (len %d)",
   1140  1.13    itojun 			inet_fmt(addr, s1, sizeof(s1)), datalen);
   1141   1.4   mycroft 		    return (FALSE);
   1142   1.4   mycroft 		}
   1143   1.4   mycroft 		for (i = 0; i < 4; i++)
   1144   1.4   mycroft 		  ((char *)&router)[i] = *p++;
   1145   1.4   mycroft 		datalen -= 4;
   1146   1.4   mycroft 		if (router == v->uv_lcl_addr) {
   1147   1.6   mycroft 		    v->uv_flags &= ~VIFF_ONEWAY;
   1148   1.4   mycroft 		    break;
   1149   1.4   mycroft 		}
   1150   1.4   mycroft 	    }
   1151   1.4   mycroft 	}
   1152   1.4   mycroft     }
   1153   1.6   mycroft     if (n->al_flags != nflags) {
   1154   1.6   mycroft 	n->al_flags = nflags;
   1155   1.4   mycroft 
   1156   1.6   mycroft 	if (n->al_flags & NF_LEAF) {
   1157   1.6   mycroft 	    /*XXX If we have non-leaf neighbors then we know we shouldn't
   1158   1.6   mycroft 	     * mark this vif as a leaf.  For now we just count on other
   1159   1.6   mycroft 	     * probes and/or reports resetting the timer. */
   1160   1.6   mycroft 	    if (!v->uv_leaf_timer)
   1161   1.6   mycroft 		v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
   1162   1.6   mycroft 	} else {
   1163   1.6   mycroft 	    /* If we get a leaf to non-leaf transition, we *must* update
   1164   1.6   mycroft 	     * the routing table. */
   1165   1.6   mycroft 	    if (v->uv_flags & VIFF_LEAF && send_tables == 0)
   1166   1.6   mycroft 		send_tables = addr;
   1167   1.6   mycroft 	    v->uv_flags &= ~VIFF_LEAF;
   1168   1.6   mycroft 	    v->uv_leaf_timer = 0;
   1169   1.1    brezak 	}
   1170   1.1    brezak     }
   1171   1.6   mycroft     if (do_reset) {
   1172   1.6   mycroft 	reset_neighbor_state(vifi, addr);
   1173   1.6   mycroft 	if (!send_tables)
   1174   1.6   mycroft 	    send_tables = addr;
   1175   1.4   mycroft     }
   1176   1.6   mycroft     if (send_tables)
   1177   1.6   mycroft 	report(ALL_ROUTES, vifi, send_tables);
   1178   1.4   mycroft 
   1179   1.1    brezak     return (TRUE);
   1180   1.1    brezak }
   1181   1.1    brezak 
   1182   1.1    brezak 
   1183   1.1    brezak /*
   1184   1.1    brezak  * On every timer interrupt, advance the timer in each neighbor and
   1185   1.1    brezak  * group entry on every vif.
   1186   1.1    brezak  */
   1187   1.4   mycroft void
   1188  1.10       wiz age_vifs(void)
   1189   1.1    brezak {
   1190  1.10       wiz     vifi_t vifi;
   1191  1.10       wiz     struct uvif *v;
   1192  1.10       wiz     struct listaddr *a, *prev_a, *n;
   1193  1.10       wiz     u_int32_t addr;
   1194   1.1    brezak 
   1195   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
   1196   1.4   mycroft 	if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) {
   1197   1.4   mycroft 		v->uv_flags |= VIFF_LEAF;
   1198   1.4   mycroft 	}
   1199   1.1    brezak 
   1200   1.1    brezak 	for (prev_a = (struct listaddr *)&(v->uv_neighbors),
   1201   1.1    brezak 	     a = v->uv_neighbors;
   1202   1.1    brezak 	     a != NULL;
   1203   1.1    brezak 	     prev_a = a, a = a->al_next) {
   1204   1.1    brezak 
   1205   1.1    brezak 	    if ((a->al_timer += TIMER_INTERVAL) < NEIGHBOR_EXPIRE_TIME)
   1206   1.1    brezak 		continue;
   1207   1.1    brezak 
   1208   1.1    brezak 	    /*
   1209   1.1    brezak 	     * Neighbor has expired; delete it from the neighbor list,
   1210   1.1    brezak 	     * delete it from the 'dominants' and 'subordinates arrays of
   1211   1.1    brezak 	     * any route entries and assume querier duties unless there is
   1212   1.1    brezak 	     * another neighbor with a lower IP address than mine.
   1213   1.1    brezak 	     */
   1214   1.1    brezak 	    addr = a->al_addr;
   1215   1.1    brezak 	    prev_a->al_next = a->al_next;
   1216   1.1    brezak 	    free((char *)a);
   1217   1.1    brezak 	    a = prev_a;
   1218   1.1    brezak 
   1219   1.1    brezak 	    delete_neighbor_from_routes(addr, vifi);
   1220   1.1    brezak 
   1221   1.4   mycroft 	    if (v->uv_neighbors == NULL)
   1222   1.4   mycroft 		vifs_with_neighbors--;
   1223   1.4   mycroft 
   1224   1.4   mycroft 	    v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
   1225   1.4   mycroft 
   1226   1.1    brezak 	    if (!(v->uv_flags & VIFF_TUNNEL)) {
   1227   1.1    brezak 		v->uv_flags |= VIFF_QUERIER;
   1228   1.1    brezak 		for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
   1229   1.1    brezak 		    if (ntohl(n->al_addr) < ntohl(v->uv_lcl_addr)) {
   1230   1.1    brezak 			v->uv_flags &= ~VIFF_QUERIER;
   1231   1.4   mycroft 		    }
   1232   1.4   mycroft 		    if (!(n->al_flags & NF_LEAF)) {
   1233   1.4   mycroft 			v->uv_leaf_timer = 0;
   1234   1.1    brezak 		    }
   1235   1.1    brezak 		}
   1236   1.1    brezak 	    }
   1237   1.1    brezak 	}
   1238   1.4   mycroft     }
   1239   1.4   mycroft }
   1240   1.1    brezak 
   1241   1.4   mycroft /*
   1242   1.4   mycroft  * Returns the neighbor info struct for a given neighbor
   1243   1.4   mycroft  */
   1244   1.4   mycroft struct listaddr *
   1245  1.10       wiz neighbor_info(vifi_t vifi, u_int32_t addr)
   1246   1.4   mycroft {
   1247   1.4   mycroft     struct listaddr *u;
   1248   1.4   mycroft 
   1249   1.4   mycroft     for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
   1250   1.4   mycroft 	if (u->al_addr == addr)
   1251   1.4   mycroft 	    return u;
   1252   1.1    brezak 
   1253   1.4   mycroft     return NULL;
   1254   1.4   mycroft }
   1255   1.1    brezak 
   1256   1.4   mycroft /*
   1257   1.1    brezak  * Print the contents of the uvifs array on file 'fp'.
   1258   1.1    brezak  */
   1259   1.4   mycroft void
   1260  1.10       wiz dump_vifs(FILE *fp)
   1261   1.1    brezak {
   1262  1.10       wiz     vifi_t vifi;
   1263  1.10       wiz     struct uvif *v;
   1264  1.10       wiz     struct listaddr *a;
   1265  1.10       wiz     struct phaddr *p;
   1266   1.4   mycroft     struct sioc_vif_req v_req;
   1267   1.4   mycroft 
   1268   1.4   mycroft     fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors);
   1269   1.4   mycroft 
   1270   1.4   mycroft     if (vifs_with_neighbors == 1)
   1271   1.4   mycroft 	fprintf(fp,"[This host is a leaf]\n\n");
   1272   1.1    brezak 
   1273   1.1    brezak     fprintf(fp,
   1274   1.1    brezak     "\nVirtual Interface Table\n%s",
   1275   1.4   mycroft     "Vif  Name  Local-Address                               ");
   1276   1.4   mycroft     fprintf(fp,
   1277   1.4   mycroft     "M  Thr  Rate   Flags\n");
   1278   1.1    brezak 
   1279   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
   1280   1.1    brezak 
   1281   1.4   mycroft 	fprintf(fp, "%2u %6s  %-15s %6s: %-18s %2u %3u  %5u  ",
   1282   1.1    brezak 		vifi,
   1283   1.4   mycroft 		v->uv_name,
   1284  1.13    itojun 		inet_fmt(v->uv_lcl_addr, s1, sizeof(s1)),
   1285   1.1    brezak 		(v->uv_flags & VIFF_TUNNEL) ?
   1286   1.1    brezak 			"tunnel":
   1287   1.1    brezak 			"subnet",
   1288   1.1    brezak 		(v->uv_flags & VIFF_TUNNEL) ?
   1289  1.13    itojun 			inet_fmt(v->uv_rmt_addr, s2, sizeof(s2)) :
   1290  1.13    itojun 			inet_fmts(v->uv_subnet, v->uv_subnetmask, s3, sizeof(s3)),
   1291   1.1    brezak 		v->uv_metric,
   1292   1.4   mycroft 		v->uv_threshold,
   1293   1.4   mycroft 		v->uv_rate_limit);
   1294   1.1    brezak 
   1295   1.4   mycroft 	if (v->uv_flags & VIFF_ONEWAY)   fprintf(fp, " one-way");
   1296   1.1    brezak 	if (v->uv_flags & VIFF_DOWN)     fprintf(fp, " down");
   1297   1.1    brezak 	if (v->uv_flags & VIFF_DISABLED) fprintf(fp, " disabled");
   1298   1.1    brezak 	if (v->uv_flags & VIFF_QUERIER)  fprintf(fp, " querier");
   1299   1.3    brezak 	if (v->uv_flags & VIFF_SRCRT)    fprintf(fp, " src-rt");
   1300   1.4   mycroft 	if (v->uv_flags & VIFF_LEAF)	 fprintf(fp, " leaf");
   1301   1.6   mycroft 	if (v->uv_flags & VIFF_IGMPV1)	 fprintf(fp, " IGMPv1");
   1302   1.1    brezak 	fprintf(fp, "\n");
   1303   1.1    brezak 
   1304   1.4   mycroft 	if (v->uv_addrs != NULL) {
   1305   1.4   mycroft 	    fprintf(fp, "                alternate subnets: %s\n",
   1306  1.13    itojun 		    inet_fmts(v->uv_addrs->pa_subnet,
   1307  1.13    itojun 		    v->uv_addrs->pa_subnetmask, s1, sizeof(s1)));
   1308   1.4   mycroft 	    for (p = v->uv_addrs->pa_next; p; p = p->pa_next) {
   1309   1.4   mycroft 		fprintf(fp, "                                   %s\n",
   1310  1.13    itojun 			inet_fmts(p->pa_subnet, p->pa_subnetmask, s1,
   1311  1.13    itojun 			sizeof(s1)));
   1312   1.4   mycroft 	    }
   1313   1.4   mycroft 	}
   1314   1.4   mycroft 
   1315   1.1    brezak 	if (v->uv_neighbors != NULL) {
   1316   1.4   mycroft 	    fprintf(fp, "                            peers: %s (%d.%d) (0x%x)\n",
   1317  1.13    itojun 		    inet_fmt(v->uv_neighbors->al_addr, s1, sizeof(s1)),
   1318   1.4   mycroft 		    v->uv_neighbors->al_pv, v->uv_neighbors->al_mv,
   1319   1.4   mycroft 		    v->uv_neighbors->al_flags);
   1320   1.1    brezak 	    for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) {
   1321   1.4   mycroft 		fprintf(fp, "                                   %s (%d.%d) (0x%x)\n",
   1322  1.13    itojun 			inet_fmt(a->al_addr, s1, sizeof(s1)), a->al_pv,
   1323  1.13    itojun 			a->al_mv, a->al_flags);
   1324   1.1    brezak 	    }
   1325   1.1    brezak 	}
   1326   1.1    brezak 
   1327   1.1    brezak 	if (v->uv_groups != NULL) {
   1328   1.4   mycroft 	    fprintf(fp, "                           groups: %-15s\n",
   1329  1.13    itojun 		    inet_fmt(v->uv_groups->al_addr, s1, sizeof(s1)));
   1330   1.1    brezak 	    for (a = v->uv_groups->al_next; a != NULL; a = a->al_next) {
   1331   1.4   mycroft 		fprintf(fp, "                                   %-15s\n",
   1332  1.13    itojun 			inet_fmt(a->al_addr, s1, sizeof(s1)));
   1333   1.1    brezak 	    }
   1334   1.1    brezak 	}
   1335   1.4   mycroft 	if (v->uv_acl != NULL) {
   1336   1.4   mycroft 	    struct vif_acl *acl;
   1337   1.4   mycroft 
   1338   1.4   mycroft 	    fprintf(fp, "                       boundaries: %-18s\n",
   1339  1.13    itojun 		    inet_fmts(v->uv_acl->acl_addr, v->uv_acl->acl_mask, s1,
   1340  1.13    itojun 		    sizeof(s1)));
   1341   1.4   mycroft 	    for (acl = v->uv_acl->acl_next; acl != NULL; acl = acl->acl_next) {
   1342   1.4   mycroft 		fprintf(fp, "                                 : %-18s\n",
   1343  1.13    itojun 			inet_fmts(acl->acl_addr, acl->acl_mask, s1,
   1344  1.13    itojun 			sizeof(s1)));
   1345   1.4   mycroft 	    }
   1346   1.4   mycroft 	}
   1347   1.4   mycroft 	v_req.vifi = vifi;
   1348   1.7       hwr 	if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) {
   1349  1.12       wiz 	    logit(LOG_WARNING, 0,
   1350   1.4   mycroft 		"SIOCGETVIFCNT fails");
   1351   1.4   mycroft 	}
   1352   1.4   mycroft 	else {
   1353   1.6   mycroft 	    fprintf(fp, "                         pkts in : %ld\n",
   1354   1.4   mycroft 		    v_req.icount);
   1355   1.6   mycroft 	    fprintf(fp, "                         pkts out: %ld\n",
   1356   1.4   mycroft 		    v_req.ocount);
   1357   1.4   mycroft 	}
   1358   1.4   mycroft 	fprintf(fp, "\n");
   1359   1.1    brezak     }
   1360   1.1    brezak     fprintf(fp, "\n");
   1361   1.4   mycroft }
   1362   1.4   mycroft 
   1363   1.6   mycroft /*
   1364   1.6   mycroft  * Time out record of a group membership on a vif
   1365   1.6   mycroft  */
   1366   1.6   mycroft static void
   1367  1.10       wiz DelVif(void *arg)
   1368   1.6   mycroft {
   1369   1.6   mycroft     cbk_t *cbk = (cbk_t *)arg;
   1370   1.6   mycroft     vifi_t vifi = cbk->vifi;
   1371   1.6   mycroft     struct uvif *v = &uvifs[vifi];
   1372   1.6   mycroft     struct listaddr *a, **anp, *g = cbk->g;
   1373   1.6   mycroft 
   1374   1.6   mycroft     /*
   1375   1.6   mycroft      * Group has expired
   1376   1.6   mycroft      * delete all kernel cache entries with this group
   1377   1.6   mycroft      */
   1378   1.6   mycroft     if (g->al_query)
   1379   1.6   mycroft 	DeleteTimer(g->al_query);
   1380   1.4   mycroft 
   1381   1.6   mycroft     delete_lclgrp(vifi, g->al_addr);
   1382   1.4   mycroft 
   1383   1.6   mycroft     anp = &(v->uv_groups);
   1384   1.6   mycroft     while ((a = *anp) != NULL) {
   1385   1.6   mycroft     	if (a == g) {
   1386   1.6   mycroft 	    *anp = a->al_next;
   1387   1.6   mycroft 	    free((char *)a);
   1388   1.6   mycroft 	} else {
   1389   1.6   mycroft 	    anp = &a->al_next;
   1390   1.6   mycroft 	}
   1391   1.6   mycroft     }
   1392   1.4   mycroft 
   1393   1.6   mycroft     free(cbk);
   1394   1.6   mycroft }
   1395   1.4   mycroft 
   1396   1.6   mycroft /*
   1397   1.6   mycroft  * Set a timer to delete the record of a group membership on a vif.
   1398   1.6   mycroft  */
   1399   1.6   mycroft static int
   1400  1.10       wiz SetTimer(vifi_t vifi, struct listaddr *g)
   1401   1.4   mycroft {
   1402   1.6   mycroft     cbk_t *cbk;
   1403   1.4   mycroft 
   1404   1.6   mycroft     cbk = (cbk_t *) malloc(sizeof(cbk_t));
   1405   1.6   mycroft     cbk->g = g;
   1406   1.6   mycroft     cbk->vifi = vifi;
   1407   1.6   mycroft     return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk);
   1408   1.4   mycroft }
   1409   1.4   mycroft 
   1410   1.6   mycroft /*
   1411   1.6   mycroft  * Delete a timer that was set above.
   1412   1.6   mycroft  */
   1413   1.6   mycroft static int
   1414  1.10       wiz DeleteTimer(int id)
   1415   1.4   mycroft {
   1416   1.6   mycroft     timer_clearTimer(id);
   1417   1.6   mycroft     return 0;
   1418   1.4   mycroft }
   1419   1.4   mycroft 
   1420   1.6   mycroft /*
   1421   1.6   mycroft  * Send a group-specific query.
   1422   1.6   mycroft  */
   1423   1.6   mycroft static void
   1424  1.10       wiz SendQuery(void *arg)
   1425   1.4   mycroft {
   1426   1.6   mycroft     cbk_t *cbk = (cbk_t *)arg;
   1427  1.10       wiz     struct uvif *v = &uvifs[cbk->vifi];
   1428   1.6   mycroft 
   1429   1.6   mycroft     send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
   1430   1.6   mycroft 	      IGMP_HOST_MEMBERSHIP_QUERY,
   1431   1.6   mycroft 	      cbk->q_time, cbk->g->al_addr, 0);
   1432   1.6   mycroft     cbk->g->al_query = 0;
   1433   1.6   mycroft     free(cbk);
   1434   1.4   mycroft }
   1435   1.4   mycroft 
   1436   1.6   mycroft /*
   1437   1.6   mycroft  * Set a timer to send a group-specific query.
   1438   1.6   mycroft  */
   1439   1.6   mycroft static int
   1440  1.10       wiz SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time)
   1441   1.4   mycroft {
   1442   1.6   mycroft     cbk_t *cbk;
   1443   1.4   mycroft 
   1444   1.6   mycroft     cbk = (cbk_t *) malloc(sizeof(cbk_t));
   1445   1.6   mycroft     cbk->g = g;
   1446   1.6   mycroft     cbk->q_time = q_time;
   1447   1.6   mycroft     cbk->vifi = vifi;
   1448   1.6   mycroft     return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk);
   1449   1.1    brezak }
   1450