rtsold.c revision 147150
139214Sgibbs/* $KAME: rtsold.c,v 1.67 2003/05/17 18:16:15 itojun Exp $ */ 2172093Sken 339214Sgibbs/* 439214Sgibbs * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 539214Sgibbs * All rights reserved. 639214Sgibbs * 739214Sgibbs * Redistribution and use in source and binary forms, with or without 839214Sgibbs * modification, are permitted provided that the following conditions 939214Sgibbs * are met: 1039214Sgibbs * 1. Redistributions of source code must retain the above copyright 1139214Sgibbs * notice, this list of conditions and the following disclaimer. 1239214Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1339214Sgibbs * notice, this list of conditions and the following disclaimer in the 1439214Sgibbs * documentation and/or other materials provided with the distribution. 1539214Sgibbs * 3. Neither the name of the project nor the names of its contributors 1639214Sgibbs * may be used to endorse or promote products derived from this software 1739214Sgibbs * without specific prior written permission. 1839214Sgibbs * 1939214Sgibbs * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2039214Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2139214Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2239214Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2339214Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2439214Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2539214Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2639214Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2739214Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2850476Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2939214Sgibbs * SUCH DAMAGE. 30271058Sgavin * 3139214Sgibbs * $FreeBSD: head/usr.sbin/rtsold/rtsold.c 147150 2005-06-08 23:51:42Z suz $ 3261229Sken */ 3339214Sgibbs 3439214Sgibbs#include <sys/types.h> 3539214Sgibbs#include <sys/time.h> 3639214Sgibbs#include <sys/socket.h> 3768960Sru#include <sys/param.h> 3861229Sken 3946938Sken#include <net/if.h> 4039214Sgibbs#include <net/if_dl.h> 4139214Sgibbs 4268960Sru#include <netinet/in.h> 4361229Sken#include <netinet/icmp6.h> 44260177Sscottl 4539214Sgibbs#include <signal.h> 4668960Sru#include <unistd.h> 4761229Sken#include <syslog.h> 4846938Sken#include <string.h> 4939214Sgibbs#include <stdlib.h> 5039214Sgibbs#include <stdio.h> 5168960Sru#include <errno.h> 5261229Sken#include <err.h> 5346938Sken#include <stdarg.h> 5439214Sgibbs#include <ifaddrs.h> 5568960Sru#ifdef HAVE_POLL_H 5679754Sdd#include <poll.h> 5746938Sken#endif 5839214Sgibbs 5939214Sgibbs#include "rtsold.h" 6039214Sgibbs 6139214Sgibbsstruct ifinfo *iflist; 6268960Srustruct timeval tm_max = {0x7fffffff, 0x7fffffff}; 63195534Sscottlstatic int log_upto = 999; 64195534Sscottlstatic int fflag = 0; 65195534Sscottlstatic int Fflag = 0; /* force setting sysctl parameters */ 66202694Smav 67195534Sscottlint aflag = 0; 68161506Skenint dflag = 0; 69161506Sken 70161506Skenchar *otherconf_script; 71161506Sken 72161506Sken/* protocol constants */ 73161506Sken#define MAX_RTR_SOLICITATION_DELAY 1 /* second */ 74161506Sken#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ 75172093Sken#define MAX_RTR_SOLICITATIONS 3 /* times */ 76172093Sken 77172093Sken/* 78172093Sken * implementation dependent constants in seconds 79172093Sken * XXX: should be configurable 80172093Sken */ 81172093Sken#define PROBE_INTERVAL 60 82172093Sken 83172093Skenint main __P((int, char **)); 84172093Sken 8561229Sken/* static variables and functions */ 8646938Skenstatic int mobile_node = 0; 8739214Sgibbs#ifndef SMALL 8868960Srustatic int do_dump; 8961229Skenstatic char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */ 9046938Sken#endif 9139214Sgibbs#if 1 9268960Srustatic char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */ 93103033Smdodd#endif 94103033Smdodd 95103033Smdodd#if 0 96103033Smdoddstatic int ifreconfig __P((char *)); 9761229Sken#endif 9846938Skenstatic int make_packet __P((struct ifinfo *)); 9939214Sgibbsstatic struct timeval *rtsol_check_timer __P((void)); 10068960Sru 10161229Sken#ifndef SMALL 10289515Skenstatic void rtsold_set_dump_file __P((int)); 10368960Sru#endif 10461229Skenstatic void usage __P((char *)); 10589515Sken 10668960Sruint 10761229Skenmain(int argc, char **argv) 10846938Sken{ 10939214Sgibbs int s, ch, once = 0; 11039214Sgibbs struct timeval *timeout; 11139214Sgibbs char *argv0, *opts; 11239214Sgibbs#ifdef HAVE_POLL_H 11368960Sru struct pollfd set[2]; 11461229Sken#else 11546938Sken fd_set *fdsetp, *selectfdp; 11639214Sgibbs int fdmasks; 11781773Sru int maxfd; 11841466Sbillf#endif 11964382Skbyanc int rtsock; 12039214Sgibbs 12168960Sru /* 12261229Sken * Initialization 12346938Sken */ 12439214Sgibbs argv0 = argv[0]; 125196831Smav 12639214Sgibbs /* get option */ 127207498Smav if (argv0 && argv0[strlen(argv0) - 1] != 'd') { 128207498Smav fflag = 1; 12939214Sgibbs once = 1; 13039214Sgibbs opts = "adDFO:"; 13139214Sgibbs } else 132196831Smav opts = "adDfFm1O:"; 13339214Sgibbs 13468960Sru while ((ch = getopt(argc, argv, opts)) != -1) { 135216088Sken switch (ch) { 136216088Sken case 'a': 137216088Sken aflag = 1; 138216088Sken break; 139216088Sken case 'd': 140216088Sken dflag = 1; 141216088Sken break; 142216088Sken case 'D': 143216088Sken dflag = 2; 144216088Sken break; 145216088Sken case 'f': 146216088Sken fflag = 1; 147216088Sken break; 148216088Sken case 'F': 149216088Sken Fflag = 1; 150216088Sken break; 151216088Sken case 'm': 152216088Sken mobile_node = 1; 153216088Sken break; 154216088Sken case '1': 155216088Sken once = 1; 156216088Sken break; 157216088Sken case 'O': 158216088Sken otherconf_script = optarg; 159216088Sken break; 160216088Sken default: 161216088Sken usage(argv0); 162216088Sken /*NOTREACHED*/ 163216088Sken } 164216088Sken } 165216088Sken argc -= optind; 166216088Sken argv += optind; 167216088Sken 168216088Sken if ((!aflag && argc == 0) || (aflag && argc != 0)) { 169216088Sken usage(argv0); 170216088Sken /*NOTREACHED*/ 171216088Sken } 17261229Sken 17339214Sgibbs /* set log level */ 174107966Snjl if (dflag == 0) 17539214Sgibbs log_upto = LOG_NOTICE; 17639214Sgibbs if (!fflag) { 177107966Snjl char *ident; 17839932Sken 179236555Smav ident = strrchr(argv0, '/'); 18039214Sgibbs if (!ident) 18168960Sru ident = argv0; 18261229Sken else 18346938Sken ident++; 18446581Sken openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON); 18546581Sken if (log_upto >= 0) 18646581Sken setlogmask(LOG_UPTO(log_upto)); 18746581Sken } 18868960Sru 18961229Sken if (otherconf_script && *otherconf_script != '/') { 19046938Sken errx(1, "configuration script (%s) must be an absolute path", 19146581Sken otherconf_script); 19246581Sken } 19346581Sken 194199821Smav#ifndef HAVE_ARC4RANDOM 19546581Sken /* random value initialization */ 19646581Sken srandom((u_long)time(NULL)); 19746581Sken#endif 19846581Sken 19946581Sken if (Fflag) { 20046581Sken setinet6sysctl(IPV6CTL_ACCEPT_RTADV, 1); 20146581Sken setinet6sysctl(IPV6CTL_FORWARDING, 0); 20268960Sru } else { 20361229Sken /* warn if accept_rtadv is down */ 20460767Sken if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) 20560767Sken warnx("kernel is configured not to accept RAs"); 20660767Sken /* warn if forwarding is up */ 207144134Sken if (getinet6sysctl(IPV6CTL_FORWARDING)) 20860767Sken warnx("kernel is configured as a router, not a host"); 20960767Sken } 21068960Sru 211255307Sbryanv#ifndef SMALL 212255307Sbryanv /* initialization to dump internal status to a file */ 213255307Sbryanv signal(SIGUSR1, rtsold_set_dump_file); 214255307Sbryanv#endif 215255307Sbryanv 216255307Sbryanv if (!fflag) 217255307Sbryanv daemon(0, 0); /* act as a daemon */ 218255307Sbryanv 219255307Sbryanv /* 220255307Sbryanv * Open a socket for sending RS and receiving RA. 221255307Sbryanv * This should be done before calling ifinit(), since the function 222255307Sbryanv * uses the socket. 223255307Sbryanv */ 224199079Smav if ((s = sockopen()) < 0) { 225199079Smav warnmsg(LOG_ERR, __func__, "failed to open a socket"); 226199079Smav exit(1); 227199079Smav /*NOTREACHED*/ 228199079Smav } 229199079Smav#ifdef HAVE_POLL_H 230199079Smav set[0].fd = s; 231199079Smav set[0].events = POLLIN; 232199079Smav#else 233199079Smav maxfd = s; 234199079Smav#endif 235199079Smav 236199079Smav#ifdef HAVE_POLL_H 237199079Smav set[1].fd = -1; 238227961Semaste#endif 239227961Semaste 240227961Semaste if ((rtsock = rtsock_open()) < 0) { 241227961Semaste warnmsg(LOG_ERR, __func__, "failed to open a socket"); 242227961Semaste exit(1); 243227961Semaste /*NOTREACHED*/ 244227961Semaste } 245249115Ssmh#ifdef HAVE_POLL_H 246249115Ssmh set[1].fd = rtsock; 247249115Ssmh set[1].events = POLLIN; 248249115Ssmh#else 249249115Ssmh if (rtsock > maxfd) 250249115Ssmh maxfd = rtsock; 251249115Ssmh#endif 252249115Ssmh 253249115Ssmh#ifndef HAVE_POLL_H 254249115Ssmh fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 255249115Ssmh if ((fdsetp = malloc(fdmasks)) == NULL) { 256249115Ssmh err(1, "malloc"); 257249115Ssmh /*NOTREACHED*/ 258249115Ssmh } 259249115Ssmh if ((selectfdp = malloc(fdmasks)) == NULL) { 260249895Ssmh err(1, "malloc"); 261249895Ssmh /*NOTREACHED*/ 262249895Ssmh } 263249895Ssmh#endif 264249895Ssmh 265249895Ssmh /* configuration per interface */ 266249895Ssmh if (ifinit()) { 267249895Ssmh warnmsg(LOG_ERR, __func__, 268249895Ssmh "failed to initialization interfaces"); 269249895Ssmh exit(1); 270249895Ssmh /*NOTREACHED*/ 271249895Ssmh } 272268700Smav if (aflag) 273268700Smav argv = autoifprobe(); 274268700Smav while (argv && *argv) { 275268700Smav if (ifconfig(*argv)) { 276268700Smav warnmsg(LOG_ERR, __func__, 277268700Smav "failed to initialize %s", *argv); 278268700Smav exit(1); 279268700Smav /*NOTREACHED*/ 280268700Smav } 281268700Smav argv++; 282268700Smav } 283268700Smav 284268700Smav /* setup for probing default routers */ 285268700Smav if (probe_init()) { 286268700Smav warnmsg(LOG_ERR, __func__, 28761229Sken "failed to setup for probing routers"); 28839214Sgibbs exit(1); 28999501Scharnier /*NOTREACHED*/ 29068960Sru } 29199501Scharnier 29261229Sken#if 1 29339214Sgibbs /* dump the current pid */ 29439214Sgibbs if (!once) { 29599501Scharnier pid_t pid = getpid(); 29668960Sru FILE *fp; 29799501Scharnier 298131488Sru if ((fp = fopen(pidfilename, "w")) == NULL) 299131488Sru warnmsg(LOG_ERR, __func__, 30046581Sken "failed to open a pid log file(%s): %s", 30139214Sgibbs pidfilename, strerror(errno)); 30239214Sgibbs else { 30399501Scharnier fprintf(fp, "%d\n", pid); 30468960Sru fclose(fp); 30599501Scharnier } 306131488Sru } 307131488Sru#endif 30870152Sru 30946938Sken#ifndef HAVE_POLL_H 31046938Sken memset(fdsetp, 0, fdmasks); 31146938Sken FD_SET(s, fdsetp); 312131488Sru FD_SET(rtsock, fdsetp); 313131488Sru#endif 31446938Sken while (1) { /* main loop */ 31546938Sken int e; 31646938Sken 31746938Sken#ifndef HAVE_POLL_H 318131488Sru memcpy(selectfdp, fdsetp, fdmasks); 319131488Sru#endif 32046938Sken 32146938Sken#ifndef SMALL 32246938Sken if (do_dump) { /* SIGUSR1 */ 32346938Sken do_dump = 0; 32446938Sken rtsold_dump_file(dumpfilename); 325131488Sru } 326131488Sru#endif 32746938Sken 32846938Sken timeout = rtsol_check_timer(); 32946938Sken 33046938Sken if (once) { 331131488Sru struct ifinfo *ifi; 332131488Sru 33346938Sken /* if we have no timeout, we are done (or failed) */ 33446938Sken if (timeout == NULL) 33546938Sken break; 33646938Sken 33746938Sken /* if all interfaces have got RA packet, we are done */ 33860767Sken for (ifi = iflist; ifi; ifi = ifi->next) { 33946938Sken if (ifi->state != IFS_DOWN && ifi->racnt == 0) 34046938Sken break; 34168960Sru } 34246938Sken if (ifi == NULL) 34370152Sru break; 34439214Sgibbs } 345131488Sru#ifdef HAVE_POLL_H 346131488Sru e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFTIM); 34770152Sru#else 34839214Sgibbs e = select(maxfd + 1, selectfdp, NULL, NULL, timeout); 34939214Sgibbs#endif 35039214Sgibbs if (e < 1) { 351131488Sru if (e < 0 && errno != EINTR) { 352131488Sru warnmsg(LOG_ERR, __func__, "select: %s", 35370152Sru strerror(errno)); 354131488Sru } 355131488Sru continue; 35639214Sgibbs } 35739214Sgibbs 35839214Sgibbs /* packet reception */ 35939214Sgibbs#ifdef HAVE_POLL_H 360131488Sru if (set[1].revents & POLLIN) 36139214Sgibbs#else 362131488Sru if (FD_ISSET(rtsock, selectfdp)) 363131488Sru#endif 36439214Sgibbs rtsock_input(rtsock); 36539214Sgibbs#ifdef HAVE_POLL_H 366131488Sru if (set[0].revents & POLLIN) 36739214Sgibbs#else 36839214Sgibbs if (FD_ISSET(s, selectfdp)) 36939214Sgibbs#endif 37039214Sgibbs rtsol_input(s); 37139406Sken } 37239214Sgibbs /* NOTREACHED */ 37361229Sken 37439214Sgibbs return 0; 37539214Sgibbs} 37639214Sgibbs 37739214Sgibbsint 37839214Sgibbsifconfig(char *ifname) 37939214Sgibbs{ 380260177Sscottl struct ifinfo *ifinfo; 381260177Sscottl struct sockaddr_dl *sdl; 382260177Sscottl int flags; 383260177Sscottl 38461229Sken if ((sdl = if_nametosdl(ifname)) == NULL) { 38539214Sgibbs warnmsg(LOG_ERR, __func__, 38639214Sgibbs "failed to get link layer information for %s", ifname); 38761229Sken return(-1); 38839214Sgibbs } 38999501Scharnier if (find_ifinfo(sdl->sdl_index)) { 39068960Sru warnmsg(LOG_ERR, __func__, 39199501Scharnier "interface %s was already configured", ifname); 39261229Sken free(sdl); 393131488Sru return(-1); 394131488Sru } 39568960Sru 39639214Sgibbs if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) { 397131488Sru warnmsg(LOG_ERR, __func__, "memory allocation failed"); 398131488Sru free(sdl); 39939214Sgibbs return(-1); 40070152Sru } 40139214Sgibbs memset(ifinfo, 0, sizeof(*ifinfo)); 40239214Sgibbs ifinfo->sdl = sdl; 40339214Sgibbs 404131488Sru strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname)); 405131488Sru 40668960Sru /* construct a router solicitation message */ 40739214Sgibbs if (make_packet(ifinfo)) 40839214Sgibbs goto bad; 40939214Sgibbs 41039214Sgibbs /* set link ID of this interface. */ 41139214Sgibbs#ifdef HAVE_SCOPELIB 412195534Sscottl if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid)) 413195534Sscottl goto bad; 414161506Sken#else 415161506Sken /* XXX: assume interface IDs as link IDs */ 416161506Sken ifinfo->linkid = ifinfo->sdl->sdl_index; 417161506Sken#endif 418161506Sken 419161506Sken /* 420162395Sru * check if the interface is available. 421161506Sken * also check if SIOCGIFMEDIA ioctl is OK on the interface. 422161506Sken */ 423161506Sken ifinfo->mediareqok = 1; 424249373Sjoel ifinfo->active = interface_status(ifinfo); 425161506Sken if (!ifinfo->mediareqok) { 426161506Sken /* 427161506Sken * probe routers periodically even if the link status 428161506Sken * does not change. 429161506Sken */ 430161506Sken ifinfo->probeinterval = PROBE_INTERVAL; 431161506Sken } 432161506Sken 433161506Sken /* activate interface: interface_up returns 0 on success */ 434161506Sken flags = interface_up(ifinfo->ifname); 435161506Sken if (flags == 0) 436161506Sken ifinfo->state = IFS_DELAY; 437161506Sken else if (flags == IFS_TENTATIVE) 438161506Sken ifinfo->state = IFS_TENTATIVE; 439161506Sken else 440161506Sken ifinfo->state = IFS_DOWN; 441161506Sken 442161506Sken rtsol_timer_update(ifinfo); 443161506Sken 444161506Sken /* link into chain */ 445172093Sken if (iflist) 446172093Sken ifinfo->next = iflist; 447172093Sken iflist = ifinfo; 448172093Sken 449172093Sken return(0); 450172093Sken 451172093Skenbad: 452172093Sken free(ifinfo->sdl); 453172093Sken free(ifinfo); 454172093Sken return(-1); 455172093Sken} 456172093Sken 457172093Skenvoid 458172093Skeniflist_init(void) 459172093Sken{ 460172093Sken struct ifinfo *ifi, *next; 461172093Sken 462172093Sken for (ifi = iflist; ifi; ifi = next) { 463172093Sken next = ifi->next; 464172093Sken if (ifi->sdl) 465172093Sken free(ifi->sdl); 466172093Sken if (ifi->rs_data) 467172093Sken free(ifi->rs_data); 468172093Sken free(ifi); 469172093Sken iflist = NULL; 470172093Sken } 471172093Sken} 472172093Sken 473172093Sken#if 0 474172093Skenstatic int 475172093Skenifreconfig(char *ifname) 476172093Sken{ 477172093Sken struct ifinfo *ifi, *prev; 478172093Sken int rv; 479172093Sken 480172093Sken prev = NULL; 481172093Sken for (ifi = iflist; ifi; ifi = ifi->next) { 482172093Sken if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0) 483172093Sken break; 484172093Sken prev = ifi; 48561229Sken } 48639214Sgibbs prev->next = ifi->next; 48739214Sgibbs 48861229Sken rv = ifconfig(ifname); 48939214Sgibbs 49039214Sgibbs /* reclaim it after ifconfig() in case ifname is pointer inside ifi */ 491103033Smdodd if (ifi->rs_data) 492103033Smdodd free(ifi->rs_data); 493103033Smdodd free(ifi->sdl); 49461229Sken free(ifi); 49539214Sgibbs return rv; 496103033Smdodd} 49761229Sken#endif 49889515Sken 49989515Skenstruct ifinfo * 50089515Skenfind_ifinfo(int ifindex) 501131488Sru{ 502131488Sru struct ifinfo *ifi; 503131488Sru 504131488Sru for (ifi = iflist; ifi; ifi = ifi->next) 505141846Sru if (ifi->sdl->sdl_index == ifindex) 50661229Sken return(ifi); 50789515Sken return(NULL); 50889515Sken} 50989515Sken 51041962Smjacobstatic int 51141962Smjacobmake_packet(struct ifinfo *ifinfo) 51257668Ssheldonh{ 51357668Ssheldonh size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0; 51441962Smjacob struct nd_router_solicit *rs; 51561229Sken char *buf; 51639214Sgibbs 51739214Sgibbs if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) { 51839214Sgibbs warnmsg(LOG_INFO, __func__, 51970152Sru "link-layer address option has null length" 52039214Sgibbs " on %s. Treat as not included.", ifinfo->ifname); 52139214Sgibbs } 52239214Sgibbs packlen += lladdroptlen; 52339214Sgibbs ifinfo->rs_datalen = packlen; 52439214Sgibbs 52539214Sgibbs /* allocate buffer */ 52639214Sgibbs if ((buf = malloc(packlen)) == NULL) { 527131488Sru warnmsg(LOG_ERR, __func__, 528131488Sru "memory allocation failed for %s", ifinfo->ifname); 529131488Sru return(-1); 530131488Sru } 531131488Sru ifinfo->rs_data = buf; 532131488Sru 533141846Sru /* fill in the message */ 53439214Sgibbs rs = (struct nd_router_solicit *)buf; 535141846Sru rs->nd_rs_type = ND_ROUTER_SOLICIT; 53699501Scharnier rs->nd_rs_code = 0; 53768960Sru rs->nd_rs_cksum = 0; 53899501Scharnier rs->nd_rs_reserved = 0; 53939214Sgibbs buf += sizeof(*rs); 540141846Sru 54139214Sgibbs /* fill in source link-layer address option */ 54268960Sru if (lladdroptlen) 54339214Sgibbs lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf); 54439214Sgibbs 545131488Sru return(0); 546131488Sru} 54739214Sgibbs 54839214Sgibbsstatic struct timeval * 54939214Sgibbsrtsol_check_timer(void) 55039214Sgibbs{ 55139214Sgibbs static struct timeval returnval; 55239214Sgibbs struct timeval now, rtsol_timer; 55339214Sgibbs struct ifinfo *ifinfo; 55439214Sgibbs int flags; 55539214Sgibbs 55639214Sgibbs gettimeofday(&now, NULL); 55768960Sru 55839214Sgibbs rtsol_timer = tm_max; 55939214Sgibbs 560237452Sken for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { 561237452Sken if (timercmp(&ifinfo->expire, &now, <=)) { 56261229Sken if (dflag > 1) 563131488Sru warnmsg(LOG_DEBUG, __func__, 564131488Sru "timer expiration on %s, " 56539214Sgibbs "state = %d", ifinfo->ifname, 56639214Sgibbs ifinfo->state); 56739214Sgibbs 56839214Sgibbs switch (ifinfo->state) { 56961229Sken case IFS_DOWN: 57061229Sken case IFS_TENTATIVE: 57161229Sken /* interface_up returns 0 on success */ 57261229Sken flags = interface_up(ifinfo->ifname); 57370152Sru if (flags == 0) 57446581Sken ifinfo->state = IFS_DELAY; 57539214Sgibbs else if (flags == IFS_TENTATIVE) 57664382Skbyanc ifinfo->state = IFS_TENTATIVE; 57764382Skbyanc else 57839214Sgibbs ifinfo->state = IFS_DOWN; 579131488Sru break; 580131488Sru case IFS_IDLE: 58164382Skbyanc { 58264382Skbyanc int oldstatus = ifinfo->active; 58364382Skbyanc int probe = 0; 58464382Skbyanc 58568960Sru ifinfo->active = interface_status(ifinfo); 586131488Sru 587131488Sru if (oldstatus != ifinfo->active) { 58868960Sru warnmsg(LOG_DEBUG, __func__, 58964382Skbyanc "%s status is changed" 59064382Skbyanc " from %d to %d", 59164382Skbyanc ifinfo->ifname, 59239214Sgibbs oldstatus, ifinfo->active); 59339214Sgibbs probe = 1; 594131488Sru ifinfo->state = IFS_DELAY; 595131488Sru } else if (ifinfo->probeinterval && 59664391Skbyanc (ifinfo->probetimer -= 59764391Skbyanc ifinfo->timer.tv_sec) <= 0) { 59841466Sbillf /* probe timer expired */ 599131488Sru ifinfo->probetimer = 600131488Sru ifinfo->probeinterval; 60139214Sgibbs probe = 1; 60239422Sken ifinfo->state = IFS_PROBE; 60339422Sken } 60439214Sgibbs 60539422Sken /* 60639214Sgibbs * If we need a probe, clear the previous 60739422Sken * status wrt the "other" configuration. 60839214Sgibbs */ 60939214Sgibbs if (probe) 61039214Sgibbs ifinfo->otherconfig = 0; 61139214Sgibbs 61261229Sken if (probe && mobile_node) 613196831Smav defrouter_probe(ifinfo); 61461229Sken break; 61561229Sken } 61639214Sgibbs case IFS_DELAY: 61739214Sgibbs ifinfo->state = IFS_PROBE; 618196831Smav sendpacket(ifinfo); 619196831Smav break; 620196831Smav case IFS_PROBE: 621131488Sru if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 622131488Sru sendpacket(ifinfo); 623131488Sru else { 62439214Sgibbs warnmsg(LOG_INFO, __func__, 62560767Sken "No answer after sending %d RSs", 626210702Sjoel ifinfo->probes); 62739214Sgibbs ifinfo->probes = 0; 62839214Sgibbs ifinfo->state = IFS_IDLE; 62939214Sgibbs } 63039214Sgibbs break; 63170152Sru } 632196831Smav rtsol_timer_update(ifinfo); 633196831Smav } 634196831Smav 635196831Smav if (timercmp(&ifinfo->expire, &rtsol_timer, <)) 63639214Sgibbs rtsol_timer = ifinfo->expire; 637131488Sru } 638196831Smav 639207498Smav if (timercmp(&rtsol_timer, &tm_max, ==)) { 640207498Smav warnmsg(LOG_DEBUG, __func__, "there is no timer"); 641207498Smav return(NULL); 642207498Smav } else if (timercmp(&rtsol_timer, &now, <)) 64339214Sgibbs /* this may occur when the interval is too small */ 64439214Sgibbs returnval.tv_sec = returnval.tv_usec = 0; 64539214Sgibbs else 64639214Sgibbs timersub(&rtsol_timer, &now, &returnval); 64739214Sgibbs 64839214Sgibbs if (dflag > 1) 64939214Sgibbs warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld", 65039214Sgibbs (long)returnval.tv_sec, (long)returnval.tv_usec); 651131488Sru 652131488Sru return(&returnval); 65339214Sgibbs} 65439214Sgibbs 65539214Sgibbsvoid 656196831Smavrtsol_timer_update(struct ifinfo *ifinfo) 657196831Smav{ 658196831Smav#define MILLION 1000000 659196831Smav#define DADRETRY 10 /* XXX: adhoc */ 660196831Smav long interval; 661196831Smav struct timeval now; 662196831Smav 66339214Sgibbs bzero(&ifinfo->timer, sizeof(ifinfo->timer)); 664216088Sken 665233648Seadler switch (ifinfo->state) { 666216088Sken case IFS_DOWN: 667216088Sken case IFS_TENTATIVE: 668216088Sken if (++ifinfo->dadcount > DADRETRY) { 669216088Sken ifinfo->dadcount = 0; 670216088Sken ifinfo->timer.tv_sec = PROBE_INTERVAL; 671216088Sken } else 672216088Sken ifinfo->timer.tv_sec = 1; 673216088Sken break; 674216088Sken case IFS_IDLE: 675216088Sken if (mobile_node) { 676216088Sken /* XXX should be configurable */ 677216088Sken ifinfo->timer.tv_sec = 3; 678216088Sken } 679216088Sken else 680216088Sken ifinfo->timer = tm_max; /* stop timer(valid?) */ 681216088Sken break; 682216088Sken case IFS_DELAY: 683216088Sken#ifndef HAVE_ARC4RANDOM 684216088Sken interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 685255344Sjoel#else 686255344Sjoel interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 687216088Sken#endif 688216088Sken ifinfo->timer.tv_sec = interval / MILLION; 689216088Sken ifinfo->timer.tv_usec = interval % MILLION; 690216088Sken break; 691216088Sken case IFS_PROBE: 692216088Sken if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 693216088Sken ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; 694216088Sken else { 695216088Sken /* 696216088Sken * After sending MAX_RTR_SOLICITATIONS solicitations, 697216088Sken * we're just waiting for possible replies; there 698216088Sken * will be no more solicitation. Thus, we change 699216088Sken * the timer value to MAX_RTR_SOLICITATION_DELAY based 700216088Sken * on RFC 2461, Section 6.3.7. 701216088Sken */ 702216088Sken ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; 703216088Sken } 704216088Sken break; 705216088Sken default: 706216088Sken warnmsg(LOG_ERR, __func__, 707216088Sken "illegal interface state(%d) on %s", 708216088Sken ifinfo->state, ifinfo->ifname); 709216088Sken return; 710216088Sken } 711216088Sken 712216088Sken /* reset the timer */ 713216088Sken if (timercmp(&ifinfo->timer, &tm_max, ==)) { 714216088Sken ifinfo->expire = tm_max; 715216088Sken warnmsg(LOG_DEBUG, __func__, 716216088Sken "stop timer for %s", ifinfo->ifname); 717216088Sken } else { 718216088Sken gettimeofday(&now, NULL); 719216088Sken timeradd(&now, &ifinfo->timer, &ifinfo->expire); 720216088Sken 721216088Sken if (dflag > 1) 722216088Sken warnmsg(LOG_DEBUG, __func__, 723216088Sken "set timer for %s to %d:%d", ifinfo->ifname, 724216088Sken (int)ifinfo->timer.tv_sec, 725216088Sken (int)ifinfo->timer.tv_usec); 726216088Sken } 727233648Seadler 728216088Sken#undef MILLION 729216088Sken} 730216088Sken 731216088Sken/* timer related utility functions */ 732216088Sken#define MILLION 1000000 733216088Sken 734216088Sken#ifndef SMALL 735216088Skenstatic void 736216088Skenrtsold_set_dump_file(int sig) 737216088Sken{ 738216088Sken do_dump = 1; 739216088Sken} 740216088Sken#endif 741216088Sken 742216088Skenstatic void 743216088Skenusage(char *progname) 744216088Sken{ 745216088Sken if (progname && progname[strlen(progname) - 1] != 'd') { 746216088Sken fprintf(stderr, "usage: rtsol [-dDF] interfaces...\n"); 747216088Sken fprintf(stderr, "usage: rtsol [-dDF] -a\n"); 748216088Sken } else { 749216088Sken fprintf(stderr, "usage: rtsold [-adDfFm1] interfaces...\n"); 750216088Sken fprintf(stderr, "usage: rtsold [-dDfFm1] -a\n"); 751217016Sken } 752216088Sken exit(1); 753216088Sken} 754216088Sken 755216088Skenvoid 756216088Sken#if __STDC__ 757216088Skenwarnmsg(int priority, const char *func, const char *msg, ...) 758216088Sken#else 759216088Skenwarnmsg(priority, func, msg, va_alist) 760216088Sken int priority; 761216088Sken const char *func; 762216088Sken const char *msg; 763216088Sken va_dcl 764216088Sken#endif 765216088Sken{ 766216088Sken va_list ap; 767216088Sken char buf[BUFSIZ]; 768216088Sken 769216088Sken va_start(ap, msg); 770216088Sken if (fflag) { 771216088Sken if (priority <= log_upto) { 772216088Sken (void)vfprintf(stderr, msg, ap); 773216088Sken (void)fprintf(stderr, "\n"); 774216088Sken } 775216088Sken } else { 776216088Sken snprintf(buf, sizeof(buf), "<%s> %s", func, msg); 777216088Sken msg = buf; 778216088Sken vsyslog(priority, msg, ap); 779216088Sken } 780216088Sken va_end(ap); 781216088Sken} 782216088Sken 783216088Sken/* 784216088Sken * return a list of interfaces which is suitable to sending an RS. 785216088Sken */ 786216088Skenchar ** 787216088Skenautoifprobe(void) 788216088Sken{ 789216088Sken static char **argv = NULL; 790216088Sken static int n = 0; 791216088Sken char **a; 792216088Sken int i, found; 793216088Sken struct ifaddrs *ifap, *ifa, *target; 794216088Sken 795216088Sken /* initialize */ 796216088Sken while (n--) 797216088Sken free(argv[n]); 798216088Sken if (argv) { 799216088Sken free(argv); 800216088Sken argv = NULL; 801216088Sken } 802216088Sken n = 0; 803216088Sken 804236625Sjoel if (getifaddrs(&ifap) != 0) 805216088Sken return NULL; 806216088Sken 807216088Sken target = NULL; 808216088Sken /* find an ethernet */ 809216088Sken for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 810216088Sken if ((ifa->ifa_flags & IFF_UP) == 0) 811216088Sken continue; 812216088Sken if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) 813216088Sken continue; 814216088Sken if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) 815216088Sken continue; 816216088Sken if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 817216088Sken continue; 818216088Sken 819216088Sken if (ifa->ifa_addr->sa_family != AF_INET6) 820216088Sken continue; 821216088Sken 822216088Sken found = 0; 823216088Sken for (i = 0; i < n; i++) { 824216088Sken if (strcmp(argv[i], ifa->ifa_name) == 0) { 825216088Sken found++; 826216088Sken break; 827216088Sken } 828216088Sken } 829216088Sken if (found) 830216088Sken continue; 831216088Sken 832216088Sken /* if we find multiple candidates, just warn. */ 833216088Sken if (n != 0 && dflag > 1) 834216088Sken warnx("multiple interfaces found"); 835216088Sken 83661229Sken a = (char **)realloc(argv, (n + 1) * sizeof(char **)); 837131488Sru if (a == NULL) 838131488Sru err(1, "realloc"); 839131488Sru argv = a; 840131506Sru argv[n] = strdup(ifa->ifa_name); 841131488Sru if (!argv[n]) 842131488Sru err(1, "malloc"); 84339214Sgibbs n++; 84439214Sgibbs argv[n] = NULL; 84561229Sken } 84661229Sken 84761229Sken if (n) { 84870152Sru a = (char **)realloc(argv, (n + 1) * sizeof(char **)); 84939214Sgibbs if (a == NULL) 85039214Sgibbs err(1, "realloc"); 851107966Snjl argv = a; 852107966Snjl argv[n] = NULL; 85339214Sgibbs 85439214Sgibbs if (dflag > 0) { 85539214Sgibbs for (i = 0; i < n; i++) 85639214Sgibbs warnx("probing %s", argv[i]); 857107966Snjl } 858107966Snjl } 85939903Sken freeifaddrs(ifap); 860131488Sru return argv; 861131488Sru} 86239903Sken