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