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