Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/rtsold/rtsold.c
Show All 29 Lines | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
* | * | ||||
* $FreeBSD$ | * $FreeBSD$ | ||||
*/ | */ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/capsicum.h> | #include <sys/capsicum.h> | ||||
#include <sys/event.h> | |||||
#include <sys/ioctl.h> | #include <sys/ioctl.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | ||||
#include <netinet/in_var.h> | #include <netinet/in_var.h> | ||||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
#include <capsicum_helpers.h> | |||||
#include <err.h> | |||||
#include <errno.h> | |||||
#include <ifaddrs.h> | |||||
#include <libgen.h> | |||||
#include <signal.h> | #include <signal.h> | ||||
#include <unistd.h> | #include <stdarg.h> | ||||
#include <syslog.h> | |||||
#include <string.h> | |||||
#include <stdlib.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <syslog.h> | |||||
#include <time.h> | #include <time.h> | ||||
#include <errno.h> | #include <unistd.h> | ||||
#include <err.h> | |||||
#include <stdarg.h> | |||||
#include <ifaddrs.h> | |||||
#include <poll.h> | |||||
#include <libcasper.h> | |||||
#include <casper/cap_syslog.h> | |||||
#include <libutil.h> | #include <libutil.h> | ||||
#include "rtsold.h" | #include "rtsold.h" | ||||
#define RTSOL_DUMPFILE "/var/run/rtsold.dump"; | #define RTSOL_DUMPFILE "/var/run/rtsold.dump" | ||||
struct timespec tm_max; | struct timespec tm_max; | ||||
static int log_upto = 999; | static int log_upto = 999; | ||||
static int fflag = 0; | static int fflag = 0; | ||||
int Fflag = 0; /* force setting sysctl parameters */ | int Fflag = 0; /* force setting sysctl parameters */ | ||||
int aflag = 0; | int aflag = 0; | ||||
int dflag = 0; | int dflag = 0; | ||||
int uflag = 0; | int uflag = 0; | ||||
const char *otherconf_script; | const char *otherconf_script; | ||||
const char *resolvconf_script = "/sbin/resolvconf"; | const char *resolvconf_script = "/sbin/resolvconf"; | ||||
cap_channel_t *capprobe, *capscript; | |||||
static cap_channel_t *capsyslog; | |||||
/* protocol constants */ | /* protocol constants */ | ||||
#define MAX_RTR_SOLICITATION_DELAY 1 /* second */ | #define MAX_RTR_SOLICITATION_DELAY 1 /* second */ | ||||
#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ | #define RTR_SOLICITATION_INTERVAL 4 /* seconds */ | ||||
#define MAX_RTR_SOLICITATIONS 3 /* times */ | #define MAX_RTR_SOLICITATIONS 3 /* times */ | ||||
/* | /* | ||||
* implementation dependent constants in seconds | * implementation dependent constants in seconds | ||||
* XXX: should be configurable | * XXX: should be configurable | ||||
*/ | */ | ||||
#define PROBE_INTERVAL 60 | #define PROBE_INTERVAL 60 | ||||
/* static variables and functions */ | /* static variables and functions */ | ||||
static int mobile_node = 0; | static int mobile_node = 0; | ||||
#ifndef SMALL | static sig_atomic_t do_dump; | ||||
static int do_dump; | |||||
static const char *dumpfilename = RTSOL_DUMPFILE; | |||||
static struct pidfh *pfh; | static struct pidfh *pfh; | ||||
#endif | |||||
static char **autoifprobe(void); | static char **autoifprobe(void); | ||||
static int ifconfig(char *ifname); | static int ifconfig(char *ifname); | ||||
static int init_capabilities(void); | |||||
static int make_packet(struct ifinfo *); | static int make_packet(struct ifinfo *); | ||||
static struct timespec *rtsol_check_timer(void); | static struct timespec *rtsol_check_timer(void); | ||||
#ifndef SMALL | static void set_dumpfile(int); | ||||
static void rtsold_set_dump_file(int); | static void usage(const char *progname); | ||||
#endif | |||||
static void usage(void); | |||||
int | int | ||||
main(int argc, char **argv) | main(int argc, char **argv) | ||||
{ | { | ||||
int s, ch, once = 0; | struct kevent events[2]; | ||||
FILE *dumpfp; | |||||
struct ifinfo *ifi; | |||||
struct timespec *timeout; | struct timespec *timeout; | ||||
const char *opts, *pidfilepath; | const char *opts, *pidfilepath, *progname; | ||||
struct pollfd set[2]; | int ch, error, kq, once, rcvsock, rtsock; | ||||
int rtsock; | |||||
char *argv0; | |||||
#ifndef SMALL | progname = basename(argv[0]); | ||||
/* rtsold */ | if (strcmp(progname, "rtsold") == 0) { | ||||
opts = "adDfFm1O:p:R:u"; | opts = "adDfFm1O:p:R:u"; | ||||
once = 0; | |||||
pidfilepath = NULL; | pidfilepath = NULL; | ||||
#else | } else { | ||||
/* rtsol */ | |||||
opts = "adDFO:R:u"; | opts = "adDFO:R:u"; | ||||
fflag = 1; | fflag = 1; | ||||
once = 1; | once = 1; | ||||
#endif | } | ||||
argv0 = argv[0]; | |||||
while ((ch = getopt(argc, argv, opts)) != -1) { | while ((ch = getopt(argc, argv, opts)) != -1) { | ||||
switch (ch) { | switch (ch) { | ||||
case 'a': | case 'a': | ||||
aflag = 1; | aflag = 1; | ||||
break; | break; | ||||
case 'd': | case 'd': | ||||
dflag += 1; | dflag += 1; | ||||
Show All 21 Lines | case 'p': | ||||
break; | break; | ||||
case 'R': | case 'R': | ||||
resolvconf_script = optarg; | resolvconf_script = optarg; | ||||
break; | break; | ||||
case 'u': | case 'u': | ||||
uflag = 1; | uflag = 1; | ||||
break; | break; | ||||
default: | default: | ||||
usage(); | usage(progname); | ||||
exit(1); | |||||
} | } | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if ((!aflag && argc == 0) || (aflag && argc != 0)) { | if ((!aflag && argc == 0) || (aflag && argc != 0)) | ||||
usage(); | usage(progname); | ||||
exit(1); | |||||
} | |||||
/* Generate maximum time in timespec. */ | /* Generate maximum time in timespec. */ | ||||
tm_max.tv_sec = (-1) & ~((time_t)1 << ((sizeof(tm_max.tv_sec) * 8) - 1)); | tm_max.tv_sec = (-1) & ~((time_t)1 << ((sizeof(tm_max.tv_sec) * 8) - 1)); | ||||
tm_max.tv_nsec = (-1) & ~((long)1 << ((sizeof(tm_max.tv_nsec) * 8) - 1)); | tm_max.tv_nsec = (-1) & ~((long)1 << ((sizeof(tm_max.tv_nsec) * 8) - 1)); | ||||
/* set log level */ | /* set log level */ | ||||
if (dflag > 1) | if (dflag > 1) | ||||
log_upto = LOG_DEBUG; | log_upto = LOG_DEBUG; | ||||
else if (dflag > 0) | else if (dflag > 0) | ||||
log_upto = LOG_INFO; | log_upto = LOG_INFO; | ||||
else | else | ||||
log_upto = LOG_NOTICE; | log_upto = LOG_NOTICE; | ||||
if (!fflag) { | if (otherconf_script != NULL && *otherconf_script != '/') | ||||
char *ident; | |||||
ident = strrchr(argv0, '/'); | |||||
if (!ident) | |||||
ident = argv0; | |||||
else | |||||
ident++; | |||||
openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON); | |||||
if (log_upto >= 0) | |||||
setlogmask(LOG_UPTO(log_upto)); | |||||
} | |||||
if (otherconf_script && *otherconf_script != '/') { | |||||
errx(1, "configuration script (%s) must be an absolute path", | errx(1, "configuration script (%s) must be an absolute path", | ||||
otherconf_script); | otherconf_script); | ||||
} | if (*resolvconf_script != '/') | ||||
if (resolvconf_script && *resolvconf_script != '/') { | |||||
errx(1, "configuration script (%s) must be an absolute path", | errx(1, "configuration script (%s) must be an absolute path", | ||||
resolvconf_script); | resolvconf_script); | ||||
} | |||||
#ifndef SMALL | if (!fflag) { | ||||
pfh = pidfile_open(pidfilepath, 0644, NULL); | pfh = pidfile_open(pidfilepath, 0644, NULL); | ||||
if (pfh == NULL) { | if (pfh == NULL) | ||||
errx(1, "failed to open pidfile: %s", strerror(errno)); | errx(1, "failed to open pidfile: %s", strerror(errno)); | ||||
if (daemon(0, 0) != 0) | |||||
errx(1, "failed to daemonize"); | |||||
} | } | ||||
/* initialization to dump internal status to a file */ | if ((error = init_capabilities()) != 0) | ||||
signal(SIGUSR1, rtsold_set_dump_file); | err(1, "failed to initialize capabilities"); | ||||
#endif | |||||
if (!fflag) | if (!fflag) { | ||||
daemon(0, 0); /* act as a daemon */ | cap_openlog(capsyslog, progname, LOG_NDELAY | LOG_PID, | ||||
LOG_DAEMON); | |||||
if (log_upto >= 0) | |||||
(void)cap_setlogmask(capsyslog, LOG_UPTO(log_upto)); | |||||
(void)signal(SIGUSR1, set_dumpfile); | |||||
dumpfp = rtsold_init_dumpfile(RTSOL_DUMPFILE); | |||||
} | |||||
/* | kq = kqueue(); | ||||
* Open a socket for sending RS and receiving RA. | if (kq < 0) { | ||||
* This should be done before calling ifinit(), since the function | warnmsg(LOG_ERR, __func__, "failed to create a kqueue: %s", | ||||
* uses the socket. | strerror(errno)); | ||||
*/ | |||||
if ((s = sockopen()) < 0) { | |||||
warnmsg(LOG_ERR, __func__, "failed to open a socket"); | |||||
exit(1); | exit(1); | ||||
} | } | ||||
set[0].fd = s; | |||||
set[0].events = POLLIN; | |||||
set[1].fd = -1; | |||||
/* Open global sockets and register for read events. */ | |||||
if ((rtsock = rtsock_open()) < 0) { | if ((rtsock = rtsock_open()) < 0) { | ||||
warnmsg(LOG_ERR, __func__, "failed to open a socket"); | warnmsg(LOG_ERR, __func__, "failed to open routing socket"); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
set[1].fd = rtsock; | if ((rcvsock = recvsockopen()) < 0) { | ||||
set[1].events = POLLIN; | warnmsg(LOG_ERR, __func__, "failed to open receive socket"); | ||||
exit(1); | |||||
} | |||||
EV_SET(&events[0], rtsock, EVFILT_READ, EV_ADD, 0, 0, NULL); | |||||
EV_SET(&events[1], rcvsock, EVFILT_READ, EV_ADD, 0, 0, NULL); | |||||
if (kevent(kq, events, 2, NULL, 0, NULL) < 0) { | |||||
warnmsg(LOG_ERR, __func__, "kevent(): %s", strerror(errno)); | |||||
exit(1); | |||||
} | |||||
/* configuration per interface */ | /* Probe network interfaces and set up tracking info. */ | ||||
if (ifinit()) { | if (ifinit() != 0) { | ||||
warnmsg(LOG_ERR, __func__, | warnmsg(LOG_ERR, __func__, "failed to initialize interfaces"); | ||||
"failed to initialize interfaces"); | |||||
exit(1); | exit(1); | ||||
} | } | ||||
if (aflag) | if (aflag) | ||||
argv = autoifprobe(); | argv = autoifprobe(); | ||||
while (argv && *argv) { | while (argv && *argv) { | ||||
if (ifconfig(*argv)) { | if (ifconfig(*argv)) { | ||||
warnmsg(LOG_ERR, __func__, | warnmsg(LOG_ERR, __func__, | ||||
"failed to initialize %s", *argv); | "failed to initialize %s", *argv); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
argv++; | argv++; | ||||
} | } | ||||
/* setup for probing default routers */ | /* Write to our pidfile. */ | ||||
if (probe_init()) { | if (pfh != NULL && pidfile_write(pfh) != 0) { | ||||
warnmsg(LOG_ERR, __func__, | warnmsg(LOG_ERR, __func__, | ||||
"failed to setup for probing routers"); | "failed to open pidfile: %s", strerror(errno)); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
#ifndef SMALL | /* Enter capability mode. */ | ||||
/* dump the current pid */ | if (caph_enter() != 0) { | ||||
oshogbo: What if casper is not enabled? | |||||
markjAuthorUnsubmitted Done Inline ActionsSorry, I don't follow. What does that have to do with caph_enter()? markj: Sorry, I don't follow. What does that have to do with caph_enter()? | |||||
oshogboUnsubmitted Done Inline ActionsWhen the Casper is not build you still enter the capability mode. cap_syslog will be changed to use syslog, but it will fail in sandbox. You should probably use the caph_enter_with_casper(). oshogbo: When the Casper is not build you still enter the capability mode. cap_syslog will be changed to… | |||||
if (pidfile_write(pfh) != 0) { | warnmsg(LOG_ERR, __func__, "caph_enter(): %s", strerror(errno)); | ||||
warnmsg(LOG_ERR, __func__, | |||||
"failed to open pidfile: %s", strerror(errno)); | |||||
exit(1); | exit(1); | ||||
} | } | ||||
#endif | |||||
while (1) { /* main loop */ | for (;;) { | ||||
int e; | if (do_dump) { | ||||
#ifndef SMALL | /* Handle SIGUSR1. */ | ||||
if (do_dump) { /* SIGUSR1 */ | |||||
do_dump = 0; | do_dump = 0; | ||||
rtsold_dump_file(dumpfilename); | if (dumpfp != NULL) | ||||
rtsold_dump(dumpfp); | |||||
} | } | ||||
#endif | |||||
timeout = rtsol_check_timer(); | timeout = rtsol_check_timer(); | ||||
if (once) { | if (once) { | ||||
struct ifinfo *ifi; | |||||
/* if we have no timeout, we are done (or failed) */ | /* if we have no timeout, we are done (or failed) */ | ||||
if (timeout == NULL) | if (timeout == NULL) | ||||
break; | break; | ||||
/* if all interfaces have got RA packet, we are done */ | /* if all interfaces have got RA packet, we are done */ | ||||
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) { | TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) { | ||||
if (ifi->state != IFS_DOWN && ifi->racnt == 0) | if (ifi->state != IFS_DOWN && ifi->racnt == 0) | ||||
break; | break; | ||||
} | } | ||||
if (ifi == NULL) | if (ifi == NULL) | ||||
break; | break; | ||||
} | } | ||||
e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 1000 / 1000) : INFTIM); | |||||
if (e < 1) { | error = kevent(kq, NULL, 0, &events[0], 1, timeout); | ||||
if (e < 0 && errno != EINTR) { | if (error < 1) { | ||||
warnmsg(LOG_ERR, __func__, "select: %s", | if (error < 0 && errno != EINTR) | ||||
warnmsg(LOG_ERR, __func__, "kevent(): %s", | |||||
strerror(errno)); | strerror(errno)); | ||||
} | |||||
continue; | continue; | ||||
} | } | ||||
/* packet reception */ | if (events[0].ident == (uintptr_t)rtsock) | ||||
if (set[1].revents & POLLIN) | |||||
rtsock_input(rtsock); | rtsock_input(rtsock); | ||||
if (set[0].revents & POLLIN) | else | ||||
rtsol_input(s); | rtsol_input(rcvsock); | ||||
} | } | ||||
/* NOTREACHED */ | |||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
init_capabilities(void) | |||||
{ | |||||
const char *const scripts[2] = { resolvconf_script, otherconf_script }; | |||||
Done Inline ActionsShouldn't all this succeed even when casper is not avilable? oshogbo: Shouldn't all this succeed even when casper is not avilable? | |||||
Done Inline ActionsIt does - we return 0 at the end. markj: It does - we return 0 at the end. | |||||
cap_channel_t *capcasper; | |||||
nvlist_t *limits; | |||||
capcasper = cap_init(); | |||||
if (capcasper == NULL) | |||||
return (errno); | |||||
if (!fflag) { | |||||
capsyslog = cap_service_open(capcasper, "system.syslog"); | |||||
if (capsyslog == NULL) | |||||
return (errno); | |||||
} | |||||
if (mobile_node) { | |||||
capprobe = cap_service_open(capcasper, | |||||
"rtsold.defrouter_probe"); | |||||
if (capprobe == NULL) | |||||
return (errno); | |||||
} | |||||
capscript = cap_service_open(capcasper, "rtsold.script"); | |||||
if (capscript == NULL) | |||||
return (errno); | |||||
limits = nvlist_create(0); | |||||
nvlist_add_string_array(limits, "scripts", scripts, | |||||
otherconf_script != NULL ? 2 : 1); | |||||
if (cap_limit_set(capscript, limits) != 0) | |||||
return (errno); | |||||
cap_close(capcasper); | |||||
return (0); | |||||
} | |||||
static int | |||||
ifconfig(char *ifname) | ifconfig(char *ifname) | ||||
{ | { | ||||
struct ifinfo *ifi; | struct ifinfo *ifi; | ||||
struct sockaddr_dl *sdl; | struct sockaddr_dl *sdl; | ||||
int flags; | int flags; | ||||
ifi = NULL; | ifi = NULL; | ||||
if ((sdl = if_nametosdl(ifname)) == NULL) { | if ((sdl = if_nametosdl(ifname)) == NULL) { | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||
#ifdef HAVE_SCOPELIB | #ifdef HAVE_SCOPELIB | ||||
if (inet_zoneid(AF_INET6, 2, ifname, &ifi->linkid)) | if (inet_zoneid(AF_INET6, 2, ifname, &ifi->linkid)) | ||||
goto bad; | goto bad; | ||||
#else | #else | ||||
/* XXX: assume interface IDs as link IDs */ | /* XXX: assume interface IDs as link IDs */ | ||||
ifi->linkid = ifi->sdl->sdl_index; | ifi->linkid = ifi->sdl->sdl_index; | ||||
#endif | #endif | ||||
ifi->ifi_sock = sendsockopen(ifi->linkid); | |||||
if (ifi->ifi_sock == -1) | |||||
goto bad; | |||||
/* | /* | ||||
* check if the interface is available. | * check if the interface is available. | ||||
* also check if SIOCGIFMEDIA ioctl is OK on the interface. | * also check if SIOCGIFMEDIA ioctl is OK on the interface. | ||||
*/ | */ | ||||
ifi->mediareqok = 1; | ifi->mediareqok = 1; | ||||
ifi->active = interface_status(ifi); | ifi->active = interface_status(ifi); | ||||
if (!ifi->mediareqok) { | if (!ifi->mediareqok) { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
static struct timespec * | static struct timespec * | ||||
rtsol_check_timer(void) | rtsol_check_timer(void) | ||||
{ | { | ||||
static struct timespec returnval; | static struct timespec returnval; | ||||
struct timespec now, rtsol_timer; | struct timespec now, rtsol_timer; | ||||
struct ifinfo *ifi; | struct ifinfo *ifi; | ||||
struct rainfo *rai; | struct rainfo *rai; | ||||
struct ra_opt *rao, *raotmp; | struct ra_opt *rao, *raotmp; | ||||
int flags; | int error, flags; | ||||
clock_gettime(CLOCK_MONOTONIC_FAST, &now); | clock_gettime(CLOCK_MONOTONIC_FAST, &now); | ||||
rtsol_timer = tm_max; | rtsol_timer = tm_max; | ||||
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) { | TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) { | ||||
if (TS_CMP(&ifi->expire, &now, <=)) { | if (TS_CMP(&ifi->expire, &now, <=)) { | ||||
warnmsg(LOG_DEBUG, __func__, "timer expiration on %s, " | warnmsg(LOG_DEBUG, __func__, "timer expiration on %s, " | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (TS_CMP(&ifi->expire, &now, <=)) { | ||||
} | } | ||||
/* | /* | ||||
* If we need a probe, clear the previous | * If we need a probe, clear the previous | ||||
* status wrt the "other" configuration. | * status wrt the "other" configuration. | ||||
*/ | */ | ||||
if (probe) | if (probe) | ||||
ifi->otherconfig = 0; | ifi->otherconfig = 0; | ||||
if (probe && mobile_node) { | |||||
if (probe && mobile_node) | error = cap_probe_defrouters(capprobe, | ||||
defrouter_probe(ifi); | ifi); | ||||
if (error != 0) | |||||
warnmsg(LOG_DEBUG, __func__, | |||||
"failed to probe routers: %d", | |||||
error); | |||||
} | |||||
break; | break; | ||||
} | } | ||||
case IFS_DELAY: | case IFS_DELAY: | ||||
ifi->state = IFS_PROBE; | ifi->state = IFS_PROBE; | ||||
sendpacket(ifi); | sendpacket(ifi); | ||||
break; | break; | ||||
case IFS_PROBE: | case IFS_PROBE: | ||||
if (ifi->probes < MAX_RTR_SOLICITATIONS) | if (ifi->probes < MAX_RTR_SOLICITATIONS) | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | #define DADRETRY 10 /* XXX: adhoc */ | ||||
case IFS_TENTATIVE: | case IFS_TENTATIVE: | ||||
if (++ifi->dadcount > DADRETRY) { | if (++ifi->dadcount > DADRETRY) { | ||||
ifi->dadcount = 0; | ifi->dadcount = 0; | ||||
ifi->timer.tv_sec = PROBE_INTERVAL; | ifi->timer.tv_sec = PROBE_INTERVAL; | ||||
} else | } else | ||||
ifi->timer.tv_sec = 1; | ifi->timer.tv_sec = 1; | ||||
break; | break; | ||||
case IFS_IDLE: | case IFS_IDLE: | ||||
if (mobile_node) { | if (mobile_node) | ||||
/* XXX should be configurable */ | /* XXX should be configurable */ | ||||
ifi->timer.tv_sec = 3; | ifi->timer.tv_sec = 3; | ||||
} | |||||
else | else | ||||
ifi->timer = tm_max; /* stop timer(valid?) */ | ifi->timer = tm_max; /* stop timer(valid?) */ | ||||
break; | break; | ||||
case IFS_DELAY: | case IFS_DELAY: | ||||
interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION); | interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION); | ||||
ifi->timer.tv_sec = interval / MILLION; | ifi->timer.tv_sec = interval / MILLION; | ||||
ifi->timer.tv_nsec = (interval % MILLION) * 1000; | ifi->timer.tv_nsec = (interval % MILLION) * 1000; | ||||
break; | break; | ||||
case IFS_PROBE: | case IFS_PROBE: | ||||
if (ifi->probes < MAX_RTR_SOLICITATIONS) | if (ifi->probes < MAX_RTR_SOLICITATIONS) | ||||
ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL; | ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL; | ||||
else { | else | ||||
/* | /* | ||||
* After sending MAX_RTR_SOLICITATIONS solicitations, | * After sending MAX_RTR_SOLICITATIONS solicitations, | ||||
* we're just waiting for possible replies; there | * we're just waiting for possible replies; there | ||||
* will be no more solicitation. Thus, we change | * will be no more solicitation. Thus, we change | ||||
* the timer value to MAX_RTR_SOLICITATION_DELAY based | * the timer value to MAX_RTR_SOLICITATION_DELAY based | ||||
* on RFC 2461, Section 6.3.7. | * on RFC 2461, Section 6.3.7. | ||||
*/ | */ | ||||
ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; | ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; | ||||
} | |||||
break; | break; | ||||
default: | default: | ||||
warnmsg(LOG_ERR, __func__, | warnmsg(LOG_ERR, __func__, | ||||
"illegal interface state(%d) on %s", | "illegal interface state(%d) on %s", | ||||
ifi->state, ifi->ifname); | ifi->state, ifi->ifname); | ||||
return; | return; | ||||
} | } | ||||
Show All 13 Lines | #define DADRETRY 10 /* XXX: adhoc */ | ||||
} | } | ||||
#undef MILLION | #undef MILLION | ||||
} | } | ||||
/* timer related utility functions */ | /* timer related utility functions */ | ||||
#define MILLION 1000000 | #define MILLION 1000000 | ||||
#ifndef SMALL | |||||
static void | static void | ||||
rtsold_set_dump_file(int sig __unused) | set_dumpfile(int sig __unused) | ||||
{ | { | ||||
do_dump = 1; | do_dump = 1; | ||||
} | } | ||||
#endif | |||||
static void | static void | ||||
usage(void) | usage(const char *progname) | ||||
{ | { | ||||
#ifndef SMALL | |||||
if (strcmp(progname, "rtsold") == 0) { | |||||
fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] " | fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] " | ||||
"[-p pidfile] [-R script-name] interface ...\n"); | "[-p pidfile] [-R script-name] interface ...\n"); | ||||
fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] " | fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] " | ||||
"[-p pidfile] [-R script-name] -a\n"); | "[-p pidfile] [-R script-name] -a\n"); | ||||
#else | } else { | ||||
fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] " | fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] " | ||||
"[-p pidfile] [-R script-name] interface ...\n"); | "[-p pidfile] [-R script-name] interface ...\n"); | ||||
fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] " | fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] " | ||||
"[-p pidfile] [-R script-name] -a\n"); | "[-p pidfile] [-R script-name] -a\n"); | ||||
#endif | |||||
} | } | ||||
exit(1); | |||||
} | |||||
void | void | ||||
warnmsg(int priority, const char *func, const char *msg, ...) | warnmsg(int priority, const char *func, const char *msg, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
char buf[BUFSIZ]; | char buf[BUFSIZ]; | ||||
va_start(ap, msg); | va_start(ap, msg); | ||||
if (fflag) { | if (fflag) { | ||||
if (priority <= log_upto) { | if (priority <= log_upto) { | ||||
(void)vfprintf(stderr, msg, ap); | (void)vfprintf(stderr, msg, ap); | ||||
(void)fprintf(stderr, "\n"); | (void)fprintf(stderr, "\n"); | ||||
} | } | ||||
} else { | } else { | ||||
snprintf(buf, sizeof(buf), "<%s> %s", func, msg); | snprintf(buf, sizeof(buf), "<%s> %s", func, msg); | ||||
msg = buf; | msg = buf; | ||||
vsyslog(priority, msg, ap); | cap_vsyslog(capsyslog, priority, msg, ap); | ||||
} | } | ||||
va_end(ap); | va_end(ap); | ||||
} | } | ||||
/* | /* | ||||
* return a list of interfaces which is suitable to sending an RS. | * return a list of interfaces which is suitable to sending an RS. | ||||
*/ | */ | ||||
static char ** | static char ** | ||||
▲ Show 20 Lines • Show All 107 Lines • Show Last 20 Lines |
What if casper is not enabled?