Home | History | Annotate | Line # | Download | only in mrouted
main.c revision 1.14
      1  1.14      wiz /*	$NetBSD: main.c,v 1.14 2001/04/06 11:13:49 wiz Exp $	*/
      2   1.5  thorpej 
      3   1.1   brezak /*
      4   1.1   brezak  * The mrouted program is covered by the license in the accompanying file
      5   1.1   brezak  * named "LICENSE".  Use of the mrouted program represents acceptance of
      6   1.1   brezak  * the terms and conditions listed in that file.
      7   1.1   brezak  *
      8   1.1   brezak  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
      9   1.1   brezak  * Leland Stanford Junior University.
     10   1.1   brezak  */
     11   1.1   brezak 
     12   1.1   brezak /*
     13   1.1   brezak  * Written by Steve Deering, Stanford University, February 1989.
     14   1.1   brezak  *
     15   1.1   brezak  * (An earlier version of DVMRP was implemented by David Waitzman of
     16   1.1   brezak  *  BBN STC by extending Berkeley's routed program.  Some of Waitzman's
     17   1.1   brezak  *  extensions have been incorporated into mrouted, but none of the
     18   1.1   brezak  *  original routed code has been adopted.)
     19   1.1   brezak  */
     20   1.1   brezak 
     21   1.1   brezak 
     22   1.1   brezak #include "defs.h"
     23   1.6  mycroft #ifdef __STDC__
     24   1.6  mycroft #include <stdarg.h>
     25   1.6  mycroft #else
     26   1.4  mycroft #include <varargs.h>
     27   1.6  mycroft #endif
     28   1.6  mycroft #include <fcntl.h>
     29   1.4  mycroft 
     30   1.4  mycroft #ifdef SNMP
     31   1.4  mycroft #include "snmp.h"
     32   1.4  mycroft #endif
     33   1.1   brezak 
     34   1.9    lukem #include <sys/cdefs.h>
     35   1.6  mycroft #ifndef lint
     36  1.14      wiz __RCSID("@(#) $NetBSD: main.c,v 1.14 2001/04/06 11:13:49 wiz Exp $");
     37   1.6  mycroft #endif
     38   1.6  mycroft 
     39  1.12  thorpej #include <err.h>
     40  1.12  thorpej #include <util.h>
     41  1.12  thorpej 
     42   1.1   brezak extern char *configfilename;
     43   1.6  mycroft char versionstring[100];
     44   1.1   brezak 
     45   1.1   brezak static char dumpfilename[] = _PATH_MROUTED_DUMP;
     46   1.4  mycroft static char cachefilename[] = _PATH_MROUTED_CACHE;
     47   1.4  mycroft static char genidfilename[] = _PATH_MROUTED_GENID;
     48   1.4  mycroft 
     49   1.4  mycroft int cache_lifetime 	= DEFAULT_CACHE_LIFETIME;
     50   1.4  mycroft int max_prune_lifetime 	= DEFAULT_CACHE_LIFETIME * 2;
     51   1.1   brezak 
     52   1.2   brezak int debug = 0;
     53   1.4  mycroft u_char pruning = 1;	/* Enable pruning by default */
     54   1.4  mycroft 
     55   1.6  mycroft #ifdef SNMP
     56   1.6  mycroft #define NHANDLERS	34
     57   1.6  mycroft #else
     58   1.4  mycroft #define NHANDLERS	2
     59   1.6  mycroft #endif
     60   1.1   brezak 
     61   1.4  mycroft static struct ihandler {
     62   1.4  mycroft     int fd;			/* File descriptor		 */
     63   1.6  mycroft     ihfunc_t func;		/* Function to call with &fd_set */
     64   1.4  mycroft } ihandlers[NHANDLERS];
     65   1.4  mycroft static int nhandlers = 0;
     66   1.1   brezak 
     67   1.1   brezak /*
     68   1.1   brezak  * Forward declarations.
     69   1.1   brezak  */
     70   1.6  mycroft static void fasttimer __P((int));
     71   1.6  mycroft static void done __P((int));
     72   1.6  mycroft static void dump __P((int));
     73   1.6  mycroft static void fdump __P((int));
     74   1.6  mycroft static void cdump __P((int));
     75   1.6  mycroft static void restart __P((int));
     76   1.6  mycroft static void timer __P((void));
     77   1.6  mycroft static void cleanup __P((void));
     78   1.6  mycroft static void resetlogging __P((void *));
     79   1.6  mycroft 
     80   1.6  mycroft /* To shut up gcc -Wstrict-prototypes */
     81   1.6  mycroft int main __P((int argc, char **argv));
     82  1.13       is #ifdef __STDC__
     83  1.13       is void log(int severity, int syserr, const char *format, ...)
     84  1.13       is 	__attribute__((__format__(__printf__, 3, 4)));
     85  1.13       is #endif
     86   1.4  mycroft 
     87   1.4  mycroft int
     88   1.4  mycroft register_input_handler(fd, func)
     89   1.4  mycroft     int fd;
     90   1.6  mycroft     ihfunc_t func;
     91   1.4  mycroft {
     92   1.4  mycroft     if (nhandlers >= NHANDLERS)
     93   1.4  mycroft 	return -1;
     94   1.4  mycroft 
     95   1.4  mycroft     ihandlers[nhandlers].fd = fd;
     96   1.4  mycroft     ihandlers[nhandlers++].func = func;
     97   1.1   brezak 
     98   1.4  mycroft     return 0;
     99   1.4  mycroft }
    100   1.1   brezak 
    101   1.6  mycroft int
    102   1.6  mycroft main(argc, argv)
    103   1.1   brezak     int argc;
    104   1.1   brezak     char *argv[];
    105   1.1   brezak {
    106   1.1   brezak     register int recvlen;
    107   1.1   brezak     register int omask;
    108   1.1   brezak     int dummy;
    109   1.1   brezak     FILE *fp;
    110   1.4  mycroft     struct timeval tv;
    111   1.6  mycroft     u_int32_t prev_genid;
    112   1.4  mycroft     int vers;
    113   1.4  mycroft     fd_set rfds, readers;
    114   1.4  mycroft     int nfds, n, i;
    115   1.4  mycroft #ifdef SNMP
    116   1.6  mycroft     struct timeval  timeout, *tvp = &timeout;
    117   1.6  mycroft     struct timeval  sched, *svp = &sched, now, *nvp = &now;
    118   1.6  mycroft     int index, block;
    119   1.4  mycroft #endif
    120   1.1   brezak 
    121   1.1   brezak     setlinebuf(stderr);
    122   1.1   brezak 
    123   1.1   brezak     if (geteuid() != 0) {
    124   1.4  mycroft 	fprintf(stderr, "must be root\n");
    125   1.1   brezak 	exit(1);
    126   1.1   brezak     }
    127   1.1   brezak 
    128   1.1   brezak     argv++, argc--;
    129   1.1   brezak     while (argc > 0 && *argv[0] == '-') {
    130   1.1   brezak 	if (strcmp(*argv, "-d") == 0) {
    131   1.1   brezak 	    if (argc > 1 && isdigit(*(argv + 1)[0])) {
    132   1.1   brezak 		argv++, argc--;
    133   1.1   brezak 		debug = atoi(*argv);
    134   1.1   brezak 	    } else
    135   1.1   brezak 		debug = DEFAULT_DEBUG;
    136   1.1   brezak 	} else if (strcmp(*argv, "-c") == 0) {
    137   1.1   brezak 	    if (argc > 1) {
    138   1.1   brezak 		argv++, argc--;
    139   1.1   brezak 		configfilename = *argv;
    140   1.1   brezak 	    } else
    141   1.1   brezak 		goto usage;
    142   1.4  mycroft 	} else if (strcmp(*argv, "-p") == 0) {
    143   1.4  mycroft 	    pruning = 0;
    144   1.6  mycroft #ifdef SNMP
    145   1.6  mycroft    } else if (strcmp(*argv, "-P") == 0) {
    146   1.6  mycroft 	    if (argc > 1 && isdigit(*(argv + 1)[0])) {
    147   1.6  mycroft 		argv++, argc--;
    148   1.6  mycroft 		dest_port = atoi(*argv);
    149   1.6  mycroft 	    } else
    150   1.6  mycroft 		dest_port = DEFAULT_PORT;
    151   1.6  mycroft #endif
    152   1.1   brezak 	} else
    153   1.1   brezak 	    goto usage;
    154   1.1   brezak 	argv++, argc--;
    155   1.1   brezak     }
    156   1.1   brezak 
    157   1.1   brezak     if (argc > 0) {
    158   1.4  mycroft usage:	fprintf(stderr,
    159   1.4  mycroft 		"usage: mrouted [-p] [-c configfile] [-d [debug_level]]\n");
    160   1.1   brezak 	exit(1);
    161   1.1   brezak     }
    162   1.1   brezak 
    163   1.1   brezak     if (debug == 0) {
    164   1.1   brezak 	/*
    165   1.1   brezak 	 * Detach from the terminal
    166   1.1   brezak 	 */
    167  1.12  thorpej 	if (daemon(0, 0))
    168  1.12  thorpej 	    err(1, "can't fork");
    169  1.12  thorpej 	pidfile(NULL);
    170   1.1   brezak     }
    171   1.4  mycroft     else
    172   1.4  mycroft 	fprintf(stderr, "debug level %u\n", debug);
    173   1.1   brezak 
    174   1.1   brezak #ifdef LOG_DAEMON
    175   1.1   brezak     (void)openlog("mrouted", LOG_PID, LOG_DAEMON);
    176   1.1   brezak     (void)setlogmask(LOG_UPTO(LOG_NOTICE));
    177   1.1   brezak #else
    178   1.1   brezak     (void)openlog("mrouted", LOG_PID);
    179   1.1   brezak #endif
    180   1.6  mycroft     sprintf(versionstring, "mrouted version %d.%d",
    181   1.1   brezak 			PROTOCOL_VERSION, MROUTED_VERSION);
    182   1.1   brezak 
    183   1.6  mycroft     log(LOG_NOTICE, 0, "%s", versionstring);
    184   1.6  mycroft 
    185   1.4  mycroft #ifdef SYSV
    186   1.4  mycroft     srand48(time(NULL));
    187   1.4  mycroft #else
    188   1.4  mycroft     srandom(gethostid());
    189   1.4  mycroft #endif
    190   1.4  mycroft 
    191   1.4  mycroft     /*
    192   1.4  mycroft      * Get generation id
    193   1.4  mycroft      */
    194   1.4  mycroft     gettimeofday(&tv, 0);
    195   1.4  mycroft     dvmrp_genid = tv.tv_sec;
    196   1.4  mycroft 
    197   1.4  mycroft     fp = fopen(genidfilename, "r");
    198   1.4  mycroft     if (fp != NULL) {
    199   1.4  mycroft 	fscanf(fp, "%d", &prev_genid);
    200   1.4  mycroft 	if (prev_genid == dvmrp_genid)
    201   1.4  mycroft 	    dvmrp_genid++;
    202   1.4  mycroft 	(void) fclose(fp);
    203   1.4  mycroft     }
    204   1.4  mycroft 
    205   1.4  mycroft     fp = fopen(genidfilename, "w");
    206   1.1   brezak     if (fp != NULL) {
    207   1.4  mycroft 	fprintf(fp, "%d", dvmrp_genid);
    208   1.1   brezak 	(void) fclose(fp);
    209   1.1   brezak     }
    210   1.1   brezak 
    211   1.4  mycroft     callout_init();
    212   1.1   brezak     init_igmp();
    213   1.6  mycroft     init_routes();
    214   1.6  mycroft     init_ktable();
    215   1.1   brezak     k_init_dvmrp();		/* enable DVMRP routing in kernel */
    216   1.4  mycroft 
    217   1.4  mycroft #ifndef OLD_KERNEL
    218   1.4  mycroft     vers = k_get_version();
    219   1.6  mycroft     /*XXX
    220   1.6  mycroft      * This function must change whenever the kernel version changes
    221   1.6  mycroft      */
    222   1.6  mycroft     if ((((vers >> 8) & 0xff) != 3) ||
    223   1.6  mycroft 	 ((vers & 0xff) != 5))
    224   1.4  mycroft 	log(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
    225   1.4  mycroft 		(vers >> 8) & 0xff, vers & 0xff,
    226   1.4  mycroft 		PROTOCOL_VERSION, MROUTED_VERSION);
    227   1.4  mycroft #endif
    228   1.4  mycroft 
    229   1.6  mycroft #ifdef SNMP
    230   1.6  mycroft     if (i = snmp_init())
    231   1.6  mycroft        return i;
    232   1.6  mycroft 
    233   1.6  mycroft     gettimeofday(nvp, 0);
    234   1.6  mycroft     if (nvp->tv_usec < 500000L){
    235   1.6  mycroft    svp->tv_usec = nvp->tv_usec + 500000L;
    236   1.6  mycroft    svp->tv_sec = nvp->tv_sec;
    237   1.6  mycroft     } else {
    238   1.6  mycroft    svp->tv_usec = nvp->tv_usec - 500000L;
    239   1.6  mycroft    svp->tv_sec = nvp->tv_sec + 1;
    240   1.6  mycroft     }
    241   1.6  mycroft #endif /* SNMP */
    242   1.6  mycroft 
    243   1.1   brezak     init_vifs();
    244   1.6  mycroft 
    245   1.4  mycroft #ifdef RSRR
    246   1.4  mycroft     rsrr_init();
    247   1.4  mycroft #endif /* RSRR */
    248   1.4  mycroft 
    249   1.4  mycroft #if defined(__STDC__) || defined(__GNUC__)
    250   1.6  mycroft     /*
    251   1.6  mycroft      * Allow cleanup if unexpected exit.  Apparently some architectures
    252   1.4  mycroft      * have a kernel bug where closing the socket doesn't do an
    253   1.4  mycroft      * ip_mrouter_done(), so we attempt to do it on exit.
    254   1.4  mycroft      */
    255   1.4  mycroft     atexit(cleanup);
    256   1.4  mycroft #endif
    257   1.4  mycroft 
    258   1.4  mycroft     if (debug)
    259   1.4  mycroft 	fprintf(stderr, "pruning %s\n", pruning ? "on" : "off");
    260   1.1   brezak 
    261   1.2   brezak     (void)signal(SIGALRM, fasttimer);
    262   1.4  mycroft 
    263   1.4  mycroft     (void)signal(SIGHUP,  restart);
    264   1.4  mycroft     (void)signal(SIGTERM, done);
    265   1.4  mycroft     (void)signal(SIGINT,  done);
    266   1.1   brezak     (void)signal(SIGUSR1, fdump);
    267   1.4  mycroft     (void)signal(SIGUSR2, cdump);
    268   1.1   brezak     if (debug != 0)
    269   1.1   brezak 	(void)signal(SIGQUIT, dump);
    270   1.1   brezak 
    271   1.4  mycroft     FD_ZERO(&readers);
    272   1.4  mycroft     FD_SET(igmp_socket, &readers);
    273   1.4  mycroft     nfds = igmp_socket + 1;
    274   1.4  mycroft     for (i = 0; i < nhandlers; i++) {
    275   1.4  mycroft 	FD_SET(ihandlers[i].fd, &readers);
    276   1.4  mycroft 	if (ihandlers[i].fd >= nfds)
    277   1.4  mycroft 	    nfds = ihandlers[i].fd + 1;
    278   1.4  mycroft     }
    279   1.4  mycroft 
    280   1.6  mycroft     /*
    281   1.6  mycroft      * Install the vifs in the kernel as late as possible in the
    282   1.6  mycroft      * initialization sequence.
    283   1.6  mycroft      */
    284   1.6  mycroft     init_installvifs();
    285   1.6  mycroft 
    286   1.6  mycroft     if (debug >= 2) dump(0);
    287   1.6  mycroft 
    288   1.6  mycroft     /* Start up the log rate-limiter */
    289   1.6  mycroft     resetlogging(NULL);
    290   1.6  mycroft 
    291   1.2   brezak     (void)alarm(1);	 /* schedule first timer interrupt */
    292   1.1   brezak 
    293   1.1   brezak     /*
    294   1.1   brezak      * Main receive loop.
    295   1.1   brezak      */
    296   1.1   brezak     dummy = 0;
    297   1.1   brezak     for(;;) {
    298   1.6  mycroft #ifdef SYSV
    299   1.6  mycroft 	sigset_t block, oblock;
    300   1.6  mycroft #endif
    301   1.4  mycroft 	bcopy((char *)&readers, (char *)&rfds, sizeof(rfds));
    302   1.4  mycroft #ifdef SNMP
    303   1.6  mycroft    gettimeofday(nvp, 0);
    304   1.6  mycroft    if (nvp->tv_sec > svp->tv_sec
    305   1.6  mycroft        || (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){
    306   1.6  mycroft        alarmTimer(nvp);
    307   1.6  mycroft        eventTimer(nvp);
    308   1.6  mycroft        if (nvp->tv_usec < 500000L){
    309   1.6  mycroft       svp->tv_usec = nvp->tv_usec + 500000L;
    310   1.6  mycroft       svp->tv_sec = nvp->tv_sec;
    311   1.6  mycroft        } else {
    312   1.6  mycroft       svp->tv_usec = nvp->tv_usec - 500000L;
    313   1.6  mycroft       svp->tv_sec = nvp->tv_sec + 1;
    314   1.6  mycroft        }
    315   1.6  mycroft    }
    316   1.6  mycroft 
    317   1.6  mycroft 	tvp =  &timeout;
    318   1.6  mycroft 	tvp->tv_sec = 0;
    319   1.6  mycroft 	tvp->tv_usec = 500000L;
    320   1.6  mycroft 
    321   1.6  mycroft 	block = 0;
    322   1.6  mycroft 	snmp_select_info(&nfds, &rfds, tvp, &block);
    323   1.6  mycroft 	if (block == 1)
    324   1.6  mycroft 		tvp = NULL; /* block without timeout */
    325   1.6  mycroft 	if ((n = select(nfds, &rfds, NULL, NULL, tvp)) < 0)
    326   1.4  mycroft #else
    327   1.6  mycroft 	if ((n = select(nfds, &rfds, NULL, NULL, NULL)) < 0)
    328   1.4  mycroft #endif
    329   1.6  mycroft    {
    330   1.4  mycroft             if (errno != EINTR) /* SIGALRM is expected */
    331   1.4  mycroft                 log(LOG_WARNING, errno, "select failed");
    332   1.4  mycroft             continue;
    333   1.4  mycroft         }
    334   1.4  mycroft 
    335   1.4  mycroft 	if (FD_ISSET(igmp_socket, &rfds)) {
    336   1.4  mycroft 	    recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE,
    337   1.4  mycroft 			       0, NULL, &dummy);
    338   1.4  mycroft 	    if (recvlen < 0) {
    339   1.4  mycroft 		if (errno != EINTR) log(LOG_ERR, errno, "recvfrom");
    340   1.4  mycroft 		continue;
    341   1.4  mycroft 	    }
    342   1.6  mycroft #ifdef SYSV
    343   1.6  mycroft 	    (void)sigemptyset(&block);
    344   1.6  mycroft 	    (void)sigaddset(&block, SIGALRM);
    345   1.6  mycroft 	    if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
    346   1.6  mycroft 		    log(LOG_ERR, errno, "sigprocmask");
    347   1.6  mycroft #else
    348   1.4  mycroft 	    omask = sigblock(sigmask(SIGALRM));
    349   1.6  mycroft #endif
    350   1.4  mycroft 	    accept_igmp(recvlen);
    351   1.6  mycroft #ifdef SYSV
    352   1.6  mycroft 	    (void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
    353   1.6  mycroft #else
    354   1.4  mycroft 	    (void)sigsetmask(omask);
    355   1.6  mycroft #endif
    356   1.4  mycroft         }
    357   1.4  mycroft 
    358   1.4  mycroft 	for (i = 0; i < nhandlers; i++) {
    359   1.4  mycroft 	    if (FD_ISSET(ihandlers[i].fd, &rfds)) {
    360   1.6  mycroft 		(*ihandlers[i].func)(ihandlers[i].fd, &rfds);
    361   1.4  mycroft 	    }
    362   1.1   brezak 	}
    363   1.4  mycroft 
    364   1.4  mycroft #ifdef SNMP
    365   1.6  mycroft 	snmp_read(&rfds);
    366   1.6  mycroft 	snmp_timeout(); /* poll */
    367   1.4  mycroft #endif
    368   1.1   brezak     }
    369   1.1   brezak }
    370   1.1   brezak 
    371   1.1   brezak 
    372   1.1   brezak /*
    373   1.4  mycroft  * routine invoked every second.  Its main goal is to cycle through
    374   1.2   brezak  * the routing table and send partial updates to all neighbors at a
    375   1.2   brezak  * rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL
    376   1.2   brezak  * seconds.  Also, every TIMER_INTERVAL seconds it calls timer() to
    377   1.2   brezak  * do all the other time-based processing.
    378   1.2   brezak  */
    379   1.4  mycroft static void
    380   1.6  mycroft fasttimer(i)
    381   1.6  mycroft     int i;
    382   1.2   brezak {
    383   1.2   brezak     static unsigned int tlast;
    384   1.2   brezak     static unsigned int nsent;
    385   1.2   brezak     register unsigned int t = tlast + 1;
    386   1.2   brezak     register int n;
    387   1.2   brezak 
    388   1.2   brezak     /*
    389   1.2   brezak      * if we're in the last second, send everything that's left.
    390   1.2   brezak      * otherwise send at least the fraction we should have sent by now.
    391   1.2   brezak      */
    392   1.2   brezak     if (t >= ROUTE_REPORT_INTERVAL) {
    393   1.2   brezak 	register int nleft = nroutes - nsent;
    394   1.2   brezak 	while (nleft > 0) {
    395   1.2   brezak 	    if ((n = report_next_chunk()) <= 0)
    396   1.2   brezak 		break;
    397   1.2   brezak 	    nleft -= n;
    398   1.2   brezak 	}
    399   1.2   brezak 	tlast = 0;
    400   1.2   brezak 	nsent = 0;
    401   1.2   brezak     } else {
    402   1.2   brezak 	register unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL;
    403   1.2   brezak 	while (nsent < ncum) {
    404   1.2   brezak 	    if ((n = report_next_chunk()) <= 0)
    405   1.2   brezak 		break;
    406   1.2   brezak 	    nsent += n;
    407   1.2   brezak 	}
    408   1.2   brezak 	tlast = t;
    409   1.2   brezak     }
    410   1.2   brezak     if ((t % TIMER_INTERVAL) == 0)
    411   1.2   brezak 	timer();
    412   1.2   brezak 
    413   1.4  mycroft     age_callout_queue();/* Advance the timer for the callout queue
    414   1.4  mycroft 				for groups */
    415   1.2   brezak     alarm(1);
    416   1.2   brezak }
    417   1.2   brezak 
    418   1.2   brezak /*
    419   1.1   brezak  * The 'virtual_time' variable is initialized to a value that will cause the
    420   1.1   brezak  * first invocation of timer() to send a probe or route report to all vifs
    421   1.1   brezak  * and send group membership queries to all subnets for which this router is
    422   1.1   brezak  * querier.  This first invocation occurs approximately TIMER_INTERVAL seconds
    423   1.1   brezak  * after the router starts up.   Note that probes for neighbors and queries
    424   1.1   brezak  * for group memberships are also sent at start-up time, as part of initial-
    425   1.1   brezak  * ization.  This repetition after a short interval is desirable for quickly
    426   1.1   brezak  * building up topology and membership information in the presence of possible
    427   1.1   brezak  * packet loss.
    428   1.1   brezak  *
    429   1.1   brezak  * 'virtual_time' advances at a rate that is only a crude approximation of
    430   1.1   brezak  * real time, because it does not take into account any time spent processing,
    431   1.1   brezak  * and because the timer intervals are sometimes shrunk by a random amount to
    432   1.1   brezak  * avoid unwanted synchronization with other routers.
    433   1.1   brezak  */
    434   1.1   brezak 
    435   1.1   brezak static u_long virtual_time = 0;
    436   1.1   brezak 
    437   1.1   brezak 
    438   1.1   brezak /*
    439   1.1   brezak  * Timer routine.  Performs periodic neighbor probing, route reporting, and
    440   1.1   brezak  * group querying duties, and drives various timers in routing entries and
    441   1.1   brezak  * virtual interface data structures.
    442   1.1   brezak  */
    443   1.4  mycroft static void
    444   1.4  mycroft timer()
    445   1.1   brezak {
    446   1.1   brezak     age_routes();	/* Advance the timers in the route entries     */
    447   1.4  mycroft     age_vifs();		/* Advance the timers for neighbors */
    448   1.4  mycroft     age_table_entry();	/* Advance the timers for the cache entries */
    449   1.1   brezak 
    450   1.1   brezak     if (virtual_time % GROUP_QUERY_INTERVAL == 0) {
    451   1.1   brezak 	/*
    452   1.1   brezak 	 * Time to query the local group memberships on all subnets
    453   1.1   brezak 	 * for which this router is the elected querier.
    454   1.1   brezak 	 */
    455   1.1   brezak 	query_groups();
    456   1.1   brezak     }
    457   1.1   brezak 
    458   1.1   brezak     if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) {
    459   1.1   brezak 	/*
    460   1.1   brezak 	 * Time to send a probe on all vifs from which no neighbors have
    461   1.1   brezak 	 * been heard.  Also, check if any inoperative interfaces have now
    462   1.1   brezak 	 * come up.  (If they have, they will also be probed as part of
    463   1.1   brezak 	 * their initialization.)
    464   1.1   brezak 	 */
    465   1.1   brezak 	probe_for_neighbors();
    466   1.1   brezak 
    467   1.1   brezak 	if (vifs_down)
    468   1.1   brezak 	    check_vif_state();
    469   1.1   brezak     }
    470   1.1   brezak 
    471   1.1   brezak     delay_change_reports = FALSE;
    472   1.2   brezak     if (routes_changed) {
    473   1.1   brezak 	/*
    474   1.1   brezak 	 * Some routes have changed since the last timer interrupt, but
    475   1.1   brezak 	 * have not been reported yet.  Report the changed routes to all
    476   1.1   brezak 	 * neighbors.
    477   1.1   brezak 	 */
    478   1.1   brezak 	report_to_all_neighbors(CHANGED_ROUTES);
    479   1.1   brezak     }
    480   1.1   brezak 
    481   1.4  mycroft #ifdef SNMP
    482   1.6  mycroft     sync_timer();
    483   1.4  mycroft #endif
    484   1.4  mycroft 
    485   1.1   brezak     /*
    486   1.2   brezak      * Advance virtual time
    487   1.1   brezak      */
    488   1.1   brezak     virtual_time += TIMER_INTERVAL;
    489   1.1   brezak }
    490   1.1   brezak 
    491   1.1   brezak 
    492   1.1   brezak /*
    493   1.4  mycroft  * On termination, let everyone know we're going away.
    494   1.1   brezak  */
    495   1.4  mycroft static void
    496   1.6  mycroft done(i)
    497   1.6  mycroft     int i;
    498   1.1   brezak {
    499   1.6  mycroft     log(LOG_NOTICE, 0, "%s exiting", versionstring);
    500   1.4  mycroft     cleanup();
    501   1.4  mycroft     _exit(1);
    502   1.4  mycroft }
    503   1.4  mycroft 
    504   1.4  mycroft static void
    505   1.4  mycroft cleanup()
    506   1.4  mycroft {
    507  1.10      mrg     static int in_cleanup = 0;
    508   1.4  mycroft 
    509   1.4  mycroft     if (!in_cleanup) {
    510   1.4  mycroft 	in_cleanup++;
    511   1.4  mycroft #ifdef RSRR
    512   1.4  mycroft 	rsrr_clean();
    513   1.4  mycroft #endif /* RSRR */
    514   1.4  mycroft 	expire_all_routes();
    515   1.4  mycroft 	report_to_all_neighbors(ALL_ROUTES);
    516   1.4  mycroft 	k_stop_dvmrp();
    517   1.4  mycroft     }
    518   1.1   brezak }
    519   1.1   brezak 
    520   1.1   brezak 
    521   1.1   brezak /*
    522   1.1   brezak  * Dump internal data structures to stderr.
    523   1.1   brezak  */
    524   1.4  mycroft static void
    525   1.6  mycroft dump(i)
    526   1.6  mycroft     int i;
    527   1.1   brezak {
    528   1.1   brezak     dump_vifs(stderr);
    529   1.1   brezak     dump_routes(stderr);
    530   1.1   brezak }
    531   1.1   brezak 
    532   1.1   brezak 
    533   1.1   brezak /*
    534   1.1   brezak  * Dump internal data structures to a file.
    535   1.1   brezak  */
    536   1.4  mycroft static void
    537   1.6  mycroft fdump(i)
    538   1.6  mycroft     int i;
    539   1.1   brezak {
    540   1.1   brezak     FILE *fp;
    541   1.1   brezak 
    542   1.1   brezak     fp = fopen(dumpfilename, "w");
    543   1.1   brezak     if (fp != NULL) {
    544   1.1   brezak 	dump_vifs(fp);
    545   1.1   brezak 	dump_routes(fp);
    546   1.1   brezak 	(void) fclose(fp);
    547   1.1   brezak     }
    548   1.1   brezak }
    549   1.1   brezak 
    550   1.1   brezak 
    551   1.1   brezak /*
    552   1.4  mycroft  * Dump local cache contents to a file.
    553   1.4  mycroft  */
    554   1.4  mycroft static void
    555   1.6  mycroft cdump(i)
    556   1.6  mycroft     int i;
    557   1.4  mycroft {
    558   1.4  mycroft     FILE *fp;
    559   1.4  mycroft 
    560   1.4  mycroft     fp = fopen(cachefilename, "w");
    561   1.4  mycroft     if (fp != NULL) {
    562   1.4  mycroft 	dump_cache(fp);
    563   1.4  mycroft 	(void) fclose(fp);
    564   1.4  mycroft     }
    565   1.4  mycroft }
    566   1.4  mycroft 
    567   1.4  mycroft 
    568   1.4  mycroft /*
    569   1.4  mycroft  * Restart mrouted
    570   1.4  mycroft  */
    571   1.4  mycroft static void
    572   1.6  mycroft restart(i)
    573   1.6  mycroft     int i;
    574   1.4  mycroft {
    575   1.4  mycroft     register int omask;
    576   1.6  mycroft #ifdef SYSV
    577   1.6  mycroft     sigset_t block, oblock;
    578   1.6  mycroft #endif
    579   1.4  mycroft 
    580   1.6  mycroft     log(LOG_NOTICE, 0, "%s restart", versionstring);
    581   1.4  mycroft 
    582   1.4  mycroft     /*
    583   1.4  mycroft      * reset all the entries
    584   1.4  mycroft      */
    585   1.6  mycroft #ifdef SYSV
    586   1.6  mycroft     (void)sigemptyset(&block);
    587   1.6  mycroft     (void)sigaddset(&block, SIGALRM);
    588   1.6  mycroft     if (sigprocmask(SIG_BLOCK, &block, &oblock) < 0)
    589   1.6  mycroft 	log(LOG_ERR, errno, "sigprocmask");
    590   1.6  mycroft #else
    591   1.4  mycroft     omask = sigblock(sigmask(SIGALRM));
    592   1.6  mycroft #endif
    593   1.4  mycroft     free_all_prunes();
    594   1.4  mycroft     free_all_routes();
    595   1.4  mycroft     stop_all_vifs();
    596   1.4  mycroft     k_stop_dvmrp();
    597   1.4  mycroft     close(igmp_socket);
    598   1.4  mycroft     close(udp_socket);
    599   1.4  mycroft 
    600   1.4  mycroft     /*
    601   1.4  mycroft      * start processing again
    602   1.4  mycroft      */
    603   1.4  mycroft     dvmrp_genid++;
    604   1.4  mycroft     pruning = 1;
    605   1.4  mycroft 
    606   1.4  mycroft     init_igmp();
    607   1.4  mycroft     init_routes();
    608   1.4  mycroft     init_ktable();
    609   1.4  mycroft     init_vifs();
    610   1.6  mycroft     k_init_dvmrp();		/* enable DVMRP routing in kernel */
    611   1.6  mycroft     init_installvifs();
    612   1.4  mycroft 
    613   1.6  mycroft #ifdef SYSV
    614   1.6  mycroft     (void)sigprocmask(SIG_SETMASK, &oblock, (sigset_t *)NULL);
    615   1.6  mycroft #else
    616   1.4  mycroft     (void)sigsetmask(omask);
    617   1.6  mycroft #endif
    618   1.4  mycroft }
    619   1.4  mycroft 
    620   1.6  mycroft #define LOG_MAX_MSGS	20	/* if > 20/minute then shut up for a while */
    621   1.6  mycroft #define LOG_SHUT_UP	600	/* shut up for 10 minutes */
    622   1.6  mycroft static int log_nmsgs = 0;
    623   1.6  mycroft 
    624   1.6  mycroft static void
    625   1.6  mycroft resetlogging(arg)
    626   1.6  mycroft     void *arg;
    627   1.6  mycroft {
    628   1.6  mycroft     int nxttime = 60;
    629   1.6  mycroft     void *narg = NULL;
    630   1.6  mycroft 
    631   1.6  mycroft     if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) {
    632   1.6  mycroft 	nxttime = LOG_SHUT_UP;
    633   1.6  mycroft 	narg = (void *)&log_nmsgs;	/* just need some valid void * */
    634   1.6  mycroft 	syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes",
    635   1.6  mycroft 			LOG_SHUT_UP / 60);
    636   1.6  mycroft     } else {
    637   1.6  mycroft 	log_nmsgs = 0;
    638   1.6  mycroft     }
    639   1.6  mycroft 
    640   1.6  mycroft     timer_setTimer(nxttime, resetlogging, narg);
    641   1.6  mycroft }
    642   1.4  mycroft 
    643   1.4  mycroft /*
    644   1.1   brezak  * Log errors and other messages to the system log daemon and to stderr,
    645   1.1   brezak  * according to the severity of the message and the current debug level.
    646   1.1   brezak  * For errors of severity LOG_ERR or worse, terminate the program.
    647   1.1   brezak  */
    648   1.6  mycroft #ifdef __STDC__
    649   1.6  mycroft void
    650  1.13       is log(int severity, int syserr, const char *format, ...)
    651   1.6  mycroft {
    652   1.6  mycroft     va_list ap;
    653   1.6  mycroft     static char fmt[211] = "warning - ";
    654   1.6  mycroft     char *msg;
    655   1.6  mycroft     char tbuf[20];
    656   1.6  mycroft     struct timeval now;
    657   1.6  mycroft     struct tm *thyme;
    658   1.8      cgd     time_t t;
    659   1.6  mycroft 
    660   1.6  mycroft     va_start(ap, format);
    661   1.6  mycroft #else
    662   1.4  mycroft /*VARARGS3*/
    663   1.4  mycroft void
    664   1.4  mycroft log(severity, syserr, format, va_alist)
    665   1.1   brezak     int severity, syserr;
    666   1.1   brezak     char *format;
    667   1.4  mycroft     va_dcl
    668   1.1   brezak {
    669   1.4  mycroft     va_list ap;
    670   1.4  mycroft     static char fmt[211] = "warning - ";
    671   1.4  mycroft     char *msg;
    672   1.4  mycroft     char tbuf[20];
    673   1.4  mycroft     struct timeval now;
    674   1.4  mycroft     struct tm *thyme;
    675   1.8      cgd     time_t t;
    676   1.4  mycroft 
    677   1.4  mycroft     va_start(ap);
    678   1.6  mycroft #endif
    679   1.4  mycroft     vsprintf(&fmt[10], format, ap);
    680   1.4  mycroft     va_end(ap);
    681   1.4  mycroft     msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
    682   1.1   brezak 
    683   1.1   brezak     switch (debug) {
    684   1.1   brezak 	case 0: break;
    685   1.1   brezak 	case 1: if (severity > LOG_NOTICE) break;
    686   1.1   brezak 	case 2: if (severity > LOG_INFO  ) break;
    687   1.1   brezak 	default:
    688   1.4  mycroft 	    gettimeofday(&now,NULL);
    689   1.8      cgd 	    t = now.tv_sec;
    690   1.8      cgd 	    thyme = localtime(&t);
    691  1.13       is 	    strftime(tbuf, sizeof(tbuf), "%X", thyme);
    692  1.13       is 	    fprintf(stderr, "%s.%03ld %s", tbuf, (long)now.tv_usec / 1000,
    693  1.13       is 		msg);
    694   1.1   brezak 	    if (syserr == 0)
    695   1.1   brezak 		fprintf(stderr, "\n");
    696   1.1   brezak 	    else
    697  1.11   kleink 		fprintf(stderr, ": %s\n", strerror(syserr));
    698   1.1   brezak     }
    699   1.1   brezak 
    700   1.1   brezak     if (severity <= LOG_NOTICE) {
    701   1.6  mycroft 	if (log_nmsgs++ < LOG_MAX_MSGS) {
    702   1.6  mycroft 	    if (syserr != 0) {
    703   1.6  mycroft 		errno = syserr;
    704   1.6  mycroft 		syslog(severity, "%s: %m", msg);
    705   1.6  mycroft 	    } else
    706   1.6  mycroft 		syslog(severity, "%s", msg);
    707   1.6  mycroft 	}
    708   1.1   brezak 
    709  1.14      wiz 	if (severity <= LOG_ERR) exit(1);
    710   1.1   brezak     }
    711   1.1   brezak }
    712   1.6  mycroft 
    713   1.6  mycroft #ifdef DEBUG_MFC
    714   1.6  mycroft void
    715   1.6  mycroft md_log(what, origin, mcastgrp)
    716   1.6  mycroft     int what;
    717   1.6  mycroft     u_int32_t origin, mcastgrp;
    718   1.6  mycroft {
    719   1.6  mycroft     static FILE *f = NULL;
    720   1.6  mycroft     struct timeval tv;
    721   1.6  mycroft     u_int32_t buf[4];
    722   1.6  mycroft 
    723   1.6  mycroft     if (!f) {
    724   1.6  mycroft 	if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) {
    725   1.6  mycroft 	    log(LOG_ERR, errno, "open /tmp/mrouted.clog");
    726   1.6  mycroft 	}
    727   1.6  mycroft     }
    728   1.6  mycroft 
    729   1.6  mycroft     gettimeofday(&tv, NULL);
    730   1.6  mycroft     buf[0] = tv.tv_sec;
    731   1.6  mycroft     buf[1] = what;
    732   1.6  mycroft     buf[2] = origin;
    733   1.6  mycroft     buf[3] = mcastgrp;
    734   1.6  mycroft 
    735   1.6  mycroft     fwrite(buf, sizeof(u_int32_t), 4, f);
    736   1.6  mycroft }
    737   1.6  mycroft #endif
    738