1 /* $NetBSD: config.c,v 1.24 2006/05/10 22:30:33 rpaulo Exp $ */
2 /* $KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $ */
5 * Copyright (C) 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
37 #include <sys/sysctl.h>
40 #include <net/route.h>
41 #include <net/if_dl.h>
43 #include <netinet/in.h>
44 #include <netinet/in_var.h>
45 #include <netinet/ip6.h>
46 #include <netinet6/ip6_var.h>
47 #include <netinet/icmp6.h>
48 #include <netinet6/nd6.h>
50 #include <arpa/inet.h>
67 static time_t prefix_timo
= (60 * 120); /* 2 hours.
68 * XXX: should be configurable. */
69 extern struct rainfo
*ralist
;
71 static struct rtadvd_timer
*prefix_timeout
__P((void *));
72 static void makeentry
__P((char *, size_t, int, char *));
73 static int getinet6sysctl
__P((int));
87 static int forwarding
= -1;
89 #define MUSTHAVE(var, cap) \
92 if ((t = agetnum(cap)) < 0) { \
93 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
99 #define MAYHAVE(var, cap, def) \
101 if ((var = agetnum(cap)) < 0) \
105 if ((stat
= agetent(tbuf
, intface
)) <= 0) {
106 memset(tbuf
, 0, sizeof(tbuf
));
108 "<%s> %s isn't defined in the configuration file"
109 " or the configuration file doesn't exist."
110 " Treat it as default",
114 tmp
= (struct rainfo
*)malloc(sizeof(*ralist
));
116 syslog(LOG_INFO
, "<%s> %s: can't allocate enough memory",
120 memset(tmp
, 0, sizeof(*tmp
));
121 tmp
->prefix
.next
= tmp
->prefix
.prev
= &tmp
->prefix
;
123 tmp
->route
.next
= tmp
->route
.prev
= &tmp
->route
;
126 /* check if we are allowed to forward packets (if not determined) */
127 if (forwarding
< 0) {
128 if ((forwarding
= getinet6sysctl(IPV6CTL_FORWARDING
)) < 0)
132 /* get interface information */
133 if (agetflag("nolladdr"))
137 if (tmp
->advlinkopt
) {
138 if ((tmp
->sdl
= if_nametosdl(intface
)) == NULL
) {
140 "<%s> can't get information of %s",
144 tmp
->ifindex
= tmp
->sdl
->sdl_index
;
146 tmp
->ifindex
= if_nametoindex(intface
);
147 strlcpy(tmp
->ifname
, intface
, sizeof(tmp
->ifname
));
148 if ((tmp
->phymtu
= if_getmtu(intface
)) == 0) {
149 tmp
->phymtu
= IPV6_MMTU
;
151 "<%s> can't get interface mtu of %s. Treat as %d",
152 __func__
, intface
, IPV6_MMTU
);
156 * set router configuration variables.
158 MAYHAVE(val
, "maxinterval", DEF_MAXRTRADVINTERVAL
);
159 if (val
< MIN_MAXINTERVAL
|| val
> MAX_MAXINTERVAL
) {
161 "<%s> maxinterval (%ld) on %s is invalid "
162 "(must be between %u and %u)", __func__
, val
,
163 intface
, MIN_MAXINTERVAL
, MAX_MAXINTERVAL
);
166 tmp
->maxinterval
= (u_int
)val
;
167 MAYHAVE(val
, "mininterval", tmp
->maxinterval
/3);
168 if (val
< MIN_MININTERVAL
|| val
> (tmp
->maxinterval
* 3) / 4) {
170 "<%s> mininterval (%ld) on %s is invalid "
171 "(must be between %u and %d)",
172 __func__
, val
, intface
, MIN_MININTERVAL
,
173 (tmp
->maxinterval
* 3) / 4);
176 tmp
->mininterval
= (u_int
)val
;
178 MAYHAVE(val
, "chlim", DEF_ADVCURHOPLIMIT
);
179 tmp
->hoplimit
= val
& 0xff;
181 if ((flagstr
= (char *)agetstr("raflags", &bp
))) {
183 if (strchr(flagstr
, 'm'))
184 val
|= ND_RA_FLAG_MANAGED
;
185 if (strchr(flagstr
, 'o'))
186 val
|= ND_RA_FLAG_OTHER
;
187 if (strchr(flagstr
, 'h'))
188 val
|= ND_RA_FLAG_RTPREF_HIGH
;
189 if (strchr(flagstr
, 'l')) {
190 if ((val
& ND_RA_FLAG_RTPREF_HIGH
)) {
191 syslog(LOG_ERR
, "<%s> the \'h\' and \'l\'"
192 " router flags are exclusive", __func__
);
195 val
|= ND_RA_FLAG_RTPREF_LOW
;
198 MAYHAVE(val
, "raflags", 0);
200 tmp
->managedflg
= val
& ND_RA_FLAG_MANAGED
;
201 tmp
->otherflg
= val
& ND_RA_FLAG_OTHER
;
202 #ifndef ND_RA_FLAG_RTPREF_MASK
203 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
204 #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
206 tmp
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
207 if (tmp
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
208 syslog(LOG_ERR
, "<%s> invalid router preference (%02x) on %s",
209 __func__
, tmp
->rtpref
, intface
);
213 MAYHAVE(val
, "rltime", tmp
->maxinterval
* 3);
214 if (val
&& (val
< tmp
->maxinterval
|| val
> MAXROUTERLIFETIME
)) {
216 "<%s> router lifetime (%ld) on %s is invalid "
217 "(must be 0 or between %d and %d)",
218 __func__
, val
, intface
,
219 tmp
->maxinterval
, MAXROUTERLIFETIME
);
223 * Basically, hosts MUST NOT send Router Advertisement messages at any
224 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
225 * useful to allow hosts to advertise some parameters such as prefix
226 * information and link MTU. Thus, we allow hosts to invoke rtadvd
227 * only when router lifetime (on every advertising interface) is
228 * explicitly set zero. (see also the above section)
230 if (val
&& forwarding
== 0) {
232 "<%s> non zero router lifetime is specified for %s, "
233 "which must not be allowed for hosts. you must "
234 "change router lifetime or enable IPv6 forwarding.",
238 tmp
->lifetime
= val
& 0xffff;
240 MAYHAVE(val
, "rtime", DEF_ADVREACHABLETIME
);
241 if (val
< 0 || val
> MAXREACHABLETIME
) {
243 "<%s> reachable time (%ld) on %s is invalid "
244 "(must be no greater than %d)",
245 __func__
, val
, intface
, MAXREACHABLETIME
);
248 tmp
->reachabletime
= (u_int32_t
)val
;
250 MAYHAVE(val64
, "retrans", DEF_ADVRETRANSTIMER
);
251 if (val64
< 0 || val64
> 0xffffffff) {
252 syslog(LOG_ERR
, "<%s> retrans time (%lld) on %s out of range",
253 __func__
, (long long)val64
, intface
);
256 tmp
->retranstimer
= (u_int32_t
)val64
;
258 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
260 "<%s> mobile-ip6 configuration not supported",
264 /* prefix information */
267 * This is an implementation specific parameter to consider
268 * link propagation delays and poorly synchronized clocks when
269 * checking consistency of advertised lifetimes.
271 MAYHAVE(val
, "clockskew", 0);
272 tmp
->clockskew
= val
;
275 for (i
= -1; i
< MAXPREFIX
; i
++) {
279 makeentry(entbuf
, sizeof(entbuf
), i
, "addr");
280 addr
= (char *)agetstr(entbuf
, &bp
);
284 /* allocate memory to store prefix information */
285 if ((pfx
= malloc(sizeof(struct prefix
))) == NULL
) {
287 "<%s> can't allocate enough memory",
291 memset(pfx
, 0, sizeof(*pfx
));
293 /* link into chain */
294 insque(pfx
, &tmp
->prefix
);
298 pfx
->origin
= PREFIX_FROM_CONFIG
;
300 if (inet_pton(AF_INET6
, addr
, &pfx
->prefix
) != 1) {
302 "<%s> inet_pton failed for %s",
306 if (IN6_IS_ADDR_MULTICAST(&pfx
->prefix
)) {
308 "<%s> multicast prefix (%s) must "
309 "not be advertised on %s",
310 __func__
, addr
, intface
);
313 if (IN6_IS_ADDR_LINKLOCAL(&pfx
->prefix
))
315 "<%s> link-local prefix (%s) will be"
317 __func__
, addr
, intface
);
319 makeentry(entbuf
, sizeof(entbuf
), i
, "prefixlen");
320 MAYHAVE(val
, entbuf
, 64);
321 if (val
< 0 || val
> 128) {
322 syslog(LOG_ERR
, "<%s> prefixlen (%ld) for %s "
323 "on %s out of range",
324 __func__
, val
, addr
, intface
);
327 pfx
->prefixlen
= (int)val
;
329 makeentry(entbuf
, sizeof(entbuf
), i
, "pinfoflags");
330 if ((flagstr
= (char *)agetstr(entbuf
, &bp
))) {
332 if (strchr(flagstr
, 'l'))
333 val
|= ND_OPT_PI_FLAG_ONLINK
;
334 if (strchr(flagstr
, 'a'))
335 val
|= ND_OPT_PI_FLAG_AUTO
;
338 (ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
));
340 pfx
->onlinkflg
= val
& ND_OPT_PI_FLAG_ONLINK
;
341 pfx
->autoconfflg
= val
& ND_OPT_PI_FLAG_AUTO
;
343 makeentry(entbuf
, sizeof(entbuf
), i
, "vltime");
344 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
345 if (val64
< 0 || val64
> 0xffffffff) {
346 syslog(LOG_ERR
, "<%s> vltime (%lld) for "
347 "%s/%d on %s is out of range",
348 __func__
, (long long)val64
,
349 addr
, pfx
->prefixlen
, intface
);
352 pfx
->validlifetime
= (u_int32_t
)val64
;
354 makeentry(entbuf
, sizeof(entbuf
), i
, "vltimedecr");
355 if (agetflag(entbuf
)) {
357 gettimeofday(&now
, 0);
359 now
.tv_sec
+ pfx
->validlifetime
;
362 makeentry(entbuf
, sizeof(entbuf
), i
, "pltime");
363 MAYHAVE(val64
, entbuf
, DEF_ADVPREFERREDLIFETIME
);
364 if (val64
< 0 || val64
> 0xffffffff) {
366 "<%s> pltime (%lld) for %s/%d on %s "
368 __func__
, (long long)val64
,
369 addr
, pfx
->prefixlen
, intface
);
372 pfx
->preflifetime
= (u_int32_t
)val64
;
374 makeentry(entbuf
, sizeof(entbuf
), i
, "pltimedecr");
375 if (agetflag(entbuf
)) {
377 gettimeofday(&now
, 0);
379 now
.tv_sec
+ pfx
->preflifetime
;
385 MAYHAVE(val
, "mtu", 0);
386 if (val
< 0 || val
> 0xffffffff) {
388 "<%s> mtu (%ld) on %s out of range",
389 __func__
, val
, intface
);
392 tmp
->linkmtu
= (u_int32_t
)val
;
393 if (tmp
->linkmtu
== 0) {
396 if ((mtustr
= (char *)agetstr("mtu", &bp
)) &&
397 strcmp(mtustr
, "auto") == 0)
398 tmp
->linkmtu
= tmp
->phymtu
;
400 else if (tmp
->linkmtu
< IPV6_MMTU
|| tmp
->linkmtu
> tmp
->phymtu
) {
402 "<%s> advertised link mtu (%lu) on %s is invalid (must "
403 "be between least MTU (%d) and physical link MTU (%d)",
404 __func__
, (unsigned long)tmp
->linkmtu
, intface
,
405 IPV6_MMTU
, tmp
->phymtu
);
409 #ifdef SIOCSIFINFO_IN6
411 struct in6_ndireq ndi
;
414 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
415 syslog(LOG_ERR
, "<%s> socket: %s", __func__
,
419 memset(&ndi
, 0, sizeof(ndi
));
420 strncpy(ndi
.ifname
, intface
, IFNAMSIZ
);
421 if (ioctl(s
, SIOCGIFINFO_IN6
, (caddr_t
)&ndi
) < 0) {
422 syslog(LOG_INFO
, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
423 __func__
, intface
, strerror(errno
));
426 /* reflect the RA info to the host variables in kernel */
427 ndi
.ndi
.chlim
= tmp
->hoplimit
;
428 ndi
.ndi
.retrans
= tmp
->retranstimer
;
429 ndi
.ndi
.basereachable
= tmp
->reachabletime
;
430 if (ioctl(s
, SIOCSIFINFO_IN6
, (caddr_t
)&ndi
) < 0) {
431 syslog(LOG_INFO
, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s",
432 __func__
, intface
, strerror(errno
));
438 /* route information */
441 for (i
= -1; i
< MAXROUTE
; i
++) {
443 char entbuf
[256], oentbuf
[256];
445 makeentry(entbuf
, sizeof(entbuf
), i
, "rtprefix");
446 addr
= (char *)agetstr(entbuf
, &bp
);
448 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrprefix");
449 addr
= (char *)agetstr(oentbuf
, &bp
);
451 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
458 /* allocate memory to store prefix information */
459 if ((rti
= malloc(sizeof(struct rtinfo
))) == NULL
) {
461 "<%s> can't allocate enough memory",
465 memset(rti
, 0, sizeof(*rti
));
467 /* link into chain */
468 insque(rti
, &tmp
->route
);
471 if (inet_pton(AF_INET6
, addr
, &rti
->prefix
) != 1) {
472 syslog(LOG_ERR
, "<%s> inet_pton failed for %s",
478 * XXX: currently there's no restriction in route information
479 * prefix according to
480 * draft-ietf-ipngwg-router-selection-00.txt.
481 * However, I think the similar restriction be necessary.
483 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
484 if (IN6_IS_ADDR_MULTICAST(&rti
->prefix
)) {
486 "<%s> multicast route (%s) must "
487 "not be advertised on %s",
488 __func__
, addr
, intface
);
491 if (IN6_IS_ADDR_LINKLOCAL(&rti
->prefix
)) {
493 "<%s> link-local route (%s) will "
494 "be advertised on %s",
495 __func__
, addr
, intface
);
500 makeentry(entbuf
, sizeof(entbuf
), i
, "rtplen");
501 /* XXX: 256 is a magic number for compatibility check. */
502 MAYHAVE(val
, entbuf
, 256);
504 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrplen");
505 MAYHAVE(val
, oentbuf
, 256);
507 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
512 if (val
< 0 || val
> 128) {
513 syslog(LOG_ERR
, "<%s> prefixlen (%ld) for %s on %s "
515 __func__
, val
, addr
, intface
);
518 rti
->prefixlen
= (int)val
;
520 makeentry(entbuf
, sizeof(entbuf
), i
, "rtflags");
521 if ((flagstr
= (char *)agetstr(entbuf
, &bp
))) {
523 if (strchr(flagstr
, 'h'))
524 val
|= ND_RA_FLAG_RTPREF_HIGH
;
525 if (strchr(flagstr
, 'l')) {
526 if ((val
& ND_RA_FLAG_RTPREF_HIGH
)) {
528 "<%s> the \'h\' and \'l\' route"
529 " preferences are exclusive",
533 val
|= ND_RA_FLAG_RTPREF_LOW
;
536 MAYHAVE(val
, entbuf
, 256); /* XXX */
538 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrflags");
539 MAYHAVE(val
, oentbuf
, 256);
541 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
546 rti
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
547 if (rti
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
548 syslog(LOG_ERR
, "<%s> invalid route preference (%02x) "
550 __func__
, rti
->rtpref
, addr
,
551 rti
->prefixlen
, intface
);
556 * Since the spec does not a default value, we should make
557 * this entry mandatory. However, FreeBSD 4.4 has shipped
558 * with this field being optional, we use the router lifetime
559 * as an ad-hoc default value with a warning message.
561 makeentry(entbuf
, sizeof(entbuf
), i
, "rtltime");
562 MAYHAVE(val64
, entbuf
, -1);
564 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrltime");
565 MAYHAVE(val64
, oentbuf
, -1);
567 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
570 fprintf(stderr
, "%s should be specified "
571 "for interface %s.\n",
573 val64
= tmp
->lifetime
;
576 if (val64
< 0 || val64
> 0xffffffff) {
577 syslog(LOG_ERR
, "<%s> route lifetime (%lld) for "
578 "%s/%d on %s out of range", __func__
,
579 (long long)val64
, addr
, rti
->prefixlen
, intface
);
582 rti
->ltime
= (u_int32_t
)val64
;
590 /* construct the sending packet */
594 tmp
->timer
= rtadvd_add_timer(ra_timeout
, ra_timer_update
,
596 ra_timer_update((void *)tmp
, &tmp
->timer
->tm
);
597 rtadvd_set_timer(&tmp
->timer
->tm
, tmp
->timer
);
601 get_prefix(struct rainfo
*rai
)
603 struct ifaddrs
*ifap
, *ifa
;
606 u_char
*p
, *ep
, *m
, *lim
;
607 char ntopbuf
[INET6_ADDRSTRLEN
];
609 if (getifaddrs(&ifap
) < 0) {
611 "<%s> can't get interface addresses",
616 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
619 if (strcmp(ifa
->ifa_name
, rai
->ifname
) != 0)
621 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
623 a
= &((struct sockaddr_in6
*)ifa
->ifa_addr
)->sin6_addr
;
624 if (IN6_IS_ADDR_LINKLOCAL(a
))
626 /* get prefix length */
627 m
= (u_char
*)&((struct sockaddr_in6
*)ifa
->ifa_netmask
)->sin6_addr
;
628 lim
= (u_char
*)(ifa
->ifa_netmask
) + ifa
->ifa_netmask
->sa_len
;
629 plen
= prefixlen(m
, lim
);
630 if (plen
<= 0 || plen
> 128) {
631 syslog(LOG_ERR
, "<%s> failed to get prefixlen "
632 "or prefix is invalid",
636 if (plen
== 128) /* XXX */
638 if (find_prefix(rai
, a
, plen
)) {
639 /* ignore a duplicated prefix. */
643 /* allocate memory to store prefix info. */
644 if ((pp
= malloc(sizeof(*pp
))) == NULL
) {
646 "<%s> can't get allocate buffer for prefix",
650 memset(pp
, 0, sizeof(*pp
));
652 /* set prefix, sweep bits outside of prefixlen */
653 pp
->prefixlen
= plen
;
654 memcpy(&pp
->prefix
, a
, sizeof(*a
));
657 p
= (u_char
*)&pp
->prefix
;
658 ep
= (u_char
*)(&pp
->prefix
+ 1);
659 while (m
< lim
&& p
< ep
)
664 if (!inet_ntop(AF_INET6
, &pp
->prefix
, ntopbuf
,
666 syslog(LOG_ERR
, "<%s> inet_ntop failed", __func__
);
670 "<%s> add %s/%d to prefix list on %s",
671 __func__
, ntopbuf
, pp
->prefixlen
, rai
->ifname
);
673 /* set other fields with protocol defaults */
674 pp
->validlifetime
= DEF_ADVVALIDLIFETIME
;
675 pp
->preflifetime
= DEF_ADVPREFERREDLIFETIME
;
678 pp
->origin
= PREFIX_FROM_KERNEL
;
681 /* link into chain */
682 insque(pp
, &rai
->prefix
);
684 /* counter increment */
692 makeentry(buf
, len
, id
, string
)
700 strlcpy(buf
, string
, len
);
702 snprintf(buf
, len
, "%s%d", string
, id
);
706 * Add a prefix to the list of specified interface and reconstruct
707 * the outgoing packet.
708 * The prefix must not be in the list.
709 * XXX: other parameters of the prefix(e.g. lifetime) should be
710 * able to be specified.
713 add_prefix(struct rainfo
*rai
, struct in6_prefixreq
*ipr
)
715 struct prefix
*prefix
;
716 char ntopbuf
[INET6_ADDRSTRLEN
];
718 if ((prefix
= malloc(sizeof(*prefix
))) == NULL
) {
719 syslog(LOG_ERR
, "<%s> memory allocation failed",
721 return; /* XXX: error or exit? */
723 memset(prefix
, 0, sizeof(*prefix
));
724 prefix
->prefix
= ipr
->ipr_prefix
.sin6_addr
;
725 prefix
->prefixlen
= ipr
->ipr_plen
;
726 prefix
->validlifetime
= ipr
->ipr_vltime
;
727 prefix
->preflifetime
= ipr
->ipr_pltime
;
728 prefix
->onlinkflg
= ipr
->ipr_raf_onlink
;
729 prefix
->autoconfflg
= ipr
->ipr_raf_auto
;
730 prefix
->origin
= PREFIX_FROM_DYNAMIC
;
732 insque(prefix
, &rai
->prefix
);
733 prefix
->rainfo
= rai
;
735 syslog(LOG_DEBUG
, "<%s> new prefix %s/%d was added on %s",
736 __func__
, inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
,
737 ntopbuf
, INET6_ADDRSTRLEN
),
738 ipr
->ipr_plen
, rai
->ifname
);
740 /* free the previous packet */
744 /* reconstruct the packet */
750 * Delete a prefix to the list of specified interface and reconstruct
751 * the outgoing packet.
752 * The prefix must be in the list.
755 delete_prefix(struct prefix
*prefix
)
757 char ntopbuf
[INET6_ADDRSTRLEN
];
758 struct rainfo
*rai
= prefix
->rainfo
;
761 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was deleted on %s",
762 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
,
763 ntopbuf
, INET6_ADDRSTRLEN
),
764 prefix
->prefixlen
, rai
->ifname
);
766 rtadvd_remove_timer(&prefix
->timer
);
772 invalidate_prefix(struct prefix
*prefix
)
774 char ntopbuf
[INET6_ADDRSTRLEN
];
776 struct rainfo
*rai
= prefix
->rainfo
;
778 if (prefix
->timer
) { /* sanity check */
780 "<%s> assumption failure: timer already exists",
785 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was invalidated on %s, "
786 "will expire in %ld seconds", __func__
,
787 inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
, INET6_ADDRSTRLEN
),
788 prefix
->prefixlen
, rai
->ifname
, (long)prefix_timo
);
790 /* set the expiration timer */
791 prefix
->timer
= rtadvd_add_timer(prefix_timeout
, NULL
, prefix
, NULL
);
792 if (prefix
->timer
== NULL
) {
793 syslog(LOG_ERR
, "<%s> failed to add a timer for a prefix. "
794 "remove the prefix", __func__
);
795 delete_prefix(prefix
);
797 timo
.tv_sec
= prefix_timo
;
799 rtadvd_set_timer(&timo
, prefix
->timer
);
802 static struct rtadvd_timer
*
803 prefix_timeout(void *arg
)
805 struct prefix
*prefix
= (struct prefix
*)arg
;
807 delete_prefix(prefix
);
813 update_prefix(struct prefix
* prefix
)
815 char ntopbuf
[INET6_ADDRSTRLEN
];
816 struct rainfo
*rai
= prefix
->rainfo
;
818 if (prefix
->timer
== NULL
) { /* sanity check */
820 "<%s> assumption failure: timer does not exist",
825 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was re-enabled on %s",
826 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
,
827 INET6_ADDRSTRLEN
), prefix
->prefixlen
, rai
->ifname
);
829 /* stop the expiration timer */
830 rtadvd_remove_timer(&prefix
->timer
);
834 * Try to get an in6_prefixreq contents for a prefix which matches
835 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
836 * the interface whose name is ipr->ipr_name[].
839 init_prefix(struct in6_prefixreq
*ipr
)
844 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
845 syslog(LOG_ERR
, "<%s> socket: %s", __func__
,
850 if (ioctl(s
, SIOCGIFPREFIX_IN6
, (caddr_t
)ipr
) < 0) {
851 syslog(LOG_INFO
, "<%s> ioctl:SIOCGIFPREFIX %s", __func__
,
854 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
855 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
856 ipr
->ipr_raf_onlink
= 1;
857 ipr
->ipr_raf_auto
= 1;
858 /* omit other field initialization */
860 else if (ipr
->ipr_origin
< PR_ORIG_RR
) {
861 char ntopbuf
[INET6_ADDRSTRLEN
];
863 syslog(LOG_WARNING
, "<%s> Added prefix(%s)'s origin %d is"
864 "lower than PR_ORIG_RR(router renumbering)."
865 "This should not happen if I am router", __func__
,
866 inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
, ntopbuf
,
867 sizeof(ntopbuf
)), ipr
->ipr_origin
);
875 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
876 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
877 ipr
->ipr_raf_onlink
= 1;
878 ipr
->ipr_raf_auto
= 1;
884 make_prefix(struct rainfo
*rai
, int ifindex
, struct in6_addr
*addr
, int plen
)
886 struct in6_prefixreq ipr
;
888 memset(&ipr
, 0, sizeof(ipr
));
889 if (if_indextoname(ifindex
, ipr
.ipr_name
) == NULL
) {
890 syslog(LOG_ERR
, "<%s> Prefix added interface No.%d doesn't"
891 "exist. This should not happen! %s", __func__
,
892 ifindex
, strerror(errno
));
895 ipr
.ipr_prefix
.sin6_len
= sizeof(ipr
.ipr_prefix
);
896 ipr
.ipr_prefix
.sin6_family
= AF_INET6
;
897 ipr
.ipr_prefix
.sin6_addr
= *addr
;
900 if (init_prefix(&ipr
))
901 return; /* init failed by some error */
902 add_prefix(rai
, &ipr
);
906 make_packet(struct rainfo
*rainfo
)
908 size_t packlen
, lladdroptlen
= 0;
910 struct nd_router_advert
*ra
;
911 struct nd_opt_prefix_info
*ndopt_pi
;
912 struct nd_opt_mtu
*ndopt_mtu
;
915 struct nd_opt_route_info
*ndopt_rti
;
919 /* calculate total length */
920 packlen
= sizeof(struct nd_router_advert
);
921 if (rainfo
->advlinkopt
) {
922 if ((lladdroptlen
= lladdropt_length(rainfo
->sdl
)) == 0) {
924 "<%s> link-layer address option has"
925 " null length on %s. Treat as not included.",
926 __func__
, rainfo
->ifname
);
927 rainfo
->advlinkopt
= 0;
929 packlen
+= lladdroptlen
;
932 packlen
+= sizeof(struct nd_opt_prefix_info
) * rainfo
->pfxs
;
934 packlen
+= sizeof(struct nd_opt_mtu
);
936 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
)
937 packlen
+= sizeof(struct nd_opt_route_info
) +
938 ((rti
->prefixlen
+ 0x3f) >> 6) * 8;
941 /* allocate memory for the packet */
942 if ((buf
= malloc(packlen
)) == NULL
) {
944 "<%s> can't get enough memory for an RA packet",
948 if (rainfo
->ra_data
) {
949 /* free the previous packet */
950 free(rainfo
->ra_data
);
951 rainfo
->ra_data
= NULL
;
953 rainfo
->ra_data
= buf
;
954 /* XXX: what if packlen > 576? */
955 rainfo
->ra_datalen
= packlen
;
958 * construct the packet
960 ra
= (struct nd_router_advert
*)buf
;
961 ra
->nd_ra_type
= ND_ROUTER_ADVERT
;
964 ra
->nd_ra_curhoplimit
= (u_int8_t
)(0xff & rainfo
->hoplimit
);
965 ra
->nd_ra_flags_reserved
= 0; /* just in case */
967 * XXX: the router preference field, which is a 2-bit field, should be
968 * initialized before other fields.
970 ra
->nd_ra_flags_reserved
= 0xff & rainfo
->rtpref
;
971 ra
->nd_ra_flags_reserved
|=
972 rainfo
->managedflg
? ND_RA_FLAG_MANAGED
: 0;
973 ra
->nd_ra_flags_reserved
|=
974 rainfo
->otherflg
? ND_RA_FLAG_OTHER
: 0;
975 ra
->nd_ra_router_lifetime
= htons(rainfo
->lifetime
);
976 ra
->nd_ra_reachable
= htonl(rainfo
->reachabletime
);
977 ra
->nd_ra_retransmit
= htonl(rainfo
->retranstimer
);
980 if (rainfo
->advlinkopt
) {
981 lladdropt_fill(rainfo
->sdl
, (struct nd_opt_hdr
*)buf
);
985 if (rainfo
->linkmtu
) {
986 ndopt_mtu
= (struct nd_opt_mtu
*)buf
;
987 ndopt_mtu
->nd_opt_mtu_type
= ND_OPT_MTU
;
988 ndopt_mtu
->nd_opt_mtu_len
= 1;
989 ndopt_mtu
->nd_opt_mtu_reserved
= 0;
990 ndopt_mtu
->nd_opt_mtu_mtu
= htonl(rainfo
->linkmtu
);
991 buf
+= sizeof(struct nd_opt_mtu
);
996 for (pfx
= rainfo
->prefix
.next
;
997 pfx
!= &rainfo
->prefix
; pfx
= pfx
->next
) {
998 u_int32_t vltime
, pltime
;
1001 ndopt_pi
= (struct nd_opt_prefix_info
*)buf
;
1002 ndopt_pi
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
1003 ndopt_pi
->nd_opt_pi_len
= 4;
1004 ndopt_pi
->nd_opt_pi_prefix_len
= pfx
->prefixlen
;
1005 ndopt_pi
->nd_opt_pi_flags_reserved
= 0;
1007 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1008 ND_OPT_PI_FLAG_ONLINK
;
1009 if (pfx
->autoconfflg
)
1010 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1011 ND_OPT_PI_FLAG_AUTO
;
1015 if (pfx
->vltimeexpire
|| pfx
->pltimeexpire
)
1016 gettimeofday(&now
, NULL
);
1017 if (pfx
->vltimeexpire
== 0)
1018 vltime
= pfx
->validlifetime
;
1020 vltime
= (pfx
->vltimeexpire
> now
.tv_sec
) ?
1021 pfx
->vltimeexpire
- now
.tv_sec
: 0;
1026 if (pfx
->pltimeexpire
== 0)
1027 pltime
= pfx
->preflifetime
;
1029 pltime
= (pfx
->pltimeexpire
> now
.tv_sec
) ?
1030 pfx
->pltimeexpire
- now
.tv_sec
: 0;
1032 if (vltime
< pltime
) {
1034 * this can happen if vltime is decrement but pltime
1039 ndopt_pi
->nd_opt_pi_valid_time
= htonl(vltime
);
1040 ndopt_pi
->nd_opt_pi_preferred_time
= htonl(pltime
);
1041 ndopt_pi
->nd_opt_pi_reserved2
= 0;
1042 ndopt_pi
->nd_opt_pi_prefix
= pfx
->prefix
;
1044 buf
+= sizeof(struct nd_opt_prefix_info
);
1048 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
) {
1049 u_int8_t psize
= (rti
->prefixlen
+ 0x3f) >> 6;
1051 ndopt_rti
= (struct nd_opt_route_info
*)buf
;
1052 ndopt_rti
->nd_opt_rti_type
= ND_OPT_ROUTE_INFO
;
1053 ndopt_rti
->nd_opt_rti_len
= 1 + psize
;
1054 ndopt_rti
->nd_opt_rti_prefixlen
= rti
->prefixlen
;
1055 ndopt_rti
->nd_opt_rti_flags
= 0xff & rti
->rtpref
;
1056 ndopt_rti
->nd_opt_rti_lifetime
= htonl(rti
->ltime
);
1057 memcpy(ndopt_rti
+ 1, &rti
->prefix
, psize
* 8);
1058 buf
+= sizeof(struct nd_opt_route_info
) + psize
* 8;
1066 getinet6sysctl(int code
)
1068 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0 };
1073 size
= sizeof(value
);
1074 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]), &value
, &size
, NULL
, 0)
1076 syslog(LOG_ERR
, "<%s>: failed to get ip6 sysctl(%d): %s",