rtld(1): Add shared object search order to the man page
[dragonfly.git] / usr.sbin / mrouted / vif.c
1 /*
2  * The mrouted program is covered by the license in the accompanying file
3  * named "LICENSE".  Use of the mrouted program represents acceptance of
4  * the terms and conditions listed in that file.
5  *
6  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7  * Leland Stanford Junior University.
8  *
9  *
10  * vif.c,v 3.8.4.56.2.1 1999/01/20 05:18:50 fenner Exp
11  *
12  * $FreeBSD: src/usr.sbin/mrouted/vif.c,v 1.15 1999/08/28 01:17:09 peter Exp $
13  */
14
15 #include "defs.h"
16 #include <fcntl.h>
17
18 /*
19  * Exported variables.
20  */
21 struct uvif     uvifs[MAXVIFS]; /* array of virtual interfaces              */
22 vifi_t          numvifs;        /* number of vifs in use                    */
23 int             vifs_down;      /* 1=>some interfaces are down              */
24 int             phys_vif;       /* An enabled vif                           */
25 int             udp_socket;     /* Since the honkin' kernel doesn't support */
26                                 /* ioctls on raw IP sockets, we need a UDP  */
27                                 /* socket as well as our IGMP (raw) socket. */
28                                 /* How dumb.                                */
29 int             vifs_with_neighbors;    /* == 1 if I am a leaf              */
30
31 /*
32  * Private variables.
33  */
34 struct listaddr *nbrs[MAXNBRS]; /* array of neighbors                       */
35
36 typedef struct {
37         vifi_t  vifi;
38         struct listaddr *g;
39         int    q_time;
40 } cbk_t;
41
42 /*
43  * Forward declarations.
44  */
45 static void start_vif(vifi_t vifi);
46 static void start_vif2(vifi_t vifi);
47 static void stop_vif(vifi_t vifi);
48 static void age_old_hosts(void);
49 static void send_probe_on_vif(struct uvif *v);
50 static void send_query(struct uvif *v);
51 static int info_version(char *p, int plen);
52 static void DelVif(void *arg);
53 static int SetTimer(vifi_t vifi, struct listaddr *g);
54 static int DeleteTimer(int id);
55 static void SendQuery(void *arg);
56 static int SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire,
57                                         int q_time);
58
59
60 /*
61  * Initialize the virtual interfaces, but do not install
62  * them in the kernel.  Start routing on all vifs that are
63  * not down or disabled.
64  */
65 void
66 init_vifs(void)
67 {
68     vifi_t vifi;
69     struct uvif *v;
70     int enabled_vifs, enabled_phyints;
71     extern char *configfilename;
72
73     numvifs = 0;
74     vifs_with_neighbors = 0;
75     vifs_down = FALSE;
76
77     /*
78      * Configure the vifs based on the interface configuration of the
79      * the kernel and the contents of the configuration file.
80      * (Open a UDP socket for ioctl use in the config procedures if
81      * the kernel can't handle IOCTL's on the IGMP socket.)
82      */
83 #ifdef IOCTL_OK_ON_RAW_SOCKET
84     udp_socket = igmp_socket;
85 #else
86     if ((udp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
87         dolog(LOG_ERR, errno, "UDP socket");
88 #endif
89     dolog(LOG_INFO,0,"Getting vifs from kernel interfaces");
90     config_vifs_from_kernel();
91     dolog(LOG_INFO,0,"Getting vifs from %s",configfilename);
92     config_vifs_from_file();
93
94     /*
95      * Quit if there are fewer than two enabled vifs.
96      */
97     enabled_vifs    = 0;
98     enabled_phyints = 0;
99     phys_vif        = -1;
100     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
101         if (!(v->uv_flags & VIFF_DISABLED)) {
102             ++enabled_vifs;
103             if (!(v->uv_flags & VIFF_TUNNEL)) {
104                 if (phys_vif == -1)
105                     phys_vif = vifi;
106                 ++enabled_phyints;
107             }
108         }
109     }
110     if (enabled_vifs < 2)
111         dolog(LOG_ERR, 0, "can't forward: %s",
112             enabled_vifs == 0 ? "no enabled vifs" : "only one enabled vif");
113
114     if (enabled_phyints == 0)
115         dolog(LOG_WARNING, 0,
116             "no enabled interfaces, forwarding via tunnels only");
117
118     dolog(LOG_INFO, 0, "Installing vifs in mrouted...");
119     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
120         if (!(v->uv_flags & VIFF_DISABLED)) {
121             if (!(v->uv_flags & VIFF_DOWN)) {
122                 if (v->uv_flags & VIFF_TUNNEL)
123                     dolog(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
124                                 inet_fmt(v->uv_lcl_addr, s1),
125                                 inet_fmt(v->uv_rmt_addr, s2));
126                 else
127                     dolog(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
128                                 inet_fmt(v->uv_lcl_addr, s1));
129                 start_vif2(vifi);
130             } else dolog(LOG_INFO, 0,
131                      "%s is not yet up; vif #%u not in service",
132                      v->uv_name, vifi);
133         }
134     }
135 }
136
137 /*
138  * Initialize the passed vif with all appropriate default values.
139  * "t" is true if a tunnel, or false if a phyint.
140  */
141 void
142 zero_vif(struct uvif *v, int t)
143 {
144
145     v->uv_flags         = 0;
146     v->uv_metric        = DEFAULT_METRIC;
147     v->uv_admetric      = 0;
148     v->uv_threshold     = DEFAULT_THRESHOLD;
149     v->uv_rate_limit    = t ? DEFAULT_TUN_RATE_LIMIT : DEFAULT_PHY_RATE_LIMIT;
150     v->uv_lcl_addr      = 0;
151     v->uv_rmt_addr      = 0;
152     v->uv_dst_addr      = t ? 0 : dvmrp_group;
153     v->uv_subnet        = 0;
154     v->uv_subnetmask    = 0;
155     v->uv_subnetbcast   = 0;
156     v->uv_name[0]       = '\0';
157     v->uv_groups        = NULL;
158     v->uv_neighbors     = NULL;
159     NBRM_CLRALL(v->uv_nbrmap);
160     v->uv_querier       = NULL;
161     v->uv_igmpv1_warn   = 0;
162     v->uv_prune_lifetime = 0;
163     v->uv_leaf_timer    = 0;
164     v->uv_acl           = NULL;
165     v->uv_addrs         = NULL;
166     v->uv_filter        = NULL;
167     v->uv_blasterbuf    = NULL;
168     v->uv_blastercur    = NULL;
169     v->uv_blasterend    = NULL;
170     v->uv_blasterlen    = 0;
171     v->uv_blastertimer  = 0;
172     v->uv_nbrup         = 0;
173     v->uv_icmp_warn     = 0;
174     v->uv_nroutes       = 0;
175 }
176
177 /*
178  * Start routing on all virtual interfaces that are not down or
179  * administratively disabled.
180  */
181 void
182 init_installvifs(void)
183 {
184     vifi_t vifi;
185     struct uvif *v;
186
187     dolog(LOG_INFO, 0, "Installing vifs in kernel...");
188     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
189         if (!(v->uv_flags & VIFF_DISABLED)) {
190             if (!(v->uv_flags & VIFF_DOWN)) {
191                 if (v->uv_flags & VIFF_TUNNEL)
192                     dolog(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
193                                 inet_fmt(v->uv_lcl_addr, s1),
194                                 inet_fmt(v->uv_rmt_addr, s2));
195                 else
196                     dolog(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
197                                 inet_fmt(v->uv_lcl_addr, s1));
198                 k_add_vif(vifi, &uvifs[vifi]);
199             } else dolog(LOG_INFO, 0,
200                      "%s is not yet up; vif #%u not in service",
201                      v->uv_name, vifi);
202         }
203     }
204 }
205
206 /*
207  * See if any interfaces have changed from up state to down, or vice versa,
208  * including any non-multicast-capable interfaces that are in use as local
209  * tunnel end-points.  Ignore interfaces that have been administratively
210  * disabled.
211  */
212 void
213 check_vif_state(void)
214 {
215     vifi_t vifi;
216     struct uvif *v;
217     struct ifreq ifr;
218     static int checking_vifs = 0;
219
220     /*
221      * If we get an error while checking, (e.g. two interfaces go down
222      * at once, and we decide to send a prune out one of the failed ones)
223      * then don't go into an infinite loop!
224      */
225     if (checking_vifs)
226         return;
227
228     vifs_down = FALSE;
229     checking_vifs = 1;
230     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
231
232         if (v->uv_flags & VIFF_DISABLED) continue;
233
234         strncpy(ifr.ifr_name, v->uv_name, IFNAMSIZ);
235         if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ifr) < 0)
236             dolog(LOG_ERR, errno,
237                 "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
238
239         if (v->uv_flags & VIFF_DOWN) {
240             if (ifr.ifr_flags & IFF_UP) {
241                 dolog(LOG_NOTICE, 0,
242                     "%s has come up; vif #%u now in service",
243                     v->uv_name, vifi);
244                 v->uv_flags &= ~VIFF_DOWN;
245                 start_vif(vifi);
246             }
247             else vifs_down = TRUE;
248         }
249         else {
250             if (!(ifr.ifr_flags & IFF_UP)) {
251                 dolog(LOG_NOTICE, 0,
252                     "%s has gone down; vif #%u taken out of service",
253                     v->uv_name, vifi);
254                 stop_vif(vifi);
255                 v->uv_flags |= VIFF_DOWN;
256                 vifs_down = TRUE;
257             }
258         }
259     }
260     checking_vifs = 0;
261 }
262
263 /*
264  * Send a DVMRP message on the specified vif.  If DVMRP messages are
265  * to be encapsulated and sent "inside" the tunnel, use the special
266  * encapsulator.  If it's not a tunnel or DVMRP messages are to be
267  * sent "beside" the tunnel, as required by earlier versions of mrouted,
268  * then just send the message.
269  */
270 void
271 send_on_vif(struct uvif *v, u_int32 dst, int code, int datalen)
272 {
273     u_int32 group = htonl(MROUTED_LEVEL | 
274                         ((v->uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS));
275
276     /*
277      * The UNIX kernel will not decapsulate unicasts.
278      * Therefore, we don't send encapsulated unicasts.
279      */
280     if ((v->uv_flags & (VIFF_TUNNEL|VIFF_OTUNNEL)) == VIFF_TUNNEL &&
281         ((dst == 0) || IN_MULTICAST(ntohl(dst))))
282         send_ipip(v->uv_lcl_addr, dst ? dst : dvmrp_group, IGMP_DVMRP,
283                                                 code, group, datalen, v);
284     else
285         send_igmp(v->uv_lcl_addr, dst ? dst : v->uv_dst_addr, IGMP_DVMRP,
286                                                 code, group, datalen);
287 }
288
289
290 /*
291  * Send a probe message on vif v
292  */
293 static void
294 send_probe_on_vif(struct uvif *v)
295 {
296     char *p;
297     int datalen = 0;
298     struct listaddr *nbr;
299     int i;
300
301     if ((v->uv_flags & VIFF_PASSIVE && v->uv_neighbors == NULL) ||
302         (v->uv_flags & VIFF_FORCE_LEAF))
303         return;
304
305     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
306
307     for (i = 0; i < 4; i++)
308         *p++ = ((char *)&(dvmrp_genid))[i];
309     datalen += 4;
310
311     /*
312      * add the neighbor list on the interface to the message
313      */
314     nbr = v->uv_neighbors;
315
316     while (nbr) {
317         for (i = 0; i < 4; i++)
318             *p++ = ((char *)&nbr->al_addr)[i];
319         datalen +=4;
320         nbr = nbr->al_next;
321     }
322
323     send_on_vif(v, 0, DVMRP_PROBE, datalen);
324 }
325
326 static void
327 send_query(struct uvif *v)
328 {
329     IF_DEBUG(DEBUG_IGMP)
330     dolog(LOG_DEBUG, 0, "sending %squery on vif %d",
331                 (v->uv_flags & VIFF_IGMPV1) ? "v1 " : "",
332                 v - uvifs);
333     send_igmp(v->uv_lcl_addr, allhosts_group,
334                 IGMP_MEMBERSHIP_QUERY, 
335                 (v->uv_flags & VIFF_IGMPV1) ? 0 :
336                 IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
337 }
338
339 /*
340  * Add a vifi to the kernel and start routing on it.
341  */
342 static void
343 start_vif(vifi_t vifi)
344 {
345     /*
346      * Install the interface in the kernel's vif structure.
347      */
348     k_add_vif(vifi, &uvifs[vifi]);
349
350     start_vif2(vifi);
351 }
352
353 /*
354  * Add a vifi to all the user-level data structures but don't add
355  * it to the kernel yet.
356  */
357 static void
358 start_vif2(vifi_t vifi)
359 {
360     struct uvif *v;
361     u_int32 src;
362     struct phaddr *p;
363
364     v   = &uvifs[vifi];
365     src = v->uv_lcl_addr;
366
367     /*
368      * Update the existing route entries to take into account the new vif.
369      */
370     add_vif_to_routes(vifi);
371
372     if (!(v->uv_flags & VIFF_TUNNEL)) {
373         /*
374          * Join the DVMRP multicast group on the interface.
375          * (This is not strictly necessary, since the kernel promiscuously
376          * receives IGMP packets addressed to ANY IP multicast group while
377          * multicast routing is enabled.  However, joining the group allows
378          * this host to receive non-IGMP packets as well, such as 'pings'.)
379          */
380         k_join(dvmrp_group, src);
381
382         /*
383          * Join the ALL-ROUTERS multicast group on the interface.
384          * This allows mtrace requests to loop back if they are run
385          * on the multicast router.
386          */
387         k_join(allrtrs_group, src);
388
389         /*
390          * Install an entry in the routing table for the subnet to which
391          * the interface is connected.
392          */
393         start_route_updates();
394         update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi, NULL);
395         for (p = v->uv_addrs; p; p = p->pa_next) {
396             start_route_updates();
397             update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi, NULL);
398         }
399
400         /*
401          * Until neighbors are discovered, assume responsibility for sending
402          * periodic group membership queries to the subnet.  Send the first
403          * query.
404          */
405         v->uv_flags |= VIFF_QUERIER;
406         IF_DEBUG(DEBUG_IGMP)
407         dolog(LOG_DEBUG, 0, "assuming querier duties on vif %d", vifi);
408         send_query(v);
409     }
410
411     v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
412
413     /*
414      * Send a probe via the new vif to look for neighbors.
415      */
416     send_probe_on_vif(v);
417 }
418
419 /*
420  * Stop routing on the specified virtual interface.
421  */
422 static void
423 stop_vif(vifi_t vifi)
424 {
425     struct uvif *v;
426     struct listaddr *a;
427     struct phaddr *p;
428
429     v = &uvifs[vifi];
430
431     if (!(v->uv_flags & VIFF_TUNNEL)) {
432         /*
433          * Depart from the DVMRP multicast group on the interface.
434          */
435         k_leave(dvmrp_group, v->uv_lcl_addr);
436
437         /*
438          * Depart from the ALL-ROUTERS multicast group on the interface.
439          */
440         k_leave(allrtrs_group, v->uv_lcl_addr);
441
442         /*
443          * Update the entry in the routing table for the subnet to which
444          * the interface is connected, to take into account the interface
445          * failure.
446          */
447         start_route_updates();
448         update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi, NULL);
449         for (p = v->uv_addrs; p; p = p->pa_next) {
450             start_route_updates();
451             update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi, NULL);
452         }
453
454         /*
455          * Discard all group addresses.  (No need to tell kernel;
456          * the k_del_vif() call, below, will clean up kernel state.)
457          */
458         while (v->uv_groups != NULL) {
459             a = v->uv_groups;
460             v->uv_groups = a->al_next;
461             free((char *)a);
462         }
463
464         IF_DEBUG(DEBUG_IGMP)
465         dolog(LOG_DEBUG, 0, "releasing querier duties on vif %d", vifi);
466         v->uv_flags &= ~VIFF_QUERIER;
467     }
468
469     /*
470      * Update the existing route entries to take into account the vif failure.
471      */
472     delete_vif_from_routes(vifi);
473
474     /*
475      * Delete the interface from the kernel's vif structure.
476      */
477     k_del_vif(vifi);
478
479     /*
480      * Discard all neighbor addresses.
481      */
482     if (!NBRM_ISEMPTY(v->uv_nbrmap))
483         vifs_with_neighbors--;
484
485     while (v->uv_neighbors != NULL) {
486         a = v->uv_neighbors;
487         v->uv_neighbors = a->al_next;
488         nbrs[a->al_index] = NULL;
489         free((char *)a);
490     }
491     NBRM_CLRALL(v->uv_nbrmap);
492 }
493
494
495 /*
496  * stop routing on all vifs
497  */
498 void
499 stop_all_vifs(void)
500 {
501     vifi_t vifi;
502     struct uvif *v;
503     struct listaddr *a;
504     struct vif_acl *acl;
505
506     for (vifi = 0; vifi < numvifs; vifi++) {
507         v = &uvifs[vifi];
508         while (v->uv_groups != NULL) {
509             a = v->uv_groups;
510             v->uv_groups = a->al_next;
511             free((char *)a);
512         }
513         while (v->uv_neighbors != NULL) {
514             a = v->uv_neighbors;
515             v->uv_neighbors = a->al_next;
516             nbrs[a->al_index] = NULL;
517             free((char *)a);
518         }
519         while (v->uv_acl != NULL) {
520             acl = v->uv_acl;
521             v->uv_acl = acl->acl_next;
522             free((char *)acl);
523         }
524     }
525 }
526
527
528 /*
529  * Find the virtual interface from which an incoming packet arrived,
530  * based on the packet's source and destination IP addresses.
531  */
532 vifi_t
533 find_vif(u_int32 src, u_int32 dst)
534 {
535     vifi_t vifi;
536     struct uvif *v;
537     struct phaddr *p;
538
539     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
540         if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
541             if (v->uv_flags & VIFF_TUNNEL) {
542                 if (src == v->uv_rmt_addr && (dst == v->uv_lcl_addr ||
543                                               dst == dvmrp_group))
544                     return(vifi);
545             }
546             else {
547                 if ((src & v->uv_subnetmask) == v->uv_subnet &&
548                     ((v->uv_subnetmask == 0xffffffff) ||
549                      (src != v->uv_subnetbcast)))
550                     return(vifi);
551                 for (p=v->uv_addrs; p; p=p->pa_next) {
552                     if ((src & p->pa_subnetmask) == p->pa_subnet &&
553                         ((p->pa_subnetmask == 0xffffffff) ||
554                          (src != p->pa_subnetbcast)))
555                         return(vifi);
556                 }
557             }
558         }
559     }
560     return (NO_VIF);
561 }
562
563 static void
564 age_old_hosts(void)
565 {
566     vifi_t vifi;
567     struct uvif *v;
568     struct listaddr *g;
569
570     /*
571      * Decrement the old-hosts-present timer for each
572      * active group on each vif.
573      */
574     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
575         for (g = v->uv_groups; g != NULL; g = g->al_next)
576             if (g->al_old)
577                 g->al_old--;
578 }
579
580
581 /*
582  * Send group membership queries on each interface for which I am querier.
583  * Note that technically, there should be a timer per interface, as the
584  * dynamics of querier election can cause the "right" time to send a
585  * query to be different on different interfaces.  However, this simple
586  * implementation only ever sends queries sooner than the "right" time,
587  * so can not cause loss of membership (but can send more packets than
588  * necessary)
589  */
590 void
591 query_groups(void)
592 {
593     vifi_t vifi;
594     struct uvif *v;
595
596     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
597         if (v->uv_flags & VIFF_QUERIER) {
598             send_query(v);
599         }
600     }
601     age_old_hosts();
602 }
603
604 /*
605  * Process an incoming host membership query.  Warn about
606  * IGMP version mismatches, perform querier election, and
607  * handle group-specific queries when we're not the querier.
608  */
609 void
610 accept_membership_query(u_int32 src, u_int32 dst, u_int32 group, int tmo)
611 {
612     vifi_t vifi;
613     struct uvif *v;
614
615     if ((vifi = find_vif(src, dst)) == NO_VIF ||
616         (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
617         dolog(LOG_INFO, 0,
618             "ignoring group membership query from non-adjacent host %s",
619             inet_fmt(src, s1));
620         return;
621     }
622
623     v = &uvifs[vifi];
624
625     if ((tmo == 0 && !(v->uv_flags & VIFF_IGMPV1)) ||
626         (tmo != 0 &&  (v->uv_flags & VIFF_IGMPV1))) {
627         int i;
628
629         /*
630          * Exponentially back-off warning rate
631          */
632         i = ++v->uv_igmpv1_warn;
633         while (i && !(i & 1))
634             i >>= 1;
635         if (i == 1)
636             dolog(LOG_WARNING, 0, "%s %s on vif %d, %s",
637                 tmo == 0 ? "Received IGMPv1 report from"
638                          : "Received IGMPv2 report from",
639                 inet_fmt(src, s1),
640                 vifi,
641                 tmo == 0 ? "please configure vif for IGMPv1"
642                          : "but I am configured for IGMPv1");
643     }
644
645     if (v->uv_querier == NULL || v->uv_querier->al_addr != src) {
646         /*
647          * This might be:
648          * - A query from a new querier, with a lower source address
649          *   than the current querier (who might be me)
650          * - A query from a new router that just started up and doesn't
651          *   know who the querier is.
652          */
653         if (ntohl(src) < (v->uv_querier ? ntohl(v->uv_querier->al_addr)
654                                    : ntohl(v->uv_lcl_addr))) {
655             IF_DEBUG(DEBUG_IGMP)
656             dolog(LOG_DEBUG, 0, "new querier %s (was %s) on vif %d",
657                        inet_fmt(src, s1),
658                        v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2) :
659                        "me", vifi);
660             if (!v->uv_querier) {
661                 v->uv_querier = (struct listaddr *)
662                                        malloc(sizeof(struct listaddr));
663                 v->uv_flags &= ~VIFF_QUERIER;
664             }
665             time(&v->uv_querier->al_ctime);
666             v->uv_querier->al_addr = src;
667         } else {
668             IF_DEBUG(DEBUG_IGMP)
669             dolog(LOG_DEBUG, 0, "ignoring query from %s; querier on vif %d is still %s",
670                        inet_fmt(src, s1), vifi,
671                        v->uv_querier ? inet_fmt(v->uv_querier->al_addr, s2) :
672                        "me");
673
674             return;
675         }
676     }
677
678     /*
679      * Reset the timer since we've received a query.
680      */
681     if (v->uv_querier && src == v->uv_querier->al_addr)
682         v->uv_querier->al_timer = 0;
683
684     /*
685      * If this is a Group-Specific query which we did not source,
686      * we must set our membership timer to [Last Member Query Count] *
687      * the [Max Response Time] in the packet.
688      */
689     if (!(v->uv_flags & (VIFF_IGMPV1|VIFF_QUERIER)) && group != 0 &&
690                                         src != v->uv_lcl_addr) {
691         struct listaddr *g;
692
693         IF_DEBUG(DEBUG_IGMP)
694         dolog(LOG_DEBUG, 0,
695             "%s for %s from %s on vif %d, timer %d",
696             "Group-specific membership query",
697             inet_fmt(group, s2), inet_fmt(src, s1), vifi, tmo);
698         
699         for (g = v->uv_groups; g != NULL; g = g->al_next) {
700             if (group == g->al_addr && g->al_query == 0) {
701                 /* setup a timeout to remove the group membership */
702                 if (g->al_timerid)
703                     g->al_timerid = DeleteTimer(g->al_timerid);
704                 g->al_timer = IGMP_LAST_MEMBER_QUERY_COUNT *
705                                            tmo / IGMP_TIMER_SCALE;
706                 /* use al_query to record our presence in last-member state */
707                 g->al_query = -1;
708                 g->al_timerid = SetTimer(vifi, g);
709                 IF_DEBUG(DEBUG_IGMP)
710                 dolog(LOG_DEBUG, 0,
711                     "timer for grp %s on vif %d set to %d",
712                     inet_fmt(group, s2), vifi, g->al_timer);
713                 break;
714             }
715         }
716     }
717 }
718
719 /*
720  * Process an incoming group membership report.
721  */
722 void
723 accept_group_report(u_int32 src, u_int32 dst, u_int32 group, int r_type)
724 {
725     vifi_t vifi;
726     struct uvif *v;
727     struct listaddr *g;
728
729     if ((vifi = find_vif(src, dst)) == NO_VIF ||
730         (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
731         dolog(LOG_INFO, 0,
732             "ignoring group membership report from non-adjacent host %s",
733             inet_fmt(src, s1));
734         return;
735     }
736
737     v = &uvifs[vifi];
738
739     /*
740      * Look for the group in our group list; if found, reset its timer.
741      */
742     for (g = v->uv_groups; g != NULL; g = g->al_next) {
743         if (group == g->al_addr) {
744             if (r_type == IGMP_V1_MEMBERSHIP_REPORT)
745                 g->al_old = OLD_AGE_THRESHOLD;
746
747             g->al_reporter = src;
748
749             /** delete old timers, set a timer for expiration **/
750             g->al_timer = IGMP_GROUP_MEMBERSHIP_INTERVAL;
751             if (g->al_query)
752                 g->al_query = DeleteTimer(g->al_query);
753             if (g->al_timerid)
754                 g->al_timerid = DeleteTimer(g->al_timerid);
755             g->al_timerid = SetTimer(vifi, g);  
756             break;
757         }
758     }
759
760     /*
761      * If not found, add it to the list and update kernel cache.
762      */
763     if (g == NULL) {
764         g = (struct listaddr *)malloc(sizeof(struct listaddr));
765         if (g == NULL)
766             dolog(LOG_ERR, 0, "ran out of memory");    /* fatal */
767
768         g->al_addr   = group;
769         if (r_type == IGMP_V1_MEMBERSHIP_REPORT)
770             g->al_old = OLD_AGE_THRESHOLD;
771         else
772             g->al_old = 0;
773
774         /** set a timer for expiration **/
775         g->al_query     = 0;
776         g->al_timer     = IGMP_GROUP_MEMBERSHIP_INTERVAL;
777         g->al_reporter  = src;
778         g->al_timerid   = SetTimer(vifi, g);
779         g->al_next      = v->uv_groups;
780         v->uv_groups    = g;
781         time(&g->al_ctime);
782
783         update_lclgrp(vifi, group);
784     }
785
786     /* 
787      * Check if a graft is necessary for this group
788      */
789     chkgrp_graft(vifi, group);
790 }
791
792 /*
793  * Process an incoming IGMPv2 Leave Group message.
794  */
795 void
796 accept_leave_message(u_int32 src, u_int32 dst, u_int32 group)
797 {
798     vifi_t vifi;
799     struct uvif *v;
800     struct listaddr *g;
801
802     if ((vifi = find_vif(src, dst)) == NO_VIF ||
803         (uvifs[vifi].uv_flags & VIFF_TUNNEL)) {
804         dolog(LOG_INFO, 0,
805             "ignoring group leave report from non-adjacent host %s",
806             inet_fmt(src, s1));
807         return;
808     }
809
810     v = &uvifs[vifi];
811
812     if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1))
813         return;
814
815     /*
816      * Look for the group in our group list in order to set up a short-timeout
817      * query.
818      */
819     for (g = v->uv_groups; g != NULL; g = g->al_next) {
820         if (group == g->al_addr) {
821             IF_DEBUG(DEBUG_IGMP)
822             dolog(LOG_DEBUG, 0,
823                 "[vif.c, _accept_leave_message] %d %d \n",
824                 g->al_old, g->al_query);
825
826             /* Ignore the leave message if there are old hosts present */
827             if (g->al_old)
828                 return;
829
830             /* still waiting for a reply to a query, ignore the leave */
831             if (g->al_query)
832                 return;
833
834             /** delete old timer set a timer for expiration **/
835             if (g->al_timerid)
836                 g->al_timerid = DeleteTimer(g->al_timerid);
837
838 #if IGMP_LAST_MEMBER_QUERY_COUNT != 2
839 This code needs to be updated to keep a counter of the number
840 of queries remaining.
841 #endif
842             /** send a group specific querry **/
843             g->al_timer = IGMP_LAST_MEMBER_QUERY_INTERVAL *
844                         (IGMP_LAST_MEMBER_QUERY_COUNT + 1);
845             send_igmp(v->uv_lcl_addr, g->al_addr,
846                         IGMP_MEMBERSHIP_QUERY, 
847                         IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE,
848                         g->al_addr, 0);
849             g->al_query = SetQueryTimer(g, vifi,
850                         IGMP_LAST_MEMBER_QUERY_INTERVAL,
851                         IGMP_LAST_MEMBER_QUERY_INTERVAL * IGMP_TIMER_SCALE);
852             g->al_timerid = SetTimer(vifi, g);  
853             break;
854         }
855     }
856 }
857
858
859 /*
860  * Send a periodic probe on all vifs.
861  * Useful to determine one-way interfaces.
862  * Detect neighbor loss faster.
863  */
864 void
865 probe_for_neighbors(void)
866 {
867     vifi_t vifi;
868     struct uvif *v;
869
870     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
871         if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
872             send_probe_on_vif(v);
873         }
874     }
875 }
876
877
878 /*
879  * Send a list of all of our neighbors to the requestor, `src'.
880  */
881 void
882 accept_neighbor_request(u_int32 src, u_int32 dst)
883 {
884     vifi_t vifi;
885     struct uvif *v;
886     u_char *p, *ncount;
887     struct listaddr *la;
888     int datalen;
889     u_int32 temp_addr, them = src;
890
891 #define PUT_ADDR(a)     temp_addr = ntohl(a); \
892                         *p++ = temp_addr >> 24; \
893                         *p++ = (temp_addr >> 16) & 0xFF; \
894                         *p++ = (temp_addr >> 8) & 0xFF; \
895                         *p++ = temp_addr & 0xFF;
896
897     p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
898     datalen = 0;
899
900     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
901         if (v->uv_flags & VIFF_DISABLED)
902             continue;
903
904         ncount = NULL;
905
906         for (la = v->uv_neighbors; la; la = la->al_next) {
907
908             /* Make sure that there's room for this neighbor... */
909             if (datalen + (ncount == NULL ? 4 + 3 + 4 : 4) > MAX_DVMRP_DATA_LEN) {
910                 send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
911                           htonl(MROUTED_LEVEL), datalen);
912                 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
913                 datalen = 0;
914                 ncount = NULL;
915             }
916
917             /* Put out the header for this neighbor list... */
918             if (ncount == NULL) {
919                 PUT_ADDR(v->uv_lcl_addr);
920                 *p++ = v->uv_metric;
921                 *p++ = v->uv_threshold;
922                 ncount = p;
923                 *p++ = 0;
924                 datalen += 4 + 3;
925             }
926
927             PUT_ADDR(la->al_addr);
928             datalen += 4;
929             (*ncount)++;
930         }
931     }
932
933     if (datalen != 0)
934         send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS,
935                         htonl(MROUTED_LEVEL), datalen);
936 }
937
938 /*
939  * Send a list of all of our neighbors to the requestor, `src'.
940  */
941 void
942 accept_neighbor_request2(u_int32 src, u_int32 dst)
943 {
944     vifi_t vifi;
945     struct uvif *v;
946     u_char *p, *ncount;
947     struct listaddr *la;
948     int datalen;
949     u_int32 them = src;
950
951     p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
952     datalen = 0;
953
954     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
955         u_short vflags = v->uv_flags;
956         u_char rflags = 0;
957
958         if (vflags & VIFF_TUNNEL)
959             rflags |= DVMRP_NF_TUNNEL;
960         if (vflags & VIFF_SRCRT)
961             rflags |= DVMRP_NF_SRCRT;
962         if (vflags & VIFF_DOWN)
963             rflags |= DVMRP_NF_DOWN;
964         if (vflags & VIFF_DISABLED)
965             rflags |= DVMRP_NF_DISABLED;
966         if (vflags & VIFF_QUERIER)
967             rflags |= DVMRP_NF_QUERIER;
968         if (vflags & VIFF_LEAF)
969             rflags |= DVMRP_NF_LEAF;
970         ncount = NULL;
971         la = v->uv_neighbors;
972         if (la == NULL) {
973             /*
974              * include down & disabled interfaces and interfaces on
975              * leaf nets.
976              */
977             if (rflags & DVMRP_NF_TUNNEL)
978                 rflags |= DVMRP_NF_DOWN;
979             if (datalen > MAX_DVMRP_DATA_LEN - 12) {
980                 send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
981                           htonl(MROUTED_LEVEL), datalen);
982                 p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
983                 datalen = 0;
984             }
985             *(u_int*)p = v->uv_lcl_addr;
986             p += 4;
987             *p++ = v->uv_metric;
988             *p++ = v->uv_threshold;
989             *p++ = rflags;
990             *p++ = 1;
991             *(u_int*)p =  v->uv_rmt_addr;
992             p += 4;
993             datalen += 12;
994         } else {
995             for ( ; la; la = la->al_next) {
996                 /* Make sure that there's room for this neighbor... */
997                 if (datalen + (ncount == NULL ? 4+4+4 : 4) > MAX_DVMRP_DATA_LEN) {
998                     send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
999                               htonl(MROUTED_LEVEL), datalen);
1000                     p = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
1001                     datalen = 0;
1002                     ncount = NULL;
1003                 }
1004                 /* Put out the header for this neighbor list... */
1005                 if (ncount == NULL) {
1006                     /* If it's a one-way tunnel, mark it down. */
1007                     if (rflags & DVMRP_NF_TUNNEL && la->al_flags & NBRF_ONEWAY)
1008                         rflags |= DVMRP_NF_DOWN;
1009                     *(u_int*)p = v->uv_lcl_addr;
1010                     p += 4;
1011                     *p++ = v->uv_metric;
1012                     *p++ = v->uv_threshold;
1013                     *p++ = rflags;
1014                     ncount = p;
1015                     *p++ = 0;
1016                     datalen += 4 + 4;
1017                 }
1018                 /* Don't report one-way peering on phyint at all */
1019                 if (!(rflags & DVMRP_NF_TUNNEL) && la->al_flags & NBRF_ONEWAY)
1020                     continue;
1021                 *(u_int*)p = la->al_addr;
1022                 p += 4;
1023                 datalen += 4;
1024                 (*ncount)++;
1025             }
1026             if (*ncount == 0) {
1027                 *(u_int*)p = v->uv_rmt_addr;
1028                 p += 4;
1029                 datalen += 4;
1030                 (*ncount)++;
1031             }
1032         }
1033     }
1034     if (datalen != 0)
1035         send_igmp(INADDR_ANY, them, IGMP_DVMRP, DVMRP_NEIGHBORS2,
1036                 htonl(MROUTED_LEVEL), datalen);
1037 }
1038
1039 void
1040 accept_info_request(u_int32 src, u_int32 dst, u_char *p, int datalen)
1041 {
1042     u_char *q;
1043     int len;
1044     int outlen = 0;
1045
1046     q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
1047
1048     /* To be general, this must deal properly with breaking up over-sized
1049      * packets.  That implies passing a length to each function, and
1050      * allowing each function to request to be called again.  Right now,
1051      * we're only implementing the one thing we are positive will fit into
1052      * a single packet, so we wimp out.
1053      */
1054     while (datalen > 0) {
1055         len = 0;
1056         switch (*p) {
1057             case DVMRP_INFO_VERSION:
1058                 len = info_version(q, RECV_BUF_SIZE-(q-(u_char *)send_buf));
1059                 break;
1060
1061             case DVMRP_INFO_NEIGHBORS:
1062             default:
1063                 dolog(LOG_INFO, 0, "ignoring unknown info type %d", *p);
1064                 break;
1065         }
1066         *(q+1) = len++;
1067         outlen += len * 4;
1068         q += len * 4;
1069         len = (*(p+1) + 1) * 4;
1070         p += len;
1071         datalen -= len;
1072     }
1073
1074     if (outlen != 0)
1075         send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY,
1076                         htonl(MROUTED_LEVEL), outlen);
1077 }
1078
1079 /*
1080  * Information response -- return version string
1081  */
1082 static int
1083 info_version(char *p, int plen)
1084 {
1085     int len;
1086     extern char versionstring[];
1087
1088     *p++ = DVMRP_INFO_VERSION;
1089     p++;        /* skip over length */
1090     *p++ = 0;   /* zero out */
1091     *p++ = 0;   /* reserved fields */
1092     strncpy(p, versionstring, plen - 4);
1093     p[plen-5] = '\0';
1094
1095     len = strlen(versionstring);
1096     return ((len + 3) / 4);
1097 }
1098
1099 /*
1100  * Process an incoming neighbor-list message.
1101  */
1102 void
1103 accept_neighbors(u_int32 src, u_int32 dst, u_char *p, int datalen,
1104                  u_int32 level)
1105 {
1106     dolog(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s",
1107         inet_fmt(src, s1), inet_fmt(dst, s2));
1108 }
1109
1110
1111 /*
1112  * Process an incoming neighbor-list message.
1113  */
1114 void
1115 accept_neighbors2(u_int32 src, u_int32 dst, u_char *p, int datalen,
1116                   u_int32 level)
1117 {
1118     IF_DEBUG(DEBUG_PKT)
1119     dolog(LOG_DEBUG, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s",
1120         inet_fmt(src, s1), inet_fmt(dst, s2));
1121 }
1122
1123 /*
1124  * Process an incoming info reply message.
1125  */
1126 void
1127 accept_info_reply(u_int32 src, u_int32 dst, u_char *p, int datalen)
1128 {
1129     IF_DEBUG(DEBUG_PKT)
1130     dolog(LOG_DEBUG, 0, "ignoring spurious DVMRP info reply from %s to %s",
1131         inet_fmt(src, s1), inet_fmt(dst, s2));
1132 }
1133
1134
1135 /*
1136  * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
1137  * 'msgtype' is the type of DVMRP message received from the neighbor.
1138  * Return the neighbor entry if 'addr' is a valid neighbor, FALSE otherwise.
1139  */
1140 struct listaddr *
1141 update_neighbor(vifi_t vifi, u_int32 addr, int msgtype, char *p, int datalen,
1142                 u_int32 level)
1143 {
1144     struct uvif *v;
1145     struct listaddr *n;
1146     int pv = level & 0xff;
1147     int mv = (level >> 8) & 0xff;
1148     int has_genid = 0;
1149     int in_router_list = 0;
1150     int dvmrpspec = 0;
1151     u_int32 genid;
1152     u_int32 send_tables = 0;
1153     int i;
1154     int do_reset = FALSE;
1155
1156     v = &uvifs[vifi];
1157
1158     /*
1159      * Confirm that 'addr' is a valid neighbor address on vif 'vifi'.
1160      * IT IS ASSUMED that this was preceded by a call to find_vif(), which
1161      * checks that 'addr' is either a valid remote tunnel endpoint or a
1162      * non-broadcast address belonging to a directly-connected subnet.
1163      * Therefore, here we check only that 'addr' is not our own address
1164      * (due to an impostor or erroneous loopback) or an address of the form
1165      * {subnet,0} ("the unknown host").  These checks are not performed in
1166      * find_vif() because those types of address are acceptable for some
1167      * types of IGMP message (such as group membership reports).
1168      */
1169     if (!(v->uv_flags & VIFF_TUNNEL) &&
1170         (addr == v->uv_lcl_addr ||
1171          addr == v->uv_subnet )) {
1172         dolog(LOG_WARNING, 0,
1173             "received DVMRP message from %s: %s",
1174             (addr == v->uv_lcl_addr) ? "self (check device loopback)" :
1175                                        "'the unknown host'",
1176             inet_fmt(addr, s1));
1177         return NULL;
1178     }
1179
1180     /*
1181      * Ignore all neighbors on vifs forced into leaf mode
1182      */
1183     if (v->uv_flags & VIFF_FORCE_LEAF) {
1184         return NULL;
1185     }
1186
1187     /*
1188      * mrouted's version 3.3 and later include the generation ID
1189      * and the list of neighbors on the vif in their probe messages.
1190      */
1191     if (msgtype == DVMRP_PROBE && ((pv == 3 && mv > 2) ||
1192                                    (pv > 3 && pv < 10))) {
1193         u_int32 router;
1194
1195         IF_DEBUG(DEBUG_PEER)
1196         dolog(LOG_DEBUG, 0, "checking probe from %s (%d.%d) on vif %d",
1197             inet_fmt(addr, s1), pv, mv, vifi);
1198
1199         if (datalen < 4) {
1200             dolog(LOG_WARNING, 0,
1201                 "received truncated probe message from %s (len %d)",
1202                 inet_fmt(addr, s1), datalen);
1203             return NULL;
1204         }
1205
1206         has_genid = 1;
1207
1208         for (i = 0; i < 4; i++)
1209           ((char *)&genid)[i] = *p++;
1210         datalen -= 4;
1211
1212         while (datalen > 0) {
1213             if (datalen < 4) {
1214                 dolog(LOG_WARNING, 0,
1215                     "received truncated probe message from %s (len %d)",
1216                     inet_fmt(addr, s1), datalen);
1217                 return NULL;
1218             }
1219             for (i = 0; i < 4; i++)
1220               ((char *)&router)[i] = *p++;
1221             datalen -= 4;
1222
1223             if (router == v->uv_lcl_addr) {
1224                 in_router_list = 1;
1225                 break;
1226             }
1227         }
1228     }
1229
1230     if ((pv == 3 && mv == 255) || (pv > 3 && pv < 10))
1231         dvmrpspec = 1;
1232
1233     /*
1234      * Look for addr in list of neighbors.
1235      */
1236     for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
1237         if (addr == n->al_addr) {
1238             break;
1239         }
1240     }
1241
1242     if (n == NULL) {
1243         /*
1244          * New neighbor.
1245          *
1246          * If this neighbor follows the DVMRP spec, start the probe
1247          * handshake.  If not, then it doesn't require the probe
1248          * handshake, so establish the peering immediately.
1249          */
1250         if (dvmrpspec && (msgtype != DVMRP_PROBE))
1251             return NULL;
1252
1253         for (i = 0; i < MAXNBRS; i++)
1254             if (nbrs[i] == NULL)
1255                 break;
1256
1257         if (i == MAXNBRS) {
1258             /* XXX This is a severe new restriction. */
1259             /* XXX want extensible bitmaps! */
1260             dolog(LOG_ERR, 0, "Can't handle %dth neighbor %s on vif %d!",
1261                 MAXNBRS, inet_fmt(addr, s1), vifi);
1262             /*NOTREACHED*/
1263         }
1264
1265         /*
1266          * Add it to our list of neighbors.
1267          */
1268         IF_DEBUG(DEBUG_PEER)
1269         dolog(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x idx %d",
1270             inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff,
1271             (level >> 16) & 0xff, i);
1272
1273         n = (struct listaddr *)malloc(sizeof(struct listaddr));
1274         if (n == NULL)
1275             dolog(LOG_ERR, 0, "ran out of memory");    /* fatal */
1276
1277         n->al_addr      = addr;
1278         n->al_pv        = pv;
1279         n->al_mv        = mv;
1280         n->al_genid     = has_genid ? genid : 0;
1281         n->al_index     = i;
1282         nbrs[i] = n;
1283
1284         time(&n->al_ctime);
1285         n->al_timer     = 0;
1286         n->al_flags     = has_genid ? NBRF_GENID : 0;
1287         n->al_next      = v->uv_neighbors;
1288         v->uv_neighbors = n;
1289
1290         /*
1291          * If we are not configured to peer with non-pruning routers,
1292          * check the deprecated "I-know-how-to-prune" bit.  This bit
1293          * was MBZ in early mrouted implementations (<3.5) and is required
1294          * to be set by the DVMRPv3 specification.
1295          */
1296         if (!(v->uv_flags & VIFF_ALLOW_NONPRUNERS) &&
1297             !((level & 0x020000) || (pv == 3 && mv < 5))) {
1298             n->al_flags |= NBRF_TOOOLD;
1299         }
1300
1301         /*
1302          * If this router implements the DVMRPv3 spec, then don't peer
1303          * with him if we haven't yet established a bidirectional connection.
1304          */
1305         if (dvmrpspec) {
1306             if (!in_router_list) {
1307                 IF_DEBUG(DEBUG_PEER)
1308                 dolog(LOG_DEBUG, 0, "waiting for probe from %s with my addr",
1309                     inet_fmt(addr, s1));
1310                 n->al_flags |= NBRF_WAITING;
1311                 return NULL;
1312             }
1313         }
1314
1315         if (n->al_flags & NBRF_DONTPEER) {
1316             IF_DEBUG(DEBUG_PEER)
1317             dolog(LOG_DEBUG, 0, "not peering with %s on vif %d because %x",
1318                 inet_fmt(addr, s1), vifi, n->al_flags & NBRF_DONTPEER);
1319             return NULL;
1320         }
1321
1322         /*
1323          * If we thought that we had no neighbors on this vif, send a route
1324          * report to the vif.  If this is just a new neighbor on the same
1325          * vif, send the route report just to the new neighbor.
1326          */
1327         if (NBRM_ISEMPTY(v->uv_nbrmap)) {
1328             send_tables = v->uv_dst_addr;
1329             vifs_with_neighbors++;
1330         } else {
1331             send_tables = addr;
1332         }
1333
1334
1335         NBRM_SET(i, v->uv_nbrmap);
1336         add_neighbor_to_routes(vifi, i);
1337     } else {
1338         /*
1339          * Found it.  Reset its timer.
1340          */
1341         n->al_timer = 0;
1342
1343         if (n->al_flags & NBRF_WAITING && msgtype == DVMRP_PROBE) {
1344             n->al_flags &= ~NBRF_WAITING;
1345             if (!in_router_list) {
1346                 dolog(LOG_WARNING, 0, "possible one-way peering with %s on vif %d",
1347                     inet_fmt(addr, s1), vifi);
1348                 n->al_flags |= NBRF_ONEWAY;
1349                 return NULL;
1350             } else {
1351                 if (NBRM_ISEMPTY(v->uv_nbrmap)) {
1352                     send_tables = v->uv_dst_addr;
1353                     vifs_with_neighbors++;
1354                 } else {
1355                     send_tables = addr;
1356                 }
1357                 NBRM_SET(n->al_index, v->uv_nbrmap);
1358                 add_neighbor_to_routes(vifi, n->al_index);
1359                 IF_DEBUG(DEBUG_PEER)
1360                 dolog(LOG_DEBUG, 0, "%s on vif %d exits WAITING",
1361                     inet_fmt(addr, s1), vifi);
1362             }
1363         }
1364
1365         if (n->al_flags & NBRF_ONEWAY && msgtype == DVMRP_PROBE) {
1366             if (in_router_list) {
1367                 if (NBRM_ISEMPTY(v->uv_nbrmap))
1368                     vifs_with_neighbors++;
1369                 NBRM_SET(n->al_index, v->uv_nbrmap);
1370                 add_neighbor_to_routes(vifi, n->al_index);
1371                 dolog(LOG_NOTICE, 0, "peering with %s on vif %d is no longer one-way",
1372                         inet_fmt(addr, s1), vifi);
1373                 n->al_flags &= ~NBRF_ONEWAY;
1374             } else {
1375                 /* XXX rate-limited warning message? */
1376                 IF_DEBUG(DEBUG_PEER)
1377                 dolog(LOG_DEBUG, 0, "%s on vif %d is still ONEWAY",
1378                     inet_fmt(addr, s1), vifi);
1379             }
1380         }
1381
1382         /*
1383          * When peering with a genid-capable but pre-DVMRP spec peer,
1384          * we might bring up the peering with a route report and not
1385          * remember his genid.  Assume that he doesn't send a route
1386          * report and then reboot before sending a probe.
1387          */
1388         if (has_genid && !(n->al_flags & NBRF_GENID)) {
1389             n->al_flags |= NBRF_GENID;
1390             n->al_genid = genid;
1391         }
1392
1393         /*
1394          * update the neighbors version and protocol number and genid
1395          * if changed => router went down and came up, 
1396          * so take action immediately.
1397          */
1398         if ((n->al_pv != pv) ||
1399             (n->al_mv != mv) ||
1400             (has_genid && n->al_genid != genid)) {
1401
1402             do_reset = TRUE;
1403             IF_DEBUG(DEBUG_PEER)
1404             dolog(LOG_DEBUG, 0,
1405                 "version/genid change neighbor %s [old:%d.%d/%8x, new:%d.%d/%8x]",
1406                 inet_fmt(addr, s1),
1407                 n->al_pv, n->al_mv, n->al_genid, pv, mv, genid);
1408             
1409             n->al_pv = pv;
1410             n->al_mv = mv;
1411             n->al_genid = genid;
1412             time(&n->al_ctime);
1413         }
1414
1415         if ((pv == 3 && mv > 2) || (pv > 3 && pv < 10)) {
1416             if (!(n->al_flags & VIFF_ONEWAY) && has_genid && !in_router_list &&
1417                                 (time(NULL) - n->al_ctime > 20)) {
1418                 if (NBRM_ISSET(n->al_index, v->uv_nbrmap)) {
1419                     NBRM_CLR(n->al_index, v->uv_nbrmap);
1420                     if (NBRM_ISEMPTY(v->uv_nbrmap))
1421                         vifs_with_neighbors--;
1422                 }
1423                 delete_neighbor_from_routes(addr, vifi, n->al_index);
1424                 reset_neighbor_state(vifi, addr);
1425                 dolog(LOG_WARNING, 0, "peering with %s on vif %d is one-way",
1426                         inet_fmt(addr, s1), vifi);
1427                 n->al_flags |= NBRF_ONEWAY;
1428             }
1429         }
1430
1431         if (n->al_flags & NBRF_DONTPEER) {
1432             IF_DEBUG(DEBUG_PEER)
1433             dolog(LOG_DEBUG, 0, "not peering with %s on vif %d because %x",
1434                 inet_fmt(addr, s1), vifi, n->al_flags & NBRF_DONTPEER);
1435             return NULL;
1436         }
1437
1438         /* check "leaf" flag */
1439     }
1440     if (do_reset) {
1441         reset_neighbor_state(vifi, addr);
1442         if (!send_tables)
1443             send_tables = addr;
1444     }
1445     if (send_tables) {
1446         send_probe_on_vif(v);
1447         report(ALL_ROUTES, vifi, send_tables);
1448     }
1449     v->uv_leaf_timer = 0;
1450     v->uv_flags &= ~VIFF_LEAF;
1451
1452     return n;
1453 }
1454
1455
1456 /*
1457  * On every timer interrupt, advance the timer in each neighbor and
1458  * group entry on every vif.
1459  */
1460 void
1461 age_vifs(void)
1462 {
1463     vifi_t vifi;
1464     struct uvif *v;
1465     struct listaddr *a, *prev_a;
1466     u_int32 addr;
1467
1468     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
1469         if (v->uv_leaf_timer && (v->uv_leaf_timer -= TIMER_INTERVAL == 0)) {
1470                 v->uv_flags |= VIFF_LEAF;
1471         }
1472
1473         for (prev_a = (struct listaddr *)&(v->uv_neighbors),
1474              a = v->uv_neighbors;
1475              a != NULL;
1476              prev_a = a, a = a->al_next) {
1477             int exp_time;
1478             int idx;
1479
1480             if (((a->al_pv == 3) && (a->al_mv >= 3)) ||
1481                 ((a->al_pv > 3) && (a->al_pv < 10)))
1482                 exp_time = NEIGHBOR_EXPIRE_TIME;
1483             else
1484                 exp_time = OLD_NEIGHBOR_EXPIRE_TIME;
1485
1486             if ((a->al_timer += TIMER_INTERVAL) < exp_time)
1487                 continue;
1488
1489             IF_DEBUG(DEBUG_PEER)
1490             dolog(LOG_DEBUG, 0, "Neighbor %s (%d.%d) expired after %d seconds",
1491                     inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv, exp_time);
1492
1493             /*
1494              * Neighbor has expired; delete it from the neighbor list,
1495              * delete it from the 'dominants' and 'subordinates arrays of
1496              * any route entries.
1497              */
1498             NBRM_CLR(a->al_index, v->uv_nbrmap);
1499             nbrs[a->al_index] = NULL;   /* XXX is it a good idea to reuse indxs? */
1500             idx = a->al_index;
1501             addr = a->al_addr;
1502             prev_a->al_next = a->al_next;
1503             free((char *)a);
1504             a = prev_a;/*XXX use ** */
1505
1506             delete_neighbor_from_routes(addr, vifi, idx);
1507             reset_neighbor_state(vifi, addr);
1508
1509             if (NBRM_ISEMPTY(v->uv_nbrmap))
1510                 vifs_with_neighbors--;
1511
1512             v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
1513         }
1514
1515         if (v->uv_querier &&
1516             (v->uv_querier->al_timer += TIMER_INTERVAL) >
1517                 IGMP_OTHER_QUERIER_PRESENT_INTERVAL) {
1518             /*
1519              * The current querier has timed out.  We must become the
1520              * querier.
1521              */
1522             IF_DEBUG(DEBUG_IGMP)
1523             dolog(LOG_DEBUG, 0, "querier %s timed out",
1524                     inet_fmt(v->uv_querier->al_addr, s1));
1525             free(v->uv_querier);
1526             v->uv_querier = NULL;
1527             v->uv_flags |= VIFF_QUERIER;
1528             send_query(v);
1529         }
1530     }
1531 }
1532
1533 /*
1534  * Returns the neighbor info struct for a given neighbor
1535  */
1536 struct listaddr *
1537 neighbor_info(vifi_t vifi, u_int32 addr)
1538 {
1539     struct listaddr *u;
1540
1541     for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
1542         if (u->al_addr == addr)
1543             return u;
1544
1545     return NULL;
1546 }
1547
1548 static struct vnflags {
1549         int     vn_flag;
1550         char   *vn_name;
1551 } vifflags[] = {
1552         { VIFF_DOWN,            "down" },
1553         { VIFF_DISABLED,        "disabled" },
1554         { VIFF_QUERIER,         "querier" },
1555         { VIFF_ONEWAY,          "one-way" },
1556         { VIFF_LEAF,            "leaf" },
1557         { VIFF_IGMPV1,          "IGMPv1" },
1558         { VIFF_REXMIT_PRUNES,   "rexmit_prunes" },
1559         { VIFF_PASSIVE,         "passive" },
1560         { VIFF_ALLOW_NONPRUNERS,"allow_nonpruners" },
1561         { VIFF_NOFLOOD,         "noflood" },
1562         { VIFF_NOTRANSIT,       "notransit" },
1563         { VIFF_BLASTER,         "blaster" },
1564         { VIFF_FORCE_LEAF,      "force_leaf" },
1565         { VIFF_OTUNNEL,         "old-tunnel" },
1566 };
1567
1568 static struct vnflags nbrflags[] = {
1569         { NBRF_LEAF,            "leaf" },
1570         { NBRF_GENID,           "have-genid" },
1571         { NBRF_WAITING,         "waiting" },
1572         { NBRF_ONEWAY,          "one-way" },
1573         { NBRF_TOOOLD,          "too old" },
1574         { NBRF_TOOMANYROUTES,   "too many routes" },
1575         { NBRF_NOTPRUNING,      "not pruning?" },
1576 };
1577
1578 /*
1579  * Print the contents of the uvifs array on file 'fp'.
1580  */
1581 void
1582 dump_vifs(FILE *fp)
1583 {
1584     vifi_t vifi;
1585     struct uvif *v;
1586     struct listaddr *a;
1587     struct phaddr *p;
1588     struct vif_acl *acl;
1589     int i;
1590     struct sioc_vif_req v_req;
1591     time_t now;
1592     char *label;
1593
1594     time(&now);
1595     fprintf(fp, "vifs_with_neighbors = %d\n", vifs_with_neighbors);
1596
1597     if (vifs_with_neighbors == 1)
1598         fprintf(fp,"[This host is a leaf]\n\n");
1599
1600     fprintf(fp,
1601     "\nVirtual Interface Table\n%s",
1602     "Vif  Name  Local-Address                               ");
1603     fprintf(fp,
1604     "M  Thr  Rate   Flags\n");
1605
1606     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
1607
1608         fprintf(fp, "%2u %6s  %-15s %6s: %-18s %2u %3u  %5u  ",
1609                 vifi,
1610                 v->uv_name,
1611                 inet_fmt(v->uv_lcl_addr, s1),
1612                 (v->uv_flags & VIFF_TUNNEL) ?
1613                         "tunnel":
1614                         "subnet",
1615                 (v->uv_flags & VIFF_TUNNEL) ?
1616                         inet_fmt(v->uv_rmt_addr, s2) :
1617                         inet_fmts(v->uv_subnet, v->uv_subnetmask, s3),
1618                 v->uv_metric,
1619                 v->uv_threshold,
1620                 v->uv_rate_limit);
1621
1622         for (i = 0; i < sizeof(vifflags) / sizeof(struct vnflags); i++)
1623                 if (v->uv_flags & vifflags[i].vn_flag)
1624                         fprintf(fp, " %s", vifflags[i].vn_name);
1625
1626         fprintf(fp, "\n");
1627         /*
1628         fprintf(fp, "                          #routes: %d\n", v->uv_nroutes);
1629         */
1630         if (v->uv_admetric != 0)
1631             fprintf(fp, "                                        advert-metric %2u\n",
1632                 v->uv_admetric);
1633
1634         label = "alternate subnets:";
1635         for (p = v->uv_addrs; p; p = p->pa_next) {
1636             fprintf(fp, "                %18s %s\n", label,
1637                         inet_fmts(p->pa_subnet, p->pa_subnetmask, s1));
1638             label = "";
1639         }
1640
1641         label = "peers:";
1642         for (a = v->uv_neighbors; a != NULL; a = a->al_next) {
1643             fprintf(fp, "                            %6s %s (%d.%d) [%d]",
1644                     label, inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv,
1645                     a->al_index);
1646             for (i = 0; i < sizeof(nbrflags) / sizeof(struct vnflags); i++)
1647                     if (a->al_flags & nbrflags[i].vn_flag)
1648                             fprintf(fp, " %s", nbrflags[i].vn_name);
1649             fprintf(fp, " up %s\n", scaletime(now - a->al_ctime));
1650             /*fprintf(fp, " #routes %d\n", a->al_nroutes);*/
1651             label = "";
1652         }
1653
1654         label = "group host (time left):";
1655         for (a = v->uv_groups; a != NULL; a = a->al_next) {
1656             fprintf(fp, "           %23s %-15s %-15s (%s)\n",
1657                     label,
1658                     inet_fmt(a->al_addr, s1),
1659                     inet_fmt(a->al_reporter, s2),
1660                     scaletime(timer_leftTimer(a->al_timerid)));
1661             label = "";
1662         }
1663         label = "boundaries:";
1664         for (acl = v->uv_acl; acl != NULL; acl = acl->acl_next) {
1665             fprintf(fp, "                       %11s %-18s\n", label,
1666                         inet_fmts(acl->acl_addr, acl->acl_mask, s1));
1667             label = "";
1668         }
1669         if (v->uv_filter) {
1670             struct vf_element *vfe;
1671             char lbuf[100];
1672
1673             sprintf(lbuf, "%5s %7s filter:",
1674                         v->uv_filter->vf_flags & VFF_BIDIR ? "bidir"
1675                                                            : "     ",
1676                         v->uv_filter->vf_type == VFT_ACCEPT ? "accept"
1677                                                             : "deny");
1678             label = lbuf;
1679             for (vfe = v->uv_filter->vf_filter;
1680                                         vfe != NULL; vfe = vfe->vfe_next) {
1681                 fprintf(fp, "           %23s %-18s%s\n",
1682                         label,
1683                         inet_fmts(vfe->vfe_addr, vfe->vfe_mask, s1),
1684                         vfe->vfe_flags & VFEF_EXACT ? " (exact)" : "");
1685                 label = "";
1686             }
1687         }
1688         if (!(v->uv_flags & (VIFF_TUNNEL|VIFF_DOWN|VIFF_DISABLED))) {
1689             fprintf(fp, "                     IGMP querier: ");
1690             if (v->uv_querier == NULL)
1691                 if (v->uv_flags & VIFF_QUERIER)
1692                     fprintf(fp, "%-18s (this system)\n",
1693                                     inet_fmt(v->uv_lcl_addr, s1));
1694                 else
1695                     fprintf(fp, "NONE - querier election failure?\n");
1696             else
1697                 fprintf(fp, "%-18s up %s last heard %s ago\n",
1698                         inet_fmt(v->uv_querier->al_addr, s1),
1699                         scaletime(now - v->uv_querier->al_ctime),
1700                         scaletime(v->uv_querier->al_timer));
1701         }
1702         if (v->uv_flags & VIFF_BLASTER)
1703             fprintf(fp, "                  blasterbuf size: %dk\n",
1704                         v->uv_blasterlen / 1024);
1705         fprintf(fp, "                      Nbr bitmaps: 0x%08lx%08lx\n",/*XXX*/
1706                         v->uv_nbrmap.hi, v->uv_nbrmap.lo);
1707         if (v->uv_prune_lifetime != 0)
1708             fprintf(fp, "                   Prune Lifetime: %d seconds\n",
1709                                             v->uv_prune_lifetime);
1710
1711         v_req.vifi = vifi;
1712         if (did_final_init)
1713             if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) < 0) {
1714                 dolog(LOG_WARNING, errno,
1715                     "SIOCGETVIFCNT fails on vif %d", vifi);
1716             } else {
1717                 fprintf(fp, "                   pkts/bytes in : %lu/%lu\n",
1718                         v_req.icount, v_req.ibytes);
1719                 fprintf(fp, "                   pkts/bytes out: %lu/%lu\n",
1720                         v_req.ocount, v_req.obytes);
1721             }
1722         fprintf(fp, "\n");
1723     }
1724     fprintf(fp, "\n");
1725 }
1726
1727 /*
1728  * Time out record of a group membership on a vif
1729  */
1730 static void
1731 DelVif(void *arg)
1732 {
1733     cbk_t *cbk = (cbk_t *)arg;
1734     vifi_t vifi = cbk->vifi;
1735     struct uvif *v = &uvifs[vifi];
1736     struct listaddr *a, **anp, *g = cbk->g;
1737
1738     /*
1739      * Group has expired
1740      * delete all kernel cache entries with this group
1741      */
1742     if (g->al_query)
1743         DeleteTimer(g->al_query);
1744
1745     delete_lclgrp(vifi, g->al_addr);
1746
1747     anp = &(v->uv_groups);
1748     while ((a = *anp) != NULL) {
1749         if (a == g) {
1750             *anp = a->al_next;
1751             free((char *)a);
1752         } else {
1753             anp = &a->al_next;
1754         }
1755     }
1756
1757     free(cbk);
1758 }
1759
1760 /*
1761  * Set a timer to delete the record of a group membership on a vif.
1762  */
1763 static int
1764 SetTimer(vifi_t vifi, struct listaddr *g)
1765 {
1766     cbk_t *cbk;
1767
1768     cbk = (cbk_t *) malloc(sizeof(cbk_t));
1769     cbk->g = g;
1770     cbk->vifi = vifi;
1771     return timer_setTimer(g->al_timer, DelVif, cbk);
1772 }
1773
1774 /*
1775  * Delete a timer that was set above.
1776  */
1777 static int
1778 DeleteTimer(int id)
1779 {
1780     timer_clearTimer(id);
1781     return 0;
1782 }
1783
1784 /*
1785  * Send a group-specific query.
1786  */
1787 static void
1788 SendQuery(void *arg)
1789 {
1790     cbk_t *cbk = (cbk_t *)arg;
1791     struct uvif *v = &uvifs[cbk->vifi];
1792
1793     send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
1794               IGMP_MEMBERSHIP_QUERY,
1795               cbk->q_time, cbk->g->al_addr, 0);
1796     cbk->g->al_query = 0;
1797     free(cbk);
1798 }
1799
1800 /*
1801  * Set a timer to send a group-specific query.
1802  */
1803 static int
1804 SetQueryTimer(struct listaddr *g, vifi_t vifi, int to_expire, int q_time)
1805 {
1806     cbk_t *cbk;
1807
1808     cbk = (cbk_t *) malloc(sizeof(cbk_t));
1809     cbk->g = g;
1810     cbk->q_time = q_time;
1811     cbk->vifi = vifi;
1812     return timer_setTimer(to_expire, SendQuery, cbk);
1813 }