From 0b3a7ca9d0797b2974bb421e0a5c2f08b90957aa Mon Sep 17 00:00:00 2001 From: Mary Strodl Date: Thu, 30 Jan 2025 16:00:20 -0500 Subject: [PATCH] ndisc: add support for PREF64 option --- src/core/ndisc/nm-lndp-ndisc.c | 30 ++++++++++++++++++++++++++++++ src/core/ndisc/nm-ndisc-private.h | 1 + src/core/ndisc/nm-ndisc.c | 18 ++++++++++++++++++ src/core/ndisc/nm-ndisc.h | 10 ++++++++++ 4 files changed, 59 insertions(+) diff --git a/src/core/ndisc/nm-lndp-ndisc.c b/src/core/ndisc/nm-lndp-ndisc.c index c19dcc910b..980bc597bb 100644 --- a/src/core/ndisc/nm-lndp-ndisc.c +++ b/src/core/ndisc/nm-lndp-ndisc.c @@ -162,6 +162,7 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) int offset; int hop_limit; guint32 val; + gboolean pref64_found = FALSE; /* Router discovery is subject to the following RFC documents: * @@ -401,6 +402,35 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) } } + /* PREF64 */ + ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_PREF64) { + struct in6_addr pref64_prefix = *ndp_msg_opt_pref64_prefix(msg, offset); + guint8 pref64_length = ndp_msg_opt_pref64_prefix_length(msg, offset); + gint64 expiry_msec = + _nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_pref64_lifetime(msg, offset)); + + /* Currently, only /96 is supported */ + if (pref64_length != 96) { + _LOGW("Ignored PREF64 for unsupported prefix length: %d (only /96 is supported)", + pref64_length); + continue; + } + + /* Newer RA has more up to date information, prefer it: */ + if (!pref64_found) { + pref64_found = TRUE; + rdata->public.pref64.expiry_msec = 0; + } + + if (expiry_msec >= rdata->public.pref64.expiry_msec) { + rdata->public.pref64.network = pref64_prefix; + rdata->public.pref64.expiry_msec = expiry_msec; + rdata->public.pref64.plen = pref64_length; + rdata->public.pref64.valid = TRUE; + changed |= NM_NDISC_CONFIG_PREF64; + } + } + nm_ndisc_ra_received(ndisc, now_msec, changed); return 0; } diff --git a/src/core/ndisc/nm-ndisc-private.h b/src/core/ndisc/nm-ndisc-private.h index 1479e5666e..697700eb26 100644 --- a/src/core/ndisc/nm-ndisc-private.h +++ b/src/core/ndisc/nm-ndisc-private.h @@ -14,6 +14,7 @@ struct _NMNDiscDataInternal { NMNDiscData public; GArray *gateways; GArray *addresses; + GArray *clat_addresses; GArray *routes; GArray *dns_servers; GArray *dns_domains; diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index 758ce0a05c..dfe190e572 100644 --- a/src/core/ndisc/nm-ndisc.c +++ b/src/core/ndisc/nm-ndisc.c @@ -212,6 +212,12 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, for (i = 0; i < rdata->dns_domains_n; i++) nm_l3_config_data_add_search(l3cd, AF_INET6, rdata->dns_domains[i].domain); + if (rdata->pref64.valid) { + nm_l3_config_data_set_pref64(l3cd, rdata->pref64.network, rdata->pref64.plen); + } else { + nm_l3_config_data_set_pref64_valid(l3cd, FALSE); + } + nm_l3_config_data_set_ndisc_hop_limit(l3cd, rdata->hop_limit); nm_l3_config_data_set_ndisc_reachable_time_msec(l3cd, rdata->reachable_time_ms); nm_l3_config_data_set_ndisc_retrans_timer_msec(l3cd, rdata->retrans_timer_ms); @@ -1528,6 +1534,17 @@ clean_routes(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *changed |= NM_NDISC_CONFIG_ROUTES; } +static void +clean_pref64(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) +{ + NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; + + if (!rdata->public.pref64.valid) + return; + if (!expiry_next(now_msec, rdata->public.pref64.expiry_msec, next_msec)) + *changed |= NM_NDISC_CONFIG_PREF64; +} + static void clean_dns_servers(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) { @@ -1604,6 +1621,7 @@ check_timestamps(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap changed) clean_gateways(ndisc, now_msec, &changed, &next_msec); clean_addresses(ndisc, now_msec, &changed, &next_msec); clean_routes(ndisc, now_msec, &changed, &next_msec); + clean_pref64(ndisc, now_msec, &changed, &next_msec); clean_dns_servers(ndisc, now_msec, &changed, &next_msec); clean_dns_domains(ndisc, now_msec, &changed, &next_msec); diff --git a/src/core/ndisc/nm-ndisc.h b/src/core/ndisc/nm-ndisc.h index eda1e696d9..416c319117 100644 --- a/src/core/ndisc/nm-ndisc.h +++ b/src/core/ndisc/nm-ndisc.h @@ -119,6 +119,13 @@ typedef struct _NMNDiscRoute { bool duplicate : 1; } NMNDiscRoute; +typedef struct _NMNDiscPref64 { + struct in6_addr network; + gint64 expiry_msec; + guint8 plen; + bool valid : 1; +} NMNDiscPref64; + typedef struct { struct in6_addr address; gint64 expiry_msec; @@ -141,6 +148,7 @@ typedef enum { NM_NDISC_CONFIG_MTU = 1 << 7, NM_NDISC_CONFIG_REACHABLE_TIME = 1 << 8, NM_NDISC_CONFIG_RETRANS_TIMER = 1 << 9, + NM_NDISC_CONFIG_PREF64 = 1 << 10, } NMNDiscConfigMap; typedef enum { @@ -196,6 +204,8 @@ typedef struct { const NMNDiscRoute *routes; const NMNDiscDNSServer *dns_servers; const NMNDiscDNSDomain *dns_domains; + + NMNDiscPref64 pref64; } NMNDiscData; /**