ndisc: add support for PREF64 option

This commit is contained in:
Mary Strodl 2025-01-30 16:00:20 -05:00 committed by Beniamino Galvani
parent b31d3e1eae
commit 0b3a7ca9d0
4 changed files with 59 additions and 0 deletions

View file

@ -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;
}

View file

@ -14,6 +14,7 @@ struct _NMNDiscDataInternal {
NMNDiscData public;
GArray *gateways;
GArray *addresses;
GArray *clat_addresses;
GArray *routes;
GArray *dns_servers;
GArray *dns_domains;

View file

@ -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);

View file

@ -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;
/**