network/ndisc: remember the latest RA from the default router

The remembered RA will be used later. Preparation for later commits.
This commit is contained in:
Yu Watanabe
2024-04-05 05:55:06 +09:00
parent 36ca167220
commit b03d7291d5
2 changed files with 133 additions and 0 deletions
+1
View File
@@ -160,6 +160,7 @@ typedef struct Link {
sd_dhcp_server *dhcp_server;
sd_ndisc *ndisc;
sd_ndisc_router *ndisc_default_router;
sd_event_source *ndisc_expire;
Set *ndisc_rdnss;
Set *ndisc_dnssl;
+132
View File
@@ -505,6 +505,126 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
return 0;
}
static int update_default_router_address(Link *link, const struct in6_addr *original_address, const struct in6_addr *current_address) {
struct in6_addr a;
int r;
assert(link);
assert(original_address);
assert(current_address);
if (!link->ndisc_default_router)
return 0;
r = sd_ndisc_router_get_sender_address(link->ndisc_default_router, &a);
if (r < 0)
return r;
if (!in6_addr_equal(&a, original_address))
return 0;
return sd_ndisc_router_set_sender_address(link->ndisc_default_router, current_address);
}
static int drop_default_router(Link *link, const struct in6_addr *router, usec_t timestamp_usec) {
usec_t lifetime_usec;
int r;
assert(link);
if (!link->ndisc_default_router)
return 0;
if (router) {
struct in6_addr a;
r = sd_ndisc_router_get_sender_address(link->ndisc_default_router, &a);
if (r < 0)
return r;
if (!in6_addr_equal(&a, router))
return 0;
}
r = sd_ndisc_router_get_lifetime_timestamp(link->ndisc_default_router, CLOCK_BOOTTIME, &lifetime_usec);
if (r < 0)
return r;
if (lifetime_usec > timestamp_usec)
return 0;
link->ndisc_default_router = sd_ndisc_router_unref(link->ndisc_default_router);
return 0;
}
static int accept_default_router(sd_ndisc_router *new_router, sd_ndisc_router *existing_router) {
usec_t lifetime_usec;
struct in6_addr a, b;
uint8_t p, q;
int r;
assert(new_router);
r = sd_ndisc_router_get_lifetime(new_router, &lifetime_usec);
if (r < 0)
return r;
if (lifetime_usec == 0)
return false; /* Received a new RA about revoking the router, ignoring. */
if (!existing_router)
return true;
/* lifetime of the existing router is already checked in ndisc_drop_outdated(). */
r = sd_ndisc_router_get_sender_address(new_router, &a);
if (r < 0)
return r;
r = sd_ndisc_router_get_sender_address(existing_router, &b);
if (r < 0)
return r;
if (in6_addr_equal(&a, &b))
return true; /* Received a new RA from the remembered router. Replace the remembered RA. */
r = sd_ndisc_router_get_preference(new_router, &p);
if (r < 0)
return r;
r = sd_ndisc_router_get_preference(existing_router, &q);
if (r < 0)
return r;
if (p == q)
return true;
if (p == SD_NDISC_PREFERENCE_HIGH)
return true;
if (p == SD_NDISC_PREFERENCE_MEDIUM && q == SD_NDISC_PREFERENCE_LOW)
return true;
return false;
}
static int ndisc_remember_default_router(Link *link, sd_ndisc_router *rt) {
int r;
assert(link);
assert(rt);
r = accept_default_router(rt, link->ndisc_default_router);
if (r <= 0)
return r;
sd_ndisc_router_ref(rt);
sd_ndisc_router_unref(link->ndisc_default_router);
link->ndisc_default_router = rt;
return 1; /* The received router advertisement is from the default router. */
}
static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt) {
usec_t reachable_time, msec;
int r;
@@ -1410,6 +1530,10 @@ static int ndisc_drop_outdated(Link *link, const struct in6_addr *router, usec_t
* valid lifetimes to improve the reaction of SLAAC to renumbering events.
* See draft-ietf-6man-slaac-renum-02, section 4.2. */
r = drop_default_router(link, router, timestamp_usec);
if (r < 0)
RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to drop outdated default router, ignoring: %m"));
SET_FOREACH(route, link->manager->routes) {
if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
continue;
@@ -1657,6 +1781,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return r;
r = ndisc_remember_default_router(link, rt);
if (r < 0)
return r;
r = ndisc_start_dhcp6_client(link, rt);
if (r < 0)
return r;
@@ -1743,6 +1871,10 @@ static int ndisc_neighbor_handle_router_message(Link *link, sd_ndisc_neighbor *n
if (in6_addr_equal(&current_address, &original_address))
return 0; /* the router address is not changed */
r = update_default_router_address(link, &original_address, &current_address);
if (r < 0)
return r;
Route *route;
SET_FOREACH(route, link->manager->routes) {
if (route->source != NETWORK_CONFIG_SOURCE_NDISC)