From 1001dca6983e032042c609223934558cd551190c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 7 Sep 2020 23:36:00 +0200 Subject: [PATCH 01/17] device: remove unused dhcp4.root_path field --- src/devices/nm-device.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 832116bd05..b7a9df1103 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -537,7 +537,6 @@ typedef struct _NMDevicePrivate { /* DHCPv4 tracking */ struct { char * pac_url; - char * root_path; } dhcp4; struct { @@ -8310,7 +8309,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 */ @@ -8755,9 +8753,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); From ff37c961ff1006a40c843ed64129557cb4194fd6 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 8 Sep 2020 17:57:15 +0200 Subject: [PATCH 02/17] shared: fix out of bounds for nm_g_array_append_new() macro Fixes: fb6e9795b7cf ('shared: add nm_g_array_append_new() helper') --- shared/nm-glib-aux/nm-shared-utils.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index aa6169d43b..2f42574d69 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1564,14 +1564,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); \ }) /*****************************************************************************/ From 348ab39f6d14ec42ad4f4c6b6f3038cf9d5bf68c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 7 Sep 2020 18:43:17 +0200 Subject: [PATCH 03/17] shared: add nm_utils_hashtable_{equal,cmp}() helper function --- shared/nm-glib-aux/nm-shared-utils.c | 254 ++++++++++++++++-- shared/nm-glib-aux/nm-shared-utils.h | 20 +- .../nm-glib-aux/tests/test-shared-general.c | 117 ++++++++ 3 files changed, 372 insertions(+), 19 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) - return TRUE; - if (!a || !b) - return FALSE; - if (g_hash_table_size ((GHashTable *) a) != g_hash_table_size ((GHashTable *) b)) - return FALSE; + 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)); - 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)) + /* 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 (!hash_a || !hash_b) + return FALSE; + + size = g_hash_table_size (hash_a); + if (size != g_hash_table_size (hash_b)) + 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 2f42574d69..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); 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 (); } From 2fd53eb509cd3d433f094ec0f5648398be9f9bb4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 10 Sep 2020 13:58:43 +0200 Subject: [PATCH 04/17] core: add NMDhcpLease typedef and simple accessor functions --- src/NetworkManagerUtils.h | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) 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__ */ From 16e59cc37c2e66afb1e638d14e306343ca5b54a4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 7 Sep 2020 18:25:56 +0200 Subject: [PATCH 05/17] l3cfg: support tracking the DHCP lease in NML3ConfigData --- src/dhcp/nm-dhcp-options.c | 6 +-- src/nm-l3-config-data.c | 76 ++++++++++++++++++++++++++++++++++++++ src/nm-l3-config-data.h | 11 ++++++ 3 files changed, 90 insertions(+), 3 deletions(-) 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/nm-l3-config-data.c b/src/nm-l3-config-data.c index d547b5bd60..a060dc78f0 100644 --- a/src/nm-l3-config-data.c +++ b/src/nm-l3-config-data.c @@ -52,6 +52,14 @@ struct _NML3ConfigData { char *nis_domain; + union { + struct { + NMDhcpLease *dhcp_lease_6; + NMDhcpLease *dhcp_lease_4; + }; + NMDhcpLease *dhcp_lease_x[2]; + }; + union { struct { GArray *nameservers_6; @@ -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); @@ -1324,6 +1335,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 +1454,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 +2252,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) From 3b8b683f8aa017642a04c4c446cb76a65ca97170 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 8 Sep 2020 15:07:49 +0200 Subject: [PATCH 06/17] l3cfg: add nm_l3cfg_get_pllink() helper NML3Cfg already keeps track of the current NMPlatformLink object. Allow accessing it directly from an NML3Cfg instance, which saves a cache lookup from NMPlatform. --- src/nm-l3cfg.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index 4a3bab1111..13830073a2 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) { From 6358d10688289ef78693a763c194587c5ac2af43 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 8 Sep 2020 17:05:34 +0200 Subject: [PATCH 07/17] l3cfg: add nm_l3cfg_get_best_default_route() function This is the best default route that we commited the last time (if any). It may not reflect what is currently configured (in NMPlatform) and it may not reflect the latest changes since nm_l3cfg_add_config(). --- src/nm-l3cfg.c | 20 ++++++++++++++++++++ src/nm-l3cfg.h | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index 2086cd00e7..f4862a36ae 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -3018,6 +3018,26 @@ nm_l3cfg_commit_type_unregister (NML3Cfg *self, /*****************************************************************************/ +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 13830073a2..0e92b656b7 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -220,4 +220,9 @@ void nm_l3cfg_commit_type_unregister (NML3Cfg *self, /*****************************************************************************/ +const NMPObject *nm_l3cfg_get_best_default_route (NML3Cfg *self, + int addr_family); + +/*****************************************************************************/ + #endif /* __NM_L3CFG_H__ */ From d16776b5fd97ba9a387e282da985e78ba261130a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 8 Sep 2020 18:25:02 +0200 Subject: [PATCH 08/17] l3cfg: gracefully accept %NULL argument in nm_l3_config_data_lookup_objs() This way we can safely iterate over a %NULL instance with nm_l3_config_data_iter_obj_for_each(). This avoids a NULL check, which in this case seems more annoying than helpful. --- src/nm-l3-config-data.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c index a060dc78f0..bff22c578f 100644 --- a/src/nm-l3-config-data.c +++ b/src/nm-l3-config-data.c @@ -583,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); From b23825f457bc922aea7fd3cf4f8a5fa4ef3ac415 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 8 Sep 2020 18:25:41 +0200 Subject: [PATCH 09/17] l3cfg: add nm_l3cfg_get_combined_l3cd() function --- src/nm-l3cfg.c | 8 ++++++++ src/nm-l3cfg.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index f4862a36ae..5354a5dbbf 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -3018,6 +3018,14 @@ 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) diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index 0e92b656b7..7f0a9de8fa 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -220,6 +220,8 @@ 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); From ed8d7ae26438867dd74dfebe1ffd5caf417f4896 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 10 Sep 2020 12:46:53 +0200 Subject: [PATCH 10/17] core: move nm_utils_generate_duid_from_machine_id() to "nm-core-utils.c" --- src/devices/nm-device.c | 127 ++++------------------------------------ src/nm-core-utils.c | 107 +++++++++++++++++++++++++++++++++ src/nm-core-utils.h | 20 +++++++ 3 files changed, 138 insertions(+), 116 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index b7a9df1103..a063b6b31f 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -9662,111 +9662,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) { @@ -9795,7 +9690,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole if (nm_streq (duid, "lease")) { duid_enforce = FALSE; - duid_out = generate_duid_from_machine_id (); + duid_out = nm_utils_generate_duid_from_machine_id (); goto out_good; } @@ -9821,10 +9716,10 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole } if (nm_streq (duid, "ll")) - duid_out = generate_duid_ll (arp_type, hwaddr_bin, hwaddr_len); + duid_out = nm_utils_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); + 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; @@ -9901,10 +9796,10 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole 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)); + duid_out = nm_utils_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)); + duid_out = nm_utils_generate_duid_ll (arp_type, digest.hwaddr_infiniband, sizeof (digest.hwaddr_infiniband)); break; default: g_return_val_if_reached (NULL); @@ -9923,25 +9818,25 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole /* 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); + 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 = generate_duid_llt (arp_type, digest.llt_eth.hwaddr, sizeof (digest.llt_eth.hwaddr), time); + 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 = generate_duid_llt (arp_type, digest.llt_infiniband.hwaddr, sizeof (digest.llt_infiniband.hwaddr), time); + 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 = generate_duid_uuid (&digest.uuid); + duid_out = nm_utils_generate_duid_uuid (&digest.uuid); } goto out_good; @@ -9959,7 +9854,7 @@ out_fail: duid, duid_error); nm_utils_random_bytes (&uuid, sizeof (uuid)); - duid_out = generate_duid_uuid (&uuid); + duid_out = nm_utils_generate_duid_uuid (&uuid); } out_good: 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); From b6dc2e15d23abe4b6dc2468ca25ee785ee4f0438 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 10 Sep 2020 13:14:37 +0200 Subject: [PATCH 11/17] device/trivial: unify (rename) functions in "nm-device.c" --- src/devices/nm-device.c | 142 ++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index a063b6b31f..e19109336a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -704,7 +704,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); @@ -1506,9 +1506,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,9 +1671,9 @@ _add_capabilities (NMDevice *self, NMDeviceCapabilities capabilities) /*****************************************************************************/ static const char * -_get_stable_id (NMDevice *self, - NMConnection *connection, - NMUtilsStableType *out_stable_type) +_prop_get_connection_stable_id (NMDevice *self, + NMConnection *connection, + NMUtilsStableType *out_stable_type) { NMDevicePrivate *priv; @@ -1904,7 +1904,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; @@ -1938,7 +1938,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,7 +2935,7 @@ out: } static NMSettingConnectionMdns -_get_mdns (NMDevice *self) +_prop_get_connection_mdns (NMDevice *self) { NMConnection *connection; NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; @@ -2957,7 +2957,7 @@ _get_mdns (NMDevice *self) } static NMSettingConnectionLlmnr -_get_llmnr (NMDevice *self) +_prop_get_connection_llmnr (NMDevice *self) { NMConnection *connection; NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; @@ -2979,7 +2979,7 @@ _get_llmnr (NMDevice *self) } static guint32 -_get_route_table (NMDevice *self, +_prop_get_ipvx_route_table (NMDevice *self, int addr_family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -3077,7 +3077,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; } @@ -3090,7 +3090,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,7 +7251,7 @@ lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec, } static gboolean -lldp_rx_enabled (NMDevice *self) +_prop_get_connection_lldp (NMDevice *self) { NMConnection *connection; NMSettingConnection *s_con; @@ -7567,7 +7567,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) { @@ -7844,7 +7844,7 @@ nm_device_ip_method_failed (NMDevice *self, /* IPv4 DAD stuff */ static guint -get_ipv4_dad_timeout (NMDevice *self) +_prop_get_ipv4_dad_timeout (NMDevice *self) { NMConnection *connection; NMSettingIPConfig *s_ip4 = NULL; @@ -7981,7 +7981,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); @@ -8232,8 +8232,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 { @@ -8256,7 +8256,7 @@ ensure_con_ip_config (NMDevice *self, int addr_family) /* DHCPv4 stuff */ static guint32 -get_dhcp_timeout (NMDevice *self, int addr_family) +_prop_get_ipvx_dhcp_timeout (NMDevice *self, int addr_family) { NMDeviceClass *klass; NMConnection *connection; @@ -8626,7 +8626,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", @@ -8800,7 +8800,7 @@ dhcp4_state_changed (NMDhcpClient *client, } /** - * dhcp_get_iaid: + * _prop_get_ipvx_dhcp_iaid: * @self: the #NMDevice * @addr_family: the address family * @connection: the connection @@ -8811,10 +8811,10 @@ dhcp4_state_changed (NMDhcpClient *client, * 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) +_prop_get_ipvx_dhcp_iaid (NMDevice *self, + int addr_family, + NMConnection *connection, + gboolean *out_is_explicit) { NMSettingIPConfig *s_ip; const char *iaid_str; @@ -8890,7 +8890,7 @@ dhcp_get_iaid (NMDevice *self, const guint8 *host_id; gsize host_id_len; - stable_id = _get_stable_id (self, connection, &stable_type); + 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); @@ -8938,7 +8938,7 @@ out_good: } static NMDhcpHostnameFlags -get_dhcp_hostname_flags (NMDevice *self, int addr_family) +_prop_get_ipvx_dhcp_hostname_flags (NMDevice *self, int addr_family) { NMConnection *connection; NMSettingIPConfig *s_ip; @@ -8985,9 +8985,9 @@ get_dhcp_hostname_flags (NMDevice *self, int addr_family) } static const char * -connection_get_mud_url (NMDevice *self, - NMSettingConnection *s_con, - char **out_mud_url) +_prop_get_connection_mud_url (NMDevice *self, + NMSettingConnection *s_con, + char **out_mud_url) { const char *mud_url; gs_free char *s = NULL; @@ -9016,9 +9016,9 @@ connection_get_mud_url (NMDevice *self, } static GBytes * -dhcp4_get_client_id (NMDevice *self, - NMConnection *connection, - GBytes *hwaddr) +_prop_get_ipv4_dhcp_client_id (NMDevice *self, + NMConnection *connection, + GBytes *hwaddr) { NMSettingIPConfig *s_ip4; const char *client_id; @@ -9091,7 +9091,7 @@ dhcp4_get_client_id (NMDevice *self, } if (nm_streq (client_id, "duid")) { - guint32 iaid = dhcp_get_iaid (self, AF_INET, connection, NULL); + 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; @@ -9106,7 +9106,7 @@ dhcp4_get_client_id (NMDevice *self, const guint8 *host_id; gsize host_id_len; - stable_id = _get_stable_id (self, connection, &stable_type); + 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); @@ -9146,7 +9146,7 @@ out_good: } static GBytes * -dhcp4_get_vendor_class_identifier (NMDevice *self, NMSettingIP4Config *s_ip4) +_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; @@ -9217,9 +9217,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); @@ -9235,10 +9234,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, @@ -9663,7 +9662,7 @@ dhcp6_prefix_delegated (NMDhcpClient *client, /*****************************************************************************/ static GBytes * -dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboolean *out_enforce) +_prop_get_ipv6_dhcp_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboolean *out_enforce) { NMSettingIPConfig *s_ip6; const char *duid; @@ -9753,7 +9752,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole } llt_infiniband; } digest; - stable_id = _get_stable_id (self, connection, &stable_type); + 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 @@ -9909,8 +9908,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), @@ -9922,13 +9921,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)), @@ -10197,7 +10196,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), @@ -10854,7 +10853,7 @@ ndisc_node_type (NMDevice *self) } static gint32 -get_ra_timeout (NMDevice *self) +_prop_get_ipv6_ra_timeout (NMDevice *self) { NMConnection *connection; gint32 timeout; @@ -10897,7 +10896,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), @@ -10905,7 +10904,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); @@ -11069,7 +11068,7 @@ _ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) } static NMSettingIP6ConfigPrivacy -_ip6_privacy_get (NMDevice *self) +_prop_get_ipv6_ip6_privacy (NMDevice *self) { NMSettingIP6ConfigPrivacy ip6_privacy; NMConnection *connection; @@ -11314,7 +11313,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)) { @@ -12443,8 +12442,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)); @@ -16110,7 +16109,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)); @@ -17084,7 +17083,7 @@ notify_and_out: } static const char * -_get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_addr) +_prop_get_x_cloned_mac_address (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_addr) { NMSetting *setting; const char *addr = NULL; @@ -17103,9 +17102,9 @@ _get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gbool 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"), + is_wifi + ? NM_CON_DEFAULT ("wifi.cloned-mac-address") + : NM_CON_DEFAULT ("ethernet.cloned-mac-address"), self); addr = NM_CLONED_MAC_PRESERVE; @@ -17134,7 +17133,7 @@ _get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gbool } static const char * -_get_generate_mac_address_mask_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_value) +_prop_get_x_generate_mac_address_mask (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_value) { NMSetting *setting; const char *value = NULL; @@ -17403,7 +17402,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. */ @@ -17442,9 +17441,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, @@ -17465,11 +17465,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, From ee447cbb527eb0acc97827a7d2298f69b1d0791d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 10 Sep 2020 13:20:29 +0200 Subject: [PATCH 12/17] device: mark NMDevicePrivate.sys_iface_state as const It's important to find place in code where are field (state) gets mutated. Make sys_iface_state field const, but add a mutable alias via a union. You can now grep for places that change the field. --- src/devices/nm-device.c | 11 +++++++---- src/devices/nm-device.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index e19109336a..8490ffc95a 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; @@ -1423,7 +1426,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. @@ -18091,7 +18094,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, From 345aeefaf330ced2294bb64adaabf4b9429a3010 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 10 Sep 2020 13:46:10 +0200 Subject: [PATCH 13/17] dhcp: drop "event_id" parameter from NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED signal It is solely computed from the lease information (the GHashTable). No need to pass it along as separate argument in NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, especially since it only applies to IPv6. --- src/devices/nm-device.c | 6 ++++-- src/dhcp/nm-dhcp-client.c | 20 ++++++++------------ src/dhcp/nm-dhcp-manager.c | 16 ++++++++-------- src/dhcp/nm-dhcp-utils.c | 20 ++++++++++++++++++++ src/dhcp/nm-dhcp-utils.h | 2 ++ src/nm-iface-helper.c | 1 - 6 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 8490ffc95a..bbc5328a02 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -8721,7 +8721,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); @@ -9561,11 +9560,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)); @@ -9581,6 +9580,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 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-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-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; From 94fbc7bdba10b9a82aaf5b69ca5911c3e34759dc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 11 Sep 2020 12:33:40 +0200 Subject: [PATCH 14/17] platform: add nm_platform_ip6_address_match() --- src/platform/nm-platform.c | 32 ++++++++++++++++++++++++++++++++ src/platform/nm-platform.h | 5 +++++ 2 files changed, 37 insertions(+) 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 @@ -3400,6 +3400,38 @@ nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr) return &addr->peer_address; } +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, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 53bfcaf486..8fbb703677 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -2158,4 +2158,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__ */ From b6c3211fcc6c8cca242b4fa97a6306aa43cef66e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 11 Sep 2020 12:39:40 +0200 Subject: [PATCH 15/17] core: use nm_platform_ip6_address_match() in nm_ip6_config_find_first_address() --- src/nm-ip6-config.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) 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; } From 3d6fef2d9a1907ae3699b7a18ae5c1a964ce7a9c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 11 Sep 2020 12:53:49 +0200 Subject: [PATCH 16/17] platform: add nm_platform_iter_obj_for_each() macro --- src/platform/nm-platform.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 8fbb703677..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, From 2535b3a5396724ab451daa19ea059c2866b32f9a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 11 Sep 2020 14:50:44 +0200 Subject: [PATCH 17/17] device/trivial: move code around --- src/devices/nm-device.c | 2144 +++++++++++++++++++-------------------- 1 file changed, 1070 insertions(+), 1074 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index bbc5328a02..c1a2bab12b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -871,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, @@ -1673,92 +2743,6 @@ _add_capabilities (NMDevice *self, NMDeviceCapabilities capabilities) /*****************************************************************************/ -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 NM_UTILS_LOOKUP_STR_DEFINE (_ip_state_to_string, NMDeviceIPState, NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"), @@ -2937,141 +3921,6 @@ out: return nm_utils_ip_route_metric_normalize (addr_family, route_metric); } -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; -} - guint32 nm_device_get_route_table (NMDevice *self, int addr_family) @@ -7253,33 +8102,6 @@ lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec, _notify (self, PROP_LLDP_NEIGHBORS); } -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 NMPlatformVF * sriov_vf_config_to_platform (NMDevice *self, NMSriovVF *vf, @@ -7844,30 +8666,6 @@ nm_device_ip_method_failed (NMDevice *self, } /*****************************************************************************/ -/* IPv4 DAD stuff */ - -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 void acd_data_destroy (gpointer ptr) @@ -8256,52 +9054,6 @@ ensure_con_ip_config (NMDevice *self, int addr_family) } /*****************************************************************************/ -/* DHCPv4 stuff */ - -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; -} static void dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) @@ -8801,390 +9553,6 @@ dhcp4_state_changed (NMDhcpClient *client, } } -/** - * _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 NMActStageReturn dhcp4_start (NMDevice *self) { @@ -9666,215 +10034,6 @@ dhcp6_prefix_delegated (NMDhcpClient *client, /*****************************************************************************/ -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 gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) { @@ -10857,28 +11016,6 @@ ndisc_node_type (NMDevice *self) return NM_NDISC_NODE_TYPE_HOST; } -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 gboolean addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) { @@ -11059,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 -_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 gboolean ip_requires_slaves (NMDevice *self, int addr_family) { @@ -17087,86 +17163,6 @@ notify_and_out: _notify (self, PROP_PERM_HW_ADDRESS); } -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; -} - gboolean nm_device_hw_addr_is_explict (NMDevice *self) {