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