return 0;
}
+static int ndisc_remove_route(Route *route, Link *link) {
+ int r;
+
+ assert(route);
+ assert(link);
+ assert(link->manager);
+
+ ndisc_set_route_priority(link, route);
+
+ if (!route->table_set)
+ route->table = link_get_ipv6_accept_ra_route_table(link);
+
+ r = route_adjust_nexthops(route, link);
+ if (r < 0)
+ return r;
+
+ if (route->pref_set) {
+ ndisc_set_route_priority(link, route);
+ return route_remove_and_cancel(route, link->manager);
+ }
+
+ uint8_t pref;
+ FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
+ route->pref = pref;
+ ndisc_set_route_priority(link, route);
+ r = route_remove_and_cancel(route, link->manager);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
int r;
return 0;
}
+static int ndisc_router_drop_default(Link *link, sd_ndisc_router *rt) {
+ _cleanup_(route_unrefp) Route *route = NULL;
+ struct in6_addr gateway;
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(rt);
+
+ r = sd_ndisc_router_get_address(rt, &gateway);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
+
+ r = route_new(&route);
+ if (r < 0)
+ return log_oom();
+
+ route->family = AF_INET6;
+ route->nexthop.family = AF_INET6;
+ route->nexthop.gw.in6 = gateway;
+
+ r = ndisc_remove_route(route, link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to remove the default gateway configured by RA: %m");
+
+ Route *route_gw;
+ HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
+ _cleanup_(route_unrefp) Route *tmp = NULL;
+
+ if (!route_gw->gateway_from_dhcp_or_ra)
+ continue;
+
+ if (route_gw->nexthop.family != AF_INET6)
+ continue;
+
+ r = route_dup(route_gw, NULL, &tmp);
+ if (r < 0)
+ return r;
+
+ tmp->nexthop.gw.in6 = gateway;
+
+ r = ndisc_remove_route(tmp, link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not remove semi-static gateway: %m");
+ }
+
+ return 0;
+}
+
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
usec_t lifetime_usec;
struct in6_addr gateway;
assert(link->network);
assert(rt);
+ /* If the router lifetime is zero, the router should not be used as the default gateway. */
+ r = sd_ndisc_router_get_lifetime(rt, NULL);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return ndisc_router_drop_default(link, rt);
+
if (!link->network->ipv6_accept_ra_use_gateway &&
hashmap_isempty(link->network->routes_by_section))
return 0;
address->lifetime_valid_usec = lifetime_valid_usec;
address->lifetime_preferred_usec = lifetime_preferred_usec;
- r = ndisc_request_address(address, link, rt);
- if (r < 0)
- return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
+ /* draft-ietf-6man-slaac-renum-07 section 4.2
+ * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2
+ *
+ * If the advertised prefix is equal to the prefix of an address configured by stateless
+ * autoconfiguration in the list, the valid lifetime and the preferred lifetime of the
+ * address should be updated by processing the Valid Lifetime and the Preferred Lifetime
+ * (respectively) in the received advertisement. */
+ if (lifetime_valid_usec == 0) {
+ r = address_remove_and_cancel(address, link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not remove SLAAC address: %m");
+ } else {
+ r = ndisc_request_address(address, link, rt);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
+ }
}
return 0;
static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_unrefp) Route *route = NULL;
- unsigned prefixlen, preference;
+ unsigned prefixlen;
struct in6_addr prefix;
usec_t lifetime_usec;
int r;
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
- /* Prefix Information option does not have preference, hence we use the 'main' preference here */
- r = sd_ndisc_router_get_preference(rt, &preference);
- if (r < 0)
- return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
-
r = route_new(&route);
if (r < 0)
return log_oom();
route->family = AF_INET6;
route->dst.in6 = prefix;
route->dst_prefixlen = prefixlen;
- route->table = link_get_ipv6_accept_ra_route_table(link);
- route->pref = preference;
- ndisc_set_route_priority(link, route);
- route->protocol = RTPROT_RA;
-
- r = route_adjust_nexthops(route, link);
- if (r < 0)
- return r;
- r = route_remove_and_cancel(route, link->manager);
+ r = ndisc_remove_route(route, link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not remove prefix route: %m");
* A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
* a prefix option. */
if (in6_addr_is_link_local(&a)) {
- log_link_debug(link, "Received link-local prefix, ignoring autonomous prefix.");
+ log_link_debug(link, "Received link-local prefix, ignoring prefix.");
return 0;
}