Fix markup. Fix backslashes to surive roff.
[netbsd-mini2440.git] / usr.sbin / rtsold / rtsold.c
blob9fb73b2c4ca0bc31554749034bc4ffc2381130d4
1 /* $NetBSD: rtsold.c,v 1.34 2008/06/23 04:55:27 dholland Exp $ */
2 /* $KAME: rtsold.c,v 1.77 2004/01/03 01:35:13 itojun Exp $ */
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/socket.h>
36 #include <sys/param.h>
38 #include <net/if.h>
39 #include <net/if_dl.h>
41 #include <netinet/in.h>
42 #include <netinet/icmp6.h>
44 #include <signal.h>
45 #include <unistd.h>
46 #include <syslog.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <errno.h>
51 #include <err.h>
52 #include <stdarg.h>
53 #include <ifaddrs.h>
54 #include <util.h>
55 #include <poll.h>
57 #include "rtsold.h"
59 #ifdef __bsdi__
60 #define timeradd(tvp, uvp, vvp) \
61 do { \
62 (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
63 (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
64 if ((vvp)->tv_usec >= 1000000) { \
65 (vvp)->tv_sec++; \
66 (vvp)->tv_usec -= 1000000; \
67 } \
68 } while (/* CONSTCOND */ 0)
69 #define timersub(tvp, uvp, vvp) \
70 do { \
71 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
72 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
73 if ((vvp)->tv_usec < 0) { \
74 (vvp)->tv_sec--; \
75 (vvp)->tv_usec += 1000000; \
76 } \
77 } while (/* CONSTCOND */ 0)
78 #endif
80 struct ifinfo *iflist;
81 struct timeval tm_max = {0x7fffffff, 0x7fffffff};
82 static int log_upto = 999;
83 static int fflag = 0;
85 int aflag = 0;
86 int dflag = 0;
88 /* protocol constatns */
89 #define MAX_RTR_SOLICITATION_DELAY 1 /* second */
90 #define RTR_SOLICITATION_INTERVAL 4 /* seconds */
91 #define MAX_RTR_SOLICITATIONS 3 /* times */
93 /*
94 * implementation dependent constants in seconds
95 * XXX: should be configurable
97 #define PROBE_INTERVAL 60
99 int main __P((int, char **));
101 /* static variables and functions */
102 static int mobile_node = 0;
103 #ifndef SMALL
104 static int do_dump;
105 static const char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
106 #endif
108 #if 0
109 static int ifreconfig __P((char *));
110 #endif
111 static int make_packet __P((struct ifinfo *));
112 static struct timeval *rtsol_check_timer __P((void));
114 #ifndef SMALL
115 static void rtsold_set_dump_file __P((int));
116 #endif
117 static void usage __P((char *));
120 main(int argc, char **argv)
122 int s, ch, once = 0;
123 struct timeval *timeout;
124 char *argv0;
125 const char *opts;
126 struct pollfd set[2];
127 #ifdef USE_RTSOCK
128 int rtsock;
129 #endif
132 * Initialization
134 argv0 = argv[0];
136 /* get option */
137 if (argv0 && argv0[strlen(argv0) - 1] != 'd') {
138 fflag = 1;
139 once = 1;
140 opts = "adD";
141 } else
142 opts = "adDfm1";
144 while ((ch = getopt(argc, argv, opts)) != -1) {
145 switch (ch) {
146 case 'a':
147 aflag = 1;
148 break;
149 case 'd':
150 dflag = 1;
151 break;
152 case 'D':
153 dflag = 2;
154 break;
155 case 'f':
156 fflag = 1;
157 break;
158 case 'm':
159 mobile_node = 1;
160 break;
161 case '1':
162 once = 1;
163 break;
164 default:
165 usage(argv0);
166 /*NOTREACHED*/
169 argc -= optind;
170 argv += optind;
172 if ((!aflag && argc == 0) || (aflag && argc != 0)) {
173 usage(argv0);
174 /*NOTREACHED*/
177 /* set log level */
178 if (dflag == 0)
179 log_upto = LOG_NOTICE;
180 if (!fflag) {
181 char *ident;
183 ident = strrchr(argv0, '/');
184 if (!ident)
185 ident = argv0;
186 else
187 ident++;
188 openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
189 if (log_upto >= 0)
190 setlogmask(LOG_UPTO(log_upto));
193 /* warn if accept_rtadv is down */
194 if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
195 warnx("kernel is configured not to accept RAs");
196 /* warn if forwarding is up */
197 if (getinet6sysctl(IPV6CTL_FORWARDING))
198 warnx("kernel is configured as a router, not a host");
200 #ifndef SMALL
201 /* initialization to dump internal status to a file */
202 signal(SIGUSR1, rtsold_set_dump_file);
203 #endif
205 if (!fflag)
206 daemon(0, 0); /* act as a daemon */
209 * Open a socket for sending RS and receiving RA.
210 * This should be done before calling ifinit(), since the function
211 * uses the socket.
213 if ((s = sockopen()) < 0) {
214 warnmsg(LOG_ERR, __func__, "failed to open a socket");
215 exit(1);
216 /*NOTREACHED*/
218 set[0].fd = s;
219 set[0].events = POLLIN;
221 set[1].fd = -1;
223 #ifdef USE_RTSOCK
224 if ((rtsock = rtsock_open()) < 0) {
225 warnmsg(LOG_ERR, __func__, "failed to open a socket");
226 exit(1);
227 /*NOTREACHED*/
229 set[1].fd = rtsock;
230 set[1].events = POLLIN;
231 #endif
233 /* configuration per interface */
234 if (ifinit()) {
235 warnmsg(LOG_ERR, __func__,
236 "failed to initilizatoin interfaces");
237 exit(1);
238 /*NOTREACHED*/
240 if (aflag)
241 argv = autoifprobe();
242 while (argv && *argv) {
243 if (ifconfig(*argv)) {
244 warnmsg(LOG_ERR, __func__,
245 "failed to initialize %s", *argv);
246 exit(1);
247 /*NOTREACHED*/
249 argv++;
252 /* setup for probing default routers */
253 if (probe_init()) {
254 warnmsg(LOG_ERR, __func__,
255 "failed to setup for probing routers");
256 exit(1);
257 /*NOTREACHED*/
260 /* dump the current pid */
261 if (!once) {
262 if (pidfile(NULL) < 0) {
263 warnmsg(LOG_ERR, __func__,
264 "failed to open a pid log file: %s",
265 strerror(errno));
269 for (;;) { /* main loop */
270 int e;
272 #ifndef SMALL
273 if (do_dump) { /* SIGUSR1 */
274 do_dump = 0;
275 rtsold_dump_file(dumpfilename);
277 #endif
279 timeout = rtsol_check_timer();
281 if (once) {
282 struct ifinfo *ifi;
284 /* if we have no timeout, we are done (or failed) */
285 if (timeout == NULL)
286 break;
288 /* if all interfaces have got RA packet, we are done */
289 for (ifi = iflist; ifi; ifi = ifi->next) {
290 if (ifi->state != IFS_DOWN && ifi->racnt == 0)
291 break;
293 if (ifi == NULL)
294 break;
296 e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFTIM);
297 if (e < 1) {
298 if (e < 0 && errno != EINTR) {
299 warnmsg(LOG_ERR, __func__, "poll: %s",
300 strerror(errno));
302 continue;
305 /* packet reception */
306 #ifdef USE_RTSOCK
307 if (set[1].revents & POLLIN)
308 rtsock_input(rtsock);
309 #endif
310 if (set[0].revents & POLLIN)
311 rtsol_input(s);
313 /* NOTREACHED */
315 return 0;
319 ifconfig(char *ifname)
321 struct ifinfo *ifinfo;
322 struct sockaddr_dl *sdl;
323 int flags;
325 if ((sdl = if_nametosdl(ifname)) == NULL) {
326 warnmsg(LOG_ERR, __func__,
327 "failed to get link layer information for %s", ifname);
328 return(-1);
330 if (find_ifinfo(sdl->sdl_index)) {
331 warnmsg(LOG_ERR, __func__,
332 "interface %s was already configured", ifname);
333 free(sdl);
334 return(-1);
337 if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) {
338 warnmsg(LOG_ERR, __func__, "memory allocation failed");
339 free(sdl);
340 return(-1);
342 memset(ifinfo, 0, sizeof(*ifinfo));
343 ifinfo->sdl = sdl;
345 strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname));
347 /* construct a router solicitation message */
348 if (make_packet(ifinfo))
349 goto bad;
351 /* set link ID of this interface. */
352 #ifdef HAVE_SCOPELIB
353 if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid))
354 goto bad;
355 #else
356 /* XXX: assume interface IDs as link IDs */
357 ifinfo->linkid = ifinfo->sdl->sdl_index;
358 #endif
361 * check if the interface is available.
362 * also check if SIOCGIFMEDIA ioctl is OK on the interface.
364 ifinfo->mediareqok = 1;
365 ifinfo->active = interface_status(ifinfo);
366 if (!ifinfo->mediareqok) {
368 * probe routers periodically even if the link status
369 * does not change.
371 ifinfo->probeinterval = PROBE_INTERVAL;
374 /* activate interface: interface_up returns 0 on success */
375 flags = interface_up(ifinfo->ifname);
376 if (flags == 0)
377 ifinfo->state = IFS_DELAY;
378 else if (flags == IFS_TENTATIVE)
379 ifinfo->state = IFS_TENTATIVE;
380 else
381 ifinfo->state = IFS_DOWN;
383 rtsol_timer_update(ifinfo);
385 /* link into chain */
386 if (iflist)
387 ifinfo->next = iflist;
388 iflist = ifinfo;
390 return(0);
392 bad:
393 free(ifinfo->sdl);
394 free(ifinfo);
395 return(-1);
398 void
399 iflist_init(void)
401 struct ifinfo *ifi, *next;
403 for (ifi = iflist; ifi; ifi = next) {
404 next = ifi->next;
405 if (ifi->sdl)
406 free(ifi->sdl);
407 if (ifi->rs_data)
408 free(ifi->rs_data);
409 free(ifi);
410 iflist = NULL;
414 #if 0
415 static int
416 ifreconfig(char *ifname)
418 struct ifinfo *ifi, *prev;
419 int rv;
421 prev = NULL;
422 for (ifi = iflist; ifi; ifi = ifi->next) {
423 if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
424 break;
425 prev = ifi;
427 prev->next = ifi->next;
429 rv = ifconfig(ifname);
431 /* reclaim it after ifconfig() in case ifname is pointer inside ifi */
432 if (ifi->rs_data)
433 free(ifi->rs_data);
434 free(ifi->sdl);
435 free(ifi);
436 return rv;
438 #endif
440 struct ifinfo *
441 find_ifinfo(int ifindex)
443 struct ifinfo *ifi;
445 for (ifi = iflist; ifi; ifi = ifi->next)
446 if (ifi->sdl->sdl_index == ifindex)
447 return(ifi);
448 return(NULL);
451 static int
452 make_packet(struct ifinfo *ifinfo)
454 size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0;
455 struct nd_router_solicit *rs;
456 u_char *buf;
458 if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) {
459 warnmsg(LOG_INFO, __func__,
460 "link-layer address option has null length"
461 " on %s. Treat as not included.", ifinfo->ifname);
463 packlen += lladdroptlen;
464 ifinfo->rs_datalen = packlen;
466 /* allocate buffer */
467 if ((buf = malloc(packlen)) == NULL) {
468 warnmsg(LOG_ERR, __func__,
469 "memory allocation failed for %s", ifinfo->ifname);
470 return(-1);
472 ifinfo->rs_data = buf;
474 /* fill in the message */
475 rs = (struct nd_router_solicit *)buf;
476 rs->nd_rs_type = ND_ROUTER_SOLICIT;
477 rs->nd_rs_code = 0;
478 rs->nd_rs_cksum = 0;
479 rs->nd_rs_reserved = 0;
480 buf += sizeof(*rs);
482 /* fill in source link-layer address option */
483 if (lladdroptlen)
484 lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf);
486 return(0);
489 static struct timeval *
490 rtsol_check_timer(void)
492 static struct timeval returnval;
493 struct timeval now, rtsol_timer;
494 struct ifinfo *ifinfo;
495 int flags;
497 gettimeofday(&now, NULL);
499 rtsol_timer = tm_max;
501 for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
502 if (timercmp(&ifinfo->expire, &now, <=)) {
503 if (dflag > 1)
504 warnmsg(LOG_DEBUG, __func__,
505 "timer expiration on %s, "
506 "state = %d", ifinfo->ifname,
507 ifinfo->state);
509 switch (ifinfo->state) {
510 case IFS_DOWN:
511 case IFS_TENTATIVE:
512 /* interface_up returns 0 on success */
513 flags = interface_up(ifinfo->ifname);
514 if (flags == 0)
515 ifinfo->state = IFS_DELAY;
516 else if (flags == IFS_TENTATIVE)
517 ifinfo->state = IFS_TENTATIVE;
518 else
519 ifinfo->state = IFS_DOWN;
520 break;
521 case IFS_IDLE:
523 int oldstatus = ifinfo->active;
524 int probe = 0;
526 ifinfo->active = interface_status(ifinfo);
528 if (oldstatus != ifinfo->active) {
529 warnmsg(LOG_DEBUG, __func__,
530 "%s status is changed"
531 " from %d to %d",
532 ifinfo->ifname,
533 oldstatus, ifinfo->active);
534 probe = 1;
535 ifinfo->state = IFS_DELAY;
536 } else if (ifinfo->probeinterval &&
537 (ifinfo->probetimer -=
538 ifinfo->timer.tv_sec) <= 0) {
539 /* probe timer expired */
540 ifinfo->probetimer =
541 ifinfo->probeinterval;
542 probe = 1;
543 ifinfo->state = IFS_PROBE;
546 if (probe && mobile_node)
547 defrouter_probe(ifinfo);
548 break;
550 case IFS_DELAY:
551 ifinfo->state = IFS_PROBE;
552 sendpacket(ifinfo);
553 break;
554 case IFS_PROBE:
555 if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
556 sendpacket(ifinfo);
557 else {
558 warnmsg(LOG_INFO, __func__,
559 "No answer after sending %d RSs",
560 ifinfo->probes);
561 ifinfo->probes = 0;
562 ifinfo->state = IFS_IDLE;
564 break;
566 rtsol_timer_update(ifinfo);
569 if (timercmp(&ifinfo->expire, &rtsol_timer, <))
570 rtsol_timer = ifinfo->expire;
573 if (timercmp(&rtsol_timer, &tm_max, ==)) {
574 warnmsg(LOG_DEBUG, __func__, "there is no timer");
575 return(NULL);
576 } else if (timercmp(&rtsol_timer, &now, <))
577 /* this may occur when the interval is too small */
578 returnval.tv_sec = returnval.tv_usec = 0;
579 else
580 timersub(&rtsol_timer, &now, &returnval);
582 if (dflag > 1)
583 warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld",
584 (long)returnval.tv_sec, (long)returnval.tv_usec);
586 return(&returnval);
589 void
590 rtsol_timer_update(struct ifinfo *ifinfo)
592 #define MILLION 1000000
593 #define DADRETRY 10 /* XXX: adhoc */
594 long interval;
595 struct timeval now;
597 bzero(&ifinfo->timer, sizeof(ifinfo->timer));
599 switch (ifinfo->state) {
600 case IFS_DOWN:
601 case IFS_TENTATIVE:
602 if (++ifinfo->dadcount > DADRETRY) {
603 ifinfo->dadcount = 0;
604 ifinfo->timer.tv_sec = PROBE_INTERVAL;
605 } else
606 ifinfo->timer.tv_sec = 1;
607 break;
608 case IFS_IDLE:
609 if (mobile_node) {
610 /* XXX should be configurable */
611 ifinfo->timer.tv_sec = 3;
612 } else
613 ifinfo->timer = tm_max; /* stop timer(valid?) */
614 break;
615 case IFS_DELAY:
616 interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION);
617 ifinfo->timer.tv_sec = interval / MILLION;
618 ifinfo->timer.tv_usec = interval % MILLION;
619 break;
620 case IFS_PROBE:
621 if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
622 ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
623 else {
625 * After sending MAX_RTR_SOLICITATIONS solicitations,
626 * we're just waiting for possible replies; there
627 * will be no more solicatation. Thus, we change
628 * the timer value to MAX_RTR_SOLICITATION_DELAY based
629 * on RFC 2461, Section 6.3.7.
631 ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
633 break;
634 default:
635 warnmsg(LOG_ERR, __func__,
636 "illegal interface state(%d) on %s",
637 ifinfo->state, ifinfo->ifname);
638 return;
641 /* reset the timer */
642 if (timercmp(&ifinfo->timer, &tm_max, ==)) {
643 ifinfo->expire = tm_max;
644 warnmsg(LOG_DEBUG, __func__,
645 "stop timer for %s", ifinfo->ifname);
646 } else {
647 gettimeofday(&now, NULL);
648 timeradd(&now, &ifinfo->timer, &ifinfo->expire);
650 if (dflag > 1)
651 warnmsg(LOG_DEBUG, __func__,
652 "set timer for %s to %d:%d", ifinfo->ifname,
653 (int)ifinfo->timer.tv_sec,
654 (int)ifinfo->timer.tv_usec);
657 #undef MILLION
660 /* timer related utility functions */
661 #define MILLION 1000000
663 #ifndef SMALL
664 static void
665 rtsold_set_dump_file(int sig)
667 do_dump = 1;
669 #endif
671 static void
672 usage(char *progname)
674 if (progname && progname[strlen(progname) - 1] != 'd') {
675 fprintf(stderr, "usage: rtsol [-Dd] interface ...\n");
676 fprintf(stderr, "usage: rtsol [-Dd] -a\n");
677 } else {
678 fprintf(stderr, "usage: rtsold [-1Ddfm] interface ...\n");
679 fprintf(stderr, "usage: rtsold [-1Ddfm] -a\n");
681 exit(1);
684 void
685 warnmsg(int priority, const char *func, const char *msg, ...)
687 va_list ap;
688 char buf[BUFSIZ];
690 va_start(ap, msg);
691 if (fflag) {
692 if (priority <= log_upto) {
693 (void)vfprintf(stderr, msg, ap);
694 (void)fprintf(stderr, "\n");
696 } else {
697 snprintf(buf, sizeof(buf), "<%s> %s", func, msg);
698 msg = buf;
699 vsyslog(priority, msg, ap);
701 va_end(ap);
705 * return a list of interfaces which is suitable to sending an RS.
707 char **
708 autoifprobe(void)
710 static char **argv = NULL;
711 static int n = 0;
712 char **a;
713 int i, found;
714 struct ifaddrs *ifap, *ifa, *target;
716 /* initialize */
717 while (n--)
718 free(argv[n]);
719 if (argv) {
720 free(argv);
721 argv = NULL;
723 n = 0;
725 if (getifaddrs(&ifap) != 0)
726 return NULL;
728 target = NULL;
729 /* find an ethernet */
730 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
731 if ((ifa->ifa_flags & IFF_UP) == 0)
732 continue;
733 if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
734 continue;
735 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
736 continue;
737 if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
738 continue;
740 if (ifa->ifa_addr->sa_family != AF_INET6)
741 continue;
743 found = 0;
744 for (i = 0; i < n; i++) {
745 if (strcmp(argv[i], ifa->ifa_name) == 0) {
746 found++;
747 break;
750 if (found)
751 continue;
753 /* if we find multiple candidates, just warn. */
754 if (n != 0 && dflag > 1)
755 warnx("multiple interfaces found");
757 a = (char **)realloc(argv, (n + 1) * sizeof(char **));
758 if (a == NULL)
759 err(1, "realloc");
760 argv = a;
761 argv[n] = strdup(ifa->ifa_name);
762 if (!argv[n])
763 err(1, "strdup");
764 n++;
767 if (n) {
768 a = (char **)realloc(argv, (n + 1) * sizeof(char **));
769 if (a == NULL)
770 err(1, "realloc");
771 argv = a;
772 argv[n] = NULL;
774 if (dflag > 0) {
775 for (i = 0; i < n; i++)
776 warnx("probing %s", argv[i]);
779 freeifaddrs(ifap);
780 return argv;