rtsold.c revision 118909
178064Sume/* $KAME: rtsold.c,v 1.31 2001/05/22 06:03:06 jinmei Exp $ */ 266776Skris 355163Sshin/* 455163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 555163Sshin * All rights reserved. 662632Skris * 755163Sshin * Redistribution and use in source and binary forms, with or without 855163Sshin * modification, are permitted provided that the following conditions 955163Sshin * are met: 1055163Sshin * 1. Redistributions of source code must retain the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer. 1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer in the 1455163Sshin * documentation and/or other materials provided with the distribution. 1555163Sshin * 3. Neither the name of the project nor the names of its contributors 1655163Sshin * may be used to endorse or promote products derived from this software 1755163Sshin * without specific prior written permission. 1862632Skris * 1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955163Sshin * SUCH DAMAGE. 3055163Sshin * 3155163Sshin * $FreeBSD: head/usr.sbin/rtsold/rtsold.c 118909 2003-08-14 15:47:31Z ume $ 3255163Sshin */ 3355163Sshin 3455163Sshin#include <sys/types.h> 3555163Sshin#include <sys/time.h> 3662632Skris#include <sys/socket.h> 37118909Sume#include <sys/param.h> 3855163Sshin 3962632Skris#include <net/if.h> 4055163Sshin#include <net/if_dl.h> 4155163Sshin 4255163Sshin#include <netinet/in.h> 4355163Sshin#include <netinet/icmp6.h> 4455163Sshin 4555163Sshin#include <signal.h> 4655163Sshin#include <unistd.h> 4755163Sshin#include <syslog.h> 4855163Sshin#include <string.h> 4955163Sshin#include <stdlib.h> 5055163Sshin#include <stdio.h> 5155163Sshin#include <errno.h> 5255163Sshin#include <err.h> 5355163Sshin#include <stdarg.h> 5466776Skris#include <ifaddrs.h> 55118664Sume 5655163Sshin#include "rtsold.h" 5755163Sshin 5855163Sshinstruct ifinfo *iflist; 5955163Sshinstruct timeval tm_max = {0x7fffffff, 0x7fffffff}; 60118664Sumestatic int log_upto = 999; 61118664Sumestatic int fflag = 0; 62118664Sume 6366776Skrisint aflag = 0; 6466776Skrisint dflag = 0; 65118664Sume 66118661Sumechar *otherconf_script; 6755163Sshin 6855163Sshin/* protocol constatns */ 6962632Skris#define MAX_RTR_SOLICITATION_DELAY 1 /* second */ 7062632Skris#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ 7162632Skris#define MAX_RTR_SOLICITATIONS 3 /* times */ 7255163Sshin 73118664Sume/* 74118664Sume * implementation dependent constants in secondes 75118664Sume * XXX: should be configurable 76118664Sume */ 77118664Sume#define PROBE_INTERVAL 60 7855163Sshin 7955163Sshin/* utility macros */ 8055163Sshin/* a < b */ 8162632Skris#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\ 8255163Sshin (((a).tv_sec == (b).tv_sec) && \ 8355163Sshin ((a).tv_usec < (b).tv_usec))) 8455163Sshin 8555163Sshin/* a <= b */ 8662632Skris#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\ 8755163Sshin (((a).tv_sec == (b).tv_sec) &&\ 88118664Sume ((a).tv_usec <= (b).tv_usec))) 8955163Sshin 9055163Sshin/* a == b */ 9162632Skris#define TIMEVAL_EQ(a, b) (((a).tv_sec==(b).tv_sec) && ((a).tv_usec==(b).tv_usec)) 9255163Sshin 93118664Sumeint main __P((int, char **)); 9455163Sshin 9555163Sshin/* static variables and functions */ 9655163Sshinstatic int mobile_node = 0; 9755163Sshinstatic int do_dump; 9862632Skrisstatic char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */ 9955163Sshinstatic char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */ 10055163Sshin 101118664Sumestatic int ifconfig __P((char *)); 10262632Skris#if 0 103118664Sumestatic int ifreconfig __P((char *)); 10462632Skris#endif 105118664Sumestatic int make_packet __P((struct ifinfo *)); 10655163Sshinstatic struct timeval *rtsol_check_timer __P((void)); 107118664Sumestatic void TIMEVAL_ADD __P((struct timeval *, struct timeval *, 108118664Sume struct timeval *)); 109118664Sumestatic void TIMEVAL_SUB __P((struct timeval *, struct timeval *, 110118664Sume struct timeval *)); 11155163Sshin 11262632Skrisstatic void rtsold_set_dump_file __P((void)); 113118664Sumestatic void usage __P((char *)); 11466776Skrisstatic char **autoifprobe __P((void)); 11555163Sshin 11655163Sshinint 11755163Sshinmain(argc, argv) 11855163Sshin int argc; 119118664Sume char **argv; 12055163Sshin{ 121118909Sume int s, ch, once = 0; 12255163Sshin struct timeval *timeout; 123118664Sume char *argv0, *opts; 124118909Sume fd_set *fdsetp, *selectfdp; 125118909Sume int fdmasks; 126118909Sume int maxfd; 127118909Sume int rtsock; 12855163Sshin 12955163Sshin /* 13055163Sshin * Initialization 13155163Sshin */ 13255163Sshin argv0 = argv[0]; 13355163Sshin 13455163Sshin /* get option */ 13555163Sshin if (argv0 && argv0[strlen(argv0) - 1] != 'd') { 13655163Sshin fflag = 1; 13755163Sshin once = 1; 138118661Sume opts = "adDO:"; 13955163Sshin } else 140118661Sume opts = "adDfm1O:"; 14155163Sshin 14255163Sshin while ((ch = getopt(argc, argv, opts)) != -1) { 14366776Skris switch (ch) { 14466776Skris case 'a': 14566776Skris aflag = 1; 14666776Skris break; 14766776Skris case 'd': 14866776Skris dflag = 1; 14966776Skris break; 15066776Skris case 'D': 15166776Skris dflag = 2; 15266776Skris break; 15366776Skris case 'f': 15466776Skris fflag = 1; 15566776Skris break; 15666776Skris case 'm': 15766776Skris mobile_node = 1; 15866776Skris break; 15966776Skris case '1': 16066776Skris once = 1; 16166776Skris break; 162118661Sume case 'O': 163118661Sume otherconf_script = optarg; 164118661Sume break; 16566776Skris default: 16666776Skris usage(argv0); 16766776Skris /*NOTREACHED*/ 16855163Sshin } 16955163Sshin } 17055163Sshin argc -= optind; 17155163Sshin argv += optind; 17266776Skris 17366776Skris if (aflag) { 17466776Skris int i; 17566776Skris 17666776Skris if (argc != 0) { 17766776Skris usage(argv0); 17866776Skris /*NOTREACHED*/ 17966776Skris } 18066776Skris 18166776Skris argv = autoifprobe(); 18266776Skris if (!argv) { 18366776Skris errx(1, "could not autoprobe interface"); 18466776Skris /*NOTREACHED*/ 18566776Skris } 18666776Skris 18766776Skris for (i = 0; argv[i]; i++) 18866776Skris ; 18966776Skris argc = i; 19066776Skris } 19166776Skris if (argc == 0) { 19255163Sshin usage(argv0); 19366776Skris /*NOTREACHED*/ 19466776Skris } 19555163Sshin 19655163Sshin /* set log level */ 19755163Sshin if (dflag == 0) 19855163Sshin log_upto = LOG_NOTICE; 19955163Sshin if (!fflag) { 20055163Sshin char *ident; 201118664Sume 20255163Sshin ident = strrchr(argv0, '/'); 20355163Sshin if (!ident) 20455163Sshin ident = argv0; 20555163Sshin else 20655163Sshin ident++; 20755163Sshin openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON); 20855163Sshin if (log_upto >= 0) 20955163Sshin setlogmask(LOG_UPTO(log_upto)); 21055163Sshin } 21155163Sshin 212118661Sume if (otherconf_script && *otherconf_script != '/') { 213118661Sume errx(1, "configuration script (%s) must be an absolute path", 214118661Sume otherconf_script); 215118661Sume } 216118661Sume 21762632Skris#ifndef HAVE_ARC4RANDOM 218118664Sume /* random value initialization */ 21955163Sshin srandom((u_long)time(NULL)); 22062632Skris#endif 22155163Sshin 22255163Sshin /* warn if accept_rtadv is down */ 22355163Sshin if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) 22455163Sshin warnx("kernel is configured not to accept RAs"); 22566776Skris /* warn if forwarding is up */ 22666776Skris if (getinet6sysctl(IPV6CTL_FORWARDING)) 22766776Skris warnx("kernel is configured as a router, not a host"); 22855163Sshin 22955163Sshin /* initialization to dump internal status to a file */ 23066776Skris if (signal(SIGUSR1, (void *)rtsold_set_dump_file) < 0) { 23155163Sshin errx(1, "failed to set signal for dump status"); 23266776Skris /*NOTREACHED*/ 23366776Skris } 23455163Sshin 23562632Skris /* 23662632Skris * Open a socket for sending RS and receiving RA. 23762632Skris * This should be done before calling ifinit(), since the function 23862632Skris * uses the socket. 23962632Skris */ 24066776Skris if ((s = sockopen()) < 0) { 24162632Skris errx(1, "failed to open a socket"); 24266776Skris /*NOTREACHED*/ 24366776Skris } 24478064Sume maxfd = s; 24578064Sume if ((rtsock = rtsock_open()) < 0) { 24678064Sume errx(1, "failed to open a socket"); 24778064Sume /*NOTREACHED*/ 24878064Sume } 24978064Sume if (rtsock > maxfd) 25078064Sume maxfd = rtsock; 25162632Skris 252118909Sume fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 253118909Sume if ((fdsetp = malloc(fdmasks)) == NULL) { 254118909Sume err(1, "malloc"); 255118909Sume /*NOTREACHED*/ 256118909Sume } 257118909Sume if ((selectfdp = malloc(fdmasks)) == NULL) { 258118909Sume err(1, "malloc"); 259118909Sume /*NOTREACHED*/ 260118909Sume } 261118909Sume 26255163Sshin /* configuration per interface */ 26366776Skris if (ifinit()) { 26455163Sshin errx(1, "failed to initilizatoin interfaces"); 26566776Skris /*NOTREACHED*/ 26666776Skris } 26755163Sshin while (argc--) { 26866776Skris if (ifconfig(*argv)) { 26962632Skris errx(1, "failed to initialize %s", *argv); 27066776Skris /*NOTREACHED*/ 27166776Skris } 27255163Sshin argv++; 27355163Sshin } 27455163Sshin 27555163Sshin /* setup for probing default routers */ 27666776Skris if (probe_init()) { 27755163Sshin errx(1, "failed to setup for probing routers"); 27866776Skris /*NOTREACHED*/ 27966776Skris } 28055163Sshin 28155163Sshin if (!fflag) 28255163Sshin daemon(0, 0); /* act as a daemon */ 28355163Sshin 28455163Sshin /* dump the current pid */ 28555163Sshin if (!once) { 28655163Sshin pid_t pid = getpid(); 28755163Sshin FILE *fp; 28855163Sshin 28955163Sshin if ((fp = fopen(pidfilename, "w")) == NULL) 290118660Sume warnmsg(LOG_ERR, __func__, 291118664Sume "failed to open a pid log file(%s): %s", 292118664Sume pidfilename, strerror(errno)); 29355163Sshin else { 29455163Sshin fprintf(fp, "%d\n", pid); 29555163Sshin fclose(fp); 29655163Sshin } 29755163Sshin } 29855163Sshin 299118909Sume memset(fdsetp, 0, fdmasks); 300118909Sume FD_SET(s, fdsetp); 301118909Sume FD_SET(rtsock, fdsetp); 30255163Sshin while (1) { /* main loop */ 30355163Sshin int e; 30455163Sshin 305118909Sume memcpy(selectfdp, fdsetp, fdmasks); 306118909Sume 30755163Sshin if (do_dump) { /* SIGUSR1 */ 30855163Sshin do_dump = 0; 30955163Sshin rtsold_dump_file(dumpfilename); 31055163Sshin } 311118664Sume 31255163Sshin timeout = rtsol_check_timer(); 31355163Sshin 31455163Sshin if (once) { 31555163Sshin struct ifinfo *ifi; 31655163Sshin 31755163Sshin /* if we have no timeout, we are done (or failed) */ 31855163Sshin if (timeout == NULL) 31955163Sshin break; 32055163Sshin 32155163Sshin /* if all interfaces have got RA packet, we are done */ 32255163Sshin for (ifi = iflist; ifi; ifi = ifi->next) { 32355163Sshin if (ifi->state != IFS_DOWN && ifi->racnt == 0) 32455163Sshin break; 32555163Sshin } 32655163Sshin if (ifi == NULL) 32755163Sshin break; 32855163Sshin } 329118909Sume e = select(maxfd + 1, selectfdp, NULL, NULL, timeout); 33078064Sume if (e < 1) { 33155163Sshin if (e < 0 && errno != EINTR) { 332118660Sume warnmsg(LOG_ERR, __func__, "select: %s", 333118664Sume strerror(errno)); 33455163Sshin } 33555163Sshin continue; 33655163Sshin } 33755163Sshin 33855163Sshin /* packet reception */ 339118909Sume if (FD_ISSET(rtsock, selectfdp)) 34078064Sume rtsock_input(rtsock); 341118909Sume if (FD_ISSET(s, selectfdp)) 34255163Sshin rtsol_input(s); 34355163Sshin } 34455163Sshin /* NOTREACHED */ 34555163Sshin 34655163Sshin return 0; 34755163Sshin} 34855163Sshin 34955163Sshinstatic int 35055163Sshinifconfig(char *ifname) 35155163Sshin{ 35255163Sshin struct ifinfo *ifinfo; 35355163Sshin struct sockaddr_dl *sdl; 35455163Sshin int flags; 35555163Sshin 35655163Sshin if ((sdl = if_nametosdl(ifname)) == NULL) { 357118660Sume warnmsg(LOG_ERR, __func__, 358118664Sume "failed to get link layer information for %s", ifname); 35955163Sshin return(-1); 36055163Sshin } 36155163Sshin if (find_ifinfo(sdl->sdl_index)) { 362118660Sume warnmsg(LOG_ERR, __func__, 363118664Sume "interface %s was already configured", ifname); 36462632Skris free(sdl); 36555163Sshin return(-1); 36655163Sshin } 36755163Sshin 36855163Sshin if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) { 369118660Sume warnmsg(LOG_ERR, __func__, "memory allocation failed"); 37062632Skris free(sdl); 37155163Sshin return(-1); 37255163Sshin } 37355163Sshin memset(ifinfo, 0, sizeof(*ifinfo)); 37455163Sshin ifinfo->sdl = sdl; 37555163Sshin 376118786Sume strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname)); 37755163Sshin 37855163Sshin /* construct a router solicitation message */ 37955163Sshin if (make_packet(ifinfo)) 38055163Sshin goto bad; 38155163Sshin 38255163Sshin /* 38355163Sshin * check if the interface is available. 38455163Sshin * also check if SIOCGIFMEDIA ioctl is OK on the interface. 38555163Sshin */ 38655163Sshin ifinfo->mediareqok = 1; 38755163Sshin ifinfo->active = interface_status(ifinfo); 38855163Sshin if (!ifinfo->mediareqok) { 38955163Sshin /* 39055163Sshin * probe routers periodically even if the link status 39155163Sshin * does not change. 39255163Sshin */ 39355163Sshin ifinfo->probeinterval = PROBE_INTERVAL; 39455163Sshin } 39555163Sshin 39655163Sshin /* activate interface: interface_up returns 0 on success */ 39755163Sshin flags = interface_up(ifinfo->ifname); 39855163Sshin if (flags == 0) 39955163Sshin ifinfo->state = IFS_DELAY; 40055163Sshin else if (flags == IFS_TENTATIVE) 40155163Sshin ifinfo->state = IFS_TENTATIVE; 40255163Sshin else 40355163Sshin ifinfo->state = IFS_DOWN; 40455163Sshin 40555163Sshin rtsol_timer_update(ifinfo); 40655163Sshin 40755163Sshin /* link into chain */ 40855163Sshin if (iflist) 40955163Sshin ifinfo->next = iflist; 41055163Sshin iflist = ifinfo; 41155163Sshin 41255163Sshin return(0); 41355163Sshin 414118664Sumebad: 41562632Skris free(ifinfo->sdl); 41655163Sshin free(ifinfo); 41755163Sshin return(-1); 41855163Sshin} 41955163Sshin 42062632Skris#if 0 42162632Skrisstatic int 42262632Skrisifreconfig(char *ifname) 42362632Skris{ 42462632Skris struct ifinfo *ifi, *prev; 42562632Skris int rv; 42662632Skris 42762632Skris prev = NULL; 42862632Skris for (ifi = iflist; ifi; ifi = ifi->next) { 42962632Skris if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0) 43062632Skris break; 43162632Skris prev = ifi; 43262632Skris } 43362632Skris prev->next = ifi->next; 43462632Skris 43562632Skris rv = ifconfig(ifname); 43662632Skris 43762632Skris /* reclaim it after ifconfig() in case ifname is pointer inside ifi */ 43862632Skris if (ifi->rs_data) 43962632Skris free(ifi->rs_data); 44062632Skris free(ifi->sdl); 44162632Skris free(ifi); 44262632Skris return rv; 44362632Skris} 44462632Skris#endif 44562632Skris 44655163Sshinstruct ifinfo * 44755163Sshinfind_ifinfo(int ifindex) 44855163Sshin{ 44955163Sshin struct ifinfo *ifi; 45055163Sshin 45155163Sshin for (ifi = iflist; ifi; ifi = ifi->next) 45255163Sshin if (ifi->sdl->sdl_index == ifindex) 45355163Sshin return(ifi); 45455163Sshin return(NULL); 45555163Sshin} 45655163Sshin 45755163Sshinstatic int 45855163Sshinmake_packet(struct ifinfo *ifinfo) 45955163Sshin{ 460118664Sume size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0; 461118664Sume struct nd_router_solicit *rs; 46255163Sshin char *buf; 46355163Sshin 46455163Sshin if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) { 465118660Sume warnmsg(LOG_INFO, __func__, 466118664Sume "link-layer address option has null length" 467118664Sume " on %s. Treat as not included.", ifinfo->ifname); 46855163Sshin } 46955163Sshin packlen += lladdroptlen; 47055163Sshin ifinfo->rs_datalen = packlen; 47155163Sshin 47255163Sshin /* allocate buffer */ 47355163Sshin if ((buf = malloc(packlen)) == NULL) { 474118660Sume warnmsg(LOG_ERR, __func__, 475118664Sume "memory allocation failed for %s", ifinfo->ifname); 47655163Sshin return(-1); 47755163Sshin } 47855163Sshin ifinfo->rs_data = buf; 47955163Sshin 48055163Sshin /* fill in the message */ 48155163Sshin rs = (struct nd_router_solicit *)buf; 48255163Sshin rs->nd_rs_type = ND_ROUTER_SOLICIT; 48355163Sshin rs->nd_rs_code = 0; 48455163Sshin rs->nd_rs_cksum = 0; 48555163Sshin rs->nd_rs_reserved = 0; 48655163Sshin buf += sizeof(*rs); 48755163Sshin 48855163Sshin /* fill in source link-layer address option */ 48955163Sshin if (lladdroptlen) 49055163Sshin lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf); 49155163Sshin 49255163Sshin return(0); 49355163Sshin} 49455163Sshin 49555163Sshinstatic struct timeval * 49655163Sshinrtsol_check_timer() 49755163Sshin{ 49855163Sshin static struct timeval returnval; 49955163Sshin struct timeval now, rtsol_timer; 50055163Sshin struct ifinfo *ifinfo; 50155163Sshin int flags; 50255163Sshin 50355163Sshin gettimeofday(&now, NULL); 50455163Sshin 50555163Sshin rtsol_timer = tm_max; 50655163Sshin 50755163Sshin for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { 50855163Sshin if (TIMEVAL_LEQ(ifinfo->expire, now)) { 50955163Sshin if (dflag > 1) 510118660Sume warnmsg(LOG_DEBUG, __func__, 511118664Sume "timer expiration on %s, " 512118664Sume "state = %d", ifinfo->ifname, 513118664Sume ifinfo->state); 51455163Sshin 51566776Skris switch (ifinfo->state) { 51655163Sshin case IFS_DOWN: 51755163Sshin case IFS_TENTATIVE: 51855163Sshin /* interface_up returns 0 on success */ 51955163Sshin flags = interface_up(ifinfo->ifname); 52055163Sshin if (flags == 0) 52155163Sshin ifinfo->state = IFS_DELAY; 52255163Sshin else if (flags == IFS_TENTATIVE) 52355163Sshin ifinfo->state = IFS_TENTATIVE; 52455163Sshin else 52555163Sshin ifinfo->state = IFS_DOWN; 52655163Sshin break; 52755163Sshin case IFS_IDLE: 52855163Sshin { 52955163Sshin int oldstatus = ifinfo->active; 53055163Sshin int probe = 0; 53155163Sshin 532118664Sume ifinfo->active = interface_status(ifinfo); 53355163Sshin 53455163Sshin if (oldstatus != ifinfo->active) { 535118660Sume warnmsg(LOG_DEBUG, __func__, 536118664Sume "%s status is changed" 537118664Sume " from %d to %d", 538118664Sume ifinfo->ifname, 539118664Sume oldstatus, ifinfo->active); 54055163Sshin probe = 1; 54155163Sshin ifinfo->state = IFS_DELAY; 542118664Sume } else if (ifinfo->probeinterval && 543118664Sume (ifinfo->probetimer -= 544118664Sume ifinfo->timer.tv_sec) <= 0) { 54555163Sshin /* probe timer expired */ 54655163Sshin ifinfo->probetimer = 547118664Sume ifinfo->probeinterval; 54855163Sshin probe = 1; 54955163Sshin ifinfo->state = IFS_PROBE; 55055163Sshin } 55155163Sshin 552118661Sume /* 553118661Sume * If we need a probe, clear the previous 554118661Sume * status wrt the "other" configuration. 555118661Sume */ 556118661Sume if (probe) 557118661Sume ifinfo->otherconfig = 0; 558118661Sume 55955163Sshin if (probe && mobile_node) 56055163Sshin defrouter_probe(ifinfo->sdl->sdl_index); 56155163Sshin break; 56255163Sshin } 56355163Sshin case IFS_DELAY: 56455163Sshin ifinfo->state = IFS_PROBE; 56555163Sshin sendpacket(ifinfo); 56655163Sshin break; 56755163Sshin case IFS_PROBE: 56855163Sshin if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 56955163Sshin sendpacket(ifinfo); 57055163Sshin else { 571118660Sume warnmsg(LOG_INFO, __func__, 572118664Sume "No answer after sending %d RSs", 573118664Sume ifinfo->probes); 57455163Sshin ifinfo->probes = 0; 57555163Sshin ifinfo->state = IFS_IDLE; 57655163Sshin } 57755163Sshin break; 57855163Sshin } 57955163Sshin rtsol_timer_update(ifinfo); 58055163Sshin } 58155163Sshin 58255163Sshin if (TIMEVAL_LT(ifinfo->expire, rtsol_timer)) 58355163Sshin rtsol_timer = ifinfo->expire; 58455163Sshin } 58555163Sshin 58655163Sshin if (TIMEVAL_EQ(rtsol_timer, tm_max)) { 587118660Sume warnmsg(LOG_DEBUG, __func__, "there is no timer"); 58855163Sshin return(NULL); 589118664Sume } else if (TIMEVAL_LT(rtsol_timer, now)) 59055163Sshin /* this may occur when the interval is too small */ 59155163Sshin returnval.tv_sec = returnval.tv_usec = 0; 59255163Sshin else 59355163Sshin TIMEVAL_SUB(&rtsol_timer, &now, &returnval); 59455163Sshin 59555163Sshin if (dflag > 1) 596118660Sume warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld", 597118664Sume (long)returnval.tv_sec, (long)returnval.tv_usec); 59855163Sshin 59955163Sshin return(&returnval); 60055163Sshin} 60155163Sshin 60255163Sshinvoid 60355163Sshinrtsol_timer_update(struct ifinfo *ifinfo) 60455163Sshin{ 60562632Skris#define MILLION 1000000 60662632Skris#define DADRETRY 10 /* XXX: adhoc */ 60755163Sshin long interval; 60855163Sshin struct timeval now; 60955163Sshin 61055163Sshin bzero(&ifinfo->timer, sizeof(ifinfo->timer)); 61155163Sshin 61255163Sshin switch (ifinfo->state) { 61355163Sshin case IFS_DOWN: 61455163Sshin case IFS_TENTATIVE: 61555163Sshin if (++ifinfo->dadcount > DADRETRY) { 61655163Sshin ifinfo->dadcount = 0; 61755163Sshin ifinfo->timer.tv_sec = PROBE_INTERVAL; 618118664Sume } else 61955163Sshin ifinfo->timer.tv_sec = 1; 62055163Sshin break; 62155163Sshin case IFS_IDLE: 62255163Sshin if (mobile_node) { 623118664Sume /* XXX should be configurable */ 62455163Sshin ifinfo->timer.tv_sec = 3; 62555163Sshin } 62655163Sshin else 62755163Sshin ifinfo->timer = tm_max; /* stop timer(valid?) */ 62855163Sshin break; 62955163Sshin case IFS_DELAY: 63062632Skris#ifndef HAVE_ARC4RANDOM 63155163Sshin interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 63262632Skris#else 63362632Skris interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 63462632Skris#endif 63555163Sshin ifinfo->timer.tv_sec = interval / MILLION; 63655163Sshin ifinfo->timer.tv_usec = interval % MILLION; 63755163Sshin break; 63855163Sshin case IFS_PROBE: 63978064Sume if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 64078064Sume ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; 64178064Sume else { 64278064Sume /* 64378064Sume * After sending MAX_RTR_SOLICITATIONS solicitations, 64478064Sume * we're just waiting for possible replies; there 64578064Sume * will be no more solicatation. Thus, we change 64678064Sume * the timer value to MAX_RTR_SOLICITATION_DELAY based 64778064Sume * on RFC 2461, Section 6.3.7. 64878064Sume */ 64978064Sume ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; 65078064Sume } 65155163Sshin break; 65255163Sshin default: 653118660Sume warnmsg(LOG_ERR, __func__, 654118664Sume "illegal interface state(%d) on %s", 655118664Sume ifinfo->state, ifinfo->ifname); 65655163Sshin return; 65755163Sshin } 65855163Sshin 65955163Sshin /* reset the timer */ 66055163Sshin if (TIMEVAL_EQ(ifinfo->timer, tm_max)) { 66155163Sshin ifinfo->expire = tm_max; 662118660Sume warnmsg(LOG_DEBUG, __func__, 663118664Sume "stop timer for %s", ifinfo->ifname); 664118664Sume } else { 66555163Sshin gettimeofday(&now, NULL); 66655163Sshin TIMEVAL_ADD(&now, &ifinfo->timer, &ifinfo->expire); 66755163Sshin 66855163Sshin if (dflag > 1) 669118660Sume warnmsg(LOG_DEBUG, __func__, 670118664Sume "set timer for %s to %d:%d", ifinfo->ifname, 671118664Sume (int)ifinfo->timer.tv_sec, 672118664Sume (int)ifinfo->timer.tv_usec); 67355163Sshin } 67455163Sshin 67555163Sshin#undef MILLION 67655163Sshin} 67755163Sshin 67855163Sshin/* timer related utility functions */ 67962632Skris#define MILLION 1000000 68055163Sshin 68155163Sshin/* result = a + b */ 68255163Sshinstatic void 68355163SshinTIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result) 68455163Sshin{ 68555163Sshin long l; 68655163Sshin 68755163Sshin if ((l = a->tv_usec + b->tv_usec) < MILLION) { 68855163Sshin result->tv_usec = l; 68955163Sshin result->tv_sec = a->tv_sec + b->tv_sec; 690118664Sume } else { 69155163Sshin result->tv_usec = l - MILLION; 69255163Sshin result->tv_sec = a->tv_sec + b->tv_sec + 1; 69355163Sshin } 69455163Sshin} 69555163Sshin 69655163Sshin/* 69755163Sshin * result = a - b 69855163Sshin * XXX: this function assumes that a >= b. 69955163Sshin */ 70055163Sshinvoid 70155163SshinTIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result) 70255163Sshin{ 70355163Sshin long l; 70455163Sshin 70555163Sshin if ((l = a->tv_usec - b->tv_usec) >= 0) { 70655163Sshin result->tv_usec = l; 70755163Sshin result->tv_sec = a->tv_sec - b->tv_sec; 708118664Sume } else { 70955163Sshin result->tv_usec = MILLION + l; 71055163Sshin result->tv_sec = a->tv_sec - b->tv_sec - 1; 71155163Sshin } 71255163Sshin} 71355163Sshin 71455163Sshinstatic void 71555163Sshinrtsold_set_dump_file() 71655163Sshin{ 71755163Sshin do_dump = 1; 71855163Sshin} 71955163Sshin 72055163Sshinstatic void 72155163Sshinusage(char *progname) 72255163Sshin{ 72366776Skris if (progname && progname[strlen(progname) - 1] != 'd') { 72466776Skris fprintf(stderr, "usage: rtsol [-dD] interfaces...\n"); 72566776Skris fprintf(stderr, "usage: rtsol [-dD] -a\n"); 72666776Skris } else { 72766776Skris fprintf(stderr, "usage: rtsold [-adDfm1] interfaces...\n"); 72866776Skris fprintf(stderr, "usage: rtsold [-dDfm1] -a\n"); 72966776Skris } 73055163Sshin exit(1); 73155163Sshin} 73255163Sshin 73355163Sshinvoid 73455163Sshin#if __STDC__ 73555163Sshinwarnmsg(int priority, const char *func, const char *msg, ...) 73655163Sshin#else 73755163Sshinwarnmsg(priority, func, msg, va_alist) 73855163Sshin int priority; 73955163Sshin const char *func; 74055163Sshin const char *msg; 74155163Sshin va_dcl 74255163Sshin#endif 74355163Sshin{ 74455163Sshin va_list ap; 74555163Sshin char buf[BUFSIZ]; 74655163Sshin 74755163Sshin va_start(ap, msg); 74855163Sshin if (fflag) { 74955163Sshin if (priority <= log_upto) { 75055163Sshin (void)vfprintf(stderr, msg, ap); 75155163Sshin (void)fprintf(stderr, "\n"); 75255163Sshin } 75355163Sshin } else { 75455163Sshin snprintf(buf, sizeof(buf), "<%s> %s", func, msg); 75566776Skris msg = buf; 75666776Skris vsyslog(priority, msg, ap); 75755163Sshin } 75855163Sshin va_end(ap); 75955163Sshin} 76066776Skris 76166776Skrisstatic char ** 76266776Skrisautoifprobe() 76366776Skris{ 76466776Skris static char ifname[IFNAMSIZ + 1]; 76566776Skris static char *argv[2]; 76666776Skris struct ifaddrs *ifap, *ifa, *target; 76766776Skris 76866776Skris if (getifaddrs(&ifap) != 0) 76966776Skris return NULL; 77066776Skris 77166776Skris target = NULL; 77266776Skris /* find an ethernet */ 77366776Skris for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 77466776Skris if ((ifa->ifa_flags & IFF_UP) == 0) 77566776Skris continue; 77666776Skris if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) 77766776Skris continue; 77866776Skris if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) 77966776Skris continue; 78066776Skris if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 78166776Skris continue; 78266776Skris 78366776Skris if (ifa->ifa_addr->sa_family != AF_INET6) 78466776Skris continue; 78566776Skris 78666776Skris if (target && strcmp(target->ifa_name, ifa->ifa_name) == 0) 78766776Skris continue; 78866776Skris 78966776Skris if (!target) 79066776Skris target = ifa; 79166776Skris else { 79266776Skris /* if we find multiple candidates, failure. */ 79366776Skris if (dflag > 1) 79466776Skris warnx("multiple interfaces found"); 79566776Skris target = NULL; 79666776Skris break; 79766776Skris } 79866776Skris } 79966776Skris 80066776Skris if (target) { 80166776Skris strncpy(ifname, target->ifa_name, sizeof(ifname) - 1); 80266776Skris ifname[sizeof(ifname) - 1] = '\0'; 80366776Skris argv[0] = ifname; 80466776Skris argv[1] = NULL; 80566776Skris 80666776Skris if (dflag > 0) 80766776Skris warnx("probing %s", argv[0]); 80866776Skris } 80966776Skris freeifaddrs(ifap); 81066776Skris if (target) 81166776Skris return argv; 81266776Skris else 81366776Skris return (char **)NULL; 81466776Skris} 815