diff options
-rw-r--r-- | usr.sbin/map-mbone/mapper.c | 132 | ||||
-rw-r--r-- | usr.sbin/mrinfo/mrinfo.c | 250 | ||||
-rw-r--r-- | usr.sbin/mrouted/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/mrouted/callout.c | 84 | ||||
-rw-r--r-- | usr.sbin/mrouted/cfparse.y | 180 | ||||
-rw-r--r-- | usr.sbin/mrouted/config.c | 5 | ||||
-rw-r--r-- | usr.sbin/mrouted/defs.h | 313 | ||||
-rw-r--r-- | usr.sbin/mrouted/dvmrp.h | 19 | ||||
-rw-r--r-- | usr.sbin/mrouted/igmp.c | 83 | ||||
-rw-r--r-- | usr.sbin/mrouted/inet.c | 53 | ||||
-rw-r--r-- | usr.sbin/mrouted/kern.c | 32 | ||||
-rw-r--r-- | usr.sbin/mrouted/main.c | 321 | ||||
-rw-r--r-- | usr.sbin/mrouted/mrouted.8 | 17 | ||||
-rw-r--r-- | usr.sbin/mrouted/pathnames.h | 9 | ||||
-rw-r--r-- | usr.sbin/mrouted/prune.c | 469 | ||||
-rw-r--r-- | usr.sbin/mrouted/prune.h | 9 | ||||
-rw-r--r-- | usr.sbin/mrouted/route.c | 94 | ||||
-rw-r--r-- | usr.sbin/mrouted/route.h | 6 | ||||
-rw-r--r-- | usr.sbin/mrouted/rsrr.c | 243 | ||||
-rw-r--r-- | usr.sbin/mrouted/snmp.c | 1824 | ||||
-rw-r--r-- | usr.sbin/mrouted/snmp.h | 506 | ||||
-rw-r--r-- | usr.sbin/mrouted/vif.c | 686 | ||||
-rw-r--r-- | usr.sbin/mrouted/vif.h | 11 | ||||
-rw-r--r-- | usr.sbin/mtrace/mtrace.8 | 34 | ||||
-rw-r--r-- | usr.sbin/mtrace/mtrace.c | 1430 |
25 files changed, 3888 insertions, 2928 deletions
diff --git a/usr.sbin/map-mbone/mapper.c b/usr.sbin/map-mbone/mapper.c index e58b0fb3bad..7a273d01aee 100644 --- a/usr.sbin/map-mbone/mapper.c +++ b/usr.sbin/map-mbone/mapper.c @@ -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> @@ -25,6 +25,12 @@ #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; { } diff --git a/usr.sbin/mrinfo/mrinfo.c b/usr.sbin/mrinfo/mrinfo.c index 20bd54fcf36..e8cfc4f091d 100644 --- a/usr.sbin/mrinfo/mrinfo.c +++ b/usr.sbin/mrinfo/mrinfo.c @@ -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; { } diff --git a/usr.sbin/mrouted/Makefile b/usr.sbin/mrouted/Makefile index fc24ca1911d..9b64d2e905a 100644 --- a/usr.sbin/mrouted/Makefile +++ b/usr.sbin/mrouted/Makefile @@ -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 diff --git a/usr.sbin/mrouted/callout.c b/usr.sbin/mrouted/callout.c index 943ace50507..9c3acf02202 100644 --- a/usr.sbin/mrouted/callout.c +++ b/usr.sbin/mrouted/callout.c @@ -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 @@ -15,21 +15,24 @@ 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; +} diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y index 9538200f814..00608f87f86 100644 --- a/usr.sbin/mrouted/cfparse.y +++ b/usr.sbin/mrouted/cfparse.y @@ -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,17 +258,23 @@ 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"); + + } ; mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255) @@ -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 diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c index 3a4e1bd2f60..39d8f5c0db7 100644 --- a/usr.sbin/mrouted/config.c +++ b/usr.sbin/mrouted/config.c @@ -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; diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h index 8d5aa9c6d3a..27172d990be 100644 --- a/usr.sbin/mrouted/defs.h +++ b/usr.sbin/mrouted/defs.h @@ -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 @@ -10,10 +10,21 @@ */ +#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> @@ -21,15 +32,21 @@ #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 */ /* @@ -49,13 +67,17 @@ #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 @@ -78,10 +101,17 @@ #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 */ diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h index c008dd37151..b4f2bf440bf 100644 --- a/usr.sbin/mrouted/dvmrp.h +++ b/usr.sbin/mrouted/dvmrp.h @@ -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. @@ -108,6 +110,12 @@ #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 */ #define MAX_IP_PACKET_LEN 576 @@ -121,8 +129,14 @@ */ /* 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 */ @@ -143,8 +157,7 @@ #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 */ diff --git a/usr.sbin/mrouted/igmp.c b/usr.sbin/mrouted/igmp.c index f4c19d85b53..1b623ba42ff 100644 --- a/usr.sbin/mrouted/igmp.c +++ b/usr.sbin/mrouted/igmp.c @@ -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 @@ -25,10 +25,18 @@ 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)); diff --git a/usr.sbin/mrouted/inet.c b/usr.sbin/mrouted/inet.c index b6c6a01788d..7229545f913 100644 --- a/usr.sbin/mrouted/inet.c +++ b/usr.sbin/mrouted/inet.c @@ -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; } diff --git a/usr.sbin/mrouted/kern.c b/usr.sbin/mrouted/kern.c index 0dbae18624a..f41edce77c4 100644 --- a/usr.sbin/mrouted/kern.c +++ b/usr.sbin/mrouted/kern.c @@ -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 } diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c index 71d9ee36f43..6736317f885 100644 --- a/usr.sbin/mrouted/main.c +++ b/usr.sbin/mrouted/main.c @@ -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 @@ -20,14 +20,24 @@ #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) { @@ -161,6 +180,7 @@ usage: fprintf(stderr, if (setsid() < 0) perror("setsid"); #endif +#endif } else fprintf(stderr, "debug level %u\n", debug); @@ -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 diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8 index dd7c74f65c1..2b2712e3445 100644 --- a/usr.sbin/mrouted/mrouted.8 +++ b/usr.sbin/mrouted/mrouted.8 @@ -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 diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h index c7939fde1c1..27814ab1c19 100644 --- a/usr.sbin/mrouted/pathnames.h +++ b/usr.sbin/mrouted/pathnames.h @@ -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 @@ -11,7 +11,14 @@ #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 diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c index aaba6c318ee..3d28974707d 100644 --- a/usr.sbin/mrouted/prune.c +++ b/usr.sbin/mrouted/prune.c @@ -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_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_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_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_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_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_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; } diff --git a/usr.sbin/mrouted/prune.h b/usr.sbin/mrouted/prune.h index 22df280b830..b3187a89d37 100644 --- a/usr.sbin/mrouted/prune.h +++ b/usr.sbin/mrouted/prune.h @@ -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)++; \ }; diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c index d45de2361af..6765ae95548 100644 --- a/usr.sbin/mrouted/route.c +++ b/usr.sbin/mrouted/route.c @@ -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 @@ -38,12 +38,25 @@ 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. */ 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, diff --git a/usr.sbin/mrouted/route.h b/usr.sbin/mrouted/route.h index 5bc27b891af..a01a16dac5c 100644 --- a/usr.sbin/mrouted/route.h +++ b/usr.sbin/mrouted/route.h @@ -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 */ }; diff --git a/usr.sbin/mrouted/rsrr.c b/usr.sbin/mrouted/rsrr.c index f5b41955ea4..1c0261db9b8 100644 --- a/usr.sbin/mrouted/rsrr.c +++ b/usr.sbin/mrouted/rsrr.c @@ -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 @@ -30,9 +30,15 @@ * 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_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_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 */ diff --git a/usr.sbin/mrouted/snmp.c b/usr.sbin/mrouted/snmp.c index 5298da5dbc8..6f203efc826 100644 --- a/usr.sbin/mrouted/snmp.c +++ b/usr.sbin/mrouted/snmp.c @@ -1,57 +1,136 @@ -/* $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(>,&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(>, &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_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(>, &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(>, &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; } diff --git a/usr.sbin/mrouted/snmp.h b/usr.sbin/mrouted/snmp.h index c78c050d6b3..b2e203e700c 100644 --- a/usr.sbin/mrouted/snmp.h +++ b/usr.sbin/mrouted/snmp.h @@ -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 diff --git a/usr.sbin/mrouted/vif.c b/usr.sbin/mrouted/vif.c index 406e8157858..326d17dcd67 100644 --- a/usr.sbin/mrouted/vif.c +++ b/usr.sbin/mrouted/vif.c @@ -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 @@ -11,29 +11,48 @@ #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,12 +236,28 @@ 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; struct phaddr *p; @@ -202,11 +266,6 @@ start_vif(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. */ add_vif_to_routes(vifi); @@ -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); } @@ -1170,20 +1281,6 @@ neighbor_info(vifi, addr) } /* - * 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'. */ void @@ -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); } diff --git a/usr.sbin/mrouted/vif.h b/usr.sbin/mrouted/vif.h index 4ff8194946d..bb3a0f05b06 100644 --- a/usr.sbin/mrouted/vif.h +++ b/usr.sbin/mrouted/vif.h @@ -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 */ }; diff --git a/usr.sbin/mtrace/mtrace.8 b/usr.sbin/mtrace/mtrace.8 index 37495c5b44e..66ac0fb802c 100644 --- a/usr.sbin/mtrace/mtrace.8 +++ b/usr.sbin/mtrace/mtrace.8 @@ -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) diff --git a/usr.sbin/mtrace/mtrace.c b/usr.sbin/mtrace/mtrace.c index d7bfe3f1c3a..6f8323ad061 100644 --- a/usr.sbin/mtrace/mtrace.c +++ b/usr.sbin/mtrace/mtrace.c @@ -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 @@ -50,21 +50,27 @@ * 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; +{ +} |