788 lines
19 KiB
C
788 lines
19 KiB
C
/* $NetBSD: main.c,v 1.5 2000/12/04 07:09:36 itojun Exp $ */
|
|
/* $KAME: main.c,v 1.14 2000/12/04 07:01:08 itojun Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 1998 by the University of Southern California.
|
|
* All rights reserved.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and
|
|
* its documentation in source and binary forms for lawful
|
|
* purposes and without fee is hereby granted, provided
|
|
* that the above copyright notice appear in all copies and that both
|
|
* the copyright notice and this permission notice appear in supporting
|
|
* documentation, and that any documentation, advertising materials,
|
|
* and other materials related to such distribution and use acknowledge
|
|
* that the software was developed by the University of Southern
|
|
* California and/or Information Sciences Institute.
|
|
* The name of the University of Southern California may not
|
|
* be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
|
|
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
|
|
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
|
|
* NON-INFRINGEMENT.
|
|
*
|
|
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
|
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
|
|
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
|
|
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* Other copyrights might apply to parts of this software and are so
|
|
* noted when applicable.
|
|
*/
|
|
/*
|
|
* Questions concerning this software should be directed to
|
|
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
|
|
*
|
|
*/
|
|
/*
|
|
* This program has been derived from pim6dd.
|
|
* The pim6dd program is covered by the license in the accompanying file
|
|
* named "LICENSE.pim6dd".
|
|
*/
|
|
/*
|
|
* This program has been derived from pimd.
|
|
* The pimd program is covered by the license in the accompanying file
|
|
* named "LICENSE.pimd".
|
|
*
|
|
*/
|
|
/*
|
|
* Part of this program has been derived from mrouted.
|
|
* The mrouted program is covered by the license in the accompanying file
|
|
* named "LICENSE.mrouted".
|
|
*
|
|
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
|
|
* Leland Stanford Junior University.
|
|
*
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <net/route.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip_mroute.h>
|
|
#include <netinet6/ip6_mroute.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include "pathnames.h"
|
|
#include "defs.h"
|
|
#include "debug.h"
|
|
#include "mld6.h"
|
|
#include "pim6.h"
|
|
#include "vif.h"
|
|
#include "routesock.h"
|
|
#include "callout.h"
|
|
#include "mrt.h"
|
|
#include "timer.h"
|
|
#include "rp.h"
|
|
#include "kern.h"
|
|
#include "cfparse.h"
|
|
#include "pim6_proto.h"
|
|
|
|
char configfilename[256] = _PATH_PIM6D_CONF;
|
|
char versionstring[100];
|
|
char logfilename[256] = _PATH_PIM6D_LOGFILE;
|
|
|
|
/* TODO: not used
|
|
static char genidfilename[] = _PATH_PIM6D_GENID;
|
|
*/
|
|
static char pidfilename[] = _PATH_PIM6D_PID;
|
|
|
|
FILE *log_fp = stderr;
|
|
char *progname;
|
|
|
|
static int foreground = 0;
|
|
static int sighandled = 0;
|
|
|
|
#define GOT_SIGINT 0x01
|
|
#define GOT_SIGHUP 0x02
|
|
#define GOT_SIGUSR1 0x04
|
|
#define GOT_SIGUSR2 0x08
|
|
#define GOT_SIGALRM 0x10
|
|
#define GOT_SIGINFO 0x20
|
|
|
|
|
|
#define NHANDLERS 3
|
|
|
|
static struct ihandler
|
|
{
|
|
int fd; /* File descriptor */
|
|
ihfunc_t func; /* Function to call with &fd_set */
|
|
} ihandlers[NHANDLERS];
|
|
|
|
static int nhandlers = 0;
|
|
|
|
static struct debugname
|
|
{
|
|
char *name;
|
|
int level;
|
|
int nchars;
|
|
} debugnames[] = {
|
|
{ "mld_proto", DEBUG_MLD_PROTO, 5 },
|
|
{ "mld_timer", DEBUG_MLD_TIMER, 5 },
|
|
{ "mld_member", DEBUG_MLD_MEMBER, 5 },
|
|
{ "mld", DEBUG_MLD, 3 },
|
|
{ "switch", DEBUG_SWITCH, 2 },
|
|
{ "trace", DEBUG_TRACE, 2 },
|
|
{ "mtrace", DEBUG_TRACE, 2 },
|
|
{ "traceroute", DEBUG_TRACE, 2 },
|
|
{ "timeout", DEBUG_TIMEOUT, 2 },
|
|
{ "callout", DEBUG_TIMEOUT, 3 },
|
|
{ "pkt", DEBUG_PKT, 2 },
|
|
{ "packets", DEBUG_PKT, 2 },
|
|
{ "interfaces", DEBUG_IF, 2 },
|
|
{ "vif", DEBUG_IF, 1 },
|
|
{ "kernel", DEBUG_KERN, 2 },
|
|
{ "cache", DEBUG_MFC, 1 },
|
|
{ "mfc", DEBUG_MFC, 2 },
|
|
{ "k_cache", DEBUG_MFC, 2 },
|
|
{ "k_mfc", DEBUG_MFC, 2 },
|
|
{ "rsrr", DEBUG_RSRR, 2 },
|
|
{ "pim_detail", DEBUG_PIM_DETAIL, 5 },
|
|
{ "pim_hello", DEBUG_PIM_HELLO, 5 },
|
|
{ "pim_neighbors", DEBUG_PIM_HELLO, 5 },
|
|
{ "pim_register", DEBUG_PIM_REGISTER, 5 },
|
|
{ "registers", DEBUG_PIM_REGISTER, 2 },
|
|
{ "pim_join_prune", DEBUG_PIM_JOIN_PRUNE, 5 },
|
|
{ "pim_j_p", DEBUG_PIM_JOIN_PRUNE, 5 },
|
|
{ "pim_jp", DEBUG_PIM_JOIN_PRUNE, 5 },
|
|
{ "pim_bootstrap", DEBUG_PIM_BOOTSTRAP, 5 },
|
|
{ "pim_bsr", DEBUG_PIM_BOOTSTRAP, 5 },
|
|
{ "bsr", DEBUG_PIM_BOOTSTRAP, 1 },
|
|
{ "bootstrap", DEBUG_PIM_BOOTSTRAP, 1 },
|
|
{ "pim_asserts", DEBUG_PIM_ASSERT, 5 },
|
|
{ "pim_cand_rp", DEBUG_PIM_CAND_RP, 5 },
|
|
{ "pim_c_rp", DEBUG_PIM_CAND_RP, 5 },
|
|
{ "pim_rp", DEBUG_PIM_CAND_RP, 6 },
|
|
{ "rp", DEBUG_PIM_CAND_RP, 2 },
|
|
{ "pim_routes", DEBUG_PIM_MRT, 6 },
|
|
{ "pim_routing", DEBUG_PIM_MRT, 6 },
|
|
{ "pim_mrt", DEBUG_PIM_MRT, 5 },
|
|
{ "pim_timers", DEBUG_PIM_TIMER, 5 },
|
|
{ "pim_rpf", DEBUG_PIM_RPF, 6 },
|
|
{ "rpf", DEBUG_RPF, 3 },
|
|
{ "pim", DEBUG_PIM, 1 },
|
|
{ "routes", DEBUG_MRT, 1 },
|
|
{ "routing", DEBUG_MRT, 1 },
|
|
{ "mrt", DEBUG_MRT, 1 },
|
|
{ "routers", DEBUG_NEIGHBORS, 6 },
|
|
{ "mrouters", DEBUG_NEIGHBORS, 7 },
|
|
{ "neighbors", DEBUG_NEIGHBORS, 1 },
|
|
{ "timers", DEBUG_TIMER, 1 },
|
|
{ "asserts", DEBUG_ASSERT, 1 },
|
|
{ "all", DEBUG_ALL, 2 },
|
|
{ "3", 0xffffffff, 1 } /* compat. */
|
|
};
|
|
|
|
|
|
/*
|
|
* Forward declarations.
|
|
*/
|
|
|
|
static void handler __P((int));
|
|
static void timer __P((void *));
|
|
static void cleanup __P((void));
|
|
static void restart __P((int));
|
|
static void cleanup __P((void));
|
|
|
|
|
|
/* To shut up gcc -Wstrict-prototypes */
|
|
|
|
int main __P((int argc, char **argv));
|
|
|
|
int
|
|
register_input_handler(fd, func)
|
|
int fd;
|
|
ihfunc_t func;
|
|
{
|
|
if (nhandlers >= NHANDLERS)
|
|
return -1;
|
|
|
|
ihandlers[nhandlers].fd = fd;
|
|
ihandlers[nhandlers++].func = func;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int dummy,
|
|
dummysigalrm;
|
|
FILE *fp;
|
|
struct timeval tv,
|
|
difftime,
|
|
curtime,
|
|
lasttime,
|
|
*timeout;
|
|
fd_set rfds,
|
|
readers;
|
|
int nfds=0,
|
|
n,
|
|
i,
|
|
secs;
|
|
extern char todaysversion[];
|
|
struct sigaction sa;
|
|
struct debugname *d;
|
|
char c;
|
|
int tmpd;
|
|
|
|
setlinebuf(stderr);
|
|
|
|
if (geteuid() != 0)
|
|
{
|
|
fprintf(stderr, "pim6sd: must be root\n");
|
|
exit(1);
|
|
}
|
|
|
|
progname = strrchr(argv[0], '/');
|
|
if (progname)
|
|
progname++;
|
|
else
|
|
progname = argv[0];
|
|
|
|
argv++;
|
|
argc--;
|
|
while (argc > 0 && *argv[0] == '-')
|
|
{
|
|
if (strcmp(*argv, "-d") == 0)
|
|
{
|
|
if (argc > 1 && *(argv + 1)[0] != '-')
|
|
{
|
|
char *p,
|
|
*q;
|
|
int i,
|
|
len;
|
|
struct debugname *d;
|
|
int no=0;
|
|
|
|
argv++;
|
|
argc--;
|
|
debug = 0;
|
|
p = *argv;
|
|
q = NULL;
|
|
while (p)
|
|
{
|
|
q = strchr(p, ',');
|
|
if (q)
|
|
*q++ = '\0';
|
|
if(p[0]=='-')
|
|
{
|
|
no=1;
|
|
p++;
|
|
}
|
|
len = strlen(p);
|
|
for (i = 0, d = debugnames;
|
|
i < sizeof(debugnames) / sizeof(debugnames[0]);
|
|
i++, d++)
|
|
if (len >= d->nchars && strncmp(d->name, p, len) == 0)
|
|
break;
|
|
if (i == sizeof(debugnames) / sizeof(debugnames[0]))
|
|
{
|
|
int j = 0xffffffff;
|
|
int k = 0;
|
|
fprintf(stderr, "Valid debug levels: ");
|
|
for (i = 0, d = debugnames;
|
|
i < sizeof(debugnames) / sizeof(debugnames[0]);
|
|
i++, d++)
|
|
{
|
|
if ((j & d->level) == d->level)
|
|
{
|
|
if (k++)
|
|
putc(',', stderr);
|
|
fputs(d->name, stderr);
|
|
j &= ~d->level;
|
|
}
|
|
}
|
|
putc('\n', stderr);
|
|
goto usage;
|
|
}
|
|
if(no)
|
|
{
|
|
debug &=~d->level;
|
|
no=0;
|
|
}
|
|
else
|
|
debug |= d->level;
|
|
p = q;
|
|
}
|
|
}
|
|
else
|
|
debug = DEBUG_DEFAULT;
|
|
}
|
|
else if (strcmp(*argv, "-c") == 0) {
|
|
if (argc > 1)
|
|
{
|
|
argv++;
|
|
argc--;
|
|
strcpy(configfilename, *argv);
|
|
}
|
|
else
|
|
goto usage;
|
|
}
|
|
else if (strcmp(*argv, "-f") == 0)
|
|
foreground = 1;
|
|
else
|
|
goto usage;
|
|
|
|
argv++;
|
|
argc--;
|
|
}
|
|
|
|
if (argc > 0)
|
|
{
|
|
usage:
|
|
tmpd = 0xffffffff;
|
|
fprintf(stderr, "usage: pim6sd [-c configfile] [-d [debug_level][,debug_level]]\n");
|
|
|
|
fprintf(stderr, "debug levels: ");
|
|
c = '(';
|
|
for (d = debugnames; d < debugnames +
|
|
sizeof(debugnames) / sizeof(debugnames[0]); d++)
|
|
{
|
|
if ((tmpd & d->level) == d->level)
|
|
{
|
|
tmpd &= ~d->level;
|
|
fprintf(stderr, "%c%s", c, d->name);
|
|
c = ',';
|
|
}
|
|
}
|
|
fprintf(stderr, ")\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (debug != 0)
|
|
{
|
|
tmpd = debug;
|
|
fprintf(stderr, "debug level 0x%lx ", debug);
|
|
c = '(';
|
|
for (d = debugnames; d < debugnames +
|
|
sizeof(debugnames) / sizeof(debugnames[0]); d++)
|
|
{
|
|
if ((tmpd & d->level) == d->level)
|
|
{
|
|
tmpd &= ~d->level;
|
|
fprintf(stderr, "%c%s", c, d->name);
|
|
c = ',';
|
|
}
|
|
}
|
|
fprintf(stderr, ")\n");
|
|
}
|
|
|
|
#ifdef LOG_DAEMON
|
|
(void) openlog("pim6sd", LOG_PID, LOG_DAEMON);
|
|
#if 0
|
|
(void) setlogmask(LOG_UPTO(LOG_NOTICE));
|
|
#endif
|
|
#else
|
|
(void) openlog("pim6sd", LOG_PID);
|
|
#endif /* LOG_DAEMON */
|
|
/* open a log file */
|
|
if ((log_fp = fopen(logfilename, "w")) == NULL)
|
|
log(LOG_ERR, errno, "fopen(%s)", logfilename);
|
|
setlinebuf(log_fp);
|
|
|
|
sprintf(versionstring, "pim6sd version %s", todaysversion);
|
|
|
|
log(LOG_INFO, 0, "%s starting", versionstring);
|
|
|
|
/*
|
|
* TODO: XXX: use a combination of time and hostid to initialize the
|
|
* random generator.
|
|
*/
|
|
|
|
#ifdef SYSV
|
|
srand48(time(NULL));
|
|
#else
|
|
srandom(time(NULL));
|
|
#endif
|
|
|
|
callout_init();
|
|
init_mld6();
|
|
init_pim6();
|
|
|
|
#ifdef HAVE_ROUTING_SOCKETS
|
|
init_routesock();
|
|
#endif /* HAVE_ROUTING_SOCKETS */
|
|
|
|
init_pim6_mrt();
|
|
init_timers();
|
|
|
|
/* TODO: check the kernel DVMRP/MROUTED/PIM support version */
|
|
|
|
init_vifs();
|
|
init_rp6_and_bsr6(); /* Must be after init_vifs() */
|
|
|
|
sa.sa_handler = handler;
|
|
sa.sa_flags = 0; /* Interrupt system calls */
|
|
sigemptyset(&sa.sa_mask);
|
|
sigaction(SIGALRM, &sa, NULL);
|
|
sigaction(SIGHUP, &sa, NULL);
|
|
sigaction(SIGTERM, &sa, NULL);
|
|
sigaction(SIGINT, &sa, NULL);
|
|
sigaction(SIGUSR1, &sa, NULL);
|
|
sigaction(SIGUSR2, &sa, NULL);
|
|
sigaction(SIGINFO, &sa, NULL);
|
|
|
|
FD_ZERO(&readers);
|
|
FD_SET(mld6_socket, &readers);
|
|
for (i = 0; i < nhandlers; i++)
|
|
{
|
|
FD_SET(ihandlers[i].fd, &readers);
|
|
if (ihandlers[i].fd >= nfds)
|
|
nfds = ihandlers[i].fd + 1;
|
|
}
|
|
|
|
IF_DEBUG(DEBUG_IF)
|
|
dump_vifs(log_fp);
|
|
IF_DEBUG(DEBUG_PIM_MRT)
|
|
dump_pim_mrt(log_fp);
|
|
|
|
/* schedule first timer interrupt */
|
|
timer_setTimer(timer_interval, timer, NULL);
|
|
|
|
if (foreground == 0)
|
|
{
|
|
/* Detach from the terminal */
|
|
#ifdef TIOCNOTTY
|
|
int t;
|
|
#endif /* TIOCNOTTY */
|
|
|
|
if (fork())
|
|
exit(0);
|
|
|
|
#ifdef HAVE_ROUTING_SOCKETS
|
|
pid = getpid();
|
|
#endif
|
|
(void) close(0);
|
|
(void) close(1);
|
|
(void) close(2);
|
|
(void) open("/", 0);
|
|
(void) dup2(0, 1);
|
|
(void) dup2(0, 2);
|
|
|
|
#if defined(SYSV) || defined(linux)
|
|
(void) setpgrp();
|
|
#else
|
|
#ifdef TIOCNOTTY
|
|
t = open("/dev/tty", 2);
|
|
if (t >= 0)
|
|
{
|
|
(void) ioctl(t, TIOCNOTTY, (char *) 0);
|
|
(void) close(t);
|
|
}
|
|
#else
|
|
if (setsid() < 0)
|
|
perror("setsid");
|
|
#endif /* TIOCNOTTY */
|
|
#endif /* SYSV */
|
|
} /* End of child process code */
|
|
|
|
fp = fopen(pidfilename, "w");
|
|
if (fp != NULL)
|
|
{
|
|
fprintf(fp, "%d\n", (int) getpid());
|
|
(void) fclose(fp);
|
|
}
|
|
|
|
/*
|
|
* Main receive loop.
|
|
*/
|
|
dummy = 0;
|
|
dummysigalrm = SIGALRM;
|
|
difftime.tv_usec = 0;
|
|
gettimeofday(&curtime, NULL);
|
|
lasttime = curtime;
|
|
for (;;)
|
|
{
|
|
bcopy((char *) &readers, (char *) &rfds, sizeof(rfds));
|
|
secs = timer_nextTimer();
|
|
if (secs == -1)
|
|
timeout = NULL;
|
|
else
|
|
{
|
|
timeout = &tv;
|
|
timeout->tv_sec = secs;
|
|
timeout->tv_usec = 0;
|
|
}
|
|
|
|
if (sighandled)
|
|
{
|
|
if (sighandled & GOT_SIGINT)
|
|
{
|
|
sighandled &= ~GOT_SIGINT;
|
|
break;
|
|
}
|
|
if (sighandled & GOT_SIGHUP)
|
|
{
|
|
sighandled &= ~GOT_SIGHUP;
|
|
restart(SIGHUP);
|
|
}
|
|
if (sighandled & GOT_SIGINFO)
|
|
{
|
|
sighandled &= ~GOT_SIGINFO;
|
|
dump_stat();
|
|
}
|
|
if (sighandled & GOT_SIGUSR1)
|
|
{
|
|
sighandled &= ~GOT_SIGUSR1;
|
|
fdump(SIGUSR1);
|
|
}
|
|
if (sighandled & GOT_SIGUSR2)
|
|
{
|
|
sighandled &= ~GOT_SIGUSR2;
|
|
#ifdef notyet
|
|
cdump(SIGUSR2);
|
|
#else
|
|
cfparse(0, 1); /* reset debug level */
|
|
#endif
|
|
}
|
|
if (sighandled & GOT_SIGALRM)
|
|
{
|
|
sighandled &= ~GOT_SIGALRM;
|
|
timer(&dummysigalrm);
|
|
}
|
|
}
|
|
if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0)
|
|
{
|
|
if (errno != EINTR)
|
|
log(LOG_WARNING, errno, "select failed");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Handle timeout queue.
|
|
*
|
|
* If select + packet processing took more than 1 second, or if there is
|
|
* a timeout pending, age the timeout queue.
|
|
*
|
|
* If not, collect usec in difftime to make sure that the time doesn't
|
|
* drift too badly.
|
|
*
|
|
* If the timeout handlers took more than 1 second, age the timeout
|
|
* queue again. XXX This introduces the potential for infinite
|
|
* loops!
|
|
*/
|
|
do
|
|
{
|
|
/*
|
|
* If the select timed out, then there's no other activity to
|
|
* account for and we don't need to call gettimeofday.
|
|
*/
|
|
if (n == 0)
|
|
{
|
|
curtime.tv_sec = lasttime.tv_sec + secs;
|
|
curtime.tv_usec = lasttime.tv_usec;
|
|
n = -1; /* don't do this next time through the loop */
|
|
}
|
|
else
|
|
gettimeofday(&curtime, NULL);
|
|
difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
|
|
difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
|
|
#ifdef TIMERDEBUG
|
|
IF_DEBUG(DEBUG_TIMEOUT)
|
|
log(LOG_DEBUG, 0, "TIMEOUT: secs %d, diff secs %d, diff usecs %d", secs, difftime.tv_sec, difftime.tv_usec);
|
|
#endif
|
|
while (difftime.tv_usec >= 1000000)
|
|
{
|
|
difftime.tv_sec++;
|
|
difftime.tv_usec -= 1000000;
|
|
}
|
|
if (difftime.tv_usec < 0)
|
|
{
|
|
difftime.tv_sec--;
|
|
difftime.tv_usec += 1000000;
|
|
}
|
|
lasttime = curtime;
|
|
if (secs == 0 || difftime.tv_sec > 0)
|
|
if (secs == 0 || difftime.tv_sec > 0)
|
|
{
|
|
#ifdef TIMERDEBUG
|
|
IF_DEBUG(DEBUG_TIMEOUT)
|
|
log(LOG_DEBUG, 0, "\taging callouts: secs %d, diff secs %d, diff usecs %d", secs, difftime.tv_sec, difftime.tv_usec);
|
|
#endif
|
|
age_callout_queue(difftime.tv_sec);
|
|
}
|
|
secs = -1;
|
|
} while (difftime.tv_sec > 0);
|
|
|
|
/* Handle sockets */
|
|
if (n > 0)
|
|
{
|
|
for (i = 0; i < nhandlers; i++)
|
|
{
|
|
if (FD_ISSET(ihandlers[i].fd, &rfds))
|
|
{
|
|
(*ihandlers[i].func) (ihandlers[i].fd, &rfds);
|
|
}
|
|
}
|
|
}
|
|
|
|
} /* Main loop */
|
|
|
|
log(LOG_NOTICE, 0, "%s exiting", versionstring);
|
|
cleanup();
|
|
exit(0);
|
|
}
|
|
|
|
/*
|
|
* The 'virtual_time' variable is initialized to a value that will cause the
|
|
* first invocation of timer() to send a probe or route report to all vifs
|
|
* and send group membership queries to all subnets for which this router is
|
|
* querier. This first invocation occurs approximately timer_interval
|
|
* seconds after the router starts up. Note that probes for neighbors and
|
|
* queries for group memberships are also sent at start-up time, as part of
|
|
* initial- ization. This repetition after a short interval is desirable for
|
|
* quickly building up topology and membership information in the presence of
|
|
* possible packet loss.
|
|
*
|
|
* 'virtual_time' advances at a rate that is only a crude approximation of real
|
|
* time, because it does not take into account any time spent processing, and
|
|
* because the timer intervals are sometimes shrunk by a random amount to
|
|
* avoid unwanted synchronization with other routers.
|
|
*/
|
|
|
|
u_long virtual_time = 0;
|
|
|
|
/*
|
|
* Timer routine. Performs all perodic functions: aging interfaces, quering
|
|
* neighbors and members, etc... The granularity is equal to timer_interval.
|
|
* this granularity is configurable ( see file pim6sd.conf.sample)
|
|
*/
|
|
|
|
static void
|
|
timer(i)
|
|
void *i;
|
|
{
|
|
age_vifs(); /* Timeout neighbors and groups */
|
|
age_routes(); /* Timeout routing entries */
|
|
age_misc(); /* Timeout the rest (Cand-RP list, etc) */
|
|
|
|
virtual_time += timer_interval;
|
|
timer_setTimer(timer_interval, timer, NULL);
|
|
}
|
|
|
|
/*
|
|
* Performs all necessary functions to quit gracefully
|
|
*/
|
|
/* TODO: implement all necessary stuff */
|
|
|
|
static void
|
|
cleanup()
|
|
{
|
|
vifi_t vifi;
|
|
struct uvif *v;
|
|
|
|
/* inform all neighbors that I'm going to die */
|
|
for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
|
|
if ((v->uv_flags & (VIFF_DOWN|VIFF_DISABLED|MIFF_REGISTER)) == 0)
|
|
send_pim6_hello(v, 0);
|
|
}
|
|
|
|
/*
|
|
* TODO: XXX (not in the spec): if I am the BSR, somehow inform the other
|
|
* routers I am going down and need to elect another BSR? (probably by
|
|
* sending a the Cand-RP-set with my_priority=LOWEST?)
|
|
*
|
|
*/
|
|
;
|
|
|
|
k_stop_pim(mld6_socket);
|
|
}
|
|
|
|
/*
|
|
* Signal handler. Take note of the fact that the signal arrived so that the
|
|
* main loop can take care of it.
|
|
*/
|
|
static void
|
|
handler(sig)
|
|
int sig;
|
|
{
|
|
switch (sig)
|
|
{
|
|
case SIGALRM:
|
|
sighandled |= GOT_SIGALRM;
|
|
case SIGINT:
|
|
case SIGTERM:
|
|
sighandled |= GOT_SIGINT;
|
|
break;
|
|
|
|
case SIGHUP:
|
|
sighandled |= GOT_SIGHUP;
|
|
break;
|
|
|
|
case SIGUSR1:
|
|
sighandled |= GOT_SIGUSR1;
|
|
break;
|
|
|
|
case SIGUSR2:
|
|
sighandled |= GOT_SIGUSR2;
|
|
break;
|
|
|
|
case SIGINFO:
|
|
sighandled |= GOT_SIGINFO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/* TODO: not verified */
|
|
/*
|
|
* Restart the daemon
|
|
*/
|
|
|
|
static void
|
|
restart(i)
|
|
int i;
|
|
{
|
|
|
|
log(LOG_NOTICE, 0, "%s restart", versionstring);
|
|
|
|
/*
|
|
* reset all the entries
|
|
*/
|
|
/*
|
|
* TODO: delete?
|
|
free_all_routes();
|
|
*/
|
|
|
|
free_all_callouts();
|
|
stop_all_vifs();
|
|
nhandlers=0;
|
|
k_stop_pim(mld6_socket);
|
|
close(mld6_socket);
|
|
close(pim6_socket);
|
|
close(udp_socket);
|
|
|
|
/*
|
|
* start processing again
|
|
*/
|
|
|
|
init_mld6();
|
|
init_pim6();
|
|
|
|
#ifdef HAVE_ROUTING_SOCKETS
|
|
init_routesock();
|
|
#endif /* HAVE_ROUTING_SOCKETS */
|
|
|
|
init_pim6_mrt();
|
|
init_vifs();
|
|
|
|
/* schedule timer interrupts */
|
|
timer_setTimer(timer_interval, timer, NULL);
|
|
}
|