diff options
author | Andrew Zaborowski <andrew.zaborowski@intel.com> | 2022-09-19 15:30:59 +0200 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2022-09-19 13:26:11 -0500 |
commit | 5fc3c8d84677560b534b9799063471fb0e837383 (patch) | |
tree | c81e868ec416735b166bfb4b0accfea9a02af462 | |
parent | 408f6a8150c5e5dfc812146f9f8a3f9f149f727a (diff) |
icmp6: Save SLAAC prefixes from RAs
In struct l_icmp6_router save the lists of prefixes for autoconfiguration
separately from routes. The two sets of prefixes may overlap completely,
partially or not at all. Drop the preferred_lifetime information from
route_info since this is strictly to be used as the preferred lifetime
for addresses generated through SLAAC and has nothing to do with routes.
-rw-r--r-- | ell/icmp6-private.h | 7 | ||||
-rw-r--r-- | ell/icmp6.c | 98 | ||||
-rw-r--r-- | ell/netconfig.c | 7 |
3 files changed, 77 insertions, 35 deletions
diff --git a/ell/icmp6-private.h b/ell/icmp6-private.h index 77df0b85..a26639d9 100644 --- a/ell/icmp6-private.h +++ b/ell/icmp6-private.h @@ -25,6 +25,11 @@ struct route_info { bool onlink : 1; uint8_t prefix_len; uint8_t preference; + uint32_t valid_lifetime; +}; + +struct autoconf_prefix_info { + uint8_t prefix[8]; uint32_t preferred_lifetime; uint32_t valid_lifetime; }; @@ -40,6 +45,8 @@ struct l_icmp6_router { uint32_t max_rtr_adv_interval_ms; uint32_t n_routes; struct route_info *routes; + uint32_t n_ac_prefixes; + struct autoconf_prefix_info *ac_prefixes; }; struct l_icmp6_router *_icmp6_router_new(); diff --git a/ell/icmp6.c b/ell/icmp6.c index 7319903d..b71a98f4 100644 --- a/ell/icmp6.c +++ b/ell/icmp6.c @@ -693,9 +693,58 @@ struct l_icmp6_router *_icmp6_router_new() void _icmp6_router_free(struct l_icmp6_router *r) { l_free(r->routes); + l_free(r->ac_prefixes); l_free(r); } +/* Note: the following two write to @out even when they return false */ +static bool icmp6_prefix_parse_rt_info(const uint8_t *data, + struct route_info *out) +{ + out->prefix_len = data[2]; + out->onlink = true; + out->preference = 0; + out->valid_lifetime = l_get_be32(data + 4); + + /* + * Only the initial Prefix Length bits of the prefix are valid. + * The remaining bits "MUST" be ignored by the receiver. + */ + memcpy(out->address, net_prefix_from_ipv6(data + 16, out->prefix_len), + 16); + + if (out->prefix_len >= 10 && IN6_IS_ADDR_LINKLOCAL(out->address)) + return false; + + return true; +} + +static bool icmp6_prefix_parse_ac_info(const uint8_t *data, + struct autoconf_prefix_info *out) +{ + /* + * Per RFC4862 we need to silently ignore prefixes with a + * preferred lifetime longer than valid lifetime, those with + * 0 valid lifetime and those with link-local prefixes. + * Prefix Length must be 8 bytes (IPv6 address - Interface ID). + */ + if (data[2] != 64) + return false; + + if (IN6_IS_ADDR_LINKLOCAL(data + 16)) + return false; + + out->valid_lifetime = l_get_be32(data + 4); + out->preferred_lifetime = l_get_be32(data + 8); + + if (out->valid_lifetime == 0 || + out->preferred_lifetime > out->valid_lifetime) + return false; + + memcpy(out->prefix, data + 16, 8); + return true; +} + struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra, size_t len, const uint8_t src[static 16], @@ -705,6 +754,7 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra, const uint8_t *opts; uint32_t opts_len; uint32_t n_routes = 0; + uint32_t n_ac_prefixes = 0; if (ra->nd_ra_type != ND_ROUTER_ADVERT) return NULL; @@ -742,6 +792,10 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra, if (opts[3] & ND_OPT_PI_FLAG_ONLINK) n_routes += 1; + + if (opts[3] & ND_OPT_PI_FLAG_AUTO) + n_ac_prefixes += 1; + break; case ND_OPT_ROUTE_INFORMATION: if (l < 8) @@ -781,6 +835,8 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra, memcpy(r->address, src, sizeof(r->address)); r->routes = l_new(struct route_info, n_routes); r->n_routes = n_routes; + r->ac_prefixes = l_new(struct autoconf_prefix_info, n_ac_prefixes); + r->n_ac_prefixes = n_ac_prefixes; if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) r->managed = true; @@ -798,6 +854,7 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra, opts = (uint8_t *) (ra + 1); opts_len = len - sizeof(struct nd_router_advert); n_routes = 0; + n_ac_prefixes = 0; while (opts_len) { uint8_t t = opts[0]; @@ -814,41 +871,22 @@ struct l_icmp6_router *_icmp6_router_parse(const struct nd_router_advert *ra, break; case ND_OPT_PREFIX_INFORMATION: - { - struct route_info *i = &r->routes[n_routes]; - - if (!(opts[3] & ND_OPT_PI_FLAG_ONLINK)) - break; + if (opts[3] & ND_OPT_PI_FLAG_ONLINK) { + struct route_info *i = &r->routes[n_routes]; - i->prefix_len = opts[2]; - i->onlink = true; - i->valid_lifetime = l_get_be32(opts + 4); - i->preferred_lifetime = l_get_be32(opts + 8); - - /* - * Only the initial Prefix Length bits of the prefix - * are valid. The remaining bits "MUST" be ignored - * by the receiver. - */ - memcpy(i->address, net_prefix_from_ipv6(opts + 16, - i->prefix_len), 16); + if (icmp6_prefix_parse_rt_info(opts, i)) + n_routes++; + } - /* - * For SLAAC (RFC4862) we need to "silently ignore" - * routes with a preferred lifetime longer than valid - * lifetime, and those with the link-local prefix. - * Since it makes sense, do it regardless of SLAAC. - */ - if (i->preferred_lifetime > i->valid_lifetime) - break; + if (opts[3] & ND_OPT_PI_FLAG_AUTO) { + struct autoconf_prefix_info *i = + &r->ac_prefixes[n_ac_prefixes]; - if (i->prefix_len >= 10 && - IN6_IS_ADDR_LINKLOCAL(i->address)) - break; + if (icmp6_prefix_parse_ac_info(opts, i)) + n_ac_prefixes++; + } - n_routes += 1; break; - } case ND_OPT_RTR_ADV_INTERVAL: if (l < 8) break; diff --git a/ell/netconfig.c b/ell/netconfig.c index 29e95b77..bbe1dec3 100644 --- a/ell/netconfig.c +++ b/ell/netconfig.c @@ -799,7 +799,6 @@ static bool netconfig_check_route_need_update( static void netconfig_set_icmp6_route_data(struct l_netconfig *nc, struct netconfig_route_data *rd, const struct l_icmp6_router *ra, - uint32_t preferred_lifetime, uint32_t valid_lifetime, uint32_t mtu, bool updated) { @@ -916,10 +915,10 @@ static void netconfig_icmp6_event_handler(struct l_icmp6_client *client, * netconfig_set_icmp6_route_data. */ netconfig_set_icmp6_route_data(nc, default_rd, r, r->lifetime, - r->lifetime, r->mtu, false); + r->mtu, false); } else if (default_rd && r->lifetime) netconfig_set_icmp6_route_data(nc, default_rd, r, r->lifetime, - r->lifetime, r->mtu, true); + r->mtu, true); else if (default_rd && !r->lifetime) netconfig_remove_icmp6_route(nc, default_rd); @@ -941,12 +940,10 @@ static void netconfig_icmp6_event_handler(struct l_icmp6_client *client, continue; netconfig_set_icmp6_route_data(nc, rd, r, - info->preferred_lifetime, info->valid_lifetime, gateway ? r->mtu : 0, false); } else if (rd && info->valid_lifetime) netconfig_set_icmp6_route_data(nc, rd, r, - info->preferred_lifetime, info->valid_lifetime, gateway ? r->mtu : 0, true); else if (rd && !info->valid_lifetime) |