1 /* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */
4 * Copyright (C) 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * $FreeBSD: src/usr.sbin/rtadvd/config.c,v 1.3.2.5 2003/04/22 09:40:57 suz Exp $
34 #include <sys/param.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
38 #include <sys/sysctl.h>
41 #if defined(__DragonFly__)
42 #include <net/if_var.h>
43 #endif /* __DragonFly__ */
44 #include <net/route.h>
45 #include <net/if_dl.h>
47 #include <netinet/in.h>
48 #include <netinet/in_var.h>
49 #include <netinet/ip6.h>
50 #include <netinet6/ip6_var.h>
51 #include <netinet/icmp6.h>
53 #include <netinet6/mip6.h>
56 #include <arpa/inet.h>
73 static time_t prefix_timo
= (60 * 120); /* 2 hours.
74 * XXX: should be configurable. */
75 extern struct rainfo
*ralist
;
77 static struct rtadvd_timer
*prefix_timeout(void *);
78 static void makeentry(char *, size_t, int, char *, int);
79 static void get_prefix(struct rainfo
*);
80 static int getinet6sysctl(int);
83 getconfig(char *intface
)
93 static int forwarding
= -1;
95 #define MUSTHAVE(var, cap) \
98 if ((t = agetnum(cap)) < 0) { \
99 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
105 #define MAYHAVE(var, cap, def) \
107 if ((var = agetnum(cap)) < 0) \
111 if ((stat
= agetent(tbuf
, intface
)) <= 0) {
112 memset(tbuf
, 0, sizeof(tbuf
));
114 "<%s> %s isn't defined in the configuration file"
115 " or the configuration file doesn't exist."
116 " Treat it as default",
120 tmp
= (struct rainfo
*)malloc(sizeof(*ralist
));
121 memset(tmp
, 0, sizeof(*tmp
));
122 tmp
->prefix
.next
= tmp
->prefix
.prev
= &tmp
->prefix
;
123 tmp
->route
.next
= tmp
->route
.prev
= &tmp
->route
;
125 /* check if we are allowed to forward packets (if not determined) */
126 if (forwarding
< 0) {
127 if ((forwarding
= getinet6sysctl(IPV6CTL_FORWARDING
)) < 0)
131 /* get interface information */
132 if (agetflag("nolladdr"))
136 if (tmp
->advlinkopt
) {
137 if ((tmp
->sdl
= if_nametosdl(intface
)) == NULL
) {
139 "<%s> can't get information of %s",
143 tmp
->ifindex
= tmp
->sdl
->sdl_index
;
145 tmp
->ifindex
= if_nametoindex(intface
);
146 strncpy(tmp
->ifname
, intface
, sizeof(tmp
->ifname
));
147 if ((tmp
->phymtu
= if_getmtu(intface
)) == 0) {
148 tmp
->phymtu
= IPV6_MMTU
;
150 "<%s> can't get interface mtu of %s. Treat as %d",
151 __func__
, intface
, IPV6_MMTU
);
155 * set router configuration variables.
157 MAYHAVE(val
, "maxinterval", DEF_MAXRTRADVINTERVAL
);
158 if (val
< MIN_MAXINTERVAL
|| val
> MAX_MAXINTERVAL
) {
160 "<%s> maxinterval must be between %e and %u",
161 __func__
, MIN_MAXINTERVAL
, MAX_MAXINTERVAL
);
164 tmp
->maxinterval
= (u_int
)val
;
165 MAYHAVE(val
, "mininterval", tmp
->maxinterval
/3);
166 if (val
< MIN_MININTERVAL
|| val
> (tmp
->maxinterval
* 3) / 4) {
168 "<%s> mininterval must be between %e and %d",
171 (tmp
->maxinterval
* 3) / 4);
174 tmp
->mininterval
= (u_int
)val
;
176 MAYHAVE(val
, "chlim", DEF_ADVCURHOPLIMIT
);
177 tmp
->hoplimit
= val
& 0xff;
179 MAYHAVE(val
, "raflags", 0);
180 tmp
->managedflg
= val
& ND_RA_FLAG_MANAGED
;
181 tmp
->otherflg
= val
& ND_RA_FLAG_OTHER
;
184 tmp
->haflg
= val
& ND_RA_FLAG_HA
;
186 #ifndef ND_RA_FLAG_RTPREF_MASK
187 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
188 #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
190 tmp
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
191 if (tmp
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
192 syslog(LOG_ERR
, "<%s> invalid router preference on %s",
197 MAYHAVE(val
, "rltime", tmp
->maxinterval
* 3);
198 if (val
&& (val
< tmp
->maxinterval
|| val
> MAXROUTERLIFETIME
)) {
200 "<%s> router lifetime on %s must be 0 or"
201 " between %d and %d",
203 tmp
->maxinterval
, MAXROUTERLIFETIME
);
207 * Basically, hosts MUST NOT send Router Advertisement messages at any
208 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
209 * useful to allow hosts to advertise some parameters such as prefix
210 * information and link MTU. Thus, we allow hosts to invoke rtadvd
211 * only when router lifetime (on every advertising interface) is
212 * explicitly set zero. (see also the above section)
214 if (val
&& forwarding
== 0) {
216 "<%s> non zero router lifetime is specified for %s, "
217 "which must not be allowed for hosts.",
221 tmp
->lifetime
= val
& 0xffff;
223 MAYHAVE(val
, "rtime", DEF_ADVREACHABLETIME
);
224 if (val
> MAXREACHABLETIME
) {
226 "<%s> reachable time must be no greater than %d",
227 __func__
, MAXREACHABLETIME
);
230 tmp
->reachabletime
= (u_int32_t
)val
;
232 MAYHAVE(val64
, "retrans", DEF_ADVRETRANSTIMER
);
233 if (val64
< 0 || val64
> 0xffffffff) {
235 "<%s> retrans time out of range", __func__
);
238 tmp
->retranstimer
= (u_int32_t
)val64
;
241 if (agetstr("hapref", &bp
) || agetstr("hatime", &bp
)) {
243 "<%s> mobile-ip6 configuration not supported",
249 if (agetstr("hapref", &bp
) || agetstr("hatime", &bp
)) {
251 "<%s> mobile-ip6 configuration without "
252 "proper command line option",
258 if ((val
= agetnum("hapref")) >= 0)
259 tmp
->hapref
= (int16_t)val
;
260 if (tmp
->hapref
!= 0) {
262 MUSTHAVE(val
, "hatime");
263 tmp
->hatime
= (u_int16_t
)val
;
264 if (tmp
->hatime
<= 0) {
266 "<%s> home agent lifetime must be greater than 0",
274 /* prefix information */
277 * This is an implementation specific parameter to consinder
278 * link propagation delays and poorly synchronized clocks when
279 * checking consistency of advertised lifetimes.
281 MAYHAVE(val
, "clockskew", 0);
282 tmp
->clockskew
= val
;
284 if ((pfxs
= agetnum("addrs")) < 0) {
285 /* auto configure prefix information */
286 if (agetstr("addr", &bp
) || agetstr("addr1", &bp
)) {
288 "<%s> conflicting prefix configuration for %s: "
289 "automatic and manual config at the same time",
297 for (i
= 0; i
< pfxs
; i
++) {
300 int added
= (pfxs
> 1) ? 1 : 0;
302 /* allocate memory to store prefix information */
303 if ((pfx
= malloc(sizeof(struct prefix
))) == NULL
) {
305 "<%s> can't allocate enough memory",
309 memset(pfx
, 0, sizeof(*pfx
));
311 /* link into chain */
312 insque(pfx
, &tmp
->prefix
);
315 pfx
->origin
= PREFIX_FROM_CONFIG
;
317 makeentry(entbuf
, sizeof(entbuf
), i
, "prefixlen",
319 MAYHAVE(val
, entbuf
, 64);
320 if (val
< 0 || val
> 128) {
322 "<%s> prefixlen out of range",
326 pfx
->prefixlen
= (int)val
;
328 makeentry(entbuf
, sizeof(entbuf
), i
, "pinfoflags",
334 (ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
|
335 ND_OPT_PI_FLAG_ROUTER
));
340 (ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
));
342 pfx
->onlinkflg
= val
& ND_OPT_PI_FLAG_ONLINK
;
343 pfx
->autoconfflg
= val
& ND_OPT_PI_FLAG_AUTO
;
345 pfx
->routeraddr
= val
& ND_OPT_PI_FLAG_ROUTER
;
348 makeentry(entbuf
, sizeof(entbuf
), i
, "vltime", added
);
349 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
350 if (val64
< 0 || val64
> 0xffffffff) {
352 "<%s> vltime out of range",
356 pfx
->validlifetime
= (u_int32_t
)val64
;
358 makeentry(entbuf
, sizeof(entbuf
), i
, "vltimedecr",
360 if (agetflag(entbuf
)) {
362 gettimeofday(&now
, 0);
364 now
.tv_sec
+ pfx
->validlifetime
;
367 makeentry(entbuf
, sizeof(entbuf
), i
, "pltime", added
);
368 MAYHAVE(val64
, entbuf
, DEF_ADVPREFERREDLIFETIME
);
369 if (val64
< 0 || val64
> 0xffffffff) {
371 "<%s> pltime out of range",
375 pfx
->preflifetime
= (u_int32_t
)val64
;
377 makeentry(entbuf
, sizeof(entbuf
), i
, "pltimedecr",
379 if (agetflag(entbuf
)) {
381 gettimeofday(&now
, 0);
383 now
.tv_sec
+ pfx
->preflifetime
;
386 makeentry(entbuf
, sizeof(entbuf
), i
, "addr", added
);
387 addr
= (char *)agetstr(entbuf
, &bp
);
390 "<%s> need %s as an prefix for "
392 __func__
, entbuf
, intface
);
395 if (inet_pton(AF_INET6
, addr
,
396 &pfx
->prefix
) != 1) {
398 "<%s> inet_pton failed for %s",
402 if (IN6_IS_ADDR_MULTICAST(&pfx
->prefix
)) {
404 "<%s> multicast prefix(%s) must "
405 "not be advertised (IF=%s)",
406 __func__
, addr
, intface
);
409 if (IN6_IS_ADDR_LINKLOCAL(&pfx
->prefix
))
411 "<%s> link-local prefix(%s) will be"
413 __func__
, addr
, intface
);
417 MAYHAVE(val
, "mtu", 0);
418 if (val
< 0 || val
> 0xffffffff) {
420 "<%s> mtu out of range", __func__
);
423 tmp
->linkmtu
= (u_int32_t
)val
;
424 if (tmp
->linkmtu
== 0) {
427 if ((mtustr
= (char *)agetstr("mtu", &bp
)) &&
428 strcmp(mtustr
, "auto") == 0)
429 tmp
->linkmtu
= tmp
->phymtu
;
431 else if (tmp
->linkmtu
< IPV6_MMTU
|| tmp
->linkmtu
> tmp
->phymtu
) {
433 "<%s> advertised link mtu must be between"
434 " least MTU and physical link MTU",
439 /* route information */
441 MAYHAVE(val
, "routes", 0);
442 if (val
< 0 || val
> 0xffffffff) {
444 "<%s> number of route information improper", __func__
);
448 for (i
= 0; i
< tmp
->routes
; i
++) {
451 int added
= (tmp
->routes
> 1) ? 1 : 0;
453 /* allocate memory to store prefix information */
454 if ((rti
= malloc(sizeof(struct rtinfo
))) == NULL
) {
456 "<%s> can't allocate enough memory",
460 memset(rti
, 0, sizeof(*rti
));
462 /* link into chain */
463 insque(rti
, &tmp
->route
);
465 makeentry(entbuf
, sizeof(entbuf
), i
, "rtrplen", added
);
466 MAYHAVE(val
, entbuf
, 64);
467 if (val
< 0 || val
> 128) {
469 "<%s> prefixlen out of range",
473 rti
->prefixlen
= (int)val
;
475 makeentry(entbuf
, sizeof(entbuf
), i
, "rtrflags", added
);
476 MAYHAVE(val
, entbuf
, 0);
477 rti
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
478 if (rti
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
479 syslog(LOG_ERR
, "<%s> invalid route preference",
484 makeentry(entbuf
, sizeof(entbuf
), i
, "rtrltime", added
);
486 * XXX: since default value of route lifetime is not defined in
487 * draft-draves-route-selection-01.txt, I took the default
488 * value of valid lifetime of prefix as its default.
489 * It need be much considered.
491 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
492 if (val64
< 0 || val64
> 0xffffffff) {
494 "<%s> rtrltime out of range",
498 rti
->ltime
= (u_int32_t
)val64
;
500 makeentry(entbuf
, sizeof(entbuf
), i
, "rtrprefix", added
);
501 addr
= (char *)agetstr(entbuf
, &bp
);
504 "<%s> need %s as an route for "
506 __func__
, entbuf
, intface
);
509 if (inet_pton(AF_INET6
, addr
, &rti
->prefix
) != 1) {
511 "<%s> inet_pton failed for %s",
517 * XXX: currently there's no restriction in route information
518 * prefix according to draft-draves-route-selection-01.txt,
519 * however I think the similar restriction be necessary.
521 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
522 if (IN6_IS_ADDR_MULTICAST(&rti
->prefix
)) {
524 "<%s> multicast route (%s) must "
525 "not be advertised (IF=%s)",
526 __func__
, addr
, intface
);
529 if (IN6_IS_ADDR_LINKLOCAL(&rti
->prefix
)) {
531 "<%s> link-local route (%s) must "
532 "not be advertised on %s",
533 __func__
, addr
, intface
);
543 /* construct the sending packet */
547 tmp
->timer
= rtadvd_add_timer(ra_timeout
, ra_timer_update
,
549 ra_timer_update((void *)tmp
, &tmp
->timer
->tm
);
550 rtadvd_set_timer(&tmp
->timer
->tm
, tmp
->timer
);
554 get_prefix(struct rainfo
*rai
)
556 struct ifaddrs
*ifap
, *ifa
;
559 u_char
*p
, *ep
, *m
, *lim
;
560 u_char ntopbuf
[INET6_ADDRSTRLEN
];
562 if (getifaddrs(&ifap
) < 0) {
564 "<%s> can't get interface addresses",
568 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
571 if (strcmp(ifa
->ifa_name
, rai
->ifname
) != 0)
573 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
575 a
= &((struct sockaddr_in6
*)ifa
->ifa_addr
)->sin6_addr
;
576 if (IN6_IS_ADDR_LINKLOCAL(a
))
579 /* get prefix length */
580 m
= (u_char
*)&((struct sockaddr_in6
*)ifa
->ifa_netmask
)->sin6_addr
;
581 lim
= (u_char
*)(ifa
->ifa_netmask
) + ifa
->ifa_netmask
->sa_len
;
582 plen
= prefixlen(m
, lim
);
583 if (plen
< 0 || plen
> 128) {
584 syslog(LOG_ERR
, "<%s> failed to get prefixlen "
585 "or prefix is invalid",
589 if (find_prefix(rai
, a
, plen
)) {
590 /* ignore a duplicated prefix. */
594 /* allocate memory to store prefix info. */
595 if ((pp
= malloc(sizeof(*pp
))) == NULL
) {
597 "<%s> can't get allocate buffer for prefix",
601 memset(pp
, 0, sizeof(*pp
));
603 /* set prefix, sweep bits outside of prefixlen */
604 pp
->prefixlen
= plen
;
605 memcpy(&pp
->prefix
, a
, sizeof(*a
));
606 p
= (u_char
*)&pp
->prefix
;
607 ep
= (u_char
*)(&pp
->prefix
+ 1);
613 if (!inet_ntop(AF_INET6
, &pp
->prefix
, ntopbuf
,
615 syslog(LOG_ERR
, "<%s> inet_ntop failed", __func__
);
619 "<%s> add %s/%d to prefix list on %s",
620 __func__
, ntopbuf
, pp
->prefixlen
, rai
->ifname
);
622 /* set other fields with protocol defaults */
623 pp
->validlifetime
= DEF_ADVVALIDLIFETIME
;
624 pp
->preflifetime
= DEF_ADVPREFERREDLIFETIME
;
627 pp
->origin
= PREFIX_FROM_KERNEL
;
629 /* link into chain */
630 insque(pp
, &rai
->prefix
);
632 /* counter increment */
640 makeentry(char *buf
, size_t len
, int id
, char *string
, int add
)
642 char *ep
= buf
+ len
;
648 cp
= (char *)index(buf
, '\0');
649 snprintf(cp
, ep
- cp
, "%d", id
);
654 * Add a prefix to the list of specified interface and reconstruct
655 * the outgoing packet.
656 * The prefix must not be in the list.
657 * XXX: other parameter of the prefix(e.g. lifetime) shoule be
658 * able to be specified.
661 add_prefix(struct rainfo
*rai
, struct in6_prefixreq
*ipr
)
663 struct prefix
*prefix
;
664 u_char ntopbuf
[INET6_ADDRSTRLEN
];
666 if ((prefix
= malloc(sizeof(*prefix
))) == NULL
) {
667 syslog(LOG_ERR
, "<%s> memory allocation failed",
669 return; /* XXX: error or exit? */
671 memset(prefix
, 0, sizeof(*prefix
));
672 prefix
->prefix
= ipr
->ipr_prefix
.sin6_addr
;
673 prefix
->prefixlen
= ipr
->ipr_plen
;
674 prefix
->validlifetime
= ipr
->ipr_vltime
;
675 prefix
->preflifetime
= ipr
->ipr_pltime
;
676 prefix
->onlinkflg
= ipr
->ipr_raf_onlink
;
677 prefix
->autoconfflg
= ipr
->ipr_raf_auto
;
678 prefix
->origin
= PREFIX_FROM_DYNAMIC
;
680 insque(prefix
, &rai
->prefix
);
681 prefix
->rainfo
= rai
;
683 syslog(LOG_DEBUG
, "<%s> new prefix %s/%d was added on %s",
684 __func__
, inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
,
685 ntopbuf
, INET6_ADDRSTRLEN
),
686 ipr
->ipr_plen
, rai
->ifname
);
688 /* free the previous packet */
692 /* reconstruct the packet */
697 * reset the timer so that the new prefix will be advertised quickly.
699 rai
->initcounter
= 0;
700 ra_timer_update((void *)rai
, &rai
->timer
->tm
);
701 rtadvd_set_timer(&rai
->timer
->tm
, rai
->timer
);
705 * Delete a prefix to the list of specified interface and reconstruct
706 * the outgoing packet.
707 * The prefix must be in the list.
710 delete_prefix(struct prefix
*prefix
)
712 u_char ntopbuf
[INET6_ADDRSTRLEN
];
713 struct rainfo
*rai
= prefix
->rainfo
;
716 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was deleted on %s",
717 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
,
718 ntopbuf
, INET6_ADDRSTRLEN
),
719 prefix
->prefixlen
, rai
->ifname
);
721 rtadvd_remove_timer(&prefix
->timer
);
727 invalidate_prefix(struct prefix
*prefix
)
729 u_char ntopbuf
[INET6_ADDRSTRLEN
];
731 struct rainfo
*rai
= prefix
->rainfo
;
733 if (prefix
->timer
) { /* sanity check */
735 "<%s> assumption failure: timer already exists",
740 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was invalidated on %s, "
741 "will expire in %ld seconds", __func__
,
742 inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
, INET6_ADDRSTRLEN
),
743 prefix
->prefixlen
, rai
->ifname
, (long)prefix_timo
);
745 /* set the expiration timer */
746 prefix
->timer
= rtadvd_add_timer(prefix_timeout
, NULL
, prefix
, NULL
);
747 if (prefix
->timer
== NULL
) {
748 syslog(LOG_ERR
, "<%s> failed to add a timer for a prefix. "
749 "remove the prefix", __func__
);
750 delete_prefix(prefix
);
752 timo
.tv_sec
= prefix_timo
;
754 rtadvd_set_timer(&timo
, prefix
->timer
);
757 static struct rtadvd_timer
*
758 prefix_timeout(void *arg
)
760 struct prefix
*prefix
= (struct prefix
*)arg
;
762 delete_prefix(prefix
);
768 update_prefix(struct prefix
* prefix
)
770 u_char ntopbuf
[INET6_ADDRSTRLEN
];
771 struct rainfo
*rai
= prefix
->rainfo
;
773 if (prefix
->timer
== NULL
) { /* sanity check */
775 "<%s> assumption failure: timer does not exist",
780 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was re-enabled on %s",
781 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
,
782 INET6_ADDRSTRLEN
), prefix
->prefixlen
, rai
->ifname
);
784 /* stop the expiration timer */
785 rtadvd_remove_timer(&prefix
->timer
);
789 * Try to get an in6_prefixreq contents for a prefix which matches
790 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
791 * the interface whose name is ipr->ipr_name[].
794 init_prefix(struct in6_prefixreq
*ipr
)
799 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
800 syslog(LOG_ERR
, "<%s> socket: %s", __func__
,
805 if (ioctl(s
, SIOCGIFPREFIX_IN6
, (caddr_t
)ipr
) < 0) {
806 syslog(LOG_INFO
, "<%s> ioctl:SIOCGIFPREFIX %s", __func__
,
809 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
810 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
811 ipr
->ipr_raf_onlink
= 1;
812 ipr
->ipr_raf_auto
= 1;
813 /* omit other field initialization */
815 else if (ipr
->ipr_origin
< PR_ORIG_RR
) {
816 u_char ntopbuf
[INET6_ADDRSTRLEN
];
818 syslog(LOG_WARNING
, "<%s> Added prefix(%s)'s origin %d is"
819 "lower than PR_ORIG_RR(router renumbering)."
820 "This should not happen if I am router", __func__
,
821 inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
, ntopbuf
,
822 sizeof(ntopbuf
)), ipr
->ipr_origin
);
830 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
831 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
832 ipr
->ipr_raf_onlink
= 1;
833 ipr
->ipr_raf_auto
= 1;
839 make_prefix(struct rainfo
*rai
, int ifindex
, struct in6_addr
*addr
, int plen
)
841 struct in6_prefixreq ipr
;
843 memset(&ipr
, 0, sizeof(ipr
));
844 if (if_indextoname(ifindex
, ipr
.ipr_name
) == NULL
) {
845 syslog(LOG_ERR
, "<%s> Prefix added interface No.%d doesn't"
846 "exist. This should not happen! %s", __func__
,
847 ifindex
, strerror(errno
));
850 ipr
.ipr_prefix
.sin6_len
= sizeof(ipr
.ipr_prefix
);
851 ipr
.ipr_prefix
.sin6_family
= AF_INET6
;
852 ipr
.ipr_prefix
.sin6_addr
= *addr
;
855 if (init_prefix(&ipr
))
856 return; /* init failed by some error */
857 add_prefix(rai
, &ipr
);
861 make_packet(struct rainfo
*rainfo
)
863 size_t packlen
, lladdroptlen
= 0;
865 struct nd_router_advert
*ra
;
866 struct nd_opt_prefix_info
*ndopt_pi
;
867 struct nd_opt_mtu
*ndopt_mtu
;
869 struct nd_opt_advinterval
*ndopt_advint
;
870 struct nd_opt_homeagent_info
*ndopt_hai
;
872 struct nd_opt_route_info
*ndopt_rti
;
876 /* calculate total length */
877 packlen
= sizeof(struct nd_router_advert
);
878 if (rainfo
->advlinkopt
) {
879 if ((lladdroptlen
= lladdropt_length(rainfo
->sdl
)) == 0) {
881 "<%s> link-layer address option has"
882 " null length on %s."
883 " Treat as not included.",
884 __func__
, rainfo
->ifname
);
885 rainfo
->advlinkopt
= 0;
887 packlen
+= lladdroptlen
;
890 packlen
+= sizeof(struct nd_opt_prefix_info
) * rainfo
->pfxs
;
892 packlen
+= sizeof(struct nd_opt_mtu
);
894 if (mobileip6
&& rainfo
->maxinterval
)
895 packlen
+= sizeof(struct nd_opt_advinterval
);
896 if (mobileip6
&& rainfo
->hatime
)
897 packlen
+= sizeof(struct nd_opt_homeagent_info
);
899 #ifdef ND_OPT_ROUTE_INFO
900 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
)
901 packlen
+= sizeof(struct nd_opt_route_info
) +
902 ((rti
->prefixlen
+ 0x3f) >> 6) * 8;
905 /* allocate memory for the packet */
906 if ((buf
= malloc(packlen
)) == NULL
) {
908 "<%s> can't get enough memory for an RA packet",
912 if (rainfo
->ra_data
) {
913 /* free the previous packet */
914 free(rainfo
->ra_data
);
915 rainfo
->ra_data
= NULL
;
917 rainfo
->ra_data
= buf
;
918 /* XXX: what if packlen > 576? */
919 rainfo
->ra_datalen
= packlen
;
922 * construct the packet
924 ra
= (struct nd_router_advert
*)buf
;
925 ra
->nd_ra_type
= ND_ROUTER_ADVERT
;
928 ra
->nd_ra_curhoplimit
= (u_int8_t
)(0xff & rainfo
->hoplimit
);
929 ra
->nd_ra_flags_reserved
= 0; /* just in case */
931 * XXX: the router preference field, which is a 2-bit field, should be
932 * initialized before other fields.
934 ra
->nd_ra_flags_reserved
= 0xff & rainfo
->rtpref
;
935 ra
->nd_ra_flags_reserved
|=
936 rainfo
->managedflg
? ND_RA_FLAG_MANAGED
: 0;
937 ra
->nd_ra_flags_reserved
|=
938 rainfo
->otherflg
? ND_RA_FLAG_OTHER
: 0;
940 ra
->nd_ra_flags_reserved
|=
941 rainfo
->haflg
? ND_RA_FLAG_HA
: 0;
943 ra
->nd_ra_router_lifetime
= htons(rainfo
->lifetime
);
944 ra
->nd_ra_reachable
= htonl(rainfo
->reachabletime
);
945 ra
->nd_ra_retransmit
= htonl(rainfo
->retranstimer
);
948 if (rainfo
->advlinkopt
) {
949 lladdropt_fill(rainfo
->sdl
, (struct nd_opt_hdr
*)buf
);
953 if (rainfo
->linkmtu
) {
954 ndopt_mtu
= (struct nd_opt_mtu
*)buf
;
955 ndopt_mtu
->nd_opt_mtu_type
= ND_OPT_MTU
;
956 ndopt_mtu
->nd_opt_mtu_len
= 1;
957 ndopt_mtu
->nd_opt_mtu_reserved
= 0;
958 ndopt_mtu
->nd_opt_mtu_mtu
= htonl(rainfo
->linkmtu
);
959 buf
+= sizeof(struct nd_opt_mtu
);
963 if (mobileip6
&& rainfo
->maxinterval
) {
964 ndopt_advint
= (struct nd_opt_advinterval
*)buf
;
965 ndopt_advint
->nd_opt_adv_type
= ND_OPT_ADVINTERVAL
;
966 ndopt_advint
->nd_opt_adv_len
= 1;
967 ndopt_advint
->nd_opt_adv_reserved
= 0;
968 ndopt_advint
->nd_opt_adv_interval
= htonl(rainfo
->maxinterval
*
970 buf
+= sizeof(struct nd_opt_advinterval
);
975 if (rainfo
->hatime
) {
976 ndopt_hai
= (struct nd_opt_homeagent_info
*)buf
;
977 ndopt_hai
->nd_opt_hai_type
= ND_OPT_HOMEAGENT_INFO
;
978 ndopt_hai
->nd_opt_hai_len
= 1;
979 ndopt_hai
->nd_opt_hai_reserved
= 0;
980 ndopt_hai
->nd_opt_hai_preference
= htons(rainfo
->hapref
);
981 ndopt_hai
->nd_opt_hai_lifetime
= htons(rainfo
->hatime
);
982 buf
+= sizeof(struct nd_opt_homeagent_info
);
986 for (pfx
= rainfo
->prefix
.next
;
987 pfx
!= &rainfo
->prefix
; pfx
= pfx
->next
) {
988 u_int32_t vltime
, pltime
;
991 ndopt_pi
= (struct nd_opt_prefix_info
*)buf
;
992 ndopt_pi
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
993 ndopt_pi
->nd_opt_pi_len
= 4;
994 ndopt_pi
->nd_opt_pi_prefix_len
= pfx
->prefixlen
;
995 ndopt_pi
->nd_opt_pi_flags_reserved
= 0;
997 ndopt_pi
->nd_opt_pi_flags_reserved
|=
998 ND_OPT_PI_FLAG_ONLINK
;
999 if (pfx
->autoconfflg
)
1000 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1001 ND_OPT_PI_FLAG_AUTO
;
1003 if (pfx
->routeraddr
)
1004 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1005 ND_OPT_PI_FLAG_ROUTER
;
1010 if (pfx
->vltimeexpire
|| pfx
->pltimeexpire
)
1011 gettimeofday(&now
, NULL
);
1012 if (pfx
->vltimeexpire
== 0)
1013 vltime
= pfx
->validlifetime
;
1015 vltime
= (pfx
->vltimeexpire
> now
.tv_sec
) ?
1016 pfx
->vltimeexpire
- now
.tv_sec
: 0;
1021 if (pfx
->pltimeexpire
== 0)
1022 pltime
= pfx
->preflifetime
;
1024 pltime
= (pfx
->pltimeexpire
> now
.tv_sec
) ?
1025 pfx
->pltimeexpire
- now
.tv_sec
: 0;
1027 if (vltime
< pltime
) {
1029 * this can happen if vltime is decrement but pltime
1034 ndopt_pi
->nd_opt_pi_valid_time
= htonl(vltime
);
1035 ndopt_pi
->nd_opt_pi_preferred_time
= htonl(pltime
);
1036 ndopt_pi
->nd_opt_pi_reserved2
= 0;
1037 ndopt_pi
->nd_opt_pi_prefix
= pfx
->prefix
;
1039 buf
+= sizeof(struct nd_opt_prefix_info
);
1042 #ifdef ND_OPT_ROUTE_INFO
1043 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
) {
1044 u_int8_t psize
= (rti
->prefixlen
+ 0x3f) >> 6;
1046 ndopt_rti
= (struct nd_opt_route_info
*)buf
;
1047 ndopt_rti
->nd_opt_rti_type
= ND_OPT_ROUTE_INFO
;
1048 ndopt_rti
->nd_opt_rti_len
= 1 + psize
;
1049 ndopt_rti
->nd_opt_rti_prefixlen
= rti
->prefixlen
;
1050 ndopt_rti
->nd_opt_rti_flags
= 0xff & rti
->rtpref
;
1051 ndopt_rti
->nd_opt_rti_lifetime
= htonl(rti
->ltime
);
1052 memcpy(ndopt_rti
+ 1, &rti
->prefix
, psize
* 8);
1053 buf
+= sizeof(struct nd_opt_route_info
) + psize
* 8;
1061 getinet6sysctl(int code
)
1063 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0 };
1068 size
= sizeof(value
);
1069 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]), &value
, &size
, NULL
, 0)
1071 syslog(LOG_ERR
, "<%s>: failed to get ip6 sysctl(%d): %s",