diff options
Diffstat (limited to 'src/core/ndisc/nm-ndisc.c')
| -rw-r--r-- | src/core/ndisc/nm-ndisc.c | 587 |
1 files changed, 280 insertions, 307 deletions
diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index d7b1a2e1..969eacfa 100644 --- a/src/core/ndisc/nm-ndisc.c +++ b/src/core/ndisc/nm-ndisc.c @@ -7,16 +7,17 @@ #include "nm-ndisc.h" -#include <stdlib.h> #include <arpa/inet.h> +#include <stdlib.h> -#include "nm-setting-ip6-config.h" - -#include "nm-ndisc-private.h" -#include "nm-utils.h" +#include "libnm-platform/nm-platform-utils.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-netns.h" #include "nm-l3-config-data.h" +#include "nm-l3cfg.h" +#include "nm-ndisc-private.h" +#include "nm-setting-ip6-config.h" +#include "nm-utils.h" #define _NMLOG_PREFIX_NAME "ndisc" @@ -38,6 +39,8 @@ struct _NMNDiscPrivate { /* this *must* be the first field. */ NMNDiscDataInternal rdata; + const NML3ConfigData *l3cd; + char *last_error; GSource *ra_timeout_source; @@ -54,38 +57,27 @@ struct _NMNDiscPrivate { GSource *timeout_expire_source; NMUtilsIPv6IfaceId iid; + gboolean iid_is_token; - /* immutable values: */ - int ifindex; - char * ifname; - char * network_id; - guint max_addresses; - NMSettingIP6ConfigAddrGenMode addr_gen_mode; - NMUtilsStableType stable_type; - guint32 ra_timeout; - gint32 router_solicitations; - gint32 router_solicitation_interval; - NMNDiscNodeType node_type; - - NMPlatform *platform; - NMPNetns * netns; + /* immutable values from here on: */ + + union { + const NMNDiscConfig config; + NMNDiscConfig config_; + }; + + NMPNetns *netns; }; typedef struct _NMNDiscPrivate NMNDiscPrivate; -NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PLATFORM, - PROP_IFINDEX, - PROP_IFNAME, - PROP_STABLE_TYPE, - PROP_NETWORK_ID, - PROP_ADDR_GEN_MODE, - PROP_MAX_ADDRESSES, - PROP_RA_TIMEOUT, - PROP_ROUTER_SOLICITATIONS, - PROP_ROUTER_SOLICITATION_INTERVAL, - PROP_NODE_TYPE, ); +NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_CONFIG, ); -enum { CONFIG_RECEIVED, RA_TIMEOUT_SIGNAL, LAST_SIGNAL }; +enum { + CONFIG_RECEIVED, + RA_TIMEOUT_SIGNAL, + LAST_SIGNAL, +}; static guint signals[LAST_SIGNAL] = {0}; @@ -111,18 +103,14 @@ NM_UTILS_LOOKUP_STR_DEFINE(nm_ndisc_dhcp_level_to_string, /*****************************************************************************/ NML3ConfigData * -nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, +nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx, int ifindex, - const NMNDiscData * rdata, + const NMNDiscData *rdata, NMSettingIP6ConfigPrivacy ip6_privacy, - guint32 route_table, - guint32 route_metric, - gboolean kernel_support_rta_pref, - gboolean kernel_support_extended_ifa_flags) + NMUtilsIPv6IfaceId *token) { nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; guint32 ifa_flags; - guint8 plen; guint i; const gint32 now_sec = nm_utils_get_monotonic_timestamp_sec(); @@ -130,20 +118,11 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, nm_l3_config_data_set_ip6_privacy(l3cd, ip6_privacy); - /* Check, whether kernel is recent enough to help user space handling RA. - * If it's not supported, we have no ipv6-privacy and must add autoconf - * addresses as /128. The reason for the /128 is to prevent the kernel - * from adding a prefix route for this address. */ - ifa_flags = 0; - if (kernel_support_extended_ifa_flags) { - ifa_flags |= IFA_F_NOPREFIXROUTE; - if (NM_IN_SET(ip6_privacy, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)) - ifa_flags |= IFA_F_MANAGETEMPADDR; - plen = 64; - } else - plen = 128; + ifa_flags = IFA_F_NOPREFIXROUTE; + if (NM_IN_SET(ip6_privacy, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)) + ifa_flags |= IFA_F_MANAGETEMPADDR; for (i = 0; i < rdata->addresses_n; i++) { const NMNDiscAddress *ndisc_addr = &rdata->addresses[i]; @@ -152,7 +131,7 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, a = (NMPlatformIP6Address){ .ifindex = ifindex, .address = ndisc_addr->address, - .plen = plen, + .plen = 64, .timestamp = now_sec, .lifetime = _nm_ndisc_lifetime_from_expiry(((gint64) now_sec) * 1000, ndisc_addr->expiry_msec, @@ -178,8 +157,10 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, .plen = ndisc_route->plen, .gateway = ndisc_route->gateway, .rt_source = NM_IP_CONFIG_SOURCE_NDISC, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, .rt_pref = ndisc_route->preference, }; nm_assert((NMIcmpv6RouterPref) r.rt_pref == ndisc_route->preference); @@ -188,12 +169,13 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, } if (rdata->gateways_n > 0) { - const NMIcmpv6RouterPref first_pref = rdata->gateways[0].preference; - NMPlatformIP6Route r = { + NMPlatformIP6Route r = { .rt_source = NM_IP_CONFIG_SOURCE_NDISC, .ifindex = ifindex, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; for (i = 0; i < rdata->gateways_n; i++) { @@ -201,13 +183,6 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, r.rt_pref = rdata->gateways[i].preference; nm_assert((NMIcmpv6RouterPref) r.rt_pref == rdata->gateways[i].preference); nm_l3_config_data_add_route_6(l3cd, &r); - - if (first_pref != rdata->gateways[i].preference && !kernel_support_rta_pref) { - /* We are unable to configure a router preference. Hence, we skip all gateways - * with a different preference from the first gateway. Note, that the gateways - * are sorted in order of highest to lowest preference. */ - break; - } } } @@ -222,6 +197,8 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, nm_l3_config_data_set_ndisc_retrans_timer_msec(l3cd, rdata->retrans_timer_ms); nm_l3_config_data_set_ip6_mtu(l3cd, rdata->mtu); + if (token) + nm_l3_config_data_set_ip6_token(l3cd, *token); return g_steal_pointer(&l3cd); } @@ -315,7 +292,7 @@ nm_ndisc_get_ifindex(NMNDisc *self) { g_return_val_if_fail(NM_IS_NDISC(self), 0); - return NM_NDISC_GET_PRIVATE(self)->ifindex; + return nm_l3cfg_get_ifindex(NM_NDISC_GET_PRIVATE(self)->config.l3cfg); } const char * @@ -323,7 +300,7 @@ nm_ndisc_get_ifname(NMNDisc *self) { g_return_val_if_fail(NM_IS_NDISC(self), NULL); - return NM_NDISC_GET_PRIVATE(self)->ifname; + return NM_NDISC_GET_PRIVATE(self)->config.ifname; } NMNDiscNodeType @@ -331,7 +308,7 @@ nm_ndisc_get_node_type(NMNDisc *self) { g_return_val_if_fail(NM_IS_NDISC(self), NM_NDISC_NODE_TYPE_INVALID); - return NM_NDISC_GET_PRIVATE(self)->node_type; + return NM_NDISC_GET_PRIVATE(self)->config.node_type; } /*****************************************************************************/ @@ -391,15 +368,28 @@ _data_complete(NMNDiscDataInternal *data) return &data->public; } -void +static void nm_ndisc_emit_config_change(NMNDisc *self, NMNDiscConfigMap changed) { + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(self); + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMNDiscData *rdata; + _config_changed_log(self, changed); - g_signal_emit(self, - signals[CONFIG_RECEIVED], - 0, - _data_complete(&NM_NDISC_GET_PRIVATE(self)->rdata), - (guint) changed); + + rdata = _data_complete(&NM_NDISC_GET_PRIVATE(self)->rdata), + + l3cd = nm_ndisc_data_to_l3cd(nm_l3cfg_get_multi_idx(priv->config.l3cfg), + nm_l3cfg_get_ifindex(priv->config.l3cfg), + rdata, + priv->config.ip6_privacy, + priv->iid_is_token ? &priv->iid : NULL); + l3cd = nm_l3_config_data_seal(l3cd); + + if (!nm_l3_config_data_equal(priv->l3cd, l3cd)) + NM_SWAP(&priv->l3cd, &l3cd); + + g_signal_emit(self, signals[CONFIG_RECEIVED], 0, rdata, (guint) changed, priv->l3cd); } /*****************************************************************************/ @@ -474,16 +464,16 @@ static gboolean complete_address(NMNDisc *ndisc, NMNDiscAddress *addr) { NMNDiscPrivate *priv; - GError * error = NULL; + GError *error = NULL; g_return_val_if_fail(NM_IS_NDISC(ndisc), FALSE); priv = NM_NDISC_GET_PRIVATE(ndisc); - if (priv->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { - if (!nm_utils_ipv6_addr_set_stable_privacy_may_fail(priv->stable_type, + if (priv->config.addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { + if (!nm_utils_ipv6_addr_set_stable_privacy_may_fail(priv->config.stable_type, &addr->address, - priv->ifname, - priv->network_id, + priv->config.ifname, + priv->config.network_id, addr->dad_counter++, &error)) { _LOGW("complete-address: failed to generate an stable-privacy address: %s", @@ -511,15 +501,15 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr) } static gboolean -nm_ndisc_add_address(NMNDisc * ndisc, +nm_ndisc_add_address(NMNDisc *ndisc, const NMNDiscAddress *new_item, gint64 now_msec, gboolean from_ra) { - NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc); NMNDiscDataInternal *rdata = &priv->rdata; - NMNDiscAddress * new2; - NMNDiscAddress * existing = NULL; + NMNDiscAddress *new2; + NMNDiscAddress *existing = NULL; guint i; nm_assert(new_item); @@ -608,7 +598,7 @@ nm_ndisc_add_address(NMNDisc * ndisc, * what the kernel does, because it considers *all* addresses (including * static and other temporary addresses). **/ - if (rdata->addresses->len >= priv->max_addresses) + if (rdata->addresses->len >= priv->config.max_addresses) return FALSE; if (new_item->expiry_msec <= now_msec) @@ -640,7 +630,7 @@ nm_ndisc_complete_and_add_address(NMNDisc *ndisc, const NMNDiscAddress *new_item gboolean nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec) { - NMNDiscPrivate * priv; + NMNDiscPrivate *priv; NMNDiscDataInternal *rdata; guint i; guint insert_idx = G_MAXUINT; @@ -709,7 +699,7 @@ nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec gboolean nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new_item, gint64 now_msec) { - NMNDiscPrivate * priv; + NMNDiscPrivate *priv; NMNDiscDataInternal *rdata; guint i; @@ -747,9 +737,9 @@ nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new_item, gint64 gboolean nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new_item, gint64 now_msec) { - NMNDiscPrivate * priv; + NMNDiscPrivate *priv; NMNDiscDataInternal *rdata; - NMNDiscDNSDomain * item; + NMNDiscDNSDomain *item; guint i; priv = NM_NDISC_GET_PRIVATE(ndisc); @@ -824,13 +814,13 @@ solicit_retransmit_time_jitter(gint32 solicit_retransmit_time_msec) static gboolean solicit_timer_cb(gpointer user_data) { - const gint32 TIMEOUT_APPROX_THRESHOLD_SEC = 10000; - nm_auto_pop_netns NMPNetns *netns = NULL; - NMNDisc * ndisc = user_data; - NMNDiscClass * klass = NM_NDISC_GET_CLASS(ndisc); - NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc); - gs_free_error GError *error = NULL; - gint32 timeout_msec; + const gint32 TIMEOUT_APPROX_THRESHOLD_SEC = 10000; + nm_auto_pop_netns NMPNetns *netns = NULL; + NMNDisc *ndisc = user_data; + NMNDiscClass *klass = NM_NDISC_GET_CLASS(ndisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc); + gs_free_error GError *error = NULL; + gint32 timeout_msec; if (!nm_ndisc_netns_push(ndisc, &netns)) { nm_utils_error_set(&error, @@ -899,7 +889,7 @@ solicit_timer_start(NMNDisc *ndisc) g_random_int() % ((guint32) (NM_NDISC_RFC4861_MAX_RTR_SOLICITATION_DELAY * 1000 / 4)); _LOGD("solicit: schedule sending first solicitation (of %d) in %.3f seconds", - priv->router_solicitations, + priv->config.router_solicitations, ((double) delay_msec) / 1000); priv->solicit_retransmit_time_msec = 0; @@ -913,9 +903,9 @@ static gboolean announce_router(NMNDisc *ndisc) { nm_auto_pop_netns NMPNetns *netns = NULL; - NMNDiscClass * klass = NM_NDISC_GET_CLASS(ndisc); - NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc); - GError * error = NULL; + NMNDiscClass *klass = NM_NDISC_GET_CLASS(ndisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc); + GError *error = NULL; if (!nm_ndisc_netns_push(ndisc, &netns)) return G_SOURCE_REMOVE; @@ -997,30 +987,82 @@ announce_router_solicited(NMNDisc *ndisc) /*****************************************************************************/ void -nm_ndisc_set_config(NMNDisc * ndisc, - const GArray *addresses, - const GArray *dns_servers, - const GArray *dns_domains) +nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd) { - gboolean changed = FALSE; - guint i; + gboolean changed = FALSE; + const struct in6_addr *in6arr; + const char *const *strvarr; + NMDedupMultiIter iter; + const NMPObject *obj; + guint len; + guint i; + + nm_assert(NM_IS_NDISC(ndisc)); + nm_assert(nm_ndisc_get_node_type(ndisc) == NM_NDISC_NODE_TYPE_ROUTER); + + nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) { + const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); + guint32 preferred; + guint32 lifetime; + NMNDiscAddress a; + + if (IN6_IS_ADDR_UNSPECIFIED(&addr->address) || IN6_IS_ADDR_LINKLOCAL(&addr->address)) + continue; + + if (addr->n_ifa_flags & IFA_F_TENTATIVE || addr->n_ifa_flags & IFA_F_DADFAILED) + continue; + + if (addr->plen != 64) + continue; - for (i = 0; i < addresses->len; i++) { - if (nm_ndisc_add_address(ndisc, &g_array_index(addresses, NMNDiscAddress, i), 0, FALSE)) + lifetime = nmp_utils_lifetime_get(addr->timestamp, + addr->lifetime, + addr->preferred, + NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000, + &preferred); + if (!lifetime) + continue; + + a = (NMNDiscAddress){ + .address = addr->address, + .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, lifetime), + .expiry_preferred_msec = + _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, preferred), + }; + + if (nm_ndisc_add_address(ndisc, &a, 0, FALSE)) changed = TRUE; } - for (i = 0; i < dns_servers->len; i++) { - if (nm_ndisc_add_dns_server(ndisc, - &g_array_index(dns_servers, NMNDiscDNSServer, i), - G_MININT64)) + in6arr = NULL; + len = 0; + if (l3cd) + in6arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET6, &len); + for (i = 0; i < len; i++) { + NMNDiscDNSServer n; + + n = (NMNDiscDNSServer){ + .address = in6arr[i], + .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, + NM_NDISC_ROUTER_LIFETIME), + }; + if (nm_ndisc_add_dns_server(ndisc, &n, G_MININT64)) changed = TRUE; } - for (i = 0; i < dns_domains->len; i++) { - if (nm_ndisc_add_dns_domain(ndisc, - &g_array_index(dns_domains, NMNDiscDNSDomain, i), - G_MININT64)) + strvarr = NULL; + len = 0; + if (l3cd) + strvarr = nm_l3_config_data_get_searches(l3cd, AF_INET6, &len); + for (i = 0; i < len; i++) { + NMNDiscDNSDomain n; + + n = (NMNDiscDNSDomain){ + .domain = (char *) strvarr[i], + .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, + NM_NDISC_ROUTER_LIFETIME), + }; + if (nm_ndisc_add_dns_domain(ndisc, &n, G_MININT64)) changed = TRUE; } @@ -1048,20 +1090,21 @@ nm_ndisc_set_config(NMNDisc * ndisc, * Returns: %TRUE if addresses need to be regenerated, %FALSE otherwise. **/ gboolean -nm_ndisc_set_iid(NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid) +nm_ndisc_set_iid(NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid, gboolean is_token) { - NMNDiscPrivate * priv; + NMNDiscPrivate *priv; NMNDiscDataInternal *rdata; g_return_val_if_fail(NM_IS_NDISC(ndisc), FALSE); - priv = NM_NDISC_GET_PRIVATE(ndisc); - rdata = &priv->rdata; + priv = NM_NDISC_GET_PRIVATE(ndisc); + priv->iid_is_token = is_token; + rdata = &priv->rdata; if (priv->iid.id != iid.id) { priv->iid = iid; - if (priv->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) + if (priv->config.addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) return FALSE; if (rdata->addresses->len) { @@ -1090,7 +1133,7 @@ void nm_ndisc_start(NMNDisc *ndisc) { nm_auto_pop_netns NMPNetns *netns = NULL; - NMNDiscPrivate * priv; + NMNDiscPrivate *priv; g_return_if_fail(NM_IS_NDISC(ndisc)); @@ -1100,26 +1143,26 @@ nm_ndisc_start(NMNDisc *ndisc) nm_assert(!priv->ra_timeout_source); _LOGD("starting neighbor discovery for ifindex %d%s", - priv->ifindex, - priv->node_type == NM_NDISC_NODE_TYPE_HOST ? " (solicit)" : " (announce)"); + nm_l3cfg_get_ifindex(priv->config.l3cfg), + priv->config.node_type == NM_NDISC_NODE_TYPE_HOST ? " (solicit)" : " (announce)"); if (!nm_ndisc_netns_push(ndisc, &netns)) return; NM_NDISC_GET_CLASS(ndisc)->start(ndisc); - if (priv->node_type == NM_NDISC_NODE_TYPE_HOST) { + if (priv->config.node_type == NM_NDISC_NODE_TYPE_HOST) { G_STATIC_ASSERT_EXPR(NM_RA_TIMEOUT_DEFAULT == 0); G_STATIC_ASSERT_EXPR(NM_RA_TIMEOUT_INFINITY == G_MAXINT32); - nm_assert(priv->ra_timeout > 0u); - nm_assert(priv->ra_timeout <= NM_RA_TIMEOUT_INFINITY); + nm_assert(priv->config.ra_timeout > 0u); + nm_assert(priv->config.ra_timeout <= NM_RA_TIMEOUT_INFINITY); - if (priv->ra_timeout < NM_RA_TIMEOUT_INFINITY) { + if (priv->config.ra_timeout < NM_RA_TIMEOUT_INFINITY) { guint timeout_msec; - _LOGD("scheduling RA timeout in %u seconds", priv->ra_timeout); - if (priv->ra_timeout < G_MAXUINT / 1000u) - timeout_msec = priv->ra_timeout * 1000u; + _LOGD("scheduling RA timeout in %u seconds", priv->config.ra_timeout); + if (priv->config.ra_timeout < G_MAXUINT / 1000u) + timeout_msec = priv->config.ra_timeout * 1000u; else timeout_msec = G_MAXUINT; priv->ra_timeout_source = nm_g_timeout_add_source(timeout_msec, ra_timeout_cb, ndisc); @@ -1129,8 +1172,8 @@ nm_ndisc_start(NMNDisc *ndisc) return; } - nm_assert(priv->ra_timeout == 0u); - nm_assert(priv->node_type == NM_NDISC_NODE_TYPE_ROUTER); + nm_assert(priv->config.ra_timeout == 0u); + nm_assert(priv->config.node_type == NM_NDISC_NODE_TYPE_ROUTER); announce_router_initial(ndisc); } @@ -1138,8 +1181,8 @@ void nm_ndisc_stop(NMNDisc *ndisc) { nm_auto_pop_netns NMPNetns *netns = NULL; - NMNDiscDataInternal * rdata; - NMNDiscPrivate * priv; + NMNDiscDataInternal *rdata; + NMNDiscPrivate *priv; g_return_if_fail(NM_IS_NDISC(ndisc)); @@ -1147,7 +1190,7 @@ nm_ndisc_stop(NMNDisc *ndisc) nm_assert(NM_NDISC_GET_CLASS(ndisc)->stop); - _LOGD("stopping neighbor discovery for ifindex %d", priv->ifindex); + _LOGD("stopping neighbor discovery for ifindex %d", nm_l3cfg_get_ifindex(priv->config.l3cfg)); if (!nm_ndisc_netns_push(ndisc, &netns)) return; @@ -1230,7 +1273,7 @@ config_map_to_string(NMNDiscConfigMap map, char *p) static void _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed) { - NMNDiscPrivate * priv; + NMNDiscPrivate *priv; NMNDiscDataInternal *rdata; guint i; char changedstr[CONFIG_MAP_MAX_STR]; @@ -1319,7 +1362,7 @@ static void clean_gateways(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) { NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; - NMNDiscGateway * arr; + NMNDiscGateway *arr; guint i; guint j; @@ -1350,9 +1393,9 @@ clean_gateways(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint6 static void clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) { - NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc); NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; - NMNDiscAddress * arr; + NMNDiscAddress *arr; guint i; guint j; @@ -1374,7 +1417,7 @@ clean_addresses(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint g_array_set_size(rdata->addresses, j); } - if (_array_set_size_max(rdata->gateways, priv->max_addresses)) + if (_array_set_size_max(rdata->gateways, priv->config.max_addresses)) *changed |= NM_NDISC_CONFIG_ADDRESSES; } @@ -1382,7 +1425,7 @@ static void clean_routes(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) { NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; - NMNDiscRoute * arr; + NMNDiscRoute *arr; guint i; guint j; @@ -1412,7 +1455,7 @@ static void clean_dns_servers(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) { NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; - NMNDiscDNSServer * arr; + NMNDiscDNSServer *arr; guint i; guint j; @@ -1442,7 +1485,7 @@ static void clean_dns_domains(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec) { NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata; - NMNDiscDNSDomain * arr; + NMNDiscDNSDomain *arr; guint i; guint j; @@ -1549,7 +1592,7 @@ _calc_pre_expiry_rs_msec_worker(gint64 *earliest_expiry_msec, static gint64 calc_pre_expiry_rs_msec(NMNDisc *ndisc) { - NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc); NMNDiscDataInternal *rdata = &priv->rdata; gint64 expiry_msec = NM_NDISC_EXPIRY_INFINITY; guint i; @@ -1657,10 +1700,10 @@ ipv6_sysctl_get(NMPlatform *platform, void nm_ndisc_get_sysctl(NMPlatform *platform, const char *ifname, - int * out_max_addresses, - int * out_router_solicitations, - int * out_router_solicitation_interval, - guint32 * out_default_ra_timeout) + int *out_max_addresses, + int *out_router_solicitations, + int *out_router_solicitation_interval, + guint32 *out_default_ra_timeout) { int router_solicitation_interval = 0; int router_solicitations = 0; @@ -1700,85 +1743,87 @@ nm_ndisc_get_sysctl(NMPlatform *platform, /*****************************************************************************/ static void +_config_clear(NMNDiscConfig *config) +{ + g_clear_object(&config->l3cfg); + nm_clear_g_free((gpointer *) &config->ifname); + nm_clear_g_free((gpointer *) &config->network_id); +} + +static void +_config_init(NMNDiscConfig *config, const NMNDiscConfig *src) +{ + nm_assert(config); + g_return_if_fail(src); + + /* we only allow to set @config if it was cleared (or is not yet initialized). */ + nm_assert(!config->l3cfg); + nm_assert(!config->ifname); + nm_assert(!config->network_id); + + g_return_if_fail(NM_IS_L3CFG(src->l3cfg)); + + *config = *src; + + g_object_ref(config->l3cfg); + config->ifname = g_strdup(config->ifname); + config->network_id = g_strdup(config->network_id); + + if (config->max_addresses <= 0) + config->max_addresses = _SIZE_MAX_ADDRESSES; + else if (config->max_addresses > 3u * _SIZE_MAX_ADDRESSES) + config->max_addresses = 3u * _SIZE_MAX_ADDRESSES; + + /* This setter is only used in specific circumstances, and in this case, + * we expect that @src only contains valid settings. We thus assert that to + * be the case.*/ + g_return_if_fail(config->ifname && config->ifname[0]); + g_return_if_fail(config->network_id); + g_return_if_fail(config->stable_type >= NM_UTILS_STABLE_TYPE_UUID + && config->stable_type <= NM_UTILS_STABLE_TYPE_RANDOM); + g_return_if_fail(config->addr_gen_mode >= NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 + && config->addr_gen_mode + <= NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY); + nm_assert(config->max_addresses >= 0 && config->max_addresses <= G_MAXINT32); + G_STATIC_ASSERT_EXPR(G_MAXINT32 == NM_RA_TIMEOUT_INFINITY); + g_return_if_fail(config->ra_timeout <= NM_RA_TIMEOUT_INFINITY); + g_return_if_fail(config->router_solicitations > 0 + && config->router_solicitations <= G_MAXINT32); + g_return_if_fail(config->router_solicitation_interval > 0 + && config->router_solicitation_interval <= G_MAXINT32); + g_return_if_fail( + NM_IN_SET(config->node_type, NM_NDISC_NODE_TYPE_HOST, NM_NDISC_NODE_TYPE_ROUTER)); + g_return_if_fail(NM_IN_SET(config->ip6_privacy, + NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR)); +} + +/*****************************************************************************/ + +static void dns_domain_free(gpointer data) { g_free(((NMNDiscDNSDomain *) (data))->domain); } +/*****************************************************************************/ + static void set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMNDisc * self = NM_NDISC(object); + NMNDisc *self = NM_NDISC(object); NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(self); - int i; switch (prop_id) { - case PROP_PLATFORM: + case PROP_CONFIG: /* construct-only */ - priv->platform = g_value_get_object(value) ?: NM_PLATFORM_GET; - if (!priv->platform) - g_return_if_reached(); - - g_object_ref(priv->platform); - - priv->netns = nm_platform_netns_get(priv->platform); - if (priv->netns) - g_object_ref(priv->netns); + _config_init(&priv->config_, g_value_get_pointer(value)); + priv->netns = + nm_g_object_ref(nm_platform_netns_get(nm_l3cfg_get_platform(priv->config.l3cfg))); g_return_if_fail(!priv->netns || priv->netns == nmp_netns_get_current()); break; - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_int(value); - g_return_if_fail(priv->ifindex > 0); - break; - case PROP_IFNAME: - /* construct-only */ - priv->ifname = g_value_dup_string(value); - g_return_if_fail(priv->ifname && priv->ifname[0]); - break; - case PROP_STABLE_TYPE: - /* construct-only */ - priv->stable_type = g_value_get_int(value); - break; - case PROP_NETWORK_ID: - /* construct-only */ - priv->network_id = g_value_dup_string(value); - g_return_if_fail(priv->network_id); - break; - case PROP_ADDR_GEN_MODE: - /* construct-only */ - priv->addr_gen_mode = g_value_get_int(value); - break; - case PROP_MAX_ADDRESSES: - /* construct-only */ - i = g_value_get_int(value); - nm_assert(i >= 0); - priv->max_addresses = i; - - if (priv->max_addresses <= 0) - priv->max_addresses = _SIZE_MAX_ADDRESSES; - else if (priv->max_addresses > 3u * _SIZE_MAX_ADDRESSES) - priv->max_addresses = 3u * _SIZE_MAX_ADDRESSES; - break; - case PROP_RA_TIMEOUT: - /* construct-only */ - priv->ra_timeout = g_value_get_uint(value); - nm_assert(priv->ra_timeout <= NM_RA_TIMEOUT_INFINITY); - break; - case PROP_ROUTER_SOLICITATIONS: - /* construct-only */ - priv->router_solicitations = g_value_get_int(value); - break; - case PROP_ROUTER_SOLICITATION_INTERVAL: - /* construct-only */ - priv->router_solicitation_interval = g_value_get_int(value); - break; - case PROP_NODE_TYPE: - /* construct-only */ - priv->node_type = g_value_get_int(value); - nm_assert(NM_IN_SET(priv->node_type, NM_NDISC_NODE_TYPE_HOST, NM_NDISC_NODE_TYPE_ROUTER)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -1788,7 +1833,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps static void nm_ndisc_init(NMNDisc *ndisc) { - NMNDiscPrivate * priv; + NMNDiscPrivate *priv; NMNDiscDataInternal *rdata; priv = G_TYPE_INSTANCE_GET_PRIVATE(ndisc, NM_TYPE_NDISC, NMNDiscPrivate); @@ -1808,7 +1853,7 @@ nm_ndisc_init(NMNDisc *ndisc) static void dispose(GObject *object) { - NMNDisc * ndisc = NM_NDISC(object); + NMNDisc *ndisc = NM_NDISC(object); NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc); nm_clear_g_source_inst(&priv->ra_timeout_source); @@ -1824,13 +1869,10 @@ dispose(GObject *object) static void finalize(GObject *object) { - NMNDisc * ndisc = NM_NDISC(object); - NMNDiscPrivate * priv = NM_NDISC_GET_PRIVATE(ndisc); + NMNDisc *ndisc = NM_NDISC(object); + NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE(ndisc); NMNDiscDataInternal *rdata = &priv->rdata; - g_free(priv->ifname); - g_free(priv->network_id); - g_array_unref(rdata->gateways); g_array_unref(rdata->addresses); g_array_unref(rdata->routes); @@ -1838,7 +1880,10 @@ finalize(GObject *object) g_array_unref(rdata->dns_domains); g_clear_object(&priv->netns); - g_clear_object(&priv->platform); + + _config_clear(&priv->config_); + + nm_clear_l3cd(&priv->l3cd); G_OBJECT_CLASS(nm_ndisc_parent_class)->finalize(object); } @@ -1854,89 +1899,12 @@ nm_ndisc_class_init(NMNDiscClass *klass) object_class->dispose = dispose; object_class->finalize = finalize; - obj_properties[PROP_PLATFORM] = - g_param_spec_object(NM_NDISC_PLATFORM, - "", - "", - NM_TYPE_PLATFORM, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFINDEX] = - g_param_spec_int(NM_NDISC_IFINDEX, - "", - "", - 0, - G_MAXINT, - 0, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFNAME] = - g_param_spec_string(NM_NDISC_IFNAME, - "", - "", - NULL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STABLE_TYPE] = - g_param_spec_int(NM_NDISC_STABLE_TYPE, - "", - "", - NM_UTILS_STABLE_TYPE_UUID, - NM_UTILS_STABLE_TYPE_RANDOM, - NM_UTILS_STABLE_TYPE_UUID, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_NETWORK_ID] = - g_param_spec_string(NM_NDISC_NETWORK_ID, - "", - "", - NULL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ADDR_GEN_MODE] = - g_param_spec_int(NM_NDISC_ADDR_GEN_MODE, - "", - "", - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_MAX_ADDRESSES] = - g_param_spec_int(NM_NDISC_MAX_ADDRESSES, - "", - "", - 0, - G_MAXINT32, - NM_NDISC_MAX_ADDRESSES_DEFAULT, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - G_STATIC_ASSERT_EXPR(G_MAXINT32 == NM_RA_TIMEOUT_INFINITY); - obj_properties[PROP_RA_TIMEOUT] = - g_param_spec_uint(NM_NDISC_RA_TIMEOUT, - "", - "", - 0, - G_MAXINT32, - 0, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ROUTER_SOLICITATIONS] = - g_param_spec_int(NM_NDISC_ROUTER_SOLICITATIONS, - "", - "", - 1, - G_MAXINT32, - NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ROUTER_SOLICITATION_INTERVAL] = - g_param_spec_int(NM_NDISC_ROUTER_SOLICITATION_INTERVAL, - "", - "", - 1, - G_MAXINT32, - NM_NDISC_RFC4861_RTR_SOLICITATION_INTERVAL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_NODE_TYPE] = - g_param_spec_int(NM_NDISC_NODE_TYPE, - "", - "", - NM_NDISC_NODE_TYPE_INVALID, - NM_NDISC_NODE_TYPE_ROUTER, - NM_NDISC_NODE_TYPE_INVALID, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_CONFIG] = + g_param_spec_pointer(NM_NDISC_CONFIG, + "", + "", + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[CONFIG_RECEIVED] = g_signal_new(NM_NDISC_CONFIG_RECEIVED, @@ -1947,9 +1915,14 @@ nm_ndisc_class_init(NMNDiscClass *klass) NULL, NULL, G_TYPE_NONE, - 2, - G_TYPE_POINTER, - G_TYPE_UINT); + 3, + G_TYPE_POINTER + /* (const NMNDiscData *)rdata */, + G_TYPE_UINT + /* (guint) changed_i */, + G_TYPE_POINTER + /* (const NML3ConfigData *) l3cd */ + ); signals[RA_TIMEOUT_SIGNAL] = g_signal_new(NM_NDISC_RA_TIMEOUT_SIGNAL, G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, |