Hello,

I have ported support for advertising route information, from FreeBSD's
rtadvd. This is derived from FreeBSD's svn revision 78064. That was from
KAME originally.

------------------------------------------------------------------------
UMEZAWA Takeshi (FAMILY Given) <[email protected]>
Internet Initiative Japan Inc.



diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h
index 58476b6..432113c 100644
--- a/sys/netinet/icmp6.h
+++ b/sys/netinet/icmp6.h
@@ -200,6 +200,13 @@ struct mld_hdr {
  * Neighbor Discovery
  */
 
+#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
+
+#define ND_RA_FLAG_RTPREF_HIGH 0x08 /* 00001000 */
+#define ND_RA_FLAG_RTPREF_MEDIUM       0x00 /* 00000000 */
+#define ND_RA_FLAG_RTPREF_LOW  0x18 /* 00011000 */
+#define ND_RA_FLAG_RTPREF_RSV  0x10 /* 00010000 */
+
 struct nd_router_solicit {     /* router solicitation */
        struct icmp6_hdr        nd_rs_hdr;
        /* could be followed by options */
@@ -282,6 +289,7 @@ struct nd_opt_hdr {         /* Neighbor discovery option 
header */
 #define ND_OPT_PREFIX_INFORMATION      3
 #define ND_OPT_REDIRECTED_HEADER       4
 #define ND_OPT_MTU                     5
+#define ND_OPT_ROUTE_INFO              24
 #define ND_OPT_RDNSS                   25
 #define ND_OPT_DNSSL                   31
 
@@ -314,6 +322,14 @@ struct nd_opt_mtu {                /* MTU option */
        u_int32_t       nd_opt_mtu_mtu;
 } __packed;
 
+struct nd_opt_route_info {     /* route info */
+       u_int8_t        nd_opt_rti_type;
+       u_int8_t        nd_opt_rti_len;
+       u_int8_t        nd_opt_rti_prefixlen;
+       u_int8_t        nd_opt_rti_flags;
+       u_int32_t       nd_opt_rti_lifetime;
+} __packed;
+
 struct nd_opt_rdnss {          /* RDNSS option */
        u_int8_t        nd_opt_rdnss_type;
        u_int8_t        nd_opt_rdnss_len;
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index 53719ec..f38b69d 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -111,6 +111,7 @@ getconfig(intface)
        TAILQ_INIT(&tmp->prefixes);
        TAILQ_INIT(&tmp->rdnsss);
        TAILQ_INIT(&tmp->dnssls);
+       TAILQ_INIT(&tmp->rtinfos);
        SLIST_INIT(&tmp->soliciters);
 
        /* check if we are allowed to forward packets (if not determined) */
@@ -325,6 +326,77 @@ getconfig(intface)
        if (tmp->pfxs == 0 && !agetflag("noifprefix"))
                get_prefix(tmp);
 
+       tmp->rtinfocnt = 0;
+       for (i = -1; i < MAXRTINFO; i++) {
+               struct rtinfo *rti;
+               char entbuf[256];
+               const char *flagstr;
+
+               makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
+               addr = (char *)agetstr(entbuf, &bp);
+               if (addr == NULL)
+                       continue;
+
+               rti = malloc(sizeof(struct rtinfo));
+               if (rti == NULL)
+                       fatal("malloc");
+
+               if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
+                       log_warn("inet_pton failed for %s", addr);
+                       exit(1);
+               }
+
+               makeentry(entbuf, sizeof(entbuf), i, "rtplen");
+               MAYHAVE(val, entbuf, 64);
+               if (val < 0 || val > 128) {
+                       log_warnx("route prefixlen (%ld) for %s "
+                            "on %s out of range",
+                           val, addr, intface);
+                       exit(1);
+               }
+               rti->prefixlen = (int)val;
+
+               makeentry(entbuf, sizeof(entbuf), i, "rtflags");
+               if ((flagstr = (char *)agetstr(entbuf, &bp))) {
+                       val = 0;
+                       if (strchr(flagstr, 'h'))
+                               val |= ND_RA_FLAG_RTPREF_HIGH;
+                       if (strchr(flagstr, 'l')) {
+                               if (val & ND_RA_FLAG_RTPREF_HIGH) {
+                                       log_warnx("the \'h\' and \'l\'"
+                                           " route preferences are"
+                                           " exclusive");
+                                       exit(1);
+                               }
+                               val |= ND_RA_FLAG_RTPREF_LOW;
+                       }
+               } else {
+                       MAYHAVE(val, entbuf, 0);
+               }
+               rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
+               if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) {
+                       log_warnx("invalid route preference (%02x)"
+                           " for %s/%d on %s",
+                           rti->rtpref, addr, rti->prefixlen, intface);
+                       exit(1);
+               }
+
+               makeentry(entbuf, sizeof(entbuf), i, "rtltime");
+               MAYHAVE(val64, entbuf, -1);
+               if (val64 == -1)
+                       val = tmp->lifetime;
+               if (val64 < 0 || val64 >= 0xffffffff) {
+                       log_warnx("route lifetime (%d) "
+                           " for %s/%d on %s out of range",
+                           rti->rtpref, addr, rti->prefixlen, intface);
+                       exit(1);
+               }
+               rti->lifetime = (uint32_t)val64;
+
+               TAILQ_INSERT_TAIL(&tmp->rtinfos, rti, entry);
+               tmp->rtinfocnt++;
+       }
+
        tmp->rdnsscnt = 0;
        for (i = -1; i < MAXRDNSS; ++i) {
                struct rdnss *rds;
@@ -698,9 +770,11 @@ make_packet(struct rainfo *rainfo)
        struct nd_router_advert *ra;
        struct nd_opt_prefix_info *ndopt_pi;
        struct nd_opt_mtu *ndopt_mtu;
+       struct nd_opt_route_info *ndopt_rti;
        struct nd_opt_rdnss *ndopt_rdnss;
        struct nd_opt_dnssl *ndopt_dnssl;
        struct prefix *pfx;
+       struct rtinfo *rti;
        struct rdnss *rds;
        struct dnssl *dsl;
        struct dnssldom *dnsd;
@@ -720,6 +794,9 @@ make_packet(struct rainfo *rainfo)
                packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
        if (rainfo->linkmtu)
                packlen += sizeof(struct nd_opt_mtu);
+       TAILQ_FOREACH(rti, &rainfo->rtinfos, entry)
+               packlen += sizeof(struct nd_opt_route_info) +
+                   ((rti->prefixlen + 0x3f) >> 6) * 8;
        TAILQ_FOREACH(rds, &rainfo->rdnsss, entry)
                packlen += sizeof(struct nd_opt_rdnss) + 16 * rds->servercnt;
        TAILQ_FOREACH(dsl, &rainfo->dnssls, entry) {
@@ -828,6 +905,19 @@ make_packet(struct rainfo *rainfo)
                buf += sizeof(struct nd_opt_prefix_info);
        }
 
+       TAILQ_FOREACH(rti, &rainfo->rtinfos, entry) {
+               uint8_t psize = (rti->prefixlen + 0x3f) >> 6;
+
+               ndopt_rti = (struct nd_opt_route_info *)buf;
+               ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
+               ndopt_rti->nd_opt_rti_len = 1 + psize;
+               ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
+               ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
+               ndopt_rti->nd_opt_rti_lifetime = htonl(rti->lifetime);
+               memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
+               buf += sizeof(struct nd_opt_route_info) + psize * 8;
+       }
+
        TAILQ_FOREACH(rds, &rainfo->rdnsss, entry) {
                ndopt_rdnss = (struct nd_opt_rdnss *)buf;
                ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h
index 53b97bc..495af88 100644
--- a/usr.sbin/rtadvd/config.h
+++ b/usr.sbin/rtadvd/config.h
@@ -44,3 +44,4 @@ extern void get_prefix __P((struct rainfo *));
 #define MAXPREFIX      100
 #define MAXRDNSS       100
 #define MAXDNSSL       100
+#define MAXRTINFO      100
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c
index 37757b4..48b2ada 100644
--- a/usr.sbin/rtadvd/rtadvd.c
+++ b/usr.sbin/rtadvd/rtadvd.c
@@ -121,6 +121,7 @@ union nd_opts {
 #define NDOPT_FLAG_MTU         (1 << 4)
 #define NDOPT_FLAG_RDNSS       (1 << 5)
 #define NDOPT_FLAG_DNSSL       (1 << 6)
+#define NDOPT_FLAG_RTINFO      (1 << 7)
 
 u_int32_t ndopt_flags[] = {
        [ND_OPT_SOURCE_LINKADDR]        = NDOPT_FLAG_SRCLINKADDR,
@@ -128,6 +129,7 @@ u_int32_t ndopt_flags[] = {
        [ND_OPT_PREFIX_INFORMATION]     = NDOPT_FLAG_PREFIXINFO,
        [ND_OPT_REDIRECTED_HEADER]      = NDOPT_FLAG_RDHDR,
        [ND_OPT_MTU]                    = NDOPT_FLAG_MTU,
+       [ND_OPT_ROUTE_INFO]             = NDOPT_FLAG_RTINFO,
        [ND_OPT_RDNSS]                  = NDOPT_FLAG_RDNSS,
        [ND_OPT_DNSSL]                  = NDOPT_FLAG_DNSSL,
 };
@@ -812,7 +814,8 @@ ra_input(int len, struct nd_router_advert *ra,
        if (nd6_options((struct nd_opt_hdr *)(ra + 1),
                        len - sizeof(struct nd_router_advert),
                        &ndopts, NDOPT_FLAG_SRCLINKADDR | NDOPT_FLAG_PREFIXINFO
-                       | NDOPT_FLAG_MTU | NDOPT_FLAG_RDNSS | 
NDOPT_FLAG_DNSSL)) {
+                       | NDOPT_FLAG_MTU | NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL
+                       | NDOPT_FLAG_RTINFO)) {
                log_warnx("ND option check failed for an RA from %s on %s",
                    inet_ntop(AF_INET6, &from->sin6_addr,
                        ntopbuf, INET6_ADDRSTRLEN),
@@ -1112,6 +1115,7 @@ nd6_options(struct nd_opt_hdr *hdr, int limit,
                }
 
                if (hdr->nd_opt_type > ND_OPT_MTU &&
+                   hdr->nd_opt_type != ND_OPT_ROUTE_INFO &&
                    hdr->nd_opt_type != ND_OPT_RDNSS &&
                    hdr->nd_opt_type != ND_OPT_DNSSL)
                {
diff --git a/usr.sbin/rtadvd/rtadvd.conf b/usr.sbin/rtadvd/rtadvd.conf
index 04725a4..d4bdaab 100644
--- a/usr.sbin/rtadvd/rtadvd.conf
+++ b/usr.sbin/rtadvd/rtadvd.conf
@@ -19,4 +19,5 @@
  
 #ef0:\
 #      :addr="2001:db8:ffff:1000::":prefixlen#64:\
+#      :rtprefix="2001:db8:ffff:1001::":\
 #      :rdnss="2001:db8:ffff:1000::1":dnssl="example.com":
diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5
index 185ed56..3de5c34 100644
--- a/usr.sbin/rtadvd/rtadvd.conf.5
+++ b/usr.sbin/rtadvd/rtadvd.conf.5
@@ -231,6 +231,45 @@ is specified for this item, MTU option will be included 
and its value
 will be set to the interface MTU automatically.
 .El
 .Pp
+The following items are for ICMPv6 route information option,
+which will be attached to router advertisement header.
+These items are optional.
+Each items can be augmented with number, like
+.Dq Li rtplen2 ,
+to specify multiple routes.
+.Bl -tag -width indent
+.It Cm \&rtprefix
+(str) The prefix filled into the Prefix field of route information option.
+Since
+.Dq \&:
+is used for
+.Xr termcap 5
+file format as well as IPv6 numeric address, the field MUST be quoted by
+doublequote character.
+.It Cm \&rtplen
+(num) Prefix length field in route information option.
+The default value is 64.
+.It Cm \&rtflags
+(str or num) A 8-bit flags field in route information option.
+Currently only the preference values are defined.
+The notation is same as that of the raflags field.
+Bit 4
+.Po
+.Li 0x10
+.Pc
+and
+Bit 3
+.Po
+.Li 0x08
+.Pc
+are used to encode the route preference for the route.
+The default value is 0x00, i.e., medium preference.
+.It Cm \&rtltime
+(num) route lifetime field in route information option.
+.Pq unit: seconds .
+The default value is same as router lifetime.
+.El
+.Pp
 The following items are for ICMPv6 RDNSS option, used to give a list of
 recursive DNS servers to hosts.
 If this item is omitted, no information about DNS servers will be advertised.
@@ -349,6 +388,13 @@ ef0:\e
 .%T Neighbor Discovery for IP version 6 (IPv6)
 .Re
 .Rs
+.%A R. Draves
+.%A D. Thaler
+.%D 2005
+.%R RFC 4191
+.%T Default Router Preferences and More-Specific Routes
+.Re
+.Rs
 .%A J. Jeong
 .%A S. Park
 .%A L. Beloeil
diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h
index 34ffbae..5c2ccec 100644
--- a/usr.sbin/rtadvd/rtadvd.h
+++ b/usr.sbin/rtadvd/rtadvd.h
@@ -82,6 +82,15 @@ struct prefix {
        struct in6_addr prefix;
 };
 
+struct rtinfo {
+       TAILQ_ENTRY(rtinfo) entry;
+
+       uint32_t lifetime;
+       int rtpref;
+       int prefixlen;
+       struct in6_addr prefix;
+};
+
 struct rdnss {
        TAILQ_ENTRY(rdnss) entry;
 
@@ -143,6 +152,8 @@ struct      rainfo {
        int     rdnsscnt;       /* number of rdnss entries */
        TAILQ_HEAD(dnssllist, dnssl) dnssls;
        int     dnsslcnt;
+       TAILQ_HEAD(rtinfolist, rtinfo) rtinfos;
+       int     rtinfocnt;
        long    clockskew;      /* used for consisitency check of lifetimes */

Reply via email to