]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/rtsold/rtsold.c
Copy libevent sources to contrib
[FreeBSD/FreeBSD.git] / usr.sbin / rtsold / rtsold.c
1 /*      $KAME: rtsold.c,v 1.67 2003/05/17 18:16:15 itojun Exp $ */
2
3 /*-
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7  * All rights reserved.
8  * 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD$
34  */
35
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
39 #include <sys/param.h>
40
41 #include <net/if.h>
42 #include <net/if_dl.h>
43
44 #include <netinet/in.h>
45 #include <netinet/icmp6.h>
46 #include <netinet/in_var.h>
47 #include <arpa/inet.h>
48
49 #include <netinet6/nd6.h>
50
51 #include <signal.h>
52 #include <unistd.h>
53 #include <syslog.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <time.h>
58 #include <errno.h>
59 #include <err.h>
60 #include <stdarg.h>
61 #include <ifaddrs.h>
62 #include <poll.h>
63
64 #include "rtsold.h"
65
66 #define RTSOL_DUMPFILE  "/var/run/rtsold.dump";
67 #define RTSOL_PIDFILE   "/var/run/rtsold.pid";
68
69 struct timespec tm_max;
70 static int log_upto = 999;
71 static int fflag = 0;
72
73 int Fflag = 0;  /* force setting sysctl parameters */
74 int aflag = 0;
75 int dflag = 0;
76 int uflag = 0;
77
78 const char *otherconf_script;
79 const char *resolvconf_script = "/sbin/resolvconf";
80
81 /* protocol constants */
82 #define MAX_RTR_SOLICITATION_DELAY      1 /* second */
83 #define RTR_SOLICITATION_INTERVAL       4 /* seconds */
84 #define MAX_RTR_SOLICITATIONS           3 /* times */
85
86 /*
87  * implementation dependent constants in seconds
88  * XXX: should be configurable
89  */
90 #define PROBE_INTERVAL 60
91
92 /* static variables and functions */
93 static int mobile_node = 0;
94 static const char *pidfilename = RTSOL_PIDFILE;
95
96 #ifndef SMALL
97 static int do_dump;
98 static const char *dumpfilename = RTSOL_DUMPFILE;
99 #endif
100
101 #if 0
102 static int ifreconfig(char *);
103 #endif
104
105 static int make_packet(struct ifinfo *);
106 static struct timespec *rtsol_check_timer(void);
107
108 #ifndef SMALL
109 static void rtsold_set_dump_file(int);
110 #endif
111 static void usage(void);
112
113 int
114 main(int argc, char **argv)
115 {
116         int s, ch, once = 0;
117         struct timespec *timeout;
118         const char *opts;
119         struct pollfd set[2];
120         int rtsock;
121         char *argv0;
122
123 #ifndef SMALL
124         /* rtsold */
125         opts = "adDfFm1O:p:R:u";
126 #else
127         /* rtsol */
128         opts = "adDFO:R:u";
129         fflag = 1;
130         once = 1;
131 #endif
132         argv0 = argv[0];
133
134         while ((ch = getopt(argc, argv, opts)) != -1) {
135                 switch (ch) {
136                 case 'a':
137                         aflag = 1;
138                         break;
139                 case 'd':
140                         dflag += 1;
141                         break;
142                 case 'D':
143                         dflag += 2;
144                         break;
145                 case 'f':
146                         fflag = 1;
147                         break;
148                 case 'F':
149                         Fflag = 1;
150                         break;
151                 case 'm':
152                         mobile_node = 1;
153                         break;
154                 case '1':
155                         once = 1;
156                         break;
157                 case 'O':
158                         otherconf_script = optarg;
159                         break;
160                 case 'p':
161                         pidfilename = optarg;
162                         break;
163                 case 'R':
164                         resolvconf_script = optarg;
165                         break;
166                 case 'u':
167                         uflag = 1;
168                         break;
169                 default:
170                         usage();
171                         exit(1);
172                 }
173         }
174         argc -= optind;
175         argv += optind;
176
177         if ((!aflag && argc == 0) || (aflag && argc != 0)) {
178                 usage();
179                 exit(1);
180         }
181
182         /* Generate maximum time in timespec. */
183         tm_max.tv_sec = (-1) & ~((time_t)1 << ((sizeof(tm_max.tv_sec) * 8) - 1));
184         tm_max.tv_nsec = (-1) & ~((long)1 << ((sizeof(tm_max.tv_nsec) * 8) - 1));
185
186         /* set log level */
187         if (dflag > 1)
188                 log_upto = LOG_DEBUG;
189         else if (dflag > 0)
190                 log_upto = LOG_INFO;
191         else
192                 log_upto = LOG_NOTICE;
193
194         if (!fflag) {
195                 char *ident;
196
197                 ident = strrchr(argv0, '/');
198                 if (!ident)
199                         ident = argv0;
200                 else
201                         ident++;
202                 openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
203                 if (log_upto >= 0)
204                         setlogmask(LOG_UPTO(log_upto));
205         }
206
207         if (otherconf_script && *otherconf_script != '/') {
208                 errx(1, "configuration script (%s) must be an absolute path",
209                     otherconf_script);
210         }
211         if (resolvconf_script && *resolvconf_script != '/') {
212                 errx(1, "configuration script (%s) must be an absolute path",
213                     resolvconf_script);
214         }
215         if (pidfilename && *pidfilename != '/') {
216                 errx(1, "pid filename (%s) must be an absolute path",
217                     pidfilename);
218         }
219
220 #if (__FreeBSD_version < 900000)
221         if (Fflag) {
222                 setinet6sysctl(IPV6CTL_FORWARDING, 0);
223         } else {
224                 /* warn if forwarding is up */
225                 if (getinet6sysctl(IPV6CTL_FORWARDING))
226                         warnx("kernel is configured as a router, not a host");
227         }
228 #endif
229
230 #ifndef SMALL
231         /* initialization to dump internal status to a file */
232         signal(SIGUSR1, rtsold_set_dump_file);
233 #endif
234
235         if (!fflag)
236                 daemon(0, 0);           /* act as a daemon */
237
238         /*
239          * Open a socket for sending RS and receiving RA.
240          * This should be done before calling ifinit(), since the function
241          * uses the socket.
242          */
243         if ((s = sockopen()) < 0) {
244                 warnmsg(LOG_ERR, __func__, "failed to open a socket");
245                 exit(1);
246         }
247         set[0].fd = s;
248         set[0].events = POLLIN;
249         set[1].fd = -1;
250
251         if ((rtsock = rtsock_open()) < 0) {
252                 warnmsg(LOG_ERR, __func__, "failed to open a socket");
253                 exit(1);
254         }
255         set[1].fd = rtsock;
256         set[1].events = POLLIN;
257
258         /* configuration per interface */
259         if (ifinit()) {
260                 warnmsg(LOG_ERR, __func__,
261                     "failed to initialize interfaces");
262                 exit(1);
263         }
264         if (aflag)
265                 argv = autoifprobe();
266         while (argv && *argv) {
267                 if (ifconfig(*argv)) {
268                         warnmsg(LOG_ERR, __func__,
269                             "failed to initialize %s", *argv);
270                         exit(1);
271                 }
272                 argv++;
273         }
274
275         /* setup for probing default routers */
276         if (probe_init()) {
277                 warnmsg(LOG_ERR, __func__,
278                     "failed to setup for probing routers");
279                 exit(1);
280                 /*NOTREACHED*/
281         }
282
283         /* dump the current pid */
284         if (!once) {
285                 pid_t pid = getpid();
286                 FILE *fp;
287
288                 if ((fp = fopen(pidfilename, "w")) == NULL)
289                         warnmsg(LOG_ERR, __func__,
290                             "failed to open a pid log file(%s): %s",
291                             pidfilename, strerror(errno));
292                 else {
293                         fprintf(fp, "%d\n", pid);
294                         fclose(fp);
295                 }
296         }
297         while (1) {             /* main loop */
298                 int e;
299 #ifndef SMALL
300                 if (do_dump) {  /* SIGUSR1 */
301                         do_dump = 0;
302                         rtsold_dump_file(dumpfilename);
303                 }
304 #endif
305
306                 timeout = rtsol_check_timer();
307
308                 if (once) {
309                         struct ifinfo *ifi;
310
311                         /* if we have no timeout, we are done (or failed) */
312                         if (timeout == NULL)
313                                 break;
314
315                         /* if all interfaces have got RA packet, we are done */
316                         TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
317                                 if (ifi->state != IFS_DOWN && ifi->racnt == 0)
318                                         break;
319                         }
320                         if (ifi == NULL)
321                                 break;
322                 }
323                 e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 1000 / 1000) : INFTIM);
324                 if (e < 1) {
325                         if (e < 0 && errno != EINTR) {
326                                 warnmsg(LOG_ERR, __func__, "select: %s",
327                                     strerror(errno));
328                         }
329                         continue;
330                 }
331
332                 /* packet reception */
333                 if (set[1].revents & POLLIN)
334                         rtsock_input(rtsock);
335                 if (set[0].revents & POLLIN)
336                         rtsol_input(s);
337         }
338         /* NOTREACHED */
339
340         return (0);
341 }
342
343 int
344 ifconfig(char *ifname)
345 {
346         struct ifinfo *ifi;
347         struct sockaddr_dl *sdl;
348         int flags;
349
350         if ((sdl = if_nametosdl(ifname)) == NULL) {
351                 warnmsg(LOG_ERR, __func__,
352                     "failed to get link layer information for %s", ifname);
353                 return (-1);
354         }
355         if (find_ifinfo(sdl->sdl_index)) {
356                 warnmsg(LOG_ERR, __func__,
357                     "interface %s was already configured", ifname);
358                 free(sdl);
359                 return (-1);
360         }
361
362         if (Fflag) {
363                 struct in6_ndireq nd;
364                 int s;
365
366                 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
367                         warnmsg(LOG_ERR, __func__, "socket() failed.");
368                         return (-1);
369                 }
370                 memset(&nd, 0, sizeof(nd));
371                 strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
372                 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
373                         warnmsg(LOG_ERR, __func__,
374                             "cannot get accept_rtadv flag");
375                         close(s);
376                         return (-1);
377                 }
378                 nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV;
379                 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
380                         warnmsg(LOG_ERR, __func__,
381                             "cannot set accept_rtadv flag");
382                         close(s);
383                         return (-1);
384                 }
385                 close(s);
386         }
387
388         if ((ifi = malloc(sizeof(*ifi))) == NULL) {
389                 warnmsg(LOG_ERR, __func__, "memory allocation failed");
390                 free(sdl);
391                 return (-1);
392         }
393         memset(ifi, 0, sizeof(*ifi));
394         ifi->sdl = sdl;
395         ifi->ifi_rdnss = IFI_DNSOPT_STATE_NOINFO;
396         ifi->ifi_dnssl = IFI_DNSOPT_STATE_NOINFO;
397         TAILQ_INIT(&ifi->ifi_rainfo);
398         strlcpy(ifi->ifname, ifname, sizeof(ifi->ifname));
399
400         /* construct a router solicitation message */
401         if (make_packet(ifi))
402                 goto bad;
403
404         /* set link ID of this interface. */
405 #ifdef HAVE_SCOPELIB
406         if (inet_zoneid(AF_INET6, 2, ifname, &ifi->linkid))
407                 goto bad;
408 #else
409         /* XXX: assume interface IDs as link IDs */
410         ifi->linkid = ifi->sdl->sdl_index;
411 #endif
412
413         /*
414          * check if the interface is available.
415          * also check if SIOCGIFMEDIA ioctl is OK on the interface.
416          */
417         ifi->mediareqok = 1;
418         ifi->active = interface_status(ifi);
419         if (!ifi->mediareqok) {
420                 /*
421                  * probe routers periodically even if the link status
422                  * does not change.
423                  */
424                 ifi->probeinterval = PROBE_INTERVAL;
425         }
426
427         /* activate interface: interface_up returns 0 on success */
428         flags = interface_up(ifi->ifname);
429         if (flags == 0)
430                 ifi->state = IFS_DELAY;
431         else if (flags == IFS_TENTATIVE)
432                 ifi->state = IFS_TENTATIVE;
433         else
434                 ifi->state = IFS_DOWN;
435
436         rtsol_timer_update(ifi);
437
438         TAILQ_INSERT_TAIL(&ifinfo_head, ifi, ifi_next);
439         return (0);
440
441 bad:
442         free(ifi->sdl);
443         free(ifi);
444         return (-1);
445 }
446
447 void
448 iflist_init(void)
449 {
450         struct ifinfo *ifi;
451
452         while ((ifi = TAILQ_FIRST(&ifinfo_head)) != NULL) {
453                 TAILQ_REMOVE(&ifinfo_head, ifi, ifi_next);
454                 if (ifi->sdl != NULL)
455                         free(ifi->sdl);
456                 if (ifi->rs_data != NULL)
457                         free(ifi->rs_data);
458                 free(ifi);
459         }
460 }
461
462 #if 0
463 static int
464 ifreconfig(char *ifname)
465 {
466         struct ifinfo *ifi, *prev;
467         int rv;
468
469         prev = NULL;
470         TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
471                 if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
472                         break;
473                 prev = ifi;
474         }
475         prev->next = ifi->next;
476
477         rv = ifconfig(ifname);
478
479         /* reclaim it after ifconfig() in case ifname is pointer inside ifi */
480         if (ifi->rs_data)
481                 free(ifi->rs_data);
482         free(ifi->sdl);
483         free(ifi);
484
485         return (rv);
486 }
487 #endif
488
489 struct rainfo *
490 find_rainfo(struct ifinfo *ifi, struct sockaddr_in6 *sin6)
491 {
492         struct rainfo *rai;
493
494         TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next)
495                 if (memcmp(&rai->rai_saddr.sin6_addr, &sin6->sin6_addr,
496                     sizeof(rai->rai_saddr.sin6_addr)) == 0)
497                         return (rai);
498
499         return (NULL);
500 }
501
502 struct ifinfo *
503 find_ifinfo(int ifindex)
504 {
505         struct ifinfo *ifi;
506
507         TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
508                 if (ifi->sdl->sdl_index == ifindex)
509                         return (ifi);
510         }
511         return (NULL);
512 }
513
514 static int
515 make_packet(struct ifinfo *ifi)
516 {
517         size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0;
518         struct nd_router_solicit *rs;
519         char *buf;
520
521         if ((lladdroptlen = lladdropt_length(ifi->sdl)) == 0) {
522                 warnmsg(LOG_INFO, __func__,
523                     "link-layer address option has null length"
524                     " on %s. Treat as not included.", ifi->ifname);
525         }
526         packlen += lladdroptlen;
527         ifi->rs_datalen = packlen;
528
529         /* allocate buffer */
530         if ((buf = malloc(packlen)) == NULL) {
531                 warnmsg(LOG_ERR, __func__,
532                     "memory allocation failed for %s", ifi->ifname);
533                 return (-1);
534         }
535         ifi->rs_data = buf;
536
537         /* fill in the message */
538         rs = (struct nd_router_solicit *)buf;
539         rs->nd_rs_type = ND_ROUTER_SOLICIT;
540         rs->nd_rs_code = 0;
541         rs->nd_rs_cksum = 0;
542         rs->nd_rs_reserved = 0;
543         buf += sizeof(*rs);
544
545         /* fill in source link-layer address option */
546         if (lladdroptlen)
547                 lladdropt_fill(ifi->sdl, (struct nd_opt_hdr *)buf);
548
549         return (0);
550 }
551
552 static struct timespec *
553 rtsol_check_timer(void)
554 {
555         static struct timespec returnval;
556         struct timespec now, rtsol_timer;
557         struct ifinfo *ifi;
558         struct rainfo *rai;
559         struct ra_opt *rao, *raotmp;
560         int flags;
561
562         clock_gettime(CLOCK_MONOTONIC_FAST, &now);
563
564         rtsol_timer = tm_max;
565
566         TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
567                 if (TS_CMP(&ifi->expire, &now, <=)) {
568                         warnmsg(LOG_DEBUG, __func__, "timer expiration on %s, "
569                             "state = %d", ifi->ifname, ifi->state);
570
571                         while((rai = TAILQ_FIRST(&ifi->ifi_rainfo)) != NULL) {
572                                 /* Remove all RA options. */
573                                 TAILQ_REMOVE(&ifi->ifi_rainfo, rai, rai_next);
574                                 while ((rao = TAILQ_FIRST(&rai->rai_ra_opt)) !=
575                                     NULL) {
576                                         TAILQ_REMOVE(&rai->rai_ra_opt, rao,
577                                             rao_next);
578                                         if (rao->rao_msg != NULL)
579                                                 free(rao->rao_msg);
580                                         free(rao);
581                                 }
582                                 free(rai);
583                         }
584                         switch (ifi->state) {
585                         case IFS_DOWN:
586                         case IFS_TENTATIVE:
587                                 /* interface_up returns 0 on success */
588                                 flags = interface_up(ifi->ifname);
589                                 if (flags == 0)
590                                         ifi->state = IFS_DELAY;
591                                 else if (flags == IFS_TENTATIVE)
592                                         ifi->state = IFS_TENTATIVE;
593                                 else
594                                         ifi->state = IFS_DOWN;
595                                 break;
596                         case IFS_IDLE:
597                         {
598                                 int oldstatus = ifi->active;
599                                 int probe = 0;
600
601                                 ifi->active = interface_status(ifi);
602
603                                 if (oldstatus != ifi->active) {
604                                         warnmsg(LOG_DEBUG, __func__,
605                                             "%s status is changed"
606                                             " from %d to %d",
607                                             ifi->ifname,
608                                             oldstatus, ifi->active);
609                                         probe = 1;
610                                         ifi->state = IFS_DELAY;
611                                 } else if (ifi->probeinterval &&
612                                     (ifi->probetimer -=
613                                     ifi->timer.tv_sec) <= 0) {
614                                         /* probe timer expired */
615                                         ifi->probetimer =
616                                             ifi->probeinterval;
617                                         probe = 1;
618                                         ifi->state = IFS_PROBE;
619                                 }
620
621                                 /*
622                                  * If we need a probe, clear the previous
623                                  * status wrt the "other" configuration.
624                                  */
625                                 if (probe)
626                                         ifi->otherconfig = 0;
627
628                                 if (probe && mobile_node)
629                                         defrouter_probe(ifi);
630                                 break;
631                         }
632                         case IFS_DELAY:
633                                 ifi->state = IFS_PROBE;
634                                 sendpacket(ifi);
635                                 break;
636                         case IFS_PROBE:
637                                 if (ifi->probes < MAX_RTR_SOLICITATIONS)
638                                         sendpacket(ifi);
639                                 else {
640                                         warnmsg(LOG_INFO, __func__,
641                                             "No answer after sending %d RSs",
642                                             ifi->probes);
643                                         ifi->probes = 0;
644                                         ifi->state = IFS_IDLE;
645                                 }
646                                 break;
647                         }
648                         rtsol_timer_update(ifi);
649                 } else {
650                         /* Expiration check for RA options. */
651                         int expire = 0;
652
653                         TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) {
654                                 TAILQ_FOREACH_SAFE(rao, &rai->rai_ra_opt,
655                                     rao_next, raotmp) {
656                                         warnmsg(LOG_DEBUG, __func__,
657                                             "RA expiration timer: "
658                                             "type=%d, msg=%s, expire=%s",
659                                             rao->rao_type, (char *)rao->rao_msg,
660                                                 sec2str(&rao->rao_expire));
661                                         if (TS_CMP(&now, &rao->rao_expire,
662                                             >=)) {
663                                                 warnmsg(LOG_DEBUG, __func__,
664                                                     "RA expiration timer: "
665                                                     "expired.");
666                                                 TAILQ_REMOVE(&rai->rai_ra_opt,
667                                                     rao, rao_next);
668                                                 if (rao->rao_msg != NULL)
669                                                         free(rao->rao_msg);
670                                                 free(rao);
671                                                 expire = 1;
672                                         }
673                                 }
674                         }
675                         if (expire)
676                                 ra_opt_handler(ifi);
677                 }
678                 if (TS_CMP(&ifi->expire, &rtsol_timer, <))
679                         rtsol_timer = ifi->expire;
680         }
681
682         if (TS_CMP(&rtsol_timer, &tm_max, ==)) {
683                 warnmsg(LOG_DEBUG, __func__, "there is no timer");
684                 return (NULL);
685         } else if (TS_CMP(&rtsol_timer, &now, <))
686                 /* this may occur when the interval is too small */
687                 returnval.tv_sec = returnval.tv_nsec = 0;
688         else
689                 TS_SUB(&rtsol_timer, &now, &returnval);
690
691         now.tv_sec += returnval.tv_sec;
692         now.tv_nsec += returnval.tv_nsec;
693         warnmsg(LOG_DEBUG, __func__, "New timer is %s",
694             sec2str(&now));
695
696         return (&returnval);
697 }
698
699 void
700 rtsol_timer_update(struct ifinfo *ifi)
701 {
702 #define MILLION 1000000
703 #define DADRETRY 10             /* XXX: adhoc */
704         long interval;
705         struct timespec now;
706
707         bzero(&ifi->timer, sizeof(ifi->timer));
708
709         switch (ifi->state) {
710         case IFS_DOWN:
711         case IFS_TENTATIVE:
712                 if (++ifi->dadcount > DADRETRY) {
713                         ifi->dadcount = 0;
714                         ifi->timer.tv_sec = PROBE_INTERVAL;
715                 } else
716                         ifi->timer.tv_sec = 1;
717                 break;
718         case IFS_IDLE:
719                 if (mobile_node) {
720                         /* XXX should be configurable */
721                         ifi->timer.tv_sec = 3;
722                 }
723                 else
724                         ifi->timer = tm_max;    /* stop timer(valid?) */
725                 break;
726         case IFS_DELAY:
727                 interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION);
728                 ifi->timer.tv_sec = interval / MILLION;
729                 ifi->timer.tv_nsec = (interval % MILLION) * 1000;
730                 break;
731         case IFS_PROBE:
732                 if (ifi->probes < MAX_RTR_SOLICITATIONS)
733                         ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
734                 else {
735                         /*
736                          * After sending MAX_RTR_SOLICITATIONS solicitations,
737                          * we're just waiting for possible replies; there
738                          * will be no more solicitation.  Thus, we change
739                          * the timer value to MAX_RTR_SOLICITATION_DELAY based
740                          * on RFC 2461, Section 6.3.7.
741                          */
742                         ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
743                 }
744                 break;
745         default:
746                 warnmsg(LOG_ERR, __func__,
747                     "illegal interface state(%d) on %s",
748                     ifi->state, ifi->ifname);
749                 return;
750         }
751
752         /* reset the timer */
753         if (TS_CMP(&ifi->timer, &tm_max, ==)) {
754                 ifi->expire = tm_max;
755                 warnmsg(LOG_DEBUG, __func__,
756                     "stop timer for %s", ifi->ifname);
757         } else {
758                 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
759                 TS_ADD(&now, &ifi->timer, &ifi->expire);
760
761                 now.tv_sec += ifi->timer.tv_sec;
762                 now.tv_nsec += ifi->timer.tv_nsec;
763                 warnmsg(LOG_DEBUG, __func__, "set timer for %s to %s",
764                     ifi->ifname, sec2str(&now));
765         }
766
767 #undef MILLION
768 }
769
770 /* timer related utility functions */
771 #define MILLION 1000000
772
773 #ifndef SMALL
774 static void
775 rtsold_set_dump_file(int sig __unused)
776 {
777         do_dump = 1;
778 }
779 #endif
780
781 static void
782 usage(void)
783 {
784 #ifndef SMALL
785         fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
786             "[-p pidfile] [-R script-name] interface ...\n");
787         fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
788             "[-p pidfile] [-R script-name] -a\n");
789 #else
790         fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
791             "[-p pidfile] [-R script-name] interface ...\n");
792         fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
793             "[-p pidfile] [-R script-name] -a\n");
794 #endif
795 }
796
797 void
798 warnmsg(int priority, const char *func, const char *msg, ...)
799 {
800         va_list ap;
801         char buf[BUFSIZ];
802
803         va_start(ap, msg);
804         if (fflag) {
805                 if (priority <= log_upto) {
806                         (void)vfprintf(stderr, msg, ap);
807                         (void)fprintf(stderr, "\n");
808                 }
809         } else {
810                 snprintf(buf, sizeof(buf), "<%s> %s", func, msg);
811                 msg = buf;
812                 vsyslog(priority, msg, ap);
813         }
814         va_end(ap);
815 }
816
817 /*
818  * return a list of interfaces which is suitable to sending an RS.
819  */
820 char **
821 autoifprobe(void)
822 {
823         static char **argv = NULL;
824         static int n = 0;
825         char **a;
826         int s = 0, i, found;
827         struct ifaddrs *ifap, *ifa;
828         struct in6_ndireq nd;
829
830         /* initialize */
831         while (n--)
832                 free(argv[n]);
833         if (argv) {
834                 free(argv);
835                 argv = NULL;
836         }
837         n = 0;
838
839         if (getifaddrs(&ifap) != 0)
840                 return (NULL);
841
842         if (!Fflag && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
843                 warnmsg(LOG_ERR, __func__, "socket");
844                 exit(1);
845         }
846
847         /* find an ethernet */
848         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
849                 if ((ifa->ifa_flags & IFF_UP) == 0)
850                         continue;
851                 if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
852                         continue;
853                 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
854                         continue;
855                 if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
856                         continue;
857
858                 if (ifa->ifa_addr->sa_family != AF_INET6)
859                         continue;
860
861                 found = 0;
862                 for (i = 0; i < n; i++) {
863                         if (strcmp(argv[i], ifa->ifa_name) == 0) {
864                                 found++;
865                                 break;
866                         }
867                 }
868                 if (found)
869                         continue;
870
871                 /*
872                  * Skip the interfaces which IPv6 and/or accepting RA
873                  * is disabled.
874                  */
875                 if (!Fflag) {
876                         memset(&nd, 0, sizeof(nd));
877                         strlcpy(nd.ifname, ifa->ifa_name, sizeof(nd.ifname));
878                         if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
879                                 warnmsg(LOG_ERR, __func__,
880                                         "ioctl(SIOCGIFINFO_IN6)");
881                                 exit(1);
882                         }
883                         if ((nd.ndi.flags & ND6_IFF_IFDISABLED))
884                                 continue;
885                         if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV))
886                                 continue;
887                 }
888
889                 /* if we find multiple candidates, just warn. */
890                 if (n != 0 && dflag > 1)
891                         warnmsg(LOG_WARNING, __func__,
892                                 "multiple interfaces found");
893
894                 a = realloc(argv, (n + 1) * sizeof(char *));
895                 if (a == NULL) {
896                         warnmsg(LOG_ERR, __func__, "realloc");
897                         exit(1);
898                 }
899                 argv = a;
900                 argv[n] = strdup(ifa->ifa_name);
901                 if (!argv[n]) {
902                         warnmsg(LOG_ERR, __func__, "malloc");
903                         exit(1);
904                 }
905                 n++;
906         }
907
908         if (n) {
909                 a = realloc(argv, (n + 1) * sizeof(char *));
910                 if (a == NULL) {
911                         warnmsg(LOG_ERR, __func__, "realloc");
912                         exit(1);
913                 }
914                 argv = a;
915                 argv[n] = NULL;
916
917                 if (dflag > 0) {
918                         for (i = 0; i < n; i++)
919                                 warnmsg(LOG_WARNING, __func__, "probing %s",
920                                         argv[i]);
921                 }
922         }
923         if (!Fflag)
924                 close(s);
925         freeifaddrs(ifap);
926         return (argv);
927 }