diff options
author | Thomas Haller <thaller@redhat.com> | 2020-09-11 16:21:57 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-09-11 16:21:57 +0200 |
commit | ebd07a809c26962eaa936e3a2ebb4133e7f4b399 (patch) | |
tree | 1bffdc94c657fb31d39d7d9374cb46e7796ea4c7 | |
parent | 75ff7a6daf705957d91054ae435f57b49a2437cc (diff) | |
parent | 2535b3a5396724ab451daa19ea059c2866b32f9a (diff) | |
download | NetworkManager-ebd07a809c26962eaa936e3a2ebb4133e7f4b399.tar.gz |
l3cfg: merge branch 'th/l3cfg-8'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/623
-rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.c | 252 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-shared-utils.h | 32 | ||||
-rw-r--r-- | shared/nm-glib-aux/tests/test-shared-general.c | 117 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 61 | ||||
-rw-r--r-- | src/devices/nm-device.c | 2345 | ||||
-rw-r--r-- | src/devices/nm-device.h | 2 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-client.c | 20 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-manager.c | 16 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-options.c | 6 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-utils.c | 20 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-utils.h | 2 | ||||
-rw-r--r-- | src/nm-core-utils.c | 107 | ||||
-rw-r--r-- | src/nm-core-utils.h | 20 | ||||
-rw-r--r-- | src/nm-iface-helper.c | 1 | ||||
-rw-r--r-- | src/nm-ip6-config.c | 25 | ||||
-rw-r--r-- | src/nm-l3-config-data.c | 78 | ||||
-rw-r--r-- | src/nm-l3-config-data.h | 11 | ||||
-rw-r--r-- | src/nm-l3cfg.c | 28 | ||||
-rw-r--r-- | src/nm-l3cfg.h | 29 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 32 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 10 |
21 files changed, 1915 insertions, 1299 deletions
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 21fb72dfb3..242719ffed 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -3294,33 +3294,253 @@ nm_utils_hash_values_to_array (GHashTable *hash, return arr; } -gboolean -nm_utils_hashtable_same_keys (const GHashTable *a, - const GHashTable *b) +static gboolean +_utils_hashtable_equal (GHashTable *hash_a, + GHashTable *hash_b, + GCompareDataFunc cmp_values, + gpointer user_data) { GHashTableIter h; - const char *k; + gpointer a_key; + gpointer a_val; + gpointer b_val; - if (a == b) + nm_assert (hash_a); + nm_assert (hash_b); + nm_assert (hash_a != hash_b); + nm_assert (g_hash_table_size (hash_a) == g_hash_table_size (hash_b)); + + /* We rely on both hashes to have the same hash/equal function. Otherwise, we would have to iterate + * both hashes and check whether all keys/values are present in the respective other hash (which + * would be O(n^2), since we couldn't use the plain lookup function. That is not a useful thing + * for this function. */ + + g_hash_table_iter_init (&h, hash_a); + while (g_hash_table_iter_next (&h, &a_key, &a_val)) { + + if (!g_hash_table_lookup_extended (hash_b, a_key, NULL, &b_val)) + return FALSE; + + if (!cmp_values) { + /* we accept %NULL compare function to indicate that we don't care about the key. */ + continue; + } + + if (cmp_values (a_val, b_val, user_data) != 0) + return FALSE; + } + + return TRUE; +} + +/** + * nm_utils_hashtable_equal: + * @a: (allow-none): the hash table or %NULL + * @b: (allow-none): the other hash table or %NULL + * @cmp_values: (allow-none): if %NULL, only the keys + * will be compared. Otherwise, this function is used to + * check whether all keys are equal. + * @user_data: the argument for @cmp_values. + * + * It is required that both @a and @b have the same hash and equals + * function. + * + * Returns: %TRUE, if both keys have the same keys and (if + * @cmp_values is given) all values are the same. + */ +gboolean +nm_utils_hashtable_equal (const GHashTable *a, + const GHashTable *b, + GCompareDataFunc cmp_values, + gpointer user_data) +{ + GHashTable *hash_a = (GHashTable *) a; + GHashTable *hash_b = (GHashTable *) b; + gboolean same; + guint size; + + if (hash_a == hash_b) return TRUE; - if (!a || !b) + + if (!hash_a || !hash_b) return FALSE; - if (g_hash_table_size ((GHashTable *) a) != g_hash_table_size ((GHashTable *) b)) + + size = g_hash_table_size (hash_a); + if (size != g_hash_table_size (hash_b)) return FALSE; - g_hash_table_iter_init (&h, (GHashTable *) a); - while (g_hash_table_iter_next (&h, (gpointer) &k, NULL)) { - if (!g_hash_table_contains ((GHashTable *) b, k)) - return FALSE; - } + if (size == 0) + return TRUE; + + same = _utils_hashtable_equal (hash_a, hash_b, cmp_values, user_data); #if NM_MORE_ASSERTS > 5 - g_hash_table_iter_init (&h, (GHashTable *) b); - while (g_hash_table_iter_next (&h, (gpointer) &k, NULL)) - nm_assert (g_hash_table_contains ((GHashTable *) a, k)); + nm_assert (same == _utils_hashtable_equal (hash_b, hash_a, cmp_values, user_data)); #endif - return TRUE; + return same; +} + +typedef struct { + gpointer key; + gpointer val; +} HashTableCmpData; + +typedef struct { + GCompareDataFunc cmp_keys; + gpointer user_data; +} HashTableUserData; + +static int +_hashtable_cmp_func (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + const HashTableUserData *d = user_data; + const HashTableCmpData *d_a = *((const HashTableCmpData *const*) a); + const HashTableCmpData *d_b = *((const HashTableCmpData *const*) b); + + NM_CMP_RETURN (d->cmp_keys (d_a, d_b, d->user_data)); + return 0; +} + +/** + * nm_utils_hashtable_cmp: + * @a: (allow-none): the hash to compare. May be %NULL. + * @b: (allow-none): the other hash to compare. May be %NULL. + * @do_fast_precheck: if %TRUE, assume that the hashes are equal + * and that it is worth calling nm_utils_hashtable_equal() first. + * That requires, that both hashes have the same equals function + * which is compatible with the @cmp_keys function. + * @cmp_keys: the compare function for keys. Usually, the hash/equal function + * of both hashes corresponds to this function. If you set @do_fast_precheck + * to false, then this is not a requirement. + * @cmp_values: (allow-none): if %NULL, only the keys are compared. + * Otherwise, the values must are also compared with this function. + * + * Both hashes must have keys/values of the same domain, so that + * they can be effectively compared with @cmp_keys and @cmp_values. + * + * %NULL hashes compare equal to %NULL, but not to empty hashes. + * + * Returns: 0 if both hashes are equal, or -1 or 1 if one of the hashes + * sorts before/after. + */ +int +nm_utils_hashtable_cmp (const GHashTable *a, + const GHashTable *b, + gboolean do_fast_precheck, + GCompareDataFunc cmp_keys, + GCompareDataFunc cmp_values, + gpointer user_data) +{ + GHashTable *hash_a = (GHashTable *) a; + GHashTable *hash_b = (GHashTable *) b; + gs_free HashTableCmpData *cmp_array_free = NULL; + HashTableCmpData *cmp_array_a; + HashTableCmpData *cmp_array_b; + GHashTableIter h; + gpointer i_key; + gpointer i_val; + gsize size2; + guint size; + guint i; + + nm_assert (cmp_keys); + + NM_CMP_SELF (hash_a, hash_b); + + size = g_hash_table_size (hash_a); + + NM_CMP_DIRECT (size, g_hash_table_size (hash_b)); + + if (size == 0) + return 0; + + if (do_fast_precheck) { + gboolean same; + + /* we expect that the hashes are equal and the caller ensures us that they + * use the same hash/equal functions. Do a fast path check first... + * + * It's unclear whether this is worth it. The full comparison is O(n*ln(n)), + * while the fast check (using the hash lookup) is O(n). But then, the pre-check + * makes additional requirements on the hash's hash/equal functions -- the + * full comparison does not make such requirements. */ + same = _utils_hashtable_equal (hash_a, hash_b, cmp_values, user_data); +#if NM_MORE_ASSERTS > 5 + nm_assert (same == _utils_hashtable_equal (hash_b, hash_a, cmp_values, user_data)); +#endif + if (same) + return 0; + } + + size2 = ((gsize) size) * 2u; + if (size2 > 600u / sizeof (HashTableCmpData)) { + cmp_array_free = g_new (HashTableCmpData, size2); + cmp_array_a = cmp_array_free; + } else + cmp_array_a = g_newa (HashTableCmpData, size2); + cmp_array_b = &cmp_array_a[size]; + + i = 0; + g_hash_table_iter_init (&h, hash_a); + while (g_hash_table_iter_next (&h, &i_key, &i_val)) { + nm_assert (i < size); + cmp_array_a[i++] = (HashTableCmpData) { + .key = i_key, + .val = i_val, + }; + } + nm_assert (i == size); + + i = 0; + g_hash_table_iter_init (&h, hash_b); + while (g_hash_table_iter_next (&h, &i_key, &i_val)) { + nm_assert (i < size); + cmp_array_b[i++] = (HashTableCmpData) { + .key = i_key, + .val = i_val, + }; + } + nm_assert (i == size); + + g_qsort_with_data (cmp_array_a, + size, + sizeof (HashTableCmpData), + _hashtable_cmp_func, + &((HashTableUserData) { + .cmp_keys = cmp_keys, + .user_data = user_data, + })); + + g_qsort_with_data (cmp_array_b, + size, + sizeof (HashTableCmpData), + _hashtable_cmp_func, + &((HashTableUserData) { + .cmp_keys = cmp_keys, + .user_data = user_data, + })); + + for (i = 0; i < size; i++) { + NM_CMP_RETURN (cmp_keys (cmp_array_a[i].key, + cmp_array_b[i].key, + user_data)); + } + + if (cmp_values) { + for (i = 0; i < size; i++) { + NM_CMP_RETURN (cmp_values (cmp_array_a[i].val, + cmp_array_b[i].val, + user_data)); + } + } + + /* the fast-precheck should have already told that the arrays are equal. */ + nm_assert (!do_fast_precheck); + + return 0; } char ** diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index aa6169d43b..e413531fd8 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1521,8 +1521,24 @@ nm_utils_strdict_get_keys (const GHashTable *hash, out_length); } -gboolean nm_utils_hashtable_same_keys (const GHashTable *a, - const GHashTable *b); +gboolean nm_utils_hashtable_equal (const GHashTable *a, + const GHashTable *b, + GCompareDataFunc cmp_values, + gpointer user_data); + +static inline gboolean +nm_utils_hashtable_same_keys (const GHashTable *a, + const GHashTable *b) +{ + return nm_utils_hashtable_equal (a, b, NULL, NULL); +} + +int nm_utils_hashtable_cmp (const GHashTable *a, + const GHashTable *b, + gboolean do_fast_precheck, + GCompareDataFunc cmp_keys, + GCompareDataFunc cmp_values, + gpointer user_data); char **nm_utils_strv_make_deep_copied (const char **strv); @@ -1564,14 +1580,14 @@ nm_g_array_len (const GArray *arr) #define nm_g_array_append_new(arr, type) \ ({ \ - GArray *_arr = (arr); \ - gsize _l; \ + GArray *const _arr = (arr); \ + guint _len; \ \ nm_assert (_arr); \ - _l = ((gsize) _arr->len) + 1u; \ - nm_assert (_l > _arr->len); \ - g_array_set_size (_arr, _l); \ - &g_array_index (arr, type, _l); \ + _len = _arr->len; \ + nm_assert (_len < G_MAXUINT); \ + g_array_set_size (_arr, _len + 1u); \ + &g_array_index (arr, type, _len); \ }) /*****************************************************************************/ diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c index 2d5bbd2220..4e31ade8a7 100644 --- a/shared/nm-glib-aux/tests/test-shared-general.c +++ b/shared/nm-glib-aux/tests/test-shared-general.c @@ -986,6 +986,122 @@ test_strv_dup_packed (void) /*****************************************************************************/ +static int +_hash_func_cmp_direct (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + NM_CMP_DIRECT (GPOINTER_TO_INT (a), GPOINTER_TO_INT (b)); + return 0; +} + +static void +test_utils_hashtable_cmp (void) +{ + static struct { + int val_i; + const char *val_s; + } vals[] = { + { 0, "0", }, + { 1, "1", }, + { 2, "2", }, + { 3, "3", }, + { 4, "4", }, + { 5, "5", }, + { 6, "6", }, + { 7, "7", }, + { 8, "8", }, + { 9, "9", }, + { 0, "a", }, + { 1, "a", }, + { 2, "a", }, + { 3, "a", }, + { 4, "a", }, + { 5, "a", }, + { 0, "0", }, + { 0, "1", }, + { 0, "2", }, + { 0, "3", }, + { 0, "4", }, + { 0, "5", }, + }; + guint test_run; + int is_num_key; + + for (test_run = 0; test_run < 30; test_run++) { + for (is_num_key = 0; is_num_key < 2; is_num_key++) { + GHashFunc func_key_hash = is_num_key ? nm_direct_hash : nm_str_hash; + GEqualFunc func_key_equal = is_num_key ? g_direct_equal : g_str_equal; + GCompareDataFunc func_key_cmp = is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data; + GCompareDataFunc func_val_cmp = !is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data; + gs_unref_hashtable GHashTable *h1 = NULL; + gs_unref_hashtable GHashTable *h2 = NULL; + gboolean has_same_keys; + guint i, n; + + h1 = g_hash_table_new (func_key_hash, func_key_equal); + h2 = g_hash_table_new (func_key_hash, func_key_equal); + + n = nmtst_get_rand_word_length (NULL); + for (i = 0; i < n; i++) { + typeof (vals[0]) *v = &vals[nmtst_get_rand_uint32 () % G_N_ELEMENTS (vals)]; + gconstpointer v_key = is_num_key ? GINT_TO_POINTER (v->val_i) : v->val_s; + gconstpointer v_val = !is_num_key ? GINT_TO_POINTER (v->val_i) : v->val_s; + + g_hash_table_insert (h1, (gpointer) v_key, (gpointer) v_val); + g_hash_table_insert (h2, (gpointer) v_key, (gpointer) v_val); + } + + g_assert (nm_utils_hashtable_same_keys (h1, h2)); + g_assert (nm_utils_hashtable_equal (h1, h2, NULL, NULL)); + g_assert (nm_utils_hashtable_equal (h1, h2, func_val_cmp, NULL)); + g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0); + g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0); + g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) == 0); + g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) == 0); + + n = nmtst_get_rand_word_length (NULL) + 1; + has_same_keys = TRUE; + for (i = 0; i < n; i++) { +again: + { + typeof (vals[0]) *v = &vals[nmtst_get_rand_uint32 () % G_N_ELEMENTS (vals)]; + gconstpointer v_key = is_num_key ? GINT_TO_POINTER (v->val_i) : v->val_s; + gconstpointer v_val = !is_num_key ? GINT_TO_POINTER (v->val_i) : v->val_s; + gpointer v_key2; + gpointer v_val2; + + if (g_hash_table_lookup_extended (h1, v_key, &v_key2, &v_val2)) { + g_assert (func_key_cmp (v_key, v_key2, NULL) == 0); + if (func_val_cmp (v_val, v_val2, NULL) == 0) + goto again; + } else + has_same_keys = FALSE; + + g_hash_table_insert (h2, (gpointer) v_key, (gpointer) v_val); + } + } + + if (has_same_keys) { + g_assert (nm_utils_hashtable_same_keys (h1, h2)); + g_assert (nm_utils_hashtable_equal (h1, h2, NULL, NULL)); + g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0); + g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0); + } else { + g_assert (!nm_utils_hashtable_same_keys (h1, h2)); + g_assert (!nm_utils_hashtable_equal (h1, h2, NULL, NULL)); + g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, NULL, NULL) != 0); + g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, NULL, NULL) != 0); + } + g_assert (!nm_utils_hashtable_equal (h1, h2, func_val_cmp, NULL)); + g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) != 0); + g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) != 0); + } + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -1011,6 +1127,7 @@ int main (int argc, char **argv) g_test_add_func ("/general/test_in_strset_ascii_case", test_in_strset_ascii_case); g_test_add_func ("/general/test_is_specific_hostname", test_is_specific_hostname); g_test_add_func ("/general/test_strv_dup_packed", test_strv_dup_packed); + g_test_add_func ("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp); return g_test_run (); } diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 7d2b81dd49..5b3a9f9489 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -159,4 +159,65 @@ void nm_utils_ip_routes_to_dbus (int addr_family, GVariant **out_route_data, GVariant **out_routes); +/*****************************************************************************/ + +/* For now, all we track about a DHCP lease is the GHashTable with + * the options. + * + * We don't add a separate type for that, but we also don't want to use + * GHashTable directly (because most importantly leases should be immutable + * and passing a GHashTable pointer around neither makes it clear that + * this is a lease nor that it's immutable. + * + * Instead, add a simple opaque pointer and accessors that cast to a GHashTable. + * + * It has no overhead at run time, but gives some rudimentary type safety. */ + +typedef struct _NMDhcpLease NMDhcpLease; + +static inline NMDhcpLease * +nm_dhcp_lease_new_from_options (GHashTable *options_take) +{ + /* a NMDhcpLease is really just a GHashTable. But it's also supposed to be *immutable*. + * + * Hence, the API here takes over ownership of the reference to @options_take, that + * is to emphasize that we acquire ownership of the hash, and it should not be modified + * anymore. */ + return (NMDhcpLease *) options_take; +} + +static inline GHashTable * +nm_dhcp_lease_get_options (NMDhcpLease *lease) +{ + return (GHashTable *) lease; +} + +static inline void +nm_dhcp_lease_ref (NMDhcpLease *lease) +{ + if (lease) + g_hash_table_ref ((GHashTable *) lease); +} + +static inline void +nm_dhcp_lease_unref (NMDhcpLease *lease) +{ + if (lease) + g_hash_table_unref ((GHashTable *) lease); +} + +static inline const char * +nm_dhcp_lease_lookup_option (NMDhcpLease *lease, + const char *option) +{ + nm_assert (option); + + return nm_g_hash_table_lookup ((GHashTable *) lease, option); +} + +NM_AUTO_DEFINE_FCN (NMDhcpLease *, _nm_auto_unref_dhcplease, nm_dhcp_lease_unref); +#define nm_auto_unref_dhcplease nm_auto (_nm_auto_unref_dhcplease) + +/*****************************************************************************/ + #endif /* __NETWORKMANAGER_UTILS_H__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 832116bd05..c1a2bab12b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -442,6 +442,11 @@ typedef struct _NMDevicePrivate { NML3ConfigMergeFlags l3config_merge_flags_x[2]; }; + union { + const NMDeviceSysIfaceState sys_iface_state; + NMDeviceSysIfaceState sys_iface_state_; + }; + bool carrier:1; bool ignore_carrier:1; @@ -453,8 +458,6 @@ typedef struct _NMDevicePrivate { bool default_route_metric_penalty_ip4_has:1; bool default_route_metric_penalty_ip6_has:1; - NMDeviceSysIfaceState sys_iface_state:2; - bool v4_route_table_initialized:1; bool v6_route_table_initialized:1; @@ -537,7 +540,6 @@ typedef struct _NMDevicePrivate { /* DHCPv4 tracking */ struct { char * pac_url; - char * root_path; } dhcp4; struct { @@ -705,7 +707,7 @@ static gboolean linklocal6_start (NMDevice *self); static guint32 default_route_metric_penalty_get (NMDevice *self, int addr_family); -static guint get_ipv4_dad_timeout (NMDevice *self); +static guint _prop_get_ipv4_dad_timeout (NMDevice *self); static void _carrier_wait_check_queued_act_request (NMDevice *self); static gint64 _get_carrier_wait_ms (NMDevice *self); @@ -869,6 +871,1076 @@ NM_UTILS_LOOKUP_STR_DEFINE (mtu_source_to_str, NMDeviceMtuSource, /*****************************************************************************/ +static NMSettingIP6ConfigPrivacy +_ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) +{ + switch (use_tempaddr) { + case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: + return use_tempaddr; + default: + return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + } +} + +/*****************************************************************************/ + +static const char * +_prop_get_connection_stable_id (NMDevice *self, + NMConnection *connection, + NMUtilsStableType *out_stable_type) +{ + NMDevicePrivate *priv; + + nm_assert (NM_IS_DEVICE (self)); + nm_assert (NM_IS_CONNECTION (connection)); + nm_assert (out_stable_type); + + priv = NM_DEVICE_GET_PRIVATE (self); + + /* we cache the generated stable ID for the time of an activation. + * + * The reason is, that we don't want the stable-id to change as long + * as the device is active. + * + * Especially with ${RANDOM} stable-id we want to generate *one* configuration + * for each activation. */ + if (G_UNLIKELY (!priv->current_stable_id)) { + gs_free char *default_id = NULL; + gs_free char *generated = NULL; + NMUtilsStableType stable_type; + NMSettingConnection *s_con; + gboolean hwaddr_is_fake; + const char *hwaddr; + const char *stable_id; + const char *uuid; + + s_con = nm_connection_get_setting_connection (connection); + + stable_id = nm_setting_connection_get_stable_id (s_con); + + if (!stable_id) { + default_id = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("connection.stable-id"), + self); + stable_id = default_id; + } + + uuid = nm_connection_get_uuid (connection); + + /* the cloned-mac-address may be generated based on the stable-id. + * Thus, at this point, we can only use the permanent MAC address + * as seed. */ + hwaddr = nm_device_get_permanent_hw_address_full (self, TRUE, &hwaddr_is_fake); + + stable_type = nm_utils_stable_id_parse (stable_id, + nm_device_get_ip_iface (self), + !hwaddr_is_fake ? hwaddr : NULL, + nm_utils_boot_id_str (), + uuid, + &generated); + + /* current_stable_id_type is a bitfield! */ + priv->current_stable_id_type = stable_type; + nm_assert (stable_type <= (NMUtilsStableType) 0x3); + nm_assert (stable_type + (NMUtilsStableType) 1 > (NMUtilsStableType) 0); + nm_assert (priv->current_stable_id_type == stable_type); + + if (stable_type == NM_UTILS_STABLE_TYPE_UUID) + priv->current_stable_id = g_strdup (uuid); + else if (stable_type == NM_UTILS_STABLE_TYPE_STABLE_ID) + priv->current_stable_id = g_strdup (stable_id); + else if (stable_type == NM_UTILS_STABLE_TYPE_GENERATED) + priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_generated_complete (generated)); + else { + nm_assert (stable_type == NM_UTILS_STABLE_TYPE_RANDOM); + priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_random ()); + } + _LOGT (LOGD_DEVICE, + "stable-id: type=%d, \"%s\"" + "%s%s%s", + (int) priv->current_stable_id_type, + priv->current_stable_id, + NM_PRINT_FMT_QUOTED (stable_type == NM_UTILS_STABLE_TYPE_GENERATED, " from \"", generated, "\"", "")); + } + + nm_assert (priv->current_stable_id); + *out_stable_type = priv->current_stable_id_type; + return priv->current_stable_id; +} + +static GBytes * +_prop_get_ipv6_dhcp_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboolean *out_enforce) +{ + NMSettingIPConfig *s_ip6; + const char *duid; + gs_free char *duid_default = NULL; + const char *duid_error; + GBytes *duid_out; + gboolean duid_enforce = TRUE; + gs_free char *logstr1 = NULL; + const guint8 *hwaddr_bin; + gsize hwaddr_len; + int arp_type; + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + duid = nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6)); + + if (!duid) { + duid_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("ipv6.dhcp-duid"), + self); + duid = duid_default; + if (!duid) + duid = "lease"; + } + + if (nm_streq (duid, "lease")) { + duid_enforce = FALSE; + duid_out = nm_utils_generate_duid_from_machine_id (); + goto out_good; + } + + if (!_nm_utils_dhcp_duid_valid (duid, &duid_out)) { + duid_error = "invalid duid"; + goto out_fail; + } + + if (duid_out) + goto out_good; + + if (NM_IN_STRSET (duid, "ll", "llt")) { + if (!hwaddr) { + duid_error = "missing link-layer address"; + goto out_fail; + } + + hwaddr_bin = g_bytes_get_data (hwaddr, &hwaddr_len); + arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); + if (arp_type < 0) { + duid_error = "unsupported link-layer address"; + goto out_fail; + } + + if (nm_streq (duid, "ll")) + duid_out = nm_utils_generate_duid_ll (arp_type, hwaddr_bin, hwaddr_len); + else { + duid_out = nm_utils_generate_duid_llt (arp_type, hwaddr_bin, hwaddr_len, + nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NSEC_PER_SEC); + } + + goto out_good; + } + + if (NM_IN_STRSET (duid, "stable-ll", "stable-llt", "stable-uuid")) { + /* preferably, we would salt the checksum differently for each @duid type. We missed + * to do that initially, so most types use the DEFAULT_SALT. + * + * Implementations that are added later, should use a distinct salt instead, + * like "stable-ll"/"stable-llt" with ARPHRD_INFINIBAND below. */ + const guint32 DEFAULT_SALT = 670531087u; + nm_auto_free_checksum GChecksum *sum = NULL; + NMUtilsStableType stable_type; + const char *stable_id = NULL; + guint32 salted_header; + const guint8 *host_id; + gsize host_id_len; + union { + guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256]; + guint8 hwaddr_eth[ETH_ALEN]; + guint8 hwaddr_infiniband[INFINIBAND_ALEN]; + NMUuid uuid; + struct _nm_packed { + guint8 hwaddr[ETH_ALEN]; + guint32 timestamp; + } llt_eth; + struct _nm_packed { + guint8 hwaddr[INFINIBAND_ALEN]; + guint32 timestamp; + } llt_infiniband; + } digest; + + stable_id = _prop_get_connection_stable_id (self, connection, &stable_type); + + if (NM_IN_STRSET (duid, "stable-ll", "stable-llt")) { + /* for stable LL/LLT DUIDs, we still need a hardware address to detect + * the arp-type. Alternatively, we would be able to detect it based on + * other means (e.g. NMDevice type), but instead require the hardware + * address to be present. This is at least consistent with the "ll"/"llt" + * modes above. */ + if (!hwaddr) { + duid_error = "missing link-layer address"; + goto out_fail; + } + if ((arp_type = nm_utils_arp_type_detect_from_hwaddrlen (g_bytes_get_size (hwaddr))) < 0) { + duid_error = "unsupported link-layer address"; + goto out_fail; + } + + if (arp_type == ARPHRD_ETHER) + salted_header = DEFAULT_SALT; + else { + nm_assert (arp_type == ARPHRD_INFINIBAND); + salted_header = 0x42492CEFu + ((guint32) arp_type); + } + } else { + salted_header = DEFAULT_SALT; + arp_type = -1; + } + + salted_header = htonl (salted_header + ((guint32) stable_type)); + + nm_utils_host_id_get (&host_id, &host_id_len); + + sum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); + g_checksum_update (sum, (const guchar *) stable_id, -1); + g_checksum_update (sum, (const guchar *) host_id, host_id_len); + nm_utils_checksum_get_digest (sum, digest.sha256); + + G_STATIC_ASSERT_EXPR (sizeof (digest) == sizeof (digest.sha256)); + + if (nm_streq (duid, "stable-ll")) { + switch (arp_type) { + case ARPHRD_ETHER: + duid_out = nm_utils_generate_duid_ll (arp_type, digest.hwaddr_eth, sizeof (digest.hwaddr_eth)); + break; + case ARPHRD_INFINIBAND: + duid_out = nm_utils_generate_duid_ll (arp_type, digest.hwaddr_infiniband, sizeof (digest.hwaddr_infiniband)); + break; + default: + g_return_val_if_reached (NULL); + } + } else if (nm_streq (duid, "stable-llt")) { + gint64 time; + guint32 timestamp; + +#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3) + + /* We want a variable time between the host_id timestamp and three years + * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll + * subtract it from the host_id timestamp. + */ + time = nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NSEC_PER_SEC; + + /* don't use too old timestamps. They cannot be expressed in DUID-LLT and + * would all be truncated to zero. */ + time = NM_MAX (time, NM_UTILS_EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS); + + switch (arp_type) { + case ARPHRD_ETHER: + timestamp = unaligned_read_be32 (&digest.llt_eth.timestamp); + time -= timestamp % EPOCH_DATETIME_THREE_YEARS; + duid_out = nm_utils_generate_duid_llt (arp_type, digest.llt_eth.hwaddr, sizeof (digest.llt_eth.hwaddr), time); + break; + case ARPHRD_INFINIBAND: + timestamp = unaligned_read_be32 (&digest.llt_infiniband.timestamp); + time -= timestamp % EPOCH_DATETIME_THREE_YEARS; + duid_out = nm_utils_generate_duid_llt (arp_type, digest.llt_infiniband.hwaddr, sizeof (digest.llt_infiniband.hwaddr), time); + break; + default: + g_return_val_if_reached (NULL); + } + } else { + nm_assert (nm_streq (duid, "stable-uuid")); + duid_out = nm_utils_generate_duid_uuid (&digest.uuid); + } + + goto out_good; + } + + g_return_val_if_reached (NULL); + +out_fail: + nm_assert (!duid_out && duid_error); + { + NMUuid uuid; + + _LOGW (LOGD_IP6 | LOGD_DHCP6, + "ipv6.dhcp-duid: failure to generate %s DUID: %s. Fallback to random DUID-UUID.", + duid, duid_error); + + nm_utils_random_bytes (&uuid, sizeof (uuid)); + duid_out = nm_utils_generate_duid_uuid (&uuid); + } + +out_good: + nm_assert (duid_out); + _LOGD (LOGD_IP6 | LOGD_DHCP6, + "ipv6.dhcp-duid: generate %s DUID '%s' (%s)", + duid, + (logstr1 = nm_dhcp_utils_duid_to_string (duid_out)), + duid_enforce ? "enforcing" : "prefer lease"); + + NM_SET_OUT (out_enforce, duid_enforce); + return duid_out; +} + +static gint32 +_prop_get_ipv6_ra_timeout (NMDevice *self) +{ + NMConnection *connection; + gint32 timeout; + + G_STATIC_ASSERT_EXPR (NM_RA_TIMEOUT_DEFAULT == 0); + G_STATIC_ASSERT_EXPR (NM_RA_TIMEOUT_INFINITY == G_MAXINT32); + + connection = nm_device_get_applied_connection (self); + + timeout = nm_setting_ip6_config_get_ra_timeout (NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection))); + nm_assert (timeout >= 0); + if (timeout) + return timeout; + + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("ipv6.ra-timeout"), + self, + 0, G_MAXINT32, 0); +} + +static NMSettingConnectionMdns +_prop_get_connection_mdns (NMDevice *self) +{ + NMConnection *connection; + NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + + g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_MDNS_DEFAULT); + + connection = nm_device_get_applied_connection (self); + if (connection) + mdns = nm_setting_connection_get_mdns (nm_connection_get_setting_connection (connection)); + if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) + return mdns; + + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("connection.mdns"), + self, + NM_SETTING_CONNECTION_MDNS_NO, + NM_SETTING_CONNECTION_MDNS_YES, + NM_SETTING_CONNECTION_MDNS_DEFAULT); +} + +static NMSettingConnectionLlmnr +_prop_get_connection_llmnr (NMDevice *self) +{ + NMConnection *connection; + NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; + + g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_LLMNR_DEFAULT); + + connection = nm_device_get_applied_connection (self); + if (connection) + llmnr = nm_setting_connection_get_llmnr (nm_connection_get_setting_connection (connection)); + if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) + return llmnr; + + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("connection.llmnr"), + self, + NM_SETTING_CONNECTION_LLMNR_NO, + NM_SETTING_CONNECTION_LLMNR_YES, + NM_SETTING_CONNECTION_LLMNR_DEFAULT); +} + +static guint32 +_prop_get_ipvx_route_table (NMDevice *self, + int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceClass *klass; + NMConnection *connection; + NMSettingIPConfig *s_ip; + guint32 route_table = 0; + gboolean is_user_config = TRUE; + NMSettingConnection *s_con; + NMSettingVrf *s_vrf; + + nm_assert_addr_family (addr_family); + + /* the route table setting affects how we sync routes. We shall + * not change it while the device is active, hence, cache it. */ + if (addr_family == AF_INET) { + if (priv->v4_route_table_initialized) + return priv->v4_route_table; + } else { + if (priv->v6_route_table_initialized) + return priv->v6_route_table; + } + + connection = nm_device_get_applied_connection (self); + if (connection) { + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); + if (s_ip) + route_table = nm_setting_ip_config_get_route_table (s_ip); + } + if (route_table == 0u) { + gint64 v; + + v = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? NM_CON_DEFAULT ("ipv4.route-table") + : NM_CON_DEFAULT ("ipv6.route-table"), + self, + 0, + G_MAXUINT32, + -1); + if (v != -1) { + route_table = v; + is_user_config = FALSE; + } + } + + if ( route_table == 0u + && connection + && (s_con = nm_connection_get_setting_connection (connection)) + && (nm_streq0 (nm_setting_connection_get_slave_type (s_con), NM_SETTING_VRF_SETTING_NAME) + && priv->master + && nm_device_get_device_type (priv->master) == NM_DEVICE_TYPE_VRF)) { + const NMPlatformLnkVrf *lnk; + + lnk = nm_platform_link_get_lnk_vrf (nm_device_get_platform (self), + nm_device_get_ifindex (priv->master), + NULL); + + if (lnk) + route_table = lnk->table; + } + + if ( route_table == 0u + && connection + && (s_vrf = (NMSettingVrf *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF))) { + route_table = nm_setting_vrf_get_table (s_vrf); + } + + klass = NM_DEVICE_GET_CLASS (self); + if (klass->coerce_route_table) + route_table = klass->coerce_route_table (self, addr_family, route_table, is_user_config); + + if (addr_family == AF_INET) { + priv->v4_route_table_initialized = TRUE; + priv->v4_route_table = route_table; + } else { + priv->v6_route_table_initialized = TRUE; + priv->v6_route_table = route_table; + } + + _LOGT (LOGD_DEVICE, + "ipv%c.route-table = %u%s", + addr_family == AF_INET ? '4' : '6', + (guint) (route_table ?: RT_TABLE_MAIN), + route_table != 0u ? "" : " (policy routing not enabled)"); + + return route_table; +} + +static gboolean +_prop_get_connection_lldp (NMDevice *self) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingConnectionLldp lldp = NM_SETTING_CONNECTION_LLDP_DEFAULT; + + connection = nm_device_get_applied_connection (self); + g_return_val_if_fail (connection, FALSE); + + s_con = nm_connection_get_setting_connection (connection); + g_return_val_if_fail (s_con, FALSE); + + lldp = nm_setting_connection_get_lldp (s_con); + if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) { + lldp = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("connection.lldp"), + self, + NM_SETTING_CONNECTION_LLDP_DEFAULT, + NM_SETTING_CONNECTION_LLDP_ENABLE_RX, + NM_SETTING_CONNECTION_LLDP_DEFAULT); + if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) + lldp = NM_SETTING_CONNECTION_LLDP_DISABLE; + } + return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX; +} + +static guint +_prop_get_ipv4_dad_timeout (NMDevice *self) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip4 = NULL; + int timeout = -1; + + connection = nm_device_get_applied_connection (self); + if (connection) + s_ip4 = nm_connection_get_setting_ip4_config (connection); + if (s_ip4) + timeout = nm_setting_ip_config_get_dad_timeout (s_ip4); + if (timeout >= 0) + return timeout; + + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("ipv4.dad-timeout"), + self, + 0, + NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, + 0); +} + +static guint32 +_prop_get_ipvx_dhcp_timeout (NMDevice *self, int addr_family) +{ + NMDeviceClass *klass; + NMConnection *connection; + int timeout_i; + guint32 timeout; + + nm_assert (NM_IS_DEVICE (self)); + nm_assert_addr_family (addr_family); + + connection = nm_device_get_applied_connection (self); + + timeout_i = nm_setting_ip_config_get_dhcp_timeout (nm_connection_get_setting_ip_config (connection, addr_family)); + nm_assert (timeout_i >= 0 && timeout_i <= G_MAXINT32); + + timeout = (guint32) timeout_i; + if (timeout) + goto out; + + timeout = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? NM_CON_DEFAULT ("ipv4.dhcp-timeout") + : NM_CON_DEFAULT ("ipv6.dhcp-timeout"), + self, + 0, G_MAXINT32, 0); + if (timeout) + goto out; + + klass = NM_DEVICE_GET_CLASS (self); + if (klass->get_dhcp_timeout_for_device) { + timeout = klass->get_dhcp_timeout_for_device (self, addr_family); + if (timeout) + goto out; + } + + timeout = NM_DHCP_TIMEOUT_DEFAULT; + +out: + G_STATIC_ASSERT_EXPR (G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); + nm_assert (timeout > 0); + nm_assert (timeout <= G_MAXINT32); + return timeout; +} + +/** + * _prop_get_ipvx_dhcp_iaid: + * @self: the #NMDevice + * @addr_family: the address family + * @connection: the connection + * @out_is_explicit: on return, %TRUE if the user set a valid IAID in + * the connection or in global configuration; %FALSE if the connection + * property was empty and no valid global configuration was provided. + * + * Returns: a IAID value for this device and the given connection. + */ +static guint32 +_prop_get_ipvx_dhcp_iaid (NMDevice *self, + int addr_family, + NMConnection *connection, + gboolean *out_is_explicit) +{ + NMSettingIPConfig *s_ip; + const char *iaid_str; + gs_free char *iaid_str_free = NULL; + guint32 iaid; + const char *iface; + const char *fail_reason; + gboolean is_explicit = TRUE; + + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); + iaid_str = nm_setting_ip_config_get_dhcp_iaid (s_ip); + if (!iaid_str) { + iaid_str_free = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? NM_CON_DEFAULT ("ipv4.dhcp-iaid") + : NM_CON_DEFAULT ("ipv6.dhcp-iaid"), + self); + iaid_str = iaid_str_free; + if (!iaid_str) { + iaid_str = NM_IAID_IFNAME; + is_explicit = FALSE; + } else if (!_nm_utils_iaid_verify (iaid_str, NULL)) { + _LOGW (LOGD_DEVICE, "invalid global default '%s' for ipv%c.dhcp-iaid", + iaid_str, + nm_utils_addr_family_to_char (addr_family)); + iaid_str = NM_IAID_IFNAME; + is_explicit = FALSE; + } + } + + if (nm_streq0 (iaid_str, NM_IAID_MAC)) { + const NMPlatformLink *pllink; + + pllink = nm_platform_link_get (nm_device_get_platform (self), + nm_device_get_ip_ifindex (self)); + if (!pllink || pllink->l_address.len < 4) { + fail_reason = "invalid link-layer address"; + goto out_fail; + } + + /* @iaid is in native endianness. Use unaligned_read_be32() + * so that the IAID for a given MAC address is the same on + * BE and LE machines. */ + iaid = unaligned_read_be32 (&pllink->l_address.data[pllink->l_address.len - 4]); + goto out_good; + } else if (nm_streq0 (iaid_str, NM_IAID_PERM_MAC)) { + guint8 hwaddr_buf[NM_UTILS_HWADDR_LEN_MAX]; + const char *hwaddr_str; + gsize hwaddr_len; + + hwaddr_str = nm_device_get_permanent_hw_address (self); + if (!hwaddr_str) { + fail_reason = "no permanent link-layer address"; + goto out_fail; + } + + if (!_nm_utils_hwaddr_aton (hwaddr_str, hwaddr_buf, sizeof (hwaddr_buf), &hwaddr_len)) + g_return_val_if_reached (0); + + if (hwaddr_len < 4) { + fail_reason = "invalid link-layer address"; + goto out_fail; + } + + iaid = unaligned_read_be32 (&hwaddr_buf[hwaddr_len - 4]); + goto out_good; + } else if (nm_streq (iaid_str, "stable")) { + nm_auto_free_checksum GChecksum *sum = NULL; + guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; + NMUtilsStableType stable_type; + const char *stable_id; + guint32 salted_header; + const guint8 *host_id; + gsize host_id_len; + + stable_id = _prop_get_connection_stable_id (self, connection, &stable_type); + salted_header = htonl (53390459 + stable_type); + nm_utils_host_id_get (&host_id, &host_id_len); + iface = nm_device_get_ip_iface (self); + + sum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); + g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1); + g_checksum_update (sum, (const guchar *) iface, strlen (iface) + 1); + g_checksum_update (sum, (const guchar *) host_id, host_id_len); + nm_utils_checksum_get_digest (sum, digest); + + iaid = unaligned_read_be32 (digest); + goto out_good; + } else if ((iaid = _nm_utils_ascii_str_to_int64 (iaid_str, 10, 0, G_MAXUINT32, -1)) != -1) { + goto out_good; + } else { + iface = nm_device_get_ip_iface (self); + iaid = nm_utils_create_dhcp_iaid (TRUE, + (const guint8 *) iface, + strlen (iface)); + goto out_good; + } + +out_fail: + nm_assert (fail_reason); + _LOGW ( addr_family == AF_INET + ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) + : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), + "ipv%c.dhcp-iaid: failure to generate IAID: %s. Using interface-name based IAID", + nm_utils_addr_family_to_char (addr_family), fail_reason); + is_explicit = FALSE; + iface = nm_device_get_ip_iface (self); + iaid = nm_utils_create_dhcp_iaid (TRUE, + (const guint8 *) iface, + strlen (iface)); +out_good: + _LOGD ( addr_family == AF_INET + ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) + : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), + "ipv%c.dhcp-iaid: using %u (0x%08x) IAID (str: '%s', explicit %d)", + nm_utils_addr_family_to_char (addr_family), iaid, iaid, + iaid_str, is_explicit); + NM_SET_OUT (out_is_explicit, is_explicit); + return iaid; +} + +static NMDhcpHostnameFlags +_prop_get_ipvx_dhcp_hostname_flags (NMDevice *self, int addr_family) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip; + NMDhcpHostnameFlags flags; + gs_free_error GError *error = NULL; + + g_return_val_if_fail (NM_IS_DEVICE (self), NM_DHCP_HOSTNAME_FLAG_NONE); + + connection = nm_device_get_applied_connection (self); + s_ip = nm_connection_get_setting_ip_config (connection, addr_family); + g_return_val_if_fail (s_ip, NM_DHCP_HOSTNAME_FLAG_NONE); + + if (!nm_setting_ip_config_get_dhcp_send_hostname (s_ip)) + return NM_DHCP_HOSTNAME_FLAG_NONE; + + flags = nm_setting_ip_config_get_dhcp_hostname_flags (s_ip); + if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) + return flags; + + flags = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? NM_CON_DEFAULT ("ipv4.dhcp-hostname-flags") + : NM_CON_DEFAULT ("ipv6.dhcp-hostname-flags"), + self, + 0, NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS, + 0); + + if (!_nm_utils_validate_dhcp_hostname_flags (flags, addr_family, &error)) { + _LOGW (LOGD_DEVICE, "invalid global default value 0x%x for ipv%d.%s: %s", + (guint) flags, + addr_family == AF_INET ? 4 : 6, + NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS, + error->message); + flags = NM_DHCP_HOSTNAME_FLAG_NONE; + } + + if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) + return flags; + + if (addr_family == AF_INET) + return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP4; + else + return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP6; +} + +static const char * +_prop_get_connection_mud_url (NMDevice *self, + NMSettingConnection *s_con, + char **out_mud_url) +{ + const char *mud_url; + gs_free char *s = NULL; + + nm_assert (out_mud_url && !*out_mud_url); + + mud_url = nm_setting_connection_get_mud_url (s_con); + + if (mud_url) { + if (nm_streq (mud_url, NM_CONNECTION_MUD_URL_NONE)) + return NULL; + return mud_url; + } + + s = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("connection.mud-url"), + self); + if (s) { + if (nm_streq (s, NM_CONNECTION_MUD_URL_NONE)) + return NULL; + if (nm_sd_http_url_is_valid_https (s)) + return (*out_mud_url = g_steal_pointer (&s)); + } + + return NULL; +} + +static GBytes * +_prop_get_ipv4_dhcp_client_id (NMDevice *self, + NMConnection *connection, + GBytes *hwaddr) +{ + NMSettingIPConfig *s_ip4; + const char *client_id; + gs_free char *client_id_default = NULL; + guint8 *client_id_buf; + const char *fail_reason; + guint8 hwaddr_bin_buf[NM_UTILS_HWADDR_LEN_MAX]; + const guint8 *hwaddr_bin; + int arp_type; + gsize hwaddr_len; + GBytes *result; + gs_free char *logstr1 = NULL; + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + client_id = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)); + + if (!client_id) { + client_id_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("ipv4.dhcp-client-id"), + self); + if (client_id_default && client_id_default[0]) { + /* a non-empty client-id is always valid, see nm_dhcp_utils_client_id_string_to_bytes(). */ + client_id = client_id_default; + } + } + + if (!client_id) { + _LOGD (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: no explicit client-id configured"); + return NULL; + } + + if (nm_streq (client_id, "mac")) { + if (!hwaddr) { + fail_reason = "missing link-layer address"; + goto out_fail; + } + + hwaddr_bin = g_bytes_get_data (hwaddr, &hwaddr_len); + arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); + if (arp_type < 0) { + fail_reason = "unsupported link-layer address"; + goto out_fail; + } + + result = nm_utils_dhcp_client_id_mac (arp_type, hwaddr_bin, hwaddr_len); + goto out_good; + } + + if (nm_streq (client_id, "perm-mac")) { + const char *hwaddr_str; + + hwaddr_str = nm_device_get_permanent_hw_address (self); + if (!hwaddr_str) { + fail_reason = "missing permanent link-layer address"; + goto out_fail; + } + + if (!_nm_utils_hwaddr_aton (hwaddr_str, hwaddr_bin_buf, sizeof (hwaddr_bin_buf), &hwaddr_len)) + g_return_val_if_reached (NULL); + + arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); + if (arp_type < 0) { + fail_reason = "unsupported permanent link-layer address"; + goto out_fail; + } + + result = nm_utils_dhcp_client_id_mac (arp_type, hwaddr_bin_buf, hwaddr_len); + goto out_good; + } + + if (nm_streq (client_id, "duid")) { + guint32 iaid = _prop_get_ipvx_dhcp_iaid (self, AF_INET, connection, NULL); + + result = nm_utils_dhcp_client_id_systemd_node_specific (iaid); + goto out_good; + } + + if (nm_streq (client_id, "stable")) { + nm_auto_free_checksum GChecksum *sum = NULL; + guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; + NMUtilsStableType stable_type; + const char *stable_id; + guint32 salted_header; + const guint8 *host_id; + gsize host_id_len; + + stable_id = _prop_get_connection_stable_id (self, connection, &stable_type); + salted_header = htonl (2011610591 + stable_type); + nm_utils_host_id_get (&host_id, &host_id_len); + + sum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); + g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1); + g_checksum_update (sum, (const guchar *) host_id, host_id_len); + nm_utils_checksum_get_digest (sum, digest); + + client_id_buf = g_malloc (1 + 15); + client_id_buf[0] = 0; + memcpy (&client_id_buf[1], digest, 15); + result = g_bytes_new_take (client_id_buf, 1 + 15); + goto out_good; + } + + result = nm_dhcp_utils_client_id_string_to_bytes (client_id); + goto out_good; + +out_fail: + nm_assert (fail_reason); + _LOGW (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: failure to generate client id (%s). Use random client id", + fail_reason); + client_id_buf = g_malloc (1 + 15); + client_id_buf[0] = 0; + nm_utils_random_bytes (&client_id_buf[1], 15); + result = g_bytes_new_take (client_id_buf, 1 + 15); + +out_good: + nm_assert (result); + _LOGD (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: use \"%s\" client ID: %s", + client_id, + (logstr1 = nm_dhcp_utils_duid_to_string (result))); + return result; +} + +static GBytes * +_prop_get_ipv4_dhcp_vendor_class_identifier (NMDevice *self, NMSettingIP4Config *s_ip4) +{ + gs_free char *config_data_prop = NULL; + gs_free char *to_free = NULL; + const char *conn_prop; + GBytes *bytes = NULL; + const char *bin; + gsize len; + + conn_prop = nm_setting_ip4_config_get_dhcp_vendor_class_identifier (s_ip4); + + if (!conn_prop) { + /* set in NetworkManager.conf ? */ + config_data_prop = nm_config_data_get_connection_default ( + NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("ipv4.dhcp-vendor-class-identifier"), + self); + + if ( config_data_prop + && nm_utils_validate_dhcp4_vendor_class_id (config_data_prop, NULL)) + conn_prop = config_data_prop; + } + + if (conn_prop) { + bin = nm_utils_buf_utf8safe_unescape (conn_prop, + NM_UTILS_STR_UTF8_SAFE_FLAG_NONE, + &len, + (gpointer *) &to_free); + if (to_free) + bytes = g_bytes_new_take (g_steal_pointer (&to_free), len); + else + bytes = g_bytes_new (bin, len); + } + + return bytes; +} + +static NMSettingIP6ConfigPrivacy +_prop_get_ipv6_ip6_privacy (NMDevice *self) +{ + NMSettingIP6ConfigPrivacy ip6_privacy; + NMConnection *connection; + + g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + + /* 1.) First look at the per-connection setting. If it is not -1 (unknown), + * use it. */ + connection = nm_device_get_applied_connection (self); + if (connection) { + NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); + + if (s_ip6) { + ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)); + ip6_privacy = _ip6_privacy_clamp (ip6_privacy); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; + } + } + + /* 2.) use the default value from the configuration. */ + ip6_privacy = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("ipv6.ip6-privacy"), + self, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; + + if (!nm_device_get_ip_ifindex (self)) + return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + + /* 3.) No valid default-value configured. Fallback to reading sysctl. + * + * Instead of reading static config files in /etc, just read the current sysctl value. + * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves + * the "default" entry untouched. */ + ip6_privacy = nm_platform_sysctl_get_int32 (nm_device_get_platform (self), + NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/default/use_tempaddr"), + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + return _ip6_privacy_clamp (ip6_privacy); +} + +static const char * +_prop_get_x_cloned_mac_address (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_addr) +{ + NMSetting *setting; + const char *addr = NULL; + + nm_assert (out_addr && !*out_addr); + + setting = nm_connection_get_setting (connection, + is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); + if (setting) { + addr = is_wifi + ? nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) setting) + : nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) setting); + } + + if (!addr) { + gs_free char *a = NULL; + + a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + is_wifi + ? NM_CON_DEFAULT ("wifi.cloned-mac-address") + : NM_CON_DEFAULT ("ethernet.cloned-mac-address"), + self); + + addr = NM_CLONED_MAC_PRESERVE; + + if (!a) { + if (is_wifi) { + NMSettingMacRandomization v; + + /* for backward compatibility, read the deprecated wifi.mac-address-randomization setting. */ + a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + NM_CON_DEFAULT ("wifi.mac-address-randomization"), + self); + v = _nm_utils_ascii_str_to_int64 (a, 10, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT, + NM_SETTING_MAC_RANDOMIZATION_ALWAYS, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT); + if (v == NM_SETTING_MAC_RANDOMIZATION_ALWAYS) + addr = NM_CLONED_MAC_RANDOM; + } + } else if ( NM_CLONED_MAC_IS_SPECIAL (a) + || nm_utils_hwaddr_valid (a, ETH_ALEN)) + addr = *out_addr = g_steal_pointer (&a); + } + + return addr; +} + +static const char * +_prop_get_x_generate_mac_address_mask (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_value) +{ + NMSetting *setting; + const char *value = NULL; + char *a; + + nm_assert (out_value && !*out_value); + + setting = nm_connection_get_setting (connection, + is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); + if (setting) { + value = is_wifi + ? nm_setting_wireless_get_generate_mac_address_mask ((NMSettingWireless *) setting) + : nm_setting_wired_get_generate_mac_address_mask ((NMSettingWired *) setting); + if (value) + return value; + } + + a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + is_wifi + ? NM_CON_DEFAULT ("wifi.generate-mac-address-mask") + : NM_CON_DEFAULT ("ethernet.generate-mac-address-mask"), + self); + if (!a) + return NULL; + *out_value = a; + return a; +} + +/*****************************************************************************/ + static void _ethtool_features_reset (NMDevice *self, NMPlatform *platform, @@ -1424,7 +2496,7 @@ nm_device_sys_iface_state_set (NMDevice *self, _LOGT (LOGD_DEVICE, "sys-iface-state: %s -> %s", _sys_iface_state_to_str (priv->sys_iface_state), _sys_iface_state_to_str (sys_iface_state)); - priv->sys_iface_state = sys_iface_state; + priv->sys_iface_state_ = sys_iface_state; } /* this function only sets a flag, no immediate actions are initiated. @@ -1507,9 +2579,9 @@ init_ip_config_dns_priority (NMDevice *self, NMIPConfig *config) const char *property; int priority; - property = (nm_ip_config_get_addr_family (config) == AF_INET) - ? NM_CON_DEFAULT ("ipv4.dns-priority") - : NM_CON_DEFAULT ("ipv6.dns-priority"); + property = (nm_ip_config_get_addr_family (config) == AF_INET) + ? NM_CON_DEFAULT ("ipv4.dns-priority") + : NM_CON_DEFAULT ("ipv6.dns-priority"); priority = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, property, @@ -1671,92 +2743,6 @@ _add_capabilities (NMDevice *self, NMDeviceCapabilities capabilities) /*****************************************************************************/ -static const char * -_get_stable_id (NMDevice *self, - NMConnection *connection, - NMUtilsStableType *out_stable_type) -{ - NMDevicePrivate *priv; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert (NM_IS_CONNECTION (connection)); - nm_assert (out_stable_type); - - priv = NM_DEVICE_GET_PRIVATE (self); - - /* we cache the generated stable ID for the time of an activation. - * - * The reason is, that we don't want the stable-id to change as long - * as the device is active. - * - * Especially with ${RANDOM} stable-id we want to generate *one* configuration - * for each activation. */ - if (G_UNLIKELY (!priv->current_stable_id)) { - gs_free char *default_id = NULL; - gs_free char *generated = NULL; - NMUtilsStableType stable_type; - NMSettingConnection *s_con; - gboolean hwaddr_is_fake; - const char *hwaddr; - const char *stable_id; - const char *uuid; - - s_con = nm_connection_get_setting_connection (connection); - - stable_id = nm_setting_connection_get_stable_id (s_con); - - if (!stable_id) { - default_id = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.stable-id"), - self); - stable_id = default_id; - } - - uuid = nm_connection_get_uuid (connection); - - /* the cloned-mac-address may be generated based on the stable-id. - * Thus, at this point, we can only use the permanent MAC address - * as seed. */ - hwaddr = nm_device_get_permanent_hw_address_full (self, TRUE, &hwaddr_is_fake); - - stable_type = nm_utils_stable_id_parse (stable_id, - nm_device_get_ip_iface (self), - !hwaddr_is_fake ? hwaddr : NULL, - nm_utils_boot_id_str (), - uuid, - &generated); - - /* current_stable_id_type is a bitfield! */ - priv->current_stable_id_type = stable_type; - nm_assert (stable_type <= (NMUtilsStableType) 0x3); - nm_assert (stable_type + (NMUtilsStableType) 1 > (NMUtilsStableType) 0); - nm_assert (priv->current_stable_id_type == stable_type); - - if (stable_type == NM_UTILS_STABLE_TYPE_UUID) - priv->current_stable_id = g_strdup (uuid); - else if (stable_type == NM_UTILS_STABLE_TYPE_STABLE_ID) - priv->current_stable_id = g_strdup (stable_id); - else if (stable_type == NM_UTILS_STABLE_TYPE_GENERATED) - priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_generated_complete (generated)); - else { - nm_assert (stable_type == NM_UTILS_STABLE_TYPE_RANDOM); - priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_random ()); - } - _LOGT (LOGD_DEVICE, - "stable-id: type=%d, \"%s\"" - "%s%s%s", - (int) priv->current_stable_id_type, - priv->current_stable_id, - NM_PRINT_FMT_QUOTED (stable_type == NM_UTILS_STABLE_TYPE_GENERATED, " from \"", generated, "\"", "")); - } - - nm_assert (priv->current_stable_id); - *out_stable_type = priv->current_stable_id_type; - return priv->current_stable_id; -} - -/*****************************************************************************/ - static NM_UTILS_LOOKUP_STR_DEFINE (_ip_state_to_string, NMDeviceIPState, NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"), @@ -1905,7 +2891,7 @@ _dev_l3_register_l3cds_set_one (NMDevice *self, l3cd_type, default_route_metric_penalty_get (self, AF_INET), default_route_metric_penalty_get (self, AF_INET6), - get_ipv4_dad_timeout (self), + _prop_get_ipv4_dad_timeout (self), _dev_l3_get_merge_flags (self, l3cd_type))) changed = TRUE; @@ -1939,7 +2925,7 @@ _dev_l3_register_l3cds (NMDevice *self, if (!is_external) { default_route_penalty_4 = default_route_metric_penalty_get (self, AF_INET); default_route_penalty_6 = default_route_metric_penalty_get (self, AF_INET6); - acd_timeout_msec = get_ipv4_dad_timeout (self); + acd_timeout_msec = _prop_get_ipv4_dad_timeout (self); } changed = FALSE; @@ -2935,141 +3921,6 @@ out: return nm_utils_ip_route_metric_normalize (addr_family, route_metric); } -static NMSettingConnectionMdns -_get_mdns (NMDevice *self) -{ - NMConnection *connection; - NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; - - g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_MDNS_DEFAULT); - - connection = nm_device_get_applied_connection (self); - if (connection) - mdns = nm_setting_connection_get_mdns (nm_connection_get_setting_connection (connection)); - if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) - return mdns; - - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.mdns"), - self, - NM_SETTING_CONNECTION_MDNS_NO, - NM_SETTING_CONNECTION_MDNS_YES, - NM_SETTING_CONNECTION_MDNS_DEFAULT); -} - -static NMSettingConnectionLlmnr -_get_llmnr (NMDevice *self) -{ - NMConnection *connection; - NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; - - g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_LLMNR_DEFAULT); - - connection = nm_device_get_applied_connection (self); - if (connection) - llmnr = nm_setting_connection_get_llmnr (nm_connection_get_setting_connection (connection)); - if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) - return llmnr; - - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.llmnr"), - self, - NM_SETTING_CONNECTION_LLMNR_NO, - NM_SETTING_CONNECTION_LLMNR_YES, - NM_SETTING_CONNECTION_LLMNR_DEFAULT); -} - -static guint32 -_get_route_table (NMDevice *self, - int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceClass *klass; - NMConnection *connection; - NMSettingIPConfig *s_ip; - guint32 route_table = 0; - gboolean is_user_config = TRUE; - NMSettingConnection *s_con; - NMSettingVrf *s_vrf; - - nm_assert_addr_family (addr_family); - - /* the route table setting affects how we sync routes. We shall - * not change it while the device is active, hence, cache it. */ - if (addr_family == AF_INET) { - if (priv->v4_route_table_initialized) - return priv->v4_route_table; - } else { - if (priv->v6_route_table_initialized) - return priv->v6_route_table; - } - - connection = nm_device_get_applied_connection (self); - if (connection) { - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - if (s_ip) - route_table = nm_setting_ip_config_get_route_table (s_ip); - } - if (route_table == 0u) { - gint64 v; - - v = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.route-table") - : NM_CON_DEFAULT ("ipv6.route-table"), - self, - 0, - G_MAXUINT32, - -1); - if (v != -1) { - route_table = v; - is_user_config = FALSE; - } - } - - if ( route_table == 0u - && connection - && (s_con = nm_connection_get_setting_connection (connection)) - && (nm_streq0 (nm_setting_connection_get_slave_type (s_con), NM_SETTING_VRF_SETTING_NAME) - && priv->master - && nm_device_get_device_type (priv->master) == NM_DEVICE_TYPE_VRF)) { - const NMPlatformLnkVrf *lnk; - - lnk = nm_platform_link_get_lnk_vrf (nm_device_get_platform (self), - nm_device_get_ifindex (priv->master), - NULL); - - if (lnk) - route_table = lnk->table; - } - - if ( route_table == 0u - && connection - && (s_vrf = (NMSettingVrf *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF))) { - route_table = nm_setting_vrf_get_table (s_vrf); - } - - klass = NM_DEVICE_GET_CLASS (self); - if (klass->coerce_route_table) - route_table = klass->coerce_route_table (self, addr_family, route_table, is_user_config); - - if (addr_family == AF_INET) { - priv->v4_route_table_initialized = TRUE; - priv->v4_route_table = route_table; - } else { - priv->v6_route_table_initialized = TRUE; - priv->v6_route_table = route_table; - } - - _LOGT (LOGD_DEVICE, - "ipv%c.route-table = %u%s", - addr_family == AF_INET ? '4' : '6', - (guint) (route_table ?: RT_TABLE_MAIN), - route_table != 0u ? "" : " (policy routing not enabled)"); - - return route_table; -} - guint32 nm_device_get_route_table (NMDevice *self, int addr_family) @@ -3078,7 +3929,7 @@ nm_device_get_route_table (NMDevice *self, g_return_val_if_fail (NM_IS_DEVICE (self), RT_TABLE_MAIN); - route_table = _get_route_table (self, addr_family); + route_table = _prop_get_ipvx_route_table (self, addr_family); return route_table ?: (guint32) RT_TABLE_MAIN; } @@ -3091,7 +3942,7 @@ _get_route_table_sync_mode_stateful (NMDevice *self, gboolean all_sync_now; gboolean all_sync_eff; - all_sync_now = _get_route_table (self, addr_family) != 0u; + all_sync_now = _prop_get_ipvx_route_table (self, addr_family) != 0u; if (!all_sync_now) { /* If there's a local route switch to all-sync in order @@ -7251,33 +8102,6 @@ lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec, _notify (self, PROP_LLDP_NEIGHBORS); } -static gboolean -lldp_rx_enabled (NMDevice *self) -{ - NMConnection *connection; - NMSettingConnection *s_con; - NMSettingConnectionLldp lldp = NM_SETTING_CONNECTION_LLDP_DEFAULT; - - connection = nm_device_get_applied_connection (self); - g_return_val_if_fail (connection, FALSE); - - s_con = nm_connection_get_setting_connection (connection); - g_return_val_if_fail (s_con, FALSE); - - lldp = nm_setting_connection_get_lldp (s_con); - if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) { - lldp = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.lldp"), - self, - NM_SETTING_CONNECTION_LLDP_DEFAULT, - NM_SETTING_CONNECTION_LLDP_ENABLE_RX, - NM_SETTING_CONNECTION_LLDP_DEFAULT); - if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) - lldp = NM_SETTING_CONNECTION_LLDP_DISABLE; - } - return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX; -} - static NMPlatformVF * sriov_vf_config_to_platform (NMDevice *self, NMSriovVF *vf, @@ -7568,7 +8392,7 @@ lldp_init (NMDevice *self, gboolean restart) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->ifindex > 0 && lldp_rx_enabled (self)) { + if (priv->ifindex > 0 && _prop_get_connection_lldp (self)) { gs_free_error GError *error = NULL; if (priv->lldp_listener) { @@ -7842,30 +8666,6 @@ nm_device_ip_method_failed (NMDevice *self, } /*****************************************************************************/ -/* IPv4 DAD stuff */ - -static guint -get_ipv4_dad_timeout (NMDevice *self) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip4 = NULL; - int timeout = -1; - - connection = nm_device_get_applied_connection (self); - if (connection) - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4) - timeout = nm_setting_ip_config_get_dad_timeout (s_ip4); - if (timeout >= 0) - return timeout; - - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv4.dad-timeout"), - self, - 0, - NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, - 0); -} static void acd_data_destroy (gpointer ptr) @@ -7982,7 +8782,7 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, AcdCallback cb) } } - timeout = get_ipv4_dad_timeout (self); + timeout = _prop_get_ipv4_dad_timeout (self); hwaddr_arr = nm_platform_link_get_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), &length); @@ -8233,8 +9033,8 @@ ensure_con_ip_config (NMDevice *self, int addr_family) if (IS_IPv4) { nm_ip4_config_merge_setting (NM_IP4_CONFIG (con_ip_config), nm_connection_get_setting_ip4_config (connection), - _get_mdns (self), - _get_llmnr (self), + _prop_get_connection_mdns (self), + _prop_get_connection_llmnr (self), nm_device_get_route_table (self, addr_family), nm_device_get_route_metric (self, addr_family)); } else { @@ -8254,52 +9054,6 @@ ensure_con_ip_config (NMDevice *self, int addr_family) } /*****************************************************************************/ -/* DHCPv4 stuff */ - -static guint32 -get_dhcp_timeout (NMDevice *self, int addr_family) -{ - NMDeviceClass *klass; - NMConnection *connection; - int timeout_i; - guint32 timeout; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert_addr_family (addr_family); - - connection = nm_device_get_applied_connection (self); - - timeout_i = nm_setting_ip_config_get_dhcp_timeout (nm_connection_get_setting_ip_config (connection, addr_family)); - nm_assert (timeout_i >= 0 && timeout_i <= G_MAXINT32); - - timeout = (guint32) timeout_i; - if (timeout) - goto out; - - timeout = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.dhcp-timeout") - : NM_CON_DEFAULT ("ipv6.dhcp-timeout"), - self, - 0, G_MAXINT32, 0); - if (timeout) - goto out; - - klass = NM_DEVICE_GET_CLASS (self); - if (klass->get_dhcp_timeout_for_device) { - timeout = klass->get_dhcp_timeout_for_device (self, addr_family); - if (timeout) - goto out; - } - - timeout = NM_DHCP_TIMEOUT_DEFAULT; - -out: - G_STATIC_ASSERT_EXPR (G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); - nm_assert (timeout > 0); - nm_assert (timeout <= G_MAXINT32); - return timeout; -} static void dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) @@ -8310,7 +9064,6 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) nm_clear_g_source (&priv->dhcp_data_4.grace_id); priv->dhcp_data_4.grace_pending = FALSE; nm_clear_g_free (&priv->dhcp4.pac_url); - nm_clear_g_free (&priv->dhcp4.root_path); if (priv->dhcp_data_4.client) { /* Stop any ongoing DHCP transaction on this device */ @@ -8628,7 +9381,7 @@ dhcp_grace_period_start (NMDevice *self, int addr_family) /* Start a grace period equal to the DHCP timeout multiplied * by a constant factor. */ - timeout = get_dhcp_timeout (self, addr_family); + timeout = _prop_get_ipvx_dhcp_timeout (self, addr_family); if (timeout == NM_DHCP_TIMEOUT_INFINITY) _LOGI (LOGD_DHCP_from_addr_family (addr_family), "DHCPv%c: trying to acquire a new lease", @@ -8720,7 +9473,6 @@ dhcp4_state_changed (NMDhcpClient *client, NMDhcpState state, NMIP4Config *ip4_config, GHashTable *options, - const char *event_id, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); @@ -8755,9 +9507,6 @@ dhcp4_state_changed (NMDhcpClient *client, priv->dhcp4.pac_url = g_strdup (g_hash_table_lookup (options, "wpad")); nm_device_set_proxy_config (self, priv->dhcp4.pac_url); - g_free (priv->dhcp4.root_path); - priv->dhcp4.root_path = g_strdup (g_hash_table_lookup (options, "root_path")); - nm_dhcp_config_set_options (priv->dhcp_data_4.config, options); _notify (self, PROP_DHCP4_CONFIG); @@ -8804,390 +9553,6 @@ dhcp4_state_changed (NMDhcpClient *client, } } -/** - * dhcp_get_iaid: - * @self: the #NMDevice - * @addr_family: the address family - * @connection: the connection - * @out_is_explicit: on return, %TRUE if the user set a valid IAID in - * the connection or in global configuration; %FALSE if the connection - * property was empty and no valid global configuration was provided. - * - * Returns: a IAID value for this device and the given connection. - */ -static guint32 -dhcp_get_iaid (NMDevice *self, - int addr_family, - NMConnection *connection, - gboolean *out_is_explicit) -{ - NMSettingIPConfig *s_ip; - const char *iaid_str; - gs_free char *iaid_str_free = NULL; - guint32 iaid; - const char *iface; - const char *fail_reason; - gboolean is_explicit = TRUE; - - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - iaid_str = nm_setting_ip_config_get_dhcp_iaid (s_ip); - if (!iaid_str) { - iaid_str_free = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.dhcp-iaid") - : NM_CON_DEFAULT ("ipv6.dhcp-iaid"), - self); - iaid_str = iaid_str_free; - if (!iaid_str) { - iaid_str = NM_IAID_IFNAME; - is_explicit = FALSE; - } else if (!_nm_utils_iaid_verify (iaid_str, NULL)) { - _LOGW (LOGD_DEVICE, "invalid global default '%s' for ipv%c.dhcp-iaid", - iaid_str, - nm_utils_addr_family_to_char (addr_family)); - iaid_str = NM_IAID_IFNAME; - is_explicit = FALSE; - } - } - - if (nm_streq0 (iaid_str, NM_IAID_MAC)) { - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self)); - if (!pllink || pllink->l_address.len < 4) { - fail_reason = "invalid link-layer address"; - goto out_fail; - } - - /* @iaid is in native endianness. Use unaligned_read_be32() - * so that the IAID for a given MAC address is the same on - * BE and LE machines. */ - iaid = unaligned_read_be32 (&pllink->l_address.data[pllink->l_address.len - 4]); - goto out_good; - } else if (nm_streq0 (iaid_str, NM_IAID_PERM_MAC)) { - guint8 hwaddr_buf[NM_UTILS_HWADDR_LEN_MAX]; - const char *hwaddr_str; - gsize hwaddr_len; - - hwaddr_str = nm_device_get_permanent_hw_address (self); - if (!hwaddr_str) { - fail_reason = "no permanent link-layer address"; - goto out_fail; - } - - if (!_nm_utils_hwaddr_aton (hwaddr_str, hwaddr_buf, sizeof (hwaddr_buf), &hwaddr_len)) - g_return_val_if_reached (0); - - if (hwaddr_len < 4) { - fail_reason = "invalid link-layer address"; - goto out_fail; - } - - iaid = unaligned_read_be32 (&hwaddr_buf[hwaddr_len - 4]); - goto out_good; - } else if (nm_streq (iaid_str, "stable")) { - nm_auto_free_checksum GChecksum *sum = NULL; - guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - NMUtilsStableType stable_type; - const char *stable_id; - guint32 salted_header; - const guint8 *host_id; - gsize host_id_len; - - stable_id = _get_stable_id (self, connection, &stable_type); - salted_header = htonl (53390459 + stable_type); - nm_utils_host_id_get (&host_id, &host_id_len); - iface = nm_device_get_ip_iface (self); - - sum = g_checksum_new (G_CHECKSUM_SHA1); - g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); - g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1); - g_checksum_update (sum, (const guchar *) iface, strlen (iface) + 1); - g_checksum_update (sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest (sum, digest); - - iaid = unaligned_read_be32 (digest); - goto out_good; - } else if ((iaid = _nm_utils_ascii_str_to_int64 (iaid_str, 10, 0, G_MAXUINT32, -1)) != -1) { - goto out_good; - } else { - iface = nm_device_get_ip_iface (self); - iaid = nm_utils_create_dhcp_iaid (TRUE, - (const guint8 *) iface, - strlen (iface)); - goto out_good; - } - -out_fail: - nm_assert (fail_reason); - _LOGW ( addr_family == AF_INET - ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) - : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), - "ipv%c.dhcp-iaid: failure to generate IAID: %s. Using interface-name based IAID", - nm_utils_addr_family_to_char (addr_family), fail_reason); - is_explicit = FALSE; - iface = nm_device_get_ip_iface (self); - iaid = nm_utils_create_dhcp_iaid (TRUE, - (const guint8 *) iface, - strlen (iface)); -out_good: - _LOGD ( addr_family == AF_INET - ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) - : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), - "ipv%c.dhcp-iaid: using %u (0x%08x) IAID (str: '%s', explicit %d)", - nm_utils_addr_family_to_char (addr_family), iaid, iaid, - iaid_str, is_explicit); - NM_SET_OUT (out_is_explicit, is_explicit); - return iaid; -} - -static NMDhcpHostnameFlags -get_dhcp_hostname_flags (NMDevice *self, int addr_family) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip; - NMDhcpHostnameFlags flags; - gs_free_error GError *error = NULL; - - g_return_val_if_fail (NM_IS_DEVICE (self), NM_DHCP_HOSTNAME_FLAG_NONE); - - connection = nm_device_get_applied_connection (self); - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - g_return_val_if_fail (s_ip, NM_DHCP_HOSTNAME_FLAG_NONE); - - if (!nm_setting_ip_config_get_dhcp_send_hostname (s_ip)) - return NM_DHCP_HOSTNAME_FLAG_NONE; - - flags = nm_setting_ip_config_get_dhcp_hostname_flags (s_ip); - if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) - return flags; - - flags = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.dhcp-hostname-flags") - : NM_CON_DEFAULT ("ipv6.dhcp-hostname-flags"), - self, - 0, NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS, - 0); - - if (!_nm_utils_validate_dhcp_hostname_flags (flags, addr_family, &error)) { - _LOGW (LOGD_DEVICE, "invalid global default value 0x%x for ipv%d.%s: %s", - (guint) flags, - addr_family == AF_INET ? 4 : 6, - NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS, - error->message); - flags = NM_DHCP_HOSTNAME_FLAG_NONE; - } - - if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) - return flags; - - if (addr_family == AF_INET) - return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP4; - else - return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP6; -} - -static const char * -connection_get_mud_url (NMDevice *self, - NMSettingConnection *s_con, - char **out_mud_url) -{ - const char *mud_url; - gs_free char *s = NULL; - - nm_assert (out_mud_url && !*out_mud_url); - - mud_url = nm_setting_connection_get_mud_url (s_con); - - if (mud_url) { - if (nm_streq (mud_url, NM_CONNECTION_MUD_URL_NONE)) - return NULL; - return mud_url; - } - - s = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.mud-url"), - self); - if (s) { - if (nm_streq (s, NM_CONNECTION_MUD_URL_NONE)) - return NULL; - if (nm_sd_http_url_is_valid_https (s)) - return (*out_mud_url = g_steal_pointer (&s)); - } - - return NULL; -} - -static GBytes * -dhcp4_get_client_id (NMDevice *self, - NMConnection *connection, - GBytes *hwaddr) -{ - NMSettingIPConfig *s_ip4; - const char *client_id; - gs_free char *client_id_default = NULL; - guint8 *client_id_buf; - const char *fail_reason; - guint8 hwaddr_bin_buf[NM_UTILS_HWADDR_LEN_MAX]; - const guint8 *hwaddr_bin; - int arp_type; - gsize hwaddr_len; - GBytes *result; - gs_free char *logstr1 = NULL; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - client_id = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)); - - if (!client_id) { - client_id_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv4.dhcp-client-id"), - self); - if (client_id_default && client_id_default[0]) { - /* a non-empty client-id is always valid, see nm_dhcp_utils_client_id_string_to_bytes(). */ - client_id = client_id_default; - } - } - - if (!client_id) { - _LOGD (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: no explicit client-id configured"); - return NULL; - } - - if (nm_streq (client_id, "mac")) { - if (!hwaddr) { - fail_reason = "missing link-layer address"; - goto out_fail; - } - - hwaddr_bin = g_bytes_get_data (hwaddr, &hwaddr_len); - arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); - if (arp_type < 0) { - fail_reason = "unsupported link-layer address"; - goto out_fail; - } - - result = nm_utils_dhcp_client_id_mac (arp_type, hwaddr_bin, hwaddr_len); - goto out_good; - } - - if (nm_streq (client_id, "perm-mac")) { - const char *hwaddr_str; - - hwaddr_str = nm_device_get_permanent_hw_address (self); - if (!hwaddr_str) { - fail_reason = "missing permanent link-layer address"; - goto out_fail; - } - - if (!_nm_utils_hwaddr_aton (hwaddr_str, hwaddr_bin_buf, sizeof (hwaddr_bin_buf), &hwaddr_len)) - g_return_val_if_reached (NULL); - - arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); - if (arp_type < 0) { - fail_reason = "unsupported permanent link-layer address"; - goto out_fail; - } - - result = nm_utils_dhcp_client_id_mac (arp_type, hwaddr_bin_buf, hwaddr_len); - goto out_good; - } - - if (nm_streq (client_id, "duid")) { - guint32 iaid = dhcp_get_iaid (self, AF_INET, connection, NULL); - - result = nm_utils_dhcp_client_id_systemd_node_specific (iaid); - goto out_good; - } - - if (nm_streq (client_id, "stable")) { - nm_auto_free_checksum GChecksum *sum = NULL; - guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - NMUtilsStableType stable_type; - const char *stable_id; - guint32 salted_header; - const guint8 *host_id; - gsize host_id_len; - - stable_id = _get_stable_id (self, connection, &stable_type); - salted_header = htonl (2011610591 + stable_type); - nm_utils_host_id_get (&host_id, &host_id_len); - - sum = g_checksum_new (G_CHECKSUM_SHA1); - g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); - g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1); - g_checksum_update (sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest (sum, digest); - - client_id_buf = g_malloc (1 + 15); - client_id_buf[0] = 0; - memcpy (&client_id_buf[1], digest, 15); - result = g_bytes_new_take (client_id_buf, 1 + 15); - goto out_good; - } - - result = nm_dhcp_utils_client_id_string_to_bytes (client_id); - goto out_good; - -out_fail: - nm_assert (fail_reason); - _LOGW (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: failure to generate client id (%s). Use random client id", - fail_reason); - client_id_buf = g_malloc (1 + 15); - client_id_buf[0] = 0; - nm_utils_random_bytes (&client_id_buf[1], 15); - result = g_bytes_new_take (client_id_buf, 1 + 15); - -out_good: - nm_assert (result); - _LOGD (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: use \"%s\" client ID: %s", - client_id, - (logstr1 = nm_dhcp_utils_duid_to_string (result))); - return result; -} - -static GBytes * -dhcp4_get_vendor_class_identifier (NMDevice *self, NMSettingIP4Config *s_ip4) -{ - gs_free char *config_data_prop = NULL; - gs_free char *to_free = NULL; - const char *conn_prop; - GBytes *bytes = NULL; - const char *bin; - gsize len; - - conn_prop = nm_setting_ip4_config_get_dhcp_vendor_class_identifier (s_ip4); - - if (!conn_prop) { - /* set in NetworkManager.conf ? */ - config_data_prop = nm_config_data_get_connection_default ( - NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv4.dhcp-vendor-class-identifier"), - self); - - if ( config_data_prop - && nm_utils_validate_dhcp4_vendor_class_id (config_data_prop, NULL)) - conn_prop = config_data_prop; - } - - if (conn_prop) { - bin = nm_utils_buf_utf8safe_unescape (conn_prop, - NM_UTILS_STR_UTF8_SAFE_FLAG_NONE, - &len, - (gpointer *) &to_free); - if (to_free) - bytes = g_bytes_new_take (g_steal_pointer (&to_free), len); - else - bytes = g_bytes_new (bin, len); - } - - return bytes; -} - static NMActStageReturn dhcp4_start (NMDevice *self) { @@ -9222,9 +9587,8 @@ dhcp4_start (NMDevice *self) bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast); } - client_id = dhcp4_get_client_id (self, connection, hwaddr); - vendor_class_identifier - = dhcp4_get_vendor_class_identifier (self, NM_SETTING_IP4_CONFIG (s_ip4)); + client_id = _prop_get_ipv4_dhcp_client_id (self, connection, hwaddr); + vendor_class_identifier = _prop_get_ipv4_dhcp_vendor_class_identifier (self, NM_SETTING_IP4_CONFIG (s_ip4)); reject_servers = nm_setting_ip_config_get_dhcp_reject_servers (s_ip4, NULL); g_warn_if_fail (priv->dhcp_data_4.client == NULL); @@ -9240,10 +9604,10 @@ dhcp4_start (NMDevice *self) nm_setting_ip_config_get_dhcp_send_hostname (s_ip4), nm_setting_ip_config_get_dhcp_hostname (s_ip4), nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)), - get_dhcp_hostname_flags (self, AF_INET), - connection_get_mud_url (self, s_con, &mud_url_free), + _prop_get_ipvx_dhcp_hostname_flags (self, AF_INET), + _prop_get_connection_mud_url (self, s_con, &mud_url_free), client_id, - get_dhcp_timeout (self, AF_INET), + _prop_get_ipvx_dhcp_timeout (self, AF_INET), priv->dhcp_anycast_address, NULL, vendor_class_identifier, @@ -9564,11 +9928,11 @@ dhcp6_state_changed (NMDhcpClient *client, NMDhcpState state, NMIP6Config *ip6_config, GHashTable *options, - const char *event_id, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gs_free char *event_id = NULL; g_return_if_fail (nm_dhcp_client_get_addr_family (client) == AF_INET6); g_return_if_fail (!ip6_config || NM_IS_IP6_CONFIG (ip6_config)); @@ -9584,6 +9948,9 @@ dhcp6_state_changed (NMDhcpClient *client, * changed event for each of them. Use the event ID to merge IPv6 * addresses from the same transaction into a single configuration. */ + + event_id = nm_dhcp_utils_get_dhcp6_event_id (options); + if ( ip6_config && event_id && priv->dhcp6.event_id @@ -9667,320 +10034,6 @@ dhcp6_prefix_delegated (NMDhcpClient *client, /*****************************************************************************/ -/* RFC 3315 defines the epoch for the DUID-LLT time field on Jan 1st 2000. */ -#define EPOCH_DATETIME_200001010000 946684800 - -static GBytes * -generate_duid_llt (int arp_type, - const guint8 *hwaddr, - gsize hwaddr_len, - gint64 time) -{ - guint8 *arr; - const guint16 duid_type = htons (1); - const guint16 hw_type = htons (arp_type); - const guint32 duid_time = htonl (NM_MAX (0, time - EPOCH_DATETIME_200001010000)); - - if (!nm_utils_arp_type_get_hwaddr_relevant_part (arp_type, &hwaddr, &hwaddr_len)) - nm_assert_not_reached (); - - arr = g_new (guint8, 2 + 2 + 4 + hwaddr_len); - - memcpy (&arr[0], &duid_type, 2); - memcpy (&arr[2], &hw_type, 2); - memcpy (&arr[4], &duid_time, 4); - memcpy (&arr[8], hwaddr, hwaddr_len); - - return g_bytes_new_take (arr, 2 + 2 + 4 + hwaddr_len); -} - -static GBytes * -generate_duid_ll (int arp_type, - const guint8 *hwaddr, - gsize hwaddr_len) -{ - guint8 *arr; - const guint16 duid_type = htons (3); - const guint16 hw_type = htons (arp_type); - - if (!nm_utils_arp_type_get_hwaddr_relevant_part (arp_type, &hwaddr, &hwaddr_len)) - nm_assert_not_reached (); - - arr = g_new (guint8, 2 + 2 + hwaddr_len); - - memcpy (&arr[0], &duid_type, 2); - memcpy (&arr[2], &hw_type, 2); - memcpy (&arr[4], hwaddr, hwaddr_len); - - return g_bytes_new_take (arr, 2 + 2 + hwaddr_len); -} - -static GBytes * -generate_duid_uuid (const NMUuid *uuid) -{ - const guint16 duid_type = htons (4); - guint8 *duid_buffer; - - nm_assert (uuid); - - /* Generate a DHCP Unique Identifier for DHCPv6 using the - * DUID-UUID method (see RFC 6355 section 4). Format is: - * - * u16: type (DUID-UUID = 4) - * u8[16]: UUID bytes - */ - G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); - G_STATIC_ASSERT_EXPR (sizeof (*uuid) == 16); - duid_buffer = g_malloc (18); - memcpy (&duid_buffer[0], &duid_type, 2); - memcpy (&duid_buffer[2], uuid, 16); - return g_bytes_new_take (duid_buffer, 18); -} - -static GBytes * -generate_duid_from_machine_id (void) -{ - static GBytes *volatile global_duid = NULL; - GBytes *p; - -again: - p = g_atomic_pointer_get (&global_duid); - if (G_UNLIKELY (!p)) { - nm_auto_free_checksum GChecksum *sum = NULL; - const NMUuid *machine_id; - union { - guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256]; - NMUuid uuid; - } digest; - - machine_id = nm_utils_machine_id_bin (); - - /* Hash the machine ID so it's not leaked to the network */ - sum = g_checksum_new (G_CHECKSUM_SHA256); - g_checksum_update (sum, (const guchar *) machine_id, sizeof (*machine_id)); - nm_utils_checksum_get_digest (sum, digest.sha256); - - G_STATIC_ASSERT_EXPR (sizeof (digest.sha256) > sizeof (digest.uuid)); - p = generate_duid_uuid (&digest.uuid); - - if (!g_atomic_pointer_compare_and_exchange (&global_duid, NULL, p)) { - g_bytes_unref (p); - goto again; - } - } - - return g_bytes_ref (p); -} - -static GBytes * -dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboolean *out_enforce) -{ - NMSettingIPConfig *s_ip6; - const char *duid; - gs_free char *duid_default = NULL; - const char *duid_error; - GBytes *duid_out; - gboolean duid_enforce = TRUE; - gs_free char *logstr1 = NULL; - const guint8 *hwaddr_bin; - gsize hwaddr_len; - int arp_type; - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - duid = nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6)); - - if (!duid) { - duid_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv6.dhcp-duid"), - self); - duid = duid_default; - if (!duid) - duid = "lease"; - } - - if (nm_streq (duid, "lease")) { - duid_enforce = FALSE; - duid_out = generate_duid_from_machine_id (); - goto out_good; - } - - if (!_nm_utils_dhcp_duid_valid (duid, &duid_out)) { - duid_error = "invalid duid"; - goto out_fail; - } - - if (duid_out) - goto out_good; - - if (NM_IN_STRSET (duid, "ll", "llt")) { - if (!hwaddr) { - duid_error = "missing link-layer address"; - goto out_fail; - } - - hwaddr_bin = g_bytes_get_data (hwaddr, &hwaddr_len); - arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); - if (arp_type < 0) { - duid_error = "unsupported link-layer address"; - goto out_fail; - } - - if (nm_streq (duid, "ll")) - duid_out = generate_duid_ll (arp_type, hwaddr_bin, hwaddr_len); - else { - duid_out = generate_duid_llt (arp_type, hwaddr_bin, hwaddr_len, - nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NSEC_PER_SEC); - } - - goto out_good; - } - - if (NM_IN_STRSET (duid, "stable-ll", "stable-llt", "stable-uuid")) { - /* preferably, we would salt the checksum differently for each @duid type. We missed - * to do that initially, so most types use the DEFAULT_SALT. - * - * Implementations that are added later, should use a distinct salt instead, - * like "stable-ll"/"stable-llt" with ARPHRD_INFINIBAND below. */ - const guint32 DEFAULT_SALT = 670531087u; - nm_auto_free_checksum GChecksum *sum = NULL; - NMUtilsStableType stable_type; - const char *stable_id = NULL; - guint32 salted_header; - const guint8 *host_id; - gsize host_id_len; - union { - guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256]; - guint8 hwaddr_eth[ETH_ALEN]; - guint8 hwaddr_infiniband[INFINIBAND_ALEN]; - NMUuid uuid; - struct _nm_packed { - guint8 hwaddr[ETH_ALEN]; - guint32 timestamp; - } llt_eth; - struct _nm_packed { - guint8 hwaddr[INFINIBAND_ALEN]; - guint32 timestamp; - } llt_infiniband; - } digest; - - stable_id = _get_stable_id (self, connection, &stable_type); - - if (NM_IN_STRSET (duid, "stable-ll", "stable-llt")) { - /* for stable LL/LLT DUIDs, we still need a hardware address to detect - * the arp-type. Alternatively, we would be able to detect it based on - * other means (e.g. NMDevice type), but instead require the hardware - * address to be present. This is at least consistent with the "ll"/"llt" - * modes above. */ - if (!hwaddr) { - duid_error = "missing link-layer address"; - goto out_fail; - } - if ((arp_type = nm_utils_arp_type_detect_from_hwaddrlen (g_bytes_get_size (hwaddr))) < 0) { - duid_error = "unsupported link-layer address"; - goto out_fail; - } - - if (arp_type == ARPHRD_ETHER) - salted_header = DEFAULT_SALT; - else { - nm_assert (arp_type == ARPHRD_INFINIBAND); - salted_header = 0x42492CEFu + ((guint32) arp_type); - } - } else { - salted_header = DEFAULT_SALT; - arp_type = -1; - } - - salted_header = htonl (salted_header + ((guint32) stable_type)); - - nm_utils_host_id_get (&host_id, &host_id_len); - - sum = g_checksum_new (G_CHECKSUM_SHA256); - g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); - g_checksum_update (sum, (const guchar *) stable_id, -1); - g_checksum_update (sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest (sum, digest.sha256); - - G_STATIC_ASSERT_EXPR (sizeof (digest) == sizeof (digest.sha256)); - - if (nm_streq (duid, "stable-ll")) { - switch (arp_type) { - case ARPHRD_ETHER: - duid_out = generate_duid_ll (arp_type, digest.hwaddr_eth, sizeof (digest.hwaddr_eth)); - break; - case ARPHRD_INFINIBAND: - duid_out = generate_duid_ll (arp_type, digest.hwaddr_infiniband, sizeof (digest.hwaddr_infiniband)); - break; - default: - g_return_val_if_reached (NULL); - } - } else if (nm_streq (duid, "stable-llt")) { - gint64 time; - guint32 timestamp; - -#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3) - - /* We want a variable time between the host_id timestamp and three years - * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll - * subtract it from the host_id timestamp. - */ - time = nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NSEC_PER_SEC; - - /* don't use too old timestamps. They cannot be expressed in DUID-LLT and - * would all be truncated to zero. */ - time = NM_MAX (time, EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS); - - switch (arp_type) { - case ARPHRD_ETHER: - timestamp = unaligned_read_be32 (&digest.llt_eth.timestamp); - time -= timestamp % EPOCH_DATETIME_THREE_YEARS; - duid_out = generate_duid_llt (arp_type, digest.llt_eth.hwaddr, sizeof (digest.llt_eth.hwaddr), time); - break; - case ARPHRD_INFINIBAND: - timestamp = unaligned_read_be32 (&digest.llt_infiniband.timestamp); - time -= timestamp % EPOCH_DATETIME_THREE_YEARS; - duid_out = generate_duid_llt (arp_type, digest.llt_infiniband.hwaddr, sizeof (digest.llt_infiniband.hwaddr), time); - break; - default: - g_return_val_if_reached (NULL); - } - } else { - nm_assert (nm_streq (duid, "stable-uuid")); - duid_out = generate_duid_uuid (&digest.uuid); - } - - goto out_good; - } - - g_return_val_if_reached (NULL); - -out_fail: - nm_assert (!duid_out && duid_error); - { - NMUuid uuid; - - _LOGW (LOGD_IP6 | LOGD_DHCP6, - "ipv6.dhcp-duid: failure to generate %s DUID: %s. Fallback to random DUID-UUID.", - duid, duid_error); - - nm_utils_random_bytes (&uuid, sizeof (uuid)); - duid_out = generate_duid_uuid (&uuid); - } - -out_good: - nm_assert (duid_out); - _LOGD (LOGD_IP6 | LOGD_DHCP6, - "ipv6.dhcp-duid: generate %s DUID '%s' (%s)", - duid, - (logstr1 = nm_dhcp_utils_duid_to_string (duid_out)), - duid_enforce ? "enforcing" : "prefer lease"); - - NM_SET_OUT (out_enforce, duid_enforce); - return duid_out; -} - -/*****************************************************************************/ - static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) { @@ -10019,8 +10072,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) if (pllink) hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address); - iaid = dhcp_get_iaid (self, AF_INET6, connection, &iaid_explicit); - duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid); + iaid = _prop_get_ipvx_dhcp_iaid (self, AF_INET6, connection, &iaid_explicit); + duid = _prop_get_ipv6_dhcp_duid (self, connection, hwaddr, &enforce_duid); priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), nm_device_get_multi_index (self), @@ -10032,13 +10085,13 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) nm_device_get_route_metric (self, AF_INET6), nm_setting_ip_config_get_dhcp_send_hostname (s_ip6), nm_setting_ip_config_get_dhcp_hostname (s_ip6), - get_dhcp_hostname_flags (self, AF_INET6), - connection_get_mud_url (self, s_con, &mud_url_free), + _prop_get_ipvx_dhcp_hostname_flags (self, AF_INET6), + _prop_get_connection_mud_url (self, s_con, &mud_url_free), duid, enforce_duid, iaid, iaid_explicit, - get_dhcp_timeout (self, AF_INET6), + _prop_get_ipvx_dhcp_timeout (self, AF_INET6), priv->dhcp_anycast_address, (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)), @@ -10307,7 +10360,7 @@ check_and_add_ipv6ll_addr (NMDevice *self) NMUtilsStableType stable_type; const char *stable_id; - stable_id = _get_stable_id (self, connection, &stable_type); + stable_id = _prop_get_connection_stable_id (self, connection, &stable_type); if (!nm_utils_ipv6_addr_set_stable_privacy (stable_type, &lladdr, nm_device_get_iface (self), @@ -10963,28 +11016,6 @@ ndisc_node_type (NMDevice *self) return NM_NDISC_NODE_TYPE_HOST; } -static gint32 -get_ra_timeout (NMDevice *self) -{ - NMConnection *connection; - gint32 timeout; - - G_STATIC_ASSERT_EXPR (NM_RA_TIMEOUT_DEFAULT == 0); - G_STATIC_ASSERT_EXPR (NM_RA_TIMEOUT_INFINITY == G_MAXINT32); - - connection = nm_device_get_applied_connection (self); - - timeout = nm_setting_ip6_config_get_ra_timeout (NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection))); - nm_assert (timeout >= 0); - if (timeout) - return timeout; - - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv6.ra-timeout"), - self, - 0, G_MAXINT32, 0); -} - static gboolean addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) { @@ -11007,7 +11038,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection)); g_assert (s_ip6); - stable_id = _get_stable_id (self, connection, &stable_type); + stable_id = _prop_get_connection_stable_id (self, connection, &stable_type); priv->ndisc = nm_lndp_ndisc_new (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), nm_device_get_ip_iface (self), @@ -11015,7 +11046,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) stable_id, nm_setting_ip6_config_get_addr_gen_mode (s_ip6), ndisc_node_type (self), - get_ra_timeout (self), + _prop_get_ipv6_ra_timeout (self), &error); if (!priv->ndisc) { _LOGE (LOGD_IP6, "addrconf6: failed to start neighbor discovery: %s", error->message); @@ -11165,67 +11196,6 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) /*****************************************************************************/ -static NMSettingIP6ConfigPrivacy -_ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) -{ - switch (use_tempaddr) { - case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - return use_tempaddr; - default: - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - } -} - -static NMSettingIP6ConfigPrivacy -_ip6_privacy_get (NMDevice *self) -{ - NMSettingIP6ConfigPrivacy ip6_privacy; - NMConnection *connection; - - g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - - /* 1.) First look at the per-connection setting. If it is not -1 (unknown), - * use it. */ - connection = nm_device_get_applied_connection (self); - if (connection) { - NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); - - if (s_ip6) { - ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)); - ip6_privacy = _ip6_privacy_clamp (ip6_privacy); - if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) - return ip6_privacy; - } - } - - /* 2.) use the default value from the configuration. */ - ip6_privacy = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv6.ip6-privacy"), - self, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) - return ip6_privacy; - - if (!nm_device_get_ip_ifindex (self)) - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - - /* 3.) No valid default-value configured. Fallback to reading sysctl. - * - * Instead of reading static config files in /etc, just read the current sysctl value. - * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves - * the "default" entry untouched. */ - ip6_privacy = nm_platform_sysctl_get_int32 (nm_device_get_platform (self), - NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/default/use_tempaddr"), - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - return _ip6_privacy_clamp (ip6_privacy); -} - -/*****************************************************************************/ - static gboolean ip_requires_slaves (NMDevice *self, int addr_family) { @@ -11424,7 +11394,7 @@ act_stage3_ip_config_start (NMDevice *self, nm_device_get_ip_ifindex (self), NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - ip6_privacy = _ip6_privacy_get (self); + ip6_privacy = _prop_get_ipv6_ip6_privacy (self); if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { @@ -12553,8 +12523,8 @@ nm_device_reactivate_ip4_config (NMDevice *self, priv->con_ip_config_4 = nm_device_ip4_config_new (self); nm_ip4_config_merge_setting (priv->con_ip_config_4, s_ip4_new, - _get_mdns (self), - _get_llmnr (self), + _prop_get_connection_mdns (self), + _prop_get_connection_llmnr (self), nm_device_get_route_table (self, AF_INET), nm_device_get_route_metric (self, AF_INET)); @@ -16220,7 +16190,7 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, g_strdup ("--uuid")); g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection))); - stable_id = _get_stable_id (self, connection, &stable_type); + stable_id = _prop_get_connection_stable_id (self, connection, &stable_type); if (stable_type != NM_UTILS_STABLE_TYPE_UUID) { g_ptr_array_add (argv, g_strdup ("--stable-id")); g_ptr_array_add (argv, g_strdup_printf ("%d %s", (int) stable_type, stable_id)); @@ -17193,86 +17163,6 @@ notify_and_out: _notify (self, PROP_PERM_HW_ADDRESS); } -static const char * -_get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_addr) -{ - NMSetting *setting; - const char *addr = NULL; - - nm_assert (out_addr && !*out_addr); - - setting = nm_connection_get_setting (connection, - is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); - if (setting) { - addr = is_wifi - ? nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) setting) - : nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) setting); - } - - if (!addr) { - gs_free char *a = NULL; - - a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - is_wifi - ? NM_CON_DEFAULT ("wifi.cloned-mac-address") - : NM_CON_DEFAULT ("ethernet.cloned-mac-address"), - self); - - addr = NM_CLONED_MAC_PRESERVE; - - if (!a) { - if (is_wifi) { - NMSettingMacRandomization v; - - /* for backward compatibility, read the deprecated wifi.mac-address-randomization setting. */ - a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("wifi.mac-address-randomization"), - self); - v = _nm_utils_ascii_str_to_int64 (a, 10, - NM_SETTING_MAC_RANDOMIZATION_DEFAULT, - NM_SETTING_MAC_RANDOMIZATION_ALWAYS, - NM_SETTING_MAC_RANDOMIZATION_DEFAULT); - if (v == NM_SETTING_MAC_RANDOMIZATION_ALWAYS) - addr = NM_CLONED_MAC_RANDOM; - } - } else if ( NM_CLONED_MAC_IS_SPECIAL (a) - || nm_utils_hwaddr_valid (a, ETH_ALEN)) - addr = *out_addr = g_steal_pointer (&a); - } - - return addr; -} - -static const char * -_get_generate_mac_address_mask_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_value) -{ - NMSetting *setting; - const char *value = NULL; - char *a; - - nm_assert (out_value && !*out_value); - - setting = nm_connection_get_setting (connection, - is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); - if (setting) { - value = is_wifi - ? nm_setting_wireless_get_generate_mac_address_mask ((NMSettingWireless *) setting) - : nm_setting_wired_get_generate_mac_address_mask ((NMSettingWired *) setting); - if (value) - return value; - } - - a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - is_wifi - ? NM_CON_DEFAULT ("wifi.generate-mac-address-mask") - : NM_CON_DEFAULT ("ethernet.generate-mac-address-mask"), - self); - if (!a) - return NULL; - *out_value = a; - return a; -} - gboolean nm_device_hw_addr_is_explict (NMDevice *self) { @@ -17513,7 +17403,7 @@ _hw_addr_get_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi, if (!connection) g_return_val_if_reached (FALSE); - addr = addr_setting = _get_cloned_mac_address_setting (self, connection, is_wifi, &addr_setting_free); + addr = addr_setting = _prop_get_x_cloned_mac_address (self, connection, is_wifi, &addr_setting_free); if (nm_streq (addr, NM_CLONED_MAC_PRESERVE)) { /* "preserve" means to reset the initial MAC address. */ @@ -17552,9 +17442,10 @@ _hw_addr_get_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi, goto out_no_action; } hw_addr_generated = nm_utils_hw_addr_gen_random_eth (nm_device_get_initial_hw_address (self), - _get_generate_mac_address_mask_setting (self, connection, - is_wifi, - &generate_mac_address_mask_tmp)); + _prop_get_x_generate_mac_address_mask (self, + connection, + is_wifi, + &generate_mac_address_mask_tmp)); if (!hw_addr_generated) { g_set_error (error, NM_DEVICE_ERROR, @@ -17575,11 +17466,11 @@ _hw_addr_get_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi, goto out_no_action; } - stable_id = _get_stable_id (self, connection, &stable_type); + stable_id = _prop_get_connection_stable_id (self, connection, &stable_type); hw_addr_generated = nm_utils_hw_addr_gen_stable_eth (stable_type, stable_id, nm_device_get_ip_iface (self), nm_device_get_initial_hw_address (self), - _get_generate_mac_address_mask_setting (self, connection, is_wifi, &generate_mac_address_mask_tmp)); + _prop_get_x_generate_mac_address_mask (self, connection, is_wifi, &generate_mac_address_mask_tmp)); if (!hw_addr_generated) { g_set_error (error, NM_DEVICE_ERROR, @@ -18201,7 +18092,7 @@ nm_device_init (NMDevice *self) priv->unmanaged_mask = priv->unmanaged_flags; priv->available_connections = g_hash_table_new_full (nm_direct_hash, NULL, g_object_unref, NULL); priv->ip6_saved_properties = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_free); - priv->sys_iface_state = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; + priv->sys_iface_state_ = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; priv->v4_commit_first_time = TRUE; priv->v6_commit_first_time = TRUE; diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 36cae7a3aa..d9ac0022f8 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -16,7 +16,7 @@ #include "nm-rfkill-manager.h" #include "NetworkManagerUtils.h" -typedef enum { +typedef enum _nm_packed { NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, NM_DEVICE_SYS_IFACE_STATE_ASSUME, NM_DEVICE_SYS_IFACE_STATE_MANAGED, diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index b02ff93426..9f937ac13e 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -480,15 +480,8 @@ nm_dhcp_client_set_state (NMDhcpClient *self, } } - if ( priv->addr_family == AF_INET6 - && NM_IN_SET (new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - char *start, *iaid; - - iaid = g_hash_table_lookup (options, "iaid"); - start = g_hash_table_lookup (options, "life_starts"); - if (iaid && start) - event_id = g_strdup_printf ("%s|%s", iaid, start); - } + if (priv->addr_family == AF_INET6) + event_id = nm_dhcp_utils_get_dhcp6_event_id (options); _LOGI ("state changed %s -> %s%s%s%s", state_to_string (priv->state), @@ -500,8 +493,7 @@ nm_dhcp_client_set_state (NMDhcpClient *self, signals[SIGNAL_STATE_CHANGED], 0, new_state, ip_config, - options, - event_id); + options); } static gboolean @@ -1319,7 +1311,11 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class) G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_HASH_TABLE, G_TYPE_STRING); + G_TYPE_NONE, + 3, + G_TYPE_UINT, + G_TYPE_OBJECT, + G_TYPE_HASH_TABLE); signals[SIGNAL_PREFIX_DELEGATED] = g_signal_new (NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index 5148d641f1..78677d8eec 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -45,6 +45,14 @@ G_DEFINE_TYPE (NMDhcpManager, nm_dhcp_manager, G_TYPE_OBJECT) /*****************************************************************************/ +static void client_state_changed (NMDhcpClient *client, + NMDhcpState state, + GObject *ip_config, + GVariant *options, + NMDhcpManager *self); + +/*****************************************************************************/ + /* default to installed helper, but can be modified for testing */ const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper"; @@ -161,13 +169,6 @@ get_client_for_ifindex (NMDhcpManager *manager, int addr_family, int ifindex) return NULL; } -static void client_state_changed (NMDhcpClient *client, - NMDhcpState state, - GObject *ip_config, - GVariant *options, - const char *event_id, - NMDhcpManager *self); - static void remove_client (NMDhcpManager *self, NMDhcpClient *client) { @@ -192,7 +193,6 @@ client_state_changed (NMDhcpClient *client, NMDhcpState state, GObject *ip_config, GVariant *options, - const char *event_id, NMDhcpManager *self) { if (state >= NM_DHCP_STATE_TIMEOUT) diff --git a/src/dhcp/nm-dhcp-options.c b/src/dhcp/nm-dhcp-options.c index d902c77c8c..6051135cea 100644 --- a/src/dhcp/nm-dhcp-options.c +++ b/src/dhcp/nm-dhcp-options.c @@ -219,9 +219,9 @@ nm_dhcp_option_request_string (const NMDhcpOption *requests, guint option) void nm_dhcp_option_take_option (GHashTable *options, - const NMDhcpOption *requests, - guint option, - char *value) + const NMDhcpOption *requests, + guint option, + char *value) { nm_assert (options); nm_assert (requests); diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 88ced0548e..c4bb7872ce 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -786,3 +786,23 @@ nm_dhcp_utils_get_leasefile_path (int addr_family, *out_leasefile_path = g_steal_pointer (&statedir_path); return FALSE; } + +char * +nm_dhcp_utils_get_dhcp6_event_id (GHashTable *lease) +{ + const char *start; + const char *iaid; + + if (!lease) + return NULL; + + iaid = g_hash_table_lookup (lease, "iaid"); + if (!iaid) + return NULL; + + start = g_hash_table_lookup (lease, "life_starts"); + if (!start) + return NULL; + + return g_strdup_printf ("%s|%s", iaid, start); +} diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index ecb91809be..c773262d80 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -38,5 +38,7 @@ gboolean nm_dhcp_utils_get_leasefile_path (int addr_family, char **nm_dhcp_parse_search_list (guint8 *data, size_t n_data); +char *nm_dhcp_utils_get_dhcp6_event_id (GHashTable *lease); + #endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */ diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 1f976f2c30..3e785c38a5 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -3757,6 +3757,113 @@ nm_utils_dhcp_client_id_systemd_node_specific (guint32 iaid) /*****************************************************************************/ +GBytes * +nm_utils_generate_duid_llt (int arp_type, + const guint8 *hwaddr, + gsize hwaddr_len, + gint64 time) +{ + guint8 *arr; + const guint16 duid_type = htons (1); + const guint16 hw_type = htons (arp_type); + const guint32 duid_time = htonl (NM_MAX (0, time - NM_UTILS_EPOCH_DATETIME_200001010000)); + + if (!nm_utils_arp_type_get_hwaddr_relevant_part (arp_type, &hwaddr, &hwaddr_len)) + nm_assert_not_reached (); + + arr = g_new (guint8, (2u + 2u + 4u) + hwaddr_len); + + memcpy (&arr[0], &duid_type, 2); + memcpy (&arr[2], &hw_type, 2); + memcpy (&arr[4], &duid_time, 4); + memcpy (&arr[8], hwaddr, hwaddr_len); + + return g_bytes_new_take (arr, (2u + 2u + 4u) + hwaddr_len); +} + +GBytes * +nm_utils_generate_duid_ll (int arp_type, + const guint8 *hwaddr, + gsize hwaddr_len) +{ + guint8 *arr; + const guint16 duid_type = htons (3); + const guint16 hw_type = htons (arp_type); + + if (!nm_utils_arp_type_get_hwaddr_relevant_part (arp_type, &hwaddr, &hwaddr_len)) + nm_assert_not_reached (); + + arr = g_new (guint8, (2u + 2u) + hwaddr_len); + + memcpy (&arr[0], &duid_type, 2); + memcpy (&arr[2], &hw_type, 2); + memcpy (&arr[4], hwaddr, hwaddr_len); + + return g_bytes_new_take (arr, (2u + 2u) + hwaddr_len); +} + +GBytes * +nm_utils_generate_duid_uuid (const NMUuid *uuid) +{ + const guint16 duid_type = htons (4); + guint8 *duid_buffer; + + nm_assert (uuid); + + /* Generate a DHCP Unique Identifier for DHCPv6 using the + * DUID-UUID method (see RFC 6355 section 4). Format is: + * + * u16: type (DUID-UUID = 4) + * u8[16]: UUID bytes + */ + G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); + G_STATIC_ASSERT_EXPR (sizeof (*uuid) == 16); + duid_buffer = g_malloc (18); + memcpy (&duid_buffer[0], &duid_type, 2); + memcpy (&duid_buffer[2], uuid, 16); + return g_bytes_new_take (duid_buffer, 18); +} + +GBytes * +nm_utils_generate_duid_from_machine_id (void) +{ + static GBytes *volatile global_duid = NULL; + GBytes *p; + +again: + p = g_atomic_pointer_get (&global_duid); + if (G_UNLIKELY (!p)) { + nm_auto_free_checksum GChecksum *sum = NULL; + const NMUuid *machine_id; + union { + guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256]; + NMUuid uuid; + } digest; + + machine_id = nm_utils_machine_id_bin (); + + /* Hash the machine ID so it's not leaked to the network. + * + * Optimally, we would choose an use case specific seed, but for historic + * reasons we didn't. */ + sum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (sum, (const guchar *) machine_id, sizeof (*machine_id)); + nm_utils_checksum_get_digest (sum, digest.sha256); + + G_STATIC_ASSERT_EXPR (sizeof (digest.sha256) > sizeof (digest.uuid)); + p = nm_utils_generate_duid_uuid (&digest.uuid); + + if (!g_atomic_pointer_compare_and_exchange (&global_duid, NULL, p)) { + g_bytes_unref (p); + goto again; + } + } + + return g_bytes_ref (p); +} + +/*****************************************************************************/ + /** * nm_utils_setpgid: * @unused: unused diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 8b5e69916d..0ac95e285e 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -430,6 +430,26 @@ GBytes *nm_utils_dhcp_client_id_systemd_node_specific (guint32 iaid); /*****************************************************************************/ +/* RFC 3315 defines the epoch for the DUID-LLT time field on Jan 1st 2000. */ +#define NM_UTILS_EPOCH_DATETIME_200001010000 946684800 + +struct _NMUuid; + +GBytes *nm_utils_generate_duid_llt (int arp_type, + const guint8 *hwaddr, + gsize hwaddr_len, + gint64 time); + +GBytes *nm_utils_generate_duid_ll (int arp_type, + const guint8 *hwaddr, + gsize hwaddr_len); + +GBytes *nm_utils_generate_duid_uuid (const struct _NMUuid *uuid); + +GBytes *nm_utils_generate_duid_from_machine_id (void); + +/*****************************************************************************/ + void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len); void nm_utils_setpgid (gpointer unused); diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 5904e8fc0b..0335b7617a 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -95,7 +95,6 @@ dhcp4_state_changed (NMDhcpClient *client, NMDhcpState state, NMIP4Config *ip4_config, GHashTable *options, - const char *event_id, gpointer user_data) { static NMIP4Config *last_config = NULL; diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 69b74c7298..7b5046d253 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -1656,30 +1656,9 @@ nm_ip6_config_find_first_address (const NMIP6Config *self, nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) { - - if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) - continue; - } else { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) - continue; - } - - if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED)) { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) - continue; - } else if ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) - continue; - } else { - if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) - continue; - } - - return addr; + if (nm_platform_ip6_address_match (addr, match_flag)) + return addr; } - return NULL; } diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c index d547b5bd60..bff22c578f 100644 --- a/src/nm-l3-config-data.c +++ b/src/nm-l3-config-data.c @@ -54,6 +54,14 @@ struct _NML3ConfigData { union { struct { + NMDhcpLease *dhcp_lease_6; + NMDhcpLease *dhcp_lease_4; + }; + NMDhcpLease *dhcp_lease_x[2]; + }; + + union { + struct { GArray *nameservers_6; GArray *nameservers_4; }; @@ -472,6 +480,9 @@ nm_l3_config_data_unref (const NML3ConfigData *self) nm_clear_pointer (&mutable->wins, g_array_unref); nm_clear_pointer (&mutable->nis_servers, g_array_unref); + nm_clear_pointer (&mutable->dhcp_lease_4, nm_dhcp_lease_unref); + nm_clear_pointer (&mutable->dhcp_lease_6, nm_dhcp_lease_unref); + nm_clear_pointer (&mutable->nameservers_4, g_array_unref); nm_clear_pointer (&mutable->nameservers_6, g_array_unref); @@ -572,6 +583,8 @@ nm_l3_config_data_lookup_index (const NML3ConfigData *self, NMPObjectType obj_ty const NMDedupMultiHeadEntry * nm_l3_config_data_lookup_objs (const NML3ConfigData *self, NMPObjectType obj_type) { + if (!self) + return NULL; return nm_dedup_multi_index_lookup_head (self->multi_idx, nm_l3_config_data_lookup_index (self, obj_type), NULL); @@ -1324,6 +1337,63 @@ nm_l3_config_data_set_source (NML3ConfigData *self, /*****************************************************************************/ +NMDhcpLease * +nm_l3_config_data_get_dhcp_lease (const NML3ConfigData *self, + int addr_family) +{ + nm_assert (_NM_IS_L3_CONFIG_DATA (self, TRUE)); + + return self->dhcp_lease_x[NM_IS_IPv4 (addr_family)]; +} + +gboolean +nm_l3_config_data_set_dhcp_lease (NML3ConfigData *self, + int addr_family, + NMDhcpLease *lease) +{ + nm_auto_unref_dhcplease NMDhcpLease *lease_old = NULL; + NMDhcpLease **p_lease; + + nm_assert (_NM_IS_L3_CONFIG_DATA (self, FALSE)); + + p_lease = &self->dhcp_lease_x[NM_IS_IPv4 (addr_family)]; + + if (*p_lease == lease) + return FALSE; + + if (lease) + nm_dhcp_lease_ref (lease); + lease_old = *p_lease; + *p_lease = lease; + return TRUE; +} + +gboolean +nm_l3_config_data_set_dhcp_lease_from_options (NML3ConfigData *self, + int addr_family, + GHashTable *options_take) +{ + nm_auto_unref_dhcplease NMDhcpLease *lease = NULL; + nm_auto_unref_dhcplease NMDhcpLease *lease_old = NULL; + NMDhcpLease **p_lease; + + nm_assert (_NM_IS_L3_CONFIG_DATA (self, FALSE)); + + if (options_take) + lease = nm_dhcp_lease_new_from_options (g_steal_pointer (&options_take)); + + p_lease = &self->dhcp_lease_x[NM_IS_IPv4 (addr_family)]; + + if (*p_lease == lease) + return FALSE; + + lease_old = *p_lease; + *p_lease = g_steal_pointer (&lease); + return TRUE; +} + +/*****************************************************************************/ + static int _dedup_multi_index_cmp (const NML3ConfigData *a, const NML3ConfigData *b, @@ -1386,6 +1456,13 @@ nm_l3_config_data_cmp (const NML3ConfigData *a, const NML3ConfigData *b) NM_CMP_RETURN (_garray_inaddr_cmp (a->nameservers_x[IS_IPv4], b->nameservers_x[IS_IPv4], addr_family)); + NM_CMP_RETURN (nm_utils_hashtable_cmp (nm_dhcp_lease_get_options (a->dhcp_lease_x[IS_IPv4]), + nm_dhcp_lease_get_options (b->dhcp_lease_x[IS_IPv4]), + TRUE, + nm_strcmp_with_data, + nm_strcmp_with_data, + NULL)); + NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->domains_x[IS_IPv4], b->domains_x[IS_IPv4])); NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->searches_x[IS_IPv4], b->searches_x[IS_IPv4])); NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->dns_options_x[IS_IPv4], b->dns_options_x[IS_IPv4])); @@ -2177,6 +2254,7 @@ nm_l3_config_data_merge (NML3ConfigData *self, self->mtu = src->mtu; /* self->source does not get merged. */ + /* self->dhcp_lease_x does not get merged. */ } NML3ConfigData * diff --git a/src/nm-l3-config-data.h b/src/nm-l3-config-data.h index 429325626c..2a29fad0df 100644 --- a/src/nm-l3-config-data.h +++ b/src/nm-l3-config-data.h @@ -486,6 +486,17 @@ gboolean nm_l3_config_data_set_dns_priority (NML3ConfigData *self, int addr_family, int dns_priority); +struct _NMDhcpLease *nm_l3_config_data_get_dhcp_lease (const NML3ConfigData *self, + int addr_family); + +gboolean nm_l3_config_data_set_dhcp_lease (NML3ConfigData *self, + int addr_family, + struct _NMDhcpLease *lease); + +gboolean nm_l3_config_data_set_dhcp_lease_from_options (NML3ConfigData *self, + int addr_family, + GHashTable *options_take); + static inline const NMIPAddr * nmtst_l3_config_data_get_best_gateway (const NML3ConfigData *self, int addr_family) diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index 2086cd00e7..5354a5dbbf 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -3018,6 +3018,34 @@ nm_l3cfg_commit_type_unregister (NML3Cfg *self, /*****************************************************************************/ +const NML3ConfigData * +nm_l3cfg_get_combined_l3cd (NML3Cfg *self) +{ + nm_assert (NM_IS_L3CFG (self)); + + return self->priv.p->combined_l3cd; +} + +const NMPObject * +nm_l3cfg_get_best_default_route (NML3Cfg *self, + int addr_family) +{ + nm_assert (NM_IS_L3CFG (self)); + + /* we only consider the combined_l3cd. This is a merge of all the l3cd, and the one + * with which we called nm_l3cfg_platform_commit() the last time. + * + * In the meantime, we might have changed the tracked l3_config_datas, but we didn't + * nm_l3cfg_platform_commit() yet. These changes are ignored for this purpose, until + * the user call nm_l3cfg_platform_commit() to re-commit the changes. */ + if (!self->priv.p->combined_l3cd) + return NULL; + + return nm_l3_config_data_get_best_default_route (self->priv.p->combined_l3cd, addr_family); +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index 4a3bab1111..7f0a9de8fa 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -87,6 +87,28 @@ nm_l3cfg_get_ifname (const NML3Cfg *self) return nmp_object_link_get_ifname (self->priv.pllink); } +static inline const NMPObject * +nm_l3cfg_get_plobj (const NML3Cfg *self) +{ + if (!self) + return NULL; + + nm_assert (NM_IS_L3CFG (self)); + + return self->priv.pllink; +} + +static inline const NMPlatformLink * +nm_l3cfg_get_pllink (const NML3Cfg *self) +{ + if (!self) + return NULL; + + nm_assert (NM_IS_L3CFG (self)); + + return NMP_OBJECT_CAST_LINK (self->priv.pllink); +} + static inline NMNetns * nm_l3cfg_get_netns (const NML3Cfg *self) { @@ -198,4 +220,11 @@ void nm_l3cfg_commit_type_unregister (NML3Cfg *self, /*****************************************************************************/ +const NML3ConfigData *nm_l3cfg_get_combined_l3cd (NML3Cfg *self); + +const NMPObject *nm_l3cfg_get_best_default_route (NML3Cfg *self, + int addr_family); + +/*****************************************************************************/ + #endif /* __NM_L3CFG_H__ */ diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index b8302fea95..c75fb1a947 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3401,6 +3401,38 @@ nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr) } gboolean +nm_platform_ip6_address_match (const NMPlatformIP6Address *addr, + NMPlatformMatchFlags match_flag) +{ + nm_assert (!NM_FLAGS_ANY (match_flag, ~( NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY + | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); + nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); + nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); + + if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) + return FALSE; + } else { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) + return FALSE; + } + + if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED)) { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) + return FALSE; + } else if ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TENTATIVE) + && !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) + return FALSE; + } else { + if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) + return FALSE; + } + + return TRUE; +} + +gboolean nm_platform_ip4_address_add (NMPlatform *self, int ifindex, in_addr_t address, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 53bfcaf486..41b950ea02 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -1668,6 +1668,11 @@ struct _NMPLookup; const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *self, const struct _NMPLookup *lookup); +#define nm_platform_iter_obj_for_each(iter, self, lookup, obj) \ + for (nm_dedup_multi_iter_init ((iter), nm_platform_lookup ((self), (lookup))); \ + nm_platform_dedup_multi_iter_next_obj ((iter), (obj), NMP_OBJECT_TYPE_UNKNOWN); \ + ) + gboolean nm_platform_lookup_predicate_routes_main (const NMPObject *obj, gpointer user_data); gboolean nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel (const NMPObject *obj, @@ -2158,4 +2163,9 @@ void nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, struct _NMDedupMultiIndex *nm_platform_get_multi_idx (NMPlatform *self); +/*****************************************************************************/ + +gboolean nm_platform_ip6_address_match (const NMPlatformIP6Address *addr, + NMPlatformMatchFlags match_flag); + #endif /* __NETWORKMANAGER_PLATFORM_H__ */ |