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.3 2001/07/03 11:02:14 ume Exp $
34 #include <sys/param.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
38 #include <sys/sysctl.h>
41 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
42 #include <net/if_var.h>
43 #endif /* __FreeBSD__ >= 3 */
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>
63 #if defined(__NetBSD__) || defined(__OpenBSD__)
75 static void makeentry
__P((char *, int, char *, int));
76 static void get_prefix
__P((struct rainfo
*));
77 static int getinet6sysctl
__P((int));
79 extern struct rainfo
*ralist
;
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",
117 __FUNCTION__
, intface
);
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",
140 __FUNCTION__
, intface
);
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 __FUNCTION__
, 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 __FUNCTION__
, 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",
193 __FUNCTION__
, intface
);
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",
202 __FUNCTION__
, intface
,
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.",
218 __FUNCTION__
, intface
);
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 __FUNCTION__
, 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", __FUNCTION__
);
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",
290 __FUNCTION__
, intface
);
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
);
314 pfx
->origin
= PREFIX_FROM_CONFIG
;
316 makeentry(entbuf
, i
, "prefixlen", added
);
317 MAYHAVE(val
, entbuf
, 64);
318 if (val
< 0 || val
> 128) {
320 "<%s> prefixlen out of range",
324 pfx
->prefixlen
= (int)val
;
326 makeentry(entbuf
, i
, "pinfoflags", added
);
331 (ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
|
332 ND_OPT_PI_FLAG_ROUTER
));
337 (ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
));
339 pfx
->onlinkflg
= val
& ND_OPT_PI_FLAG_ONLINK
;
340 pfx
->autoconfflg
= val
& ND_OPT_PI_FLAG_AUTO
;
342 pfx
->routeraddr
= val
& ND_OPT_PI_FLAG_ROUTER
;
345 makeentry(entbuf
, i
, "vltime", added
);
346 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
347 if (val64
< 0 || val64
> 0xffffffff) {
349 "<%s> vltime out of range",
353 pfx
->validlifetime
= (u_int32_t
)val64
;
355 makeentry(entbuf
, i
, "vltimedecr", added
);
356 if (agetflag(entbuf
)) {
358 gettimeofday(&now
, 0);
360 now
.tv_sec
+ pfx
->validlifetime
;
363 makeentry(entbuf
, i
, "pltime", added
);
364 MAYHAVE(val64
, entbuf
, DEF_ADVPREFERREDLIFETIME
);
365 if (val64
< 0 || val64
> 0xffffffff) {
367 "<%s> pltime out of range",
371 pfx
->preflifetime
= (u_int32_t
)val64
;
373 makeentry(entbuf
, i
, "pltimedecr", added
);
374 if (agetflag(entbuf
)) {
376 gettimeofday(&now
, 0);
378 now
.tv_sec
+ pfx
->preflifetime
;
381 makeentry(entbuf
, i
, "addr", added
);
382 addr
= (char *)agetstr(entbuf
, &bp
);
385 "<%s> need %s as an prefix for "
387 __FUNCTION__
, entbuf
, intface
);
390 if (inet_pton(AF_INET6
, addr
,
391 &pfx
->prefix
) != 1) {
393 "<%s> inet_pton failed for %s",
397 if (IN6_IS_ADDR_MULTICAST(&pfx
->prefix
)) {
399 "<%s> multicast prefix(%s) must "
400 "not be advertised (IF=%s)",
401 __FUNCTION__
, addr
, intface
);
404 if (IN6_IS_ADDR_LINKLOCAL(&pfx
->prefix
))
406 "<%s> link-local prefix(%s) will be"
408 __FUNCTION__
, addr
, intface
);
412 MAYHAVE(val
, "mtu", 0);
413 if (val
< 0 || val
> 0xffffffff) {
415 "<%s> mtu out of range", __FUNCTION__
);
418 tmp
->linkmtu
= (u_int32_t
)val
;
419 if (tmp
->linkmtu
== 0) {
422 if ((mtustr
= (char *)agetstr("mtu", &bp
)) &&
423 strcmp(mtustr
, "auto") == 0)
424 tmp
->linkmtu
= tmp
->phymtu
;
426 else if (tmp
->linkmtu
< IPV6_MMTU
|| tmp
->linkmtu
> tmp
->phymtu
) {
428 "<%s> advertised link mtu must be between"
429 " least MTU and physical link MTU",
434 /* route information */
436 MAYHAVE(val
, "routes", 0);
437 if (val
< 0 || val
> 0xffffffff) {
439 "<%s> number of route information improper", __FUNCTION__
);
443 for (i
= 0; i
< tmp
->routes
; i
++) {
446 int added
= (tmp
->routes
> 1) ? 1 : 0;
448 /* allocate memory to store prefix information */
449 if ((rti
= malloc(sizeof(struct rtinfo
))) == NULL
) {
451 "<%s> can't allocate enough memory",
455 memset(rti
, 0, sizeof(*rti
));
457 /* link into chain */
458 insque(rti
, &tmp
->route
);
460 makeentry(entbuf
, i
, "rtrplen", added
);
461 MAYHAVE(val
, entbuf
, 64);
462 if (val
< 0 || val
> 128) {
464 "<%s> prefixlen out of range",
468 rti
->prefixlen
= (int)val
;
470 makeentry(entbuf
, i
, "rtrflags", added
);
471 MAYHAVE(val
, entbuf
, 0);
472 rti
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
473 if (rti
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
474 syslog(LOG_ERR
, "<%s> invalid router preference",
479 makeentry(entbuf
, i
, "rtrltime", added
);
481 * XXX: since default value of route lifetime is not defined in
482 * draft-draves-route-selection-01.txt, I took the default
483 * value of valid lifetime of prefix as its default.
484 * It need be much considered.
486 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
487 if (val64
< 0 || val64
> 0xffffffff) {
489 "<%s> rtrltime out of range",
493 rti
->ltime
= (u_int32_t
)val64
;
495 makeentry(entbuf
, i
, "rtrprefix", added
);
496 addr
= (char *)agetstr(entbuf
, &bp
);
499 "<%s> need %s as an route for "
501 __FUNCTION__
, entbuf
, intface
);
504 if (inet_pton(AF_INET6
, addr
, &rti
->prefix
) != 1) {
506 "<%s> inet_pton failed for %s",
512 * XXX: currently there's no restriction in route information
513 * prefix according to draft-draves-route-selection-01.txt,
514 * however I think the similar restriction be necessary.
516 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
517 if (IN6_IS_ADDR_MULTICAST(&rti
->prefix
)) {
519 "<%s> multicast route (%s) must "
520 "not be advertised (IF=%s)",
521 __FUNCTION__
, addr
, intface
);
524 if (IN6_IS_ADDR_LINKLOCAL(&rti
->prefix
)) {
526 "<%s> link-local route (%s) must "
527 "not be advertised on %s",
528 __FUNCTION__
, addr
, intface
);
538 /* construct the sending packet */
542 tmp
->timer
= rtadvd_add_timer(ra_timeout
, ra_timer_update
,
544 ra_timer_update((void *)tmp
, &tmp
->timer
->tm
);
545 rtadvd_set_timer(&tmp
->timer
->tm
, tmp
->timer
);
549 get_prefix(struct rainfo
*rai
)
551 struct ifaddrs
*ifap
, *ifa
;
554 u_char
*p
, *ep
, *m
, *lim
;
555 u_char ntopbuf
[INET6_ADDRSTRLEN
];
557 if (getifaddrs(&ifap
) < 0) {
559 "<%s> can't get interface addresses",
563 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
564 if (strcmp(ifa
->ifa_name
, rai
->ifname
) != 0)
566 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
568 a
= &((struct sockaddr_in6
*)ifa
->ifa_addr
)->sin6_addr
;
569 if (IN6_IS_ADDR_LINKLOCAL(a
))
572 /* allocate memory to store prefix info. */
573 if ((pp
= malloc(sizeof(*pp
))) == NULL
) {
575 "<%s> can't get allocate buffer for prefix",
579 memset(pp
, 0, sizeof(*pp
));
581 /* set prefix length */
582 m
= (u_char
*)&((struct sockaddr_in6
*)ifa
->ifa_netmask
)->sin6_addr
;
583 lim
= (u_char
*)(ifa
->ifa_netmask
) + ifa
->ifa_netmask
->sa_len
;
584 pp
->prefixlen
= prefixlen(m
, lim
);
585 if (pp
->prefixlen
< 0 || pp
->prefixlen
> 128) {
587 "<%s> failed to get prefixlen "
588 "or prefix is invalid",
593 /* set prefix, sweep bits outside of prefixlen */
594 memcpy(&pp
->prefix
, a
, sizeof(*a
));
595 p
= (u_char
*)&pp
->prefix
;
596 ep
= (u_char
*)(&pp
->prefix
+ 1);
602 if (!inet_ntop(AF_INET6
, &pp
->prefix
, ntopbuf
,
604 syslog(LOG_ERR
, "<%s> inet_ntop failed", __FUNCTION__
);
608 "<%s> add %s/%d to prefix list on %s",
609 __FUNCTION__
, ntopbuf
, pp
->prefixlen
, rai
->ifname
);
611 /* set other fields with protocol defaults */
612 pp
->validlifetime
= DEF_ADVVALIDLIFETIME
;
613 pp
->preflifetime
= DEF_ADVPREFERREDLIFETIME
;
616 pp
->origin
= PREFIX_FROM_KERNEL
;
618 /* link into chain */
619 insque(pp
, &rai
->prefix
);
621 /* counter increment */
629 makeentry(buf
, id
, string
, add
)
637 cp
= (char *)index(buf
, '\0');
638 cp
+= sprintf(cp
, "%d", id
);
644 * Add a prefix to the list of specified interface and reconstruct
645 * the outgoing packet.
646 * The prefix must not be in the list.
647 * XXX: other parameter of the prefix(e.g. lifetime) shoule be
648 * able to be specified.
651 add_prefix(struct rainfo
*rai
, struct in6_prefixreq
*ipr
)
653 struct prefix
*prefix
;
654 u_char ntopbuf
[INET6_ADDRSTRLEN
];
656 if ((prefix
= malloc(sizeof(*prefix
))) == NULL
) {
657 syslog(LOG_ERR
, "<%s> memory allocation failed",
659 return; /* XXX: error or exit? */
661 memset(prefix
, 0, sizeof(*prefix
));
662 prefix
->prefix
= ipr
->ipr_prefix
.sin6_addr
;
663 prefix
->prefixlen
= ipr
->ipr_plen
;
664 prefix
->validlifetime
= ipr
->ipr_vltime
;
665 prefix
->preflifetime
= ipr
->ipr_pltime
;
666 prefix
->onlinkflg
= ipr
->ipr_raf_onlink
;
667 prefix
->autoconfflg
= ipr
->ipr_raf_auto
;
668 prefix
->origin
= PREFIX_FROM_DYNAMIC
;
670 insque(prefix
, &rai
->prefix
);
672 syslog(LOG_DEBUG
, "<%s> new prefix %s/%d was added on %s",
673 __FUNCTION__
, inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
,
674 ntopbuf
, INET6_ADDRSTRLEN
),
675 ipr
->ipr_plen
, rai
->ifname
);
677 /* free the previous packet */
681 /* reconstruct the packet */
686 * reset the timer so that the new prefix will be advertised quickly.
688 rai
->initcounter
= 0;
689 ra_timer_update((void *)rai
, &rai
->timer
->tm
);
690 rtadvd_set_timer(&rai
->timer
->tm
, rai
->timer
);
694 * Delete a prefix to the list of specified interface and reconstruct
695 * the outgoing packet.
696 * The prefix must be in the list.
699 delete_prefix(struct rainfo
*rai
, struct prefix
*prefix
)
701 u_char ntopbuf
[INET6_ADDRSTRLEN
];
704 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was deleted on %s",
705 __FUNCTION__
, inet_ntop(AF_INET6
, &prefix
->prefix
,
706 ntopbuf
, INET6_ADDRSTRLEN
),
707 prefix
->prefixlen
, rai
->ifname
);
714 * Try to get an in6_prefixreq contents for a prefix which matches
715 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
716 * the interface whose name is ipr->ipr_name[].
719 init_prefix(struct in6_prefixreq
*ipr
)
723 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
724 syslog(LOG_ERR
, "<%s> socket: %s", __FUNCTION__
,
729 if (ioctl(s
, SIOCGIFPREFIX_IN6
, (caddr_t
)ipr
) < 0) {
730 syslog(LOG_INFO
, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__
,
733 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
734 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
735 ipr
->ipr_raf_onlink
= 1;
736 ipr
->ipr_raf_auto
= 1;
737 /* omit other field initialization */
739 else if (ipr
->ipr_origin
< PR_ORIG_RR
) {
740 u_char ntopbuf
[INET6_ADDRSTRLEN
];
742 syslog(LOG_WARNING
, "<%s> Added prefix(%s)'s origin %d is"
743 "lower than PR_ORIG_RR(router renumbering)."
744 "This should not happen if I am router", __FUNCTION__
,
745 inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
, ntopbuf
,
746 sizeof(ntopbuf
)), ipr
->ipr_origin
);
756 make_prefix(struct rainfo
*rai
, int ifindex
, struct in6_addr
*addr
, int plen
)
758 struct in6_prefixreq ipr
;
760 memset(&ipr
, 0, sizeof(ipr
));
761 if (if_indextoname(ifindex
, ipr
.ipr_name
) == NULL
) {
762 syslog(LOG_ERR
, "<%s> Prefix added interface No.%d doesn't"
763 "exist. This should not happen! %s", __FUNCTION__
,
764 ifindex
, strerror(errno
));
767 ipr
.ipr_prefix
.sin6_len
= sizeof(ipr
.ipr_prefix
);
768 ipr
.ipr_prefix
.sin6_family
= AF_INET6
;
769 ipr
.ipr_prefix
.sin6_addr
= *addr
;
772 if (init_prefix(&ipr
))
773 return; /* init failed by some error */
774 add_prefix(rai
, &ipr
);
778 make_packet(struct rainfo
*rainfo
)
780 size_t packlen
, lladdroptlen
= 0;
782 struct nd_router_advert
*ra
;
783 struct nd_opt_prefix_info
*ndopt_pi
;
784 struct nd_opt_mtu
*ndopt_mtu
;
786 struct nd_opt_advinterval
*ndopt_advint
;
787 struct nd_opt_homeagent_info
*ndopt_hai
;
789 struct nd_opt_route_info
*ndopt_rti
;
793 /* calculate total length */
794 packlen
= sizeof(struct nd_router_advert
);
795 if (rainfo
->advlinkopt
) {
796 if ((lladdroptlen
= lladdropt_length(rainfo
->sdl
)) == 0) {
798 "<%s> link-layer address option has"
799 " null length on %s."
800 " Treat as not included.",
801 __FUNCTION__
, rainfo
->ifname
);
802 rainfo
->advlinkopt
= 0;
804 packlen
+= lladdroptlen
;
807 packlen
+= sizeof(struct nd_opt_prefix_info
) * rainfo
->pfxs
;
809 packlen
+= sizeof(struct nd_opt_mtu
);
811 if (mobileip6
&& rainfo
->maxinterval
)
812 packlen
+= sizeof(struct nd_opt_advinterval
);
813 if (mobileip6
&& rainfo
->hatime
)
814 packlen
+= sizeof(struct nd_opt_homeagent_info
);
816 #ifdef ND_OPT_ROUTE_INFO
817 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
)
818 packlen
+= sizeof(struct nd_opt_route_info
) +
819 ((rti
->prefixlen
+ 0x3f) >> 6) * 8;
822 /* allocate memory for the packet */
823 if ((buf
= malloc(packlen
)) == NULL
) {
825 "<%s> can't get enough memory for an RA packet",
829 if (rainfo
->ra_data
) {
830 /* free the previous packet */
831 free(rainfo
->ra_data
);
832 rainfo
->ra_data
= NULL
;
834 rainfo
->ra_data
= buf
;
835 /* XXX: what if packlen > 576? */
836 rainfo
->ra_datalen
= packlen
;
839 * construct the packet
841 ra
= (struct nd_router_advert
*)buf
;
842 ra
->nd_ra_type
= ND_ROUTER_ADVERT
;
845 ra
->nd_ra_curhoplimit
= (u_int8_t
)(0xff & rainfo
->hoplimit
);
846 ra
->nd_ra_flags_reserved
= 0; /* just in case */
848 * XXX: the router preference field, which is a 2-bit field, should be
849 * initialized before other fields.
851 ra
->nd_ra_flags_reserved
= 0xff & rainfo
->rtpref
;
852 ra
->nd_ra_flags_reserved
|=
853 rainfo
->managedflg
? ND_RA_FLAG_MANAGED
: 0;
854 ra
->nd_ra_flags_reserved
|=
855 rainfo
->otherflg
? ND_RA_FLAG_OTHER
: 0;
857 ra
->nd_ra_flags_reserved
|=
858 rainfo
->haflg
? ND_RA_FLAG_HA
: 0;
860 ra
->nd_ra_router_lifetime
= htons(rainfo
->lifetime
);
861 ra
->nd_ra_reachable
= htonl(rainfo
->reachabletime
);
862 ra
->nd_ra_retransmit
= htonl(rainfo
->retranstimer
);
865 if (rainfo
->advlinkopt
) {
866 lladdropt_fill(rainfo
->sdl
, (struct nd_opt_hdr
*)buf
);
870 if (rainfo
->linkmtu
) {
871 ndopt_mtu
= (struct nd_opt_mtu
*)buf
;
872 ndopt_mtu
->nd_opt_mtu_type
= ND_OPT_MTU
;
873 ndopt_mtu
->nd_opt_mtu_len
= 1;
874 ndopt_mtu
->nd_opt_mtu_reserved
= 0;
875 ndopt_mtu
->nd_opt_mtu_mtu
= htonl(rainfo
->linkmtu
);
876 buf
+= sizeof(struct nd_opt_mtu
);
880 if (mobileip6
&& rainfo
->maxinterval
) {
881 ndopt_advint
= (struct nd_opt_advinterval
*)buf
;
882 ndopt_advint
->nd_opt_adv_type
= ND_OPT_ADVINTERVAL
;
883 ndopt_advint
->nd_opt_adv_len
= 1;
884 ndopt_advint
->nd_opt_adv_reserved
= 0;
885 ndopt_advint
->nd_opt_adv_interval
= htonl(rainfo
->maxinterval
*
887 buf
+= sizeof(struct nd_opt_advinterval
);
892 if (rainfo
->hatime
) {
893 ndopt_hai
= (struct nd_opt_homeagent_info
*)buf
;
894 ndopt_hai
->nd_opt_hai_type
= ND_OPT_HOMEAGENT_INFO
;
895 ndopt_hai
->nd_opt_hai_len
= 1;
896 ndopt_hai
->nd_opt_hai_reserved
= 0;
897 ndopt_hai
->nd_opt_hai_preference
= htons(rainfo
->hapref
);
898 ndopt_hai
->nd_opt_hai_lifetime
= htons(rainfo
->hatime
);
899 buf
+= sizeof(struct nd_opt_homeagent_info
);
903 for (pfx
= rainfo
->prefix
.next
;
904 pfx
!= &rainfo
->prefix
; pfx
= pfx
->next
) {
905 u_int32_t vltime
, pltime
;
908 ndopt_pi
= (struct nd_opt_prefix_info
*)buf
;
909 ndopt_pi
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
910 ndopt_pi
->nd_opt_pi_len
= 4;
911 ndopt_pi
->nd_opt_pi_prefix_len
= pfx
->prefixlen
;
912 ndopt_pi
->nd_opt_pi_flags_reserved
= 0;
914 ndopt_pi
->nd_opt_pi_flags_reserved
|=
915 ND_OPT_PI_FLAG_ONLINK
;
916 if (pfx
->autoconfflg
)
917 ndopt_pi
->nd_opt_pi_flags_reserved
|=
921 ndopt_pi
->nd_opt_pi_flags_reserved
|=
922 ND_OPT_PI_FLAG_ROUTER
;
924 if (pfx
->vltimeexpire
|| pfx
->pltimeexpire
)
925 gettimeofday(&now
, NULL
);
926 if (pfx
->vltimeexpire
== 0)
927 vltime
= pfx
->validlifetime
;
929 vltime
= (pfx
->vltimeexpire
> now
.tv_sec
) ?
930 pfx
->vltimeexpire
- now
.tv_sec
: 0;
931 if (pfx
->pltimeexpire
== 0)
932 pltime
= pfx
->preflifetime
;
934 pltime
= (pfx
->pltimeexpire
> now
.tv_sec
) ?
935 pfx
->pltimeexpire
- now
.tv_sec
: 0;
936 if (vltime
< pltime
) {
938 * this can happen if vltime is decrement but pltime
943 ndopt_pi
->nd_opt_pi_valid_time
= htonl(vltime
);
944 ndopt_pi
->nd_opt_pi_preferred_time
= htonl(pltime
);
945 ndopt_pi
->nd_opt_pi_reserved2
= 0;
946 ndopt_pi
->nd_opt_pi_prefix
= pfx
->prefix
;
948 buf
+= sizeof(struct nd_opt_prefix_info
);
951 #ifdef ND_OPT_ROUTE_INFO
952 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
) {
953 u_int8_t psize
= (rti
->prefixlen
+ 0x3f) >> 6;
955 ndopt_rti
= (struct nd_opt_route_info
*)buf
;
956 ndopt_rti
->nd_opt_rti_type
= ND_OPT_ROUTE_INFO
;
957 ndopt_rti
->nd_opt_rti_len
= 1 + psize
;
958 ndopt_rti
->nd_opt_rti_prefixlen
= rti
->prefixlen
;
959 ndopt_rti
->nd_opt_rti_flags
= 0xff & rti
->rtpref
;
960 ndopt_rti
->nd_opt_rti_lifetime
= rti
->ltime
;
961 memcpy(ndopt_rti
+ 1, &rti
->prefix
, psize
* 8);
962 buf
+= sizeof(struct nd_opt_route_info
) + psize
* 8;
970 getinet6sysctl(int code
)
972 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0 };
977 size
= sizeof(value
);
978 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]), &value
, &size
, NULL
, 0)
980 syslog(LOG_ERR
, "<%s>: failed to get ip6 sysctl(%d): %s",