from netbsd; update to mrouted 3.8
authorderaadt <deraadt@openbsd.org>
Thu, 14 Dec 1995 01:45:19 +0000 (01:45 +0000)
committerderaadt <deraadt@openbsd.org>
Thu, 14 Dec 1995 01:45:19 +0000 (01:45 +0000)
25 files changed:
usr.sbin/map-mbone/mapper.c
usr.sbin/mrinfo/mrinfo.c
usr.sbin/mrouted/Makefile
usr.sbin/mrouted/callout.c
usr.sbin/mrouted/cfparse.y
usr.sbin/mrouted/config.c
usr.sbin/mrouted/defs.h
usr.sbin/mrouted/dvmrp.h
usr.sbin/mrouted/igmp.c
usr.sbin/mrouted/inet.c
usr.sbin/mrouted/kern.c
usr.sbin/mrouted/main.c
usr.sbin/mrouted/mrouted.8
usr.sbin/mrouted/pathnames.h
usr.sbin/mrouted/prune.c
usr.sbin/mrouted/prune.h
usr.sbin/mrouted/route.c
usr.sbin/mrouted/route.h
usr.sbin/mrouted/rsrr.c
usr.sbin/mrouted/snmp.c
usr.sbin/mrouted/snmp.h
usr.sbin/mrouted/vif.c
usr.sbin/mrouted/vif.h
usr.sbin/mtrace/mtrace.8
usr.sbin/mtrace/mtrace.c

index e58b0fb..7a273d0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: mapper.c,v 1.2 1995/10/03 23:16:56 thorpej Exp $       */
+/*     $NetBSD: mapper.c,v 1.3 1995/12/10 11:12:04 mycroft Exp $       */
 
 /* Mapper for connections between MRouteD multicast routers.
  * Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
 #include <netdb.h>
 #include <sys/time.h>
 #include "defs.h"
+#include <arpa/inet.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
 
 #define DEFAULT_TIMEOUT        2       /* How long to wait before retrying requests */
 #define DEFAULT_RETRIES 1      /* How many times to ask each router */
@@ -68,6 +74,23 @@ int  show_names = TRUE;
 vifi_t  numvifs;               /* to keep loader happy */
                                /* (see COPY_TABLES macro called in kern.c) */
 
+Node *                 find_node __P((u_int32_t addr, Node **ptr));
+Interface *            find_interface __P((u_int32_t addr, Node *node));
+Neighbor *             find_neighbor __P((u_int32_t addr, Node *node));
+int                    main __P((int argc, char *argv[]));
+void                   ask __P((u_int32_t dst));
+void                   ask2 __P((u_int32_t dst));
+int                    retry_requests __P((Node *node));
+char *                 inet_name __P((u_int32_t addr));
+void                   print_map __P((Node *node));
+char *                 graph_name __P((u_int32_t addr, char *buf));
+void                   graph_edges __P((Node *node));
+void                   elide_aliases __P((Node *node));
+void                   graph_map __P((void));
+int                    get_number __P((int *var, int deflt, char ***pargv,
+                                               int *pargc));
+u_int32_t                      host_addr __P((char *name));
+
 
 Node *find_node(addr, ptr)
     u_int32_t addr;
@@ -135,12 +158,27 @@ Neighbor *find_neighbor(addr, node)
  * message and the current debug level.  For errors of severity LOG_ERR or
  * worse, terminate the program.
  */
-void log(severity, syserr, format, a, b, c, d, e)
-    int severity, syserr;
-    char *format;
-    int a, b, c, d, e;
+#ifdef __STDC__
+void
+log(int severity, int syserr, char *format, ...)
 {
-    char fmt[100];
+       va_list ap;
+       char    fmt[100];
+
+       va_start(ap, format);
+#else
+/*VARARGS3*/
+void 
+log(severity, syserr, format, va_alist)
+       int     severity, syserr;
+       char   *format;
+       va_dcl
+{
+       va_list ap;
+       char    fmt[100];
+
+       va_start(ap);
+#endif
 
     switch (debug) {
        case 0: if (severity > LOG_WARNING) return;
@@ -151,7 +189,7 @@ void log(severity, syserr, format, a, b, c, d, e)
            if (severity == LOG_WARNING)
                strcat(fmt, "warning - ");
            strncat(fmt, format, 80);
-           fprintf(stderr, fmt, a, b, c, d, e);
+           vfprintf(stderr, fmt, ap);
            if (syserr == 0)
                fprintf(stderr, "\n");
            else if (syserr < sys_nerr)
@@ -186,8 +224,9 @@ void ask2(dst)
 /*
  * Process an incoming group membership report.
  */
-void accept_group_report(src, dst, group)
+void accept_group_report(src, dst, group, r_type)
     u_int32_t src, dst, group;
+    int r_type;
 {
     log(LOG_INFO, 0, "ignoring IGMP group membership report from %s to %s",
        inet_fmt(src, s1), inet_fmt(dst, s2));
@@ -197,8 +236,10 @@ void accept_group_report(src, dst, group)
 /*
  * Process an incoming neighbor probe message.
  */
-void accept_probe(src, dst)
-    u_int32_t src, dst;
+void accept_probe(src, dst, p, datalen, level)
+    u_int32_t src, dst, level;
+    char *p;
+    int datalen;
 {
     log(LOG_INFO, 0, "ignoring DVMRP probe from %s to %s",
        inet_fmt(src, s1), inet_fmt(dst, s2));
@@ -208,8 +249,8 @@ void accept_probe(src, dst)
 /*
  * Process an incoming route report message.
  */
-void accept_report(src, dst, p, datalen)
-    u_int32_t src, dst;
+void accept_report(src, dst, p, datalen, level)
+    u_int32_t src, dst, level;
     char *p;
     int datalen;
 {
@@ -260,8 +301,8 @@ void accept_neighbors(src, dst, p, datalen, level)
 
     /* if node is running a recent mrouted, ask for additional info */
     if (level != 0) {
-       node->version = ntohl(level);
-       node->tries = 0;
+       node->version = level;
+       node->tries = 1;
        ask2(src);
        return;
     }
@@ -333,7 +374,7 @@ void accept_neighbors(src, dst, p, datalen, level)
                    for (nb_n = old_neighbors; nb_n; nb_n = nb_n->next)
                        if (nb_i->addr == nb_n->addr) {
                            if (nb_i->metric != nb_n->metric
-                               || nb_i->threshold != nb_i->threshold)
+                               || nb_i->threshold != nb_n->threshold)
                                log(LOG_WARNING, 0,
                                    "inconsistent %s for neighbor %s of %s",
                                    "metric/threshold",
@@ -404,12 +445,14 @@ void accept_neighbors(src, dst, p, datalen, level)
     }
 }
 
-void accept_neighbors2(src, dst, p, datalen)
-    u_int32_t src, dst;
+void accept_neighbors2(src, dst, p, datalen, level)
+    u_int32_t src, dst, level;
     u_char *p;
     int datalen;
 {
     Node       *node = find_node(src, &routers);
+    u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
+    /* well, only possibly_broken_cisco, but that's too long to type. */
 
     if (node->tries == 0)      /* Never heard of 'em; must have hit them at */
        node->tries = 1;        /* least once, though...*/
@@ -437,6 +480,11 @@ void accept_neighbors2(src, dst, p, datalen)
        ncount = *p++;
        datalen -= 4 + 4;
 
+       if (broken_cisco && ncount == 0)        /* dumb Ciscos */
+               ncount = 1;
+       if (broken_cisco && ncount > 15)        /* dumb Ciscos */
+               ncount = ncount & 0xf;
+
        /* Fix up any alias information */
        ifc_node = find_node(ifc_addr, &routers);
        if (ifc_node->tries == 0) { /* new node */
@@ -496,7 +544,7 @@ void accept_neighbors2(src, dst, p, datalen)
        old_neighbors = ifc->neighbors;
        
        /* Add the neighbors for this interface */
-       while (ncount--) {
+       while (ncount-- && datalen > 0) {
            u_int32_t   neighbor;
            Neighbor   *nb;
            Node       *n_node;
@@ -796,11 +844,7 @@ int main(argc, argv)
 {
     int flood = FALSE, graph = FALSE;
     
-#ifdef SYSV
-    setvbuf(stderr, NULL, _IOLBF, 0);
-#else
     setlinebuf(stderr);
-#endif
 
     if (geteuid() != 0) {
        fprintf(stderr, "must be root\n");
@@ -937,24 +981,54 @@ int main(argc, argv)
     exit(0);
 }
 
-void accept_prune()
+/* dummies */
+void accept_prune(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
+{
+}
+void accept_graft(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
+{
+}
+void accept_g_ack(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
 {
 }
-void accept_graft()
+void add_table_entry(origin, mcastgrp)
+       u_int32_t origin, mcastgrp;
 {
 }
-void accept_g_ack()
+void accept_leave_message(src, dst, group)
+       u_int32_t src, dst, group;
 {
 }
-void add_table_entry()
+void accept_mtrace(src, dst, group, data, no, datalen)
+       u_int32_t src, dst, group;
+       char *data;
+       u_int no;
+       int datalen;
 {
 }
-void accept_leave_message()
+void accept_membership_query(src, dst, group, tmo)
+       u_int32_t src, dst, group;
+       int tmo;
 {
 }
-void accept_mtrace()
+void accept_info_request(src, dst, p, datalen)
+       u_int32_t src, dst;
+       u_char *p;
+       int datalen;
 {
 }
-void accept_membership_query()
+void accept_info_reply(src, dst, p, datalen)
+       u_int32_t src, dst;
+       u_char *p;
+       int datalen;
 {
 }
index 20bd54f..e8cfc4f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: mrinfo.c,v 1.3 1995/10/03 23:20:45 thorpej Exp $       */
+/*     $NetBSD: mrinfo.c,v 1.4 1995/12/10 11:00:51 mycroft Exp $       */
 
 /*
  * This tool requests configuration info from a multicast router
@@ -63,7 +63,7 @@
 
 #ifndef lint
 static char rcsid[] =
-    "@(#) $NetBSD: mrinfo.c,v 1.3 1995/10/03 23:20:45 thorpej Exp $";
+    "@(#) $NetBSD: mrinfo.c,v 1.4 1995/12/10 11:00:51 mycroft Exp $";
 /*  original rcsid:
     "@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
 */
@@ -74,6 +74,11 @@ static char rcsid[] =
 #include <sys/time.h>
 #include "defs.h"
 #include <arpa/inet.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
 
 #define DEFAULT_TIMEOUT        4       /* How long to wait before retrying requests */
 #define DEFAULT_RETRIES 3      /* How many times to ask each router */
@@ -83,10 +88,22 @@ int     debug = 0;
 int    nflag = 0;
 int     retries = DEFAULT_RETRIES;
 int     timeout = DEFAULT_TIMEOUT;
-int    target_level;
+int    target_level = 0;
 vifi_t  numvifs;               /* to keep loader happy */
                                /* (see COPY_TABLES macro called in kern.c) */
 
+char *                 inet_name __P((u_int32_t addr));
+void                   ask __P((u_int32_t dst));
+void                   ask2 __P((u_int32_t dst));
+int                    get_number __P((int *var, int deflt, char ***pargv,
+                                       int *pargc));
+u_int32_t                      host_addr __P((char *name));
+void                   usage __P((void));
+
+/* to shut up -Wstrict-prototypes */
+int                    main __P((int argc, char *argv[]));
+
+
 char   *
 inet_name(addr)
        u_int32_t  addr;
@@ -110,14 +127,26 @@ inet_name(addr)
  * message and the current debug level.  For errors of severity LOG_ERR or
  * worse, terminate the program.
  */
+#ifdef __STDC__
+void
+log(int severity, int syserr, char *format, ...)
+{
+       va_list ap;
+       char    fmt[100];
+
+       va_start(ap, format);
+#else
 void 
-log(severity, syserr, format, a, b, c, d, e)
+log(severity, syserr, format, va_alist)
        int     severity, syserr;
        char   *format;
-       int     a, b, c, d, e;
+       va_dcl
 {
+       va_list ap;
        char    fmt[100];
 
+       va_start(ap);
+#endif
        switch (debug) {
        case 0:
                if (severity > LOG_WARNING)
@@ -133,7 +162,7 @@ log(severity, syserr, format, a, b, c, d, e)
                if (severity == LOG_WARNING)
                        strcat(fmt, "warning - ");
                strncat(fmt, format, 80);
-               fprintf(stderr, fmt, a, b, c, d, e);
+               vfprintf(stderr, fmt, ap);
                if (syserr == 0)
                        fprintf(stderr, "\n");
                else if (syserr < sys_nerr)
@@ -169,9 +198,9 @@ ask2(dst)
  * Process an incoming neighbor-list message.
  */
 void 
-accept_neighbors(src, dst, p, datalen)
-       u_int32_t  src, dst;
-       u_char *p;
+accept_neighbors(src, dst, p, datalen, level)
+       u_int32_t       src, dst, level;
+       u_char  *p;
        int     datalen;
 {
        u_char *ep = p + datalen;
@@ -202,17 +231,22 @@ accept_neighbors(src, dst, p, datalen)
 }
 
 void 
-accept_neighbors2(src, dst, p, datalen)
-       u_int32_t  src, dst;
-       u_char *p;
+accept_neighbors2(src, dst, p, datalen, level)
+       u_int32_t       src, dst, level;
+       u_char  *p;
        int     datalen;
 {
        u_char *ep = p + datalen;
-       u_int broken_cisco = ((target_level & 0xffff) == 0x020a); /* 10.2 */
+       u_int broken_cisco = ((level & 0xffff) == 0x020a); /* 10.2 */
        /* well, only possibly_broken_cisco, but that's too long to type. */
 
-       printf("%s (%s) [version %d.%d]:\n", inet_fmt(src, s1), inet_name(src),
-              target_level & 0xff, (target_level >> 8) & 0xff);
+       printf("%s (%s) [version %d.%d", inet_fmt(src, s1), inet_name(src),
+              level & 0xff, (level >> 8) & 0xff);
+       if ((level >> 16) & NF_LEAF)   { printf (",leaf"); }
+       if ((level >> 16) & NF_PRUNE)  { printf (",prune"); }
+       if ((level >> 16) & NF_GENID)  { printf (",genid"); }
+       if ((level >> 16) & NF_MTRACE) { printf (",mtrace"); }
+       printf ("]:\n");
        
        while (p < ep) {
                register u_char metric;
@@ -281,23 +315,6 @@ get_number(var, deflt, pargv, pargc)
        }
 }
 
-u_int32_t 
-host_addr(name)
-       char   *name;
-{
-       struct hostent *e;
-       u_int32_t               addr;
-
-       addr = inet_addr(name);
-       if ((int)addr == -1) {
-               e = gethostbyname(name);
-               if (e == NULL || e->h_length != sizeof(addr))
-                       return (0);
-               memcpy(&addr, e->h_addr_list[0], e->h_length);
-       }
-       return(addr);
-}
-
 void
 usage()
 {
@@ -311,6 +328,14 @@ main(argc, argv)
        int     argc;
        char   *argv[];
 {
+       int tries;
+       int trynew;
+       struct timeval et;
+       struct hostent *hp;
+       struct hostent bogus;
+       char *host;
+       int curaddr;
+
        setlinebuf(stderr);
 
        if (geteuid() != 0) {
@@ -343,11 +368,21 @@ main(argc, argv)
        if (argc > 1)
                usage();
        if (argc == 1)
-               target_addr = host_addr(argv[0]);
+               host = argv[0];
        else
-               target_addr = host_addr("127.0.0.1");
-
-       if (target_addr == 0) {
+               host = "127.0.0.1";
+
+       if ((target_addr = inet_addr(host)) != -1) {
+               hp = &bogus;
+               hp->h_length = sizeof(target_addr);
+               hp->h_addr_list = (char **)malloc(2 * sizeof(char *));
+               hp->h_addr_list[0] = malloc(hp->h_length);
+               memcpy(hp->h_addr_list[0], &target_addr, hp->h_length);
+               hp->h_addr_list[1] = 0;
+       } else
+               hp = gethostbyname(host);
+
+       if (hp == NULL) {
                fprintf(stderr, "mrinfo: %s: no such host\n", argv[0]);
                exit(1);
        }
@@ -356,7 +391,10 @@ main(argc, argv)
 
        init_igmp();
 
-       {                       /* Find a good local address for us. */
+       /* Check all addresses; mrouters often have unreachable interfaces */
+       for (curaddr = 0; hp->h_addr_list[curaddr] != NULL; curaddr++) {
+           memcpy(&target_addr, hp->h_addr_list[curaddr], hp->h_length);
+           {                   /* Find a good local address for us. */
                int     udp;
                struct sockaddr_in addr;
                int     addrlen = sizeof(addr);
@@ -376,14 +414,24 @@ main(argc, argv)
                }
                close(udp);
                our_addr = addr.sin_addr.s_addr;
-       }
-
-       ask(target_addr);
-
-       /* Main receive loop */
-       for (;;) {
+           }
+
+           tries = 0;
+           trynew = 1;
+           /*
+            * New strategy: send 'ask2' for two timeouts, then fall back
+            * to 'ask', since it's not very likely that we are going to
+            * find someone who only responds to 'ask' these days
+            */
+           ask2(target_addr);
+
+           gettimeofday(&et, 0);
+           et.tv_sec += timeout;
+
+           /* Main receive loop */
+           for (;;) {
                fd_set  fds;
-               struct timeval tv;
+               struct timeval tv, now;
                int     count, recvlen, dummy = 0;
                register u_int32_t src, dst, group;
                struct ip *ip;
@@ -393,8 +441,16 @@ main(argc, argv)
                FD_ZERO(&fds);
                FD_SET(igmp_socket, &fds);
 
-               tv.tv_sec = timeout;
-               tv.tv_usec = 0;
+               gettimeofday(&now, 0);
+               tv.tv_sec = et.tv_sec - now.tv_sec;
+               tv.tv_usec = et.tv_usec - now.tv_usec;
+
+               if (tv.tv_usec < 0) {
+                       tv.tv_usec += 1000000L;
+                       --tv.tv_sec;
+               }
+               if (tv.tv_sec < 0)
+                       tv.tv_sec = tv.tv_usec = 0;
 
                count = select(igmp_socket + 1, &fds, 0, 0, &tv);
 
@@ -404,12 +460,19 @@ main(argc, argv)
                        continue;
                } else if (count == 0) {
                        log(LOG_DEBUG, 0, "Timed out receiving neighbor lists");
-                       if (--retries < 0)
-                               exit(1);
-                       if (target_level == 0)
+                       if (++tries > retries)
+                               break;
+                       /* If we've tried ASK_NEIGHBORS2 twice with
+                        * no response, fall back to ASK_NEIGHBORS
+                        */
+                       if (tries == 2 && target_level == 0)
+                               trynew = 0;
+                       if (target_level == 0 && trynew == 0)
                                ask(target_addr);
                        else
                                ask2(target_addr);
+                       gettimeofday(&et, 0);
+                       et.tv_sec += timeout;
                        continue;
                }
                recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
@@ -434,19 +497,19 @@ main(argc, argv)
                iphdrlen = ip->ip_hl << 2;
                ipdatalen = ip->ip_len;
                if (iphdrlen + ipdatalen != recvlen) {
-                       log(LOG_WARNING, 0,
-                           "packet shorter (%u bytes) than hdr+data length (%u+%u)",
-                           recvlen, iphdrlen, ipdatalen);
-                       continue;
+                   log(LOG_WARNING, 0,
+                     "packet shorter (%u bytes) than hdr+data length (%u+%u)",
+                     recvlen, iphdrlen, ipdatalen);
+                   continue;
                }
                igmp = (struct igmp *) (recv_buf + iphdrlen);
                group = igmp->igmp_group.s_addr;
                igmpdatalen = ipdatalen - IGMP_MINLEN;
                if (igmpdatalen < 0) {
-                       log(LOG_WARNING, 0,
-                           "IP data field too short (%u bytes) for IGMP, from %s",
-                           ipdatalen, inet_fmt(src, s1));
-                       continue;
+                   log(LOG_WARNING, 0,
+                       "IP data field too short (%u bytes) for IGMP, from %s",
+                       ipdatalen, inet_fmt(src, s1));
+                   continue;
                }
                if (igmp->igmp_type != IGMP_DVMRP)
                        continue;
@@ -476,57 +539,98 @@ main(argc, argv)
                                        ask2(target_addr);
                                }
                        } else {
-                               accept_neighbors(src, dst, (char *)(igmp + 1),
-                                                igmpdatalen);
+                               accept_neighbors(src, dst, (u_char *)(igmp + 1),
+                                                igmpdatalen, ntohl(group));
                                exit(0);
                        }
                        break;
 
                case DVMRP_NEIGHBORS2:
-                       accept_neighbors2(src, dst, (char *)(igmp + 1),
-                                         igmpdatalen);
+                       accept_neighbors2(src, dst, (u_char *)(igmp + 1),
+                                         igmpdatalen, ntohl(group));
                        exit(0);
                }
+           }
        }
+       exit(1);
 }
 
 /* dummies */
-void accept_probe()
+void accept_probe(src, dst, p, datalen, level)
+       u_int32_t src, dst, level;
+       char *p;
+       int datalen;
 {
 }
-void accept_group_report()
+void accept_group_report(src, dst, group, r_type)
+       u_int32_t src, dst, group;
+       int r_type;
 {
 }
-void accept_neighbor_request2()
+void accept_neighbor_request2(src, dst)
+       u_int32_t src, dst;
 {
 }
-void accept_report()
+void accept_report(src, dst, p, datalen, level)
+       u_int32_t src, dst, level;
+       char *p;
+       int datalen;
 {
 }
-void accept_neighbor_request()
+void accept_neighbor_request(src, dst)
+       u_int32_t src, dst;
 {
 }
-void accept_prune()
+void accept_prune(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
 {
 }
-void accept_graft()
+void accept_graft(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
 {
 }
-void accept_g_ack()
+void accept_g_ack(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
 {
 }
-void add_table_entry()
+void add_table_entry(origin, mcastgrp)
+       u_int32_t origin, mcastgrp;
 {
 }
 void check_vif_state()
 {
 }
-void accept_leave_message()
+void accept_leave_message(src, dst, group)
+       u_int32_t src, dst, group;
+{
+}
+void accept_mtrace(src, dst, group, data, no, datalen)
+       u_int32_t src, dst, group;
+       char *data;
+       u_int no;
+       int datalen;
 {
 }
-void accept_mtrace()
+void accept_membership_query(src, dst, group, tmo)
+       u_int32_t src, dst, group;
+       int tmo;
 {
 }
-void accept_membership_query()
+void accept_info_request(src, dst, p, datalen)
+       u_int32_t src, dst;
+       u_char *p;
+       int datalen;
+{
+}
+void accept_info_reply(src, dst, p, datalen)
+       u_int32_t src, dst;
+       u_char *p;
+       int datalen;
 {
 }
index fc24ca1..9b64d2e 100644 (file)
@@ -1,9 +1,9 @@
-#      $NetBSD: Makefile,v 1.5 1995/10/09 03:51:32 thorpej Exp $
+#      $NetBSD: Makefile,v 1.7 1995/12/10 10:08:37 mycroft Exp $
 #      from: Id: Makefile,v 1.5 1993/06/24 05:11:16 deering Exp
 
 PROG=  mrouted
-SRCS=  igmp.c inet.c kern.c config.c cfparse.c main.c route.c vif.c \
-       prune.c callout.c
+SRCS=  callout.c cfparse.c config.c igmp.c inet.c kern.c main.c prune.c \
+       route.c vif.c
 MAN=   mrouted.8
 
 CLEANFILES+= cfparse.c y.tab.h
index 943ace5..9c3acf0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: callout.c,v 1.2 1995/10/09 03:51:34 thorpej Exp $      */
+/*     $NetBSD: callout.c,v 1.3 1995/12/10 10:06:56 mycroft Exp $      */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
 static int id = 0;
 static struct timeout_q  *Q = 0; /* pointer to the beginning of timeout queue */
 
-static int in_callout= 0;
-
-typedef void (* cfunc_t)();
+static int in_callout = 0;
 
 struct timeout_q {
        struct timeout_q *next;         /* next event */
        int              id;  
-       cfunc_t          func ;         /* function to call */
+       cfunc_t          func         /* function to call */
        char             *data;         /* func's data */
        int              time;          /* time offset to next event*/
 };
 
-static void print_Q();
+#ifdef IGMP_DEBUG
+static void print_Q __P((void));
+#else
+#define        print_Q()       
+#endif
 
-void callout_init()
+void
+callout_init()
 {
     Q = (struct timeout_q *) 0;
 }
@@ -38,7 +41,8 @@ void callout_init()
 /*
  * signal handler for SIGALARM that is called once every second
  */
-void age_callout_queue()
+void
+age_callout_queue()
 {
     struct timeout_q *ptr;
     
@@ -48,12 +52,15 @@ void age_callout_queue()
     in_callout = 1;
     ptr = Q;
     
-    while (ptr){
-       if (!ptr->time ) {
+    while (ptr) {
+       if (!ptr->time) {
            /* timeout has happened */
-           if(ptr->func)
-               ptr->func(ptr->data);
            Q = Q->next;
+
+           in_callout = 0;
+           if (ptr->func)
+               ptr->func(ptr->data);
+           in_callout = 1;
            
            free(ptr);
            ptr = Q;
@@ -62,7 +69,7 @@ void age_callout_queue()
            ptr->time --;
 #ifdef IGMP_DEBUG
            log(LOG_DEBUG,0,"[callout, age_callout_queue] -- time (%d)", ptr->time);
-#endif IGMP_DEBUG
+#endif /* IGMP_DEBUG */
            in_callout = 0; return;
        }
     }
@@ -74,7 +81,8 @@ void age_callout_queue()
 /* 
  * sets the timer
  */
-int timer_setTimer(delay, action, data)
+int
+timer_setTimer(delay, action, data)
     int        delay;          /* number of units for timeout */
     cfunc_t    action;         /* function to be called on timeout */
     char       *data;          /* what to call the timeout function with */
@@ -87,7 +95,7 @@ int timer_setTimer(delay, action, data)
     in_callout = 1;
     
     /* create a node */        
-    node   = (struct timeout_q *)malloc(sizeof(struct timeout_q));
+    node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
     if (node == 0) {
        log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
        in_callout = 0;
@@ -108,9 +116,9 @@ int timer_setTimer(delay, action, data)
        Q = node;
     else {
        /* chase the pointer looking for the right place */
-       while (ptr){
+       while (ptr) {
            
-           if (delay < ptr->time){
+           if (delay < ptr->time) {
                /* right place */
                
                node->next = ptr;
@@ -122,8 +130,7 @@ int timer_setTimer(delay, action, data)
                print_Q();
                in_callout = 0;
                return node->id;
-           }
-           else  {
+           } else  {
                /* keep moving */
                
                delay -= ptr->time; node->time = delay;
@@ -140,17 +147,19 @@ int timer_setTimer(delay, action, data)
 
 
 /* clears the associated timer */
-void timer_clearTimer( timer_id)
+void
+timer_clearTimer(timer_id)
     int  timer_id;
 {
     struct timeout_q  *ptr, *prev;
     
-    if (in_callout)  return;
+    if (in_callout)
+        return;
+    if (!timer_id)
+       return;
+
     in_callout = 1;
     
-    
-    if ( !timer_id ) {in_callout = 0; return;}
-    
     prev = ptr = Q;
     
     /*
@@ -159,12 +168,12 @@ void timer_clearTimer( timer_id)
      */
     
     print_Q();
-    while (ptr){
-       if (ptr->id == timer_id){
+    while (ptr) {
+       if (ptr->id == timer_id) {
            /* got the right node */
            
            /* unlink it from the queue */
-           if ( ptr == Q)
+           if (ptr == Q)
                Q = Q->next;
            else
                prev->next = ptr->next;
@@ -186,16 +195,31 @@ void timer_clearTimer( timer_id)
     in_callout = 0;
 }
 
+#ifdef IGMP_DEBUG
 /*
  * debugging utility
  */
-static void print_Q()
+static void
+print_Q()
 {
-#ifdef IGMP_DEBUG
     struct timeout_q  *ptr;
     
     for(ptr = Q; ptr; ptr = ptr->next)
        log(LOG_DEBUG,0,"(%d,%d) ", ptr->id, ptr->time);
-#endif IGMP_DEBUG
 }
+#endif /* IGMP_DEBUG */
+int
+secs_remaining( timer_id)
+    int  timer_id;
+{
+    struct timeout_q  *ptr;
+    int left=0;
+
+    for (ptr = Q; ptr && ptr->id != timer_id; ptr = ptr->next)
+       left += ptr->time;
 
+    if (!ptr) /* not found */
+       return 0;
+
+    return left + ptr->time;
+}
index 9538200..00608f8 100644 (file)
@@ -1,5 +1,5 @@
 %{
-/*     $NetBSD: cfparse.y,v 1.3 1995/10/09 03:51:35 thorpej Exp $      */
+/*     $NetBSD: cfparse.y,v 1.4 1995/12/10 10:06:57 mycroft Exp $      */
 
 /*
  * Configuration file parser for mrouted.
@@ -7,9 +7,26 @@
  * Written by Bill Fenner, NRL, 1994
  */
 #include <stdio.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
 #include <string.h>
 #include <varargs.h>
+#endif
 #include "defs.h"
+#include <netdb.h>
+
+/*
+ * Local function declarations
+ */
+static void            fatal __P((char *fmt, ...));
+static void            warn __P((char *fmt, ...));
+static void            yyerror __P((char *s));
+static char *          next_word __P((void));
+static int             yylex __P((void));
+static u_int32_t       valid_if __P((char *s));
+static struct ifreq *  ifconfaddr __P((struct ifconf *ifcp, u_int32_t a));
+int                    yyparse __P((void));
 
 static FILE *f;
 
@@ -54,14 +71,16 @@ int numbounds = 0;                  /* Number of named boundaries */
 
 %token CACHE_LIFETIME PRUNING
 %token PHYINT TUNNEL NAME
-%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET
+%token DISABLE IGMPV1 SRCRT
+%token METRIC THRESHOLD RATE_LIMIT BOUNDARY NETMASK ALTNET
+%token SYSNAM SYSCONTACT SYSVERSION SYSLOCATION
 %token <num> BOOLEAN
 %token <num> NUMBER
 %token <ptr> STRING
 %token <addrmask> ADDRMASK
 %token <addr> ADDR
 
-%type <addr> interface
+%type <addr> interface addrname
 %type <addrmask> bound boundary addrmask
 
 %start conf
@@ -94,10 +113,9 @@ stmt        : error
                            fatal("%s is not a configured interface",
                                inet_fmt($2,s1));
 
-                       /*log(LOG_INFO, 0, "phyint: %x\n", v);*/
                                        }
                ifmods
-       | TUNNEL interface ADDR         {
+       | TUNNEL interface addrname     {
 
                        struct ifreq *ifr;
                        struct ifreq ffr;
@@ -157,7 +175,6 @@ stmt        : error
                            v->uv_flags |= VIFF_DOWN;
                            vifs_down = TRUE;
                        }
-                       /*log(LOG_INFO, 0, "tunnel: %x\n", v);*/
                                        }
                tunnelmods
                                        {
@@ -180,10 +197,30 @@ stmt      : error
                                      strcpy(boundlist[numbounds].name, $2);
                                      boundlist[numbounds++].bound = $3;
                                    }
+       | SYSNAM STRING    {
+#ifdef SNMP
+                           set_sysName($2);
+#endif /* SNMP */
+                           }
+       | SYSCONTACT STRING {
+#ifdef SNMP
+                           set_sysContact($2);
+#endif /* SNMP */
+                           }
+        | SYSVERSION STRING {
+#ifdef SNMP
+                           set_sysVersion($2);
+#endif /* SNMP */
+                           }
+       | SYSLOCATION STRING {
+#ifdef SNMP
+                           set_sysLocation($2);
+#endif /* SNMP */
+                           }
        ;
 
 tunnelmods     : /* empty */
-       | tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod
+       | tunnelmods tunnelmod
        ;
 
 tunnelmod      : mod
@@ -191,12 +228,28 @@ tunnelmod : mod
        ;
 
 ifmods : /* empty */
-       | ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod
+       | ifmods ifmod
        ;
 
 ifmod  : mod
        | DISABLE               { v->uv_flags |= VIFF_DISABLED; }
-       | NETMASK ADDR          { v->uv_subnetmask = $2; }
+       | IGMPV1                { v->uv_flags |= VIFF_IGMPV1; }
+       | NETMASK addrname      {
+                                 u_int32_t subnet, mask;
+
+                                 mask = $2;
+                                 subnet = v->uv_lcl_addr & mask;
+                                 if (!inet_valid_subnet(subnet, mask))
+                                       fatal("Invalid netmask");
+                                 v->uv_subnet = subnet;
+                                 v->uv_subnetmask = mask;
+                                 v->uv_subnetbcast = subnet | ~mask;
+                               }
+       | NETMASK               {
+
+                   warn("Expected address after netmask keyword, ignored");
+
+                               }
        | ALTNET addrmask       {
 
                    struct phaddr *ph;
@@ -205,16 +258,22 @@ ifmod     : mod
                    if (ph == NULL)
                        fatal("out of memory");
                    if ($2.mask) {
-                       VAL_TO_MASK(ph->pa_mask, $2.mask);
+                       VAL_TO_MASK(ph->pa_subnetmask, $2.mask);
                    } else
-                       ph->pa_mask = v->uv_subnetmask;
-                   ph->pa_addr = $2.addr & ph->pa_mask;
-                   if ($2.addr & ~ph->pa_mask)
-                       warn("Extra addr %s/%d has host bits set",
+                       ph->pa_subnetmask = v->uv_subnetmask;
+                   ph->pa_subnet = $2.addr & ph->pa_subnetmask;
+                   ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask;
+                   if ($2.addr & ~ph->pa_subnetmask)
+                       warn("Extra subnet %s/%d has host bits set",
                                inet_fmt($2.addr,s1), $2.mask);
                    ph->pa_next = v->uv_addrs;
                    v->uv_addrs = ph;
 
+                               }
+       | ALTNET                {
+
+                   warn("Expected address after altnet keyword, ignored");
+
                                }
        ;
 
@@ -224,7 +283,7 @@ mod : THRESHOLD NUMBER      { if ($2 < 1 || $2 > 255)
                                }
        | THRESHOLD             {
 
-                   warn("Expected number after threshold keyword");
+                   warn("Expected number after threshold keyword, ignored");
 
                                }
        | METRIC NUMBER         { if ($2 < 1 || $2 > UNREACHABLE)
@@ -233,7 +292,7 @@ mod : THRESHOLD NUMBER      { if ($2 < 1 || $2 > 255)
                                }
        | METRIC                {
 
-                   warn("Expected number after metric keyword");
+                   warn("Expected number after metric keyword, ignored");
 
                                }
        | RATE_LIMIT NUMBER     { if ($2 > MAX_RATE_LIMIT)
@@ -242,7 +301,7 @@ mod : THRESHOLD NUMBER      { if ($2 < 1 || $2 > 255)
                                }
        | RATE_LIMIT            {
 
-                   warn("Expected number after rate_limit keyword");
+                   warn("Expected number after rate_limit keyword, ignored");
 
                                }
        | BOUNDARY bound        {
@@ -263,7 +322,7 @@ mod : THRESHOLD NUMBER      { if ($2 < 1 || $2 > 255)
                                }
        | BOUNDARY              {
 
-                   warn("Expected boundary spec after boundary keyword");
+               warn("Expected boundary spec after boundary keyword, ignored");
 
                                }
        ;
@@ -276,6 +335,20 @@ interface  : ADDR          { $$ = $1; }
                                }
        ;
 
+addrname       : ADDR          { $$ = $1; }
+       | STRING                { struct hostent *hp;
+
+                                 if ((hp = gethostbyname($1)) == NULL)
+                                   fatal("No such host %s", $1);
+
+                                 if (hp->h_addr_list[1])
+                                   fatal("Hostname %s does not %s",
+                                       $1, "map to a unique address");
+
+                                 bcopy(hp->h_addr_list[0], &$$,
+                                           hp->h_length);
+                               }
+
 bound  : boundary              { $$ = $1; }
        | STRING                { int i;
 
@@ -306,8 +379,18 @@ addrmask   : ADDRMASK      { $$ = $1; }
        | ADDR                  { $$.addr = $1; $$.mask = 0; }
        ;
 %%
+#ifdef __STDC__
+static void
+fatal(char *fmt, ...)
+{
+       va_list ap;
+       char buf[200];
+
+       va_start(ap, fmt);
+#else
 /*VARARGS1*/
-static void fatal(fmt, va_alist)
+static void
+fatal(fmt, va_alist)
 char *fmt;
 va_dcl
 {
@@ -315,14 +398,25 @@ va_dcl
        char buf[200];
 
        va_start(ap);
+#endif
        vsprintf(buf, fmt, ap);
        va_end(ap);
 
        log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno);
 }
 
+#ifdef __STDC__
+static void
+warn(char *fmt, ...)
+{
+       va_list ap;
+       char buf[200];
+
+       va_start(ap, fmt);
+#else
 /*VARARGS1*/
-static void warn(fmt, va_alist)
+static void
+warn(fmt, va_alist)
 char *fmt;
 va_dcl
 {
@@ -330,19 +424,22 @@ va_dcl
        char buf[200];
 
        va_start(ap);
+#endif
        vsprintf(buf, fmt, ap);
        va_end(ap);
 
        log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno);
 }
 
-void yyerror(s)
+static void
+yyerror(s)
 char *s;
 {
        log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno);
 }
 
-char *next_word()
+static char *
+next_word()
 {
        static char buf[1024];
        static char *p=NULL;
@@ -363,6 +460,15 @@ char *next_word()
                continue;
            }
            q = p;
+#ifdef SNMP
+       if (*p == '"') {
+          p++;
+              while (*p && *p != '"' && *p != '\n')
+                     p++;              /* find next whitespace */
+          if (*p == '"')
+             p++;
+       } else
+#endif
            while (*p && *p != ' ' && *p != '\t' && *p != '\n')
                p++;            /* find next whitespace */
            *p++ = '\0';        /* null-terminate string */
@@ -376,7 +482,8 @@ char *next_word()
        }
 }
 
-int yylex()
+static int
+yylex()
 {
        int n;
        u_int32_t addr;
@@ -408,10 +515,12 @@ int yylex()
                return BOUNDARY;
        if (!strcmp(q,"netmask"))
                return NETMASK;
-       if (!strcmp(q,"name"))
-               return NAME;
+       if (!strcmp(q,"igmpv1"))
+               return IGMPV1;
        if (!strcmp(q,"altnet"))
                return ALTNET;
+       if (!strcmp(q,"name"))
+               return NAME;
        if (!strcmp(q,"on") || !strcmp(q,"yes")) {
                yylval.num = 1;
                return BOOLEAN;
@@ -443,11 +552,28 @@ int yylex()
                yylval.num = n;
                return NUMBER;
        }
+#ifdef SNMP
+       if (!strcmp(q,"sysName"))
+               return SYSNAM;
+       if (!strcmp(q,"sysContact"))
+               return SYSCONTACT;
+       if (!strcmp(q,"sysVersion"))
+               return SYSVERSION;
+       if (!strcmp(q,"sysLocation"))
+               return SYSLOCATION;
+   if (*q=='"') {
+      if (q[ strlen(q)-1 ]=='"')
+         q[ strlen(q)-1 ]='\0'; /* trash trailing quote */
+      yylval.ptr = q+1;
+      return STRING;
+   }
+#endif
        yylval.ptr = q;
        return STRING;
 }
 
-void config_vifs_from_file()
+void
+config_vifs_from_file()
 {
        extern FILE *f;
 
@@ -468,7 +594,7 @@ void config_vifs_from_file()
 
        yyparse();
 
-       close(f);
+       fclose(f);
 }
 
 static u_int32_t
index 3a4e1bd..39d8f5c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: config.c,v 1.5 1995/10/09 03:51:37 thorpej Exp $       */
+/*     $NetBSD: config.c,v 1.6 1995/12/10 10:06:58 mycroft Exp $       */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -17,7 +17,8 @@
  * Query the kernel to find network interfaces that are multicast-capable
  * and install them in the uvifs array.
  */
-void config_vifs_from_kernel()
+void
+config_vifs_from_kernel()
 {
     struct ifreq ifbuf[32];
     struct ifreq *ifrp, *ifend;
index 8d5aa9c..27172d9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: defs.h,v 1.5 1995/10/09 03:51:38 thorpej Exp $ */
+/*     $NetBSD: defs.h,v 1.6 1995/12/10 10:06:59 mycroft Exp $ */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
  */
 
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <syslog.h>
+#include <signal.h>
+#include <string.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
+#ifdef SYSV
+#include <sys/sockio.h>
+#endif
 #include <sys/time.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #include <netinet/igmp.h>
 #include <netinet/ip_mroute.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <syslog.h>
-#include <signal.h>
 #ifdef RSRR
 #include <sys/un.h>
 #endif /* RSRR */
 
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+typedef void (*cfunc_t) __P((void *));
+typedef void (*ihfunc_t) __P((int, fd_set *));
+
 #include "dvmrp.h"
 #include "vif.h"
 #include "route.h"
@@ -37,6 +54,7 @@
 #include "pathnames.h"
 #ifdef RSRR
 #include "rsrr.h"
+#include "rsrr_var.h"
 #endif /* RSRR */
 
 /*
 
 #define TIMER_INTERVAL ROUTE_MAX_REPORT_DELAY
 
+#define VENDOR_CODE    1   /* Get a new vendor code if you make significant
+                            * changes to mrouted. */
+
 #define PROTOCOL_VERSION 3  /* increment when packet format/content changes */
 
-#define MROUTED_VERSION  5  /* increment on local changes or bug fixes, */
+#define MROUTED_VERSION  8  /* increment on local changes or bug fixes, */
                            /* reset to 0 whever PROTOCOL_VERSION increments */
 
-#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
-                       ((NF_PRUNE | NF_GENID | NF_MTRACE) << 16))
+#define MROUTED_LEVEL  ((MROUTED_VERSION << 8) | PROTOCOL_VERSION | \
+                       ((NF_PRUNE | NF_GENID | NF_MTRACE) << 16) | \
+                       (VENDOR_CODE << 24))
                            /* for IGMP 'group' field of DVMRP messages */
 
 #define LEAF_FLAGS     (( vifs_with_neighbors == 1 ) ? 0x010000 : 0)
@@ -69,6 +91,7 @@
 #define JAN_1970       2208988800UL    /* 1970 - 1900 in seconds */
 #else
 #define JAN_1970       2208988800L     /* 1970 - 1900 in seconds */
+#define const          /**/
 #endif
 
 #ifdef RSRR
 #define BIT_TST(X,n)     ((X) & 1 << (n))
 #endif /* RSRR */
 
+#ifdef SYSV
+#define bcopy(a, b, c) memcpy(b, a, c)
+#define bzero(s, n)    memset((s), 0, (n))
+#define setlinebuf(s)  setvbuf(s, NULL, _IOLBF, 0)
+#define signal(s,f)    sigset(s,f)
+#endif
+
 /*
  * External declarations for global variables and functions.
  */
-#define RECV_BUF_SIZE MAX_IP_PACKET_LEN
+#define RECV_BUF_SIZE 8192
 extern char            *recv_buf;
 extern char            *send_buf;
 extern int             igmp_socket;
@@ -113,118 +143,171 @@ extern char             s2[];
 extern char            s3[];
 extern char            s4[];
 
-extern void            log();
-
-extern void            init_igmp();
-extern void            accept_igmp();
-extern void            send_igmp();
-
-extern void            init_routes();
-extern void            start_route_updates();
-extern void            update_route();
-extern void            age_routes();
-extern void            expire_all_routes();
-extern void            free_all_routes();
-
-extern void            accept_probe();
-extern void            accept_report();
-extern void            report();
-extern void            report_to_all_neighbors();
-extern int             report_next_chunk();
-extern void            add_vif_to_routes();
-extern void            delete_vif_from_routes();
-extern void            delete_neighbor_from_routes();
-extern void            dump_routes();
-
-extern void            init_vifs();
-extern void            check_vif_state();
-extern vifi_t          find_vif();
-extern void            age_vifs();
-extern void            dump_vifs();
-extern void            stop_all_vifs();
-extern struct listaddr *neighbor_info();
-
-extern void            accept_group_report();
-extern void            query_groups();
-extern void            probe_for_neighbors();
-extern int             update_neighbor();
-extern void            accept_neighbor_request();
-extern void            accept_neighbor_request2();
-extern void            accept_neighbors();
-extern void            accept_neighbors2();
-
-extern void            config_vifs_from_kernel();
-extern void            config_vifs_from_file();
-
-extern int             inet_valid_host();
-extern int             inet_valid_subnet();
-extern char *          inet_fmt();
-extern char *          inet_fmts();
-extern u_int32_t       inet_parse();
-extern int             inet_cksum();
-
-extern struct rtentry *        determine_route();
-
-extern void            init_ktable();
-extern void            add_table_entry();
-extern void            del_table_entry();
-extern void            update_table_entry();
-extern void            update_lclgrp();
-extern void            delete_lclgrp();
+#if !(defined(BSD) && (BSD >= 199103))
+extern int             errno;
+extern int             sys_nerr;
+extern char *          sys_errlist[];
+#endif
+
+#ifdef OLD_KERNEL
+#define        MRT_INIT        DVMRP_INIT
+#define        MRT_DONE        DVMRP_DONE
+#define        MRT_ADD_VIF     DVMRP_ADD_VIF
+#define        MRT_DEL_VIF     DVMRP_DEL_VIF
+#define        MRT_ADD_MFC     DVMRP_ADD_MFC
+#define        MRT_DEL_MFC     DVMRP_DEL_MFC
 
+#define        IGMP_PIM        0x14
+#endif
+
+/* main.c */
+extern void            log __P((int, int, char *, ...));
+extern int             register_input_handler __P((int fd, ihfunc_t func));
+
+/* igmp.c */
+extern void            init_igmp __P((void));
+extern void            accept_igmp __P((int recvlen));
+extern void            send_igmp __P((u_int32_t src, u_int32_t dst, int type,
+                                               int code, u_int32_t group,
+                                               int datalen));
+
+/* callout.c */
+extern void            callout_init __P((void));
+extern void            age_callout_queue __P((void));
+extern int             timer_setTimer __P((int delay, cfunc_t action,
+                                               char *data));
+extern void            timer_clearTimer __P((int timer_id));
+
+/* route.c */
+extern void            init_routes __P((void));
+extern void            start_route_updates __P((void));
+extern void            update_route __P((u_int32_t origin, u_int32_t mask,
+                                               u_int metric, u_int32_t src,
+                                               vifi_t vifi));
+extern void            age_routes __P((void));
+extern void            expire_all_routes __P((void));
+extern void            free_all_routes __P((void));
+extern void            accept_probe __P((u_int32_t src, u_int32_t dst,
+                                               char *p, int datalen,
+                                               u_int32_t level));
+extern void            accept_report __P((u_int32_t src, u_int32_t dst,
+                                               char *p, int datalen,
+                                               u_int32_t level));
+extern struct rtentry *        determine_route __P((u_int32_t src));
+extern void            report __P((int which_routes, vifi_t vifi,
+                                               u_int32_t dst));
+extern void            report_to_all_neighbors __P((int which_routes));
+extern int             report_next_chunk __P((void));
+extern void            add_vif_to_routes __P((vifi_t vifi));
+extern void            delete_vif_from_routes __P((vifi_t vifi));
+extern void            delete_neighbor_from_routes __P((u_int32_t addr,
+                                                       vifi_t vifi));
+extern void            dump_routes __P((FILE *fp));
+extern void            start_route_updates __P((void));
+
+/* vif.c */
+extern void            init_vifs __P((void));
+extern void            check_vif_state __P((void));
+extern vifi_t          find_vif __P((u_int32_t src, u_int32_t dst));
+extern void            age_vifs __P((void));
+extern void            dump_vifs __P((FILE *fp));
+extern void            stop_all_vifs __P((void));
+extern struct listaddr *neighbor_info __P((vifi_t vifi, u_int32_t addr));
+extern void            accept_group_report __P((u_int32_t src, u_int32_t dst,
+                                       u_int32_t group, int r_type));
+extern void            query_groups __P((void));
+extern void            probe_for_neighbors __P((void));
+extern int             update_neighbor __P((vifi_t vifi, u_int32_t addr,
+                                       int msgtype, char *p, int datalen,
+                                       u_int32_t level));
+extern void            accept_neighbor_request __P((u_int32_t src, u_int32_t dst));
+extern void            accept_neighbor_request2 __P((u_int32_t src,
+                                       u_int32_t dst));
+extern void            accept_neighbors __P((u_int32_t src, u_int32_t dst,
+                                       u_char *p, int datalen, u_int32_t level));
+extern void            accept_neighbors2 __P((u_int32_t src, u_int32_t dst,
+                                       u_char *p, int datalen, u_int32_t level));
+extern void            accept_leave_message __P((u_int32_t src, u_int32_t dst,
+                                       u_int32_t group));
+extern void            accept_membership_query __P((u_int32_t src, u_int32_t dst,
+                                       u_int32_t group, int tmo));
+
+/* config.c */
+extern void            config_vifs_from_kernel __P((void));
+
+/* cfparse.y */
+extern void            config_vifs_from_file __P((void));
+
+/* inet.c */
+extern int             inet_valid_host __P((u_int32_t naddr));
+extern int             inet_valid_subnet __P((u_int32_t nsubnet, u_int32_t nmask));
+extern char *          inet_fmt __P((u_int32_t addr, char *s));
+extern char *          inet_fmts __P((u_int32_t addr, u_int32_t mask, char *s));
+extern u_int32_t       inet_parse __P((char *s));
+extern int             inet_cksum __P((u_short *addr, u_int len));
+
+/* prune.c */
 extern unsigned                kroutes;
-extern void            accept_prune();
-extern int             no_entry_exists();
-extern int             rtr_cnt();
-extern void            free_all_prunes();
-extern void            age_table_entry();
-extern void            dump_cache();
+extern void            add_table_entry __P((u_int32_t origin, u_int32_t mcastgrp));
+extern void            del_table_entry __P((struct rtentry *r,
+                                       u_int32_t mcastgrp, u_int del_flag));
+extern void            update_table_entry __P((struct rtentry *r));
+extern void            init_ktable __P((void));
+extern void            accept_prune __P((u_int32_t src, u_int32_t dst, char *p,
+                                       int datalen));
+extern void            steal_sources __P((struct rtentry *rt));
+extern void            reset_neighbor_state __P((vifi_t vifi, u_int32_t addr));
+extern int             grplst_mem __P((vifi_t vifi, u_int32_t mcastgrp));
+extern int             scoped_addr __P((vifi_t vifi, u_int32_t addr));
+extern void            free_all_prunes __P((void));
+extern void            age_table_entry __P((void));
+extern void            dump_cache __P((FILE *fp2));
+extern void            update_lclgrp __P((vifi_t vifi, u_int32_t mcastgrp));
+extern void            delete_lclgrp __P((vifi_t vifi, u_int32_t mcastgrp));
+extern void            chkgrp_graft __P((vifi_t vifi, u_int32_t mcastgrp));
+extern void            accept_graft __P((u_int32_t src, u_int32_t dst, char *p,
+                                       int datalen));
+extern void            accept_g_ack __P((u_int32_t src, u_int32_t dst, char *p,
+                                       int datalen));
+/* u_int is promoted u_char */
+extern void            accept_mtrace __P((u_int32_t src, u_int32_t dst,
+                                       u_int32_t group, char *data, u_int no,
+                                       int datalen));
+
+/* kern.c */
+extern void            k_set_rcvbuf __P((int bufsize));
+extern void            k_hdr_include __P((int bool));
+extern void            k_set_ttl __P((int t));
+extern void            k_set_loop __P((int l));
+extern void            k_set_if __P((u_int32_t ifa));
+extern void            k_join __P((u_int32_t grp, u_int32_t ifa));
+extern void            k_leave __P((u_int32_t grp, u_int32_t ifa));
+extern void            k_init_dvmrp __P((void));
+extern void            k_stop_dvmrp __P((void));
+extern void            k_add_vif __P((vifi_t vifi, struct uvif *v));
+extern void            k_del_vif __P((vifi_t vifi));
+extern void            k_add_rg __P((u_int32_t origin, struct gtable *g));
+extern int             k_del_rg __P((u_int32_t origin, struct gtable *g));
+extern int             k_get_version __P((void));
 
 #ifdef SNMP
-extern struct rtentry * snmp_find_route();
-extern struct gtable * find_grp();
-extern struct stable * find_grp_src();
+/* prune.c */
+extern struct rtentry * snmp_find_route __P(());
+extern struct gtable * find_grp __P(());
+extern struct stable * find_grp_src __P(());
 #endif
 
-extern void            chkgrp_graft();
-extern void            accept_graft();
-extern void            accept_g_ack();
-extern void            accept_mtrace();
-extern void            accept_leave_message();
-extern void            accept_membership_query();
 #ifdef RSRR
+/* prune.c */
 extern struct gtable   *kernel_table;
 extern struct gtable   *gtp;
-extern int             find_src_grp();
-extern int             grplst_mem();
-extern int             scoped_addr();
-#endif /* RSRR */
-
-extern void            k_set_rcvbuf();
-extern void            k_hdr_include();
-extern void            k_set_ttl();
-extern void            k_set_loop();
-extern void            k_set_if();
-extern void            k_join();
-extern void            k_leave();
-extern void            k_init_dvmrp();
-extern void            k_stop_dvmrp();
-extern void            k_add_vif();
-extern void            k_del_vif();
-extern void            k_add_rg();
-extern int             k_del_rg();
-extern int             k_get_version();
-
-extern char *          malloc();
-extern char *          fgets();
-extern FILE *          fopen();
-
-#if !defined(htonl) && !defined(__osf__)
-extern u_long          htonl();
-extern u_long          ntohl();
-#endif
-
-#ifdef RSRR
-extern void            rsrr_init();
-extern void            rsrr_read();
+extern int             find_src_grp __P((u_int32_t src, u_int32_t mask,
+                                       u_int32_t grp));
+
+/* rsrr.c */
+extern void            rsrr_init __P((void));
+extern void            rsrr_read __P((int f, fd_set *rfd));
+extern void            rsrr_clean __P((void));
+extern void            rsrr_cache_send __P((struct gtable *gt, int notify));
+extern void            rsrr_cache_clean __P((struct gtable *gt));
 #endif /* RSRR */
index c008dd3..b4f2bf4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: dvmrp.h,v 1.4 1995/10/09 03:51:39 thorpej Exp $        */
+/*     $NetBSD: dvmrp.h,v 1.5 1995/12/10 10:07:00 mycroft Exp $        */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -95,6 +95,8 @@
 #define DVMRP_PRUNE            7       /* prune message */
 #define DVMRP_GRAFT            8       /* graft message */
 #define DVMRP_GRAFT_ACK                9       /* graft acknowledgement */
+#define DVMRP_INFO_REQUEST     10      /* information request */
+#define DVMRP_INFO_REPLY       11      /* information reply */
 
 /*
  * 'flags' byte values in DVMRP_NEIGHBORS2 reply.
 #define DVMRP_NF_QUERIER       0x40    /* I am the subnet's querier */
 #define DVMRP_NF_LEAF          0x80    /* Neighbor reports that it is a leaf */
 
+/*
+ * Request/reply types for info queries/replies
+ */
+#define DVMRP_INFO_VERSION     1       /* version string */
+#define DVMRP_INFO_NEIGHBORS   2       /* neighbors2 data */
+
 /*
  * Limit on length of route data
  */
  */
                                        /* address for multicast DVMRP msgs */
 #define INADDR_DVMRP_GROUP     (u_int32_t)0xe0000004     /* 224.0.0.4 */
+/*
+ * The IGMPv2 <netinet/in.h> defines INADDR_ALLRTRS_GROUP, but earlier
+ * ones don't, so we define it conditionally here.
+ */
+#ifndef INADDR_ALLRTRS_GROUP
                                        /* address for multicast mtrace msg */
 #define INADDR_ALLRTRS_GROUP   (u_int32_t)0xe0000002   /* 224.0.0.2 */
+#endif
 
 #define ROUTE_MAX_REPORT_DELAY 5       /* max delay for reporting changes  */
                                        /*  (This is the timer interrupt    */
 #define GROUP_EXPIRE_TIME      270     /* time to consider group gone      */
 #define LEAVE_EXPIRE_TIME      3       /* " " after receiving a leave      */
 /* Note: LEAVE_EXPIRE_TIME should ideally be shorter, but the resolution of
- * the timer in mrouted doesn't allow us to follow the spec and make it any
- * shorter. */
+ * the timer in mrouted doesn't allow us to make it any shorter. */
 
 #define UNREACHABLE            32      /* "infinity" metric, must be <= 64 */
 #define DEFAULT_METRIC         1       /* default subnet/tunnel metric     */
index f4c19d8..1b623ba 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: igmp.c,v 1.4 1995/10/09 03:51:40 thorpej Exp $ */
+/*     $NetBSD: igmp.c,v 1.5 1995/12/10 10:07:01 mycroft Exp $ */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -24,11 +24,19 @@ u_int32_t   allrtrs_group;               /* All-Routers "  in net order */
 u_int32_t      dvmrp_group;                 /* DVMRP grp addr in net order */
 u_int32_t      dvmrp_genid;                 /* IGMP generation id          */
 
+/*
+ * Local function definitions.
+ */
+/* u_char promoted to u_int */
+static char *  packet_kind __P((u_int type, u_int code));
+static int     igmp_log_level __P((u_int type, u_int code));
+
 /*
  * Open and initialize the igmp socket, and fill in the non-changing
  * IP header fields in the output packet buffer.
  */
-void init_igmp()
+void
+init_igmp()
 {
     struct ip *ip;
 
@@ -65,13 +73,14 @@ void init_igmp()
 #define PIM_GRAFT        6
 #define PIM_GRAFT_ACK    7
 
-static char *packet_kind(type, code)
-     u_char type, code;
+static char *
+packet_kind(type, code)
+     u_int type, code;
 {
     switch (type) {
        case IGMP_HOST_MEMBERSHIP_QUERY:        return "membership query  ";
-       case IGMP_v1_HOST_MEMBERSHIP_REPORT:    return "membership report ";
-       case IGMP_v2_HOST_MEMBERSHIP_REPORT:    return "new member report ";
+       case IGMP_v1_HOST_MEMBERSHIP_REPORT:    return "v1 member report  ";
+       case IGMP_v2_HOST_MEMBERSHIP_REPORT:    return "v2 member report  ";
        case IGMP_HOST_LEAVE_MESSAGE:           return "leave message     ";
        case IGMP_DVMRP:
          switch (code) {
@@ -84,6 +93,8 @@ static char *packet_kind(type, code)
            case DVMRP_PRUNE:                   return "prune message     ";
            case DVMRP_GRAFT:                   return "graft message     ";
            case DVMRP_GRAFT_ACK:               return "graft message ack ";
+           case DVMRP_INFO_REQUEST:            return "info request      ";
+           case DVMRP_INFO_REPLY:              return "info reply        ";
            default:                            return "unknown DVMRP msg ";
          }
        case IGMP_PIM:
@@ -108,7 +119,8 @@ static char *packet_kind(type, code)
  * Process a newly received IGMP packet that is sitting in the input
  * packet buffer.
  */
-void accept_igmp(recvlen)
+void
+accept_igmp(recvlen)
     int recvlen;
 {
     register u_int32_t src, dst, group;
@@ -143,8 +155,8 @@ void accept_igmp(recvlen)
     ipdatalen = ip->ip_len;
     if (iphdrlen + ipdatalen != recvlen) {
        log(LOG_WARNING, 0,
-           "received packet shorter (%u bytes) than hdr+data length (%u+%u)",
-           recvlen, iphdrlen, ipdatalen);
+           "received packet from %s shorter (%u bytes) than hdr+data length (%u+%u)",
+           inet_fmt(src, s1), recvlen, iphdrlen, ipdatalen);
        return;
     }
 
@@ -200,12 +212,12 @@ void accept_igmp(recvlen)
                    return;
 
                case DVMRP_NEIGHBORS:
-                   accept_neighbors(src, dst, (char *)(igmp+1), igmpdatalen,
+                   accept_neighbors(src, dst, (u_char *)(igmp+1), igmpdatalen,
                                             group);
                    return;
 
                case DVMRP_NEIGHBORS2:
-                   accept_neighbors2(src, dst, (char *)(igmp+1), igmpdatalen,
+                   accept_neighbors2(src, dst, (u_char *)(igmp+1), igmpdatalen,
                                             group);
                    return;
 
@@ -221,6 +233,15 @@ void accept_igmp(recvlen)
                    accept_g_ack(src, dst, (char *)(igmp+1), igmpdatalen);
                    return;
 
+               case DVMRP_INFO_REQUEST:
+                   accept_info_request(src, dst, (char *)(igmp+1),
+                               igmpdatalen);
+                   return;
+
+               case DVMRP_INFO_REPLY:
+                   accept_info_reply(src, dst, (char *)(igmp+1), igmpdatalen);
+                   return;
+
                default:
                    log(LOG_INFO, 0,
                     "ignoring unknown DVMRP message code %u from %s to %s",
@@ -249,6 +270,29 @@ void accept_igmp(recvlen)
     }
 }
 
+/*
+ * Some IGMP messages are more important than others.  This routine
+ * determines the logging level at which to log a send error (often
+ * "No route to host").  This is important when there is asymmetric
+ * reachability and someone is trying to, i.e., mrinfo me periodically.
+ */
+static int
+igmp_log_level(type, code)
+    u_int type, code;
+{
+    switch (type) {
+       case IGMP_MTRACE_REPLY:
+           return LOG_INFO;
+
+       case IGMP_DVMRP:
+         switch (code) {
+           case DVMRP_NEIGHBORS:
+           case DVMRP_NEIGHBORS2:
+               return LOG_INFO;
+         }
+    }
+    return LOG_WARNING;
+}
 
 /*
  * Construct an IGMP message in the output packet buffer.  The caller may
@@ -262,9 +306,10 @@ send_igmp(src, dst, type, code, group, datalen)
     u_int32_t group;
     int datalen;
 {
-    static struct sockaddr_in sdst;
+    struct sockaddr_in sdst;
     struct ip *ip;
     struct igmp *igmp;
+    int setloop;
 
     ip                      = (struct ip *)send_buf;
     ip->ip_src.s_addr       = src;
@@ -279,8 +324,13 @@ send_igmp(src, dst, type, code, group, datalen)
     igmp->igmp_cksum        = inet_cksum((u_short *)igmp,
                                         IGMP_MINLEN + datalen);
 
-    if (IN_MULTICAST(ntohl(dst))) k_set_if(src);
-    if (dst == allhosts_group) k_set_loop(TRUE);
+    if (IN_MULTICAST(ntohl(dst))) {
+       k_set_if(src);
+       if (type != IGMP_DVMRP) {
+           setloop = 1;
+           k_set_loop(TRUE);
+       }
+    }
 
     bzero(&sdst, sizeof(sdst));
     sdst.sin_family = AF_INET;
@@ -293,12 +343,13 @@ send_igmp(src, dst, type, code, group, datalen)
        if (errno == ENETDOWN)
            check_vif_state();
        else
-           log(LOG_WARNING, errno,
+           log(igmp_log_level(type, code), errno,
                "sendto to %s on %s",
                inet_fmt(dst, s1), inet_fmt(src, s2));
     }
 
-    if (dst == allhosts_group) k_set_loop(FALSE);
+    if (setloop)
+           k_set_loop(FALSE);
 
     log(LOG_DEBUG, 0, "SENT %s from %-15s to %s",
        packet_kind(type, code), inet_fmt(src, s1), inet_fmt(dst, s2));
index b6c6a01..7229545 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: inet.c,v 1.3 1995/10/09 03:51:42 thorpej Exp $ */
+/*     $NetBSD: inet.c,v 1.4 1995/12/10 10:07:03 mycroft Exp $ */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -27,7 +27,8 @@ char s4[19];
  * (Without a mask, cannot detect addresses of the form {subnet,0} or
  * {subnet,-1}.)
  */
-int inet_valid_host(naddr)
+int
+inet_valid_host(naddr)
     u_int32_t naddr;
 {
     register u_int32_t addr;
@@ -39,6 +40,22 @@ int inet_valid_host(naddr)
              (addr & 0xff000000) == 0));
 }
 
+/*
+ * Verify that a given netmask is plausible;
+ * make sure that it is a series of 1's followed by
+ * a series of 0's with no discontiguous 1's.
+ */
+int
+inet_valid_mask(mask)
+    u_int32_t mask;
+{
+    if (~(((mask & -mask) - 1) | mask) != 0) {
+       /* Mask is not contiguous */
+       return (FALSE);
+    }
+
+    return (TRUE);
+}
 
 /*
  * Verify that a given subnet number and mask pair are credible.
@@ -49,7 +66,8 @@ int inet_valid_host(naddr)
  * within the [ABC] range and that the host bits of the subnet
  * are all 0.
  */
-int inet_valid_subnet(nsubnet, nmask)
+int
+inet_valid_subnet(nsubnet, nmask)
     u_int32_t nsubnet, nmask;
 {
     register u_int32_t subnet, mask;
@@ -59,21 +77,26 @@ int inet_valid_subnet(nsubnet, nmask)
 
     if ((subnet & mask) != subnet) return (FALSE);
 
-    if (subnet == 0 && mask == 0)
-       return (TRUE);
+    if (subnet == 0)
+       return (mask == 0);
 
     if (IN_CLASSA(subnet)) {
        if (mask < 0xff000000 ||
-          (subnet & 0xff000000) == 0x7f000000) return (FALSE);
+           (subnet & 0xff000000) == 0x7f000000 ||
+           (subnet & 0xff000000) == 0x00000000) return (FALSE);
     }
     else if (IN_CLASSD(subnet) || IN_BADCLASS(subnet)) {
        /* Above Class C address space */
        return (FALSE);
     }
-    else if (subnet & ~mask) {
+    if (subnet & ~mask) {
        /* Host bits are set in the subnet */
        return (FALSE);
     }
+    if (!inet_valid_mask(mask)) {
+       /* Netmask is not contiguous */
+       return (FALSE);
+    }
 
     return (TRUE);
 }
@@ -82,7 +105,8 @@ int inet_valid_subnet(nsubnet, nmask)
 /*
  * Convert an IP address in u_long (network) format into a printable string.
  */
-char *inet_fmt(addr, s)
+char *
+inet_fmt(addr, s)
     u_int32_t addr;
     char *s;
 {
@@ -98,7 +122,8 @@ char *inet_fmt(addr, s)
  * Convert an IP subnet number in u_long (network) format into a printable
  * string including the netmask as a number of bits.
  */
-char *inet_fmts(addr, mask, s)
+char *
+inet_fmts(addr, mask, s)
     u_int32_t addr, mask;
     char *s;
 {
@@ -128,7 +153,8 @@ char *inet_fmts(addr, mask, s)
  * legal address with that value, you must explicitly compare the string
  * with "255.255.255.255".)
  */
-u_int32_t inet_parse(s)
+u_int32_t
+inet_parse(s)
     char *s;
 {
     u_int32_t a = 0;
@@ -166,7 +192,8 @@ u_int32_t inet_parse(s)
  * Checksum routine for Internet Protocol family headers (C Version)
  *
  */
-int inet_cksum(addr, len)
+int
+inet_cksum(addr, len)
        u_short *addr;
        u_int len;
 {
@@ -181,13 +208,13 @@ int inet_cksum(addr, len)
         *  back all the carry bits from the top 16 bits into the lower
         *  16 bits.
         */
-       while( nleft > 1 )  {
+       while (nleft > 1)  {
                sum += *w++;
                nleft -= 2;
        }
 
        /* mop up an odd byte, if necessary */
-       if( nleft == 1 ) {
+       if (nleft == 1) {
                *(u_char *) (&answer) = *(u_char *)w ;
                sum += answer;
        }
index 0dbae18..f41edce 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern.c,v 1.3 1995/10/09 03:51:43 thorpej Exp $ */
+/*     $NetBSD: kern.c,v 1.4 1995/12/10 10:07:03 mycroft Exp $ */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -157,12 +157,15 @@ void k_del_vif(vifi)
  * Adds a (source, mcastgrp) entry to the kernel
  */
 void k_add_rg(origin, g)
-    u_long origin;
+    u_int32_t origin;
     struct gtable *g;
 {
     struct mfcctl mc;
-    int i;
+    vifi_t i;
 
+#ifdef DEBUG_MFC
+    md_log(MD_ADD, origin, g->gt_mcastgrp);
+#endif
     /* copy table values so that setsockopt can process it */
     mc.mfcc_origin.s_addr = origin;
 #ifdef OLD_KERNEL
@@ -175,8 +178,12 @@ void k_add_rg(origin, g)
 
     /* write to kernel space */
     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
-                  (char *)&mc, sizeof(mc)) < 0)
+                  (char *)&mc, sizeof(mc)) < 0) {
+#ifdef DEBUG_MFC
+       md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
+#endif
        log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
+    }
 }
 
 
@@ -184,12 +191,15 @@ void k_add_rg(origin, g)
  * Deletes a (source, mcastgrp) entry from the kernel
  */
 int k_del_rg(origin, g)
-    u_long origin;
+    u_int32_t origin;
     struct gtable *g;
 {
     struct mfcctl mc;
-    int retval, i;
+    int retval;
 
+#ifdef DEBUG_MFC
+    md_log(MD_DEL, origin, g->gt_mcastgrp);
+#endif
     /* copy table values so that setsockopt can process it */
     mc.mfcc_origin.s_addr = origin;
 #ifdef OLD_KERNEL
@@ -199,8 +209,12 @@ int k_del_rg(origin, g)
 
     /* write to kernel space */
     if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
-                  (char *)&mc, sizeof(mc))) < 0)
+                  (char *)&mc, sizeof(mc))) < 0) {
+#ifdef DEBUG_MFC
+       md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
+#endif
        log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC");
+    }
 
     return retval;
 }      
@@ -210,6 +224,9 @@ int k_del_rg(origin, g)
  */
 int k_get_version()
 {
+#ifdef OLD_KERNEL
+    return -1;
+#else
     int vers;
     int len = sizeof(vers);
 
@@ -219,4 +236,5 @@ int k_get_version()
                "getsockopt MRT_VERSION: perhaps your kernel is too old");
 
     return vers;
+#endif
 }
index 71d9ee3..6736317 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: main.c,v 1.5 1995/10/09 03:51:44 thorpej Exp $ */
+/*     $NetBSD: main.c,v 1.6 1995/12/10 10:07:05 mycroft Exp $ */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
 
 
 #include "defs.h"
-#include <string.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
 #include <varargs.h>
+#endif
+#include <fcntl.h>
 
 #ifdef SNMP
 #include "snmp.h"
 #endif
 
+#ifndef lint
+static char rcsid[] =
+       "@(#) $Id: main.c,v 1.2 1995/12/14 01:45:26 deraadt Exp $";
+#endif
+
 extern char *configfilename;
+char versionstring[100];
 
 static char pidfilename[]  = _PATH_MROUTED_PID;
 static char dumpfilename[] = _PATH_MROUTED_DUMP;
@@ -40,30 +50,38 @@ int max_prune_lifetime      = DEFAULT_CACHE_LIFETIME * 2;
 int debug = 0;
 u_char pruning = 1;    /* Enable pruning by default */
 
+#ifdef SNMP
+#define NHANDLERS      34
+#else
 #define NHANDLERS      2
+#endif
 
 static struct ihandler {
     int fd;                    /* File descriptor               */
-    void (*func)();            /* Function to call with &fd_set */
+    ihfunc_t func;             /* Function to call with &fd_set */
 } ihandlers[NHANDLERS];
 static int nhandlers = 0;
 
 /*
  * Forward declarations.
  */
-static void fasttimer();
-static void timer();
-static void cleanup();
-static void done();
-static void dump();
-static void fdump();
-static void cdump();
-static void restart();
+static void fasttimer __P((int));
+static void done __P((int));
+static void dump __P((int));
+static void fdump __P((int));
+static void cdump __P((int));
+static void restart __P((int));
+static void timer __P((void));
+static void cleanup __P((void));
+static void resetlogging __P((void *));
+
+/* To shut up gcc -Wstrict-prototypes */
+int main __P((int argc, char **argv));
 
 int
 register_input_handler(fd, func)
     int fd;
-    void (*func)();
+    ihfunc_t func;
 {
     if (nhandlers >= NHANDLERS)
        return -1;
@@ -74,7 +92,8 @@ register_input_handler(fd, func)
     return 0;
 }
 
-int main(argc, argv)
+int
+main(argc, argv)
     int argc;
     char *argv[];
 {
@@ -82,29 +101,18 @@ int main(argc, argv)
     register int omask;
     int dummy;
     FILE *fp;
-    extern uid_t geteuid();
     struct timeval tv;
-    u_long prev_genid;
+    u_int32_t prev_genid;
     int vers;
     fd_set rfds, readers;
     int nfds, n, i;
 #ifdef SNMP
-    char *myname;
-    fd_set wfds;
-  
-
-    if (myname = strrchr(argv[0], '/'))
-        myname++;
-    if (myname == NULL || *myname == 0)
-        myname = argv[0];
-    isodetailor (myname, 0);
+    struct timeval  timeout, *tvp = &timeout;
+    struct timeval  sched, *svp = &sched, now, *nvp = &now;
+    int index, block;
 #endif
 
-#ifdef SYSV
-    setvbuf(stderr, NULL, _IOLBF, 0);
-#else
     setlinebuf(stderr);
-#endif
 
     if (geteuid() != 0) {
        fprintf(stderr, "must be root\n");
@@ -127,6 +135,14 @@ int main(argc, argv)
                goto usage;
        } else if (strcmp(*argv, "-p") == 0) {
            pruning = 0;
+#ifdef SNMP
+   } else if (strcmp(*argv, "-P") == 0) {
+           if (argc > 1 && isdigit(*(argv + 1)[0])) {
+               argv++, argc--;
+               dest_port = atoi(*argv);
+           } else
+               dest_port = DEFAULT_PORT;
+#endif
        } else
            goto usage;
        argv++, argc--;
@@ -151,6 +167,9 @@ usage:      fprintf(stderr,
        (void)open("/", 0);
        (void)dup2(0, 1);
        (void)dup2(0, 2);
+#ifdef SYSV
+       (void)setpgrp();
+#else
 #ifdef TIOCNOTTY
        t = open("/dev/tty", 2);
        if (t >= 0) {
@@ -160,6 +179,7 @@ usage:      fprintf(stderr,
 #else
        if (setsid() < 0)
            perror("setsid");
+#endif
 #endif
     }
     else
@@ -171,9 +191,11 @@ usage:     fprintf(stderr,
 #else
     (void)openlog("mrouted", LOG_PID);
 #endif
-    log(LOG_NOTICE, 0, "mrouted version %d.%d",
+    sprintf(versionstring, "mrouted version %d.%d",
                        PROTOCOL_VERSION, MROUTED_VERSION);
 
+    log(LOG_NOTICE, 0, "%s", versionstring);
+
 #ifdef SYSV
     srand48(time(NULL));
 #else
@@ -201,32 +223,46 @@ usage:    fprintf(stderr,
     }
 
     callout_init();
-
-#ifdef SNMP
-    snmp_init();
-#endif
-
     init_igmp();
+    init_routes();
+    init_ktable();
     k_init_dvmrp();            /* enable DVMRP routing in kernel */
 
 #ifndef OLD_KERNEL
     vers = k_get_version();
-    if ((((vers >> 8) & 0xff) != PROTOCOL_VERSION) ||
-        ((vers & 0xff) != MROUTED_VERSION))
+    /*XXX
+     * This function must change whenever the kernel version changes
+     */
+    if ((((vers >> 8) & 0xff) != 3) ||
+        ((vers & 0xff) != 5))
        log(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
                (vers >> 8) & 0xff, vers & 0xff,
                PROTOCOL_VERSION, MROUTED_VERSION);
 #endif
 
-    init_routes();
-    init_ktable();
+#ifdef SNMP
+    if (i = snmp_init())
+       return i;
+
+    gettimeofday(nvp, 0);
+    if (nvp->tv_usec < 500000L){
+   svp->tv_usec = nvp->tv_usec + 500000L;
+   svp->tv_sec = nvp->tv_sec;
+    } else {
+   svp->tv_usec = nvp->tv_usec - 500000L;
+   svp->tv_sec = nvp->tv_sec + 1;
+    }
+#endif /* SNMP */
+
     init_vifs();
+
 #ifdef RSRR
     rsrr_init();
 #endif /* RSRR */
 
 #if defined(__STDC__) || defined(__GNUC__)
-    /* Allow cleanup if unexpected exit.  Apparently some architectures
+    /*
+     * Allow cleanup if unexpected exit.  Apparently some architectures
      * have a kernel bug where closing the socket doesn't do an
      * ip_mrouter_done(), so we attempt to do it on exit.
      */
@@ -238,12 +274,10 @@ usage:    fprintf(stderr,
 
     fp = fopen(pidfilename, "w");              
     if (fp != NULL) {
-       fprintf(fp, "%d\n", getpid());
+       fprintf(fp, "%d\n", (int)getpid());
        (void) fclose(fp);
     }
 
-    if (debug >= 2) dump();
-
     (void)signal(SIGALRM, fasttimer);
 
     (void)signal(SIGHUP,  restart);
@@ -263,6 +297,17 @@ usage:     fprintf(stderr,
            nfds = ihandlers[i].fd + 1;
     }
 
+    /*
+     * Install the vifs in the kernel as late as possible in the
+     * initialization sequence.
+     */
+    init_installvifs();
+
+    if (debug >= 2) dump(0);
+
+    /* Start up the log rate-limiter */
+    resetlogging(NULL);
+
     (void)alarm(1);     /* schedule first timer interrupt */
 
     /*
@@ -270,23 +315,38 @@ usage:    fprintf(stderr,
      */
     dummy = 0;
     for(;;) {
+#ifdef SYSV
+       sigset_t block, oblock;
+#endif
        bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
 #ifdef SNMP
-        FD_ZERO(&wfds);
-  
-        if (smux_fd != NOTOK) {
-           if (rock_and_roll)
-              FD_SET(smux_fd, &rfds);
-           else
-              FD_SET(smux_fd, &wfds);
-           if (smux_fd >= nfds)
-              nfds = smux_fd + 1;
-        }
-  
-        if ((n = xselect(nfds, &rfds, &wfds, NULLFD, NOTOK))==NOTOK) {
+   gettimeofday(nvp, 0);
+   if (nvp->tv_sec > svp->tv_sec
+       || (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){
+       alarmTimer(nvp);
+       eventTimer(nvp);
+       if (nvp->tv_usec < 500000L){
+      svp->tv_usec = nvp->tv_usec + 500000L;
+      svp->tv_sec = nvp->tv_sec;
+       } else {
+      svp->tv_usec = nvp->tv_usec - 500000L;
+      svp->tv_sec = nvp->tv_sec + 1;
+       }
+   }
+
+       tvp =  &timeout;
+       tvp->tv_sec = 0;
+       tvp->tv_usec = 500000L;
+
+       block = 0;
+       snmp_select_info(&nfds, &rfds, tvp, &block);
+       if (block == 1)
+               tvp = NULL; /* block without timeout */
+       if ((n = select(nfds, &rfds, NULL, NULL, tvp)) < 0) 
 #else
-       if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0) {
+       if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0) 
 #endif
+   {
             if (errno != EINTR) /* SIGALRM is expected */
                 log(LOG_WARNING, errno, "select failed");
             continue;
@@ -299,25 +359,31 @@ usage:    fprintf(stderr,
                if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
                continue;
            }
+#ifdef SYSV
+           (void)sigemptyset(&block);
+           (void)sigaddset(&block, SIGALRM);
+           if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
+                   log(LOG_ERR, errno, "sigprocmask");
+#else
            omask = sigblock(sigmask(SIGALRM));
+#endif
            accept_igmp(recvlen);
+#ifdef SYSV
+           (void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
+#else
            (void)sigsetmask(omask);
+#endif
         }
 
        for (i = 0; i < nhandlers; i++) {
            if (FD_ISSET(ihandlers[i].fd, &rfds)) {
-               (*ihandlers[i].func)(&rfds);
+               (*ihandlers[i].func)(ihandlers[i].fd, &rfds);
            }
        }
 
 #ifdef SNMP
-        if (smux_fd != NOTOK) {
-            if (rock_and_roll) {
-               if (FD_ISSET(smux_fd, &rfds))
-                   doit_smux();
-           } else if (FD_ISSET(smux_fd, &wfds)) 
-                start_smux();
-        }
+       snmp_read(&rfds); 
+       snmp_timeout(); /* poll */
 #endif
     }
 }
@@ -331,7 +397,8 @@ usage:      fprintf(stderr,
  * do all the other time-based processing.
  */
 static void
-fasttimer()
+fasttimer(i)
+    int i;
 {
     static unsigned int tlast;
     static unsigned int nsent;
@@ -432,13 +499,7 @@ timer()
     }
 
 #ifdef SNMP
-    if (smux_fd == NOTOK && !dont_bother_anymore
-                && virtual_time % SNMPD_RETRY_INTERVAL == 0) {
-       /*
-        * Time to check for snmpd running.
-        */
-        try_smux_init();
-    }
+    sync_timer();
 #endif
 
     /*
@@ -452,10 +513,10 @@ timer()
  * On termination, let everyone know we're going away.
  */
 static void
-done()
+done(i)
+    int i;
 {
-    log(LOG_NOTICE, 0, "mrouted version %d.%d exiting",
-                       PROTOCOL_VERSION, MROUTED_VERSION);
+    log(LOG_NOTICE, 0, "%s exiting", versionstring);
     cleanup();
     _exit(1);
 }
@@ -481,7 +542,8 @@ cleanup()
  * Dump internal data structures to stderr.
  */
 static void
-dump()
+dump(i)
+    int i;
 {
     dump_vifs(stderr);
     dump_routes(stderr);
@@ -492,7 +554,8 @@ dump()
  * Dump internal data structures to a file.
  */
 static void
-fdump()
+fdump(i)
+    int i;
 {
     FILE *fp;
 
@@ -509,7 +572,8 @@ fdump()
  * Dump local cache contents to a file.
  */
 static void
-cdump()
+cdump(i)
+    int i;
 {
     FILE *fp;
 
@@ -525,17 +589,27 @@ cdump()
  * Restart mrouted
  */
 static void
-restart()
+restart(i)
+    int i;
 {
     register int omask;
+#ifdef SYSV
+    sigset_t block, oblock;
+#endif
 
-    log(LOG_NOTICE, 0, "mrouted version %d.%d restart",
-                       PROTOCOL_VERSION, MROUTED_VERSION);
+    log(LOG_NOTICE, 0, "%s restart", versionstring);
 
     /*
      * reset all the entries
      */
+#ifdef SYSV
+    (void)sigemptyset(&block);
+    (void)sigaddset(&block, SIGALRM);
+    if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
+       log(LOG_ERR, errno, "sigprocmask");
+#else
     omask = sigblock(sigmask(SIGALRM));
+#endif
     free_all_prunes();
     free_all_routes();
     stop_all_vifs();
@@ -550,20 +624,60 @@ restart()
     pruning = 1;
 
     init_igmp();
-    k_init_dvmrp();            /* enable DVMRP routing in kernel */
     init_routes();
     init_ktable();
     init_vifs();
+    k_init_dvmrp();            /* enable DVMRP routing in kernel */
+    init_installvifs();
 
+#ifdef SYSV
+    (void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
+#else
     (void)sigsetmask(omask);
+#endif
 }
 
+#define LOG_MAX_MSGS   20      /* if > 20/minute then shut up for a while */
+#define LOG_SHUT_UP    600     /* shut up for 10 minutes */
+static int log_nmsgs = 0;
+
+static void
+resetlogging(arg)
+    void *arg;
+{
+    int nxttime = 60;
+    void *narg = NULL;
+
+    if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) {
+       nxttime = LOG_SHUT_UP;
+       narg = (void *)&log_nmsgs;      /* just need some valid void * */
+       syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes",
+                       LOG_SHUT_UP / 60);
+    } else {
+       log_nmsgs = 0;
+    }
+
+    timer_setTimer(nxttime, resetlogging, narg);
+}
 
 /*
  * Log errors and other messages to the system log daemon and to stderr,
  * according to the severity of the message and the current debug level.
  * For errors of severity LOG_ERR or worse, terminate the program.
  */
+#ifdef __STDC__
+void
+log(int severity, int syserr, char *format, ...)
+{
+    va_list ap;
+    static char fmt[211] = "warning - ";
+    char *msg;
+    char tbuf[20];
+    struct timeval now;
+    struct tm *thyme;
+
+    va_start(ap, format);
+#else
 /*VARARGS3*/
 void
 log(severity, syserr, format, va_alist)
@@ -579,6 +693,7 @@ log(severity, syserr, format, va_alist)
     struct tm *thyme;
 
     va_start(ap);
+#endif
     vsprintf(&fmt[10], format, ap);
     va_end(ap);
     msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
@@ -589,23 +704,53 @@ log(severity, syserr, format, va_alist)
        case 2: if (severity > LOG_INFO  ) break;
        default:
            gettimeofday(&now,NULL);
-           thyme = localtime((time_t *)&now.tv_sec);
+           thyme = localtime(&now.tv_sec);
            strftime(tbuf, sizeof(tbuf), "%X.%%03d ", thyme);
            fprintf(stderr, tbuf, now.tv_usec / 1000);
            fprintf(stderr, "%s", msg);
            if (syserr == 0)
                fprintf(stderr, "\n");
+           else if (syserr < sys_nerr)
+               fprintf(stderr, ": %s\n", sys_errlist[syserr]);
            else
-               fprintf(stderr, ": %s\n", strerror(syserr));
+               fprintf(stderr, ": errno %d\n", syserr);
     }
 
     if (severity <= LOG_NOTICE) {
-       if (syserr != 0) {
-           errno = syserr;
-           syslog(severity, "%s: %m", msg);
-       } else
-           syslog(severity, "%s", msg);
+       if (log_nmsgs++ < LOG_MAX_MSGS) {
+           if (syserr != 0) {
+               errno = syserr;
+               syslog(severity, "%s: %m", msg);
+           } else
+               syslog(severity, "%s", msg);
+       }
 
        if (severity <= LOG_ERR) exit(-1);
     }
 }
+
+#ifdef DEBUG_MFC
+void
+md_log(what, origin, mcastgrp)
+    int what;
+    u_int32_t origin, mcastgrp;
+{
+    static FILE *f = NULL;
+    struct timeval tv;
+    u_int32_t buf[4];
+
+    if (!f) {
+       if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) {
+           log(LOG_ERR, errno, "open /tmp/mrouted.clog");
+       }
+    }
+
+    gettimeofday(&tv, NULL);
+    buf[0] = tv.tv_sec;
+    buf[1] = what;
+    buf[2] = origin;
+    buf[3] = mcastgrp;
+
+    fwrite(buf, sizeof(u_int32_t), 4, f);
+}
+#endif
index dd7c74f..2b2712e 100644 (file)
@@ -1,4 +1,4 @@
-'\"    $NetBSD: mrouted.8,v 1.5 1995/10/09 03:51:46 thorpej Exp $
+'\"    $NetBSD: mrouted.8,v 1.6 1995/12/10 10:07:07 mycroft Exp $
 '\"COPYRIGHT 1989 by The Board of Trustees of Leland Stanford Junior University.
 .TH MROUTED 8
 .UC 5
@@ -118,7 +118,7 @@ There are four types of configuration commands:
                   [altnet <network>/<mask-len>]
 
     tunnel <local-addr> <remote-addr> [metric <m>]
-                [threshold <t>] [srcrt] [rate_limit <b>]
+                [threshold <t>] [rate_limit <b>]
                   [boundary (<boundary-name>|<scoped-addr>/<mask-len>)]
 
     cache_lifetime <ct>
@@ -140,7 +140,7 @@ options may be specified as many times as necessary.
 The phyint command can be used to disable multicast routing on the physical
 interface identified by local IP address <local-addr>, or to associate a
 non-default metric or threshold with the specified physical interface.
-The local IP address <local-addr> may be alternatively replaced by the 
+The local IP address <local-addr> may be replaced by the 
 interface name (e.g le0).
 If a phyint is attached to multiple IP subnets, describe each additional subnet
 with the altnet keyword.
@@ -148,7 +148,12 @@ Phyint commands must precede tunnel commands.
 .PP
 The tunnel command can be used to establish a tunnel link between local
 IP address <local-addr> and remote IP address <remote-addr>, and to associate
-a non-default metric or threshold with that tunnel.  The tunnel must be set
+a non-default metric or threshold with that tunnel.
+The local IP address <local-addr> may be replaced by the
+interface name (e.g. le0).  The remote IP address <remote-addr> may
+be replaced by a host name, if and only if the host name has a single
+IP address associated with it.
+The tunnel must be set
 up in the mrouted.conf files of both routers before it can be used.
 '\"For backwards compatibility with older
 '\".IR mrouted s,
@@ -327,7 +332,7 @@ shown at each interface.
 Associated with each subnet from which a multicast datagram can originate
 is the address of the previous hop router (unless the subnet is directly-
 connected), the metric of the path back to the origin, the amount of time
-since we last recieved an update for this subnet, the incoming vif for
+since we last received an update for this subnet, the incoming vif for
 multicasts from that origin, and a list of outgoing vifs.  "*" means that
 the outgoing vif is connected to a leaf of the broadcast tree rooted at the
 origin, and a multicast datagram from that origin will be forwarded on that
@@ -365,7 +370,7 @@ The 'Ptmr' field is simply a dash if no prune was sent upstream, or the
 amount of time until the upstream prune will time out.
 The 'Ivif' field indicates the
 incoming vif for multicast packets from that origin.  Each router also
-maintains a record of the number of prunes received from neighbouring
+maintains a record of the number of prunes received from neighboring
 routers for a particular source and group. If there are no members of
 a multicast group on any downward link of the multicast tree for a
 subnet, a prune message is sent to the upstream router. They are
index c7939fd..27814ab 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: pathnames.h,v 1.3 1995/10/09 03:51:48 thorpej Exp $    */
+/*     $NetBSD: pathnames.h,v 1.4 1995/12/10 10:07:08 mycroft Exp $    */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
 
 #define _PATH_MROUTED_CONF     "/etc/mrouted.conf"
 
+#if (defined(BSD) && (BSD >= 199103))
 #define _PATH_MROUTED_PID      "/var/run/mrouted.pid"
 #define _PATH_MROUTED_GENID    "/var/run/mrouted.genid"
 #define _PATH_MROUTED_DUMP     "/var/tmp/mrouted.dump"
 #define _PATH_MROUTED_CACHE    "/var/tmp/mrouted.cache"
+#else
+#define _PATH_MROUTED_PID      "/etc/mrouted.pid"
+#define _PATH_MROUTED_GENID    "/etc/mrouted.genid"
+#define _PATH_MROUTED_DUMP     "/usr/tmp/mrouted.dump"
+#define _PATH_MROUTED_CACHE    "/usr/tmp/mrouted.cache"
+#endif
index aaba6c3..3d28974 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: prune.c,v 1.2 1995/10/09 03:51:49 thorpej Exp $        */
+/*     $NetBSD: prune.c,v 1.3 1995/12/10 10:07:09 mycroft Exp $        */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -16,6 +16,8 @@ extern int cache_lifetime;
 extern int max_prune_lifetime;
 extern struct rtentry *routing_table;
 
+extern int phys_vif;
+
 /*
  * dither cache lifetime to obtain a value between x and 2*x
  */
@@ -48,6 +50,17 @@ unsigned int kroutes;                        /* current number of cache entries  */
 /****************************************************************************
                        Functions that are local to prune.c
 ****************************************************************************/
+static void            prun_add_ttls __P((struct gtable *gt));
+static int             pruning_neighbor __P((vifi_t vifi, u_int32_t addr));
+static int             can_mtrace __P((vifi_t vifi, u_int32_t addr));
+static struct ptable * find_prune_entry __P((u_int32_t vr, struct ptable *pt));
+static void            expire_prune __P((vifi_t vifi, struct gtable *gt));
+static void            send_prune __P((struct gtable *gt));
+static void            send_graft __P((struct gtable *gt));
+static void            send_graft_ack __P((u_int32_t src, u_int32_t dst,
+                                       u_int32_t origin, u_int32_t grp));
+static void            update_kernel __P((struct gtable *g));
+static char *          scaletime __P((u_long t));
 
 /* 
  * Updates the ttl values for each vif.
@@ -71,7 +84,7 @@ prun_add_ttls(gt)
  * checks for scoped multicast addresses
  */
 #define GET_SCOPE(gt) { \
-       register int _i; \
+       register vifi_t _i; \
        if ((ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
            for (_i = 0; _i < numvifs; _i++) \
                if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
@@ -620,7 +633,11 @@ add_table_entry(origin, mcastgrp)
     struct rtentry *r;
     struct gtable *gt,**gtnp,*prev_gt;
     struct stable *st,**stnp;
-    int i;
+    vifi_t i;
+
+#ifdef DEBUG_MFC
+    md_log(MD_MISS, origin, mcastgrp);
+#endif
     
     r = determine_route(origin);
     prev_gt = NULL;
@@ -659,6 +676,9 @@ add_table_entry(origin, mcastgrp)
        gt->gt_srctbl       = NULL;
        gt->gt_pruntbl      = NULL;
        gt->gt_route        = r;
+#ifdef RSRR
+       gt->gt_rsrr_cache   = NULL;
+#endif
 
        if (r != NULL) {
            /* obtain the multicast group membership list */
@@ -711,7 +731,7 @@ add_table_entry(origin, mcastgrp)
                    gt->gt_gnext->gt_gprev = gt;
            }
        } else {
-           gt->gt_gnext = gt->gt_prev = NULL;
+           gt->gt_gnext = gt->gt_gprev = NULL;
        }
     }
 
@@ -732,8 +752,14 @@ add_table_entry(origin, mcastgrp)
        st->st_next = *stnp;
        *stnp = st;
     } else {
+#ifdef DEBUG_MFC
+       md_log(MD_DUPE, origin, mcastgrp);
+#endif
        log(LOG_WARNING, 0, "kernel entry already exists for (%s %s)",
                inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
+       /* XXX Doing this should cause no harm, and may ensure 
+        * kernel<>mrouted synchronization */
+       k_add_rg(origin, gt);
        return;
     }
 
@@ -764,60 +790,31 @@ reset_neighbor_state(vifi, addr)
 {
     struct rtentry *r;
     struct gtable *g;
-    struct ptable *pt, *prev_pt;
-    struct stable *st, *prev_st;
+    struct ptable *pt, **ptnp;
+    struct stable *st;
     
     for (g = kernel_table; g; g = g->gt_gnext) {
        r = g->gt_route;
 
        /*
         * If neighbor was the parent, remove the prune sent state
-        * Don't send any grafts upstream.
+        * and all of the source cache info so that prunes get
+        * regenerated.
         */
        if (vifi == r->rt_parent) {
            if (addr == r->rt_gateway) {
-               log(LOG_DEBUG, 0, "reset_neighbor_state del prunes (%s %s)",
+               log(LOG_DEBUG, 0, "reset_neighbor_state parent reset (%s %s)",
                    inet_fmts(r->rt_origin, r->rt_originmask, s1),
                    inet_fmt(g->gt_mcastgrp, s2));
 
-               pt = g->gt_pruntbl;
-               while (pt) {
-                   /*
-                    * Expire prune, send again on this vif.
-                    */
-                   VIFM_SET(pt->pt_vifi, g->gt_grpmems);
-                   prev_pt = pt;
-                   pt = prev_pt->pt_next;
-                   free(prev_pt);
-               }
-               g->gt_pruntbl = NULL;
-
-               st = g->gt_srctbl;
-               while (st) {
-                   log(LOG_DEBUG, 0, "reset_neighbor_state del sg (%s %s)",
-                       inet_fmt(st->st_origin, s1),
-                       inet_fmt(g->gt_mcastgrp, s2));
-
-                   if (k_del_rg(st->st_origin, g) < 0) {
-                       log(LOG_WARNING, errno,
-                           "reset_neighbor_state trying to delete (%s %s)",
-                           inet_fmt(st->st_origin, s1),
-                           inet_fmt(g->gt_mcastgrp, s2));
-                   }
-                   kroutes--;
-                   prev_st = st;
-                   st = prev_st->st_next;
-                   free(prev_st);
-               }
-               g->gt_srctbl = NULL;
-               /*
-                * Keep the group entries themselves around since the
-                * state will likely just come right back, and if not,
-                * the group entries will time out with no kernel entries
-                * and no prune state.
-                */
                g->gt_prsent_timer = 0;
                g->gt_grftsnt = 0;
+               while (st = g->gt_srctbl) {
+                   g->gt_srctbl = st->st_next;
+                   k_del_rg(st->st_origin, g);
+                   kroutes--;
+                   free(st);
+               }
            }
        } else {
            /*
@@ -832,13 +829,13 @@ reset_neighbor_state(vifi, addr)
            /*
             * Remove any prunes that this router has sent us.
             */
-           prev_pt = (struct ptable *)&g->gt_pruntbl;
-           for (pt = g->gt_pruntbl; pt; pt = pt->pt_next) {
+           ptnp = &g->gt_pruntbl;
+           while ((pt = *ptnp) != NULL) {
                if (pt->pt_vifi == vifi && pt->pt_router == addr) {
-                   prev_pt->pt_next = pt->pt_next;
+                   *ptnp = pt->pt_next;
                    free(pt);
                } else
-                   prev_pt = pt;
+                   ptnp = &pt->pt_next;
            }
 
            /*
@@ -858,6 +855,10 @@ reset_neighbor_state(vifi, addr)
 
                /* Update kernel state */
                update_kernel(g);
+#ifdef RSRR
+               /* Send route change notification to reservation protocol. */
+               rsrr_cache_send(g,1);
+#endif /* RSRR */
 
                log(LOG_DEBUG, 0, "reset member state (%s %s) gm:%x",
                    inet_fmts(r->rt_origin, r->rt_originmask, s1),
@@ -904,9 +905,9 @@ del_table_entry(r, mcastgrp, del_flag)
 
            pt = g->gt_pruntbl;
            while (pt) {
-               prev_pt = pt->pt_next;
-               free(pt);
-               pt = prev_pt;
+               prev_pt = pt;
+               pt = pt->pt_next;
+               free(prev_pt);
            }
            g->gt_pruntbl = NULL;
 
@@ -917,9 +918,14 @@ del_table_entry(r, mcastgrp, del_flag)
            else
                kernel_table = g->gt_gnext;
 
-           prev_g = g->gt_next;
-           free(g);
-           g = prev_g;
+#ifdef RSRR
+           /* Send route change notification to reservation protocol. */
+           rsrr_cache_send(g,0);
+           rsrr_cache_clean(g);
+#endif /* RSRR */
+           prev_g = g;
+           g = g->gt_next;
+           free(prev_g);
        }
        r->rt_groups = NULL;
     }
@@ -943,17 +949,17 @@ del_table_entry(r, mcastgrp, del_flag)
                            inet_fmt(g->gt_mcastgrp, s2));
                    }
                    kroutes--;
-                   prev_st = st->st_next;
-                   free(st);
-                   st = prev_st;
+                   prev_st = st;
+                   st = st->st_next;
+                   free(prev_st);
                }
                g->gt_srctbl = NULL;
 
                pt = g->gt_pruntbl;
                while (pt) {
-                   prev_pt = pt->pt_next;
-                   free(pt);
-                   pt = prev_pt;
+                   prev_pt = pt;
+                   pt = pt->pt_next;
+                   free(prev_pt);
                }
                g->gt_pruntbl = NULL;
 
@@ -970,6 +976,11 @@ del_table_entry(r, mcastgrp, del_flag)
                    g->gt_next->gt_prev = NULL;
                prev_g->gt_next = g->gt_next;
 
+#ifdef RSRR
+               /* Send route change notification to reservation protocol. */
+               rsrr_cache_send(g,0);
+               rsrr_cache_clean(g);
+#endif /* RSRR */
                free(g);
                g = prev_g;
            } else {
@@ -988,7 +999,7 @@ update_table_entry(r)
 {
     struct gtable *g;
     struct ptable *pt, *prev_pt;
-    int i;
+    vifi_t i;
 
     for (g = r->rt_groups; g; g = g->gt_next) {
        pt = g->gt_pruntbl;
@@ -1028,6 +1039,10 @@ update_table_entry(r)
        /* update ttls and add entry into kernel */
        prun_add_ttls(g);
        update_kernel(g);
+#ifdef RSRR
+       /* Send route change notification to reservation protocol. */
+       rsrr_cache_send(g,1);
+#endif /* RSRR */
 
        /* Check if we want to prune this group */
        if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
@@ -1070,6 +1085,10 @@ update_lclgrp(vifi, mcastgrp)
                inet_fmt(g->gt_mcastgrp, s2), g->gt_grpmems);
 
            update_kernel(g);
+#ifdef RSRR
+           /* Send route change notification to reservation protocol. */
+           rsrr_cache_send(g,1);
+#endif /* RSRR */
        }
     }
 }
@@ -1118,6 +1137,10 @@ delete_lclgrp(vifi, mcastgrp)
 
                prun_add_ttls(g);
                update_kernel(g);
+#ifdef RSRR
+               /* Send route change notification to reservation protocol. */
+               rsrr_cache_send(g,1);
+#endif /* RSRR */
 
                /*
                 * If there are no more members of this particular group,
@@ -1184,6 +1207,7 @@ accept_prune(src, dst, p, datalen)
        ((char *)&prun_grp)[i] = *p++;
     for (i = 0; i< 4; i++)
        ((char *)&prun_tmr)[i] = *p++;
+    prun_tmr = ntohl(prun_tmr);
     
     log(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s)/%d",
        inet_fmt(src, s1), vifi,
@@ -1239,7 +1263,7 @@ accept_prune(src, dst, p, datalen)
        g->gt_timer = CACHE_LIFETIME(cache_lifetime);
        if (g->gt_timer < prun_tmr)
            g->gt_timer = prun_tmr;
-       
+
        /*
         * check if any more packets need to be sent on the 
         * vif which sent this message
@@ -1259,6 +1283,10 @@ accept_prune(src, dst, p, datalen)
 
            prun_add_ttls(g);
            update_kernel(g);
+#ifdef RSRR
+           /* Send route change notification to reservation protocol. */
+           rsrr_cache_send(g,1);
+#endif /* RSRR */
        }
 
        /*
@@ -1329,6 +1357,10 @@ chkgrp_graft(vifi, mcastgrp)
 
                prun_add_ttls(g);
                update_kernel(g);
+#ifdef RSRR
+               /* Send route change notification to reservation protocol. */
+               rsrr_cache_send(g,1);
+#endif /* RSRR */
            }
     }
 }
@@ -1410,6 +1442,10 @@ accept_graft(src, dst, p, datalen)
 
                prun_add_ttls(g);
                update_kernel(g);
+#ifdef RSRR
+               /* Send route change notification to reservation protocol. */
+               rsrr_cache_send(g,1);
+#endif /* RSRR */
                break;                          
            } else {
                ptnp = &pt->pt_next;
@@ -1525,21 +1561,21 @@ free_all_prunes()
        while (g) {
            s = g->gt_srctbl;
            while (s) {
-               prev_s = s->st_next;
-               free(s);
-               s = prev_s;
+               prev_s = s;
+               s = s->st_next;
+               free(prev_s);
            }
 
            p = g->gt_pruntbl;
            while (p) {
-               prev_p = p->pt_next;
-               free(p);
-               p = prev_p;
+               prev_p = p;
+               p = p->pt_next;
+               free(prev_p);
            }
 
-           prev_g = g->gt_next;
-           free(g);
-           g = prev_g;
+           prev_g = g;
+           g = g->gt_next;
+           free(prev_g);
        }
        r->rt_groups = NULL;
     }
@@ -1550,9 +1586,9 @@ free_all_prunes()
        if (g->gt_srctbl)
            free(g->gt_srctbl);
 
-       prev_g = g->gt_next;
-       free(g);
-       g = prev_g;
+       prev_g = g;
+       g = g->gt_next;
+       free(prev_g);
     }
     kernel_no_route = NULL;
 }
@@ -1687,28 +1723,8 @@ age_table_entry()
                    inet_fmt(gt->gt_mcastgrp, s2),
                    inet_fmt(pt->pt_router, s3),
                    pt->pt_vifi);
-               
-               /*
-                * No need to send a graft, any prunes that we sent
-                * will expire before any prunes that we have received.
-                */
-               if (gt->gt_prsent_timer > 0) {
-                   log(LOG_DEBUG, 0, "prune expired with %d left on %s",
-                       gt->gt_prsent_timer, "prsent_timer");
-                   gt->gt_prsent_timer = 0;
-               }
 
-               /* modify the kernel entry to forward packets */
-               if (!VIFM_ISSET(pt->pt_vifi, gt->gt_grpmems)) {
-                   VIFM_SET(pt->pt_vifi, gt->gt_grpmems);
-                   log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
-                       inet_fmts(r->rt_origin, r->rt_originmask, s1),
-                       inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems,
-                       pt->pt_vifi);
-    
-                   prun_add_ttls(gt);
-                   update_kernel(gt);
-               }
+               expire_prune(pt->pt_vifi, gt);
 
                /* remove the router's prune entry and await new one */
                *ptnp = pt->pt_next;
@@ -1719,94 +1735,65 @@ age_table_entry()
        }
 
        /*
-        * If the cache entry has expired, check for downstream prunes.
-        *
-        * If there are downstream prunes, refresh the cache entry's timer.
-        * Otherwise, check for traffic.  If no traffic, delete this
-        * entry.
+        * If the cache entry has expired, delete source table entries for
+        * silent sources.  If there are no source entries left, and there
+        * are no downstream prunes, then the entry is deleted.
+        * Otherwise, the cache entry's timer is refreshed.
         */
        if (gt->gt_timer <= 0) {
-           if (gt->gt_pruntbl) {
-               if (gt->gt_prsent_timer == -1)
-                   gt->gt_prsent_timer = 0;
-               gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
-               gtnptr = &gt->gt_gnext;
-               continue;
-           }
-
-           /*
-            * If this entry was pruned, but all downstream prunes
-            * have expired, then it is safe to simply delete it.
-            * Otherwise, check for traffic before deleting.
-            */
-           if (gt->gt_prsent_timer == 0) {
-               sg_req.grp.s_addr = gt->gt_mcastgrp;
-               stnp = &gt->gt_srctbl;
-               while ((st = *stnp) != NULL) {
-                   sg_req.src.s_addr = st->st_origin;
-                   if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req)
-                           < 0) {
-                       log(LOG_WARNING, errno, "%s (%s %s)",
-                           "age_table_entry: SIOCGETSGCNT failing for",
-                           inet_fmt(st->st_origin, s1),
-                           inet_fmt(gt->gt_mcastgrp, s2));
-                       /* Make sure it gets deleted below */
-                       sg_req.pktcnt = st->st_pktcnt;
-                   }
-                   if (sg_req.pktcnt == st->st_pktcnt) {
-                       *stnp = st->st_next;
-                       log(LOG_DEBUG, 0,
-                           "age_table_entry deleting (%s %s)",
+           /* Check for traffic before deleting source entries */
+           sg_req.grp.s_addr = gt->gt_mcastgrp;
+           stnp = &gt->gt_srctbl;
+           while ((st = *stnp) != NULL) {
+               sg_req.src.s_addr = st->st_origin;
+               if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
+                   log(LOG_WARNING, errno, "%s (%s %s)",
+                       "age_table_entry: SIOCGETSGCNT failing for",
+                       inet_fmt(st->st_origin, s1),
+                       inet_fmt(gt->gt_mcastgrp, s2));
+                   /* Make sure it gets deleted below */
+                   sg_req.pktcnt = st->st_pktcnt;
+               }
+               if (sg_req.pktcnt == st->st_pktcnt) {
+                   *stnp = st->st_next;
+                   log(LOG_DEBUG, 0, "age_table_entry deleting (%s %s)",
+                       inet_fmt(st->st_origin, s1),
+                       inet_fmt(gt->gt_mcastgrp, s2));
+                   if (k_del_rg(st->st_origin, gt) < 0) {
+                       log(LOG_WARNING, errno,
+                           "age_table_entry trying to delete (%s %s)",
                            inet_fmt(st->st_origin, s1),
                            inet_fmt(gt->gt_mcastgrp, s2));
-                       if (k_del_rg(st->st_origin, gt) < 0) {
-                           log(LOG_WARNING, errno,
-                               "age_table_entry trying to delete (%s %s)",
-                               inet_fmt(st->st_origin, s1),
-                               inet_fmt(gt->gt_mcastgrp, s2));
-                       }
-                       kroutes--;
-                       free(st);
-                   } else {
-                       stnp = &st->st_next;
                    }
+                   kroutes--;
+                   free(st);
+               } else {
+                   st->st_pktcnt = sg_req.pktcnt;
+                   stnp = &st->st_next;
                }
+           }
 
-               if (gt->gt_srctbl) {
-                   /* At least one source in the list still has traffic */
-                   gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
-                   gtnptr = &gt->gt_gnext;
-                   continue;
-               }
+           /*
+            * Retain the group entry if we have downstream prunes or if
+            * there is at least one source in the list that still has
+            * traffic, or if our upstream prune timer is running.
+            */
+           if (gt->gt_pruntbl != NULL || gt->gt_srctbl != NULL ||
+               gt->gt_prsent_timer > 0) {
+               gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
+               if (gt->gt_prsent_timer == -1)
+                   if (gt->gt_grpmems == 0)
+                       send_prune(gt);
+                   else
+                       gt->gt_prsent_timer = 0;
+               gtnptr = &gt->gt_gnext;
+               continue;
            }
 
            log(LOG_DEBUG, 0, "timeout cache entry (%s, %s)",
                inet_fmts(r->rt_origin, r->rt_originmask, s1),
                inet_fmt(gt->gt_mcastgrp, s2));
            
-           /* free all the source entries */
-           while (st = gt->gt_srctbl) {
-               log(LOG_DEBUG, 0,
-                   "age_table_entry (P) deleting (%s %s)",
-                   inet_fmt(st->st_origin, s1),
-                   inet_fmt(gt->gt_mcastgrp, s2));
-               if (k_del_rg(st->st_origin, gt) < 0) {
-                   log(LOG_WARNING, errno,
-                       "age_table_entry (P) trying to delete (%s %s)",
-                       inet_fmt(st->st_origin, s1),
-                       inet_fmt(gt->gt_mcastgrp, s2));
-               }
-               kroutes--;
-               gt->gt_srctbl = st->st_next;
-               free(st);
-           }
-
-           /* free all the prune list entries */
-           while (gt->gt_pruntbl) {
-               gt->gt_pruntbl = pt->pt_next;
-               free(pt);
-           }
-
            if (gt->gt_prev)
                gt->gt_prev->gt_next = gt->gt_next;
            else
@@ -1824,10 +1811,18 @@ age_table_entry()
            if (gt->gt_gnext)
                gt->gt_gnext->gt_gprev = gt->gt_gprev;
 
+#ifdef RSRR
+           /* Send route change notification to reservation protocol. */
+           rsrr_cache_send(gt,0);
+           rsrr_cache_clean(gt);
+#endif /* RSRR */
            free((char *)gt);
        } else {
            if (gt->gt_prsent_timer == -1)
-               gt->gt_prsent_timer = 0;
+               if (gt->gt_grpmems == 0)
+                   send_prune(gt);
+               else
+                   gt->gt_prsent_timer = 0;
            gtnptr = &gt->gt_gnext;
        }
     }
@@ -1862,7 +1857,45 @@ age_table_entry()
     }
 }
 
-char *
+/*
+ * Modify the kernel to forward packets when one or multiple prunes that
+ * were received on the vif given by vifi, for the group given by gt,
+ * have expired.
+ */
+static void
+expire_prune(vifi, gt)
+     vifi_t vifi;
+     struct gtable *gt;
+{
+    /*
+     * No need to send a graft, any prunes that we sent
+     * will expire before any prunes that we have received.
+     */
+    if (gt->gt_prsent_timer > 0) {
+        log(LOG_DEBUG, 0, "prune expired with %d left on %s",
+               gt->gt_prsent_timer, "prsent_timer");
+        gt->gt_prsent_timer = 0;
+    }
+
+    /* modify the kernel entry to forward packets */
+    if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
+        struct rtentry *rt = gt->gt_route;
+        VIFM_SET(vifi, gt->gt_grpmems);
+        log(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
+       inet_fmts(rt->rt_origin, rt->rt_originmask, s1),
+       inet_fmt(gt->gt_mcastgrp, s2), gt->gt_grpmems, vifi);
+
+        prun_add_ttls(gt);
+        update_kernel(gt);
+#ifdef RSRR
+        /* Send route change notification to reservation protocol. */
+        rsrr_cache_send(gt,1);
+#endif /* RSRR */
+    }
+}
+
+
+static char *
 scaletime(t)
     u_long t;
 {
@@ -1896,7 +1929,7 @@ scaletime(t)
     if (t > 999)
        return "*** ";
 
-    sprintf(p,"%3d%c", t, s);
+    sprintf(p,"%3d%c", (int)t, s);
 
     return p;
 }
@@ -1912,7 +1945,7 @@ dump_cache(fp2)
     register struct gtable *gt;
     register struct stable *st;
     register struct ptable *pt;
-    register int i;
+    register vifi_t i;
     register time_t thyme = time(0);
 
     fprintf(fp2,
@@ -1976,7 +2009,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
     u_int32_t dst;
     u_int32_t group;
     char *data;
-    u_char no;
+    u_int no;  /* promoted u_char */
     int datalen;
 {
     u_char type;
@@ -2004,43 +2037,27 @@ accept_mtrace(src, dst, group, data, no, datalen)
      */
     if (datalen == QLEN) {
        type = QUERY;
-       log(LOG_DEBUG, 0, "Traceroute query rcvd from %s to %s",
+       log(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s",
            inet_fmt(src, s1), inet_fmt(dst, s2));
     }
     else if ((datalen - QLEN) % RLEN == 0) {
        type = RESP;
-       log(LOG_DEBUG, 0, "Traceroute response rcvd from %s to %s",
+       log(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s",
            inet_fmt(src, s1), inet_fmt(dst, s2));
-       if IN_MULTICAST(ntohl(dst)) {
+       if (IN_MULTICAST(ntohl(dst))) {
            log(LOG_DEBUG, 0, "Dropping multicast response");
            return;
        }
     }
     else {
        log(LOG_WARNING, 0, "%s from %s to %s",
-           "Non decipherable tracer request recieved",
+           "Non decipherable traceroute request recieved",
            inet_fmt(src, s1), inet_fmt(dst, s2));
        return;
     }
 
     qry = (struct tr_query *)data;
 
-    if (oqid == qry->tr_qid) {
-       /*
-        * If the multicast router is a member of the group being
-        * queried, and the query is multicasted, then the router can
-        * recieve multiple copies of the same query.  If we have already
-        * replied to this traceroute, just ignore it this time.
-        *
-        * This is not a total solution, but since if this fails you
-        * only get N copies, N <= the number of interfaces on the router,
-        * it is not fatal.
-        */
-       log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
-       return;
-    } else
-       oqid = qry->tr_qid;
-
     /*
      * if it is a packet with all reports filled, drop it
      */
@@ -2053,7 +2070,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
            inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3));
     log(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl,
            inet_fmt(qry->tr_raddr, s1));
-    log(LOG_DEBUG, 0, "rcount:%d", rcount);
+    log(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid);
 
     /* determine the routing table entry for this traceroute */
     rt = determine_route(qry->tr_src);
@@ -2071,6 +2088,21 @@ accept_mtrace(src, dst, group, data, no, datalen)
      * and if so, whether I should start response back
      */
     if (type == QUERY) {
+       if (oqid == qry->tr_qid) {
+           /*
+            * If the multicast router is a member of the group being
+            * queried, and the query is multicasted, then the router can
+            * recieve multiple copies of the same query.  If we have already
+            * replied to this traceroute, just ignore it this time.
+            *
+            * This is not a total solution, but since if this fails you
+            * only get N copies, N <= the number of interfaces on the router,
+            * it is not fatal.
+            */
+           log(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
+           return;
+       }
+
        if (rt == NULL) {
            log(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
                   inet_fmt(qry->tr_src, s1));
@@ -2106,6 +2138,9 @@ accept_mtrace(src, dst, group, data, no, datalen)
        }
     }   
     
+    /* Now that we've decided to send a response, save the qid */
+    oqid = qry->tr_qid;
+
     log(LOG_DEBUG, 0, "Sending traceroute response");
     
     /* copy the packet to the sending buffer */
@@ -2133,7 +2168,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
     bzero(resp, sizeof(struct tr_resp));
     datalen += RLEN;
 
-    resp->tr_qarr    = ((tp.tv_sec + JAN_1970) << 16) + 
+    resp->tr_qarr    = htonl((tp.tv_sec + JAN_1970) << 16) + 
                                ((tp.tv_usec >> 4) & 0xffff);
 
     resp->tr_rproto  = PROTO_DVMRP;
@@ -2151,7 +2186,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
      */
     v_req.vifi = vifi;
     if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
-       resp->tr_vifout  =  v_req.ocount;
+       resp->tr_vifout  =  htonl(v_req.ocount);
 
     /*
      * fill in scoping & pruning information
@@ -2168,7 +2203,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
        sg_req.src.s_addr = qry->tr_src;
        sg_req.grp.s_addr = group;
        if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
-           resp->tr_pktcnt = sg_req.pktcnt;
+           resp->tr_pktcnt = htonl(sg_req.pktcnt);
 
        if (VIFM_ISSET(vifi, gt->gt_scope))
            resp->tr_rflags = TR_SCOPED;
@@ -2183,7 +2218,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
     } else {
        if (scoped_addr(vifi, group))
            resp->tr_rflags = TR_SCOPED;
-       else if (!VIFM_ISSET(vifi, rt->rt_children))
+       else if (rt && !VIFM_ISSET(vifi, rt->rt_children))
            resp->tr_rflags = TR_NO_FWD;
     }
 
@@ -2199,7 +2234,7 @@ accept_mtrace(src, dst, group, data, no, datalen)
        /* get # of packets in on interface */
        v_req.vifi = rt->rt_parent;
        if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
-           resp->tr_vifin = v_req.icount;
+           resp->tr_vifin = htonl(v_req.icount);
 
        MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
        src = uvifs[rt->rt_parent].uv_lcl_addr;
@@ -2238,22 +2273,30 @@ sendit:
            resptype = IGMP_MTRACE_QUERY;
        }
 
-    log(LOG_DEBUG, 0, "Sending %s to %s from %s",
-       resptype == IGMP_MTRACE_REPLY ?  "response" : "request on",
-       inet_fmt(dst, s1), inet_fmt(src, s2));
-
     if (IN_MULTICAST(ntohl(dst))) {
-       k_set_ttl(qry->tr_rttl);
-       /* Let the kernel pick the source address, since we might have picked
-        * a disabled phyint to multicast on.
+       /*
+        * Send the reply on a known multicast capable vif.
+        * If we don't have one, we can't source any multicasts anyway.
         */
-       send_igmp(INADDR_ANY, dst,
-                 resptype, no, group,
-                 datalen);
-       k_set_ttl(1);
-    } else
+       if (phys_vif != -1) {
+           log(LOG_DEBUG, 0, "Sending reply to %s from %s",
+               inet_fmt(dst, s1), inet_fmt(uvifs[phys_vif].uv_lcl_addr, s2));
+           k_set_ttl(qry->tr_rttl);
+           send_igmp(uvifs[phys_vif].uv_lcl_addr, dst,
+                     resptype, no, group,
+                     datalen);
+           k_set_ttl(1);
+       } else
+           log(LOG_INFO, 0, "No enabled phyints -- %s",
+                       "dropping traceroute reply");
+    } else {
+       log(LOG_DEBUG, 0, "Sending %s to %s from %s",
+           resptype == IGMP_MTRACE_REPLY ?  "reply" : "request on",
+           inet_fmt(dst, s1), inet_fmt(src, s2));
+
        send_igmp(src, dst,
                  resptype, no, group,
                  datalen);
+    }
     return;
 }
index 22df280..b3187a8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: prune.h,v 1.2 1995/10/09 03:51:52 thorpej Exp $        */
+/*     $NetBSD: prune.h,v 1.3 1995/12/10 10:07:11 mycroft Exp $        */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -36,6 +36,9 @@ struct gtable {
     struct stable  *gt_srctbl;         /* source table                     */
     struct ptable  *gt_pruntbl;                /* prune table                      */
     struct rtentry *gt_route;          /* parent route                     */
+#ifdef RSRR
+    struct rsrr_cache *gt_rsrr_cache;  /* RSRR cache                       */
+#endif /* RSRR */
 };
 
 /*
@@ -127,8 +130,8 @@ struct tr_resp {
 
 #define MASK_TO_VAL(x, i) { \
                        u_int32_t _x = ntohl(x); \
-                       (i) = 0; \
-                       while ((_x) << (i)) \
+                       (i) = 1; \
+                       while ((_x) <<= 1) \
                                (i)++; \
                        };
 
index d45de23..6765ae9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: route.c,v 1.4 1995/10/09 03:51:53 thorpej Exp $        */
+/*     $NetBSD: route.c,v 1.5 1995/12/10 10:07:12 mycroft Exp $        */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -37,6 +37,18 @@ static struct rtentry *rtp;          /* pointer to a route entry         */
 static struct rtentry *rt_end;         /* pointer to last route entry      */
 unsigned int nroutes;                  /* current number of route entries  */
 
+/*
+ * Private functions.
+ */
+static int init_children_and_leaves    __P((struct rtentry *r,
+                                               vifi_t parent));
+static int find_route          __P((u_int32_t origin, u_int32_t mask));
+static void create_route       __P((u_int32_t origin, u_int32_t mask));
+static void discard_route      __P((struct rtentry *prev_r));
+static int compare_rts         __P((const void *rt1, const void *rt2));
+static int report_chunk                __P((struct rtentry *start_rt, vifi_t vifi,
+                                               u_int32_t dst));
+
 /*
  * Initialize the routing table and associated variables.
  */
@@ -44,6 +56,7 @@ void
 init_routes()
 {
     routing_table        = NULL;
+    rt_end              = RT_ADDR;
     nroutes             = 0;
     routes_changed       = FALSE;
     delay_change_reports = FALSE;
@@ -283,7 +296,7 @@ create_route(origin, mask)
 
     if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) +
                                       (2 * numvifs * sizeof(u_int32_t)) +
-                                      (numvifs * sizeof(u_long)))) == NULL) {
+                                      (numvifs * sizeof(u_int)))) == NULL) {
        log(LOG_ERR, 0, "ran out of memory");   /* fatal */
     }
     r->rt_origin     = origin;
@@ -295,7 +308,7 @@ create_route(origin, mask)
     r->rt_flags        = 0;
     r->rt_dominants    = (u_int32_t *)(r + 1);
     r->rt_subordinates = (u_int32_t *)(r->rt_dominants + numvifs);
-    r->rt_leaf_timers  = (u_long *)(r->rt_subordinates + numvifs);
+    r->rt_leaf_timers  = (u_int *)(r->rt_subordinates + numvifs);
     r->rt_groups       = NULL;
 
     r->rt_next = rtp->rt_next;
@@ -339,13 +352,12 @@ discard_route(prev_r)
 void
 update_route(origin, mask, metric, src, vifi)
     u_int32_t origin, mask;
-    int metric;
+    u_int metric;
     u_int32_t src;
     vifi_t vifi;
 {
     register struct rtentry *r;
-    struct rtentry *prev_r;
-    int adj_metric;
+    u_int adj_metric;
 
     /*
      * Compute an adjusted metric, taking into account the cost of the
@@ -365,10 +377,6 @@ update_route(origin, mask, metric, src, vifi)
      * Look up the reported origin in the routing table.
      */
     if (!find_route(origin, mask)) {
-       register struct rtentry *rp;
-       register struct gtable *gt;
-       register struct stable *st, **stnp;
-
        /*
         * Not found.
         * Don't create a new entry if the report says it's unreachable,
@@ -453,7 +461,8 @@ update_route(origin, mask, metric, src, vifi)
             (r->rt_gateway != 0 &&
              (adj_metric < r->rt_metric ||
               (adj_metric == r->rt_metric &&
-               r->rt_timer >= ROUTE_SWITCH_TIME)))) {
+               (ntohl(src) < ntohl(r->rt_gateway) ||
+                r->rt_timer >= ROUTE_SWITCH_TIME))))) {
        /*
         * The report is for an origin we consider reachable; the report
         * comes either from one of our own interfaces or from a gateway
@@ -464,10 +473,15 @@ update_route(origin, mask, metric, src, vifi)
         * what our routing entry says, update the entry to use the new
         * gateway and metric.  We also switch gateways if the reported
         * metric is the same as the one in the route entry and the gateway
-        * associated with the route entry has not been heard from recently.
+        * associated with the route entry has not been heard from recently,
+        * or if the metric is the same but the reporting gateway has a lower
+        * IP address than the gateway associated with the route entry.
         * Did you get all that?
         */
        if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
+           /*
+            * XXX Why do we do this if we are just changing the metric?
+            */
            r->rt_parent = vifi;
            if (init_children_and_leaves(r, vifi)) {
                update_table_entry(r);
@@ -696,10 +710,7 @@ accept_probe(src, dst, p, datalen, level)
        return;
     }
 
-    if (!update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level))
-       return;
-
-    report(ALL_ROUTES, vifi, src);
+    update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level);
 }
 
 struct newrt {
@@ -709,11 +720,13 @@ struct newrt {
        int pad;
 }; 
 
-int
-compare_rts(r1, r2)
-    register struct newrt *r1;
-    register struct newrt *r2;
+static int
+compare_rts(rt1, rt2)
+    const void *rt1;
+    const void *rt2;
 {
+    register struct newrt *r1 = (struct newrt *)rt1;
+    register struct newrt *r2 = (struct newrt *)rt2;
     register u_int32_t m1 = ntohl(r1->mask);
     register u_int32_t m2 = ntohl(r2->mask);
     register u_int32_t o1, o2;
@@ -777,6 +790,12 @@ accept_report(src, dst, p, datalen, level)
        if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
        if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
        if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
+       if (!inet_valid_mask(ntohl(mask))) {
+           log(LOG_WARNING, 0,
+               "%s reports bogus netmask 0x%08x (%s)",
+               inet_fmt(src, s1), ntohl(mask), inet_fmt(mask, s2));
+           return;
+       }
        datalen -= 3;
 
        do {                    /* Loop through (origin, metric) pairs */
@@ -797,6 +816,7 @@ accept_report(src, dst, p, datalen, level)
            ++nrt;
        } while (!(metric & 0x80));
     }
+
     qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
     start_route_updates();
     /*
@@ -807,9 +827,16 @@ accept_report(src, dst, p, datalen, level)
 
     log(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
                inet_fmt(src, s1), inet_fmt(dst, s2));
-    for (i = 0; i < nrt; ++i)
+    for (i = 0; i < nrt; ++i) {
+       if (i != 0 && rt[i].origin == rt[i-1].origin &&
+                     rt[i].mask == rt[i-1].mask) {
+           log(LOG_WARNING, 0, "%s reports duplicate route for %s",
+               inet_fmt(src, s1), inet_fmts(rt[i].origin, rt[i].mask, s2));
+           continue;
+       }
        update_route(rt[i].origin, rt[i].mask, rt[i].metric, 
                     src, vifi);
+    }
 
     if (routes_changed && !delay_change_reports)
        report_to_all_neighbors(CHANGED_ROUTES);
@@ -829,17 +856,15 @@ report(which_routes, vifi, dst)
     register struct rtentry *r;
     register char *p;
     register int i;
-    int datalen;
-    int width;
-    u_int32_t mask;
+    int datalen = 0;
+    int width = 0;
+    u_int32_t mask = 0;
     u_int32_t src;
     u_int32_t nflags;
 
     src = uvifs[vifi].uv_lcl_addr;
 
     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
-    datalen = 0;
-    mask = 0;
 
 #ifdef NOTYET
     /* If I'm not a leaf, but the neighbor is a leaf, only advertise default */
@@ -879,7 +904,7 @@ report(which_routes, vifi, dst)
            mask = 0;
        }
 
-       if(r->rt_originmask != mask) {
+       if (r->rt_originmask != mask || datalen == 0) {
            mask  = r->rt_originmask;
            width = r->rt_originwidth;
            if (datalen != 0) *(p-1) |= 0x80;
@@ -960,7 +985,7 @@ report_to_all_neighbors(which_routes)
  * Send a route report message to destination 'dst', via virtual interface
  * 'vifi'.  'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
  */
-int
+static int
 report_chunk(start_rt, vifi, dst)
     register struct rtentry *start_rt;
     vifi_t vifi;
@@ -970,16 +995,14 @@ report_chunk(start_rt, vifi, dst)
     register char *p;
     register int i;
     register int nrt = 0;
-    int datalen;
-    int width;
-    u_int32_t mask;
+    int datalen = 0;
+    int width = 0;
+    u_int32_t mask = 0;
     u_int32_t src;
     u_int32_t nflags;
 
     src = uvifs[vifi].uv_lcl_addr;
     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
-    datalen = 0;
-    mask = 0;
 
     nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
 
@@ -1006,7 +1029,7 @@ report_chunk(start_rt, vifi, dst)
                      htonl(MROUTED_LEVEL | nflags), datalen);
            return (nrt);
        }
-       if(r->rt_originmask != mask) {
+       if (r->rt_originmask != mask || datalen == 0) {
            mask  = r->rt_originmask;
            width = r->rt_originwidth;
            if (datalen != 0) *(p-1) |= 0x80;
@@ -1094,8 +1117,7 @@ dump_routes(fp)
     FILE *fp;
 {
     register struct rtentry *r;
-    register int i;
-    register time_t thyme = time(0);
+    register vifi_t i;
 
 
     fprintf(fp,
index 5bc27b8..a01a16d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: route.h,v 1.3 1995/10/09 03:51:54 thorpej Exp $        */
+/*     $NetBSD: route.h,v 1.4 1995/12/10 10:07:13 mycroft Exp $        */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -37,8 +37,8 @@ struct rtentry {
     vifbitmap_t             rt_leaves;         /* subset of outgoing children vifs */
     u_int32_t      *rt_dominants;      /* per vif dominant gateways        */
     u_int32_t      *rt_subordinates;   /* per vif subordinate gateways     */
-    u_long         *rt_leaf_timers;    /* per vif leaf confirmation timers */
-    u_long          rt_timer;          /* for timing out the route entry   */
+    u_int          *rt_leaf_timers;    /* per vif leaf confirmation timers */
+    u_int           rt_timer;          /* for timing out the route entry   */
     struct rtentry  *rt_prev;          /* link to previous entry           */
     struct gtable   *rt_groups;                /* link to active groups            */
 };
index f5b4195..1c0261d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: rsrr.c,v 1.2 1995/10/09 03:51:56 thorpej Exp $ */
+/*     $NetBSD: rsrr.c,v 1.3 1995/12/10 10:07:14 mycroft Exp $ */
 
 /*
  * Copyright (c) 1993 by the University of Southern California
  * April 1995.
  */
 
+/* May 1995 -- Added support for Route Change Notification */
+
 #ifdef RSRR
 
 #include "defs.h"
+#include <sys/param.h>
+#if (defined(BSD) && (BSD >= 199103))
+#include <stddef.h>
+#endif
 
 /* Taken from prune.c */
 /*
@@ -57,13 +63,20 @@ int rsrr_socket;                    /* interface to reservation protocol */
 char rsrr_recv_buf[RSRR_MAX_LEN];      /* RSRR receive buffer */
 char rsrr_send_buf[RSRR_MAX_LEN];      /* RSRR send buffer */
 
+struct sockaddr_un client_addr;
+int client_length = sizeof(client_addr);
+
+
 /*
  * Procedure definitions needed internally.
  */
-void rsrr_accept();
-void rsrr_send();
-void rsrr_accept_iq();
-void rsrr_accept_rq();
+static void    rsrr_accept __P((int recvlen));
+static void    rsrr_accept_iq __P((void));
+static int     rsrr_accept_rq __P((struct rsrr_rq *route_query, int flags,
+                                       struct gtable *gt_notify));
+static int     rsrr_send __P((int sendlen));
+static void    rsrr_cache __P((struct gtable *gt,
+                                       struct rsrr_rq *route_query));
 
 /* Initialize RSRR socket */
 void
@@ -79,7 +92,13 @@ rsrr_init()
     bzero((char *) &serv_addr, sizeof(serv_addr));
     serv_addr.sun_family = AF_UNIX;
     strcpy(serv_addr.sun_path, RSRR_SERV_PATH);
+#if (defined(BSD) && (BSD >= 199103))
+    servlen = offsetof(struct sockaddr_un, sun_path) +
+               strlen(serv_addr.sun_path);
+    serv_addr.sun_len = servlen;
+#else
     servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
+#endif
  
     if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0)
        log(LOG_ERR, errno, "Can't bind RSRR socket");
@@ -90,16 +109,16 @@ rsrr_init()
 
 /* Read a message from the RSRR socket */
 void
-rsrr_read()
+rsrr_read(f, rfd)
+       int f;
+       fd_set *rfd;
 {
     register int rsrr_recvlen;
-    struct sockaddr_un client_addr;
-    int client_length = sizeof(client_addr);
     register int omask;
     
     bzero((char *) &client_addr, sizeof(client_addr));
     rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf),
-                           0, &client_addr, &client_length);
+                           0, (struct sockaddr *)&client_addr, &client_length);
     if (rsrr_recvlen < 0) {    
        if (errno != EINTR)
            log(LOG_ERR, errno, "RSRR recvfrom");
@@ -107,18 +126,16 @@ rsrr_read()
     }
     /* Use of omask taken from main() */
     omask = sigblock(sigmask(SIGALRM));
-    rsrr_accept(rsrr_recvlen,&client_addr,client_length);
+    rsrr_accept(rsrr_recvlen);
     (void)sigsetmask(omask);
 }
 
 /* Accept a message from the reservation protocol and take
  * appropriate action.
  */
-void
-rsrr_accept(recvlen,client_addr,client_length)
+static void
+rsrr_accept(recvlen)
     int recvlen;
-    struct sockaddr_un *client_addr;
-    int client_length;
 {
     struct rsrr_header *rsrr;
     struct rsrr_rq *route_query;
@@ -145,7 +162,7 @@ rsrr_accept(recvlen,client_addr,client_length)
          case RSRR_INITIAL_QUERY:
            /* Send Initial Reply to client */
            log(LOG_INFO, 0, "Received Initial Query\n");
-           rsrr_accept_iq(client_addr,client_length);
+           rsrr_accept_iq();
            break;
          case RSRR_ROUTE_QUERY:
            /* Check size */
@@ -163,7 +180,7 @@ rsrr_accept(recvlen,client_addr,client_length)
                inet_fmt(route_query->dest_addr.s_addr,s2),
                BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT));
            /* Send Route Reply to client */
-           rsrr_accept_rq(rsrr,route_query,client_addr,client_length);
+           rsrr_accept_rq(route_query,rsrr->flags,NULL);
            break;
          default:
            log(LOG_WARNING, 0,
@@ -182,10 +199,8 @@ rsrr_accept(recvlen,client_addr,client_length)
 }
 
 /* Send an Initial Reply to the reservation protocol. */
-void
-rsrr_accept_iq(client_addr,client_length)
-    struct sockaddr_un *client_addr;
-    int client_length;    
+static void
+rsrr_accept_iq()
 {
     struct rsrr_header *rsrr;
     struct rsrr_vif *vif_list;
@@ -226,16 +241,21 @@ rsrr_accept_iq(client_addr,client_length)
     
     /* Send it. */
     log(LOG_INFO, 0, "Send RSRR Initial Reply");
-    rsrr_send(sendlen,client_addr,client_length);
+    rsrr_send(sendlen);
 }
 
-/* Send a Route Reply to the reservation protocol. */
-void
-rsrr_accept_rq(rsrr_in,route_query,client_addr,client_length)
-    struct rsrr_header *rsrr_in;
-    struct rsrr_rq *route_query;    
-    struct sockaddr_un *client_addr;
-    int client_length;    
+/* Send a Route Reply to the reservation protocol.  The Route Query
+ * contains the query to which we are responding.  The flags contain
+ * the incoming flags from the query or, for route change
+ * notification, the flags that should be set for the reply.  The
+ * kernel table entry contains the routing info to use for a route
+ * change notification.
+ */
+static int
+rsrr_accept_rq(route_query,flags,gt_notify)
+    struct rsrr_rq *route_query;
+    int flags;
+    struct gtable *gt_notify;
 {
     struct rsrr_header *rsrr;
     struct rsrr_rr *route_reply;
@@ -248,7 +268,7 @@ rsrr_accept_rq(rsrr_in,route_query,client_addr,client_length)
     rsrr = (struct rsrr_header *) rsrr_send_buf;
     rsrr->version = 1;
     rsrr->type = RSRR_ROUTE_REPLY;
-    rsrr->flags = rsrr_in->flags;
+    rsrr->flags = 0;
     rsrr->num = 0;
     
     route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN);
@@ -261,19 +281,35 @@ rsrr_accept_rq(rsrr_in,route_query,client_addr,client_length)
     route_reply->reserved = 0;
     route_reply->out_vif_bm = 0;
     
-    /* Clear error bit. */
-    BIT_CLR(rsrr->flags,RSRR_ERROR_BIT);
-    /* Turn notification off.  We don't do it yet. */
-    BIT_CLR(rsrr->flags,RSRR_NOTIFICATION_BIT);
-    
-    /* First check kernel. Code taken from add_table_entry() */
-    if (find_src_grp(route_query->source_addr.s_addr, 0,
-                    route_query->dest_addr.s_addr)) {
+    /* Get the size. */
+    sendlen = RSRR_RR_LEN;
+
+    /* If kernel table entry is defined, then we are sending a Route Reply
+     * due to a Route Change Notification event.  Use the kernel table entry
+     * to supply the routing info.
+     */
+    if (gt_notify) {
+       /* Set flags */
+       rsrr->flags = flags;
+       /* Include the routing entry. */
+       route_reply->in_vif = gt_notify->gt_route->rt_parent;
+       route_reply->out_vif_bm = gt_notify->gt_grpmems;
+
+    } else if (find_src_grp(route_query->source_addr.s_addr, 0,
+                           route_query->dest_addr.s_addr)) {
+
+       /* Found kernel entry. Code taken from add_table_entry() */
        gt = gtp ? gtp->gt_gnext : kernel_table;
        
        /* Include the routing entry. */
        route_reply->in_vif = gt->gt_route->rt_parent;
        route_reply->out_vif_bm = gt->gt_grpmems;
+
+       /* Cache reply if using route change notification. */
+       if BIT_TST(flags,RSRR_NOTIFICATION_BIT) {
+           rsrr_cache(gt,route_query);
+           BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT);
+       }
        
     } else {
        /* No kernel entry; use routing table. */
@@ -319,42 +355,141 @@ rsrr_accept_rq(rsrr_in,route_query,client_addr,client_length)
        }
     }
     
-    /* Get the size. */
-    sendlen = RSRR_RR_LEN;
-    
-    log(LOG_INFO, 0, "Send RSRR Route Reply for src %s grp %s ",
+    if (gt_notify)
+       log(LOG_INFO, 0, "Route Change: Send RSRR Route Reply");
+
+    else
+       log(LOG_INFO, 0, "Send RSRR Route Reply");
+
+    log(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n",
        inet_fmt(route_reply->source_addr.s_addr,s1),
-       inet_fmt(route_reply->dest_addr.s_addr,s2));
-    log(LOG_INFO, 0, "in vif %d out vif %d\n",
+       inet_fmt(route_reply->dest_addr.s_addr,s2),
        route_reply->in_vif,route_reply->out_vif_bm);
     
     /* Send it. */
-    rsrr_send(sendlen,client_addr,client_length);
+    return rsrr_send(sendlen);
 }
 
 /* Send an RSRR message. */
-void
-rsrr_send(sendlen,client_addr,client_length)
+static int
+rsrr_send(sendlen)
     int sendlen;
-    struct sockaddr_un *client_addr;
-    int client_length;
 {
     int error;
     
     /* Send it. */
     error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0,
-                  *client_addr, client_length);
+                  (struct sockaddr *)&client_addr, client_length);
     
     /* Check for errors. */
     if (error < 0) {
        log(LOG_WARNING, errno, "Failed send on RSRR socket");
-       return;
-    }
-    if (error != sendlen) {
+    } else if (error != sendlen) {
        log(LOG_WARNING, 0,
            "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen);
-       return;
     }
+    return error;
+}
+
+/* Cache a message being sent to a client.  Currently only used for
+ * caching Route Reply messages for route change notification.
+ */
+static void
+rsrr_cache(gt,route_query)
+    struct gtable *gt;
+    struct rsrr_rq *route_query;
+{
+    struct rsrr_cache *rc, **rcnp;
+    struct rsrr_header *rsrr;
+
+    rsrr = (struct rsrr_header *) rsrr_send_buf;
+
+    rcnp = &gt->gt_rsrr_cache;
+    while ((rc = *rcnp) != NULL) {
+       if ((rc->route_query.source_addr.s_addr == 
+            route_query->source_addr.s_addr) &&
+           (rc->route_query.dest_addr.s_addr == 
+            route_query->dest_addr.s_addr) &&
+           (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) {
+           /* Cache entry already exists.
+            * Check if route notification bit has been cleared.
+            */
+           if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) {
+               /* Delete cache entry. */
+               *rcnp = rc->next;
+               free(rc);
+           } else {
+               /* Update */
+               rc->route_query.query_id = route_query->query_id;
+               log(LOG_DEBUG, 0,
+                       "Update cached query id %ld from client %s\n",
+                       rc->route_query.query_id, rc->client_addr.sun_path);
+           }
+           return;
+       }
+       rcnp = &rc->next;
+    }
+
+    /* Cache entry doesn't already exist.  Create one and insert at
+     * front of list.
+     */
+    rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache));
+    if (rc == NULL)
+       log(LOG_ERR, 0, "ran out of memory");
+    rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr;
+    rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr;
+    rc->route_query.query_id = route_query->query_id;
+    strcpy(rc->client_addr.sun_path, client_addr.sun_path);
+    rc->client_length = client_length;
+    rc->next = gt->gt_rsrr_cache;
+    gt->gt_rsrr_cache = rc;
+    log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n",
+          rc->route_query.query_id,rc->client_addr.sun_path);
+}
+
+/* Send all the messages in the cache.  Currently this is used to send
+ * all the cached Route Reply messages for route change notification.
+ */
+void
+rsrr_cache_send(gt,notify)
+    struct gtable *gt;
+    int notify;
+{
+    struct rsrr_cache *rc, **rcnp;
+    int flags = 0;
+
+    if (notify)
+       BIT_SET(flags,RSRR_NOTIFICATION_BIT);
+
+    rcnp = &gt->gt_rsrr_cache;
+    while ((rc = *rcnp) != NULL) {
+       if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) {
+           log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n",
+                  rc->route_query.query_id,rc->client_addr.sun_path);
+           /* Delete cache entry. */
+           *rcnp = rc->next;
+           free(rc);
+       } else {
+           rcnp = &rc->next;
+       }
+    }
+}
+
+/* Clean the cache by deleting all entries. */
+void
+rsrr_cache_clean(gt)
+    struct gtable *gt;
+{
+    struct rsrr_cache *rc,*rc_next;
+
+    printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1));
+    rc = gt->gt_rsrr_cache;
+    while (rc) {
+       rc_next = rc->next;
+       free(rc);
+       rc = rc_next;
+    }
+    gt->gt_rsrr_cache = NULL;
 }
 
 void
@@ -363,4 +498,4 @@ rsrr_clean()
     unlink(RSRR_SERV_PATH);
 }
 
-#endif RSRR
+#endif /* RSRR */
index 5298da5..6f203ef 100644 (file)
-/*     $NetBSD: snmp.c,v 1.2 1995/10/09 03:51:58 thorpej Exp $ */
-
-/*
- * snmp.c
- *
- * Code written by David Thaler <thalerd@eecs.umich.edu>
- * Moved to a seperate file by Bill Fenner <fenner@parc.xerox.com>
- */
-
+/*     $NetBSD: snmp.c,v 1.3 1995/12/10 10:07:16 mycroft Exp $ */
 
 #include "defs.h"
-#include <string.h>
+#include <netinet/in_var.h>
 #include "snmp.h"
+#include "snmplib/asn1.h"
+#include "snmplib/party.h"
+#include "snmplib/snmp_impl.h"
+#define MROUTED
+#include "snmpd/snmp_vars.h"
+
+    u_short dest_port = 0;
+    int sdlen = 0;
+
+struct addrCache {
+    u_long addr;
+    int status;
+#define UNUSED 0
+#define USED   1
+#define OLD 2
+};
 
-#define NUMMIBS 2
-#define SNMPD_RETRY_INTERVAL 300 /* periodic snmpd probe interval */
+static struct addrCache addrCache[10];
 
-char *mibs[]={ "ipMRouteMIB", "dvmrpMIB" };
+/*
+ * Initialize the SNMP part of mrouted
+ */
+int /* returns: 0 on success, true on error */
+snmp_init(dest_port)
+    u_short dest_port;
+{
+   u_long myaddr;
+   int ret;
+   struct partyEntry *pp;
+   struct sockaddr_in  me;
+   int index, sd, portlist[32];
+
+   init_snmp();
+   /* init_mib(); why was this here? */
+    if (read_party_database("/etc/party.conf") > 0){
+   fprintf(stderr, "Couldn't read party database from /etc/party.conf\n");
+   exit(0);
+    }
+    if (read_context_database("/etc/context.conf") > 0){
+   fprintf(stderr, "Couldn't read context database from /etc/context.conf\n");
+   exit(0);
+    }
+    if (read_acl_database("/etc/acl.conf") > 0){
+   fprintf(stderr, "Couldn't read acl database from /etc/acl.conf\n");
+   exit(0);
+    }
+    if (read_view_database("/etc/view.conf") > 0){
+   fprintf(stderr, "Couldn't read view database from /etc/view.conf\n");
+   exit(0);
+    }
 
-extern int o_ipMRouteTable();
-extern int o_ipMRouteNextHopTable();
-extern int o_dvmrpRouteTable();
-extern int o_dvmrpRouteNextHopTable();
+    myaddr = get_myaddr();
+    if (ret = agent_party_init(myaddr, ".1.3.6.1")){
+   if (ret == 1){
+       fprintf(stderr, "Conflict found with initial noAuth/noPriv parties... continuing\n");
+   } else if (ret == -1){
+       fprintf(stderr, "Error installing initial noAuth/noPriv parties, exiting\n");
+       exit(1);
+   } else {
+       fprintf(stderr, "Unknown error, exiting\n");
+       exit(2);
+   }
+    }
 
-       int smux_fd = NOTOK;
-       int rock_and_roll = 0;
-       int dont_bother_anymore = 0;
-       int quantum = 0;
-static OID   subtree[NUMMIBS] = NULLOID;
-static struct smuxEntry *se = NULL;
-extern int smux_errno;
-extern char smux_info[BUFSIZ];
+    printf("Opening port(s): ");
+    fflush(stdout);
+    party_scanInit();
+    for(pp = party_scanNext(); pp; pp = party_scanNext()){
+   if ((pp->partyTDomain != DOMAINSNMPUDP)
+       || bcmp((char *)&myaddr, pp->partyTAddress, 4))
+       continue;  /* don't listen for non-local parties */
+
+   dest_port = 0;
+   bcopy(pp->partyTAddress + 4, &dest_port, 2);
+   for(index = 0; index < sdlen; index++)
+       if (dest_port == portlist[index])
+      break;
+   if (index < sdlen)  /* found a hit before the end of the list */
+       continue;
+   printf("%u ", dest_port);
+   fflush(stdout);
+   /* Set up connections */
+   sd = socket(AF_INET, SOCK_DGRAM, 0);
+   if (sd < 0){
+       perror("socket");
+       return 1;
+   }
+   me.sin_family = AF_INET;
+   me.sin_addr.s_addr = INADDR_ANY;
+   /* already in network byte order (I think) */
+   me.sin_port = dest_port;
+   if (bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0){
+       perror("bind");
+       return 2;
+   }
+   register_input_handler(sd, snmp_read_packet);
+   portlist[sdlen] = dest_port;
+   if (++sdlen == 32){
+       printf("No more sockets... ignoring rest of file\n");
+       break;
+   }
+    }
+    printf("\n");
+    bzero((char *)addrCache, sizeof(addrCache));
+}
 
 /*
- * Place an IP address into an OID starting at element n 
+ * Place an IP address into an OID starting at element n
  */
 void
-put_address(oid, addr, n)
-   OID oid;
+put_address(name, addr, n)
+   oid  *name;
    u_long addr;
    int n;
 {
    int i;
 
    for (i=n+3; i>=n+0; i--) {
-      oid->oid_elements[i] = addr & 0xFF;
+      name[i] = addr & 0xFF;
       addr >>= 8;
    }
 }
 
 /* Get an IP address from an OID starting at element n */
 int
-get_address(oid, addr, n)
-   OID oid;
+get_address(name, length, addr, n)
+   oid  *name; 
+   int   length;
    u_long *addr;
    int n;
 {
@@ -60,106 +139,75 @@ get_address(oid, addr, n)
 
    (*addr) = 0;
 
-   if (oid -> oid_nelem < n+4)
+   if (length < n+4)
       return 0;
 
    for (i=n; i<n+4; i++) {
       (*addr) <<= 8;
-      if (i >= oid->oid_nelem)
+      if (i >= length)
           ok = 0;
       else
-         (*addr) |= oid->oid_elements[i];
+         (*addr) |= name[i];
    }
-
    return ok;
 }
 
 /*
- *  Attempt to start up SMUX protocol
+ * Implements scalar objects from DVMRP and Multicast MIBs
  */
-void
-try_smux_init()
+u_char *
+o_scalar(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
 {
-    if (smux_fd != NOTOK || dont_bother_anymore) 
-       return;
-    if ((smux_fd = smux_init(debug)) == NOTOK) {
-       log(LOG_WARNING, 0,"smux_init: %s [%s]", smux_error(smux_errno), 
-        smux_info);
-    } else 
-       rock_and_roll = 0;
-}
+    int result;
 
-/* 
- * Implements scalar objects from both MIBs 
- */
-static int 
-o_scalar(oi, v, offset)
-   OI oi;
-   register struct type_SNMP_VarBind *v;
-   int offset;
-{
-    int     ifvar;
-    register OID    oid = oi -> oi_name;
-    register OT     ot = oi -> oi_type;
-
-    ifvar = (int) ot -> ot_info;
-    switch (offset) {
-        case type_SNMP_SMUX__PDUs_get__request:
-            if (oid -> oid_nelem !=
-                        ot -> ot_name -> oid_nelem + 1
-                    || oid -> oid_elements[oid -> oid_nelem - 1]
-                            != 0)
-                return int_SNMP_error__status_noSuchName;
-            break;
-
-        case type_SNMP_SMUX__PDUs_get__next__request:
-            if (oid -> oid_nelem
-                    == ot -> ot_name -> oid_nelem) {
-                OID     new;
-
-                if ((new = oid_extend (oid, 1)) == NULLOID)
-                    return int_SNMP_error__status_genErr;
-                new -> oid_elements[new -> oid_nelem - 1] = 0;
-
-                if (v -> name)
-                    free_SNMP_ObjectName (v -> name);
-                v -> name = new;
-            }
-            else
-                return NOTOK;
-            break;
-
-        default:
-            return int_SNMP_error__status_genErr;
-    }
+    *write_method = 0;
+    result = compare(name, *length, vp->name, (int)vp->namelen);
+    if ((exact && (result != 0)) || (!exact && (result >= 0)))
+   return NULL;
+
+       bcopy((char *)vp->name, (char *)name,
+     (int)vp->namelen * sizeof(oid));
+       *length = vp->namelen;
+       *var_len = sizeof(long);
 
-    switch (ifvar) {
-        case ipMRouteEnable:
-            return o_integer (oi, v, 1);
+    switch (vp->magic) {
 
-        case dvmrpVersion: {
-            static char buff[15];
+    case ipMRouteEnable:
+       long_return = 1;
+       return (u_char *) &long_return;
+
+    case dvmrpVersion: {
+       static char buff[15];
 
-            sprintf(buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION);
-            return o_string (oi, v, buff, strlen (buff));
-        }
+       sprintf(buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION);
+       *var_len = strlen(buff);
+       return (u_char *)buff;
+    }
 
-        case dvmrpGenerationId:
-            return o_integer (oi, v, dvmrp_genid);
+    case dvmrpGenerationId:
+       long_return = dvmrp_genid;
+       return (u_char *) &long_return;
 
-        default:
-            return int_SNMP_error__status_noSuchName;
+    default:
+       ERROR("");
     }
+    return NULL;
 }
 
-/* 
+/*
  * Find if a specific scoped boundary exists on a Vif
  */
 struct vif_acl *
 find_boundary(vifi, addr, mask)
-   int vifi;
-   int addr;
-   int mask;
+   vifi_t vifi;
+   u_long addr;
+   u_long mask;
 {
    struct vif_acl *n;
 
@@ -171,13 +219,13 @@ find_boundary(vifi, addr, mask)
 }
 
 /*
- * Find the next scoped boundary in order after a given spec
+ * Find the lowest boundary >= (V,A,M) spec
  */
 struct vif_acl *
 next_boundary(vifi, addr, mask)
-   int *vifi;
-   int  addr;
-   int  mask;
+   vifi_t *vifi;
+   u_long  addr;
+   u_long  mask;
 {
    struct vif_acl *bestn, *n;
    int  i;
@@ -185,9 +233,9 @@ next_boundary(vifi, addr, mask)
    for (i = *vifi; i < numvifs; i++) {
       bestn = NULL;
       for (n = uvifs[i].uv_acl; n; n=n->acl_next) {
-         if ((i > *vifi || n->acl_addr > addr 
-           || (n->acl_addr==addr && n->acl_mask>mask)) 
-          && (!bestn || n->acl_addr < bestn->acl_addr 
+         if ((i > *vifi || n->acl_addr > addr
+           || (n->acl_addr == addr && n->acl_mask >= mask))
+          && (!bestn || n->acl_addr < bestn->acl_addr
            || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask)))
             bestn = n;
       }
@@ -202,97 +250,100 @@ next_boundary(vifi, addr, mask)
 /*
  * Implements the Boundary Table portion of the DVMRP MIB
  */
-static int  
-o_dvmrpBoundaryTable (oi, v, offset)
-OI     oi;
-register struct type_SNMP_VarBind *v;
+u_char *
+o_dvmrpBoundaryTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
 {
-    int            ifvar, vifi,
-           addr, mask;
-    register OID    oid = oi -> oi_name;
-    register OT           ot = oi -> oi_type;
+    vifi_t     vifi;
+    u_long        addr, mask;
     struct vif_acl *bound;
+    oid        newname[MAX_NAME_LEN];
+    int        len;
 
-    ifvar = (int) ot -> ot_info;
-    switch (offset) {
-       case type_SNMP_SMUX__PDUs_get__request:
-           if (oid->oid_nelem != ot->ot_name->oid_nelem + 9)
-               return int_SNMP_error__status_noSuchName;
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
 
-      if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs)
-      return int_SNMP_error__status_noSuchName;
+    if (exact) {
+           if (*length != vp->namelen + 9)
+               return NULL;
 
-      if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1)
-       || !get_address(oid, &mask, ot->ot_name->oid_nelem+5))
-               return int_SNMP_error__status_noSuchName;
+      if ((vifi = name[vp->namelen]) >= numvifs)
+      return NULL;
 
-      if (!(bound = find_boundary(vifi, addr, mask)))
-               return int_SNMP_error__status_noSuchName;
-           break;
-
-       case type_SNMP_SMUX__PDUs_get__next__request:
-           if (oid->oid_nelem < ot->ot_name->oid_nelem + 9) {
-               OID     new;
-
-      if (oid->oid_nelem == ot->ot_name->oid_nelem) {
-         vifi = addr = mask = 0;
-      } else {
-         vifi = oid->oid_elements[ot->ot_name->oid_nelem];
-         get_address(oid, &addr, ot->ot_name->oid_nelem+1);
-         get_address(oid, &mask, ot->ot_name->oid_nelem+5);
-      }
+      if (!get_address(name, *length, &addr, vp->namelen+1)
+       || !get_address(name, *length, &mask, vp->namelen+5))
+               return NULL;
 
-      bound = next_boundary(&vifi,addr,mask);
-      if (!bound)
-         return NOTOK;
+      if (!(bound = find_boundary(vifi, addr, mask)))
+               return NULL;
+
+       bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
+        } else {
+       len = *length;
+       if (compare(name, *length, vp->name, vp->namelen) < 0)
+          len = vp->namelen;
+
+           if (len < vp->namelen + 9) { /* get first entry */
+
+         if (len == vp->namelen) {
+            vifi = addr = mask = 0;
+         } else {
+            vifi = name[vp->namelen];
+            get_address(name, len, &addr, vp->namelen+1);
+            get_address(name, len, &mask, vp->namelen+5);
+         }
 
-               new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem);
-               if (new == NULLOID)
-                   return NOTOK;
-               new -> oid_elements[ot->ot_name->oid_nelem] = vifi;
-      put_address(new, bound->acl_addr, ot->ot_name->oid_nelem+1);
-      put_address(new, bound->acl_mask, ot->ot_name->oid_nelem+5);
+         bound = next_boundary(&vifi,addr,mask);
+         if (!bound)
+            return NULL;
 
-               if (v -> name)
-                   free_SNMP_ObjectName (v -> name);
-               v -> name = new;
+               newname[vp->namelen] = vifi;
+         put_address(newname, bound->acl_addr, vp->namelen+1);
+         put_address(newname, bound->acl_mask, vp->namelen+5);
            } else {  /* get next entry given previous */
-               int     i = ot -> ot_name -> oid_nelem;
+                  vifi = name[vp->namelen];
+         get_address(name, *length, &addr, vp->namelen+1);
+         get_address(name, *length, &mask, vp->namelen+5);
 
-                  vifi = oid->oid_elements[i];
-         get_address(oid, &addr, ot->ot_name->oid_nelem+1);
-         get_address(oid, &mask, ot->ot_name->oid_nelem+5);
          if (!(bound = next_boundary(&vifi,addr,mask+1)))
-            return NOTOK;
+            return NULL;
 
-         put_address(oid, bound->acl_addr, ot->ot_name->oid_nelem+1);
-         put_address(oid, bound->acl_mask, ot->ot_name->oid_nelem+5);
-                  oid->oid_elements[i] = vifi;
-                  oid->oid_nelem = i + 9;
+                  newname[vp->namelen] = vifi;
+         put_address(newname, bound->acl_addr, vp->namelen+1);
+         put_address(newname, bound->acl_mask, vp->namelen+5);
            }
-           break;
-
-       default:
-           return int_SNMP_error__status_genErr;
     }
 
-    switch (ifvar) {
+    /* Save new OID */
+    *length = vp->namelen + 9;
+    bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
+    *write_method = 0;
+    *var_len = sizeof(long);
+
+    switch (vp->magic) {
 
    case dvmrpBoundaryVifIndex:
-       return o_integer (oi, v, vifi);
+       long_return = vifi;
+       return (u_char *) &long_return;
 
-       default:
-           return int_SNMP_error__status_noSuchName;
+    default:
+       ERROR("");
     }
+    return NULL;
 }
 
-/* 
- * Given a vif index and address, return the next greater neighbor entry 
+/*
+ * Find the lowest neighbor >= (V,A) spec
  */
 struct listaddr *
 next_neighbor(vifi, addr)
-   int *vifi;
-   int  addr;
+   vifi_t *vifi;
+   u_long  addr;
 {
    struct listaddr *bestn, *n;
    int  i;
@@ -300,7 +351,7 @@ next_neighbor(vifi, addr)
    for (i = *vifi; i < numvifs; i++) {
       bestn = NULL;
       for (n = uvifs[i].uv_neighbors; n; n=n->al_next) {
-         if ((i > *vifi || n->al_addr > addr) 
+         if ((i > *vifi || n->al_addr >= addr)
           && (!bestn || n->al_addr < bestn->al_addr))
             bestn = n;
       }
@@ -317,8 +368,8 @@ next_neighbor(vifi, addr)
  */
 struct listaddr *
 find_neighbor(vifi, addr)
-   int vifi;
-   int addr;
+   vifi_t vifi;
+   u_long addr;
 {
    struct listaddr *n;
 
@@ -329,979 +380,908 @@ find_neighbor(vifi, addr)
    return NULL;
 }
 
-/*
- * Implements the Neighbor Table portion of the DVMRP MIB
- */
-static int  
-o_dvmrpNeighborTable (oi, v, offset)
-OI     oi;
-register struct type_SNMP_VarBind *v;
+u_char *
+o_dvmrpNeighborTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
 {
-    int            ifvar, vifi,
-           addr;
-    register OID    oid = oi -> oi_name;
-    register OT           ot = oi -> oi_type;
+    vifi_t     vifi;
+    u_long     addr, mask;
     struct listaddr *neighbor;
+    oid        newname[MAX_NAME_LEN];
+    int        len;
 
-    ifvar = (int) ot -> ot_info;
-    switch (offset) {
-       case type_SNMP_SMUX__PDUs_get__request:
-           if (oid->oid_nelem != ot->ot_name->oid_nelem + 5)
-               return int_SNMP_error__status_noSuchName;
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
 
-      if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs)
-      return int_SNMP_error__status_noSuchName;
+    if (exact) {
+           if (*length != vp->namelen + 5)
+               return NULL;
 
-      if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1))
-               return int_SNMP_error__status_noSuchName;
+      if ((vifi = name[vp->namelen]) >= numvifs)
+      return NULL;
 
-      if (!(neighbor = find_neighbor(vifi, addr)))
-               return int_SNMP_error__status_noSuchName;
-           break;
+      if (!get_address(name, *length, &addr, vp->namelen+1))
+               return NULL;
 
-       case type_SNMP_SMUX__PDUs_get__next__request:
-           if (oid->oid_nelem < ot->ot_name->oid_nelem + 5) { 
-               OID     new;
+      if (!(neighbor = find_neighbor(vifi, addr)))
+               return NULL;
 
-      if (oid->oid_nelem == ot->ot_name->oid_nelem) {
-         vifi = addr = 0;
-      } else {
-         vifi = oid->oid_elements[ot->ot_name->oid_nelem];
-         get_address(oid, &addr, ot->ot_name->oid_nelem+1);
-      }
+       bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
+        } else {
+       len = *length;
+       if (compare(name, *length, vp->name, vp->namelen) < 0)
+          len = vp->namelen;
 
-      neighbor = next_neighbor(&vifi,addr); /* Get first entry */
-      if (!neighbor)
-         return NOTOK;
+           if (len < vp->namelen + 5) { /* get first entry */
 
-               new = oid_extend (oid, ot->ot_name->oid_nelem+5-oid->oid_nelem);
-               if (new == NULLOID)
-                   return NOTOK;
-               new -> oid_elements[ot->ot_name->oid_nelem] = vifi;
-      put_address(new, neighbor->al_addr, ot->ot_name->oid_nelem+1);
+         if (len == vp->namelen) {
+            vifi = addr = 0;
+         } else {
+            vifi = name[vp->namelen];
+            get_address(name, len, &addr, vp->namelen+1);
+         }
 
-               if (v -> name)
-                   free_SNMP_ObjectName (v -> name);
-               v -> name = new;
+         neighbor = next_neighbor(&vifi,addr);
+         if (!neighbor)
+            return NULL;
 
+               newname[vp->namelen] = vifi;
+         put_address(newname, neighbor->al_addr, vp->namelen+1);
            } else {  /* get next entry given previous */
-               int     i = ot -> ot_name -> oid_nelem;
+                  vifi = name[vp->namelen];
+         get_address(name, *length, &addr, vp->namelen+1);
 
-                  vifi = oid->oid_elements[i];
-         get_address(oid, &addr, ot->ot_name->oid_nelem+1);
          if (!(neighbor = next_neighbor(&vifi,addr+1)))
-            return NOTOK;
+            return NULL;
 
-         put_address(oid, neighbor->al_addr, ot->ot_name->oid_nelem+1);
-                  oid->oid_elements[i] = vifi;
-                  oid->oid_nelem = i + 5;
+                  newname[vp->namelen] = vifi;
+         put_address(newname, neighbor->al_addr, vp->namelen+1);
            }
-           break;
-
-       default:
-           return int_SNMP_error__status_genErr;
     }
 
-    switch (ifvar) {
+    /* Save new OID */
+    *length = vp->namelen + 5;
+    bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
+    *write_method = 0;
+    *var_len = sizeof(long);
+
+    switch (vp->magic) {
 
    case dvmrpNeighborUpTime: {
        time_t currtime;
        time(&currtime);
-       return o_integer (oi, v, (currtime - neighbor->al_ctime)*100);
+       long_return = (currtime - neighbor->al_ctime)*100;
+       return (u_char *) &long_return;
    }
 
-   case dvmrpNeighborExpiryTime:
-       return o_integer (oi, v, (NEIGHBOR_EXPIRE_TIME-neighbor->al_timer) * 100);
+   case dvmrpNeighborExpiryTime: 
+       long_return = (NEIGHBOR_EXPIRE_TIME - neighbor->al_timer 
+        + secs_remaining_offset()) * 100;
+       return (u_char *) &long_return;
 
    case dvmrpNeighborVersion: {
        static char buff[15];
 
        sprintf(buff, "%d.%d", neighbor->al_pv, neighbor->al_mv);
-       return o_string (oi, v, buff, strlen (buff));
+       *var_len = strlen(buff);
+       return (u_char *)buff;
    }
 
-   case dvmrpNeighborGenerationId: 
-       return o_integer (oi, v, neighbor->al_genid);
+   case dvmrpNeighborGenerationId:
+       long_return = neighbor->al_genid;
+       return (u_char *) &long_return;
 
-       default:
-           return int_SNMP_error__status_noSuchName;
+    default:
+       ERROR("");
+    }
+    return NULL;
+}
+
+/* Look up ifIndex given uvifs[ifnum].uv_lcl_addr */
+struct in_ifaddr *        /* returns: in_ifaddr structure, or null on error */
+ipaddr_to_ifindex(ipaddr, ifIndex)
+   u_long ipaddr;
+   int   *ifIndex;
+{
+    int interface;
+static struct in_ifaddr in_ifaddr;
+
+    Interface_Scan_Init();
+    for (;;) {
+       if (Interface_Scan_Next(&interface, (char *)0, NULL, &in_ifaddr) == 0) 
+          return NULL;
+    
+       if (((struct sockaddr_in *) &(in_ifaddr.ia_addr))->sin_addr.s_addr 
+        == ipaddr) {
+          *ifIndex = interface;
+          return &in_ifaddr;
+       }
     }
 }
 
 /*
- * Given a virtual interface number, make sure we have the current
- * kernel information for that Vif.
+ * Find if a specific scoped boundary exists on a Vif
  */
-refresh_vif(v_req, ifnum)
-   struct sioc_vif_req *v_req;
-   int ifnum;
+struct listaddr *
+find_cache(grp, vifi)
+   u_long grp;
+   vifi_t vifi;
 {
-   static   int lastq = -1;
+   struct listaddr *n;
 
-   if (quantum!=lastq || v_req->vifi != ifnum) {
-       lastq = quantum;
-       v_req->vifi = ifnum;
-       if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
-          v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
+   for (n = uvifs[vifi].uv_groups; n != NULL; n = n->al_next) {
+      if (grp == n->al_addr)
+         return n;
    }
+   return NULL;
 }
 
 /*
- * Implements the Multicast Routing Interface Table portion of the Multicast MIB
+ * Find the next group cache entry >= (A,V) spec
  */
-static int  
-o_ipMRouteInterfaceTable (oi, v, offset)
-OI     oi;
-register struct type_SNMP_VarBind *v;
-int    offset;
+struct listaddr *
+next_cache(addr, vifi)
+   u_long  addr;
+   vifi_t *vifi;
 {
-    int            ifnum,
-           ifvar;
-    register OID    oid = oi -> oi_name;
-    register OT           ot = oi -> oi_type;
-static struct sioc_vif_req v_req;
+   struct listaddr *bestn=NULL, *n;
+   int  i, besti;
+
+   /* Step through all entries looking for the next one */
+   for (i = 0; i < numvifs; i++) {
+      for (n = uvifs[i].uv_groups; n; n=n->al_next) {
+         if ((n->al_addr > addr || (n->al_addr == addr && i >= *vifi))
+          && (!bestn || n->al_addr < bestn->al_addr 
+           || (n->al_addr == bestn->al_addr && i < besti))) {
+            bestn = n;
+            besti = i;
+         }
+      }
+   }
 
-    ifvar = (int) ot -> ot_info;
-    switch (offset) {
-       case type_SNMP_SMUX__PDUs_get__request:
-           if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1)
-               return int_SNMP_error__status_noSuchName;
-           if ((ifnum = oid -> oid_elements[oid -> oid_nelem - 1]) >= numvifs)
-               return int_SNMP_error__status_noSuchName;
-           break;
+   if (bestn) {
+      *vifi = besti;
+      return bestn;
+   }
+   return NULL;
+}
 
-       case type_SNMP_SMUX__PDUs_get__next__request:
-           if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
-               OID     new;
+/*
+ * Implements the IGMP Cache Table portion of the IGMP MIB
+ */
+u_char *
+o_igmpCacheTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
+{
+    vifi_t     vifi;
+    u_long     grp;
+    int              ifIndex;
+    struct listaddr *cache;
+    oid        newname[MAX_NAME_LEN];
+    int        len;
+    struct in_ifaddr *in_ifaddr;
+    struct in_multi   in_multi, *inm;
+
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
+
+    if (exact) {
+           if (*length != vp->namelen + 5)
+               return NULL;
+
+      if ((vifi = name[vp->namelen+4]) >= numvifs)
+      return NULL;
+
+      if (!get_address(name, *length, &grp, vp->namelen))
+               return NULL;
+
+      if (!(cache = find_cache(grp, vifi)))
+               return NULL;
+
+       bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
+        } else {
+       len = *length;
+       if (compare(name, *length, vp->name, vp->namelen) < 0)
+          len = vp->namelen;
+
+           if (len < vp->namelen + 5) { /* get first entry */
+
+         if (len == vp->namelen) {
+            vifi = grp = 0;
+         } else {
+            get_address(name, len, &grp, vp->namelen);
+            vifi = name[vp->namelen+4];
+         }
 
-               ifnum = 0;
+         cache = next_cache(grp,&vifi);
+         if (!cache)
+            return NULL;
 
-               if ((new = oid_extend (oid, 1)) == NULLOID)
-                   return NOTOK;
-               new -> oid_elements[new -> oid_nelem - 1] = ifnum;
+         put_address(newname, cache->al_addr, vp->namelen);
+               newname[vp->namelen+4] = vifi;
+           } else {  /* get next entry given previous */
+         get_address(name, *length, &grp, vp->namelen);
+                  vifi = name[vp->namelen+4]+1;
 
-               if (v -> name)
-                   free_SNMP_ObjectName (v -> name);
-               v -> name = new;
+         if (!(cache = next_cache(grp,&vifi)))
+            return NULL;
 
-           } else {
-               int     i = ot -> ot_name -> oid_nelem;
+         put_address(newname, cache->al_addr, vp->namelen);
+                  newname[vp->namelen+4] = vifi;
+           }
+    }
 
-               if ((ifnum = oid -> oid_elements[i] + 1) >= numvifs)
-                   return NOTOK;
+    /* Save new OID */
+    *length = vp->namelen + 5;
+    bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
+    *write_method = 0;
+    *var_len = sizeof(long);
 
-               oid -> oid_elements[i] = ifnum;
-               oid -> oid_nelem = i + 1;
-           }
-           break;
+    /* Look up ifIndex given uvifs[vifi].uv_lcl_addr */
+    in_ifaddr = ipaddr_to_ifindex(uvifs[vifi].uv_lcl_addr, &ifIndex);
 
-       default:
-           return int_SNMP_error__status_genErr;
-    }
+    switch (vp->magic) {
 
-    switch (ifvar) {
-       case ipMRouteInterfaceTtl:
-           return o_integer (oi, v, uvifs[ifnum].uv_threshold);
+   case igmpCacheSelf: 
+       inm = in_ifaddr->ia_multiaddrs;
+       while (inm) {
+          klookup( (int)inm, (char *)&in_multi, sizeof(in_multi));
 
-       case dvmrpVInterfaceType:
-      if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
-         return o_integer (oi, v, 2); 
-      else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
-         return o_integer (oi, v, 1); 
-      else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
-         return o_integer (oi, v, 3); 
-      else                               /* SUBNET */
-         return o_integer (oi, v, 4); 
+          if (in_multi.inm_addr.s_addr == cache->al_addr) {
+             long_return = 1; /* true */
+             return (u_char *) &long_return;
+          }
 
-       case dvmrpVInterfaceState: 
-      if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
-         return o_integer (oi, v, 3);
-      else if (uvifs[ifnum].uv_flags & VIFF_DOWN)
-         return o_integer (oi, v, 2);
-      else /* UP */
-         return o_integer (oi, v, 1); 
+          inm = in_multi.inm_next;
+       }
+       long_return = 2; /* false */
+       return (u_char *) &long_return;
 
-   case dvmrpVInterfaceLocalAddress: {
-      struct sockaddr_in tmp;
-      tmp.sin_addr.s_addr = uvifs[ifnum].uv_lcl_addr;
-      return o_ipaddr (oi, v, &tmp);
-   }
+   case igmpCacheLastReporter:
+       return (u_char *) &cache->al_genid;
 
-   case dvmrpVInterfaceRemoteAddress: {
-      struct sockaddr_in tmp;
-      tmp.sin_addr.s_addr = (uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
-         uvifs[ifnum].uv_rmt_addr :
-         uvifs[ifnum].uv_subnet;
-      return o_ipaddr (oi, v, &tmp);
+   case igmpCacheUpTime: {
+      time_t currtime;
+      time(&currtime);
+      long_return = (currtime - cache->al_ctime)*100;
+      return (u_char *) &long_return;
    }
 
-   case dvmrpVInterfaceRemoteSubnetMask: {
-      struct sockaddr_in tmp;
-      tmp.sin_addr.s_addr = uvifs[ifnum].uv_subnetmask;
-      return o_ipaddr (oi, v, &tmp);
-   }
+   case igmpCacheExpiryTime: 
+       long_return = secs_remaining(cache->al_timerid)*100;
+       return (u_char *) &long_return;
 
-       case dvmrpVInterfaceMetric:
-           return o_integer (oi, v, uvifs[ifnum].uv_metric);
+   case igmpCacheStatus: 
+       long_return = 1;
+       return (u_char *) &long_return;
 
-       case dvmrpVInterfaceRateLimit:
-           return o_integer (oi, v, uvifs[ifnum].uv_rate_limit);
+    default:
+       ERROR("");
+    }
+    return NULL;
+}
 
-       case dvmrpVInterfaceInPkts:
-       refresh_vif(&v_req, ifnum);
-           return o_integer(oi, v, v_req.icount);
+/*
+ * Implements the IGMP Interface Table portion of the IGMP MIB
+ */
+u_char *
+o_igmpInterfaceTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
+{
+    oid                        newname[MAX_NAME_LEN];
+    register int       ifnum;
+    int result;
+static struct sioc_vif_req v_req;
 
-       case dvmrpVInterfaceOutPkts:
-       refresh_vif(&v_req, ifnum);
-           return o_integer(oi, v, v_req.ocount);
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
+
+    /* find "next" interface */
+    for(ifnum = 0; ifnum < numvifs; ifnum++){
+       if (!(uvifs[ifnum].uv_flags & VIFF_QUERIER))
+           continue;
+       newname[vp->namelen] = (oid)ifnum;
+       result = compare(name, *length, newname, (int)vp->namelen + 1);
+       if ((exact && (result == 0)) || (!exact && (result < 0)))
+          break;
+    }
+    if (ifnum >= numvifs)
+       return NULL;
 
-       case dvmrpVInterfaceInOctets:
-       refresh_vif(&v_req, ifnum);
-           return o_integer(oi, v, v_req.ibytes);
+    /* Save new OID */
+    bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
+    *length = vp->namelen + 1;
+    *write_method = 0;
+    *var_len = sizeof(long);
 
-       case dvmrpVInterfaceOutOctets:
-       refresh_vif(&v_req, ifnum);
-           return o_integer(oi, v, v_req.obytes);
+    switch (vp->magic){
+
+       case igmpInterfaceQueryInterval:
+               long_return = GROUP_QUERY_INTERVAL;
+      return (u_char *) &long_return;
+
+       case igmpInterfaceStatus:
+               long_return = 1; /* active */
+      return (u_char *) &long_return;
 
        default:
-           return int_SNMP_error__status_noSuchName;
+           ERROR("");
     }
+    return NULL;
 }
 
-struct mib_variable {
-   char     *name;        /* MIB variable name */
-   int     (*function)(); /* Function to call */
-   int       info;        /* Which variable */
-} mib_vars[] = {
- "ipMRouteEnable",               o_scalar, ipMRouteEnable,
- "ipMRouteUpstreamNeighbor",     o_ipMRouteTable,  ipMRouteUpstreamNeighbor,
- "ipMRouteInIfIndex",            o_ipMRouteTable,  ipMRouteInIfIndex,
- "ipMRouteUpTime",               o_ipMRouteTable,  ipMRouteUpTime, 
- "ipMRouteExpiryTime",           o_ipMRouteTable,  ipMRouteExpiryTime,
- "ipMRoutePkts",                 o_ipMRouteTable,  ipMRoutePkts, 
- "ipMRouteDifferentInIfIndexes", o_ipMRouteTable,  ipMRouteDifferentInIfIndexes,
- "ipMRouteOctets",               o_ipMRouteTable,  ipMRouteOctets,
- "ipMRouteProtocol",             o_ipMRouteTable,  ipMRouteProtocol,
- "ipMRouteNextHopState",      o_ipMRouteNextHopTable, ipMRouteNextHopState,
- "ipMRouteNextHopUpTime",     o_ipMRouteNextHopTable, ipMRouteNextHopUpTime,
- "ipMRouteNextHopExpiryTime", o_ipMRouteNextHopTable, ipMRouteNextHopExpiryTime,
- "ipMRouteNextHopClosestMemberHops", o_ipMRouteNextHopTable, ipMRouteNextHopClosestMemberHops,
- "ipMRouteNextHopProtocol",   o_ipMRouteNextHopTable, ipMRouteNextHopProtocol,
- "ipMRouteInterfaceTtl",  o_ipMRouteInterfaceTable, ipMRouteInterfaceTtl,
- "dvmrpVersion",               o_scalar, dvmrpVersion,
- "dvmrpGenerationId",          o_scalar, dvmrpGenerationId,
- "dvmrpVInterfaceType",     o_ipMRouteInterfaceTable, dvmrpVInterfaceType,
- "dvmrpVInterfaceState",    o_ipMRouteInterfaceTable, dvmrpVInterfaceState,
- "dvmrpVInterfaceLocalAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceLocalAddress,
- "dvmrpVInterfaceRemoteAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteAddress,
- "dvmrpVInterfaceRemoteSubnetMask", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteSubnetMask,
- "dvmrpVInterfaceMetric",    o_ipMRouteInterfaceTable, dvmrpVInterfaceMetric,
- "dvmrpVInterfaceRateLimit", o_ipMRouteInterfaceTable, dvmrpVInterfaceRateLimit,
- "dvmrpVInterfaceInPkts",    o_ipMRouteInterfaceTable, dvmrpVInterfaceInPkts,
- "dvmrpVInterfaceOutPkts",   o_ipMRouteInterfaceTable, dvmrpVInterfaceOutPkts,
- "dvmrpVInterfaceInOctets",  o_ipMRouteInterfaceTable, dvmrpVInterfaceInOctets,
- "dvmrpVInterfaceOutOctets", o_ipMRouteInterfaceTable, dvmrpVInterfaceOutOctets,
- "dvmrpNeighborUpTime",      o_dvmrpNeighborTable, dvmrpNeighborUpTime,
- "dvmrpNeighborExpiryTime",  o_dvmrpNeighborTable, dvmrpNeighborExpiryTime,
- "dvmrpNeighborVersion",     o_dvmrpNeighborTable, dvmrpNeighborVersion,
- "dvmrpNeighborGenerationId",o_dvmrpNeighborTable, dvmrpNeighborGenerationId,
- "dvmrpRouteUpstreamNeighbor", o_dvmrpRouteTable, dvmrpRouteUpstreamNeighbor,
- "dvmrpRouteInVifIndex",       o_dvmrpRouteTable, dvmrpRouteInVifIndex,
- "dvmrpRouteMetric",           o_dvmrpRouteTable, dvmrpRouteMetric,
- "dvmrpRouteExpiryTime",       o_dvmrpRouteTable, dvmrpRouteExpiryTime,
- "dvmrpRouteNextHopType",    o_dvmrpRouteNextHopTable, dvmrpRouteNextHopType,
- "dvmrpBoundaryVifIndex",    o_dvmrpBoundaryTable, dvmrpBoundaryVifIndex,
- 0, 0, 0
-};
-
 /*
- * Register variables as part of the MIBs
+ * Given a virtual interface number, make sure we have the current
+ * kernel information for that Vif.
  */
-void
-init_mib()
+refresh_vif(v_req, ifnum)
+   struct sioc_vif_req *v_req;
+   int ifnum;
 {
-   register OT ot;
-   int i;
+   static   int lastq = -1;
 
-   for (i=0; mib_vars[i].name; i++)
-      if (ot=text2obj(mib_vars[i].name)) {
-         ot->ot_getfnx = mib_vars[i].function;
-         ot->ot_info = (caddr_t)mib_vars[i].info;
-      }
+   if (quantum!=lastq || v_req->vifi != ifnum) {
+       lastq = quantum;
+       v_req->vifi = ifnum;
+       if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
+          v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
+   }
 }
 
 /*
- * Initialize the SNMP part of mrouted
+ * Implements the Multicast Routing Interface Table portion of the Multicast MIB
  */
-void
-snmp_init()
+u_char *
+o_ipMRouteInterfaceTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
 {
-    OT ot;
-    int i;
-
-    if (readobjects("mrouted.defs") == NOTOK)
-       log(LOG_ERR, 0, "readobjects: %s", PY_pepy);
-    for (i=0; i < NUMMIBS; i++) {
-       if ((ot = text2obj(mibs[i])) == NULL)
-          log(LOG_ERR, 0, "object \"%s\" not in \"%s\"",
-                 mibs[i], "mrouted.defs");
-       subtree[i] = ot -> ot_name;
+    oid                        newname[MAX_NAME_LEN];
+    register int       ifnum;
+    int result;
+static struct sioc_vif_req v_req;
+
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
+
+    /* find "next" interface */
+    for(ifnum = 0; ifnum < numvifs; ifnum++){
+       newname[vp->namelen] = (oid)ifnum;
+       result = compare(name, *length, newname, (int)vp->namelen + 1);
+       if ((exact && (result == 0)) || (!exact && (result < 0)))
+           break;
     }
-    init_mib();
-    try_smux_init();
-}
+    if (ifnum >= numvifs)
+       return NULL;
 
-/*
- * Process an SNMP "get" or "get-next" request
- */
-static  
-get_smux (pdu, offset)
-   register struct type_SNMP_GetRequest__PDU *pdu;
-   int     offset;
-{
-    int     idx,
-            status;
-    object_instance ois;
-    register struct type_SNMP_VarBindList *vp;
-    IFP method;
-
-    quantum = pdu -> request__id;
-    idx = 0;
-    for (vp = pdu -> variable__bindings; vp; vp = vp -> next) {
-        register OI     oi;
-        register OT     ot;
-        register struct type_SNMP_VarBind *v = vp -> VarBind;
-
-        idx++;
-
-        if (offset == type_SNMP_SMUX__PDUs_get__next__request) {
-            if ((oi = name2inst (v -> name)) == NULLOI
-                    && (oi = next2inst (v -> name)) == NULLOI)
-                goto no_name;
-
-            if ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP)
-                goto get_next;
-        }
-        else
-            if ((oi = name2inst (v -> name)) == NULLOI
-                    || (ot = oi -> oi_type) -> ot_getfnx
-                            == NULLIFP) {
-no_name: ;
-                pdu -> error__status =
-                        int_SNMP_error__status_noSuchName;
-                goto out;
-            }
-
-try_again: ;
-   switch (offset) {
-       case type_SNMP_SMUX__PDUs_get__request:
-      if (!(method = ot -> ot_getfnx))
-          goto no_name;
-      break;
+    /* Save new OID */
+    bcopy((char *)newname, (char *)name, ((int)vp->namelen + 1) * sizeof(oid));
+    *length = vp->namelen + 1;
+    *write_method = 0;
+    *var_len = sizeof(long);
 
-       case type_SNMP_SMUX__PDUs_get__next__request:
-    if (!(method = ot -> ot_getfnx))
-          goto get_next;
-      break;
+    switch (vp->magic){
 
-       case type_SNMP_SMUX__PDUs_set__request:
-      if (!(method = ot -> ot_setfnx))
-          goto no_name;
-      break;
+   case ipMRouteInterfaceTtl:
+       long_return = uvifs[ifnum].uv_threshold;
+       return (u_char *) &long_return;
 
-       default:
-      goto no_name;
-   }
+   case dvmrpVInterfaceType:
+      if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
+         long_return = 2;
+      else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
+         long_return = 1;
+      else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
+         long_return = 3;
+      else                               /* SUBNET */
+         long_return = 4;
+      return (u_char *) &long_return;
 
-        switch (status = (*ot -> ot_getfnx) (oi, v, offset)) {
-            case NOTOK:     /* get-next wants a bump */
-get_next: ;
-                oi = &ois;
-                for (;;) {
-                    if ((ot = ot -> ot_next) == NULLOT) {
-                        pdu -> error__status =
-                              int_SNMP_error__status_noSuchName;
-                        goto out;
-                    }
-                    oi -> oi_name =
-                                (oi -> oi_type = ot) -> ot_name;
-                    if (ot -> ot_getfnx)
-                        goto try_again;
-                }
-
-            case int_SNMP_error__status_noError:
-                break;
-
-            default:
-                pdu -> error__status = status;
-                goto out;
-        }
-    }
-    idx = 0;
+   case dvmrpVInterfaceState:
+      if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
+         long_return = 3;
+      else if ((uvifs[ifnum].uv_flags & VIFF_DOWN)
+       || ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) && (uvifs[ifnum].uv_neighbors==NULL)))
+         long_return = 2;
+      else /* UP */
+         long_return = 1;
+      return (u_char *) &long_return;
 
-out: ;
-    pdu -> error__index = idx;
+   case dvmrpVInterfaceLocalAddress: 
+      return (u_char *) &uvifs[ifnum].uv_lcl_addr;
 
-    if (smux_response (pdu) == NOTOK) {
-        log(LOG_WARNING,0,"smux_response: %s [%s]",
-               smux_error (smux_errno), smux_info);
-        smux_fd = NOTOK;
-    }
-}
+   case dvmrpVInterfaceRemoteAddress: 
+      return (u_char *) ((uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
+         &uvifs[ifnum].uv_rmt_addr :
+         &uvifs[ifnum].uv_subnet);
 
-/*
- * Handle SNMP "set" request by replying that it is illegal
- */
-static  
-set_smux(event)
-   struct type_SNMP_SMUX__PDUs *event;
-{
-    switch (event -> offset) {
-        case type_SNMP_SMUX__PDUs_set__request:
-            {
-                register struct type_SNMP_GetResponse__PDU *pdu =
-                                    event -> un.get__response;
-
-                pdu -> error__status = int_SNMP_error__status_noSuchName;
-                pdu -> error__index = pdu -> variable__bindings ? 1 : 0;
-
-                if (smux_response (pdu) == NOTOK) {
-                    log(LOG_WARNING, 0,
-                            "smux_response: %s [%s]",
-                            smux_error (smux_errno),
-                            smux_info);
-                    smux_fd = NOTOK;
-                }
-            }
-            break;
-
-        case type_SNMP_SMUX__PDUs_commitOrRollback:
-            {
-                struct type_SNMP_SOutPDU *cor =
-                                event -> un.commitOrRollback;
-
-                if (cor -> parm == int_SNMP_SOutPDU_commit) {
-                                    /* "should not happen" */
-                    (void) smux_close (protocolError);
-                    smux_fd = NOTOK;
-                }
-            }
-            break;
-    }
-}
+   case dvmrpVInterfaceRemoteSubnetMask:
+      return (u_char *) &uvifs[ifnum].uv_subnetmask;
 
-/* 
- *  Handle an incoming SNMP message
- */
-void
-doit_smux()
-{
-   struct type_SNMP_SMUX__PDUs *event;
-   if (smux_wait(&event, NOTOK)==NOTOK) {
-      if (smux_errno==inProgress)
-         return;
-      log(LOG_WARNING, 0, "smux_wait: %s [%s]", smux_error(smux_errno), 
-       smux_info);
-      smux_fd = NOTOK;
-      return;
-   }
+   case dvmrpVInterfaceMetric:
+       long_return = uvifs[ifnum].uv_metric;
+       return (u_char *) &long_return;
 
-   switch (event -> offset) {
-    case type_SNMP_SMUX__PDUs_registerResponse:
-        {
-            struct type_SNMP_RRspPDU *rsp =
-                        event -> un.registerResponse;
-
-            if (rsp -> parm == int_SNMP_RRspPDU_failure) {
-                log(LOG_WARNING,0,"SMUX registration of subtree failed");
-                dont_bother_anymore = 1;
-                (void) smux_close (goingDown);
-                break;
-            }
-        }
-        if (smux_trap(NULLOID, int_SNMP_generic__trap_coldStart, 0,
-                       (struct type_SNMP_VarBindList *)0) == NOTOK) {
-            log(LOG_WARNING,0,"smux_trap: %s [%s]", smux_error (smux_errno), 
-             smux_info);
-            break;
-        }
-        return;
-
-    case type_SNMP_SMUX__PDUs_get__request:
-    case type_SNMP_SMUX__PDUs_get__next__request:
-        get_smux (event -> un.get__request, event -> offset);
-        return;
-
-    case type_SNMP_SMUX__PDUs_close:
-        log(LOG_WARNING, 0, "SMUX close: %s", 
-         smux_error (event -> un.close -> parm));
-        break;
-
-    case type_SNMP_SMUX__PDUs_set__request:
-    case type_SNMP_SMUX__PDUs_commitOrRollback:
-        set_smux (event);
-        return;
+   case dvmrpVInterfaceRateLimit:
+       long_return = uvifs[ifnum].uv_rate_limit;
+       return (u_char *) &long_return;
 
-    default:
-        log(LOG_WARNING,0,"bad SMUX operation: %d", event -> offset);
-        (void) smux_close (protocolError);
-        break;
-   }
-   smux_fd = NOTOK;
-}
+   case dvmrpVInterfaceInPkts:
+       refresh_vif(&v_req, ifnum);
+       long_return = v_req.icount;
+       return (u_char *) &long_return;
 
-/* 
- * Inform snmpd that we are here and handling our MIBs
- */
-void
-start_smux()
-{
-   int i;
+   case dvmrpVInterfaceOutPkts:
+       refresh_vif(&v_req, ifnum);
+       long_return = v_req.ocount;
+       return (u_char *) &long_return;
 
-   for (i=0; i<NUMMIBS; i++) {
-      if ((se = getsmuxEntrybyname (mibs[i])) == NULL) {
-         log(LOG_WARNING,0,"no SMUX entry for \"%s\"", mibs[i]);
-         return;
-      }
-      /* Only open a new connection the first time through */
-      if (!i) {
-         if (smux_simple_open(&se->se_identity, mibs[i], 
-          se->se_password, strlen(se->se_password))==NOTOK) {
-            if (smux_errno == inProgress)
-               return;
-
-            log(LOG_WARNING, 0,"smux_simple_open: %s [%s]", 
-             smux_error(smux_errno), smux_info);
-            smux_fd = NOTOK;
-            return;
-         }
-         log(LOG_NOTICE,0, "SMUX open: %s \"%s\"",
-          oid2ode (&se->se_identity), se->se_name);
-         rock_and_roll = 1;
-      }
+   case dvmrpVInterfaceInOctets:
+       refresh_vif(&v_req, ifnum);
+       long_return = v_req.ibytes;
+       return (u_char *) &long_return;
 
-      if (smux_register(subtree[i], -1, readWrite)==NOTOK) {
-         log(LOG_WARNING, 0,"smux_register: %s [%s]", smux_error(smux_errno), 
-          smux_info);
-         smux_fd = NOTOK;
-         return;
-      }
-   }
-   log(LOG_NOTICE, 0, "SMUX registered");
+   case dvmrpVInterfaceOutOctets:
+       refresh_vif(&v_req, ifnum);
+       long_return = v_req.obytes;
+       return (u_char *) &long_return;
+
+       default:
+           ERROR("");
+    }
+    return NULL;
 }
 
 /*
- * Implements the DVMRP Route Table portion of the DVMRP MIB 
+ * Implements the DVMRP Route Table portion of the DVMRP MIB
  */
-int
-o_dvmrpRouteTable (oi, v, offset)
-OI oi;
-register struct type_SNMP_VarBind *v;
-int    offset;
+u_char *
+o_dvmrpRouteTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
 {
-    u_long   src, mask;
-    int            ifvar;
-    register OID    oid = oi -> oi_name;
-    register OT            ot = oi -> oi_type;
+    u_long src, mask;
+    oid        newname[MAX_NAME_LEN];
+    int        len;
     struct rtentry *rt = NULL;
 
-    ifvar = (int) ot -> ot_info;
-    switch (offset) {
-       case type_SNMP_SMUX__PDUs_get__request:
-      if (!get_address(oid, &src, ot->ot_name->oid_nelem)
-       || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
-       || !(rt = snmp_find_route(src,mask)))
-         return int_SNMP_error__status_noSuchName;
-      break;
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
 
-       case type_SNMP_SMUX__PDUs_get__next__request:
+    if (exact) {
+           if (*length != vp->namelen + 8)
+               return NULL;
 
-       /* Check if we're requesting the first row */
-      if (oid->oid_nelem < ot->ot_name->oid_nelem+8) {
-         OID   new;
+      if (!get_address(name, *length, &src, vp->namelen)
+       || !get_address(name, *length, &mask, vp->namelen+4))
+               return NULL;
 
-         /* Get partial specification (if any) */
-         get_address(oid, &src, ot->ot_name->oid_nelem);
-         get_address(oid, &mask, ot->ot_name->oid_nelem+4);
+      if (!(rt = snmp_find_route(src, mask)))
+               return NULL;
 
-         if (!next_route(&rt,src,mask)) /* Get first entry */
-            return NOTOK;
+       bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
+        } else {
+       len = *length;
+       if (compare(name, *length, vp->name, vp->namelen) < 0)
+          len = vp->namelen;
 
-         /* Extend by 8 more ints to hold index columns */
-         new = oid_extend (oid, ot->ot_name->oid_nelem+8-oid->oid_nelem);
-         if (new == NULLOID)
-            return NOTOK;
+           if (len < vp->namelen + 8) { /* get first entry */
 
-         put_address(new, rt->rt_origin,     ot->ot_name->oid_nelem);
-         put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4); 
+         if (len == vp->namelen) {
+            src = mask = 0;
+         } else {
+            get_address(name, len, &src, vp->namelen);
+            get_address(name, len, &mask, vp->namelen+4);
+         }
 
-         if (v -> name)
-            free_SNMP_ObjectName (v -> name);
-         v -> name = new;
+         if (!next_route(&rt,src,mask)) /* Get first entry */
+            return NULL;
 
-      /* Else we start from a previous row */
-      } else {
-         int   i = ot -> ot_name -> oid_nelem;
+         put_address(newname, rt->rt_origin    , vp->namelen);
+         put_address(newname, rt->rt_originmask, vp->namelen+4);
+           } else {  /* get next entry given previous */
+         get_address(name, *length, &src,  vp->namelen);
+         get_address(name, *length, &mask, vp->namelen+4);
 
-         /* Get the lowest entry in the table > the given grp/src/mask */
-         get_address(oid, &src, ot->ot_name->oid_nelem);
-         get_address(oid, &mask, ot->ot_name->oid_nelem+4);
          if (!next_route(&rt, src,mask))
-            return NOTOK; 
+            return NULL;
 
-         put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem);
-         put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4);
-      }
-      break;
+         put_address(newname, rt->rt_origin,     vp->namelen);
+         put_address(newname, rt->rt_originmask, vp->namelen+4);
+           }
+    }
 
-       default:
-          return int_SNMP_error__status_genErr;
-   }
+    /* Save new OID */
+    *length = vp->namelen + 8;
+    bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
+    *write_method = 0;
+    *var_len = sizeof(long);
 
-   switch (ifvar) {
-      case dvmrpRouteUpstreamNeighbor: {
-         struct sockaddr_in tmp;
-         tmp.sin_addr.s_addr = rt->rt_gateway;
-         return o_ipaddr (oi, v, &tmp);
-      }
+    switch (vp->magic) {
+
+      case dvmrpRouteUpstreamNeighbor: 
+         return (u_char *) &rt->rt_gateway;
 
       case dvmrpRouteInVifIndex:
-         return o_integer (oi, v, rt->rt_parent);
+         long_return = rt->rt_parent;
+         return (u_char *) &long_return;
 
       case dvmrpRouteMetric:
-         return o_integer (oi, v, rt->rt_metric);
+         long_return = rt->rt_metric;
+         return (u_char *) &long_return;
 
       case dvmrpRouteExpiryTime:
-         return o_integer (oi, v, rt->rt_timer*100);
+         long_return = (ROUTE_EXPIRE_TIME - rt->rt_timer 
+          + secs_remaining_offset()) * 100;
+         return (u_char *) &long_return;
 
-      default:
-         return int_SNMP_error__status_noSuchName;
-   }
+    default:
+       ERROR("");
+    }
+    return NULL;
 }
 
-/* 
- * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB 
+/*
+ * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB
  */
-int
-o_dvmrpRouteNextHopTable (oi, v, offset)
-OI oi;
-register struct type_SNMP_VarBind *v;
-int   offset;
+u_char *
+o_dvmrpRouteNextHopTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
 {
-    u_long   src, mask;
-    vifi_t   vifi;
-    int            ifvar;
-    register OID    oid = oi -> oi_name;
-    register OT            ot = oi -> oi_type;
+    u_long     src, mask;
+    vifi_t     vifi;
     struct rtentry *rt = NULL;
+    oid        newname[MAX_NAME_LEN];
+    int        len;
+
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
 
-    ifvar = (int) ot -> ot_info;
-    switch (offset) {
-       case type_SNMP_SMUX__PDUs_get__request:
-      if (oid->oid_nelem != ot->ot_name->oid_nelem+9)
-         return int_SNMP_error__status_noSuchName;
+    if (exact) {
+           if (*length != vp->namelen + 9)
+               return NULL;
 
-      if (!get_address(oid, &src, ot->ot_name->oid_nelem)
-       || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
+      if (!get_address(name, *length, &src, vp->namelen)
+       || !get_address(name, *length, &mask, vp->namelen+4)
        || (!(rt=snmp_find_route(src,mask))))
-         return int_SNMP_error__status_noSuchName;
+               return NULL;
 
-      vifi = oid->oid_elements[ot->ot_name->oid_nelem+8];
+      vifi = name[vp->namelen+8];
       if (!(VIFM_ISSET(vifi, rt->rt_children)))
-         return int_SNMP_error__status_noSuchName;
-      break;
+      return NULL;
 
-       case type_SNMP_SMUX__PDUs_get__next__request:
+       bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
+        } else {
+       len = *length;
+       if (compare(name, *length, vp->name, vp->namelen) < 0)
+          len = vp->namelen;
 
-      /* Check if we're requesting the first row */
-      if (oid->oid_nelem < ot->ot_name->oid_nelem+9) {
-         OID   new;
+           if (len < vp->namelen + 9) { /* get first entry */
 
-         get_address(oid, &src, ot->ot_name->oid_nelem);
-         get_address(oid, &mask, ot->ot_name->oid_nelem+4);
+         get_address(name, len, &src,  vp->namelen);
+         get_address(name, len, &mask, vp->namelen+4);
 
          /* Find first child vif */
          vifi=0;
          if (!next_route_child(&rt, src, mask, &vifi))
-            return NOTOK;
-
-         /* Extend by 9 more ints to hold index columns */
-         new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem);
-         if (new == NULLOID)
-            return NOTOK;
-
-         put_address(new, rt->rt_origin, ot->ot_name->oid_nelem);
-         put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4);
-         new->oid_elements[ot->ot_name->oid_nelem+8] = vifi;
-
-         if (v -> name)
-            free_SNMP_ObjectName (v -> name);
-         v -> name = new;
-
-      /* Else we start from a previous row */
-      } else {
-         int   i = ot -> ot_name -> oid_nelem;
+            return NULL;
 
-         /* Get the lowest entry in the table > the given grp/src/mask */
-         vifi = oid->oid_elements[oid->oid_nelem-1] + 1;
-         if (!get_address(oid, &src, ot->ot_name->oid_nelem)
-          || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
+         put_address(newname, rt->rt_origin,     vp->namelen);
+         put_address(newname, rt->rt_originmask, vp->namelen+4);
+               newname[vp->namelen+8] = vifi;
+           } else {  /* get next entry given previous */
+                  vifi = name[vp->namelen+8] + 1;
+         if (!get_address(name, *length, &src,  vp->namelen)
+          || !get_address(name, *length, &mask, vp->namelen+4)
           || !next_route_child(&rt, src, mask, &vifi))
-            return NOTOK;
+            return NULL;
 
-         put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem);
-         put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4);
-         oid->oid_elements[ot->ot_name->oid_nelem+8] = vifi;
-      }
-      break;
+         put_address(newname, rt->rt_origin,     vp->namelen);
+         put_address(newname, rt->rt_originmask, vp->namelen+4);
+                  newname[vp->namelen+8] = vifi;
+           }
+    }
 
-       default:
-          return int_SNMP_error__status_genErr;
-   }
+    /* Save new OID */
+    *length = vp->namelen + 9;
+    bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
+    *write_method = 0;
+    *var_len = sizeof(long);
 
-   switch (ifvar) {
+    switch (vp->magic) {
 
-      case dvmrpRouteNextHopType:
-         return o_integer (oi, v, (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2);
+    case dvmrpRouteNextHopType:
+       long_return = (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2;
+       return (u_char *) &long_return;
 
-      default:
-         return int_SNMP_error__status_noSuchName;
-   }
+    default:
+       ERROR("");
+    }
+    return NULL;
 }
 
-/* 
- * Implements the IP Multicast Route Table portion of the Multicast MIB 
+/*
+ * Implements the IP Multicast Route Table portion of the Multicast MIB
  */
-int  
-o_ipMRouteTable (oi, v, offset)
-OI     oi;
-register struct type_SNMP_VarBind *v;
-int    offset;
+u_char *
+o_ipMRouteTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
 {
     u_long src, grp, mask;
-    int            ifvar;
-    register OID    oid = oi -> oi_name;
-    register OT            ot = oi -> oi_type;
     struct gtable *gt = NULL;
     struct stable *st = NULL;
 static struct sioc_sg_req sg_req;
+    oid        newname[MAX_NAME_LEN];
+    int        len;
+
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
+
+    if (exact) {
+           if (*length != vp->namelen + 12)
+               return NULL;
 
-    ifvar = (int) ot -> ot_info;
-    switch (offset) {
-       case type_SNMP_SMUX__PDUs_get__request:
-      if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
-       || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
-       || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
+      if (!get_address(name, *length, &grp,  vp->namelen)
+       || !get_address(name, *length, &src,  vp->namelen+4)
+       || !get_address(name, *length, &mask, vp->namelen+8)
        || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */
        || !(gt = find_grp(grp))
        || !(st = find_grp_src(gt,src)))
-         return int_SNMP_error__status_noSuchName;
-      break;
+               return NULL;
 
-       case type_SNMP_SMUX__PDUs_get__next__request:
+       bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
+        } else {
+       len = *length;
+       if (compare(name, *length, vp->name, vp->namelen) < 0)
+          len = vp->namelen;
 
-       /* Check if we're requesting the first row */
-      if (oid->oid_nelem < ot->ot_name->oid_nelem+12) {
-         OID   new;
+           if (len < vp->namelen + 12) { /* get first entry */
 
-         /* Get partial specification (if any) */
-         get_address(oid, &grp, ot->ot_name->oid_nelem);
-         get_address(oid, &src, ot->ot_name->oid_nelem+4);
-         get_address(oid, &mask, ot->ot_name->oid_nelem+8);
+         get_address(name, len, &grp,  vp->namelen);
+         get_address(name, len, &src,  vp->namelen+4);
+         get_address(name, len, &mask, vp->namelen+8);
 
          if (!next_grp_src_mask(&gt,&st,grp,src,mask)) /* Get first entry */
-            return NOTOK;
-
-         /* Extend by 12 more ints to hold index columns */
-         new = oid_extend (oid, ot->ot_name->oid_nelem+12-oid->oid_nelem);
-         if (new == NULLOID)
-            return NOTOK;
-
-         put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
-         put_address(new, st->st_origin, ot->ot_name->oid_nelem+4);
-         put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8); 
-
-         if (v -> name)
-            free_SNMP_ObjectName (v -> name);
-         v -> name = new;
+            return NULL;
 
-      /* Else we start from a previous row */
-      } else {
-         int   i = ot -> ot_name -> oid_nelem;
+         put_address(newname, gt->gt_mcastgrp, vp->namelen);
+         put_address(newname, st->st_origin,   vp->namelen+4);
+         put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
+           } else {  /* get next entry given previous */
+         get_address(name, *length, &grp , vp->namelen);
+         get_address(name, *length, &src , vp->namelen+4);
+         get_address(name, *length, &mask, vp->namelen+8);
 
-         /* Get the lowest entry in the table > the given grp/src/mask */
-         get_address(oid, &grp, ot->ot_name->oid_nelem);
-         get_address(oid, &src, ot->ot_name->oid_nelem+4);
-         get_address(oid, &mask, ot->ot_name->oid_nelem+8);
          if (!next_grp_src_mask(&gt, &st, grp,src,mask))
-            return NOTOK; 
+            return NULL;
 
-         put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
-         put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4);
-         put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
-      }
-      break;
+         put_address(newname, gt->gt_mcastgrp, vp->namelen);
+         put_address(newname, st->st_origin,   vp->namelen+4);
+         put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
+           }
+    }
 
-       default:
-          return int_SNMP_error__status_genErr;
-   }
+    /* Save new OID */
+    *length = vp->namelen + 12;
+    bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
+    *write_method = 0;
+    *var_len = sizeof(long);
 
-   switch (ifvar) {
-      case ipMRouteUpstreamNeighbor: {
-         struct sockaddr_in tmp;
-         tmp.sin_addr.s_addr = gt->gt_route->rt_gateway;
-         return o_ipaddr (oi, v, &tmp);
-      }
+    switch (vp->magic) {
+
+      case ipMRouteUpstreamNeighbor: 
+         return (u_char *) &gt->gt_route->rt_gateway;
 
       case ipMRouteInIfIndex:
-         return o_integer (oi, v, gt->gt_route->rt_parent);
+         long_return = gt->gt_route->rt_parent;
+         return (u_char *) &long_return;
 
       case ipMRouteUpTime: {
          time_t currtime;
          time(&currtime);
-         return o_integer (oi, v, (currtime - gt->gt_ctime)*100);
+         long_return = (currtime - gt->gt_ctime)*100;
+         return (u_char *) &long_return;
       }
 
       case ipMRouteExpiryTime:
-         return o_integer (oi, v, gt->gt_timer*100);
+         long_return = 5*((gt->gt_timer+4)/5); /* round up to nearest 5 */
+         long_return = (long_return + secs_remaining_offset()) * 100;
+         return (u_char *) &long_return;
 
       case ipMRoutePkts:
          refresh_sg(&sg_req, gt, st);
-         return o_integer (oi, v, sg_req.pktcnt);
-    
+         long_return = sg_req.pktcnt;
+         return (u_char *) &long_return;
+
       case ipMRouteOctets:
          refresh_sg(&sg_req, gt, st);
-         return o_integer (oi, v, sg_req.bytecnt);
+         long_return = sg_req.bytecnt;
+         return (u_char *) &long_return;
 
       case ipMRouteDifferentInIfIndexes:
          refresh_sg(&sg_req, gt, st);
-         return o_integer (oi, v, sg_req.wrong_if);
+         long_return = sg_req.wrong_if;
+         return (u_char *) &long_return;
 
       case ipMRouteProtocol:
-         return o_integer (oi, v, 4);
+         long_return = 4;
+         return (u_char *) &long_return;
 
-      default:
-         return int_SNMP_error__status_noSuchName;
-   }
+    default:
+       ERROR("");
+    }
+    return NULL;
 }
 
-/* 
+/*
  * Implements the IP Multicast Routing Next Hop Table portion of the Multicast
- * MIB 
+ * MIB
  */
-int  
-o_ipMRouteNextHopTable (oi, v, offset)
-OI     oi;
-register struct type_SNMP_VarBind *v;
-int    offset;
+u_char *
+o_ipMRouteNextHopTable(vp, name, length, exact, var_len, write_method)
+    register struct variable *vp;   /* IN - pointer to variable entry that points here */
+    register oid       *name;      /* IN/OUT - input name requested, output name found */
+    register int       *length;    /* IN/OUT - length of input and output oid's */
+    int                        exact;      /* IN - TRUE if an exact match was requested. */
+    int                        *var_len;   /* OUT - length of variable or 0 if function returned. */
+    int                        (**write_method)(); /* OUT - pointer to function to set variable, otherwise 0 */
 {
     u_long src, grp, mask, addr;
     vifi_t   vifi;
-    int            ifvar;
-    register OID    oid = oi -> oi_name;
-    register OT            ot = oi -> oi_type;
     struct gtable *gt;
     struct stable *st;
+    oid        newname[MAX_NAME_LEN];
+    int        len;
+
+    /* Copy name OID to new OID */
+    bcopy((char *)vp->name, (char *)newname, (int)vp->namelen * sizeof(oid));
 
-    ifvar = (int) ot -> ot_info;
-    switch (offset) {
-       case type_SNMP_SMUX__PDUs_get__request:
-      if (oid->oid_nelem != ot->ot_name->oid_nelem+17)
-         return int_SNMP_error__status_noSuchName;
+    if (exact) {
+           if (*length != vp->namelen + 17)
+               return NULL;
 
-      if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
-       || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
-       || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
-       || !get_address(oid, &addr, ot->ot_name->oid_nelem+13)
+      if (!get_address(name, *length, &grp, vp->namelen)
+       || !get_address(name, *length, &src, vp->namelen+4)
+       || !get_address(name, *length, &mask, vp->namelen+8)
+       || !get_address(name, *length, &addr, vp->namelen+13)
        || grp!=addr
        || mask!=0xFFFFFFFF
        || (!(gt=find_grp(grp)))
        || (!(st=find_grp_src(gt,src))))
-         return int_SNMP_error__status_noSuchName;
+               return NULL;
 
-      vifi = oid->oid_elements[ot->ot_name->oid_nelem+12];
+      vifi = name[vp->namelen+12];
       if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children)))
-         return int_SNMP_error__status_noSuchName;
-      break;
+      return NULL;
 
-       case type_SNMP_SMUX__PDUs_get__next__request:
+       bcopy((char *)name, (char *)newname, ((int)*length) * sizeof(oid));
+        } else {
+       len = *length;
+       if (compare(name, *length, vp->name, vp->namelen) < 0)
+          len = vp->namelen;
 
-      /* Check if we're requesting the first row */
-      if (oid->oid_nelem < ot->ot_name->oid_nelem+17) {
-         OID   new;
+           if (len < vp->namelen + 17) { /* get first entry */
 
-         get_address(oid, &grp, ot->ot_name->oid_nelem);
-         get_address(oid, &src, ot->ot_name->oid_nelem+4);
-         get_address(oid, &mask, ot->ot_name->oid_nelem+8);
+         get_address(name, len, &grp, vp->namelen);
+         get_address(name, len, &src, vp->namelen+4);
+         get_address(name, len, &mask, vp->namelen+8);
 
          /* Find first child vif */
          vifi=0;
          if (!next_child(&gt, &st, grp, src, mask, &vifi))
-            return NOTOK;
-
-         /* Extend by 17 more ints to hold index columns */
-         new = oid_extend (oid, ot->ot_name->oid_nelem+17-oid->oid_nelem);
-         if (new == NULLOID)
-            return NOTOK;
-
-         put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
-         put_address(new, st->st_origin, ot->ot_name->oid_nelem+4);
-         put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
-         new->oid_elements[ot->ot_name->oid_nelem+12] = vifi;
-         put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13);
-
-         if (v -> name)
-            free_SNMP_ObjectName (v -> name);
-         v -> name = new;
-
-      /* Else we start from a previous row */
-      } else {
-         int   i = ot -> ot_name -> oid_nelem;
-
-         /* Get the lowest entry in the table > the given grp/src/mask */
-         vifi = oid->oid_elements[oid->oid_nelem-1] + 1;
-         if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
-          || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
-          || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
+            return NULL;
+
+         put_address(newname, gt->gt_mcastgrp, vp->namelen);
+         put_address(newname, st->st_origin,   vp->namelen+4);
+         put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
+               newname[vp->namelen+12] = vifi;
+         put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
+
+           } else {  /* get next entry given previous */
+                  vifi = name[vp->namelen+12]+1;
+         if (!get_address(name, *length, &grp,  vp->namelen)
+          || !get_address(name, *length, &src,  vp->namelen+4)
+          || !get_address(name, *length, &mask, vp->namelen+8)
           || !next_child(&gt, &st, grp, src, mask, &vifi))
-            return NOTOK;
+            return NULL;
 
-         put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
-         put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4);
-         put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
-         oid->oid_elements[ot->ot_name->oid_nelem+12] = vifi;
-         put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13);
-      }
-      break;
+         put_address(newname, gt->gt_mcastgrp, vp->namelen);
+         put_address(newname, st->st_origin,   vp->namelen+4);
+         put_address(newname, 0xFFFFFFFF,      vp->namelen+8);
+                  newname[vp->namelen+12] = vifi;
+         put_address(newname, gt->gt_mcastgrp, vp->namelen+13);
+           }
+    }
 
-       default:
-          return int_SNMP_error__status_genErr;
-   }
+    /* Save new OID */
+    *length = vp->namelen + 17;
+    bcopy((char *)newname, (char *)name, ((int)*length) * sizeof(oid));
+    *write_method = 0;
+    *var_len = sizeof(long);
 
-   switch (ifvar) {
+    switch (vp->magic) {
 
       case ipMRouteNextHopState:
-         return o_integer (oi, v, (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1);
+         long_return = (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1;
+         return (u_char *) &long_return;
 
       /* Currently equal to ipMRouteUpTime */
       case ipMRouteNextHopUpTime: {
          time_t currtime;
          time(&currtime);
-         return o_integer (oi, v, (currtime - gt->gt_ctime)*100);
+         long_return = (currtime - gt->gt_ctime)*100;
+         return (u_char *) &long_return;
       }
 
       case ipMRouteNextHopExpiryTime:
-         return o_integer (oi, v, gt->gt_prsent_timer);
+         long_return = 5*((gt->gt_prsent_timer+4)/5); /* round up to nearest 5*/
+         long_return = (long_return + secs_remaining_offset()) * 100;
+         return (u_char *) &long_return;
 
       case ipMRouteNextHopClosestMemberHops:
-         return o_integer (oi, v, 0);
+         long_return = 0;
+         return (u_char *) &long_return;
 
       case ipMRouteNextHopProtocol:
-         return o_integer (oi, v, 4);
+         long_return = 4;
+         return (u_char *) &long_return;
 
-      default:
-         return int_SNMP_error__status_noSuchName;
-   }
+    default:
+       ERROR("");
+    }
+    return NULL;
+}
+
+/* sync_timer is called by timer() every TIMER_INTERVAL seconds.
+ * Its job is to record this time so that we can compute on demand
+ * the approx # seconds remaining until the next timer() call
+ */
+static time_t lasttimer;
+
+void
+sync_timer()
+{
+    time(&lasttimer);
+}
+
+int /* in range [-TIMER_INTERVAL..0] */
+secs_remaining_offset()
+{
+   time_t tm;
+
+   time(&tm);
+   return lasttimer-tm;
 }
index c78c050..b2e203e 100644 (file)
@@ -1,505 +1,9 @@
-/*     $NetBSD: snmp.h,v 1.2 1995/10/09 03:52:00 thorpej Exp $ */
+/*     $NetBSD: snmp.h,v 1.3 1995/12/10 10:07:18 mycroft Exp $ */
 
-/*
- *    This file contains excepts from ISODE include files, and is 
- *    subject to the following notice:
- *
- * The ISODE is not proprietary, but it is not in the public domain.  This was
- * necessary to include a "hold harmless" clause in the release.  The upshot
- * of all this is that anyone can get a copy of the release and do anything
- * they want with it, but no one takes any responsibility whatsoever for any
- * (mis)use.
- */
-
-typedef u_char    PElementClass;
-typedef u_char    PElementForm;
-typedef u_short   PElementID;   /* 0..16383 are meaningful (14 bits) */
-typedef int       PElementLen;
-typedef u_char   *PElementData;
-typedef int     (*IFP) ();
-#define      INTDEF  long
-typedef INTDEF integer;
-#undef   IP
-typedef int *IP;
-#define      NULLIP          ((IP) 0)
-#define      NULLIFP         ((IFP) 0)
-#define      NULLFD          ((fd_set *) 0)
-#define      NULLCP          ((char *) 0)
-#define      NULLVP          ((char **) 0)
-
-#ifndef  SFD
-#if !defined(SVR3) && !defined(SUNOS4) && !defined(BSD44) && !defined(ultrix)
-#define  SFD   int
-#define  SFP   IFP
-#else
-#define  SFD   void
-#define  SFP   VFP
-#endif
-#endif
-
-typedef struct {
-   int   pe_type; /* Type of entry */
-   integer  pe_ucode;   /* index to user's code if any */
-   int   pe_tag;     /* Tag of this entry if any */
-   int   pe_flags;   /* Flags */
-}  tpe;
-
-typedef struct {
-   int   pe_type; /* Type of entry */
-   integer  pe_ucode;   /* index to user's code if any */
-   int   pe_tag;     /* Tag of this entry if any */
-   int   pe_flags;   /* Flags */
-   char **pe_typename; /* User defined name of variable */
-}  ptpe;
-
-typedef  struct   {
-   char  *md_name;   /* Name of this module */
-   int   md_nentries;   /* Number of entries */
-   tpe   **md_etab;  /* Pointer to encoding tables */
-   tpe   **md_dtab;  /* Pointer to decoding tables */
-   ptpe    **md_ptab;   /* Pointer to printing tables */
-   int   (*md_eucode)();   /* User code for encoding */
-   int   (*md_ducode)();   /* User code for decoding */
-   int   (*md_pucode)();   /* User code for printing */
-   caddr_t  *md_ptrtab; /* pointer table */
-}  modtyp;
-
-#define  type_SNMP_ObjectSyntax  PElement
-typedef struct PElement {
-    int      pe_errno;     /* Error codes */
-    int      pe_context;      /* indirect reference */
-    PElementClass pe_class;
-#define  PE_CLASS_UNIV  0x0   /*   Universal */
-    PElementForm  pe_form;
-#define  PE_FORM_PRIM   0x0   /*   PRIMitive */
-    PElementID pe_id;      /* should be extensible, 14 bits for now */
-#define  PE_PRIM_NULL   0x005 /*   Null */
-    PElementLen   pe_len;
-    PElementLen   pe_ilen;
-    union {
-   PElementData    un_pe_prim;   /* PRIMitive value */
-   struct PElement *un_pe_cons;  /* CONStructor head */
-    }                       pe_un1;
-    union {
-   int       un_pe_cardinal;  /* cardinality of list */
-   int       un_pe_nbits;  /* number of bits in string */
-    }           pe_un2;
-    int      pe_inline;    /* for "ultra-efficient" PElements */
-    char   *pe_realbase;   /*   .. */
-    int      pe_offset;    /* offset of element in sequence */
-    struct PElement *pe_next;
-    int      pe_refcnt;    /* hack for ANYs in pepy */
-}        *PE;
-#define  NULLPE  ((PE) 0)
-
-typedef struct OIDentifier {
-    int      oid_nelem;    /* number of sub-identifiers */
-
-    unsigned int *oid_elements;  /* the (ordered) list of sub-identifiers */
-}                        OIDentifier, *OID;
-#define  NULLOID  ((OID) 0)
-#define  type_SNMP_ObjectName OIDentifier
-
-typedef struct object_syntax {
-    char   *os_name;       /* syntax name */
-    IFP      os_encode;       /* data -> PE */
-    IFP      os_decode;       /* PE -> data */
-    IFP      os_free;         /* free data */
-    IFP      os_parse;        /* str -> data */
-    IFP      os_print;        /* data -> tty */
-    char  **os_data1;         /* for moresyntax() in snmpi... */
-    int      os_data2;        /*   .. */
-}     *OS;
-
-typedef struct object_type {
-    char   *ot_text;       /* OBJECT DESCRIPTOR */
-    char   *ot_id;         /* OBJECT IDENTIFIER */
-    OID      ot_name;         /*   .. */
-    OS       ot_syntax;       /* SYNTAX */
-    int      ot_access;       /* ACCESS */
-    u_long  ot_views;         /* for views */
-    int      ot_status;       /* STATUS */
-    caddr_t ot_info;       /* object information */
-    IFP      ot_getfnx;       /* get/get-next method */
-    IFP      ot_setfnx;       /* set method */
-    caddr_t ot_save;       /* for set method */
-    caddr_t ot_smux;       /* for SMUX */
-    struct object_type *ot_chain;   /* hash-bucket for text2obj */
-    struct object_type *ot_sibling; /* linked-list for name2obj */
-    struct object_type *ot_children;   /*   .. */
-    struct object_type *ot_next; /* linked-list for get-next */
-}     *OT;
-#define       NULLOT  ((OT) 0)
-
-typedef struct object_instance {
-    OID      oi_name;         /* instance OID */
-    OT       oi_type;         /* prototype */
-}     object_instance, *OI;
-#define       NULLOI  ((OI) 0)
-
-struct type_SNMP_VarBind {
-    struct type_SNMP_ObjectName *name;
-    struct type_SNMP_ObjectSyntax *value;
-};
-
-struct type_SNMP_VarBindList {
-        struct type_SNMP_VarBind *VarBind;
-        struct type_SNMP_VarBindList *next;
-};
-
-#define    type_SNMP_GetRequest__PDU       type_SNMP_PDU
-#define    type_SNMP_GetResponse__PDU       type_SNMP_PDU
-struct type_SNMP_PDU {
-    integer     request__id;
-    integer     error__status;
-#define  int_SNMP_error__status_noError   0
-#define  int_SNMP_error__status_noSuchName   2
-#define  int_SNMP_error__status_genErr 5
-    integer     error__index;
-    struct type_SNMP_VarBindList *variable__bindings;
-};
-
-struct type_SNMP_PDUs {
-    int         offset;
-#define  type_SNMP_PDUs_get__request   1
-#define  type_SNMP_PDUs_get__next__request   2
-#define  type_SNMP_PDUs_get__response  3
-#define        type_SNMP_PDUs_set__request     4
-    union {
-        struct type_SNMP_GetRequest__PDU *get__request;
-        struct type_SNMP_GetNextRequest__PDU *get__next__request;
-        struct type_SNMP_GetResponse__PDU *get__response;
-        struct type_SNMP_SetRequest__PDU *set__request;
-        struct type_SNMP_Trap__PDU *trap;
-    }       un;
-};
-
-struct type_SNMP_Message {
-    integer     version;
-#define  int_SNMP_version_version__1   0
-    struct qbuf *community;
-    struct type_SNMP_PDUs *data;
-};
-
-struct type_SNMP_SMUX__PDUs {
-    int         offset;
-#define  type_SNMP_SMUX__PDUs_close 2
-#define  type_SNMP_SMUX__PDUs_registerResponse  4
-#define  type_SNMP_SMUX__PDUs_get__request   5
-#define  type_SNMP_SMUX__PDUs_get__next__request   6
-#define  type_SNMP_SMUX__PDUs_set__request   8
-#define  type_SNMP_SMUX__PDUs_commitOrRollback  10
-    union {
-        struct type_SNMP_SimpleOpen *simple;
-        struct type_SNMP_ClosePDU *close;
-        struct type_SNMP_RReqPDU *registerRequest;
-        struct type_SNMP_RRspPDU *registerResponse;
-        struct type_SNMP_GetRequest__PDU *get__request;
-        struct type_SNMP_GetNextRequest__PDU *get__next__request;
-        struct type_SNMP_GetResponse__PDU *get__response;
-        struct type_SNMP_SetRequest__PDU *set__request;
-        struct type_SNMP_Trap__PDU *trap;
-        struct type_SNMP_SOutPDU *commitOrRollback;
-    }       un;
-};
-
-struct type_SNMP_RReqPDU {
-    struct type_SNMP_ObjectName *subtree;
-    integer     priority;
-    integer     operation;
-#define  int_SNMP_operation_readWrite  2
-};
-
-struct type_SNMP_ClosePDU {
-    integer     parm;
-#define  int_SNMP_ClosePDU_goingDown   0
-#define  int_SNMP_ClosePDU_protocolError  3
-};
-
-struct type_SNMP_RRspPDU {
-    integer     parm;
-#define  int_SNMP_RRspPDU_failure   -1
-};
-
-struct type_SNMP_SOutPDU {
-    integer     parm;
-#define  int_SNMP_SOutPDU_commit 0
-};
-
-struct type_SNMP_Trap__PDU {
-    OID     enterprise;
-    struct type_SNMP_NetworkAddress *agent__addr;
-    integer     generic__trap;
-#define  int_SNMP_generic__trap_coldStart 0
-    integer     specific__trap;
-    struct type_SNMP_TimeTicks *time__stamp;
-    struct type_SNMP_VarBindList *variable__bindings;
-};
-
-struct smuxEntry {
-    char   *se_name;
-    OIDentifier se_identity;
-    char   *se_password;
-    int      se_priority;
-};
-
-typedef struct {
-    int            ps_errno;           /* Error codes */
-#define        PS_ERR_NONE      0      /*   No error */
-#define        PS_ERR_OVERID    1      /*   Overflow in ID */
-#define        PS_ERR_OVERLEN   2      /*   Overflow in length */
-#define        PS_ERR_NMEM      3      /*   Out of memory */
-#define        PS_ERR_EOF       4      /*   End of file */
-#define        PS_ERR_EOFID     5      /*   End of file reading extended ID */
-#define        PS_ERR_EOFLEN    6      /*   End of file reading extended length */
-#define        PS_ERR_LEN       7      /*   Length mismatch */
-#define        PS_ERR_TRNC      8      /*   Truncated */
-#define        PS_ERR_INDF      9      /*   Indefinite length in primitive form */
-#define        PS_ERR_IO       10      /*   I/O error */
-#define        PS_ERR_EXTRA    11      /*   Extraneous octets */
-#define        PS_ERR_XXX      12      /*   XXX */
-    union {
-       caddr_t un_ps_addr;
-       struct {
-           char   *st_ps_base;
-           int     st_ps_cnt;
-           char   *st_ps_ptr;
-           int     st_ps_bufsiz;
-       }                       un_ps_st;
-       struct {
-           struct udvec *uv_ps_head;
-           struct udvec *uv_ps_cur;
-           struct udvec *uv_ps_end;
-           int     uv_ps_elems;
-           int     uv_ps_slop;
-           int     uv_ps_cc;
-       }                       un_ps_uv;
-    }                       ps_un;
-#define        ps_addr ps_un.un_ps_addr
-#define        ps_base ps_un.un_ps_st.st_ps_base
-#define        ps_cnt  ps_un.un_ps_st.st_ps_cnt
-#define        ps_ptr  ps_un.un_ps_st.st_ps_ptr
-#define        ps_bufsiz       ps_un.un_ps_st.st_ps_bufsiz
-#define        ps_head ps_un.un_ps_uv.uv_ps_head
-#define        ps_cur  ps_un.un_ps_uv.uv_ps_cur
-#define        ps_end  ps_un.un_ps_uv.uv_ps_end
-#define        ps_elems        ps_un.un_ps_uv.uv_ps_elems
-#define        ps_slop ps_un.un_ps_uv.uv_ps_slop
-#define        ps_cc   ps_un.un_ps_uv.uv_ps_cc
-    caddr_t ps_extra;          /* for George's recursive PStreams */
-    int            ps_inline;          /* for "ultra-efficient" PStreams */
-    int            ps_scratch;         /* XXX */
-    int            ps_byteno;          /* byte position */
-    IFP            ps_primeP;
-    IFP            ps_readP;
-    IFP            ps_writeP;
-    IFP            ps_flushP;
-    IFP            ps_closeP;
-}                      PStream, *PS;
-#define        NULLPS  ((PS) 0)
-
-struct NSAPaddr {              /* this structure shouldn't have holes in it */
-    long     na_stack;                 /* TS-stack */
-#define        NA_TCP  1                       /*   RFC1006/TCP */
-    long    na_community;              /* internal community # */
-    union {
-       struct na_nsap {                /* real network service */
-#define        NASIZE  64                      /* 20 ought to do it */
-           char    na_nsap_address[NASIZE];
-           char    na_nsap_addrlen;
-       }               un_na_nsap;
-       struct na_tcp {                 /* emulation via RFC1006 */
-#define        NSAP_DOMAINLEN  63
-           char    na_tcp_domain[NSAP_DOMAINLEN + 1];
-           u_short na_tcp_port;        /* non-standard TCP port */
-           u_short na_tcp_tset;        /* transport set */
-#define        NA_TSET_TCP     0x0001          /*   .. TCP */
-#define        NA_TSET_UDP     0x0002          /*   .. UDP */
-       }               un_na_tcp;
-       struct na_x25 {                 /* X.25 (assume single subnet) */
-#define        NSAP_DTELEN     36
-           char    na_x25_dte[NSAP_DTELEN + 1]; /* Numeric DTE + Link */
-           char    na_x25_dtelen;      /* number of digits used */
-
-/* Conventionally, the PID sits at the first head bytes of user data and so
- * should probably not be mentioned specially. A macro might do it, if
- * necessary.
- */
-#define        NPSIZE  4
-           char    na_x25_pid[NPSIZE]; /* X.25 protocol id */
-           char    na_x25_pidlen;      /*   .. */
-#define        CUDFSIZE 16
-           char    na_x25_cudf[CUDFSIZE];/* call user data field */
-           char    na_x25_cudflen;     /* .. */
-/*
- * X25 Facilities field. 
- */
-#define        FACSIZE 6
-           char    na_x25_fac[FACSIZE];        /* X.25 facilities */
-           char    na_x25_faclen;              /*   .. */
-       }               un_na_x25;
-    }               na_un;
-#define        na_address      na_un.un_na_nsap.na_nsap_address
-#define        na_addrlen      na_un.un_na_nsap.na_nsap_addrlen
-#define        na_domain       na_un.un_na_tcp.na_tcp_domain
-#define        na_port         na_un.un_na_tcp.na_tcp_port
-#define        na_tset         na_un.un_na_tcp.na_tcp_tset
-#define        na_dte          na_un.un_na_x25.na_x25_dte
-#define        na_dtelen       na_un.un_na_x25.na_x25_dtelen
-#define        na_pid          na_un.un_na_x25.na_x25_pid
-#define        na_pidlen       na_un.un_na_x25.na_x25_pidlen
-#define        na_cudf         na_un.un_na_x25.na_x25_cudf
-#define        na_cudflen      na_un.un_na_x25.na_x25_cudflen
-#define        na_fac          na_un.un_na_x25.na_x25_fac
-#define        na_faclen       na_un.un_na_x25.na_x25_faclen
-/* for backwards compatibility... these two will be removed after ISODE 7.0 */
-#define        na_type         na_stack
-#define        na_subnet       na_community
-};
-
-struct TSAPaddr {
-#define  NTADDR   8        /* according to NIST OIW */
-    struct NSAPaddr ta_addrs[NTADDR];  /* choice of network addresses */
-    int     ta_naddr;
-#define  TSSIZE   64
-    int      ta_selectlen;
-    union un_ta_type {           /* TSAP selector */
-   char    ta_un_selector[TSSIZE];
-   u_short ta_un_port;
-    }               un_ta;
-#define  ta_selector un_ta.ta_un_selector
-#define  ta_port     un_ta.ta_un_port
-};
-
-struct qbuf {
-    struct qbuf *qb_forw;  /* doubly-linked list */
-    struct qbuf *qb_back;  /*   .. */
-    int      qb_len;    /* length of data */
-    char   *qb_data;    /* current pointer into data */
-    char    qb_base[1];    /* extensible... */
-};
-
-#define  start_udp_client        start_udp_server
-#define  read_udp_socket      read_dgram_socket
-#define  write_udp_socket  write_dgram_socket
-#define  close_udp_socket  close_dgram_socket
-#define  check_udp_socket        check_dgram_socket
-#define  free_SNMP_ObjectName oid_free
-#define  o_ipaddr(oi,v,value) o_specific ((oi), (v), (caddr_t) (value))
-#define  o_integer(oi,v,value)   o_longword ((oi), (v), (integer) (value))
-#define  oid2ode(i)  oid2ode_aux ((i), 1)
-#define  ps2pe(ps)               ps2pe_aux ((ps), 1, 1)
-#define  pe2ps(ps, pe)           pe2ps_aux ((ps), (pe), 1)
-#define  str2vec(s,v)    str2vecX ((s), (v), 0, NULLIP, NULL, 1)
-#define  free_SNMP_Message(parm)\
-   (void) fre_obj((char *) parm, _ZSNMP_mod.md_dtab[_ZMessageSNMP], &_ZSNMP_mod, 1)
-#define encode_SNMP_Message(pe, top, len, buffer, parm) \
-    enc_f(_ZMessageSNMP, &_ZSNMP_mod, pe, top, len, buffer, (char *) parm)
-#define print_SNMP_Message(pe, top, len, buffer, parm) \
-    prnt_f(_ZMessageSNMP, &_ZSNMP_mod, pe, top, len, buffer)
-#define decode_SNMP_Message(pe, top, len, buffer, parm) \
-    dec_f(_ZMessageSNMP, &_ZSNMP_mod, pe, top, len, buffer, (char **) parm)
-#define  inaddr_copy(hp,sin) \
-    bcopy ((hp) -> h_addr, (char *) &((sin) -> sin_addr), (hp) -> h_length)
-#define  join_udp_server(fd,sock) \
-      join_dgram_aux ((fd), (struct sockaddr *) (sock), 0)
-
-#define MAXDGRAM        8192
-#define      NOTOK           (-1)
-#define      OK              0
-#define  NVEC  100
-#define  invalidOperation        (-1)
-#define  parameterMissing        (-2)
-#define  systemError             (-3)
-#define  youLoseBig              (-4)
-#define  congestion              (-5)
-#define  inProgress              (-6)
-#define  protocolError     int_SNMP_ClosePDU_protocolError
-#define  goingDown      int_SNMP_ClosePDU_goingDown
-#define  readWrite   int_SNMP_operation_readWrite
-
-OID   oid_extend(), text2oid (), oid_cpy ();
-OT    text2obj ();
-OI    name2inst (), next2inst (), text2inst ();
-OS    text2syn ();
-PS    ps_alloc ();
-PE    pe_alloc (), ps2pe_aux ();
-struct smuxEntry *getsmuxEntrybyname ();
-struct hostent *gethostbystring ();
-char   *getlocalhost (), *oid2ode_aux ();
-struct TSAPaddr *str2taddr ();  /* string encoding to TSAPaddr */
-int   dg_open (), read_dgram_socket (), write_dgram_socket ();
-int   check_dgram_socket (), pe2ps_aux ();
-struct qbuf *str2qb ();
-
-integer     request__id;
-extern char PY_pepy[];
+extern int portlist[32], sdlen;
+extern u_short dest_port;
 extern int quantum;
-extern int  ts_comm_tcp_default, ps_len_strategy;
-extern modtyp  _ZSNMP_mod;
-#define _ZMessageSNMP   0
-
-#define  PS_LEN_LONG 2
-
-/* Scalars */
-#define ipMRouteEnable                   0
-
-/* IP Multicast Route Table */
-#define ipMRouteUpstreamNeighbor         0
-#define ipMRouteInIfIndex                1
-#define ipMRouteUpTime                   2
-#define ipMRouteExpiryTime               3
-#define ipMRoutePkts                     4
-#define ipMRouteDifferentInIfIndexes     5
-#define ipMRouteOctets                   6
-#define ipMRouteProtocol                 7
-
-/* IP Multicast Routing Next Hop Table */
-#define ipMRouteNextHopState             0
-#define ipMRouteNextHopUpTime            1
-#define ipMRouteNextHopExpiryTime        2
-#define ipMRouteNextHopClosestMemberHops 3
-#define ipMRouteNextHopProtocol          4
-
-/* Multicast Routing Interface Table */
-#define ipMRouteInterfaceTtl             0
-
-/* Scalars (cont.) */
-#define dvmrpVersion                     1
-#define dvmrpGenerationId                2
-
-/* DVMRP Virtual Interface Table */
-#define dvmrpVInterfaceType              1
-#define dvmrpVInterfaceState             2
-#define dvmrpVInterfaceLocalAddress      3
-#define dvmrpVInterfaceRemoteAddress     4
-#define dvmrpVInterfaceRemoteSubnetMask  5
-#define dvmrpVInterfaceMetric            6
-#define dvmrpVInterfaceRateLimit         7
-#define dvmrpVInterfaceInPkts            8
-#define dvmrpVInterfaceOutPkts           9
-#define dvmrpVInterfaceInOctets         10
-#define dvmrpVInterfaceOutOctets        11
-
-/* DVMRP Neighbor Table */
-#define dvmrpNeighborUpTime              0
-#define dvmrpNeighborExpiryTime          1
-#define dvmrpNeighborVersion             2
-#define dvmrpNeighborGenerationId        3
-
-/* DVMRP Route Table */
-#define dvmrpRouteUpstreamNeighbor       0
-#define dvmrpRouteInVifIndex             1
-#define dvmrpRouteMetric                 2
-#define dvmrpRouteExpiryTime             3
-
-/* DVMRP Routing Next Hop Table */
-#define dvmrpRouteNextHopType            0
 
-/* Boundary Table */
-#define dvmrpBoundaryVifIndex            0
+extern int snmp_read_packet();
 
-#define SNMPD_RETRY_INTERVAL 300 /* periodic snmpd probe interval */
-extern int smux_fd;
-extern int rock_and_roll;
-extern int dont_bother_anymore;
+#define DEFAULT_PORT 161
index 406e815..326d17d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: vif.c,v 1.5 1995/10/09 03:52:01 thorpej Exp $  */
+/*     $NetBSD: vif.c,v 1.6 1995/12/10 10:07:19 mycroft Exp $  */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
 
 
 #include "defs.h"
-
+#include <fcntl.h>
 
 /*
  * Exported variables.
  */
-struct uvif    uvifs[MAXVIFS]; /* array of virtual interfaces */
-vifi_t         numvifs;        /* number of vifs in use       */
-int            vifs_down;      /* 1=>some interfaces are down */
+struct uvif    uvifs[MAXVIFS]; /* array of virtual interfaces              */
+vifi_t         numvifs;        /* number of vifs in use                    */
+int            vifs_down;      /* 1=>some interfaces are down              */
+int            phys_vif;       /* An enabled vif                           */
 int            udp_socket;     /* Since the honkin' kernel doesn't support */
                                /* ioctls on raw IP sockets, we need a UDP  */
                                /* socket as well as our IGMP (raw) socket. */
                                /* How dumb.                                */
 int            vifs_with_neighbors;    /* == 1 if I am a leaf              */
 
+typedef struct {
+        vifi_t  vifi;
+        struct listaddr *g;
+       int    q_time;
+} cbk_t;
+
 /*
  * Forward declarations.
  */
-static void start_vif();
-static void stop_vif();
-static void age_old_hosts();
+static void start_vif __P((vifi_t vifi));
+static void start_vif2 __P((vifi_t vifi));
+static void stop_vif __P((vifi_t vifi));
+static void age_old_hosts __P((void));
+static void send_probe_on_vif __P((struct uvif *v));
+static int info_version __P((char *p));
+static void DelVif __P((void *arg));
+static int SetTimer __P((int vifi, struct listaddr *g));
+static int DeleteTimer __P((int id));
+static void SendQuery __P((void *arg));
+static int SetQueryTimer __P((struct listaddr *g, vifi_t vifi, int to_expire,
+                                       int q_time));
+
 
 /*
- * Initialize the virtual interfaces.
+ * Initialize the virtual interfaces, but do not install
+ * them in the kernel.  Start routing on all vifs that are
+ * not down or disabled.
  */
 void
 init_vifs()
@@ -44,6 +63,7 @@ init_vifs()
     extern char *configfilename;
 
     numvifs = 0;
+    vifs_with_neighbors = 0;
     vifs_down = FALSE;
 
     /*
@@ -63,11 +83,15 @@ init_vifs()
      */
     enabled_vifs    = 0;
     enabled_phyints = 0;
+    phys_vif       = -1;
     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        if (!(v->uv_flags & VIFF_DISABLED)) {
            ++enabled_vifs;
-           if (!(v->uv_flags & VIFF_TUNNEL))
+           if (!(v->uv_flags & VIFF_TUNNEL)) {
+               if (phys_vif == -1)
+                   phys_vif = vifi;
                ++enabled_phyints;
+           }
        }
     }
     if (enabled_vifs < 2)
@@ -78,22 +102,18 @@ init_vifs()
        log(LOG_WARNING, 0,
            "no enabled interfaces, forwarding via tunnels only");
 
-    /*
-     * Start routing on all virtual interfaces that are not down or
-     * administratively disabled.
-     */
-    log(LOG_INFO,0,"Installing vifs in kernel...");
+    log(LOG_INFO, 0, "Installing vifs in mrouted...");
     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        if (!(v->uv_flags & VIFF_DISABLED)) {
            if (!(v->uv_flags & VIFF_DOWN)) {
                if (v->uv_flags & VIFF_TUNNEL)
-                   log(LOG_INFO,0,"vif #%d, tunnel %s -> %s", vifi,
-                               inet_fmt(v->uv_lcl_addr,s1),
-                               inet_fmt(v->uv_rmt_addr,s2));
+                   log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
+                               inet_fmt(v->uv_lcl_addr, s1),
+                               inet_fmt(v->uv_rmt_addr, s2));
                else
-                   log(LOG_INFO,0,"vif #%d, phyint %s", vifi,
-                               inet_fmt(v->uv_lcl_addr,s1));
-               start_vif(vifi);
+                   log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
+                               inet_fmt(v->uv_lcl_addr, s1));
+               start_vif2(vifi);
            } else log(LOG_INFO, 0,
                     "%s is not yet up; vif #%u not in service",
                     v->uv_name, vifi);
@@ -101,6 +121,34 @@ init_vifs()
     }
 }
 
+/*
+ * Start routing on all virtual interfaces that are not down or
+ * administratively disabled.
+ */
+void
+init_installvifs()
+{
+    vifi_t vifi;
+    struct uvif *v;
+
+    log(LOG_INFO, 0, "Installing vifs in kernel...");
+    for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+       if (!(v->uv_flags & VIFF_DISABLED)) {
+           if (!(v->uv_flags & VIFF_DOWN)) {
+               if (v->uv_flags & VIFF_TUNNEL)
+                   log(LOG_INFO, 0, "vif #%d, tunnel %s -> %s", vifi,
+                               inet_fmt(v->uv_lcl_addr, s1),
+                               inet_fmt(v->uv_rmt_addr, s2));
+               else
+                   log(LOG_INFO, 0, "vif #%d, phyint %s", vifi,
+                               inet_fmt(v->uv_lcl_addr, s1));
+               k_add_vif(vifi, &uvifs[vifi]);
+           } else log(LOG_INFO, 0,
+                    "%s is not yet up; vif #%u not in service",
+                    v->uv_name, vifi);
+       }
+    }
+}
 
 /*
  * See if any interfaces have changed from up state to down, or vice versa,
@@ -151,7 +199,7 @@ check_vif_state()
 /*
  * Send a probe message on vif v
  */
-void
+static void
 send_probe_on_vif(v)
     register struct uvif *v;
 {
@@ -188,11 +236,27 @@ send_probe_on_vif(v)
 }
 
 /*
- * Start routing on the specified virtual interface.
+ * Add a vifi to the kernel and start routing on it.
  */
 static void
 start_vif(vifi)
     vifi_t vifi;
+{
+    /*
+     * Install the interface in the kernel's vif structure.
+     */
+    k_add_vif(vifi, &uvifs[vifi]);
+
+    start_vif2(vifi);
+}
+
+/*
+ * Add a vifi to all the user-level data structures but don't add
+ * it to the kernel yet.
+ */
+static void
+start_vif2(vifi)
+    vifi_t vifi;
 {
     struct uvif *v;
     u_int32_t src;
@@ -201,11 +265,6 @@ start_vif(vifi)
     v   = &uvifs[vifi];
     src = v->uv_lcl_addr;
 
-    /*
-     * Install the interface in the kernel's vif structure.
-     */
-    k_add_vif(vifi, &uvifs[vifi]);
-
     /*
      * Update the existing route entries to take into account the new vif.
      */
@@ -236,7 +295,7 @@ start_vif(vifi)
        update_route(v->uv_subnet, v->uv_subnetmask, 0, 0, vifi);
        for (p = v->uv_addrs; p; p = p->pa_next) {
            start_route_updates();
-           update_route(p->pa_addr, p->pa_mask, 0, 0, vifi);
+           update_route(p->pa_subnet, p->pa_subnetmask, 0, 0, vifi);
        }
 
        /*
@@ -246,7 +305,8 @@ start_vif(vifi)
         */
        v->uv_flags |= VIFF_QUERIER;
        send_igmp(src, allhosts_group, IGMP_HOST_MEMBERSHIP_QUERY, 
-                 IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
+             (v->uv_flags & VIFF_IGMPV1) ? 0 :
+             IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
        age_old_hosts();
     }
 
@@ -291,7 +351,7 @@ stop_vif(vifi)
        update_route(v->uv_subnet, v->uv_subnetmask, UNREACHABLE, 0, vifi);
        for (p = v->uv_addrs; p; p = p->pa_next) {
            start_route_updates();
-           update_route(p->pa_addr, p->pa_mask, UNREACHABLE, 0, vifi);
+           update_route(p->pa_subnet, p->pa_subnetmask, UNREACHABLE, 0, vifi);
        }
 
        /*
@@ -384,11 +444,13 @@ find_vif(src, dst)
            }
            else {
                if ((src & v->uv_subnetmask) == v->uv_subnet &&
-                   src != v->uv_subnetbcast)
+                   ((v->uv_subnetmask == 0xffffffff) ||
+                    (src != v->uv_subnetbcast)))
                    return(vifi);
                for (p=v->uv_addrs; p; p=p->pa_next) {
-                   if ((src & p->pa_mask) == p->pa_addr &&
-                       src != p->pa_addr)
+                   if ((src & p->pa_subnetmask) == p->pa_subnet &&
+                       ((p->pa_subnetmask == 0xffffffff) ||
+                        (src != p->pa_subnetbcast)))
                        return(vifi);
                }
            }
@@ -403,16 +465,15 @@ age_old_hosts()
     register vifi_t vifi;
     register struct uvif *v;
     register struct listaddr *g;
-    for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
-        /* -*- increment the time since an old report was heard  */
-        for (g = v->uv_groups; g != NULL; g = g->al_next)  {
-                g->al_last ++;
-                if (g->al_last >= OLD_AGE_THRESHOLD){
-                         g->al_old = 0;
-                         g->al_last = OLD_AGE_THRESHOLD;
-                }
-        }
-    }
+
+    /*
+     * Decrement the old-hosts-present timer for each
+     * active group on each vif.
+     */
+    for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
+        for (g = v->uv_groups; g != NULL; g = g->al_next)
+           if (g->al_old)
+               g->al_old--;
 }
 
 
@@ -429,6 +490,7 @@ query_groups()
        if (v->uv_flags & VIFF_QUERIER) {
            send_igmp(v->uv_lcl_addr, allhosts_group,
                      IGMP_HOST_MEMBERSHIP_QUERY, 
+                     (v->uv_flags & VIFF_IGMPV1) ? 0 :
                      IGMP_MAX_HOST_REPORT_DELAY * IGMP_TIMER_SCALE, 0, 0);
        }
     }
@@ -456,16 +518,19 @@ accept_membership_query(src, dst, group, tmo)
 
     v = &uvifs[vifi];
 
-    /* If we consider ourselves the querier for this vif, but hear a
+    /*
+     * If we consider ourselves the querier for this vif, but hear a
      * query from a router with a lower IP address, yield to them.
      *
      * This is done here as well as in the neighbor discovery in case
      * there is a querier that doesn't speak DVMRP.
+     *
+     * XXX If this neighbor doesn't speak DVMRP, then we need to create
+     * some neighbor state for him so that we can time him out!
      */
     if ((v->uv_flags & VIFF_QUERIER) &&
        (ntohl(src) < ntohl(v->uv_lcl_addr))) {
-
-       v->uv_flags &= ~VIFF_QUERIER;
+           v->uv_flags &= ~VIFF_QUERIER;
 
     }
 }
@@ -497,17 +562,14 @@ accept_group_report(src, dst, group, r_type)
      */
     for (g = v->uv_groups; g != NULL; g = g->al_next) {
        if (group == g->al_addr) {
-           if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT) {
-               g->al_last = OLD_AGE_THRESHOLD;
-               g->al_old = 0;
-           }
-           else {
-               g->al_last = 0;
-               g->al_old = 1;
-           }
-
-           /** delete old timer set a timer for expiration **/
-           g->al_timer= GROUP_EXPIRE_TIME;
+           if (r_type == IGMP_v1_HOST_MEMBERSHIP_REPORT)
+               g->al_old = OLD_AGE_THRESHOLD;
+#ifdef SNMP
+           g->al_genid = src;
+#endif /* SNMP */
+
+           /** delete old timers, set a timer for expiration **/
+           g->al_timer = GROUP_EXPIRE_TIME;
            if (g->al_query)
                g->al_query = DeleteTimer(g->al_query);
            if (g->al_timerid)
@@ -526,14 +588,13 @@ accept_group_report(src, dst, group, r_type)
            log(LOG_ERR, 0, "ran out of memory");    /* fatal */
 
        g->al_addr   = group;
-       if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT) {
-           g->al_last = OLD_AGE_THRESHOLD;
+       if (r_type == IGMP_v2_HOST_MEMBERSHIP_REPORT)
            g->al_old = 0;
-       }
-       else {
-           g->al_last = 0;
-           g->al_old = 1;
-       }
+       else
+           g->al_old = OLD_AGE_THRESHOLD;
+#ifdef SNMP
+       g->al_genid = src;
+#endif
 
        /** set a timer for expiration **/
         g->al_query = 0;
@@ -554,7 +615,7 @@ accept_group_report(src, dst, group, r_type)
 
 
 void
-accept_leave_message( src, dst, group)
+accept_leave_message(src, dst, group)
     u_int32_t src, dst, group;
 {
     register vifi_t vifi;
@@ -571,7 +632,7 @@ accept_leave_message( src, dst, group)
 
     v = &uvifs[vifi];
 
-    if (!(v->uv_flags & VIFF_QUERIER))
+    if (!(v->uv_flags & VIFF_QUERIER) || (v->uv_flags & VIFF_IGMPV1))
        return;
 
     /*
@@ -832,6 +893,68 @@ accept_neighbor_request2(src, dst)
                  datalen);
 }
 
+void
+accept_info_request(src, dst, p, datalen)
+    u_int32_t src, dst;
+    u_char *p;
+    int datalen;
+{
+    u_char *q;
+    int len;
+    int outlen = 0;
+
+    q = (u_char *) (send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+
+    /* To be general, this must deal properly with breaking up over-sized
+     * packets.  That implies passing a length to each function, and
+     * allowing each function to request to be called again.  Right now,
+     * we're only implementing the one thing we are positive will fit into
+     * a single packet, so we wimp out.
+     */
+    while (datalen > 0) {
+       len = 0;
+       switch (*p) {
+           case DVMRP_INFO_VERSION:
+               len = info_version(q);
+               break;
+
+           case DVMRP_INFO_NEIGHBORS:
+           default:
+               log(LOG_INFO, 0, "ignoring unknown info type %d", *p);
+               break;
+       }
+       *(q+1) = len++;
+       outlen += len * 4;
+       q += len * 4;
+       len = (*(p+1) + 1) * 4;
+       p += len;
+       datalen -= len;
+    }
+
+    if (outlen != 0)
+       send_igmp(INADDR_ANY, src, IGMP_DVMRP, DVMRP_INFO_REPLY,
+                       htonl(MROUTED_LEVEL), outlen);
+}
+
+/*
+ * Information response -- return version string
+ */
+static int
+info_version(p)
+    char *p;
+{
+    int len;
+    extern char versionstring[];
+
+    *p++ = DVMRP_INFO_VERSION;
+    p++;       /* skip over length */
+    *p++ = 0;  /* zero out */
+    *p++ = 0;  /* reserved fields */
+    strcpy(p, versionstring);  /* XXX strncpy!!! */
+
+    len = strlen(versionstring);
+    return ((len + 3) / 4);
+}
 
 /*
  * Process an incoming neighbor-list message.
@@ -839,7 +962,7 @@ accept_neighbor_request2(src, dst)
 void
 accept_neighbors(src, dst, p, datalen, level)
     u_int32_t src, dst, level;
-    char *p;
+    u_char *p;
     int datalen;
 {
     log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list from %s to %s",
@@ -853,13 +976,26 @@ accept_neighbors(src, dst, p, datalen, level)
 void
 accept_neighbors2(src, dst, p, datalen, level)
     u_int32_t src, dst, level;
-    char *p;
+    u_char *p;
     int datalen;
 {
     log(LOG_INFO, 0, "ignoring spurious DVMRP neighbor list2 from %s to %s",
        inet_fmt(src, s1), inet_fmt(dst, s2));
 }
 
+/*
+ * Process an incoming info reply message.
+ */
+void
+accept_info_reply(src, dst, p, datalen)
+    u_int32_t src, dst;
+    u_char *p;
+    int datalen;
+{
+    log(LOG_INFO, 0, "ignoring spurious DVMRP info reply from %s to %s",
+       inet_fmt(src, s1), inet_fmt(dst, s2));
+}
+
 
 /*
  * Update the neighbor entry for neighbor 'addr' on vif 'vifi'.
@@ -879,7 +1015,8 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level)
     register struct listaddr *n;
     u_int32_t genid = 0;
     u_int32_t router;
-    int he_hears_me = TRUE;
+    u_int32_t send_tables = 0;
+    int do_reset = FALSE;
     int nflags;
 
     v = &uvifs[vifi];
@@ -906,18 +1043,83 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level)
     }
 
     /*
-     * If we have received a route report from a neighbor, and we believed
-     * that we had no neighbors on this vif, send a full route report to
-     * all neighbors on the vif.
+     * Look for addr in list of neighbors.
+     */
+    for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
+       if (addr == n->al_addr) {
+           break;
+       }
+    }
+
+    /*
+     * Found it.  Reset its timer, and check for a version change
      */
+    if (n) {
+       n->al_timer = 0;
+
+       /*
+        * update the neighbors version and protocol number
+        * if changed => router went down and came up, 
+        * so take action immediately.
+        */
+       if ((n->al_pv != (level & 0xff)) ||
+           (n->al_mv != ((level >> 8) & 0xff))) {
+
+           do_reset = TRUE;
+           log(LOG_DEBUG, 0,
+               "version change neighbor %s [old:%d.%d, new:%d.%d]",
+               inet_fmt(addr, s1),
+               n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff);
+           
+           n->al_pv = level & 0xff;
+           n->al_mv = (level >> 8) & 0xff;
+       }
+    } else {
+       /*
+        * If not found, add it to the list.  If the neighbor has a lower
+        * IP address than me, yield querier duties to it.
+        */
+       log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x",
+           inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff,
+           (level >> 16) & 0xff);
+
+       n = (struct listaddr *)malloc(sizeof(struct listaddr));
+       if (n == NULL)
+           log(LOG_ERR, 0, "ran out of memory");    /* fatal */
+
+       n->al_addr      = addr;
+       n->al_pv        = level & 0xff;
+       n->al_mv        = (level >> 8) & 0xff;
+       n->al_genid     = 0;
+
+       time(&n->al_ctime);
+       n->al_timer     = 0;
+       n->al_next      = v->uv_neighbors;
+
+       /*
+        * If we thought that we had no neighbors on this vif, send a route
+        * report to the vif.  If this is just a new neighbor on the same
+        * vif, send the route report just to the new neighbor.
+        */
+       if (v->uv_neighbors == NULL) {
+           send_tables = (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group;
+           vifs_with_neighbors++;
+       } else {
+           send_tables = addr;
+       }
+
+       v->uv_neighbors = n;
 
-    if (msgtype == DVMRP_REPORT && v->uv_neighbors == NULL)
-       report(ALL_ROUTES, vifi,
-              (v->uv_flags & VIFF_TUNNEL) ? addr : dvmrp_group);
+       if (!(v->uv_flags & VIFF_TUNNEL) &&
+           ntohl(addr) < ntohl(v->uv_lcl_addr))
+           v->uv_flags &= ~VIFF_QUERIER;
+    }
 
     /*
-     * Check if the router gen-ids are the same (only if vers > 3.2)
+     * Check if the router gen-ids are the same.
      * Need to reset the prune state of the router if not.
+     * Also check for one-way interfaces by seeing if we are in our
+     * neighbor's list of known routers.
      */
     if (msgtype == DVMRP_PROBE) {
 
@@ -937,13 +1139,24 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level)
 
            for (i = 0; i < 4; i++)
              ((char *)&genid)[i] = *p++;
-           datalen -=4;
+           datalen -= 4;
+
+           if (n->al_genid == 0)
+               n->al_genid = genid;
+           else if (n->al_genid != genid) {
+               log(LOG_DEBUG, 0,
+                   "new genid neigbor %s on vif %d [old:%x, new:%x]",
+                   inet_fmt(addr, s1), vifi, n->al_genid, genid);
+
+               n->al_genid = genid;
+               do_reset = TRUE;
+           }
            
            /* 
             * loop through router list and check for one-way ifs.
             */
            
-           he_hears_me = FALSE;
+           v->uv_flags |= VIFF_ONEWAY;
            
            while (datalen > 0) {
                if (datalen < 4) {
@@ -956,139 +1169,37 @@ update_neighbor(vifi, addr, msgtype, p, datalen, level)
                  ((char *)&router)[i] = *p++;
                datalen -= 4;
                if (router == v->uv_lcl_addr) {
-                   he_hears_me = TRUE;
+                   v->uv_flags &= ~VIFF_ONEWAY;
                    break;
                }
            }
        }
     }
-    /*
-     * Look for addr in list of neighbors; if found, reset its timer.
-     */
-    for (n = v->uv_neighbors; n != NULL; n = n->al_next) {
-       if (addr == n->al_addr) {
-           n->al_timer = 0;
-
-           /*
-            * If probe message and version no >= 3.3 check genid
-            */
-           if (msgtype == DVMRP_PROBE && 
-               ((n->al_pv >= 3 && n->al_mv > 2) || n->al_pv > 3)) {
-               if (he_hears_me == TRUE && v->uv_flags & VIFF_ONEWAY)
-                   v->uv_flags &= ~VIFF_ONEWAY;
-
-               if (he_hears_me == FALSE)
-                   v->uv_flags |= VIFF_ONEWAY;
-
-               if (n->al_genid == 0)
-                   n->al_genid = genid;
-               else if (n->al_genid != genid) {
-                   log(LOG_DEBUG, 0,
-                       "reset neighbor %s on vif %d [old genid:%x, new:%x]",
-                       inet_fmt(addr, s1), vifi, n->al_genid, genid);
-
-                   n->al_genid = genid;
-                   n->al_pv = level & 0xff;
-                   n->al_mv = (level >> 8) & 0xff;
-                   n->al_flags = 0;    /*XXX*/
-                   reset_neighbor_state(vifi, addr);
-
-                   /* 
-                    * need to do a full route report here 
-                    * it gets done by accept_probe()
-                    */
-                   return (TRUE);
-               }
-                /*XXX nflags shouldn't be dealt with in 2 places in the same
-                 *XXX routine...*/
-                if (n->al_flags != nflags) {
-                    n->al_flags = nflags;
-                    if (nflags & NF_LEAF) {
-                        if (!v->uv_leaf_timer)
-                            v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
-                    } else {
-                        v->uv_flags &= ~VIFF_LEAF;
-                        v->uv_leaf_timer = 0;
-                    }
-                    /* Neighbor flags changed, do a full report */
-                    return TRUE;
-               }
-           }
-
-           /*
-            * update the neighbors version and protocol number
-            * if changed => router went down and came up, 
-            * so take action immediately.
-            */
-           if ((n->al_pv != (level & 0xff)) ||
-               (n->al_mv != ((level >> 8) & 0xff))) {
-
-               log(LOG_DEBUG, 0,
-                   "resetting neighbor %s [old:%d.%d, new:%d.%d]",
-                   inet_fmt(addr, s1),
-                   n->al_pv, n->al_mv, level&0xff, (level >> 8) & 0xff);
-               
-               n->al_pv = level & 0xff;
-               n->al_mv = (level >> 8) & 0xff;
-
-               reset_neighbor_state(vifi, addr);
-           }
-
-           /* recurring probe - so no need to do a route report */
-           if (msgtype == DVMRP_PROBE)
-               return (FALSE);
-           else
-               return (TRUE);
+    if (n->al_flags != nflags) {
+       n->al_flags = nflags;
+
+       if (n->al_flags & NF_LEAF) {
+           /*XXX If we have non-leaf neighbors then we know we shouldn't
+            * mark this vif as a leaf.  For now we just count on other
+            * probes and/or reports resetting the timer. */
+           if (!v->uv_leaf_timer)
+               v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+       } else {
+           /* If we get a leaf to non-leaf transition, we *must* update
+            * the routing table. */
+           if (v->uv_flags & VIFF_LEAF && send_tables == 0)
+               send_tables = addr;
+           v->uv_flags &= ~VIFF_LEAF;
+           v->uv_leaf_timer = 0;
        }
     }
-
-    /*
-     * If not found, add it to the list.  If the neighbor has a lower
-     * IP address than me, yield querier duties to it.
-     */
-    if (n == NULL) {
-       log(LOG_DEBUG, 0, "New neighbor %s on vif %d v%d.%d nf 0x%02x",
-           inet_fmt(addr, s1), vifi, level & 0xff, (level >> 8) & 0xff,
-           (level >> 16) & 0xff);
-
-       n = (struct listaddr *)malloc(sizeof(struct listaddr));
-       if (n == NULL)
-           log(LOG_ERR, 0, "ran out of memory");    /* fatal */
-
-       n->al_addr      = addr;
-       n->al_pv        = level & 0xff;
-       n->al_mv        = (level >> 8) & 0xff;
-       if (msgtype == DVMRP_PROBE)
-           n->al_genid = genid;
-       else
-           n->al_genid = 0;
-
-       time(&n->al_ctime);
-       n->al_timer     = 0;
-       n->al_next      = v->uv_neighbors;
-
-       if (v->uv_neighbors == NULL)
-           vifs_with_neighbors++;
-
-       v->uv_neighbors = n;
-
-       if (!(v->uv_flags & VIFF_TUNNEL) &&
-           ntohl(addr) < ntohl(v->uv_lcl_addr))
-           v->uv_flags &= ~VIFF_QUERIER;
-    }
-
-    n->al_flags = nflags;
-    if (!(n->al_flags & NF_LEAF)) {
-       v->uv_flags &= ~VIFF_LEAF;
-       v->uv_leaf_timer = 0;
-    } else {
-       /*XXX If we have non-leaf neighbors then we know we shouldn't
-        * mark this vif as a leaf.  For now we just count on other
-        * probes and/or reports resetting the timer. */
-       if (!v->uv_leaf_timer)
-           v->uv_leaf_timer = LEAF_CONFIRMATION_TIME;
+    if (do_reset) {
+       reset_neighbor_state(vifi, addr);
+       if (!send_tables)
+           send_tables = addr;
     }
+    if (send_tables)
+       report(ALL_ROUTES, vifi, send_tables);
 
     return (TRUE);
 }
@@ -1169,20 +1280,6 @@ neighbor_info(vifi, addr)
     return NULL;
 }
 
-/*
- * Return the neighbor's version number
- * returns (protocol_version << 8 + mrouted_version) of neighbor
- */
-int
-nbr_vers(vifi, addr)
-    vifi_t vifi;
-    u_int32_t addr;
-{
-    struct listaddr *u = neighbor_info(vifi, addr);
-
-    return u ? NBR_VERS(u) : 0;
-}
-
 /*
  * Print the contents of the uvifs array on file 'fp'.
  */
@@ -1229,14 +1326,15 @@ dump_vifs(fp)
        if (v->uv_flags & VIFF_QUERIER)  fprintf(fp, " querier");
        if (v->uv_flags & VIFF_SRCRT)    fprintf(fp, " src-rt");
        if (v->uv_flags & VIFF_LEAF)     fprintf(fp, " leaf");
+       if (v->uv_flags & VIFF_IGMPV1)   fprintf(fp, " IGMPv1");
        fprintf(fp, "\n");
 
        if (v->uv_addrs != NULL) {
            fprintf(fp, "                alternate subnets: %s\n",
-                   inet_fmts(v->uv_addrs->pa_addr, v->uv_addrs->pa_mask, s1));
+                   inet_fmts(v->uv_addrs->pa_subnet, v->uv_addrs->pa_subnetmask, s1));
            for (p = v->uv_addrs->pa_next; p; p = p->pa_next) {
                fprintf(fp, "                                   %s\n",
-                       inet_fmts(p->pa_addr, p->pa_mask, s1));
+                       inet_fmts(p->pa_subnet, p->pa_subnetmask, s1));
            }
        }
 
@@ -1276,9 +1374,9 @@ dump_vifs(fp)
                "SIOCGETVIFCNT fails");
        }
        else {
-           fprintf(fp, "                         pkts in : %d\n",
+           fprintf(fp, "                         pkts in : %ld\n",
                    v_req.icount);
-           fprintf(fp, "                         pkts out: %d\n",
+           fprintf(fp, "                         pkts out: %ld\n",
                    v_req.ocount);
        }
        fprintf(fp, "\n");
@@ -1286,88 +1384,98 @@ dump_vifs(fp)
     fprintf(fp, "\n");
 }
 
-
-/****           the timeout routines    ********/
-
-typedef struct {
-        vifi_t  vifi;
-        struct listaddr *g;
-       int    q_time;
-} cbk_t;
-
-static cbk_t *cbk;
-
-void
-DelVif(cbk)
-cbk_t *cbk;
+/*
+ * Time out record of a group membership on a vif
+ */
+static void
+DelVif(arg)
+    void *arg;
 {
-        /* -*- make the list consistent */
-        register vifi_t   vifi = cbk->vifi;
-        register struct uvif *v;
-        register struct listaddr *a, *prev_a, *g = cbk->g;
-
-        v = &uvifs[vifi];
+    cbk_t *cbk = (cbk_t *)arg;
+    vifi_t vifi = cbk->vifi;
+    struct uvif *v = &uvifs[vifi];
+    struct listaddr *a, **anp, *g = cbk->g;
 
-         for (prev_a = (struct listaddr *)&(v->uv_groups),
-             a = v->uv_groups;
-             a != NULL;
-             prev_a = a, a = a->al_next) {
-
-            if (a != g) continue;
+    /*
+     * Group has expired
+     * delete all kernel cache entries with this group
+     */
+    if (g->al_query)
+       DeleteTimer(g->al_query);
 
-            /*
-             * Group has expired
-             * delete all kernel cache entries with this group
-             */
-           if (g->al_query) DeleteTimer(g->al_query);
-            delete_lclgrp(vifi, a->al_addr);
+    delete_lclgrp(vifi, g->al_addr);
 
-            prev_a->al_next = a->al_next;
-            free((char *)a);
-            a = prev_a;
-         }
+    anp = &(v->uv_groups);
+    while ((a = *anp) != NULL) {
+       if (a == g) {
+           *anp = a->al_next;
+           free((char *)a);
+       } else {
+           anp = &a->al_next;
+       }
+    }
 
-         free(cbk);
+    free(cbk);
 }
 
-
-int
-SetTimer( vifi, g)
-        vifi_t vifi;  struct listaddr *g;
+/*
+ * Set a timer to delete the record of a group membership on a vif.
+ */
+static int
+SetTimer(vifi, g)
+    vifi_t vifi;
+    struct listaddr *g;
 {
-        cbk = (cbk_t *) malloc(sizeof(cbk_t));
-        cbk->g = g;
-        cbk->vifi = vifi;
-        return timer_setTimer(g->al_timer,DelVif,cbk);
+    cbk_t *cbk;
+
+    cbk = (cbk_t *) malloc(sizeof(cbk_t));
+    cbk->g = g;
+    cbk->vifi = vifi;
+    return timer_setTimer(g->al_timer, (cfunc_t)DelVif, (void *)cbk);
 }
 
-int
-DeleteTimer( id)
-int id;
+/*
+ * Delete a timer that was set above.
+ */
+static int
+DeleteTimer(id)
+    int id;
 {
-        timer_clearTimer(id);
-       return 0;
+    timer_clearTimer(id);
+    return 0;
 }
 
-void
-SendQuery(cbk)
-cbk_t *cbk;
+/*
+ * Send a group-specific query.
+ */
+static void
+SendQuery(arg)
+    void *arg;
 {
-        register struct uvif *v = &uvifs[cbk->vifi];
-            send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
-                      IGMP_HOST_MEMBERSHIP_QUERY,
-                      cbk->q_time, 0, 0);
-           cbk->g->al_query = 0;
-           free(cbk);
+    cbk_t *cbk = (cbk_t *)arg;
+    register struct uvif *v = &uvifs[cbk->vifi];
+
+    send_igmp(v->uv_lcl_addr, cbk->g->al_addr,
+             IGMP_HOST_MEMBERSHIP_QUERY,
+             cbk->q_time, cbk->g->al_addr, 0);
+    cbk->g->al_query = 0;
+    free(cbk);
 }
 
-int
-SetQueryTimer(g , vifi, to_expire, q_time)
-       struct listaddr *g;  vifi_t vifi;
-       int to_expire, q_time;
+/*
+ * Set a timer to send a group-specific query.
+ */
+static int
+SetQueryTimer(g, vifi, to_expire, q_time)
+    struct listaddr *g;
+    vifi_t vifi;
+    int to_expire, q_time;
 {
-        cbk = (cbk_t *) malloc(sizeof(cbk_t));
-        cbk->g = g;
-        cbk->q_time = q_time; cbk-> vifi = vifi;
-        return timer_setTimer(to_expire,SendQuery,cbk);
+    cbk_t *cbk;
+
+    cbk = (cbk_t *) malloc(sizeof(cbk_t));
+    cbk->g = g;
+    cbk->q_time = q_time;
+    cbk->vifi = vifi;
+    return timer_setTimer(to_expire, (cfunc_t)SendQuery, (void *)cbk);
 }
index 4ff8194..bb3a0f0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: vif.h,v 1.5 1995/10/09 03:52:03 thorpej Exp $  */
+/*     $NetBSD: vif.h,v 1.6 1995/12/10 10:07:20 mycroft Exp $  */
 
 /*
  * The mrouted program is covered by the license in the accompanying file
@@ -40,11 +40,13 @@ struct uvif {
 #define VIFF_QUERIER           0x0400         /* I am the subnet's querier */
 #define VIFF_ONEWAY            0x0800         /* Maybe one way interface   */
 #define VIFF_LEAF              0x1000         /* all neighbors are leaves  */
+#define VIFF_IGMPV1            0x2000         /* Act as an IGMPv1 Router   */
 
 struct phaddr {
     struct phaddr   *pa_next;
-    u_long          pa_addr;
-    u_long          pa_mask;
+    u_int32_t       pa_subnet;         /* extra subnet                 */
+    u_int32_t       pa_subnetmask;     /* netmask of extra subnet      */
+    u_int32_t       pa_subnetbcast;    /* broadcast of extra subnet    */
 };
 
 struct vif_acl {
@@ -63,8 +65,7 @@ struct listaddr {
     u_char          al_mv;             /* router mrouted version           */
     u_long           al_timerid;        /* returned by set timer            */
     u_long          al_query;          /* second query in case of leave    */
-    u_short          al_old;            /* if old memberships are present   */
-    u_short          al_last;          /* # of query's since last old rep  */
+    u_short          al_old;            /* time since heard old report      */
     u_char          al_flags;          /* flags related to this neighbor   */
 };
 
index 37495c5..66ac0fb 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $NetBSD: mtrace.8,v 1.3 1995/10/04 03:47:54 thorpej Exp $
+.\"    $NetBSD: mtrace.8,v 1.4 1995/12/10 10:57:11 mycroft Exp $
 .\"
 .\" Copyright (c) 1995 by the University of Southern California
 .\" All rights reserved.
@@ -63,9 +63,14 @@ mtrace \- print multicast path from a source to a receiver
 ] [
 .B \-s
 ] [
+.B \-S
+.I stat_int
+] [
 .B \-t
 .I ttl
 ] [
+.B \-v
+] [
 .B \-w
 .I waittime
 ]
@@ -105,6 +110,9 @@ detailed below.  The two parameters can be distinguished because the
 is a unicast address and the
 .I group
 is a multicast address.
+.PP
+NOTE: For Solaris 2.4/2.5, if the multicast interface is not the default
+interface, the -i option must be used to set the local address.
 .SH OPTIONS
 .TP 8 8
 .BI \-g\  gwy
@@ -118,7 +126,7 @@ to the
 .RS 8
 .TP 12 12
 .I CAUTION!!
-Version 3.3 of
+Versions 3.3 and 3.5 of
 .B mrouted
 will crash if a trace query is received via a
 unicast packet and
@@ -129,7 +137,7 @@ address.  Therefore, do not use the
 .B \-g
 option unless the target
 .B mrouted
-has been verified to be newer than 3.3.
+has been verified to be 3.4 or newer than 3.5.
 .RE
 .TP 8 8
 .BI \-i\  addr
@@ -142,7 +150,9 @@ and the response destination.
 .TP 8 8
 .B \-l
 Loop indefinitely printing packet rate and loss statistics for the
-multicast path every 10 seconds.
+multicast path every 10 seconds (see 
+.B \-S
+.IR stat_int ).
 .TP 8 8
 .B \-M
 Always send the response using multicast rather than attempting
@@ -169,7 +179,7 @@ The default is 3.
 .TP 8 8
 .B \-p
 Listen passively for multicast responses from traces initiated by
-others (not implemented yet).
+others.  This works best when run on a multicast router.
 .TP 8 8
 .BI \-r\  host
 Send the trace response to
@@ -183,6 +193,11 @@ for this purpose (224.0.1.32).
 Print a short form output including only the multicast path and not
 the packet rate and loss statistics.
 .TP 8 8
+.BI \-S\  n
+Change the interval between statistics gathering traces to
+.I n
+seconds (default 10 seconds).
+.TP 8 8
 .BI \-t\  ttl
 Set the
 .I ttl
@@ -190,6 +205,9 @@ Set the
 responses.  The default is 64, except for local queries to the "all
 routers" multicast group which use ttl 1.
 .TP 8 8
+.B \-v
+Verbose mode; show hop times on the initial trace and statistics display.
+.TP 8 8
 .BI \-w\  n
 Set the time to wait for a trace response to
 .I n
@@ -492,7 +510,7 @@ are modeled after the unicast
 .B traceroute
 program written by Van Jacobson. 
 .SH SEE ALSO
-.BR mrouted (8),
-.BR mrinfo (8),
-.BR map-mbone (8),
+.BR mrouted (8) ,
+.BR mrinfo (8) ,
+.BR map-mbone (8) ,
 .BR traceroute (8)
index d7bfe3f..6f8323a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $NetBSD: mtrace.c,v 1.4 1995/10/04 03:47:57 thorpej Exp $       */
+/*     $NetBSD: mtrace.c,v 1.5 1995/12/10 10:57:15 mycroft Exp $       */
 
 /*
  * mtrace.c
  * license in the accompanying file named "LICENSE".
  */
 
-#include <sys/filio.h>
+#ifndef lint
+static char rcsid[] =
+    "@(#) $Id: mtrace.c,v 1.2 1995/12/14 01:46:22 deraadt Exp $";
+#endif
+
+#include <netdb.h>
 #include <sys/time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <ctype.h>
 #include <memory.h>
-#include <netdb.h>
 #include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-extern int optind;
-extern char *optarg;
-
+#include <ctype.h>
+#include <sys/ioctl.h>
 #include "defs.h"
+#include <arpa/inet.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#ifdef SUNOS5
+#include <sys/systeminfo.h>
+#endif
 
 #define DEFAULT_TIMEOUT        3       /* How long to wait before retrying requests */
 #define DEFAULT_RETRIES 3      /* How many times to try */
@@ -93,6 +99,8 @@ struct resp_buf {
 #define ndata u.d
 
 char names[MAXHOPS][40];
+int reset[MAXHOPS];                    /* To get around 3.4 bug, ... */
+int swaps[MAXHOPS];                    /* To get around 3.6 bug, ... */
 
 int timeout = DEFAULT_TIMEOUT;
 int nqueries = DEFAULT_RETRIES;
@@ -100,6 +108,8 @@ int numeric = FALSE;
 int debug = 0;
 int passive = FALSE;
 int multicast = FALSE;
+int statint = 10;
+int verbose = 0;
 
 u_int32_t defgrp;                      /* Default group if not specified */
 u_int32_t query_cast;                  /* All routers multicast addr */
@@ -112,38 +122,55 @@ u_int32_t dst_netmask;                    /* netmask to go with qdst */
  * Query/response parameters, all initialized to zero and set later
  * to default values or from options.
  */
-u_int32_t qsrc = 0;
-u_int32_t qgrp = 0;
-u_int32_t qdst = 0;
-u_char qno  = 0;
-u_int32_t raddr = 0;
-int    qttl = 0;
-u_char rttl = 0;
-u_int32_t gwy = 0;
+u_int32_t qsrc = 0;            /* Source address in the query */
+u_int32_t qgrp = 0;            /* Group address in the query */
+u_int32_t qdst = 0;            /* Destination (receiver) address in query */
+u_char qno  = 0;               /* Max number of hops to query */
+u_int32_t raddr = 0;           /* Address where response should be sent */
+int    qttl = 0;               /* TTL for the query packet */
+u_char rttl = 0;               /* TTL for the response packet */
+u_int32_t gwy = 0;             /* User-supplied last-hop router address */
+u_int32_t tdst = 0;            /* Address where trace is sent (last-hop) */
 
 vifi_t  numvifs;               /* to keep loader happy */
                                /* (see kern.c) */
-extern void k_join();
-extern void k_leave();
-extern void k_set_ttl();
-extern void exit();
 #ifndef SYSV
 extern long random();
 #endif
 extern int errno;
 
-void
-usage()
-{
-
-    printf("\
-Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
-              [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
-       exit(1);
-}
-
-
-char *
+char *                 inet_name __P((u_int32_t addr));
+u_int32_t                      host_addr __P((char *name));
+/* u_int is promoted u_char */
+char *                 proto_type __P((u_int type));
+char *                 flag_type __P((u_int type));
+
+u_int32_t                      get_netmask __P((int s, u_int32_t dst));
+int                    get_ttl __P((struct resp_buf *buf));
+int                    t_diff __P((u_long a, u_long b));
+u_long                 fixtime __P((u_long time));
+int                    send_recv __P((u_int32_t dst, int type, int code,
+                                       int tries, struct resp_buf *save));
+char *                 print_host __P((u_int32_t addr));
+char *                 print_host2 __P((u_int32_t addr1, u_int32_t addr2));
+void                   print_trace __P((int index, struct resp_buf *buf));
+int                    what_kind __P((struct resp_buf *buf, char *why));
+char *                 scale __P((int *hop));
+void                   stat_line __P((struct tr_resp *r, struct tr_resp *s,
+                                       int have_next, int *res));
+void                   fixup_stats __P((struct resp_buf *base,
+                                       struct resp_buf *prev,
+                                       struct resp_buf *new));
+int                    print_stats __P((struct resp_buf *base,
+                                       struct resp_buf *prev,
+                                       struct resp_buf *new));
+void                   check_vif_state __P((void));
+
+int                    main __P((int argc, char *argv[]));
+
+
+
+char   *
 inet_name(addr)
     u_int32_t  addr;
 {
@@ -159,46 +186,45 @@ u_int32_t
 host_addr(name)
     char   *name;
 {
-    struct hostent *e;
-    struct in_addr ina;
+    struct hostent *e = (struct hostent *)0;
+    u_int32_t  addr;
     int        i, dots = 3;
     char       buf[40];
     char       *ip = name;
     char       *op = buf;
 
     /*
-     * Undo the BSD-ism `127.1' == `127.0.0.1'.  We change this to
-     * `127.1' == `127.1.0.0'.
+     * Undo BSD's favor -- take fewer than 4 octets as net/subnet address
+     * if the name is all numeric.
      */
-
     for (i = sizeof(buf) - 7; i > 0; --i) {
-        if (*ip == '.')
-            --dots;
-        if (*ip == '\0')
-            break;
-        *op++ = *ip++;
+       if (*ip == '.') --dots;
+       else if (*ip == '\0') break;
+       else if (!isdigit(*ip)) dots = 0;  /* Not numeric, don't add zeroes */
+       *op++ = *ip++;
     }
     for (i = 0; i < dots; ++i) {
-        *op++ = '.';
+       *op++ = '.';
        *op++ = '0';
     }
     *op = '\0';
 
-    if (inet_aton(buf, &ina) == 0) {
-        if ((e = gethostbyname(name)) == NULL) {
-           ina.s_addr = 0;
+    if (dots <= 0) e = gethostbyname(name);
+    if (e) memcpy((char *)&addr, e->h_addr_list[0], e->h_length);
+    else {
+       addr = inet_addr(buf);
+       if (addr == -1) {
+           addr = 0;
            printf("Could not parse %s as host name or address\n", name);
-        } else
-           memcpy((char *)&ina.s_addr, e->h_addr_list[0], e->h_length);
+       }
     }
-
-    return (ina.s_addr);
+    return addr;
 }
 
 
 char *
 proto_type(type)
-    u_char type;
+    u_int type;
 {
     static char buf[80];
 
@@ -220,7 +246,7 @@ proto_type(type)
 
 char *
 flag_type(type)
-    u_char type;
+    u_int type;
 {
     static char buf[80];
 
@@ -262,21 +288,20 @@ get_netmask(s, dst)
     int s;
     u_int32_t dst;
 {
-    char inbuf[8192];
+    unsigned int i;
+    char ifbuf[5000];
     struct ifconf ifc;
     struct ifreq *ifr;
-    int i;
     u_int32_t if_addr, if_mask;
     u_int32_t retval = 0xFFFFFFFF;
     int found = FALSE;
 
-    ifc.ifc_len = sizeof(inbuf);
-    ifc.ifc_buf = inbuf;
-    if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
+    ifc.ifc_buf = ifbuf;
+    ifc.ifc_len = sizeof(ifbuf);
+    if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) {
        perror("ioctl (SIOCGIFCONF)");
        return (retval);
     }
-
     for (i = 0; i < ifc.ifc_len; ) {
        ifr = (struct ifreq *)((char *)ifc.ifc_req + i);
        i += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
@@ -285,12 +310,10 @@ get_netmask(s, dst)
            if_mask = ((struct sockaddr_in *)&(ifr->ifr_addr))->sin_addr.s_addr;
            if ((dst & if_mask) == (if_addr & if_mask)) {
                retval = if_mask;
-               if (lcl_addr == 0)
-                   lcl_addr = if_addr;
+               if (lcl_addr == 0) lcl_addr = if_addr;
            }
        }
-       if (lcl_addr == if_addr)
-           found = TRUE;
+       if (lcl_addr == if_addr) found = TRUE;
     }
     if (!found && lcl_addr != 0) {
        printf("Interface address is not valid\n");
@@ -304,9 +327,9 @@ int
 get_ttl(buf)
     struct resp_buf *buf;
 {
-    register rno;
-    register struct tr_resp *b;
-    register ttl;
+    int rno;
+    struct tr_resp *b;
+    u_int ttl;
 
     if (buf && (rno = buf->len) > 0) {
        b = buf->resps + rno - 1;
@@ -314,19 +337,14 @@ get_ttl(buf)
 
        while (--rno > 0) {
            --b;
-           if (ttl < b->tr_fttl)
-               ttl = b->tr_fttl;
-           else
-               ++ttl;
+           if (ttl < b->tr_fttl) ttl = b->tr_fttl;
+           else ++ttl;
        }
        ttl += MULTICAST_TTL_INC;
-       if (ttl < MULTICAST_TTL1)
-           ttl = MULTICAST_TTL1;
-       if (ttl > MULTICAST_TTL_MAX)
-           ttl = MULTICAST_TTL_MAX;
+       if (ttl < MULTICAST_TTL1) ttl = MULTICAST_TTL1;
+       if (ttl > MULTICAST_TTL_MAX) ttl = MULTICAST_TTL_MAX;
        return (ttl);
-    } else
-        return(MULTICAST_TTL1);
+    } else return(MULTICAST_TTL1);
 }
 
 /*
@@ -357,6 +375,17 @@ fixtime(time)
     return (time);
 }
 
+/*
+ * Swap bytes for poor little-endian machines that don't byte-swap
+ */
+u_long
+byteswap(v)
+    u_long v;
+{
+    return ((v << 24) | ((v & 0xff00) << 8) |
+           ((v >> 8) & 0xff00) | (v >> 24));
+}
+
 int
 send_recv(dst, type, code, tries, save)
     u_int32_t dst;
@@ -382,10 +411,8 @@ send_recv(dst, type, code, tries, save)
        group = htonl(MROUTED_LEVEL);
        datalen = 0;
     }
-    if (IN_MULTICAST(ntohl(dst)))
-        local = lcl_addr;
-    else
-        local = INADDR_ANY;
+    if (IN_MULTICAST(ntohl(dst))) local = lcl_addr;
+    else local = INADDR_ANY;
 
     /*
      * If the reply address was not explictly specified, start off
@@ -399,6 +426,8 @@ send_recv(dst, type, code, tries, save)
     query->tr_raddr = raddr ? raddr : multicast ? resp_cast : lcl_addr;
     query->tr_rttl  = rttl ? rttl :
       IN_MULTICAST(ntohl(query->tr_raddr)) ? get_ttl(save) : UNICAST_TTL;
+    query->tr_src   = qsrc;
+    query->tr_dst   = qdst;
 
     for (i = tries ; i > 0; --i) {
        if (tries == nqueries && raddr == 0) {
@@ -417,7 +446,11 @@ send_recv(dst, type, code, tries, save)
         * Change the qid for each request sent to avoid being confused
         * by duplicate responses
         */
+#ifdef SYSV    
+       query->tr_qid  = ((u_int32_t)lrand48() >> 8);
+#else
        query->tr_qid  = ((u_int32_t)random() >> 8);
+#endif
 
        /*
         * Set timer to calculate delays, then send query
@@ -434,17 +467,14 @@ send_recv(dst, type, code, tries, save)
            gettimeofday(&tv, 0);
            tv.tv_sec = tq.tv_sec + timeout - tv.tv_sec;
            tv.tv_usec = tq.tv_usec - tv.tv_usec;
-           if (tv.tv_usec < 0)
-               tv.tv_usec += 1000000L, --tv.tv_sec;
-           if (tv.tv_sec < 0)
-               tv.tv_sec = tv.tv_usec = 0;
+           if (tv.tv_usec < 0) tv.tv_usec += 1000000L, --tv.tv_sec;
+           if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
 
            count = select(igmp_socket + 1, &fds, (fd_set *)0, (fd_set *)0,
                           &tv);
 
            if (count < 0) {
-               if (errno != EINTR)
-                   perror("select");
+               if (errno != EINTR) perror("select");
                continue;
            } else if (count == 0) {
                printf("* ");
@@ -457,8 +487,7 @@ send_recv(dst, type, code, tries, save)
                               0, (struct sockaddr *)0, &dummy);
 
            if (recvlen <= 0) {
-               if (recvlen && errno != EINTR)
-                   perror("recvfrom");
+               if (recvlen && errno != EINTR) perror("recvfrom");
                continue;
            }
 
@@ -492,17 +521,32 @@ send_recv(dst, type, code, tries, save)
            switch (igmp->igmp_type) {
 
              case IGMP_DVMRP:
-               if (igmp->igmp_code != DVMRP_NEIGHBORS2)
-                   continue;
-               if (ip->ip_src.s_addr != dst)
-                   continue;
+               if (igmp->igmp_code != DVMRP_NEIGHBORS2) continue;
                len = igmpdatalen;
+               /*
+                * Accept DVMRP_NEIGHBORS2 response if it comes from the
+                * address queried or if that address is one of the local
+                * addresses in the response.
+                */
+               if (ip->ip_src.s_addr != dst) {
+                   u_int32_t *p = (u_int32_t *)(igmp + 1);
+                   u_int32_t *ep = p + (len >> 2);
+                   while (p < ep) {
+                       u_int32_t laddr = *p++;
+                       int n = ntohl(*p++) & 0xFF;
+                       if (laddr == dst) {
+                           ep = p + 1;         /* ensure p < ep after loop */
+                           break;
+                       }
+                       p += n;
+                   }
+                   if (p >= ep) continue;
+               }
                break;
 
-             case IGMP_MTRACE_QUERY:  /* For backward compatibility with 3.3 */
+             case IGMP_MTRACE_QUERY:       /* For backward compatibility with 3.3 */
              case IGMP_MTRACE_REPLY:
-               if (igmpdatalen <= QLEN)
-                   continue;
+               if (igmpdatalen <= QLEN) continue;
                if ((igmpdatalen - QLEN)%RLEN) {
                    printf("packet with incorrect datalen\n");
                    continue;
@@ -512,18 +556,15 @@ send_recv(dst, type, code, tries, save)
                 * Ignore responses that don't match query.
                 */
                rquery = (struct tr_query *)(igmp + 1);
-               if (rquery->tr_qid != query->tr_qid)
-                   continue;
-               if (rquery->tr_src != qsrc)
-                   continue;
-               if (rquery->tr_dst != qdst)
-                   continue;
+               if (rquery->tr_qid != query->tr_qid) continue;
+               if (rquery->tr_src != qsrc) continue;
+               if (rquery->tr_dst != qdst) continue;
                len = (igmpdatalen - QLEN)/RLEN;
 
                /*
                 * Ignore trace queries passing through this node when
                 * mtrace is run on an mrouter that is in the path
-                * (needed only because IGMP_MTRACE is accepted above
+                * (needed only because IGMP_MTRACE_QUERY is accepted above
                 * for backward compatibility with multicast release 3.3).
                 */
                if (igmp->igmp_type == IGMP_MTRACE_QUERY) {
@@ -570,19 +611,155 @@ send_recv(dst, type, code, tries, save)
     return (0);
 }
 
+/*
+ * Most of this code is duplicated elsewhere.  I'm not sure if
+ * the duplication is absolutely required or not.
+ *
+ * Ideally, this would keep track of ongoing statistics
+ * collection and print out statistics.  (& keep track
+ * of h-b-h traces and only print the longest)  For now,
+ * it just snoops on what traces it can.
+ */
+void
+passive_mode()
+{
+    struct timeval tr;
+    struct ip *ip;
+    struct igmp *igmp;
+    struct tr_resp *r;
+    int ipdatalen, iphdrlen, igmpdatalen;
+    int len, recvlen, dummy = 0;
+    u_int32_t smask;
+
+    init_igmp();
+
+    if (raddr) {
+       if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, INADDR_ANY);
+    } else k_join(htonl(0xE0000120), INADDR_ANY);
+
+    while (1) {
+       recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
+                          0, (struct sockaddr *)0, &dummy);
+       gettimeofday(&tr,0);
+
+       if (recvlen <= 0) {
+           if (recvlen && errno != EINTR) perror("recvfrom");
+           continue;
+       }
+
+       if (recvlen < sizeof(struct ip)) {
+           fprintf(stderr,
+                   "packet too short (%u bytes) for IP header", recvlen);
+           continue;
+       }
+       ip = (struct ip *) recv_buf;
+       if (ip->ip_p == 0)      /* ignore cache creation requests */
+           continue;
+
+       iphdrlen = ip->ip_hl << 2;
+       ipdatalen = ip->ip_len;
+       if (iphdrlen + ipdatalen != recvlen) {
+           fprintf(stderr,
+                   "packet shorter (%u bytes) than hdr+data len (%u+%u)\n",
+                   recvlen, iphdrlen, ipdatalen);
+           continue;
+       }
+
+       igmp = (struct igmp *) (recv_buf + iphdrlen);
+       igmpdatalen = ipdatalen - IGMP_MINLEN;
+       if (igmpdatalen < 0) {
+           fprintf(stderr,
+                   "IP data field too short (%u bytes) for IGMP from %s\n",
+                   ipdatalen, inet_fmt(ip->ip_src.s_addr, s1));
+           continue;
+       }
+
+       switch (igmp->igmp_type) {
+
+         case IGMP_MTRACE_QUERY:           /* For backward compatibility with 3.3 */
+         case IGMP_MTRACE_REPLY:
+           if (igmpdatalen < QLEN) continue;
+           if ((igmpdatalen - QLEN)%RLEN) {
+               printf("packet with incorrect datalen\n");
+               continue;
+           }
+
+           len = (igmpdatalen - QLEN)/RLEN;
+
+           break;
+
+         default:
+           continue;
+       }
+
+       base.qtime = ((tr.tv_sec + JAN_1970) << 16) +
+                     (tr.tv_usec << 10) / 15625;
+       base.rtime = ((tr.tv_sec + JAN_1970) << 16) +
+                     (tr.tv_usec << 10) / 15625;
+       base.len = len;
+       bcopy((char *)igmp, (char *)&base.igmp, ipdatalen);
+       /*
+        * If the user specified which traces to monitor,
+        * only accept traces that correspond to the
+        * request
+        */
+       if ((qsrc != 0 && qsrc != base.qhdr.tr_src) ||
+           (qdst != 0 && qdst != base.qhdr.tr_dst) ||
+           (qgrp != 0 && qgrp != igmp->igmp_group.s_addr))
+           continue;
+
+       printf("Mtrace from %s to %s via group %s (mxhop=%d)\n",
+               inet_fmt(base.qhdr.tr_dst, s1), inet_fmt(base.qhdr.tr_src, s2),
+               inet_fmt(igmp->igmp_group.s_addr, s3), igmp->igmp_code);
+       if (len == 0)
+           continue;
+       printf("  0  ");
+       print_host(base.qhdr.tr_dst);
+       printf("\n");
+       print_trace(1, &base);
+       r = base.resps + base.len - 1;
+       VAL_TO_MASK(smask, r->tr_smask);
+       if ((r->tr_inaddr & smask) == (base.qhdr.tr_src & smask)) {
+           printf("%3d  ", -(base.len+1));
+           print_host(base.qhdr.tr_src);
+           printf("\n");
+       } else if (r->tr_rmtaddr != 0) {
+           printf("%3d  ", -(base.len+1));
+           what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
+                                  "doesn't support mtrace"
+                                : "is the next hop");
+       }
+       printf("\n");
+    }
+}
 
 char *
 print_host(addr)
     u_int32_t addr;
+{
+    return print_host2(addr, 0);
+}
+
+/*
+ * On some routers, one interface has a name and the other doesn't.
+ * We always print the address of the outgoing interface, but can
+ * sometimes get the name from the incoming interface.  This might be
+ * confusing but should be slightly more helpful than just a "?".
+ */
+char *
+print_host2(addr1, addr2)
+    u_int32_t addr1, addr2;
 {
     char *name;
 
     if (numeric) {
-       printf("%s", inet_fmt(addr, s1));
+       printf("%s", inet_fmt(addr1, s1));
        return ("");
     }
-    name = inet_name(addr);
-    printf("%s (%s)", name, inet_fmt(addr, s1));
+    name = inet_name(addr1);
+    if (*name == '?' && *(name + 1) == '\0' && addr2 != 0)
+       name = inet_name(addr2);
+    printf("%s (%s)", name, inet_fmt(addr1, s1));
     return (name);
 }
 
@@ -597,16 +774,22 @@ print_trace(index, buf)
     struct tr_resp *r;
     char *name;
     int i;
+    int hop;
+    char *ms;
 
     i = abs(index);
     r = buf->resps + i - 1;
 
     for (; i <= buf->len; ++i, ++r) {
        if (index > 0) printf("%3d  ", -i);
-       name = print_host(r->tr_outaddr);
-       printf("  %s  thresh^ %d  %d ms  %s\n", proto_type(r->tr_rproto),
-              r->tr_fttl, t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime),
-              flag_type(r->tr_rflags));
+       name = print_host2(r->tr_outaddr, r->tr_inaddr);
+       printf("  %s  thresh^ %d", proto_type(r->tr_rproto), r->tr_fttl);
+       if (verbose) {
+           hop = t_diff(fixtime(ntohl(r->tr_qarr)), buf->qtime);
+           ms = scale(&hop);
+           printf("  %d%s", hop, ms);
+       }
+       printf("  %s\n", flag_type(r->tr_rflags));
        memcpy(names[i-1], name, sizeof(names[0]) - 1);
        names[i-1][sizeof(names[0])-1] = '\0';
     }
@@ -615,44 +798,63 @@ print_trace(index, buf)
 /*
  * See what kind of router is the next hop
  */
-void
-what_kind(buf)
+int
+what_kind(buf, why)
     struct resp_buf *buf;
+    char *why;
 {
     u_int32_t smask;
-    int recvlen;
+    int retval;
     int hops = buf->len;
     struct tr_resp *r = buf->resps + hops - 1;
     u_int32_t next = r->tr_rmtaddr;
 
-    recvlen = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]);
+    retval = send_recv(next, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]);
     print_host(next);
-    if (recvlen) {
+    if (retval) {
        u_int32_t version = ntohl(incr[0].igmp.igmp_group.s_addr);
        u_int32_t *p = (u_int32_t *)incr[0].ndata;
        u_int32_t *ep = p + (incr[0].len >> 2);
-       printf(" [%s%d.%d] didn't respond\n",
-              (version == 1) ? "proteon/mrouted " :
-              ((version & 0xff) == 2) ? "mrouted " :
-              ((version & 0xff) == 3) ? "mrouted " :
-              ((version & 0xff) == 4) ? "mrouted " :
-              ((version & 0xff) == 10) ? "cisco " : "",
-              version & 0xff, (version >> 8) & 0xff);
+       char *type = "";
+       retval = 0;
+       switch (version & 0xFF) {
+         case 1:
+           type = "proteon/mrouted ";
+           retval = 1;
+           break;
+
+         case 2:
+         case 3:
+           if (((version >> 8) & 0xFF) < 3) retval = 1;
+                               /* Fall through */
+         case 4:
+           type = "mrouted ";
+           break;
+
+         case 10:
+           type = "cisco ";
+       }
+       printf(" [%s%d.%d] %s\n",
+              type, version & 0xFF, (version >> 8) & 0xFF,
+              why);
        VAL_TO_MASK(smask, r->tr_smask);
        while (p < ep) {
-           register u_int32_t laddr = *p++;
-           register int n = ntohl(*p++) & 0xFF;
-           if ((laddr & smask) == (qsrc & smask)) {
+           u_int32_t laddr = *p++;
+           int flags = (ntohl(*p) & 0xFF00) >> 8;
+           int n = ntohl(*p++) & 0xFF;
+           if (!(flags & (DVMRP_NF_DOWN | DVMRP_NF_DISABLED)) &&
+                (laddr & smask) == (qsrc & smask)) {
                printf("%3d  ", -(hops+2));
                print_host(qsrc);
                printf("\n");
-               break;
+               return 1;
            }
            p += n;
        }
-       return;
+       return retval;
     }
-    printf(" didn't respond\n");
+    printf(" %s\n", why);
+    return 0;
 }
 
 
@@ -675,133 +877,199 @@ scale(hop)
 #define OUTS    2
 #define BOTH    3
 void
-stat_line(r, s, have_next)
+stat_line(r, s, have_next, rst)
     struct tr_resp *r, *s;
     int have_next;
+    int *rst;
 {
-    register timediff = (fixtime(ntohl(s->tr_qarr)) -
+    int timediff = (fixtime(ntohl(s->tr_qarr)) -
                         fixtime(ntohl(r->tr_qarr))) >> 16;
-    register v_lost, v_pct;
-    register g_lost, g_pct;
-    register v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
-    register g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
-    register v_pps, g_pps;
+    int v_lost, v_pct;
+    int g_lost, g_pct;
+    int v_out = ntohl(s->tr_vifout) - ntohl(r->tr_vifout);
+    int g_out = ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt);
+    int v_pps, g_pps;
     char v_str[8], g_str[8];
-    register have = NEITHER;
+    int have = NEITHER;
+    int res = *rst;
 
-    if (timediff == 0)
-        timediff = 1;
+    if (timediff == 0) timediff = 1;
     v_pps = v_out / timediff;
     g_pps = g_out / timediff;
 
-    if (v_out || s->tr_vifout != 0xFFFFFFFF)
-        have |= OUTS;
+    if (v_out && (s->tr_vifout != 0xFFFFFFFF && s->tr_vifout != 0) ||
+                (r->tr_vifout != 0xFFFFFFFF && r->tr_vifout != 0))
+           have |= OUTS;
 
     if (have_next) {
-       --r,  --s;
-       if (s->tr_vifin != 0xFFFFFFFF || r->tr_vifin != 0xFFFFFFFF)
+       --r,  --s,  --rst;
+       if ((s->tr_vifin != 0xFFFFFFFF && s->tr_vifin != 0) ||
+           (r->tr_vifin != 0xFFFFFFFF && r->tr_vifin != 0))
          have |= INS;
+       if (*rst)
+         res = 1;
     }
 
     switch (have) {
       case BOTH:
        v_lost = v_out - (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
-       if (v_out)
-           v_pct = (v_lost * 100 + (v_out >> 1)) / v_out;
-       else
-           v_pct = 0;
+       if (v_out) v_pct = (v_lost * 100 + (v_out >> 1)) / v_out;
+       else v_pct = 0;
        if (-100 < v_pct && v_pct < 101 && v_out > 10)
-           sprintf(v_str, "%3d", v_pct);
-       else
-           memcpy(v_str, " --", 4);
+         sprintf(v_str, "%3d", v_pct);
+       else memcpy(v_str, " --", 4);
 
        g_lost = g_out - (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
-       if (g_out)
-           g_pct = (g_lost * 100 + (g_out >> 1))/ g_out;
-       else
-           g_pct = 0;
+       if (g_out) g_pct = (g_lost * 100 + (g_out >> 1))/ g_out;
+       else g_pct = 0;
        if (-100 < g_pct && g_pct < 101 && g_out > 10)
-           sprintf(g_str, "%3d", g_pct);
+         sprintf(g_str, "%3d", g_pct);
+       else memcpy(g_str, " --", 4);
+
+       printf("%6d/%-5d=%s%%%4d pps",
+              v_lost, v_out, v_str, v_pps);
+       if (res)
+           printf("\n");
        else
-           memcpy(g_str, " --", 4);
-
-       printf("%6d/%-5d=%s%%%4d pps%6d/%-5d=%s%%%4d pps\n",
-              v_lost, v_out, v_str, v_pps, g_lost, g_out, g_str, g_pps);
-       if (debug > 2) {
-           printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
-           printf("v_out: %ld ", ntohl(s->tr_vifout));
-           printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
-           printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
-           printf("v_out: %ld ", ntohl(r->tr_vifout));
-           printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
-           printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
-           printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
-           printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
-           printf("time: %d\n", timediff);
-       }
+           printf("%6d/%-5d=%s%%%4d pps\n",
+                  g_lost, g_out, g_str, g_pps);
        break;
 
       case INS:
-       v_out = (ntohl(s->tr_vifin) - ntohl(r->tr_vifin));
-       g_out = (ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+       v_out = ntohl(s->tr_vifin) - ntohl(r->tr_vifin);
        v_pps = v_out / timediff;
-       g_pps = g_out / timediff;
        /* Fall through */
 
       case OUTS:
-       printf("       %-5d     %4d pps       %-5d     %4d pps\n",
-              v_out, v_pps, g_out, g_pps);
+       printf("       %-5d     %4d pps",
+              v_out, v_pps);
+       if (res)
+           printf("\n");
+       else
+           printf("       %-5d     %4d pps\n",
+                  g_out, g_pps);
        break;
 
       case NEITHER:
        printf("\n");
        break;
     }
+
+    if (debug > 2) {
+       printf("\t\t\t\tv_in: %ld ", ntohl(s->tr_vifin));
+       printf("v_out: %ld ", ntohl(s->tr_vifout));
+       printf("pkts: %ld\n", ntohl(s->tr_pktcnt));
+       printf("\t\t\t\tv_in: %ld ", ntohl(r->tr_vifin));
+       printf("v_out: %ld ", ntohl(r->tr_vifout));
+       printf("pkts: %ld\n", ntohl(r->tr_pktcnt));
+       printf("\t\t\t\tv_in: %ld ",ntohl(s->tr_vifin)-ntohl(r->tr_vifin));
+       printf("v_out: %ld ", ntohl(s->tr_vifout) - ntohl(r->tr_vifout));
+       printf("pkts: %ld ", ntohl(s->tr_pktcnt) - ntohl(r->tr_pktcnt));
+       printf("time: %d\n", timediff);
+       printf("\t\t\t\tres: %d\n", res);
+    }
 }
 
 /*
- * A fixup to check if any pktcnt has been reset.
+ * A fixup to check if any pktcnt has been reset, and to fix the
+ * byteorder bugs in mrouted 3.6 on little-endian machines.
  */
 void
-fixup_stats(base, new)
-    struct resp_buf *base, *new;
+fixup_stats(base, prev, new)
+    struct resp_buf *base, *prev, *new;
 {
-    register rno = base->len;
-    register struct tr_resp *b = base->resps + rno;
-    register struct tr_resp *n = new->resps + rno;
-
-    while (--rno >= 0)
-        if (ntohl((--n)->tr_pktcnt) < ntohl((--b)->tr_pktcnt))
-            break;
+    int rno = base->len;
+    struct tr_resp *b = base->resps + rno;
+    struct tr_resp *p = prev->resps + rno;
+    struct tr_resp *n = new->resps + rno;
+    int *r = reset + rno;
+    int *s = swaps + rno;
+    int res;
+
+    /* Check for byte-swappers */
+    while (--rno >= 0) {
+       --n; --p; --b; --s;
+       if (*s || abs(ntohl(n->tr_vifout) - ntohl(p->tr_vifout)) > 100000) {
+           /* This host sends byteswapped reports; swap 'em */
+           if (!*s) {
+               *s = 1;
+               b->tr_qarr = byteswap(b->tr_qarr);
+               b->tr_vifin = byteswap(b->tr_vifin);
+               b->tr_vifout = byteswap(b->tr_vifout);
+               b->tr_pktcnt = byteswap(b->tr_pktcnt);
+           }
 
-    if (rno < 0)
-        return;
+           n->tr_qarr = byteswap(n->tr_qarr);
+           n->tr_vifin = byteswap(n->tr_vifin);
+           n->tr_vifout = byteswap(n->tr_vifout);
+           n->tr_pktcnt = byteswap(n->tr_pktcnt);
+       }
+    }
 
     rno = base->len;
     b = base->resps + rno;
+    p = prev->resps + rno;
     n = new->resps + rno;
 
-    while (--rno >= 0)
-        (--b)->tr_pktcnt = (--n)->tr_pktcnt;
+    while (--rno >= 0) {
+       --n; --p; --b; --r;
+       res = ((ntohl(n->tr_pktcnt) < ntohl(b->tr_pktcnt)) ||
+              (ntohl(n->tr_pktcnt) < ntohl(p->tr_pktcnt)));
+       if (debug > 2)
+           printf("\t\tr=%d, res=%d\n", *r, res);
+       if (*r) {
+           if (res || *r > 1) {
+               /*
+                * This router appears to be a 3.4 with that nasty ol'
+                * neighbor version bug, which causes it to constantly
+                * reset.  Just nuke the statistics for this node, and
+                * don't even bother giving it the benefit of the
+                * doubt from now on.
+                */
+               p->tr_pktcnt = b->tr_pktcnt = n->tr_pktcnt;
+               *r++;
+           } else {
+               /*
+                * This is simply the situation that the original
+                * fixup_stats was meant to deal with -- that a
+                * 3.3 or 3.4 router deleted a cache entry while
+                * traffic was still active.
+                */
+               *r = 0;
+               break;
+           }
+       } else
+           *r = res;
+    }
+
+    if (rno < 0) return;
+
+    rno = base->len;
+    b = base->resps + rno;
+    p = prev->resps + rno;
+
+    while (--rno >= 0) (--b)->tr_pktcnt = (--p)->tr_pktcnt;
 }
 
 /*
  * Print responses with statistics for forward path (from src to dst)
  */
-void
+int
 print_stats(base, prev, new)
     struct resp_buf *base, *prev, *new;
 {
     int rtt, hop;
-    register char *ms;
-    register u_int32_t smask;
-    register rno = base->len - 1;
-    register struct tr_resp *b = base->resps + rno;
-    register struct tr_resp *p = prev->resps + rno;
-    register struct tr_resp *n = new->resps + rno;
-    register u_long resptime = new->rtime;
-    register u_long qarrtime = fixtime(ntohl(n->tr_qarr));
-    register ttl = n->tr_fttl;
+    char *ms;
+    u_int32_t smask;
+    int rno = base->len - 1;
+    struct tr_resp *b = base->resps + rno;
+    struct tr_resp *p = prev->resps + rno;
+    struct tr_resp *n = new->resps + rno;
+    int *r = reset + rno;
+    u_long resptime = new->rtime;
+    u_long qarrtime = fixtime(ntohl(n->tr_qarr));
+    u_int ttl = n->tr_fttl;
+    int first = (base == prev);
 
     VAL_TO_MASK(smask, b->tr_smask);
     printf("  Source        Response Dest");
@@ -811,12 +1079,14 @@ print_stats(base, prev, new)
           inet_fmt(base->qhdr.tr_raddr, s2), inet_fmt(qsrc, s1));
     rtt = t_diff(resptime, new->qtime);
     ms = scale(&rtt);
-    printf("     |       __/  rtt%5d%s    Lost/Sent = Pct  Rate       To %s\n",
-          rtt, ms, inet_fmt(qgrp, s2));
-    hop = t_diff(resptime, qarrtime);
-    ms = scale(&hop);
-    printf("     v      /     hop%5d%s", hop, ms);
-    printf("    ---------------------     --------------------\n");
+    printf("     %c       __/  rtt%5d%s    Lost/Sent = Pct  Rate       To %s\n",
+          first ? 'v' : '|', rtt, ms, inet_fmt(qgrp, s2));
+    if (!first) {
+       hop = t_diff(resptime, qarrtime);
+       ms = scale(&hop);
+       printf("     v      /     hop%5d%s", hop, ms);
+       printf("    ---------------------     --------------------\n");
+    }
     if (debug > 2) {
        printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin));
        printf("v_out: %ld ", ntohl(n->tr_vifout));
@@ -827,13 +1097,13 @@ print_stats(base, prev, new)
        printf("\t\t\t\tv_in: %ld ", ntohl(n->tr_vifin) - ntohl(b->tr_vifin));
        printf("v_out: %ld ", ntohl(n->tr_vifout) - ntohl(b->tr_vifout));
        printf("pkts: %ld\n", ntohl(n->tr_pktcnt) - ntohl(b->tr_pktcnt));
+       printf("\t\t\t\treset: %d\n", *r);
     }
 
     while (TRUE) {
-       if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_inaddr != b->tr_inaddr)) {
-           printf("Route changed, start again.\n");
-           exit(1);
-       }
+       if ((n->tr_inaddr != b->tr_inaddr) || (n->tr_inaddr != b->tr_inaddr))
+         return 1;             /* Route changed */
+
        if ((n->tr_inaddr != n->tr_outaddr))
          printf("%-15s\n", inet_fmt(n->tr_inaddr, s1));
        printf("%-15s %-14s %s\n", inet_fmt(n->tr_outaddr, s1), names[rno],
@@ -841,36 +1111,33 @@ print_stats(base, prev, new)
 
        if (rno-- < 1) break;
 
-       printf("     |     ^      ttl%5d   ", ttl);
-       if (prev == new)
-           printf("\n");
-       else
-           stat_line(p, n, TRUE);
-       resptime = qarrtime;
-       qarrtime = fixtime(ntohl((n-1)->tr_qarr));
-       hop = t_diff(resptime, qarrtime);
-       ms = scale(&hop);
-       printf("     v     |      hop%5d%s", hop, ms);
-       stat_line(b, n, TRUE);
+       printf("     %c     ^      ttl%5d   ", first ? 'v' : '|', ttl);
+       stat_line(p, n, TRUE, r);
+       if (!first) {
+           resptime = qarrtime;
+           qarrtime = fixtime(ntohl((n-1)->tr_qarr));
+           hop = t_diff(resptime, qarrtime);
+           ms = scale(&hop);
+           printf("     v     |      hop%5d%s", hop, ms);
+           stat_line(b, n, TRUE, r);
+       }
 
-       --b, --p, --n;
-       if (ttl < n->tr_fttl)
-           ttl = n->tr_fttl;
-       else
-           ++ttl;
+       --b, --p, --n, --r;
+       if (ttl < n->tr_fttl) ttl = n->tr_fttl;
+       else ++ttl;
     }
           
-    printf("     |      \\__   ttl%5d   ", ttl);
-    if (prev == new)
-        printf("\n");
-    else
-        stat_line(p, n, FALSE);
-    hop = t_diff(qarrtime, new->qtime);
-    ms = scale(&hop);
-    printf("     v         \\  hop%5d%s", hop, ms);
-    stat_line(b, n, FALSE);
+    printf("     %c      \\__   ttl%5d   ", first ? 'v' : '|', ttl);
+    stat_line(p, n, FALSE, r);
+    if (!first) {
+       hop = t_diff(qarrtime, new->qtime);
+       ms = scale(&hop);
+       printf("     v         \\  hop%5d%s", hop, ms);
+       stat_line(b, n, FALSE, r);
+    }
     printf("%-15s %s\n", inet_fmt(qdst, s1), inet_fmt(lcl_addr, s2));
     printf("  Receiver      Query Source\n\n");
+    return 0;
 }
 
 
@@ -889,147 +1156,155 @@ char *argv[];
     int recvlen;
     struct timeval tv;
     struct resp_buf *prev, *new;
-    struct tr_query *query;
     struct tr_resp *r;
     u_int32_t smask;
     int rno;
-    int hops, tries;
+    int hops, nexthop, tries;
+    u_int32_t lastout = 0;
     int numstats = 1;
     int waittime;
     int seed;
-    int ch;
 
     if (geteuid() != 0) {
        fprintf(stderr, "mtrace: must be root\n");
        exit(1);
     }
 
-    while ((ch = getopt(argc, argv, "d:g:i:lMm:npq:r:st:w:")) != -1) {
-        switch (ch) {
-       case 'd':                       /* Unlisted debug print option */
-           if (!isdigit(*optarg))
-               usage();
-           debug = atoi(optarg);
-           if (debug < 0)
-                debug = 0;
-           else if (debug > 3)
-               debug = 3;
-           break;
-
-        case 'M':                      /* Use multicast for reponse */
-           multicast = TRUE;
-           break;
-
-       case 'l':                       /* Loop updating stats indefinitely */
-           numstats = 3153600;
-           break;
-
-       case 'n':                       /* Don't reverse map host addresses */
-           numeric = TRUE;
-           break;
-
-       case 'p':                       /* Passive listen for traces */
-           passive = TRUE;
-           break;
-
-       case 's':                       /* Short form, don't wait for stats */
-           numstats = 0;
-           break;
-
-       case 'w':                       /* Time to wait for packet arrival */
-           if (!isdigit(*optarg))
-               usage();
-           timeout = atoi(optarg);
-           if (timeout < 1)
-               timeout = 1;
-           break;
-
-       case 'm':                       /* Max number of hops to trace */
-           if (!isdigit(*optarg))
-               usage();
-           qno = atoi(optarg);
-           if (qno > MAXHOPS)
-               qno = MAXHOPS;
-           else if (qno < 1)
-               qno = 0;
-           break;
-
-       case 'q':                       /* Number of query retries */
-           if (!isdigit(*optarg))
-               usage();
-           nqueries = atoi(optarg);
-           if (nqueries < 1)
-               nqueries = 1;
-           break;
-
-       case 'g':                       /* Last-hop gateway (dest of query) */
-           if ((gwy = host_addr(optarg)) == 0)
-               usage();
-           break;
-
-       case 't':                       /* TTL for query packet */
-           if (!isdigit(*optarg))
-               usage();
-           qttl = atoi(optarg);
-           if (qttl < 1)
-               qttl = 1;
-           rttl = qttl;
-           break;
-
-       case 'r':                       /* Dest for response packet */
-           if ((raddr = host_addr(optarg)) == 0)
-               usage();
-           break;
-
-       case 'i':                       /* Local interface address */
-           if ((lcl_addr = host_addr(optarg)) == 0)
-               usage();
-           break;
-
-       default:
-           usage();
-       } /* switch */
-    } /* while */
-    argv += optind;
-    argc -= optind;
-
-    switch (argc) {
-    case 3:            /* Path via group */
-       if ((qgrp = host_addr(argv[2])) == 0)
-               usage();
-       /* FALLTHROUGH */
-    case 2:            /* dest of path */
-       if ((qdst = host_addr(argv[1])) == 0)
-               usage();
-       /* FALLTHROUGH */
-    case 1:            /* source of path */
-       if ((qsrc = host_addr(argv[0])) == 0 || IN_MULTICAST(ntohl(qsrc)))
-           usage();
-       break;
+    argv++, argc--;
+    if (argc == 0) goto usage;
+
+    while (argc > 0 && *argv[0] == '-') {
+       char *p = *argv++;  argc--;
+       p++;
+       do {
+           char c = *p++;
+           char *arg = (char *) 0;
+           if (isdigit(*p)) {
+               arg = p;
+               p = "";
+           } else if (argc > 0) arg = argv[0];
+           switch (c) {
+             case 'd':                 /* Unlisted debug print option */
+               if (arg && isdigit(*arg)) {
+                   debug = atoi(arg);
+                   if (debug < 0) debug = 0;
+                   if (debug > 3) debug = 3;
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             case 'M':                 /* Use multicast for reponse */
+               multicast = TRUE;
+               break;
+             case 'l':                 /* Loop updating stats indefinitely */
+               numstats = 3153600;
+               break;
+             case 'n':                 /* Don't reverse map host addresses */
+               numeric = TRUE;
+               break;
+             case 'p':                 /* Passive listen for traces */
+               passive = TRUE;
+               break;
+             case 'v':                 /* Verbosity */
+               verbose = TRUE;
+               break;
+             case 's':                 /* Short form, don't wait for stats */
+               numstats = 0;
+               break;
+             case 'w':                 /* Time to wait for packet arrival */
+               if (arg && isdigit(*arg)) {
+                   timeout = atoi(arg);
+                   if (timeout < 1) timeout = 1;
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             case 'm':                 /* Max number of hops to trace */
+               if (arg && isdigit(*arg)) {
+                   qno = atoi(arg);
+                   if (qno > MAXHOPS) qno = MAXHOPS;
+                   else if (qno < 1) qno = 0;
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             case 'q':                 /* Number of query retries */
+               if (arg && isdigit(*arg)) {
+                   nqueries = atoi(arg);
+                   if (nqueries < 1) nqueries = 1;
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             case 'g':                 /* Last-hop gateway (dest of query) */
+               if (arg && (gwy = host_addr(arg))) {
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             case 't':                 /* TTL for query packet */
+               if (arg && isdigit(*arg)) {
+                   qttl = atoi(arg);
+                   if (qttl < 1) qttl = 1;
+                   rttl = qttl;
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             case 'r':                 /* Dest for response packet */
+               if (arg && (raddr = host_addr(arg))) {
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             case 'i':                 /* Local interface address */
+               if (arg && (lcl_addr = host_addr(arg))) {
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             case 'S':                 /* Stat accumulation interval */
+               if (arg && isdigit(*arg)) {
+                   statint = atoi(arg);
+                   if (statint < 1) statint = 1;
+                   if (arg == argv[0]) argv++, argc--;
+                   break;
+               } else
+                   goto usage;
+             default:
+               goto usage;
+           }
+       } while (*p);
+    }
 
-    default:
-       usage();
+    if (argc > 0 && (qsrc = host_addr(argv[0]))) {          /* Source of path */
+       if (IN_MULTICAST(ntohl(qsrc))) goto usage;
+       argv++, argc--;
+       if (argc > 0 && (qdst = host_addr(argv[0]))) {      /* Dest of path */
+           argv++, argc--;
+           if (argc > 0 && (qgrp = host_addr(argv[0]))) {  /* Path via group */
+               argv++, argc--;
+           }
+           if (IN_MULTICAST(ntohl(qdst))) {
+               u_int32_t temp = qdst;
+               qdst = qgrp;
+               qgrp = temp;
+               if (IN_MULTICAST(ntohl(qdst))) goto usage;
+           } else if (qgrp && !IN_MULTICAST(ntohl(qgrp))) goto usage;
+       }
     }
 
-    /*
-     * If argc is > 1 and the second argument is a multicast address,
-     * assume that the second argument is actually qgrp and the third
-     * (if any) is qdst; in this case, the third argument is not allowed
-     * to be a multicast address.
-     */
-    if (argc > 1) {
-       if (IN_MULTICAST(ntohl(qdst))) {
-           u_int32_t temp = qdst;
-           qdst = qgrp;
-           qgrp = temp;
-           if (IN_MULTICAST(ntohl(qdst)))
-               usage();
-       } else if (qgrp != 0 && !IN_MULTICAST(ntohl(qgrp)))
-           usage();
+    if (passive) {
+       passive_mode();
+       return(0);
     }
 
-    if (qsrc == 0)
-       usage();
+    if (argc > 0 || qsrc == 0) {
+usage: printf("\
+Usage: mtrace [-Mlnps] [-w wait] [-m max_hops] [-q nqueries] [-g gateway]\n\
+              [-S statint] [-t ttl] [-r resp_dest] [-i if_addr] source [receiver] [group]\n");
+       exit(1);
+    }
 
     init_igmp();
 
@@ -1040,8 +1315,7 @@ char *argv[];
     defgrp = htonl(0xE0020001);                /* MBone Audio (224.2.0.1) */
     query_cast = htonl(0xE0000002);    /* All routers multicast addr */
     resp_cast = htonl(0xE0000120);     /* Mtrace response multicast addr */
-    if (qgrp == 0)
-        qgrp = defgrp;
+    if (qgrp == 0) qgrp = defgrp;
 
     /*
      * Get default local address for multicasts to use in setting defaults.
@@ -1060,41 +1334,67 @@ char *argv[];
        exit(-1);
     }
 
+#ifdef SUNOS5
     /*
-     * Default destination for path to be queried is the local host.
+     * SunOS 5.X prior to SunOS 2.6, getsockname returns 0 for udp socket.
+     * This call to sysinfo will return the hostname.
+     * If the default multicast interfface (set with the route
+     * for 224.0.0.0) is not the same as the hostname,
+     * mtrace -i [if_addr] will have to be used.
      */
-    if (qdst == 0)
-        qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
+    if (addr.sin_addr.s_addr == 0) {
+       char myhostname[MAXHOSTNAMELEN];
+       struct hostent *hp;
+       int error;
+    
+       error = sysinfo(SI_HOSTNAME, myhostname, sizeof(myhostname));
+       if (error == -1) {
+           perror("Getting my hostname");
+           exit(-1);
+       }
+
+       hp = gethostbyname(myhostname);
+       if (hp == NULL || hp->h_addrtype != AF_INET ||
+           hp->h_length != sizeof(addr.sin_addr)) {
+           perror("Finding IP address for my hostname");
+           exit(-1);
+       }
+
+       memcpy((char *)&addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
+    }
+#endif
 
     /*
-     * If the destination is on the local net, the last-hop router can
-     * be found by multicast to the all-routers multicast group.
-     * Otherwise, use the group address that is the subject of the
-     * query since by definition the last hop router will be a member.
-     * Set default TTLs for local remote multicasts.
+     * Default destination for path to be queried is the local host.
      */
+    if (qdst == 0) qdst = lcl_addr ? lcl_addr : addr.sin_addr.s_addr;
     dst_netmask = get_netmask(udp, qdst);
     close(udp);
-    if (lcl_addr == 0)
-        lcl_addr = addr.sin_addr.s_addr;
-    if (gwy == 0)
-        if ((qdst & dst_netmask) == (lcl_addr & dst_netmask))
-            gwy = query_cast;
-        else
-            gwy = qgrp;
+    if (lcl_addr == 0) lcl_addr = addr.sin_addr.s_addr;
 
-    if (IN_MULTICAST(ntohl(gwy))) {
-      k_set_loop(1);   /* If I am running on a router, I need to hear this */
-      if (gwy == query_cast)
-          k_set_ttl(qttl ? qttl : 1);
-      else
-          k_set_ttl(qttl ? qttl : MULTICAST_TTL1);
-    } else
-      if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0]))
-       if (ntohl(incr[0].igmp.igmp_group.s_addr) == 0x0303) {
-           printf("Don't use -g to address an mrouted 3.3, it might crash\n");
+    /*
+     * Initialize the seed for random query identifiers.
+     */
+    gettimeofday(&tv, 0);
+    seed = tv.tv_usec ^ lcl_addr;
+#ifdef SYSV    
+    srand48(seed);
+#else
+    srandom(seed);
+#endif
+
+    /*
+     * Protect against unicast queries to mrouted versions that might crash.
+     */
+    if (gwy && !IN_MULTICAST(ntohl(gwy)))
+      if (send_recv(gwy, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS2, 1, &incr[0])) {
+         int version = ntohl(incr[0].igmp.igmp_group.s_addr) & 0xFFFF;
+         if (version == 0x0303 || version == 0x0503) {
+           printf("Don't use -g to address an mrouted 3.%d, it might crash\n",
+                  (version >> 8) & 0xFF);
            exit(0);
        }
+      }
 
     printf("Mtrace from %s to %s via group %s\n",
           inet_fmt(qsrc, s1), inet_fmt(qdst, s2), inet_fmt(qgrp, s3));
@@ -1105,29 +1405,35 @@ char *argv[];
     }
 
     /*
-     * Make up the IGMP_MTRACE_QUERY query packet to send (some parameters
-     * are set later), including initializing the seed for random
-     * query identifiers.
+     * If the response is to be a multicast address, make sure we 
+     * are listening on that multicast address.
      */
-    query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
-    query->tr_src   = qsrc;
-    query->tr_dst   = qdst;
-
-    gettimeofday(&tv, 0);
-    seed = tv.tv_usec ^ lcl_addr;
-    srandom(seed);
+    if (raddr) {
+       if (IN_MULTICAST(ntohl(raddr))) k_join(raddr, lcl_addr);
+    } else k_join(resp_cast, lcl_addr);
 
     /*
-     * If the response is to be a multicast address, make sure we 
-     * are listening on that multicast address.
+     * If the destination is on the local net, the last-hop router can
+     * be found by multicast to the all-routers multicast group.
+     * Otherwise, use the group address that is the subject of the
+     * query since by definition the last-hop router will be a member.
+     * Set default TTLs for local remote multicasts.
      */
-    if (raddr && IN_MULTICAST(ntohl(raddr)))
-        k_join(raddr, lcl_addr);
-    else
-        k_join(resp_cast, lcl_addr);
+    restart:
+
+    if (gwy == 0)
+      if ((qdst & dst_netmask) == (lcl_addr & dst_netmask)) tdst = query_cast;
+      else tdst = qgrp;
+    else tdst = gwy;
+
+    if (IN_MULTICAST(ntohl(tdst))) {
+      k_set_loop(1);   /* If I am running on a router, I need to hear this */
+      if (tdst == query_cast) k_set_ttl(qttl ? qttl : 1);
+      else k_set_ttl(qttl ? qttl : MULTICAST_TTL1);
+    }
 
     /*
-     * Try a query at the requested number of hops or MAXOPS if unspecified.
+     * Try a query at the requested number of hops or MAXHOPS if unspecified.
      */
     if (qno == 0) {
        hops = MAXHOPS;
@@ -1143,12 +1449,14 @@ char *argv[];
     base.rtime = 0;
     base.len = 0;
 
-    recvlen = send_recv(gwy, IGMP_MTRACE_QUERY, hops, tries, &base);
+    recvlen = send_recv(tdst, IGMP_MTRACE_QUERY, hops, tries, &base);
 
     /*
      * If the initial query was successful, print it.  Otherwise, if
      * the query max hop count is the default of zero, loop starting
-     * from one until a timeout occurs.
+     * from one until there is no response for four hops.  The extra
+     * hops allow getting past an mtrace-capable mrouter that can't
+     * send multicast packets because all phyints are disabled.
      */
     if (recvlen) {
        printf("\n  0  ");
@@ -1156,10 +1464,12 @@ char *argv[];
        printf("\n");
        print_trace(1, &base);
        r = base.resps + base.len - 1;
-       if (r->tr_rflags == TR_OLD_ROUTER) {
+       if (r->tr_rflags == TR_OLD_ROUTER || r->tr_rflags == TR_NO_SPACE ||
+               qno != 0) {
            printf("%3d  ", -(base.len+1));
-           fflush(stdout);
-           what_kind(&base);
+           what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
+                                  "doesn't support mtrace"
+                                : "is the next hop");
        } else {
            VAL_TO_MASK(smask, r->tr_smask);
            if ((r->tr_inaddr & smask) == (qsrc & smask)) {
@@ -1173,50 +1483,113 @@ char *argv[];
        print_host(qdst);
        printf("\n");
 
-       for (hops = 1; hops <= MAXHOPS; ++hops) {
+       for (hops = 1, nexthop = 1; hops <= MAXHOPS; ++hops) {
            printf("%3d  ", -hops);
            fflush(stdout);
 
-           recvlen = send_recv(gwy, IGMP_MTRACE_QUERY, hops, nqueries, &base);
+           /*
+            * After a successful first hop, try switching to the unicast
+            * address of the last-hop router instead of multicasting the
+            * trace query.  This should be safe for mrouted versions 3.3
+            * and 3.5 because there is a long route timeout with metric
+            * infinity before a route disappears.  Switching to unicast
+            * reduces the amount of multicast traffic and avoids a bug
+            * with duplicate suppression in mrouted 3.5.
+            */
+           if (hops == 2 && gwy == 0 &&
+               (recvlen = send_recv(lastout, IGMP_MTRACE_QUERY, hops, 1, &base)))
+             tdst = lastout;
+           else recvlen = send_recv(tdst, IGMP_MTRACE_QUERY, hops, nqueries, &base);
 
            if (recvlen == 0) {
-               if (--hops == 0) break;
-               what_kind(&base);
-               break;
+               if (hops == 1) break;
+               if (hops == nexthop) {
+                   if (what_kind(&base, "didn't respond")) {
+                       /* the ask_neighbors determined that the
+                        * not-responding router is the first-hop. */
+                       break;
+                   }
+               } else if (hops < nexthop + 3) {
+                   printf("\n");
+               } else {
+                   printf("...giving up\n");
+                   break;
+               }
+               continue;
            }
            r = base.resps + base.len - 1;
-           if (base.len == hops)
-               print_trace(-hops, &base);
-           else {
-               hops = base.len;
-               if (r->tr_rflags == TR_OLD_ROUTER) {
-                   what_kind(&base);
-                   break;
+           if (base.len == hops &&
+               (hops == 1 || (base.resps+nexthop-2)->tr_outaddr == lastout)) {
+               if (hops == nexthop) {
+                   print_trace(-hops, &base);
+               } else {
+                   printf("\nResuming...\n");
+                   print_trace(nexthop, &base);
                }
-               if (r->tr_rflags == TR_NO_SPACE) {
-                   printf("No space left in trace packet for further hops\n");
-                   break;      /* XXX could do segmented trace */
+           } else {
+               if (base.len < hops) {
+                   /*
+                    * A shorter trace than requested means a fatal error
+                    * occurred along the path, or that the route changed
+                    * to a shorter one.
+                    *
+                    * If the trace is longer than the last one we received,
+                    * then we are resuming from a skipped router (but there
+                    * is still probably a problem).
+                    *
+                    * If the trace is shorter than the last one we
+                    * received, then the route must have changed (and
+                    * there is still probably a problem).
+                    */
+                   if (nexthop <= base.len) {
+                       printf("\nResuming...\n");
+                       print_trace(nexthop, &base);
+                   } else if (nexthop > base.len + 1) {
+                       hops = base.len;
+                       printf("\nRoute must have changed...\n");
+                       print_trace(1, &base);
+                   }
+               } else {
+                   /*
+                    * The last hop address is not the same as it was;
+                    * the route probably changed underneath us.
+                    */
+                   hops = base.len;
+                   printf("\nRoute must have changed...\n");
+                   print_trace(1, &base);
                }
-               printf("Route must have changed...\n\n");
-               print_trace(1, &base);
            }
-
-           VAL_TO_MASK(smask, r->tr_smask);
-           if ((r->tr_inaddr & smask) == (qsrc & smask)) {
-               printf("%3d  ", -(hops+1));
-               print_host(qsrc);
-               printf("\n");
+           lastout = r->tr_outaddr;
+
+           if (base.len < hops ||
+               r->tr_rmtaddr == 0 ||
+               (r->tr_rflags & 0x80)) {
+               VAL_TO_MASK(smask, r->tr_smask);
+               if (r->tr_rmtaddr) {
+                   if (hops != nexthop) {
+                       printf("\n%3d  ", -(base.len+1));
+                   }
+                   what_kind(&base, r->tr_rflags == TR_OLD_ROUTER ?
+                               "doesn't support mtrace" :
+                               "would be the next hop");
+                   /* XXX could do segmented trace if TR_NO_SPACE */
+               } else if (r->tr_rflags == TR_NO_ERR &&
+                          (r->tr_inaddr & smask) == (qsrc & smask)) {
+                   printf("%3d  ", -(hops + 1));
+                   print_host(qsrc);
+                   printf("\n");
+               }
                break;
            }
-           if (r->tr_rmtaddr == 0 || (r->tr_rflags & 0x80))
-               break;
+
+           nexthop = hops + 1;
        }
     }
 
     if (base.rtime == 0) {
        printf("Timed out receiving responses\n");
-       if (IN_MULTICAST(ntohl(gwy)))
-         if (gwy == query_cast)
+       if (IN_MULTICAST(ntohl(tdst)))
+         if (tdst == query_cast)
            printf("Perhaps no local router has a route for source %s\n",
                   inet_fmt(qsrc, s1));
          else
@@ -1237,8 +1610,9 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
     raddr = base.qhdr.tr_raddr;
     rttl = base.qhdr.tr_rttl;
     gettimeofday(&tv, 0);
-    waittime = 10 - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
-    prev = new = &incr[numstats&1];
+    waittime = statint - (((tv.tv_sec + JAN_1970) & 0xFFFF) - (base.qtime >> 16));
+    prev = &base;
+    new = &incr[numstats&1];
 
     while (numstats--) {
        if (waittime < 1) printf("\n");
@@ -1248,7 +1622,7 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
            sleep((unsigned)waittime);
        }
        rno = base.len;
-       recvlen = send_recv(gwy, IGMP_MTRACE_QUERY, rno, nqueries, new);
+       recvlen = send_recv(tdst, IGMP_MTRACE_QUERY, rno, nqueries, new);
 
        if (recvlen == 0) {
            printf("Timed out.\n");
@@ -1256,24 +1630,41 @@ or multicast at ttl %d doesn't reach its last-hop router for that source\n",
        }
 
        if (rno != new->len) {
-           printf("Trace length doesn't match.\n");
-           exit(1);
+           printf("Trace length doesn't match:\n");
+           /*
+            * XXX Should this trace result be printed, or is that
+            * too verbose?  Perhaps it should just say restarting.
+            * But if the path is changing quickly, this may be the
+            * only snapshot of the current path.  But, if the path
+            * is changing that quickly, does the current path really
+            * matter?
+            */
+           print_trace(1, new);
+           printf("Restarting.\n\n");
+           numstats++;
+           goto restart;
        }
 
        printf("Results after %d seconds:\n\n",
-              (new->qtime - base.qtime) >> 16);
-       fixup_stats(&base, new);
-       print_stats(&base, prev, new);
+              (int)((new->qtime - base.qtime) >> 16));
+       fixup_stats(&base, prev, new);
+       if (print_stats(&base, prev, new)) {
+           printf("Route changed:\n");
+           print_trace(1, new);
+           printf("Restarting.\n\n");
+           goto restart;
+       }
        prev = new;
        new = &incr[numstats&1];
-       waittime = 10;
+       waittime = statint;
     }
 
     /*
      * If the response was multicast back, leave the group
      */
-    if (raddr && IN_MULTICAST(ntohl(raddr))) k_leave(raddr, lcl_addr);
-    else k_leave(resp_cast, lcl_addr);
+    if (raddr) {
+       if (IN_MULTICAST(ntohl(raddr))) k_leave(raddr, lcl_addr);
+    } else k_leave(resp_cast, lcl_addr);
 
     return (0);
 }
@@ -1289,30 +1680,37 @@ check_vif_state()
  * of the message and the current debug level.  For errors of severity
  * LOG_ERR or worse, terminate the program.
  */
-/*VARARGS3*/
+#ifdef __STDC__
 void
-log(severity, syserr, format, a, b, c, d, e)
-    int severity, syserr;
-    char *format;
-    int a, b, c, d, e;
+log(int severity, int syserr, char *format, ...)
 {
-    char fmt[100];
+       va_list ap;
+       char    fmt[100];
+
+       va_start(ap, format);
+#else
+/*VARARGS3*/
+void 
+log(severity, syserr, format, va_alist)
+       int     severity, syserr;
+       char   *format;
+       va_dcl
+{
+       va_list ap;
+       char    fmt[100];
+
+       va_start(ap);
+#endif
 
     switch (debug) {
-       case 0:
-           if (severity > LOG_WARNING)
-               return;
-       case 1:
-           if (severity > LOG_NOTICE)
-               return;
-       case 2:
-           if (severity > LOG_INFO)
-               return;
+       case 0: if (severity > LOG_WARNING) return;
+       case 1: if (severity > LOG_NOTICE) return;
+       case 2: if (severity > LOG_INFO  ) return;
        default:
            fmt[0] = '\0';
            if (severity == LOG_WARNING) strcat(fmt, "warning - ");
            strncat(fmt, format, 80);
-           fprintf(stderr, fmt, a, b, c, d, e);
+           vfprintf(stderr, fmt, ap);
            if (syserr == 0)
                fprintf(stderr, "\n");
            else if(syserr < sys_nerr)
@@ -1320,24 +1718,94 @@ log(severity, syserr, format, a, b, c, d, e)
            else
                fprintf(stderr, ": errno %d\n", syserr);
     }
-    if (severity <= LOG_ERR)
-        exit(-1);
+    if (severity <= LOG_ERR) exit(-1);
 }
 
 /* dummies */
-
-/*VARARGS*/
-void accept_probe() {} /*VARARGS*/
-void accept_group_report() {} /*VARARGS*/
-void accept_neighbors() {} /*VARARGS*/
-void accept_neighbors2() {} /*VARARGS*/
-void accept_neighbor_request() {} /*VARARGS*/
-void accept_neighbor_request2() {} /*VARARGS*/
-void accept_report() {} /*VARARGS*/
-void accept_prune() {} /*VARARGS*/
-void accept_graft() {} /*VARARGS*/
-void accept_g_ack() {} /*VARARGS*/
-void add_table_entry() {} /*VARARGS*/
-void accept_mtrace() {} /*VARARGS*/
-void accept_leave_message() {} /*VARARGS*/
-void accept_membership_query() {} /*VARARGS*/
+void accept_probe(src, dst, p, datalen, level)
+       u_int32_t src, dst, level;
+       char *p;
+       int datalen;
+{
+}
+void accept_group_report(src, dst, group, r_type)
+       u_int32_t src, dst, group;
+       int r_type;
+{
+}
+void accept_neighbor_request2(src, dst)
+       u_int32_t src, dst;
+{
+}
+void accept_report(src, dst, p, datalen, level)
+       u_int32_t src, dst, level;
+       char *p;
+       int datalen;
+{
+}
+void accept_neighbor_request(src, dst)
+       u_int32_t src, dst;
+{
+}
+void accept_prune(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
+{
+}
+void accept_graft(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
+{
+}
+void accept_g_ack(src, dst, p, datalen)
+       u_int32_t src, dst;
+       char *p;
+       int datalen;
+{
+}
+void add_table_entry(origin, mcastgrp)
+       u_int32_t origin, mcastgrp;
+{
+}
+void accept_leave_message(src, dst, group)
+       u_int32_t src, dst, group;
+{
+}
+void accept_mtrace(src, dst, group, data, no, datalen)
+       u_int32_t src, dst, group;
+       char *data;
+       u_int no;
+       int datalen;
+{
+}
+void accept_membership_query(src, dst, group, tmo)
+       u_int32_t src, dst, group;
+       int tmo;
+{
+}
+void accept_neighbors(src, dst, p, datalen, level)
+       u_int32_t src, dst, level;
+       u_char *p;
+       int datalen;
+{
+}
+void accept_neighbors2(src, dst, p, datalen, level)
+       u_int32_t src, dst, level;
+       u_char *p;
+       int datalen;
+{
+}
+void accept_info_request(src, dst, p, datalen)
+       u_int32_t src, dst;
+       u_char *p;
+       int datalen;
+{
+}
+void accept_info_reply(src, dst, p, datalen)
+       u_int32_t src, dst;
+       u_char *p;
+       int datalen;
+{
+}