rtsold.c revision 124524
1212904Sdim/* $KAME: rtsold.c,v 1.67 2003/05/17 18:16:15 itojun Exp $ */ 2193326Sed 3193326Sed/* 4193326Sed * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5193326Sed * All rights reserved. 6193326Sed * 7193326Sed * Redistribution and use in source and binary forms, with or without 8193326Sed * modification, are permitted provided that the following conditions 9193326Sed * are met: 10193326Sed * 1. Redistributions of source code must retain the above copyright 11193326Sed * notice, this list of conditions and the following disclaimer. 12193326Sed * 2. Redistributions in binary form must reproduce the above copyright 13193326Sed * notice, this list of conditions and the following disclaimer in the 14193326Sed * documentation and/or other materials provided with the distribution. 15193326Sed * 3. Neither the name of the project nor the names of its contributors 16193326Sed * may be used to endorse or promote products derived from this software 17193326Sed * without specific prior written permission. 18193326Sed * 19193326Sed * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20193326Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21193326Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22193326Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23212904Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24193326Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27193326Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28193326Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29193326Sed * SUCH DAMAGE. 30193326Sed * 31193326Sed * $FreeBSD: head/usr.sbin/rtsold/rtsold.c 124524 2004-01-14 17:16:19Z ume $ 32193326Sed */ 33193326Sed 34193326Sed#include <sys/types.h> 35193326Sed#include <sys/time.h> 36212904Sdim#include <sys/socket.h> 37212904Sdim#include <sys/param.h> 38212904Sdim 39193326Sed#include <net/if.h> 40193326Sed#include <net/if_dl.h> 41193326Sed 42206084Srdivacky#include <netinet/in.h> 43249423Sdim#include <netinet/icmp6.h> 44193326Sed 45249423Sdim#include <signal.h> 46249423Sdim#include <unistd.h> 47193326Sed#include <syslog.h> 48193326Sed#include <string.h> 49206084Srdivacky#include <stdlib.h> 50249423Sdim#include <stdio.h> 51193326Sed#include <errno.h> 52249423Sdim#include <err.h> 53193326Sed#include <stdarg.h> 54193326Sed#include <ifaddrs.h> 55206084Srdivacky#ifdef HAVE_POLL_H 56249423Sdim#include <poll.h> 57193326Sed#endif 58249423Sdim 59249423Sdim#include "rtsold.h" 60193326Sed 61193326Sedstruct ifinfo *iflist; 62206084Srdivackystruct timeval tm_max = {0x7fffffff, 0x7fffffff}; 63249423Sdimstatic int log_upto = 999; 64193326Sedstatic int fflag = 0; 65249423Sdim 66193326Sedint aflag = 0; 67193326Sedint dflag = 0; 68206084Srdivacky 69249423Sdimchar *otherconf_script; 70193326Sed 71249423Sdim/* protocol constatns */ 72249423Sdim#define MAX_RTR_SOLICITATION_DELAY 1 /* second */ 73193326Sed#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ 74193326Sed#define MAX_RTR_SOLICITATIONS 3 /* times */ 75206084Srdivacky 76249423Sdim/* 77193326Sed * implementation dependent constants in seconds 78249423Sdim * XXX: should be configurable 79193326Sed */ 80193326Sed#define PROBE_INTERVAL 60 81206084Srdivacky 82249423Sdimint main __P((int, char **)); 83193326Sed 84249423Sdim/* static variables and functions */ 85249423Sdimstatic int mobile_node = 0; 86193326Sedstatic int do_dump; 87193326Sedstatic char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */ 88206084Srdivackystatic char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */ 89249423Sdim 90193326Sed#if 0 91249423Sdimstatic int ifreconfig __P((char *)); 92193326Sed#endif 93193326Sedstatic int make_packet __P((struct ifinfo *)); 94206084Srdivackystatic struct timeval *rtsol_check_timer __P((void)); 95249423Sdim 96193326Sedstatic void rtsold_set_dump_file __P((int)); 97249423Sdimstatic void usage __P((char *)); 98249423Sdim 99193326Sedint 100193326Sedmain(int argc, char **argv) 101206084Srdivacky{ 102249423Sdim int s, ch, once = 0; 103193326Sed struct timeval *timeout; 104249423Sdim char *argv0, *opts; 105193326Sed#ifdef HAVE_POLL_H 106193326Sed struct pollfd set[2]; 107206084Srdivacky#else 108249423Sdim fd_set *fdsetp, *selectfdp; 109193326Sed int fdmasks; 110249423Sdim int maxfd; 111193326Sed#endif 112193326Sed int rtsock; 113206084Srdivacky 114249423Sdim /* 115193326Sed * Initialization 116249423Sdim */ 117193326Sed argv0 = argv[0]; 118193326Sed 119206084Srdivacky /* get option */ 120249423Sdim if (argv0 && argv0[strlen(argv0) - 1] != 'd') { 121193326Sed fflag = 1; 122249423Sdim once = 1; 123193326Sed opts = "adDO:"; 124193326Sed } else 125206084Srdivacky opts = "adDfm1O:"; 126249423Sdim 127193326Sed while ((ch = getopt(argc, argv, opts)) != -1) { 128249423Sdim switch (ch) { 129193326Sed case 'a': 130193326Sed aflag = 1; 131206084Srdivacky break; 132249423Sdim case 'd': 133193326Sed dflag = 1; 134249423Sdim break; 135193326Sed case 'D': 136193326Sed dflag = 2; 137206084Srdivacky break; 138249423Sdim case 'f': 139193326Sed fflag = 1; 140249423Sdim break; 141193326Sed case 'm': 142193326Sed mobile_node = 1; 143206084Srdivacky break; 144249423Sdim case '1': 145193326Sed once = 1; 146249423Sdim break; 147193326Sed case 'O': 148193326Sed otherconf_script = optarg; 149206084Srdivacky break; 150249423Sdim default: 151193326Sed usage(argv0); 152249423Sdim /*NOTREACHED*/ 153193326Sed } 154193326Sed } 155206084Srdivacky argc -= optind; 156249423Sdim argv += optind; 157193326Sed 158249423Sdim if ((!aflag && argc == 0) || (aflag && argc != 0)) { 159193326Sed usage(argv0); 160193326Sed /*NOTREACHED*/ 161206084Srdivacky } 162249423Sdim 163193326Sed /* set log level */ 164249423Sdim if (dflag == 0) 165193326Sed log_upto = LOG_NOTICE; 166193326Sed if (!fflag) { 167206084Srdivacky char *ident; 168249423Sdim 169193326Sed ident = strrchr(argv0, '/'); 170249423Sdim if (!ident) 171193326Sed ident = argv0; 172193326Sed else 173206084Srdivacky ident++; 174249423Sdim openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON); 175193326Sed if (log_upto >= 0) 176249423Sdim setlogmask(LOG_UPTO(log_upto)); 177193326Sed } 178193326Sed 179206084Srdivacky if (otherconf_script && *otherconf_script != '/') { 180249423Sdim errx(1, "configuration script (%s) must be an absolute path", 181193326Sed otherconf_script); 182249423Sdim } 183193326Sed 184193326Sed#ifndef HAVE_ARC4RANDOM 185206084Srdivacky /* random value initialization */ 186249423Sdim srandom((u_long)time(NULL)); 187193326Sed#endif 188249423Sdim 189193326Sed /* warn if accept_rtadv is down */ 190193326Sed if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) 191206084Srdivacky warnx("kernel is configured not to accept RAs"); 192249423Sdim /* warn if forwarding is up */ 193193326Sed if (getinet6sysctl(IPV6CTL_FORWARDING)) 194249423Sdim warnx("kernel is configured as a router, not a host"); 195193326Sed 196193326Sed /* initialization to dump internal status to a file */ 197206084Srdivacky signal(SIGUSR1, rtsold_set_dump_file); 198249423Sdim 199193326Sed if (!fflag) 200249423Sdim daemon(0, 0); /* act as a daemon */ 201193326Sed 202193326Sed /* 203206084Srdivacky * Open a socket for sending RS and receiving RA. 204249423Sdim * This should be done before calling ifinit(), since the function 205193326Sed * uses the socket. 206249423Sdim */ 207193326Sed if ((s = sockopen()) < 0) { 208193326Sed warnmsg(LOG_ERR, __func__, "failed to open a socket"); 209206084Srdivacky exit(1); 210249423Sdim /*NOTREACHED*/ 211193326Sed } 212249423Sdim#ifdef HAVE_POLL_H 213193326Sed set[0].fd = s; 214193326Sed set[0].events = POLLIN; 215206084Srdivacky#else 216249423Sdim maxfd = s; 217193326Sed#endif 218249423Sdim 219193326Sed#ifdef HAVE_POLL_H 220193326Sed set[1].fd = -1; 221206084Srdivacky#endif 222249423Sdim 223193326Sed if ((rtsock = rtsock_open()) < 0) { 224249423Sdim warnmsg(LOG_ERR, __func__, "failed to open a socket"); 225193326Sed exit(1); 226193326Sed /*NOTREACHED*/ 227206084Srdivacky } 228249423Sdim#ifdef HAVE_POLL_H 229193326Sed set[1].fd = rtsock; 230249423Sdim set[1].events = POLLIN; 231193326Sed#else 232193326Sed if (rtsock > maxfd) 233206084Srdivacky maxfd = rtsock; 234249423Sdim#endif 235193326Sed 236249423Sdim#ifndef HAVE_POLL_H 237193326Sed fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); 238193326Sed if ((fdsetp = malloc(fdmasks)) == NULL) { 239206084Srdivacky err(1, "malloc"); 240249423Sdim /*NOTREACHED*/ 241193326Sed } 242249423Sdim if ((selectfdp = malloc(fdmasks)) == NULL) { 243193326Sed err(1, "malloc"); 244193326Sed /*NOTREACHED*/ 245206084Srdivacky } 246249423Sdim#endif 247193326Sed 248263508Sdim /* configuration per interface */ 249263508Sdim if (ifinit()) { 250193326Sed warnmsg(LOG_ERR, __func__, 251193326Sed "failed to initilizatoin interfaces"); 252206084Srdivacky exit(1); 253249423Sdim /*NOTREACHED*/ 254193326Sed } 255263508Sdim if (aflag) 256263508Sdim argv = autoifprobe(); 257193326Sed while (argv && *argv) { 258193326Sed if (ifconfig(*argv)) { 259206084Srdivacky warnmsg(LOG_ERR, __func__, 260249423Sdim "failed to initialize %s", *argv); 261193326Sed exit(1); 262249423Sdim /*NOTREACHED*/ 263193326Sed } 264193326Sed argv++; 265206084Srdivacky } 266249423Sdim 267193326Sed /* setup for probing default routers */ 268249423Sdim if (probe_init()) { 269193326Sed warnmsg(LOG_ERR, __func__, 270193326Sed "failed to setup for probing routers"); 271206084Srdivacky exit(1); 272249423Sdim /*NOTREACHED*/ 273193326Sed } 274249423Sdim 275193326Sed /* dump the current pid */ 276193326Sed if (!once) { 277206084Srdivacky pid_t pid = getpid(); 278249423Sdim FILE *fp; 279193326Sed 280249423Sdim if ((fp = fopen(pidfilename, "w")) == NULL) 281193326Sed warnmsg(LOG_ERR, __func__, 282193326Sed "failed to open a pid log file(%s): %s", 283206084Srdivacky pidfilename, strerror(errno)); 284249423Sdim else { 285193326Sed fprintf(fp, "%d\n", pid); 286249423Sdim fclose(fp); 287193326Sed } 288193326Sed } 289206084Srdivacky 290249423Sdim#ifndef HAVE_POLL_H 291193326Sed memset(fdsetp, 0, fdmasks); 292263508Sdim FD_SET(s, fdsetp); 293263508Sdim FD_SET(rtsock, fdsetp); 294193326Sed#endif 295193326Sed while (1) { /* main loop */ 296206084Srdivacky int e; 297249423Sdim 298193326Sed#ifndef HAVE_POLL_H 299263508Sdim memcpy(selectfdp, fdsetp, fdmasks); 300263508Sdim#endif 301193326Sed 302193326Sed if (do_dump) { /* SIGUSR1 */ 303206084Srdivacky do_dump = 0; 304249423Sdim rtsold_dump_file(dumpfilename); 305193326Sed } 306249423Sdim 307193326Sed timeout = rtsol_check_timer(); 308193326Sed 309206084Srdivacky if (once) { 310249423Sdim struct ifinfo *ifi; 311193326Sed 312249423Sdim /* if we have no timeout, we are done (or failed) */ 313193326Sed if (timeout == NULL) 314193326Sed break; 315206084Srdivacky 316249423Sdim /* if all interfaces have got RA packet, we are done */ 317193326Sed for (ifi = iflist; ifi; ifi = ifi->next) { 318249423Sdim if (ifi->state != IFS_DOWN && ifi->racnt == 0) 319193326Sed break; 320193326Sed } 321206084Srdivacky if (ifi == NULL) 322249423Sdim break; 323193326Sed } 324249423Sdim#ifdef HAVE_POLL_H 325193326Sed e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFTIM); 326193326Sed#else 327206084Srdivacky e = select(maxfd + 1, selectfdp, NULL, NULL, timeout); 328249423Sdim#endif 329226633Sdim if (e < 1) { 330249423Sdim if (e < 0 && errno != EINTR) { 331226633Sdim warnmsg(LOG_ERR, __func__, "select: %s", 332226633Sdim strerror(errno)); 333226633Sdim } 334249423Sdim continue; 335193326Sed } 336249423Sdim 337193326Sed /* packet reception */ 338193326Sed#ifdef HAVE_POLL_H 339206084Srdivacky if (set[1].revents & POLLIN) 340249423Sdim#else 341193326Sed if (FD_ISSET(rtsock, selectfdp)) 342249423Sdim#endif 343193326Sed rtsock_input(rtsock); 344193326Sed#ifdef HAVE_POLL_H 345206084Srdivacky if (set[0].revents & POLLIN) 346249423Sdim#else 347193326Sed if (FD_ISSET(s, selectfdp)) 348249423Sdim#endif 349193326Sed rtsol_input(s); 350193326Sed } 351206084Srdivacky /* NOTREACHED */ 352249423Sdim 353193326Sed return 0; 354249423Sdim} 355193326Sed 356193326Sedint 357206084Srdivackyifconfig(char *ifname) 358249423Sdim{ 359193326Sed struct ifinfo *ifinfo; 360249423Sdim struct sockaddr_dl *sdl; 361193326Sed int flags; 362193326Sed 363206084Srdivacky if ((sdl = if_nametosdl(ifname)) == NULL) { 364249423Sdim warnmsg(LOG_ERR, __func__, 365226633Sdim "failed to get link layer information for %s", ifname); 366249423Sdim return(-1); 367226633Sdim } 368226633Sdim if (find_ifinfo(sdl->sdl_index)) { 369226633Sdim warnmsg(LOG_ERR, __func__, 370249423Sdim "interface %s was already configured", ifname); 371193326Sed free(sdl); 372249423Sdim return(-1); 373193326Sed } 374193326Sed 375206084Srdivacky if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) { 376249423Sdim warnmsg(LOG_ERR, __func__, "memory allocation failed"); 377193326Sed free(sdl); 378249423Sdim return(-1); 379193326Sed } 380193326Sed memset(ifinfo, 0, sizeof(*ifinfo)); 381206084Srdivacky ifinfo->sdl = sdl; 382249423Sdim 383193326Sed strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname)); 384249423Sdim 385193326Sed /* construct a router solicitation message */ 386193326Sed if (make_packet(ifinfo)) 387206084Srdivacky goto bad; 388249423Sdim 389193326Sed /* set link ID of this interface. */ 390249423Sdim#ifdef HAVE_SCOPELIB 391193326Sed if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid)) 392193326Sed goto bad; 393206084Srdivacky#else 394249423Sdim /* XXX: assume interface IDs as link IDs */ 395193326Sed ifinfo->linkid = ifinfo->sdl->sdl_index; 396249423Sdim#endif 397193326Sed 398193326Sed /* 399206084Srdivacky * check if the interface is available. 400249423Sdim * also check if SIOCGIFMEDIA ioctl is OK on the interface. 401193326Sed */ 402249423Sdim ifinfo->mediareqok = 1; 403193326Sed ifinfo->active = interface_status(ifinfo); 404193326Sed if (!ifinfo->mediareqok) { 405206084Srdivacky /* 406249423Sdim * probe routers periodically even if the link status 407193326Sed * does not change. 408249423Sdim */ 409249423Sdim ifinfo->probeinterval = PROBE_INTERVAL; 410193326Sed } 411193326Sed 412206084Srdivacky /* activate interface: interface_up returns 0 on success */ 413249423Sdim flags = interface_up(ifinfo->ifname); 414193326Sed if (flags == 0) 415249423Sdim ifinfo->state = IFS_DELAY; 416249423Sdim else if (flags == IFS_TENTATIVE) 417193326Sed ifinfo->state = IFS_TENTATIVE; 418193326Sed else 419206084Srdivacky ifinfo->state = IFS_DOWN; 420249423Sdim 421193326Sed rtsol_timer_update(ifinfo); 422249423Sdim 423249423Sdim /* link into chain */ 424193326Sed if (iflist) 425193326Sed ifinfo->next = iflist; 426206084Srdivacky iflist = ifinfo; 427249423Sdim 428193326Sed return(0); 429249423Sdim 430193326Sedbad: 431193326Sed free(ifinfo->sdl); 432206084Srdivacky free(ifinfo); 433249423Sdim return(-1); 434193326Sed} 435249423Sdim 436193326Sedvoid 437193326Sediflist_init(void) 438206084Srdivacky{ 439249423Sdim struct ifinfo *ifi, *next; 440193326Sed 441249423Sdim for (ifi = iflist; ifi; ifi = next) { 442193326Sed next = ifi->next; 443193326Sed if (ifi->sdl) 444206084Srdivacky free(ifi->sdl); 445249423Sdim if (ifi->rs_data) 446193326Sed free(ifi->rs_data); 447249423Sdim free(ifi); 448193326Sed iflist = NULL; 449193326Sed } 450206084Srdivacky} 451249423Sdim 452193326Sed#if 0 453249423Sdimstatic int 454193326Sedifreconfig(char *ifname) 455193326Sed{ 456206084Srdivacky struct ifinfo *ifi, *prev; 457249423Sdim int rv; 458193326Sed 459249423Sdim prev = NULL; 460193326Sed for (ifi = iflist; ifi; ifi = ifi->next) { 461193326Sed if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0) 462206084Srdivacky break; 463249423Sdim prev = ifi; 464193326Sed } 465249423Sdim prev->next = ifi->next; 466193326Sed 467193326Sed rv = ifconfig(ifname); 468206084Srdivacky 469249423Sdim /* reclaim it after ifconfig() in case ifname is pointer inside ifi */ 470193326Sed if (ifi->rs_data) 471226633Sdim free(ifi->rs_data); 472249423Sdim free(ifi->sdl); 473226633Sdim free(ifi); 474249423Sdim return rv; 475249423Sdim} 476193326Sed#endif 477193326Sed 478193326Sedstruct ifinfo * 479193326Sedfind_ifinfo(int ifindex) 480206084Srdivacky{ 481249423Sdim struct ifinfo *ifi; 482193326Sed 483249423Sdim for (ifi = iflist; ifi; ifi = ifi->next) 484249423Sdim if (ifi->sdl->sdl_index == ifindex) 485193326Sed return(ifi); 486193326Sed return(NULL); 487206084Srdivacky} 488249423Sdim 489193326Sedstatic int 490223017Sdimmake_packet(struct ifinfo *ifinfo) 491249423Sdim{ 492223017Sdim size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0; 493249423Sdim struct nd_router_solicit *rs; 494193326Sed char *buf; 495193326Sed 496206084Srdivacky if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) { 497249423Sdim warnmsg(LOG_INFO, __func__, 498193326Sed "link-layer address option has null length" 499226633Sdim " on %s. Treat as not included.", ifinfo->ifname); 500249423Sdim } 501226633Sdim packlen += lladdroptlen; 502249423Sdim ifinfo->rs_datalen = packlen; 503249423Sdim 504193326Sed /* allocate buffer */ 505193326Sed if ((buf = malloc(packlen)) == NULL) { 506206084Srdivacky warnmsg(LOG_ERR, __func__, 507249423Sdim "memory allocation failed for %s", ifinfo->ifname); 508193326Sed return(-1); 509226633Sdim } 510249423Sdim ifinfo->rs_data = buf; 511226633Sdim 512249423Sdim /* fill in the message */ 513249423Sdim rs = (struct nd_router_solicit *)buf; 514193326Sed rs->nd_rs_type = ND_ROUTER_SOLICIT; 515193326Sed rs->nd_rs_code = 0; 516206084Srdivacky rs->nd_rs_cksum = 0; 517249423Sdim rs->nd_rs_reserved = 0; 518193326Sed buf += sizeof(*rs); 519226633Sdim 520249423Sdim /* fill in source link-layer address option */ 521226633Sdim if (lladdroptlen) 522249423Sdim lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf); 523249423Sdim 524193326Sed return(0); 525193326Sed} 526206084Srdivacky 527249423Sdimstatic struct timeval * 528193326Sedrtsol_check_timer(void) 529249423Sdim{ 530193326Sed static struct timeval returnval; 531193326Sed struct timeval now, rtsol_timer; 532206084Srdivacky struct ifinfo *ifinfo; 533249423Sdim int flags; 534193326Sed 535249423Sdim gettimeofday(&now, NULL); 536193326Sed 537193326Sed rtsol_timer = tm_max; 538206084Srdivacky 539249423Sdim for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { 540193326Sed if (timercmp(&ifinfo->expire, &now, <=)) { 541249423Sdim if (dflag > 1) 542193326Sed warnmsg(LOG_DEBUG, __func__, 543193326Sed "timer expiration on %s, " 544206084Srdivacky "state = %d", ifinfo->ifname, 545249423Sdim ifinfo->state); 546193326Sed 547249423Sdim switch (ifinfo->state) { 548193326Sed case IFS_DOWN: 549193326Sed case IFS_TENTATIVE: 550206084Srdivacky /* interface_up returns 0 on success */ 551193326Sed flags = interface_up(ifinfo->ifname); 552193326Sed if (flags == 0) 553193326Sed ifinfo->state = IFS_DELAY; 554193326Sed else if (flags == IFS_TENTATIVE) 555193326Sed ifinfo->state = IFS_TENTATIVE; 556206084Srdivacky else 557249423Sdim ifinfo->state = IFS_DOWN; 558193326Sed break; 559249423Sdim case IFS_IDLE: 560193326Sed { 561193326Sed int oldstatus = ifinfo->active; 562206084Srdivacky int probe = 0; 563249423Sdim 564193326Sed ifinfo->active = interface_status(ifinfo); 565226633Sdim 566249423Sdim if (oldstatus != ifinfo->active) { 567226633Sdim warnmsg(LOG_DEBUG, __func__, 568249423Sdim "%s status is changed" 569193326Sed " from %d to %d", 570193326Sed ifinfo->ifname, 571206084Srdivacky oldstatus, ifinfo->active); 572249423Sdim probe = 1; 573193326Sed ifinfo->state = IFS_DELAY; 574226633Sdim } else if (ifinfo->probeinterval && 575249423Sdim (ifinfo->probetimer -= 576226633Sdim ifinfo->timer.tv_sec) <= 0) { 577249423Sdim /* probe timer expired */ 578249423Sdim ifinfo->probetimer = 579193326Sed ifinfo->probeinterval; 580193326Sed probe = 1; 581206084Srdivacky ifinfo->state = IFS_PROBE; 582249423Sdim } 583193326Sed 584249423Sdim /* 585193326Sed * If we need a probe, clear the previous 586193326Sed * status wrt the "other" configuration. 587206084Srdivacky */ 588249423Sdim if (probe) 589193326Sed ifinfo->otherconfig = 0; 590249423Sdim 591193326Sed if (probe && mobile_node) 592193326Sed defrouter_probe(ifinfo); 593206084Srdivacky break; 594249423Sdim } 595193326Sed case IFS_DELAY: 596249423Sdim ifinfo->state = IFS_PROBE; 597249423Sdim sendpacket(ifinfo); 598193326Sed break; 599193326Sed case IFS_PROBE: 600206084Srdivacky if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 601249423Sdim sendpacket(ifinfo); 602193326Sed else { 603226633Sdim warnmsg(LOG_INFO, __func__, 604249423Sdim "No answer after sending %d RSs", 605226633Sdim ifinfo->probes); 606249423Sdim ifinfo->probes = 0; 607193326Sed ifinfo->state = IFS_IDLE; 608193326Sed } 609206084Srdivacky break; 610249423Sdim } 611193326Sed rtsol_timer_update(ifinfo); 612226633Sdim } 613249423Sdim 614226633Sdim if (timercmp(&ifinfo->expire, &rtsol_timer, <)) 615249423Sdim rtsol_timer = ifinfo->expire; 616193326Sed } 617193326Sed 618206084Srdivacky if (timercmp(&rtsol_timer, &tm_max, ==)) { 619249423Sdim warnmsg(LOG_DEBUG, __func__, "there is no timer"); 620193326Sed return(NULL); 621249423Sdim } else if (timercmp(&rtsol_timer, &now, <)) 622193326Sed /* this may occur when the interval is too small */ 623193326Sed returnval.tv_sec = returnval.tv_usec = 0; 624206084Srdivacky else 625249423Sdim timersub(&rtsol_timer, &now, &returnval); 626193326Sed 627249423Sdim if (dflag > 1) 628193326Sed warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld", 629193326Sed (long)returnval.tv_sec, (long)returnval.tv_usec); 630206084Srdivacky 631249423Sdim return(&returnval); 632193326Sed} 633249423Sdim 634193326Sedvoid 635193326Sedrtsol_timer_update(struct ifinfo *ifinfo) 636206084Srdivacky{ 637249423Sdim#define MILLION 1000000 638193326Sed#define DADRETRY 10 /* XXX: adhoc */ 639249423Sdim long interval; 640193326Sed struct timeval now; 641193326Sed 642206084Srdivacky bzero(&ifinfo->timer, sizeof(ifinfo->timer)); 643249423Sdim 644193326Sed switch (ifinfo->state) { 645249423Sdim case IFS_DOWN: 646193326Sed case IFS_TENTATIVE: 647193326Sed if (++ifinfo->dadcount > DADRETRY) { 648206084Srdivacky ifinfo->dadcount = 0; 649249423Sdim ifinfo->timer.tv_sec = PROBE_INTERVAL; 650193326Sed } else 651249423Sdim ifinfo->timer.tv_sec = 1; 652193326Sed break; 653193326Sed case IFS_IDLE: 654206084Srdivacky if (mobile_node) { 655249423Sdim /* XXX should be configurable */ 656193326Sed ifinfo->timer.tv_sec = 3; 657249423Sdim } 658193326Sed else 659193326Sed ifinfo->timer = tm_max; /* stop timer(valid?) */ 660206084Srdivacky break; 661249423Sdim case IFS_DELAY: 662193326Sed#ifndef HAVE_ARC4RANDOM 663249423Sdim interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 664193326Sed#else 665193326Sed interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); 666206084Srdivacky#endif 667249423Sdim ifinfo->timer.tv_sec = interval / MILLION; 668193326Sed ifinfo->timer.tv_usec = interval % MILLION; 669249423Sdim break; 670193326Sed case IFS_PROBE: 671193326Sed if (ifinfo->probes < MAX_RTR_SOLICITATIONS) 672206084Srdivacky ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; 673249423Sdim else { 674193326Sed /* 675249423Sdim * After sending MAX_RTR_SOLICITATIONS solicitations, 676193326Sed * we're just waiting for possible replies; there 677193326Sed * will be no more solicatation. Thus, we change 678206084Srdivacky * the timer value to MAX_RTR_SOLICITATION_DELAY based 679249423Sdim * on RFC 2461, Section 6.3.7. 680193326Sed */ 681249423Sdim ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; 682193326Sed } 683193326Sed break; 684206084Srdivacky default: 685249423Sdim warnmsg(LOG_ERR, __func__, 686193326Sed "illegal interface state(%d) on %s", 687249423Sdim ifinfo->state, ifinfo->ifname); 688193326Sed return; 689193326Sed } 690206084Srdivacky 691249423Sdim /* reset the timer */ 692193326Sed if (timercmp(&ifinfo->timer, &tm_max, ==)) { 693249423Sdim ifinfo->expire = tm_max; 694193326Sed warnmsg(LOG_DEBUG, __func__, 695193326Sed "stop timer for %s", ifinfo->ifname); 696206084Srdivacky } else { 697249423Sdim gettimeofday(&now, NULL); 698193326Sed timeradd(&now, &ifinfo->timer, &ifinfo->expire); 699249423Sdim 700193326Sed if (dflag > 1) 701193326Sed warnmsg(LOG_DEBUG, __func__, 702206084Srdivacky "set timer for %s to %d:%d", ifinfo->ifname, 703249423Sdim (int)ifinfo->timer.tv_sec, 704193326Sed (int)ifinfo->timer.tv_usec); 705249423Sdim } 706193326Sed 707193326Sed#undef MILLION 708206084Srdivacky} 709249423Sdim 710193326Sed/* timer related utility functions */ 711249423Sdim#define MILLION 1000000 712193326Sed 713193326Sedstatic void 714206084Srdivackyrtsold_set_dump_file(int sig) 715249423Sdim{ 716193326Sed do_dump = 1; 717249423Sdim} 718193326Sed 719193326Sedstatic void 720206084Srdivackyusage(char *progname) 721249423Sdim{ 722193326Sed if (progname && progname[strlen(progname) - 1] != 'd') { 723249423Sdim fprintf(stderr, "usage: rtsol [-dD] interfaces...\n"); 724193326Sed fprintf(stderr, "usage: rtsol [-dD] -a\n"); 725193326Sed } else { 726206084Srdivacky fprintf(stderr, "usage: rtsold [-adDfm1] interfaces...\n"); 727249423Sdim fprintf(stderr, "usage: rtsold [-dDfm1] -a\n"); 728193326Sed } 729249423Sdim exit(1); 730193326Sed} 731193326Sed 732206084Srdivackyvoid 733249423Sdim#if __STDC__ 734193326Sedwarnmsg(int priority, const char *func, const char *msg, ...) 735249423Sdim#else 736193326Sedwarnmsg(priority, func, msg, va_alist) 737193326Sed int priority; 738206084Srdivacky const char *func; 739249423Sdim const char *msg; 740193326Sed va_dcl 741249423Sdim#endif 742193326Sed{ 743193326Sed va_list ap; 744206084Srdivacky char buf[BUFSIZ]; 745249423Sdim 746193326Sed va_start(ap, msg); 747249423Sdim if (fflag) { 748193326Sed if (priority <= log_upto) { 749193326Sed (void)vfprintf(stderr, msg, ap); 750206084Srdivacky (void)fprintf(stderr, "\n"); 751249423Sdim } 752193326Sed } else { 753249423Sdim snprintf(buf, sizeof(buf), "<%s> %s", func, msg); 754193326Sed msg = buf; 755193326Sed vsyslog(priority, msg, ap); 756206084Srdivacky } 757249423Sdim va_end(ap); 758193326Sed} 759249423Sdim 760193326Sed/* 761193326Sed * return a list of interfaces which is suitable to sending an RS. 762206084Srdivacky */ 763249423Sdimchar ** 764193326Sedautoifprobe(void) 765249423Sdim{ 766193326Sed static char **argv = NULL; 767193326Sed static int n = 0; 768206084Srdivacky char **a; 769249423Sdim int i, found; 770193326Sed struct ifaddrs *ifap, *ifa, *target; 771249423Sdim 772193326Sed /* initialize */ 773193326Sed while (n--) 774206084Srdivacky free(argv[n]); 775249423Sdim if (argv) { 776193326Sed free(argv); 777249423Sdim argv = NULL; 778193326Sed } 779193326Sed n = 0; 780206084Srdivacky 781249423Sdim if (getifaddrs(&ifap) != 0) 782193326Sed return NULL; 783249423Sdim 784193326Sed target = NULL; 785193326Sed /* find an ethernet */ 786206084Srdivacky for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 787249423Sdim if ((ifa->ifa_flags & IFF_UP) == 0) 788193326Sed continue; 789249423Sdim if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) 790193326Sed continue; 791193326Sed if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) 792206084Srdivacky continue; 793249423Sdim if ((ifa->ifa_flags & IFF_MULTICAST) == 0) 794193326Sed continue; 795249423Sdim 796193326Sed if (ifa->ifa_addr->sa_family != AF_INET6) 797193326Sed continue; 798206084Srdivacky 799249423Sdim found = 0; 800193326Sed for (i = 0; i < n; i++) { 801249423Sdim if (strcmp(argv[i], ifa->ifa_name) == 0) { 802193326Sed found++; 803193326Sed break; 804206084Srdivacky } 805249423Sdim } 806193326Sed if (found) 807249423Sdim continue; 808193326Sed 809193326Sed /* if we find multiple candidates, just warn. */ 810206084Srdivacky if (n != 0 && dflag > 1) 811249423Sdim warnx("multiple interfaces found"); 812193326Sed 813249423Sdim a = (char **)realloc(argv, (n + 1) * sizeof(char **)); 814193326Sed if (a == NULL) 815193326Sed err(1, "realloc"); 816206084Srdivacky argv = a; 817249423Sdim argv[n] = strdup(ifa->ifa_name); 818193326Sed if (!argv[n]) 819249423Sdim err(1, "malloc"); 820193326Sed n++; 821193326Sed argv[n] = NULL; 822206084Srdivacky } 823249423Sdim 824193326Sed if (n) { 825249423Sdim a = (char **)realloc(argv, (n + 1) * sizeof(char **)); 826193326Sed if (a == NULL) 827193326Sed err(1, "realloc"); 828234353Sdim argv = a; 829263508Sdim argv[n] = NULL; 830234353Sdim 831263508Sdim if (dflag > 0) { 832234353Sdim for (i = 0; i < n; i++) 833193326Sed warnx("probing %s", argv[i]); 834206084Srdivacky } 835249423Sdim } 836193326Sed freeifaddrs(ifap); 837249423Sdim return argv; 838193326Sed} 839193326Sed