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