From b3785245071a1d01232070cc81a3a419cc487315 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 15 Jun 2020 17:13:38 +0200 Subject: [PATCH 001/199] release: bump version to 1.27.0 (development) --- configure.ac | 4 ++-- meson.build | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 6e89a61873..acf9e9df6f 100644 --- a/configure.ac +++ b/configure.ac @@ -7,8 +7,8 @@ dnl - add corresponding NM_VERSION_x_y_z macros in dnl "shared/nm-version-macros.h.in" dnl - update number in meson.build m4_define([nm_major_version], [1]) -m4_define([nm_minor_version], [25]) -m4_define([nm_micro_version], [90]) +m4_define([nm_minor_version], [27]) +m4_define([nm_micro_version], [0]) m4_define([nm_version], [nm_major_version.nm_minor_version.nm_micro_version]) diff --git a/meson.build b/meson.build index 03ab071b90..8eed507f08 100644 --- a/meson.build +++ b/meson.build @@ -6,7 +6,7 @@ project( # - add corresponding NM_VERSION_x_y_z macros in # "shared/nm-version-macros.h.in" # - update number in configure.ac - version: '1.25.90', + version: '1.27.0', license: 'GPL2+', default_options: [ 'buildtype=debugoptimized', From 56b15ca0b615a12e06df0e56a921b575c26a0019 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 15 Jun 2020 23:44:24 +0200 Subject: [PATCH 002/199] build: fix detecting use of pregenerated docs in "configure.ac" Without it, we fail to use the pregenerated gtk-doc files. Fixes: 8a78b15c9b29 ('docs: merge branch 'th/nm-settings-manual'') --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index acf9e9df6f..175ee554ed 100644 --- a/configure.ac +++ b/configure.ac @@ -1289,9 +1289,10 @@ if test "$build_docs" != "yes" -a \ -f "$srcdir"/man/nm-settings-keyfile.5 -a \ -f "$srcdir"/man/nm-settings-nmcli.5 -a \ \ - -f "$srcdir"/man/nm-settings.xml -a \ - -f "$srcdir"/man/nm-settings-keyfile.xml -a \ + -f "$srcdir"/man/nm-settings-dbus.xml -a \ -f "$srcdir"/man/nm-settings-ifcfg-rh.xml -a \ + -f "$srcdir"/man/nm-settings-keyfile.xml -a \ + -f "$srcdir"/man/nm-settings-nmcli.xml -a \ \ -f "$srcdir"/docs/api/settings-spec.xml; then use_pregen_docs=yes From 5d0d13f57010b4eadcd547a29ec5a1f88ac07668 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Fri, 29 May 2020 17:53:02 +0200 Subject: [PATCH 003/199] platform: add support for local routes Also update unit tests. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/407 https://bugzilla.redhat.com/show_bug.cgi?id=1821787 --- libnm-core/nm-core-internal.h | 2 +- .../nm-libnm-core-utils.c | 30 +++++++++++++ .../nm-libnm-core-utils.h | 4 ++ libnm-core/nm-setting-ip-config.c | 43 ++++++++++++++++++- libnm-core/nm-setting-ip-config.h | 1 + libnm-core/tests/test-general.c | 5 +++ src/nm-ip4-config.c | 20 ++++++++- src/platform/nm-linux-platform.c | 10 +++-- src/platform/nm-platform.c | 24 ++++++++++- src/platform/nm-platform.h | 40 +++++++++++++++++ src/platform/tests/test-route.c | 4 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 38 +++++++++++++++- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 8 ++++ .../route-test-wired-static-routes | 4 ++ .../route-test-wired-static-routes-legacy | 1 + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 18 +++++++- .../tests/keyfiles/Test_Wired_Connection | 4 +- .../keyfile/tests/test-keyfile-settings.c | 9 +++- 18 files changed, 248 insertions(+), 17 deletions(-) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 6d7661b916..1d67b09408 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -347,7 +347,7 @@ const char **_nm_ip_address_get_attribute_names (const NMIPAddress *addr, gboole void _nm_setting_wired_clear_s390_options (NMSettingWired *setting); -gboolean _nm_ip_route_attribute_validate_all (const NMIPRoute *route); +gboolean _nm_ip_route_attribute_validate_all (const NMIPRoute *route, GError **error); const char **_nm_ip_route_get_attribute_names (const NMIPRoute *route, gboolean sorted, guint *out_length); GHashTable *_nm_ip_route_get_attributes (NMIPRoute *route); diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c index df2f2e7769..8d2ea09cdf 100644 --- a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c +++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c @@ -6,6 +6,8 @@ #include "nm-common-macros.h" +#include + /*****************************************************************************/ gboolean @@ -178,3 +180,31 @@ nm_client_permission_result_to_string (NMClientPermissionResult permission) nm_assert_not_reached (); return NULL; } + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE ( + nm_utils_route_type_by_name, + guint8, + { nm_assert (name); }, + { return RTN_UNSPEC; }, + { "blackhole", RTN_BLACKHOLE }, + { "broadcast", RTN_BROADCAST }, + { "local", RTN_LOCAL }, + { "multicast", RTN_MULTICAST }, + { "nat", RTN_NAT }, + { "prohibit", RTN_PROHIBIT }, + { "throw", RTN_THROW }, + { "unicast", RTN_UNICAST }, + { "unreachable", RTN_UNREACHABLE }, +); + +NM_UTILS_ENUM2STR_DEFINE (nm_utils_route_type2str, guint8, + NM_UTILS_ENUM2STR (RTN_BLACKHOLE, "blackhole"), + NM_UTILS_ENUM2STR (RTN_BROADCAST, "broadcast"), + NM_UTILS_ENUM2STR (RTN_LOCAL, "local"), + NM_UTILS_ENUM2STR (RTN_MULTICAST, "multicast"), + NM_UTILS_ENUM2STR (RTN_NAT, "nat"), + NM_UTILS_ENUM2STR (RTN_PROHIBIT, "prohibit"), + NM_UTILS_ENUM2STR (RTN_THROW, "throw"), + NM_UTILS_ENUM2STR (RTN_UNICAST, "unicast"), + NM_UTILS_ENUM2STR (RTN_UNREACHABLE, "unreachable"), +); diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h index a35a5e15bf..afc214d4f3 100644 --- a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h +++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h @@ -112,4 +112,8 @@ NMClientPermission nm_auth_permission_from_string (const char *str); NMClientPermissionResult nm_client_permission_result_from_string (const char *nm); const char *nm_client_permission_result_to_string (NMClientPermissionResult permission); +guint8 nm_utils_route_type_by_name (const char *name); + +const char *nm_utils_route_type2str (guint8 val, char *buf, gsize len); + #endif /* __NM_LIBNM_SHARED_UTILS_H__ */ diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index 09a3428362..c750e97e31 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -1214,6 +1214,7 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = { NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, .v4 = TRUE, .v6 = TRUE, .str_type = 'a', ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TABLE, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, .v4 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TYPE, G_VARIANT_TYPE_STRING, .v4 = TRUE, .v6 = TRUE, .str_type = 'T', ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), NULL, }; @@ -1339,6 +1340,18 @@ nm_ip_route_attribute_validate (const char *name, } break; } + case 'T': /* route type. */ + if (!NM_IN_SET (nm_utils_route_type_by_name (string), + RTN_UNICAST, + RTN_LOCAL)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("%s is not a valid route type"), + string); + return FALSE; + } + break; default: break; } @@ -1348,22 +1361,48 @@ nm_ip_route_attribute_validate (const char *name, } gboolean -_nm_ip_route_attribute_validate_all (const NMIPRoute *route) +_nm_ip_route_attribute_validate_all (const NMIPRoute *route, GError **error) { GHashTableIter iter; const char *key; GVariant *val; + guint8 u8; g_return_val_if_fail (route, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); if (!route->attributes) return TRUE; g_hash_table_iter_init (&iter, route->attributes); while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { - if (!nm_ip_route_attribute_validate (key, val, route->family, NULL, NULL)) + if (!nm_ip_route_attribute_validate (key, val, route->family, NULL, error)) return FALSE; } + + if ((val = g_hash_table_lookup (route->attributes, + NM_IP_ROUTE_ATTRIBUTE_TYPE))) { + nm_assert (g_variant_is_of_type (val, G_VARIANT_TYPE_STRING)); + u8 = nm_utils_route_type_by_name (g_variant_get_string (val, NULL)); + + if ( u8 == RTN_LOCAL + && route->family == AF_INET + && (val = g_hash_table_lookup (route->attributes, NM_IP_ROUTE_ATTRIBUTE_SCOPE))) { + nm_assert (g_variant_is_of_type (val, G_VARIANT_TYPE_BYTE)); + u8 = g_variant_get_byte (val); + + if (!NM_IN_SET(u8, + RT_SCOPE_HOST, + RT_SCOPE_NOWHERE)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("route scope is invalid")); + return FALSE; + } + } + } + return TRUE; } diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h index ae77480c08..0c655d2604 100644 --- a/libnm-core/nm-setting-ip-config.h +++ b/libnm-core/nm-setting-ip-config.h @@ -164,6 +164,7 @@ gboolean nm_ip_route_attribute_validate (const char *name, #define NM_IP_ROUTE_ATTRIBUTE_SRC "src" #define NM_IP_ROUTE_ATTRIBUTE_TABLE "table" #define NM_IP_ROUTE_ATTRIBUTE_TOS "tos" +#define NM_IP_ROUTE_ATTRIBUTE_TYPE "type" #define NM_IP_ROUTE_ATTRIBUTE_WINDOW "window" /*****************************************************************************/ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index a6fb700715..714dcd4236 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -2020,6 +2020,11 @@ test_setting_ip_route_attributes (void) TEST_ATTR ("src", string, "1.2.3.0/24", AF_INET, FALSE, TRUE); TEST_ATTR ("src", string, "fd01::12", AF_INET6, TRUE, TRUE); + TEST_ATTR ("type", string, "local", AF_INET, TRUE, TRUE); + TEST_ATTR ("type", string, "local", AF_INET6, TRUE, TRUE); + TEST_ATTR ("type", string, "unicast", AF_INET, TRUE, TRUE); + TEST_ATTR ("type", string, "unicast", AF_INET6, TRUE, TRUE); + #undef TEST_ATTR } diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 0feb7b2c3c..62b41478f4 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -860,8 +860,26 @@ _nm_ip_config_merge_route_attributes (int addr_family, (dst) = (dflt); \ } G_STMT_END + if ( (variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TYPE)) + && g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) { + guint8 type; + + type = nm_utils_route_type_by_name (g_variant_get_string (variant, NULL)); + nm_assert (NM_IN_SET (type, + RTN_UNICAST, + RTN_LOCAL)); + + r->type_coerced = nm_platform_route_type_coerce (type); + } else + r->type_coerced = nm_platform_route_type_coerce (RTN_UNICAST); + GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table, UINT32, uint32, 0); - r->table_coerced = nm_platform_route_table_coerce (table ?: (route_table ?: RT_TABLE_MAIN)); + + if ( !table + && r->type_coerced == nm_platform_route_type_coerce (RTN_LOCAL)) + r->table_coerced = nm_platform_route_table_coerce (RT_TABLE_LOCAL); + else + r->table_coerced = nm_platform_route_table_coerce (table ?: (route_table ?: RT_TABLE_MAIN)); if (addr_family == AF_INET) { guint8 scope; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index e2c45c8874..710a6f91f1 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3257,14 +3257,16 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) rtm = nlmsg_data (nlh); /***************************************************************** - * only handle ~normal~ routes. + * only handle ~supported~ routes. *****************************************************************/ if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6)) return NULL; - if (rtm->rtm_type != RTN_UNICAST) - return NULL; + if (!NM_IN_SET (rtm->rtm_type, + RTN_UNICAST, + RTN_LOCAL)) + return NULL; if (nlmsg_parse_arr (nlh, sizeof (struct rtmsg), @@ -4491,7 +4493,7 @@ _nl_msg_new_route (int nlmsg_type, .rtm_scope = is_v4 ? nm_platform_route_scope_inv (obj->ip4_route.scope_inv) : RT_SCOPE_NOWHERE, - .rtm_type = RTN_UNICAST, + .rtm_type = nm_platform_route_type_uncoerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->type_coerced), .rtm_flags = obj->ip_route.r_rtm_flags & ((unsigned) (RTNH_F_ONLINK)), .rtm_dst_len = obj->ip_route.plen, .rtm_src_len = is_v4 diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index c023f43574..c8b8c6e869 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4518,8 +4518,12 @@ _ip_route_scope_inv_get_normalized (const NMPlatformIP4Route *route) * so that the default equals zero (~(RT_SCOPE_NOWHERE)). **/ if (route->scope_inv == 0) { - return nm_platform_route_scope_inv (!route->gateway - ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); + if (route->type_coerced == nm_platform_route_type_coerce (RTN_LOCAL)) + return nm_platform_route_scope_inv (RT_SCOPE_HOST); + else { + return nm_platform_route_scope_inv (!route->gateway + ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); + } } return route->scope_inv; } @@ -6079,6 +6083,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN]; char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; + char str_type[30]; char str_table[30]; char str_scope[30], s_source[50]; char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; @@ -6093,6 +6098,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); g_snprintf (buf, len, + "%s" /* type */ "%s" /* table */ "%s/%d" " via %s" @@ -6110,6 +6116,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsi "%s" /* initrwnd */ "%s" /* mtu */ "", + route->type_coerced ? nm_sprintf_buf (str_type, "type %s ", nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), NULL, 0)) : "", route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_uncoerce (route->table_coerced, FALSE)) : "", s_network, route->plen, @@ -6152,6 +6159,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi char s_pref_src[INET6_ADDRSTRLEN]; char s_src_all[INET6_ADDRSTRLEN + 40]; char s_src[INET6_ADDRSTRLEN]; + char str_type[30]; char str_table[30]; char str_pref[40]; char str_pref2[30]; @@ -6178,6 +6186,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi _to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev)); g_snprintf (buf, len, + "%s" /* type */ "%s" /* table */ "%s/%d" " via %s" @@ -6195,6 +6204,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi "%s" /* mtu */ "%s" /* pref */ "", + route->type_coerced ? nm_sprintf_buf (str_type, "type %s ", nm_utils_route_type2str (nm_platform_route_type_uncoerce (route->type_coerced), NULL, 0)) : "", route->table_coerced ? nm_sprintf_buf (str_table, "table %u ", nm_platform_route_table_uncoerce (route->table_coerced, FALSE)) : "", s_network, route->plen, @@ -7274,6 +7284,7 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: nm_hash_update_vals (h, + obj->type_coerced, nm_platform_route_table_uncoerce (obj->table_coerced, TRUE), nm_utils_ip4_address_clear_host_address (obj->network, obj->plen), obj->plen, @@ -7301,6 +7312,7 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: nm_hash_update_vals (h, + obj->type_coerced, nm_platform_route_table_uncoerce (obj->table_coerced, TRUE), obj->ifindex, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen), @@ -7327,6 +7339,7 @@ nm_platform_ip4_route_hash_update (const NMPlatformIP4Route *obj, NMPlatformIPRo break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: nm_hash_update_vals (h, + obj->type_coerced, obj->table_coerced, obj->ifindex, obj->network, @@ -7369,6 +7382,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route NM_CMP_FIELD (a, b, tos); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { NM_CMP_FIELD (a, b, ifindex); + NM_CMP_FIELD (a, b, type_coerced); NM_CMP_DIRECT (nmp_utils_ip_config_source_round_trip_rtprot (a->rt_source), nmp_utils_ip_config_source_round_trip_rtprot (b->rt_source)); NM_CMP_DIRECT (_ip_route_scope_inv_get_normalized (a), @@ -7392,6 +7406,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: + NM_CMP_FIELD (a, b, type_coerced); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { NM_CMP_DIRECT (nm_platform_route_table_uncoerce (a->table_coerced, TRUE), nm_platform_route_table_uncoerce (b->table_coerced, TRUE)); @@ -7454,6 +7469,7 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: nm_hash_update_vals (h, + obj->type_coerced, nm_platform_route_table_uncoerce (obj->table_coerced, TRUE), *nm_utils_ip6_address_clear_host_address (&a1, &obj->network, obj->plen), obj->plen, @@ -7466,6 +7482,7 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: nm_hash_update_vals (h, + obj->type_coerced, nm_platform_route_table_uncoerce (obj->table_coerced, TRUE), obj->ifindex, *nm_utils_ip6_address_clear_host_address (&a1, &obj->network, obj->plen), @@ -7493,6 +7510,7 @@ nm_platform_ip6_route_hash_update (const NMPlatformIP6Route *obj, NMPlatformIPRo break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: nm_hash_update_vals (h, + obj->type_coerced, obj->table_coerced, obj->ifindex, obj->network, @@ -7537,11 +7555,13 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route NM_CMP_FIELD (a, b, src_plen); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { NM_CMP_FIELD (a, b, ifindex); + NM_CMP_FIELD (a, b, type_coerced); NM_CMP_FIELD_IN6ADDR (a, b, gateway); } break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: + NM_CMP_FIELD (a, b, type_coerced); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { NM_CMP_DIRECT (nm_platform_route_table_uncoerce (a->table_coerced, TRUE), nm_platform_route_table_uncoerce (b->table_coerced, TRUE)); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index aa3551a6d1..3e6ef84cf0 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -468,6 +468,13 @@ typedef union { * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \ guint32 table_coerced; \ \ + /* rtm_type. + * + * This is not the original type, if type_coerced is 0 then + * it means RTN_UNSPEC otherwise the type value is preserved. + * */ \ + guint8 type_coerced; \ + \ /*end*/ typedef struct { @@ -1285,6 +1292,39 @@ _nm_platform_uint8_inv (guint8 scope) return (guint8) ~scope; } +/** + * nm_platform_route_type_coerce: + * @table: the route type, in its original value. + * + * Returns: returns the coerced type, that can be stored in + * NMPlatformIPRoute.type_coerced. + */ +static inline guint8 +nm_platform_route_type_coerce (guint8 type) +{ + switch (type) { + case 0 /* RTN_UNSPEC */: + return 1; + case 1 /* RTN_UNICAST */: + return 0; + default: + return type; + } +} + +/** + * nm_platform_route_type_uncoerce: + * @table: the type table, in its coerced value + * + * Returns: reverts the coerced type in NMPlatformIPRoute.type_coerced + * to the original value as kernel understands it. + */ +static inline guint8 +nm_platform_route_type_uncoerce (guint8 type_coerced) +{ + return nm_platform_route_type_coerce (type_coerced); +} + gboolean nm_platform_get_use_udev (NMPlatform *self); gboolean nm_platform_get_log_with_ptr (NMPlatform *self); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index f074ca69cf..19debfb501 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -328,13 +328,13 @@ test_ip6_route (void) g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, pref_src, 128, in6addr_any, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0)); - accept_signals (route_added, 0, 1); + accept_signals (route_added, 0, 2); _wait_for_ipv6_addr_non_tentative (NM_PLATFORM_GET, 200, ifindex, 1, &pref_src); /* Add route to gateway */ nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway, 128, in6addr_any, in6addr_any, metric, mss); - accept_signal (route_added); + accept_signals (route_added, 0, 3); /* Add route */ g_assert (!nmtstp_ip6_route_get (NM_PLATFORM_GET, ifindex, &network, plen, metric, NULL, 0)); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index d65ae55551..798b833602 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -800,6 +800,7 @@ typedef struct { union { guint8 uint8; guint32 uint32; + const char *str; struct { guint32 uint32; bool lock:1; @@ -815,6 +816,7 @@ typedef struct { enum { /* route attributes */ + PARSE_LINE_ATTR_ROUTE_TYPE, PARSE_LINE_ATTR_ROUTE_TABLE, PARSE_LINE_ATTR_ROUTE_SRC, PARSE_LINE_ATTR_ROUTE_FROM, @@ -844,6 +846,7 @@ enum { #define PARSE_LINE_TYPE_IFNAME 'i' #define PARSE_LINE_TYPE_FLAG 'f' #define PARSE_LINE_TYPE_ROUTE_SCOPE 'S' +#define PARSE_LINE_TYPE_STRING 's' /** * parse_route_line: @@ -875,6 +878,8 @@ parse_route_line (const char *line, GError **error) { static const ParseLineInfo parse_infos[] = { + [PARSE_LINE_ATTR_ROUTE_TYPE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TYPE, + .type = PARSE_LINE_TYPE_STRING, }, [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, .type = PARSE_LINE_TYPE_UINT32, }, [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, @@ -1010,6 +1015,23 @@ parse_route_line (const char *line, } } + p_info = &parse_infos[PARSE_LINE_ATTR_ROUTE_TYPE]; + p_data = &parse_datas[PARSE_LINE_ATTR_ROUTE_TYPE]; + if ( !p_data->has + && NM_IN_STRSET (w, + "local", + "unicast", + "broadcast" + "multicast", + "throw", + "unreachable", + "prohibit", + "blackhole", + "nat")) { + p_data->has = TRUE; + goto parse_line_type_string; + } + /* "to" is also accepted unqualified... (once) */ p_info = &parse_infos[PARSE_LINE_ATTR_ROUTE_TO]; p_data = &parse_datas[PARSE_LINE_ATTR_ROUTE_TO]; @@ -1160,6 +1182,15 @@ parse_line_type_addr_with_prefix: i_words++; goto next; +parse_line_type_string: + s = words[i_words]; + if (!s) + goto err_word_missing_argument; + + p_data->v.str = s; + i_words++; + goto next; + err_word_missing_argument: g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing argument for \"%s\"", w); @@ -1253,13 +1284,18 @@ next: p_info->key, g_variant_new_boolean (TRUE)); break; + case PARSE_LINE_TYPE_STRING: + nm_ip_route_set_attribute (route, + p_info->key, + g_variant_new_string (p_data->v.str)); + break; default: nm_assert_not_reached (); break; } } - nm_assert (_nm_ip_route_attribute_validate_all (route)); + nm_assert (_nm_ip_route_attribute_validate_all (route, NULL)); NM_SET_OUT (out_route, g_steal_pointer (&route)); return 0; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 199e8e4e64..e6526944c7 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -2099,7 +2099,15 @@ get_route_attributes_string (NMIPRoute *route, int family) str = g_string_new (""); + attr = nm_ip_route_get_attribute (route, NM_IP_ROUTE_ATTRIBUTE_TYPE); + if ( attr + && nm_ip_route_attribute_validate (NM_IP_ROUTE_ATTRIBUTE_TYPE, attr, family, NULL, NULL)) + g_string_append_printf (str, "%s ", g_variant_get_string (attr, NULL)); + for (i = 0; i < len; i++) { + if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TYPE)) + continue; + attr = nm_ip_route_get_attribute (route, names[i]); if (!nm_ip_route_attribute_validate (names[i], attr, family, NULL, NULL)) diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index 5d02c62ef3..9c05417ec2 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -13,3 +13,7 @@ NETMASK2=255.255.255.255 GATEWAY2=192.168.1.8 METRIC2=3 OPTIONS2="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 onlink window 30000 initcwnd lock 13 initrwnd 14 scope link" + +ADDRESS3=1.2.3.4 +NETMASK3=255.255.255.255 +OPTIONS3="local scope host" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy index faa247d86a..1fef7e9792 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes-legacy @@ -6,3 +6,4 @@ 43.53.0.0/16 metric 3 via 7.7.7.7 dev eth2 cwnd 14 mtu lock 9000 initrwnd 20 window lock 10000 initcwnd lock 42 src 1.2.3.4 7.7.7.8/32 via (null) metric 18 +local 1.2.3.4 diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index a5025f3b93..40d1bb8c53 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -1323,7 +1323,7 @@ test_read_wired_static_routes (void) g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); /* Routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 3); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 4); ip4_route = nm_setting_ip_config_get_route (s_ip4, 0); g_assert (ip4_route); @@ -1367,6 +1367,13 @@ test_read_wired_static_routes (void) nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, TRUE); nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 253); + ip4_route = nm_setting_ip_config_get_route (s_ip4, 3); + g_assert (ip4_route); + g_assert_cmpstr (nm_ip_route_get_dest (ip4_route), ==, "1.2.3.4"); + g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 32); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_TYPE, "local"); + nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 254); + g_object_unref (connection); } @@ -1402,7 +1409,7 @@ test_read_wired_static_routes_legacy (void) g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); /* Routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 4); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 5); /* Route #1 */ ip4_route = nm_setting_ip_config_get_route (s_ip4, 0); @@ -1443,6 +1450,13 @@ test_read_wired_static_routes_legacy (void) g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, NULL); g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 18); + + /* Route #5 */ + ip4_route = nm_setting_ip_config_get_route (s_ip4, 4); + g_assert (ip4_route != NULL); + g_assert_cmpstr (nm_ip_route_get_dest (ip4_route), ==, "1.2.3.4"); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_TYPE, "local"); + g_object_unref (connection); } diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection index 1e62f4b3ef..f9ccc003df 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection @@ -36,7 +36,9 @@ routes9=1.1.1.9/19,0.0.0.0,0 route10=1.1.1.10/21,,0 routes10=1.1.1.10/20,,0 routes11=1.1.1.11/21,,21 -routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,src=7.7.7.7 +routes11_options=cwnd=10,lock-cwnd=true,mtu=1430,src=7.7.7.7,type=unicast +routes12=1.2.3.4/32 +routes12_options=type=local address30=1.2.3.30/24 addresses30=1.2.3.30/25 addresses31=1.2.3.31/25 diff --git a/src/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/settings/plugins/keyfile/tests/test-keyfile-settings.c index 1a9482e5b6..98820272c1 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -274,7 +274,7 @@ test_read_valid_wired_connection (void) g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "2.3.4.6"); /* IPv4 routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 13); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 14); check_ip_route (s_ip4, 0, "5.6.7.8", 32, NULL, -1); check_ip_route (s_ip4, 1, "1.2.3.0", 24, "2.3.4.8", 99); check_ip_route (s_ip4, 2, "1.1.1.2", 12, NULL, -1); @@ -288,6 +288,7 @@ test_read_valid_wired_connection (void) check_ip_route (s_ip4, 10, "1.1.1.10", 21, NULL, 0); check_ip_route (s_ip4, 11, "1.1.1.10", 20, NULL, 0); check_ip_route (s_ip4, 12, "1.1.1.11", 21, NULL, 21); + check_ip_route (s_ip4, 13, "1.2.3.4", 32, NULL, -1); /* Route attributes */ route = nm_setting_ip_config_get_route (s_ip4, 12); @@ -297,6 +298,12 @@ test_read_valid_wired_connection (void) nmtst_assert_route_attribute_uint32 (route, NM_IP_ROUTE_ATTRIBUTE_MTU, 1430); nmtst_assert_route_attribute_boolean (route, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, TRUE); nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_SRC, "7.7.7.7"); + nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_TYPE, "unicast"); + + route = nm_setting_ip_config_get_route (s_ip4, 13); + g_assert (route); + + nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_TYPE, "local"); s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); From 7781f7843546aeea26ac8a7b67af7707768f1fc0 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Tue, 9 Jun 2020 11:29:42 +0200 Subject: [PATCH 004/199] setting-ip-config: validate route attributes in verify() It's better to verify these route attributes so that the user can be notified early if something is not supported or invalid. The downside is that some incorrect profiles (with invalid route attributes) that previously would work since this commit will not anymore as the incorrect bits don't get ignored but rejected instead. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/407 https://bugzilla.redhat.com/show_bug.cgi?id=1821787 --- libnm-core/nm-setting-ip-config.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index c750e97e31..bc81129177 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -5059,6 +5059,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) /* Validate routes */ for (i = 0; i < priv->routes->len; i++) { + gs_free_error GError *local = NULL; NMIPRoute *route = (NMIPRoute *) priv->routes->pdata[i]; if (nm_ip_route_get_family (route) != NM_SETTING_IP_CONFIG_GET_FAMILY (setting)) { @@ -5070,6 +5071,19 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), NM_SETTING_IP_CONFIG_ROUTES); return FALSE; } + + if (!_nm_ip_route_attribute_validate_all (route, &local)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("invalid attribute: %s"), + local->message); + g_prefix_error (error, + "%s.%s: ", + nm_setting_get_name (setting), + NM_SETTING_IP_CONFIG_ROUTES); + return FALSE; + } } if (priv->routing_rules) { From 3ecfd13dedb1260968e07b49423017e7bf328200 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 18 Jun 2020 08:49:15 +0200 Subject: [PATCH 005/199] cli: fix reference count handling in hotspot error path The connection is automatically unreferenced when the function returns. Fixes: 9c5ea0917d51 ('devices: reuse the hotspot connection if we find appropriate one'): --- clients/cli/devices.c | 1 - 1 file changed, 1 deletion(-) diff --git a/clients/cli/devices.c b/clients/cli/devices.c index e83d3472c3..27f72e7787 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -4192,7 +4192,6 @@ do_device_wifi_hotspot (const NMCCommand *cmd, NmCli *nmc, int argc, const char g_return_if_fail (s_wsec); if (!set_wireless_security_for_hotspot (s_wsec, wifi_mode, caps, password, show_password, &error)) { - g_object_unref (connection); g_string_printf (nmc->return_text, _("Error: Invalid 'password': %s."), error->message); g_clear_error (&error); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; From 92208ebd1facd7b0d5af3e6fd05b918a41479c6b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 18 Jun 2020 08:51:34 +0200 Subject: [PATCH 006/199] libnm-core: fix memory leak in match setting Fixes: 808e83714997 ('all: add "path" property to the match setting') --- libnm-core/nm-setting-match.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libnm-core/nm-setting-match.c b/libnm-core/nm-setting-match.c index 8fb513e545..6071c88290 100644 --- a/libnm-core/nm-setting-match.c +++ b/libnm-core/nm-setting-match.c @@ -796,6 +796,7 @@ finalize (GObject *object) nm_clear_pointer (&self->interface_name, g_array_unref); nm_clear_pointer (&self->kernel_command_line, g_array_unref); nm_clear_pointer (&self->driver, g_array_unref); + nm_clear_pointer (&self->path, g_array_unref); G_OBJECT_CLASS (nm_setting_match_parent_class)->finalize (object); } From e12d32bf5632821341543dae2f90335e277b1dfa Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 18 Jun 2020 17:07:49 +0200 Subject: [PATCH 007/199] supplicant: fix memory leak Fixes: b83f07916a54 ('supplicant: large rework of wpa_supplicant handling') --- src/supplicant/nm-supplicant-interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 6bbeb1ebcd..3dda0fbf25 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -3292,6 +3292,7 @@ dispose (GObject *object) g_clear_object (&priv->supplicant_manager); g_clear_object (&priv->dbus_connection); nm_clear_g_free (&priv->ifname); + nm_clear_g_free (&priv->driver); nm_assert (!priv->net_path); } From 88e8f2829e5f8f3ea78a323e617ae4ca0baa2f02 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 18 Jun 2020 17:25:42 +0200 Subject: [PATCH 008/199] ifcfg-rh: fix memory leak reading tc filters Fixes: 902bbfdb1878 ('ifcfg-rh: add tc support') --- src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 798b833602..1a9df92cee 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -2515,7 +2515,7 @@ make_tc_setting (shvarFile *ifcfg) NMTCTfilter *tfilter = NULL; gs_free char *value_to_free = NULL; const char *value = NULL; - GError *local = NULL; + gs_free_error GError *local = NULL; value = svGetValueStr (ifcfg, numbered_tag (tag, "FILTER", i), &value_to_free); if (!value) From 38d291f2294dd15d9cb128a693d20b34df7046f1 Mon Sep 17 00:00:00 2001 From: Yuri Chornoivan Date: Wed, 17 Jun 2020 14:46:05 +0300 Subject: [PATCH 009/199] po: update Ukrainian (uk) translation https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/543 --- po/uk.po | 1661 +++++++++++++++++++++++++++--------------------------- 1 file changed, 838 insertions(+), 823 deletions(-) diff --git a/po/uk.po b/po/uk.po index 82907a27fc..56d718a3c2 100644 --- a/po/uk.po +++ b/po/uk.po @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/NetworkManager/NetworkMan" "ager/issues\n" -"POT-Creation-Date: 2020-06-11 03:27+0000\n" -"PO-Revision-Date: 2020-06-11 12:34+0300\n" +"POT-Creation-Date: 2020-06-17 03:27+0000\n" +"PO-Revision-Date: 2020-06-17 14:43+0300\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" @@ -169,8 +169,8 @@ msgid "Error: error connecting to system bus: %s" msgstr "Помилка: помилка під час спроби з'єднатися із каналом системи: %s" #: ../clients/cli/common.c:1493 ../clients/cli/connections.c:67 -#: ../clients/cli/connections.c:77 ../clients/cli/devices.c:431 -#: ../clients/cli/devices.c:523 ../clients/cli/devices.c:530 +#: ../clients/cli/connections.c:77 ../clients/cli/devices.c:434 +#: ../clients/cli/devices.c:526 ../clients/cli/devices.c:533 #: ../clients/cli/general.c:31 ../clients/cli/general.c:86 #: ../clients/cli/general.c:91 ../clients/common/nm-client-utils.c:252 #: ../clients/common/nm-client-utils.c:265 @@ -1041,10 +1041,10 @@ msgstr "Помилка: «connection show»: %s" msgid "Activate connection details" msgstr "Активувати параметри з'єднання" -#: ../clients/cli/connections.c:1572 ../clients/cli/devices.c:1498 -#: ../clients/cli/devices.c:1512 ../clients/cli/devices.c:1526 -#: ../clients/cli/devices.c:1541 ../clients/cli/devices.c:1598 -#: ../clients/cli/devices.c:1700 +#: ../clients/cli/connections.c:1572 ../clients/cli/devices.c:1501 +#: ../clients/cli/devices.c:1515 ../clients/cli/devices.c:1529 +#: ../clients/cli/devices.c:1544 ../clients/cli/devices.c:1601 +#: ../clients/cli/devices.c:1703 msgid "NAME" msgstr "НАЗВА" @@ -1097,17 +1097,17 @@ msgstr "Профілі з'єднань NetworkManager" #: ../clients/cli/connections.c:2178 ../clients/cli/connections.c:2857 #: ../clients/cli/connections.c:2870 ../clients/cli/connections.c:2883 #: ../clients/cli/connections.c:3115 ../clients/cli/connections.c:8986 -#: ../clients/cli/connections.c:9008 ../clients/cli/devices.c:3118 -#: ../clients/cli/devices.c:3131 ../clients/cli/devices.c:3143 -#: ../clients/cli/devices.c:3436 ../clients/cli/devices.c:3447 -#: ../clients/cli/devices.c:3465 ../clients/cli/devices.c:3474 -#: ../clients/cli/devices.c:3495 ../clients/cli/devices.c:3506 -#: ../clients/cli/devices.c:3524 ../clients/cli/devices.c:4044 -#: ../clients/cli/devices.c:4055 ../clients/cli/devices.c:4064 -#: ../clients/cli/devices.c:4078 ../clients/cli/devices.c:4095 -#: ../clients/cli/devices.c:4104 ../clients/cli/devices.c:4251 -#: ../clients/cli/devices.c:4262 ../clients/cli/devices.c:4478 -#: ../clients/cli/devices.c:4650 +#: ../clients/cli/connections.c:9008 ../clients/cli/devices.c:3121 +#: ../clients/cli/devices.c:3134 ../clients/cli/devices.c:3146 +#: ../clients/cli/devices.c:3439 ../clients/cli/devices.c:3450 +#: ../clients/cli/devices.c:3468 ../clients/cli/devices.c:3477 +#: ../clients/cli/devices.c:3498 ../clients/cli/devices.c:3509 +#: ../clients/cli/devices.c:3527 ../clients/cli/devices.c:4047 +#: ../clients/cli/devices.c:4058 ../clients/cli/devices.c:4067 +#: ../clients/cli/devices.c:4081 ../clients/cli/devices.c:4098 +#: ../clients/cli/devices.c:4107 ../clients/cli/devices.c:4254 +#: ../clients/cli/devices.c:4265 ../clients/cli/devices.c:4481 +#: ../clients/cli/devices.c:4653 #, c-format msgid "Error: %s argument is missing." msgstr "Помилка: пропущено аргумент %s." @@ -1120,16 +1120,16 @@ msgstr "Помилка: профілю з'єднання %s не існує." #: ../clients/cli/connections.c:2297 ../clients/cli/connections.c:2843 #: ../clients/cli/connections.c:2913 ../clients/cli/connections.c:8527 #: ../clients/cli/connections.c:8619 ../clients/cli/connections.c:9113 -#: ../clients/cli/devices.c:1798 ../clients/cli/devices.c:2066 -#: ../clients/cli/devices.c:2236 ../clients/cli/devices.c:2349 -#: ../clients/cli/devices.c:2538 ../clients/cli/devices.c:3315 -#: ../clients/cli/devices.c:4215 ../clients/cli/devices.c:4657 +#: ../clients/cli/devices.c:1801 ../clients/cli/devices.c:2069 +#: ../clients/cli/devices.c:2239 ../clients/cli/devices.c:2352 +#: ../clients/cli/devices.c:2541 ../clients/cli/devices.c:3318 +#: ../clients/cli/devices.c:4218 ../clients/cli/devices.c:4660 #: ../clients/cli/general.c:997 #, c-format msgid "Error: %s." msgstr "Помилка: %s." -#: ../clients/cli/connections.c:2389 ../clients/cli/devices.c:4429 +#: ../clients/cli/connections.c:2389 ../clients/cli/devices.c:4432 #, c-format msgid "no active connection on device '%s'" msgstr "на пристрої «%s» немає активних з'єднань" @@ -1199,11 +1199,11 @@ msgid "invalid passwd-file '%s': %s" msgstr "некоректний файл passwd «%s»: %s" #: ../clients/cli/connections.c:2894 ../clients/cli/connections.c:9019 -#: ../clients/cli/devices.c:1756 ../clients/cli/devices.c:1804 -#: ../clients/cli/devices.c:2242 ../clients/cli/devices.c:3178 -#: ../clients/cli/devices.c:3537 ../clients/cli/devices.c:4114 -#: ../clients/cli/devices.c:4268 ../clients/cli/devices.c:4488 -#: ../clients/cli/devices.c:4662 +#: ../clients/cli/devices.c:1759 ../clients/cli/devices.c:1807 +#: ../clients/cli/devices.c:2245 ../clients/cli/devices.c:3181 +#: ../clients/cli/devices.c:3540 ../clients/cli/devices.c:4117 +#: ../clients/cli/devices.c:4271 ../clients/cli/devices.c:4491 +#: ../clients/cli/devices.c:4665 #, c-format msgid "Error: invalid extra argument '%s'." msgstr "Помилка: некоректний додатковий аргумент, «%s»." @@ -1395,9 +1395,9 @@ msgid "Connection '%s' (%s) successfully added.\n" msgstr "Запис з'єднання «%s» (%s) успішно додано.\n" #: ../clients/cli/connections.c:5008 ../clients/cli/connections.c:6934 -#: ../clients/cli/connections.c:6935 ../clients/cli/devices.c:522 -#: ../clients/cli/devices.c:529 ../clients/cli/devices.c:1247 -#: ../clients/cli/general.c:93 ../clients/cli/utils.h:293 +#: ../clients/cli/connections.c:6935 ../clients/cli/devices.c:525 +#: ../clients/cli/devices.c:532 ../clients/cli/devices.c:1250 +#: ../clients/cli/general.c:93 ../clients/cli/utils.h:294 #: ../clients/common/nm-client-utils.c:303 #: ../clients/common/nm-meta-setting-desc.c:871 #: ../clients/common/nm-meta-setting-desc.c:2675 @@ -1405,9 +1405,9 @@ msgid "no" msgstr "ні" #: ../clients/cli/connections.c:5009 ../clients/cli/connections.c:6934 -#: ../clients/cli/connections.c:6935 ../clients/cli/devices.c:521 -#: ../clients/cli/devices.c:528 ../clients/cli/devices.c:1247 -#: ../clients/cli/general.c:92 ../clients/cli/utils.h:293 +#: ../clients/cli/connections.c:6935 ../clients/cli/devices.c:524 +#: ../clients/cli/devices.c:531 ../clients/cli/devices.c:1250 +#: ../clients/cli/general.c:92 ../clients/cli/utils.h:294 #: ../clients/common/nm-client-utils.c:302 #: ../clients/common/nm-meta-setting-desc.c:871 #: ../clients/common/nm-meta-setting-desc.c:2672 @@ -2409,7 +2409,7 @@ msgstr "Інтерфейс: " msgid "Interface(s): " msgstr "Інтерфейси: " -#: ../clients/cli/devices.c:64 ../clients/cli/devices.c:1275 +#: ../clients/cli/devices.c:64 ../clients/cli/devices.c:1278 msgid "(none)" msgstr "(немає)" @@ -2417,21 +2417,21 @@ msgstr "(немає)" msgid "(unknown)" msgstr "(невідомо)" -#: ../clients/cli/devices.c:326 +#: ../clients/cli/devices.c:329 #, c-format msgid " | %s" msgstr "<невидимий> | %s" -#: ../clients/cli/devices.c:327 +#: ../clients/cli/devices.c:330 msgid "" msgstr "<невидимий>" -#: ../clients/cli/devices.c:428 +#: ../clients/cli/devices.c:431 #, c-format msgid "%u Mb/s" msgstr "%u Мб/с" -#: ../clients/cli/devices.c:729 +#: ../clients/cli/devices.c:732 #, c-format msgid "" "Usage: nmcli device { COMMAND | help }\n" @@ -2513,7 +2513,7 @@ msgstr "" " lldp [list [ifname <інтерфейс>]]\n" "\n" -#: ../clients/cli/devices.c:753 +#: ../clients/cli/devices.c:756 #, c-format msgid "" "Usage: nmcli device status { help }\n" @@ -2544,7 +2544,7 @@ msgstr "" "device status».\n" "\n" -#: ../clients/cli/devices.c:768 +#: ../clients/cli/devices.c:771 #, c-format msgid "" "Usage: nmcli device show { ARGUMENTS | help }\n" @@ -2564,7 +2564,7 @@ msgstr "" "аргументу пристрою.\n" "\n" -#: ../clients/cli/devices.c:779 +#: ../clients/cli/devices.c:782 #, c-format msgid "" "Usage: nmcli device connect { ARGUMENTS | help }\n" @@ -2588,7 +2588,7 @@ msgstr "" "з'єднання.\n" "\n" -#: ../clients/cli/devices.c:791 +#: ../clients/cli/devices.c:794 #, c-format msgid "" "Usage: nmcli device reapply { ARGUMENTS | help }\n" @@ -2607,7 +2607,7 @@ msgstr "" "внесено до поточного активного з'єднання з часу його застосування.\n" "\n" -#: ../clients/cli/devices.c:802 +#: ../clients/cli/devices.c:805 #, c-format msgid "" "Usage: nmcli device modify { ARGUMENTS | --help }\n" @@ -2647,7 +2647,7 @@ msgstr "" "nmcli dev mod em1 -ipv4.dns 1\n" "nmcli dev mod em1 -ipv6.addr \"abbe::cafe/56\"\n" -#: ../clients/cli/devices.c:822 +#: ../clients/cli/devices.c:825 #, c-format msgid "" "Usage: nmcli device disconnect { ARGUMENTS | help }\n" @@ -2668,7 +2668,7 @@ msgstr "" "повторну активацію для подальших з'єднань без ручного втручання.\n" "\n" -#: ../clients/cli/devices.c:834 +#: ../clients/cli/devices.c:837 #, c-format msgid "" "Usage: nmcli device delete { ARGUMENTS | help }\n" @@ -2691,7 +2691,7 @@ msgstr "" "за допомогою цієї команди.\n" "\n" -#: ../clients/cli/devices.c:847 +#: ../clients/cli/devices.c:850 #, c-format msgid "" "Usage: nmcli device set { ARGUMENTS | help }\n" @@ -2714,7 +2714,7 @@ msgstr "" "Змінити властивості пристрою.\n" "\n" -#: ../clients/cli/devices.c:860 +#: ../clients/cli/devices.c:863 #, c-format msgid "" "Usage: nmcli device monitor { ARGUMENTS | help }\n" @@ -2736,7 +2736,7 @@ msgstr "" "Стежить за усіма пристроями, якщо не вказано інтерфейс.\n" "\n" -#: ../clients/cli/devices.c:872 +#: ../clients/cli/devices.c:875 #, c-format msgid "" "Usage: nmcli device wifi { ARGUMENTS | help }\n" @@ -2840,7 +2840,7 @@ msgstr "" "скористатися командою «nmcli device wifi list».\n" "\n" -#: ../clients/cli/devices.c:919 +#: ../clients/cli/devices.c:922 #, c-format msgid "" "Usage: nmcli device lldp { ARGUMENTS | help }\n" @@ -2861,90 +2861,90 @@ msgstr "" "певного інтерфейсу.\n" "\n" -#: ../clients/cli/devices.c:1018 +#: ../clients/cli/devices.c:1021 #, c-format msgid "Error: No interface specified." msgstr "Помилка: мало бути вказано інтерфейс." -#: ../clients/cli/devices.c:1041 +#: ../clients/cli/devices.c:1044 #, c-format msgid "Warning: argument '%s' is duplicated.\n" msgstr "Попередження: аргумент «%s» дубльовано.\n" -#: ../clients/cli/devices.c:1044 +#: ../clients/cli/devices.c:1047 #, c-format msgid "Error: Device '%s' not found.\n" msgstr "Помилка: не знайдено пристрій «%s».\n" -#: ../clients/cli/devices.c:1045 +#: ../clients/cli/devices.c:1048 #, c-format msgid "Error: not all devices found." msgstr "Помилка: знайдено не усі пристрої." -#: ../clients/cli/devices.c:1076 +#: ../clients/cli/devices.c:1079 msgid "No interface specified" msgstr "Не вказано інтерфейс" -#: ../clients/cli/devices.c:1095 +#: ../clients/cli/devices.c:1098 #, c-format msgid "Device '%s' not found" msgstr "Не знайдено пристрою «%s»" -#: ../clients/cli/devices.c:1191 +#: ../clients/cli/devices.c:1194 #, c-format msgid "%u MHz" msgstr "%u МГц" -#: ../clients/cli/devices.c:1192 +#: ../clients/cli/devices.c:1195 #, c-format msgid "%u Mbit/s" msgstr "%u МБ/с" -#: ../clients/cli/devices.c:1234 +#: ../clients/cli/devices.c:1237 msgid "Ad-Hoc" msgstr "Ad-Hoc" -#: ../clients/cli/devices.c:1235 +#: ../clients/cli/devices.c:1238 msgid "Infra" msgstr "Інфраструктура" -#: ../clients/cli/devices.c:1236 ../src/devices/wifi/nm-device-olpc-mesh.c:118 +#: ../clients/cli/devices.c:1239 ../src/devices/wifi/nm-device-olpc-mesh.c:118 msgid "Mesh" msgstr "Сітка" -#: ../clients/cli/devices.c:1237 +#: ../clients/cli/devices.c:1240 msgid "N/A" msgstr "н/д" -#: ../clients/cli/devices.c:1432 +#: ../clients/cli/devices.c:1435 msgid "Device details" msgstr "Дані щодо пристрою" -#: ../clients/cli/devices.c:1444 +#: ../clients/cli/devices.c:1447 #, c-format msgid "Error: 'device show': %s" msgstr "Помилка: «device show»: %s" -#: ../clients/cli/devices.c:1773 +#: ../clients/cli/devices.c:1776 msgid "Status of devices" msgstr "Стан пристрою" -#: ../clients/cli/devices.c:1777 +#: ../clients/cli/devices.c:1780 #, c-format msgid "Error: 'device status': %s" msgstr "Помилка: «device status»: %s" -#: ../clients/cli/devices.c:1839 ../clients/cli/general.c:511 +#: ../clients/cli/devices.c:1842 ../clients/cli/general.c:511 #, c-format msgid "Error: Timeout %d sec expired." msgstr "Помилка: перевищено час очікування у %d с." -#: ../clients/cli/devices.c:1911 +#: ../clients/cli/devices.c:1914 #, c-format msgid "Device '%s' successfully activated with '%s'.\n" msgstr "Пристрій «%s» успішно активовано з «%s».\n" -#: ../clients/cli/devices.c:1916 +#: ../clients/cli/devices.c:1919 #, c-format msgid "" "Hint: \"nmcli dev wifi show-password\" shows the Wi-Fi name and password.\n" @@ -2952,153 +2952,153 @@ msgstr "" "Підказка: за допомогою команди «nmcli dev wifi show-password» можна " "переглянути ім'я користувача Wi-Fi і пароль.\n" -#: ../clients/cli/devices.c:1920 +#: ../clients/cli/devices.c:1923 #, c-format msgid "Error: Connection activation failed: (%d) %s.\n" msgstr "Помилка: не вдалося активувати з'єднання: (%d) %s.\n" -#: ../clients/cli/devices.c:1950 +#: ../clients/cli/devices.c:1953 #, c-format msgid "Error: Failed to setup a Wi-Fi hotspot: %s" msgstr "Помилка: не вдалося налаштувати точку доступу Wi-Fi: %s" -#: ../clients/cli/devices.c:1953 +#: ../clients/cli/devices.c:1956 #, c-format msgid "Error: Failed to add/activate new connection: %s" msgstr "Помилка: не вдалося додати або задіяти нове з'єднання: %s" -#: ../clients/cli/devices.c:1956 +#: ../clients/cli/devices.c:1959 #, c-format msgid "Error: Failed to activate connection: %s" msgstr "Помилка: не вдалося задіяти з'єднання: %s" -#: ../clients/cli/devices.c:2021 +#: ../clients/cli/devices.c:2024 #, c-format msgid "Error: Device activation failed: %s" msgstr "Помилка: не вдалося активувати пристрій: %s" -#: ../clients/cli/devices.c:2072 +#: ../clients/cli/devices.c:2075 #, c-format msgid "Error: extra argument not allowed: '%s'." msgstr "Помилка: некоректний додатковий аргумент, «%s»." -#: ../clients/cli/devices.c:2141 ../clients/cli/devices.c:2156 -#: ../clients/cli/devices.c:2397 +#: ../clients/cli/devices.c:2144 ../clients/cli/devices.c:2159 +#: ../clients/cli/devices.c:2400 #, c-format msgid "Device '%s' successfully disconnected.\n" msgstr "Пристрій «%s» успішно від'єднано.\n" -#: ../clients/cli/devices.c:2144 ../clients/cli/devices.c:2470 +#: ../clients/cli/devices.c:2147 ../clients/cli/devices.c:2473 #, c-format msgid "Device '%s' successfully removed.\n" msgstr "Пристрій «%s» успішно вилучено.\n" -#: ../clients/cli/devices.c:2206 ../clients/cli/devices.c:2276 +#: ../clients/cli/devices.c:2209 ../clients/cli/devices.c:2279 #, c-format msgid "Error: Reapplying connection to device '%s' (%s) failed: %s" msgstr "" "Помилка: не вдалося повторно застосувати з'єднання із пристроєм «%s» (%s): %s" -#: ../clients/cli/devices.c:2216 ../clients/cli/devices.c:2285 +#: ../clients/cli/devices.c:2219 ../clients/cli/devices.c:2288 #, c-format msgid "Connection successfully reapplied to device '%s'.\n" msgstr "З'єднання успішно повторно застосовано до пристрою «%s».\n" -#: ../clients/cli/devices.c:2312 +#: ../clients/cli/devices.c:2315 #, c-format msgid "Error: Reading applied connection from device '%s' (%s) failed: %s" msgstr "" "Помилка: спроба читання застосованого з'єднання з пристрою «%s» (%s) зазнала " "невдачі: %s" -#: ../clients/cli/devices.c:2381 +#: ../clients/cli/devices.c:2384 #, c-format msgid "Error: not all devices disconnected." msgstr "Помилка: не усі пристрої від'єднано." -#: ../clients/cli/devices.c:2382 +#: ../clients/cli/devices.c:2385 #, c-format msgid "Error: Device '%s' (%s) disconnecting failed: %s\n" msgstr "Помилка: невдала спроба від'єднання «%s» (%s): %s\n" -#: ../clients/cli/devices.c:2461 +#: ../clients/cli/devices.c:2464 #, c-format msgid "Error: not all devices deleted." msgstr "Помилка: вилучено не усі пристрої." -#: ../clients/cli/devices.c:2462 +#: ../clients/cli/devices.c:2465 #, c-format msgid "Error: Device '%s' (%s) deletion failed: %s\n" msgstr "Помилка: помилка під час спроби вилучення пристрою «%s» (%s): %s\n" -#: ../clients/cli/devices.c:2544 +#: ../clients/cli/devices.c:2547 #, c-format msgid "Error: No property specified." msgstr "Помилка: не вказано властивості." -#: ../clients/cli/devices.c:2560 ../clients/cli/devices.c:2579 +#: ../clients/cli/devices.c:2563 ../clients/cli/devices.c:2582 #: ../clients/cli/general.c:773 ../clients/cli/general.c:786 #, c-format msgid "Error: '%s' argument is missing." msgstr "Помилка: пропущено параметр %s." -#: ../clients/cli/devices.c:2567 +#: ../clients/cli/devices.c:2570 #, c-format msgid "Error: 'managed': %s." msgstr "Помилка: «managed»: %s." -#: ../clients/cli/devices.c:2586 +#: ../clients/cli/devices.c:2589 #, c-format msgid "Error: 'autoconnect': %s." msgstr "Помилка: «autoconnect»: %s." -#: ../clients/cli/devices.c:2595 ../clients/cli/general.c:801 +#: ../clients/cli/devices.c:2598 ../clients/cli/general.c:801 #, c-format msgid "Error: property '%s' is not known." msgstr "Помилка: властивість «%s» є невідомою." -#: ../clients/cli/devices.c:2641 +#: ../clients/cli/devices.c:2644 #, c-format msgid "%s: using connection '%s'\n" msgstr "%s: використовуємо з'єднання «%s»\n" -#: ../clients/cli/devices.c:2667 +#: ../clients/cli/devices.c:2670 #, c-format msgid "%s: device created\n" msgstr "%s: створено запис пристрою\n" -#: ../clients/cli/devices.c:2674 +#: ../clients/cli/devices.c:2677 #, c-format msgid "%s: device removed\n" msgstr "%s: пристрій вилучено\n" -#: ../clients/cli/devices.c:2853 +#: ../clients/cli/devices.c:2856 msgid "Wi-Fi scan list" msgstr "Список сканування Wi-Fi" -#: ../clients/cli/devices.c:2971 ../clients/cli/devices.c:3248 +#: ../clients/cli/devices.c:2974 ../clients/cli/devices.c:3251 #, c-format msgid "Error: Access point with bssid '%s' not found." msgstr "Помилка: не знайдено точки доступу з bssid «%s»." -#: ../clients/cli/devices.c:3171 +#: ../clients/cli/devices.c:3174 #, c-format msgid "Error: 'device wifi': %s" msgstr "Помилка: «device wifi»: %s" -#: ../clients/cli/devices.c:3190 +#: ../clients/cli/devices.c:3193 #, c-format msgid "Error: invalid rescan argument: '%s' not among [auto, no, yes]" msgstr "" "Помилка: некоректний аргумент rescan: «%s» не належить до набору [auto, no, " "yes]" -#: ../clients/cli/devices.c:3229 +#: ../clients/cli/devices.c:3232 #, c-format msgid "Error: Device '%s' not found." msgstr "Помилка: не знайдено пристрій «%s»." -#: ../clients/cli/devices.c:3234 +#: ../clients/cli/devices.c:3237 #, c-format msgid "" "Error: Device '%s' was not recognized as a Wi-Fi device, check " @@ -3107,28 +3107,28 @@ msgstr "" "Помилка: пристрій «%s» не розпізнано як пристрій Wi-Fi, перевірте, чи працює " "додаток Wi-Fi NetworkManager." -#: ../clients/cli/devices.c:3238 ../clients/cli/devices.c:3567 -#: ../clients/cli/devices.c:4156 ../clients/cli/devices.c:4284 -#: ../clients/cli/devices.c:4417 +#: ../clients/cli/devices.c:3241 ../clients/cli/devices.c:3570 +#: ../clients/cli/devices.c:4159 ../clients/cli/devices.c:4287 +#: ../clients/cli/devices.c:4420 #, c-format msgid "Error: Device '%s' is not a Wi-Fi device." msgstr "Помилка: пристрій «%s» не є пристроєм Wi-Fi." -#: ../clients/cli/devices.c:3414 +#: ../clients/cli/devices.c:3417 msgid "SSID or BSSID: " msgstr "SSID або BSSID: " -#: ../clients/cli/devices.c:3419 +#: ../clients/cli/devices.c:3422 #, c-format msgid "Error: SSID or BSSID are missing." msgstr "Помилка: не вистачає SSID або BSSID." -#: ../clients/cli/devices.c:3456 +#: ../clients/cli/devices.c:3459 #, c-format msgid "Error: bssid argument value '%s' is not a valid BSSID." msgstr "Помилка: значення параметра bssid, «%s», не є коректним BSSID." -#: ../clients/cli/devices.c:3486 +#: ../clients/cli/devices.c:3489 #, c-format msgid "" "Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'." @@ -3136,49 +3136,49 @@ msgstr "" "Помилка: значення параметра wep-key-type, «%s», є некоректним, слід " "використовувати «key» або «phrase»." -#: ../clients/cli/devices.c:3513 ../clients/cli/devices.c:3531 +#: ../clients/cli/devices.c:3516 ../clients/cli/devices.c:3534 #, c-format msgid "Error: %s: %s." msgstr "Помилка: %s: %s." -#: ../clients/cli/devices.c:3550 +#: ../clients/cli/devices.c:3553 #, c-format msgid "Error: BSSID to connect to (%s) differs from bssid argument (%s)." msgstr "" "Помилка: BSSID для з'єднання з (%s) відрізняється від параметра bssid (%s)." -#: ../clients/cli/devices.c:3556 +#: ../clients/cli/devices.c:3559 #, c-format msgid "Error: Parameter '%s' is neither SSID nor BSSID." msgstr "Помилка: параметр «%s» не дорівнює ні SSID, ні BSSID." -#: ../clients/cli/devices.c:3569 ../clients/cli/devices.c:4158 -#: ../clients/cli/devices.c:4286 ../clients/cli/devices.c:4522 +#: ../clients/cli/devices.c:3572 ../clients/cli/devices.c:4161 +#: ../clients/cli/devices.c:4289 ../clients/cli/devices.c:4525 #, c-format msgid "Error: No Wi-Fi device found." msgstr "Помилка: не знайдено жодного пристрою Wi-Fi." -#: ../clients/cli/devices.c:3589 +#: ../clients/cli/devices.c:3592 #, c-format msgid "Error: Failed to scan hidden SSID: %s." msgstr "Помилка: неможливо виконати сканування прихованого SSID: %s." -#: ../clients/cli/devices.c:3616 +#: ../clients/cli/devices.c:3619 #, c-format msgid "Error: No network with SSID '%s' found." msgstr "Помилка: не знайдено мережі з SSID «%s»." -#: ../clients/cli/devices.c:3618 +#: ../clients/cli/devices.c:3621 #, c-format msgid "Error: No access point with BSSID '%s' found." msgstr "Помилка: не знайдено точки доступу з BSSID «%s»." -#: ../clients/cli/devices.c:3645 +#: ../clients/cli/devices.c:3648 #, c-format msgid "Error: Connection '%s' exists but properties don't match." msgstr "Помилка: існує з'єднання «%s», але його властивості є невідповідними." -#: ../clients/cli/devices.c:3688 +#: ../clients/cli/devices.c:3691 #, c-format msgid "" "Warning: '%s' should be SSID for hidden APs; but it looks like a BSSID.\n" @@ -3186,76 +3186,76 @@ msgstr "" "Попередження: «%s» має бути SSID для прихованих точок доступу; втім, " "здається, маємо BSSID.\n" -#: ../clients/cli/devices.c:3729 +#: ../clients/cli/devices.c:3732 msgid "Password: " msgstr "Пароль: " -#: ../clients/cli/devices.c:3868 +#: ../clients/cli/devices.c:3871 #, c-format msgid "'%s' is not valid WPA PSK" msgstr "«%s» не є коректним PSK WPA" -#: ../clients/cli/devices.c:3885 +#: ../clients/cli/devices.c:3888 #, c-format msgid "'%s' is not valid WEP key (it should be 5 or 13 ASCII chars)" msgstr "" "«%s» не є коректним ключем WEP (коректний ключ має складатися з 5 або 13 " "символів ASCII)" -#: ../clients/cli/devices.c:3901 +#: ../clients/cli/devices.c:3904 #, c-format msgid "Hotspot password: %s\n" msgstr "Пароль до точки доступу: %s\n" -#: ../clients/cli/devices.c:4069 +#: ../clients/cli/devices.c:4072 #, c-format msgid "Error: ssid is too long." msgstr "Помилка: SSID є надто довгим." -#: ../clients/cli/devices.c:4086 +#: ../clients/cli/devices.c:4089 #, c-format msgid "Error: band argument value '%s' is invalid; use 'a' or 'bg'." msgstr "" "Помилка: значення аргументу «band» «%s» є некоректним; має бути «a» або «bg»." -#: ../clients/cli/devices.c:4137 +#: ../clients/cli/devices.c:4140 #, c-format msgid "Error: channel requires band too." msgstr "Помилка: разом із каналом слід вказати смугу." -#: ../clients/cli/devices.c:4143 +#: ../clients/cli/devices.c:4146 #, c-format msgid "Error: channel '%s' not valid for band '%s'." msgstr "Помилка: не можна використовувати канал «%s» для смуги «%s»." -#: ../clients/cli/devices.c:4170 +#: ../clients/cli/devices.c:4173 #, c-format msgid "Error: Device '%s' supports neither AP nor Ad-Hoc mode." msgstr "" "Помилка: для пристрою «%s» не передбачено ні режиму точки доступу, ні режиму " "Ad-Hoc." -#: ../clients/cli/devices.c:4193 +#: ../clients/cli/devices.c:4196 #, c-format msgid "Error: Invalid 'password': %s." msgstr "Помилка: некоректне значення «password»: %s." -#: ../clients/cli/devices.c:4244 ../clients/cli/devices.c:4469 +#: ../clients/cli/devices.c:4247 ../clients/cli/devices.c:4472 #, c-format msgid "Error: '%s' cannot repeat." msgstr "Помилка: не можна повторювати «%s»." -#: ../clients/cli/devices.c:4375 ../clients/cli/devices.c:4379 -#: ../clients/cli/devices.c:4384 ../clients/cli/devices.c:4387 +#: ../clients/cli/devices.c:4378 ../clients/cli/devices.c:4382 +#: ../clients/cli/devices.c:4387 ../clients/cli/devices.c:4390 #: ../clients/tui/nmt-page-wifi.c:250 msgid "Security" msgstr "Захист" -#: ../clients/cli/devices.c:4375 +#: ../clients/cli/devices.c:4378 msgid "None" msgstr "Немає" -#: ../clients/cli/devices.c:4391 ../clients/common/nm-secret-agent-simple.c:273 +#: ../clients/cli/devices.c:4394 ../clients/common/nm-secret-agent-simple.c:273 #: ../clients/common/nm-secret-agent-simple.c:310 #: ../clients/common/nm-secret-agent-simple.c:333 #: ../clients/common/nm-secret-agent-simple.c:366 @@ -3271,17 +3271,17 @@ msgstr "Немає" msgid "Password" msgstr "Пароль" -#: ../clients/cli/devices.c:4509 +#: ../clients/cli/devices.c:4512 #, c-format msgid "%s" msgstr "%s" #. Main header name -#: ../clients/cli/devices.c:4563 +#: ../clients/cli/devices.c:4566 msgid "Device LLDP neighbors" msgstr "LLDP-сусіди пристрою" -#: ../clients/cli/devices.c:4680 +#: ../clients/cli/devices.c:4683 #, c-format msgid "Error: 'device lldp list': %s" msgstr "Помилка: «device lldp list»: %s" @@ -4198,20 +4198,20 @@ msgstr "Не вдалося створити відгалуження пейдж msgid "Failed to duplicate pager pipe: %s\n" msgstr "Не вдалося здублювати конвеєр пейджера: %s\n" -#: ../clients/cli/utils.h:299 ../clients/common/nm-meta-setting-desc.c:4129 +#: ../clients/cli/utils.h:300 ../clients/common/nm-meta-setting-desc.c:4129 msgid "on" msgstr "увімкн." -#: ../clients/cli/utils.h:299 ../clients/common/nm-meta-setting-desc.c:4130 +#: ../clients/cli/utils.h:300 ../clients/common/nm-meta-setting-desc.c:4130 msgid "off" msgstr "вимкн." -#: ../clients/cli/utils.h:325 +#: ../clients/cli/utils.h:326 #, c-format msgid "%lld (%s)" msgstr "%lld (%s)" -#: ../clients/cli/utils.h:332 +#: ../clients/cli/utils.h:333 #, c-format msgid "%lld - %s" msgstr "%lld — %s" @@ -4287,18 +4287,15 @@ msgstr "невдала спроба з'єднання" #: ../clients/common/nm-client-utils.c:274 #: ../clients/common/nm-client-utils.c:275 #: ../clients/common/nm-client-utils.c:276 -#| msgid "connecting (prepare)" msgid "connecting (externally)" msgstr "з'єднання (ззовні)" #: ../clients/common/nm-client-utils.c:277 -#| msgid "connected (site only)" msgid "connected (externally)" msgstr "з'єднано (ззовні)" #: ../clients/common/nm-client-utils.c:278 #: ../clients/common/nm-client-utils.c:279 -#| msgid "deactivating" msgid "deactivating (externally)" msgstr "деактивація (ззовні)" @@ -4313,7 +4310,7 @@ msgstr "ні (вгадано)" #. TRANSLATORS: Unknown reason for a device state change (NMDeviceStateReason) #. TRANSLATORS: Unknown reason for a connection state change (NMActiveConnectionStateReason) #: ../clients/common/nm-client-utils.c:311 -#: ../clients/common/nm-client-utils.c:384 ../libnm/nm-device.c:1583 +#: ../clients/common/nm-client-utils.c:384 ../libnm/nm-device.c:1628 msgid "Unknown" msgstr "Невідомо" @@ -4793,7 +4790,7 @@ msgid "invalid option '%s', use a combination of [%s]" msgstr "некоректний параметр «%s», скористайтеся комбінацією [%s]" #: ../clients/common/nm-meta-setting-desc.c:1595 -#: ../shared/nm-keyfile/nm-keyfile.c:1076 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1076 #, c-format msgid "invalid option '%s', use one of [%s]" msgstr "" @@ -5332,7 +5329,7 @@ msgstr "Користувач" #: ../clients/common/nm-meta-setting-desc.c:4809 #: ../clients/common/nm-meta-setting-desc.c:5093 #: ../clients/common/nm-meta-setting-desc.c:5520 -#: ../clients/common/nm-meta-setting-desc.c:6480 +#: ../clients/common/nm-meta-setting-desc.c:6492 msgid "Password [none]" msgstr "Пароль [типово немає]" @@ -5342,10 +5339,10 @@ msgstr "Адреса пристрою Bluetooth" #: ../clients/common/nm-meta-setting-desc.c:4903 #: ../clients/common/nm-meta-setting-desc.c:5573 -#: ../clients/common/nm-meta-setting-desc.c:7188 -#: ../clients/common/nm-meta-setting-desc.c:7226 -#: ../clients/common/nm-meta-setting-desc.c:7408 -#: ../clients/common/nm-meta-setting-desc.c:7638 +#: ../clients/common/nm-meta-setting-desc.c:7200 +#: ../clients/common/nm-meta-setting-desc.c:7238 +#: ../clients/common/nm-meta-setting-desc.c:7420 +#: ../clients/common/nm-meta-setting-desc.c:7650 msgid "MAC [none]" msgstr "MAC [типово немає]" @@ -5395,7 +5392,7 @@ msgstr "Початкова зона [типово немає]" #: ../clients/common/nm-meta-setting-desc.c:5087 #: ../clients/common/nm-meta-setting-desc.c:5514 -#: ../clients/common/nm-meta-setting-desc.c:7034 +#: ../clients/common/nm-meta-setting-desc.c:7046 msgid "Username [none]" msgstr "Користувач [типово немає]" @@ -5456,8 +5453,8 @@ msgid "APN" msgstr "APN" #: ../clients/common/nm-meta-setting-desc.c:5582 -#: ../clients/common/nm-meta-setting-desc.c:7257 -#: ../clients/common/nm-meta-setting-desc.c:7448 +#: ../clients/common/nm-meta-setting-desc.c:7269 +#: ../clients/common/nm-meta-setting-desc.c:7460 msgid "MTU [auto]" msgstr "MTU [типово авто]" @@ -5613,7 +5610,7 @@ msgstr "" "\n" #: ../clients/common/nm-meta-setting-desc.c:6075 -#: ../clients/common/nm-meta-setting-desc.c:7087 +#: ../clients/common/nm-meta-setting-desc.c:7099 msgid "Parent device [none]" msgstr "Батьківський пристрій [типово немає]" @@ -5622,7 +5619,7 @@ msgid "Local endpoint [none]" msgstr "Локальна кінцева точка [типово немає]" #: ../clients/common/nm-meta-setting-desc.c:6088 -#: ../clients/common/nm-meta-setting-desc.c:7107 +#: ../clients/common/nm-meta-setting-desc.c:7119 msgid "Remote" msgstr "Віддалений" @@ -5655,127 +5652,127 @@ msgstr "Батьківський пристрій MACVLAN або UUID з'єдн msgid "Tap [no]" msgstr "Tap [типово ні]" -#: ../clients/common/nm-meta-setting-desc.c:6278 -#: ../clients/common/nm-meta-setting-desc.c:7362 +#: ../clients/common/nm-meta-setting-desc.c:6290 +#: ../clients/common/nm-meta-setting-desc.c:7374 #: ../clients/tui/nmt-page-wifi.c:213 msgid "SSID" msgstr "SSID" -#: ../clients/common/nm-meta-setting-desc.c:6287 +#: ../clients/common/nm-meta-setting-desc.c:6299 msgid "OLPC Mesh channel [1]" msgstr "Канал OLPC Mesh [типово 1]" -#: ../clients/common/nm-meta-setting-desc.c:6296 +#: ../clients/common/nm-meta-setting-desc.c:6308 msgid "DHCP anycast MAC address [none]" msgstr "MAC-адреса довільного надсилання (anycast) DHCP [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:6461 +#: ../clients/common/nm-meta-setting-desc.c:6473 msgid "PPPoE parent device" msgstr "Батьківський пристрій PPPoE" -#: ../clients/common/nm-meta-setting-desc.c:6467 +#: ../clients/common/nm-meta-setting-desc.c:6479 msgid "Service [none]" msgstr "Служба [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:6474 +#: ../clients/common/nm-meta-setting-desc.c:6486 msgid "PPPoE username" msgstr "Користувач PPPoE" -#: ../clients/common/nm-meta-setting-desc.c:6510 +#: ../clients/common/nm-meta-setting-desc.c:6522 msgid "Browser only [no]" msgstr "Лише навігатор [типово «ні»]" -#: ../clients/common/nm-meta-setting-desc.c:6516 +#: ../clients/common/nm-meta-setting-desc.c:6528 msgid "PAC URL" msgstr "Адреса PAC" -#: ../clients/common/nm-meta-setting-desc.c:6522 +#: ../clients/common/nm-meta-setting-desc.c:6534 msgid "PAC script" msgstr "Скрипт PAC" -#: ../clients/common/nm-meta-setting-desc.c:6646 -#: ../clients/common/nm-meta-setting-desc.c:6834 +#: ../clients/common/nm-meta-setting-desc.c:6658 +#: ../clients/common/nm-meta-setting-desc.c:6846 msgid "Team JSON configuration [none]" msgstr "Налаштування JSON команди [немає]" -#: ../clients/common/nm-meta-setting-desc.c:6937 +#: ../clients/common/nm-meta-setting-desc.c:6949 msgid "User ID [none]" msgstr "Ідентифікатор користувача [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:6943 +#: ../clients/common/nm-meta-setting-desc.c:6955 msgid "Group ID [none]" msgstr "Ідентифікатор групи [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:6949 +#: ../clients/common/nm-meta-setting-desc.c:6961 msgid "Enable PI [no]" msgstr "Увімкнути PI [типово ні]" -#: ../clients/common/nm-meta-setting-desc.c:6955 +#: ../clients/common/nm-meta-setting-desc.c:6967 msgid "Enable VNET header [no]" msgstr "Увімкнути заголовок VNET [типово ні]" -#: ../clients/common/nm-meta-setting-desc.c:6961 +#: ../clients/common/nm-meta-setting-desc.c:6973 msgid "Enable multi queue [no]" msgstr "Увімкнути декілька черг [типово ні]" -#: ../clients/common/nm-meta-setting-desc.c:6974 +#: ../clients/common/nm-meta-setting-desc.c:6986 msgid "VLAN parent device or connection UUID" msgstr "Батьківський пристрій VLAN або UUID з'єднання" -#: ../clients/common/nm-meta-setting-desc.c:6981 +#: ../clients/common/nm-meta-setting-desc.c:6993 msgid "VLAN ID (<0-4094>)" msgstr "Ід. VLAN (<0-4094>)" -#: ../clients/common/nm-meta-setting-desc.c:6987 +#: ../clients/common/nm-meta-setting-desc.c:6999 msgid "VLAN flags (<0-7>) [none]" msgstr "Прапорці VLAN (<0-7>) [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:6996 +#: ../clients/common/nm-meta-setting-desc.c:7008 msgid "Ingress priority maps [none]" msgstr "Відображення пріоритетності вхідного доступу [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:7006 +#: ../clients/common/nm-meta-setting-desc.c:7018 msgid "Egress priority maps [none]" msgstr "Відображення пріоритетності вихідного доступу [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:7074 +#: ../clients/common/nm-meta-setting-desc.c:7086 msgid "Table [0]" msgstr "Таблиця [0]" -#: ../clients/common/nm-meta-setting-desc.c:7094 +#: ../clients/common/nm-meta-setting-desc.c:7106 msgid "VXLAN ID" msgstr "Ід. VXLAN" -#: ../clients/common/nm-meta-setting-desc.c:7100 +#: ../clients/common/nm-meta-setting-desc.c:7112 msgid "Local address [none]" msgstr "Локальна адреса [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:7113 +#: ../clients/common/nm-meta-setting-desc.c:7125 msgid "Minimum source port [0]" msgstr "Мінімальний порт джерела [0]" -#: ../clients/common/nm-meta-setting-desc.c:7119 +#: ../clients/common/nm-meta-setting-desc.c:7131 msgid "Maximum source port [0]" msgstr "Максимальний порт джерела [0]" -#: ../clients/common/nm-meta-setting-desc.c:7125 +#: ../clients/common/nm-meta-setting-desc.c:7137 msgid "Destination port [8472]" msgstr "Порт призначення [типово 8472]" -#: ../clients/common/nm-meta-setting-desc.c:7165 +#: ../clients/common/nm-meta-setting-desc.c:7177 msgid "Peer" msgstr "Вузол" -#: ../clients/common/nm-meta-setting-desc.c:7195 +#: ../clients/common/nm-meta-setting-desc.c:7207 msgid "WiMAX NSP name" msgstr "Назва NSP WiMAX" -#: ../clients/common/nm-meta-setting-desc.c:7232 -#: ../clients/common/nm-meta-setting-desc.c:7413 +#: ../clients/common/nm-meta-setting-desc.c:7244 +#: ../clients/common/nm-meta-setting-desc.c:7425 msgid "Cloned MAC [none]" msgstr "Клонований MAC [типово немає]" -#: ../clients/common/nm-meta-setting-desc.c:7265 +#: ../clients/common/nm-meta-setting-desc.c:7277 msgid "" "Enter a list of subchannels (comma or space separated).\n" "\n" @@ -5785,7 +5782,7 @@ msgstr "" "\n" "Приклад: 0.0.0e20 0.0.0e21 0.0.0e22\n" -#: ../clients/common/nm-meta-setting-desc.c:7587 +#: ../clients/common/nm-meta-setting-desc.c:7599 msgid "" "Enter the type of WEP keys. The accepted values are: 0 or unknown, 1 or key, " "and 2 or passphrase.\n" @@ -5793,221 +5790,221 @@ msgstr "" "Вкажіть тип ключів WEP. Можливі значення: 0 або unknown (невідомо), 1 або " "key (ключ) та 2 або passphrase (пароль).\n" -#: ../clients/common/nm-meta-setting-desc.c:7646 +#: ../clients/common/nm-meta-setting-desc.c:7658 msgid "Short address (<0x0000-0xffff>)" msgstr "Коротка адреса (<0x0000-0xffff>)" -#: ../clients/common/nm-meta-setting-desc.c:7662 +#: ../clients/common/nm-meta-setting-desc.c:7674 msgid "PAN Identifier (<0x0000-0xffff>)" msgstr "Ідентифікатор PAN (<0x0000-0xffff>)" -#: ../clients/common/nm-meta-setting-desc.c:7677 +#: ../clients/common/nm-meta-setting-desc.c:7689 msgid "Page ()" msgstr "Сторінка ()" -#: ../clients/common/nm-meta-setting-desc.c:7691 +#: ../clients/common/nm-meta-setting-desc.c:7703 msgid "Channel ()" msgstr "Канал ()" #. *************************************************************************** -#: ../clients/common/nm-meta-setting-desc.c:7826 +#: ../clients/common/nm-meta-setting-desc.c:7838 msgid "6LOWPAN settings" msgstr "Параметри 6LOWPAN" -#: ../clients/common/nm-meta-setting-desc.c:7827 +#: ../clients/common/nm-meta-setting-desc.c:7839 msgid "802-1x settings" msgstr "Параметри 802-1x" -#: ../clients/common/nm-meta-setting-desc.c:7828 +#: ../clients/common/nm-meta-setting-desc.c:7840 #: ../src/devices/adsl/nm-device-adsl.c:117 msgid "ADSL connection" msgstr "З'єднання ADSL" -#: ../clients/common/nm-meta-setting-desc.c:7829 +#: ../clients/common/nm-meta-setting-desc.c:7841 msgid "bluetooth connection" msgstr "з'єднання bluetooth" -#: ../clients/common/nm-meta-setting-desc.c:7830 +#: ../clients/common/nm-meta-setting-desc.c:7842 msgid "Bond device" msgstr "Пристрій Bond" -#: ../clients/common/nm-meta-setting-desc.c:7831 +#: ../clients/common/nm-meta-setting-desc.c:7843 msgid "Bridge device" msgstr "Пристрій містка" -#: ../clients/common/nm-meta-setting-desc.c:7832 +#: ../clients/common/nm-meta-setting-desc.c:7844 msgid "Bridge port" msgstr "Порт містка" -#: ../clients/common/nm-meta-setting-desc.c:7833 +#: ../clients/common/nm-meta-setting-desc.c:7845 msgid "CDMA mobile broadband connection" msgstr "мобільне широкосмугове з'єднання CDMA" -#: ../clients/common/nm-meta-setting-desc.c:7834 +#: ../clients/common/nm-meta-setting-desc.c:7846 msgid "General settings" msgstr "Загальні параметри" -#: ../clients/common/nm-meta-setting-desc.c:7835 +#: ../clients/common/nm-meta-setting-desc.c:7847 msgid "DCB settings" msgstr "Параметри DCB" -#: ../clients/common/nm-meta-setting-desc.c:7836 +#: ../clients/common/nm-meta-setting-desc.c:7848 msgid "Dummy settings" msgstr "Фіктивні параметри" -#: ../clients/common/nm-meta-setting-desc.c:7837 +#: ../clients/common/nm-meta-setting-desc.c:7849 msgid "Ethtool settings" msgstr "Параметри Ethtool" -#: ../clients/common/nm-meta-setting-desc.c:7838 +#: ../clients/common/nm-meta-setting-desc.c:7850 msgid "Generic settings" msgstr "Загальні параметри" -#: ../clients/common/nm-meta-setting-desc.c:7839 +#: ../clients/common/nm-meta-setting-desc.c:7851 msgid "GSM mobile broadband connection" msgstr "мобільне широкосмугове з'єднання GSM" -#: ../clients/common/nm-meta-setting-desc.c:7840 +#: ../clients/common/nm-meta-setting-desc.c:7852 #: ../src/devices/nm-device-infiniband.c:158 msgid "InfiniBand connection" msgstr "З'єднання InfiniBand" -#: ../clients/common/nm-meta-setting-desc.c:7841 +#: ../clients/common/nm-meta-setting-desc.c:7853 msgid "IPv4 protocol" msgstr "Протокол IPv4" -#: ../clients/common/nm-meta-setting-desc.c:7842 +#: ../clients/common/nm-meta-setting-desc.c:7854 msgid "IPv6 protocol" msgstr "Протокол IPv6" -#: ../clients/common/nm-meta-setting-desc.c:7843 +#: ../clients/common/nm-meta-setting-desc.c:7855 msgid "IP-tunnel settings" msgstr "Параметри IP-тунелювання" -#: ../clients/common/nm-meta-setting-desc.c:7844 +#: ../clients/common/nm-meta-setting-desc.c:7856 msgid "MACsec connection" msgstr "З'єднання MACsec" -#: ../clients/common/nm-meta-setting-desc.c:7845 +#: ../clients/common/nm-meta-setting-desc.c:7857 msgid "macvlan connection" msgstr "З'єднання MACVLAN" -#: ../clients/common/nm-meta-setting-desc.c:7846 +#: ../clients/common/nm-meta-setting-desc.c:7858 msgid "Match" msgstr "Відповідність" -#: ../clients/common/nm-meta-setting-desc.c:7847 +#: ../clients/common/nm-meta-setting-desc.c:7859 msgid "OLPC Mesh connection" msgstr "З'єднання OLPC Mesh" -#: ../clients/common/nm-meta-setting-desc.c:7848 +#: ../clients/common/nm-meta-setting-desc.c:7860 msgid "Open vSwitch bridge settings" msgstr "Параметри містка Open vSwitch" -#: ../clients/common/nm-meta-setting-desc.c:7849 +#: ../clients/common/nm-meta-setting-desc.c:7861 msgid "Open vSwitch DPDK interface settings" msgstr "Параметри інтерфейсу Open vSwitch DPDK" -#: ../clients/common/nm-meta-setting-desc.c:7850 +#: ../clients/common/nm-meta-setting-desc.c:7862 msgid "Open vSwitch interface settings" msgstr "Параметри інтерфейсу Open vSwitch" -#: ../clients/common/nm-meta-setting-desc.c:7851 +#: ../clients/common/nm-meta-setting-desc.c:7863 msgid "Open vSwitch patch interface settings" msgstr "Параметри інтерфейсу латок Open vSwitch" -#: ../clients/common/nm-meta-setting-desc.c:7852 +#: ../clients/common/nm-meta-setting-desc.c:7864 msgid "Open vSwitch port settings" msgstr "Параметри портів Open vSwitch" -#: ../clients/common/nm-meta-setting-desc.c:7853 +#: ../clients/common/nm-meta-setting-desc.c:7865 msgid "PPP settings" msgstr "Параметри PPP" -#: ../clients/common/nm-meta-setting-desc.c:7854 +#: ../clients/common/nm-meta-setting-desc.c:7866 msgid "PPPoE" msgstr "PPPoE" -#: ../clients/common/nm-meta-setting-desc.c:7855 +#: ../clients/common/nm-meta-setting-desc.c:7867 msgid "Proxy" msgstr "Проксі" -#: ../clients/common/nm-meta-setting-desc.c:7856 +#: ../clients/common/nm-meta-setting-desc.c:7868 msgid "Serial settings" msgstr "Параметри послідовного з'єднання" -#: ../clients/common/nm-meta-setting-desc.c:7857 +#: ../clients/common/nm-meta-setting-desc.c:7869 msgid "SR-IOV settings" msgstr "Параметри SR-IOV" -#: ../clients/common/nm-meta-setting-desc.c:7858 +#: ../clients/common/nm-meta-setting-desc.c:7870 msgid "Traffic controls" msgstr "Засоби керування обміном даними" -#: ../clients/common/nm-meta-setting-desc.c:7859 +#: ../clients/common/nm-meta-setting-desc.c:7871 msgid "Team device" msgstr "Пристрій Team" -#: ../clients/common/nm-meta-setting-desc.c:7860 +#: ../clients/common/nm-meta-setting-desc.c:7872 msgid "Team port" msgstr "Порт Team" -#: ../clients/common/nm-meta-setting-desc.c:7861 +#: ../clients/common/nm-meta-setting-desc.c:7873 msgid "Tun device" msgstr "Пристрій TUN" -#: ../clients/common/nm-meta-setting-desc.c:7862 +#: ../clients/common/nm-meta-setting-desc.c:7874 msgid "User settings" msgstr "Параметри користувача" -#: ../clients/common/nm-meta-setting-desc.c:7863 +#: ../clients/common/nm-meta-setting-desc.c:7875 #: ../src/devices/nm-device-vlan.c:385 msgid "VLAN connection" msgstr "З'єднання VLAN" -#: ../clients/common/nm-meta-setting-desc.c:7864 ../src/nm-manager.c:5697 +#: ../clients/common/nm-meta-setting-desc.c:7876 ../src/nm-manager.c:5697 msgid "VPN connection" msgstr "З'єднання VPN" -#: ../clients/common/nm-meta-setting-desc.c:7865 +#: ../clients/common/nm-meta-setting-desc.c:7877 #: ../src/devices/nm-device-vrf.c:175 msgid "VRF connection" msgstr "З'єднання VRF" -#: ../clients/common/nm-meta-setting-desc.c:7866 +#: ../clients/common/nm-meta-setting-desc.c:7878 #: ../src/devices/nm-device-vxlan.c:354 msgid "VXLAN connection" msgstr "З'єднання VXLAN" -#: ../clients/common/nm-meta-setting-desc.c:7867 +#: ../clients/common/nm-meta-setting-desc.c:7879 msgid "Wi-Fi P2P connection" msgstr "З'єднання P2P Wi-Fi" -#: ../clients/common/nm-meta-setting-desc.c:7868 +#: ../clients/common/nm-meta-setting-desc.c:7880 msgid "WiMAX connection" msgstr "З'єднання WiMAX" -#: ../clients/common/nm-meta-setting-desc.c:7869 +#: ../clients/common/nm-meta-setting-desc.c:7881 msgid "Wired Ethernet" msgstr "Дротовий Ethernet" -#: ../clients/common/nm-meta-setting-desc.c:7870 +#: ../clients/common/nm-meta-setting-desc.c:7882 msgid "WireGuard VPN settings" msgstr "Параметри VPN WireGuard" -#: ../clients/common/nm-meta-setting-desc.c:7871 +#: ../clients/common/nm-meta-setting-desc.c:7883 msgid "Wi-Fi connection" msgstr "З'єднання Wi-Fi" -#: ../clients/common/nm-meta-setting-desc.c:7872 +#: ../clients/common/nm-meta-setting-desc.c:7884 msgid "Wi-Fi security settings" msgstr "Параметри захисту Wi-Fi" -#: ../clients/common/nm-meta-setting-desc.c:7873 +#: ../clients/common/nm-meta-setting-desc.c:7885 msgid "WPAN settings" msgstr "Параметри WPAN" -#: ../clients/common/nm-meta-setting-desc.c:8250 +#: ../clients/common/nm-meta-setting-desc.c:8262 msgid "name" msgstr "назва" @@ -6799,16 +6796,6 @@ msgstr "" "на розпізнавання складатиме 25 секунд." #: ../clients/common/settings-docs.h.in:47 -#| msgid "" -#| "Contains the CA certificate if used by the EAP method specified in the " -#| "\"eap\" property. Certificate data is specified using a \"scheme\"; two " -#| "are currently supported: blob and path. When using the blob scheme (which " -#| "is backwards compatible with NM 0.7.x) this property should be set to the " -#| "certificate's DER encoded data. When using the path scheme, this property " -#| "should be set to the full UTF-8 encoded path of the certificate, prefixed " -#| "with the string \"file://\" and ending with a terminating NUL byte. This " -#| "property can be unset even if the EAP method supports CA certificates, " -#| "but this allows man-in-the-middle attacks and is NOT recommended." msgid "" "Contains the CA certificate if used by the EAP method specified in the \"eap" "\" property. Certificate data is specified using a \"scheme\"; three are " @@ -6824,18 +6811,17 @@ msgid "" msgstr "" "Містить сертифікат служби сертифікації, якщо використано способом EAP, " "вказаним у властивості «eap». Дані сертифіката визначаються за допомогою " -"«схеми». У поточній версії передбачено три варіанти: blob, path і адреса" -" pkcs#11. Якщо " -"використовується схема blob, значенням " -"цієї властивості мають бути дані сертифіката у кодуванні DER. Якщо " -"використовується схема path, для цієї властивості слід встановити повний " -"шлях у кодуванні UTF-8 до сертифіката із рядком-префіксом «file://» та " -"завершальним байтом NUL. Встановлення цієї властивості можна скасувати, " -"навіть якщо у способі EAP передбачено підтримку сертифікатів служб " -"сертифікації, але це уможливлює втручання сторонніх осіб у ланцюжки " -"передавання даних, тому ми наполегливо не рекомендуємо це робити. Зауважте," -" що вмикання NMSetting8021x:system-ca-certs перевизначить цей параметр на" -" використання вбудованого шляху, якщо вбудований шлях не є каталогом." +"«схеми». У поточній версії передбачено три варіанти: blob, path і адреса " +"pkcs#11. Якщо використовується схема blob, значенням цієї властивості мають " +"бути дані сертифіката у кодуванні DER. Якщо використовується схема path, для " +"цієї властивості слід встановити повний шлях у кодуванні UTF-8 до " +"сертифіката із рядком-префіксом «file://» та завершальним байтом NUL. " +"Встановлення цієї властивості можна скасувати, навіть якщо у способі EAP " +"передбачено підтримку сертифікатів служб сертифікації, але це уможливлює " +"втручання сторонніх осіб у ланцюжки передавання даних, тому ми наполегливо " +"не рекомендуємо це робити. Зауважте, що вмикання NMSetting8021x:system-ca-" +"certs перевизначить цей параметр на використання вбудованого шляху, якщо " +"вбудований шлях не є каталогом." #: ../clients/common/settings-docs.h.in:48 msgid "" @@ -6853,10 +6839,6 @@ msgid "Flags indicating how to handle the \"ca-cert-password\" property." msgstr "Прапорці, які позначають, як обробляти властивість «ca-cert-password»." #: ../clients/common/settings-docs.h.in:50 -#| msgid "" -#| "UTF-8 encoded path to a directory containing PEM or DER formatted " -#| "certificates to be added to the verification chain in addition to the " -#| "certificate specified in the \"ca-cert\" property." msgid "" "UTF-8 encoded path to a directory containing PEM or DER formatted " "certificates to be added to the verification chain in addition to the " @@ -6866,9 +6848,9 @@ msgid "" msgstr "" "Шлях у кодуванні UTF-8 до каталогу, де зберігаються сертифікати у " "форматуванні PEM або DER, які слід додати до ланцюжка перевірки на додачу до " -"сертифікатів, вказаних за допомогою властивості «ca-cert». Якщо увімкнено" -" NMSetting8021x:system-ca-certs і вбудований шлях до CA є наявним каталогом," -" цей параметр буде проігноровано." +"сертифікатів, вказаних за допомогою властивості «ca-cert». Якщо увімкнено " +"NMSetting8021x:system-ca-certs і вбудований шлях до CA є наявним каталогом, " +"цей параметр буде проігноровано." #: ../clients/common/settings-docs.h.in:51 msgid "" @@ -6994,7 +6976,7 @@ msgstr "" #: ../clients/common/settings-docs.h.in:107 #: ../clients/common/settings-docs.h.in:149 #: ../clients/common/settings-docs.h.in:199 -#: ../clients/common/settings-docs.h.in:320 +#: ../clients/common/settings-docs.h.in:321 msgid "Flags indicating how to handle the \"password\" property." msgstr "Прапорці, які позначають, як обробляти властивість «password»." @@ -7122,17 +7104,6 @@ msgstr "" "опис параметрів можна знайти у документації з wpa_supplicant." #: ../clients/common/settings-docs.h.in:71 -#| msgid "" -#| "Contains the \"phase 2\" CA certificate if used by the EAP method " -#| "specified in the \"phase2-auth\" or \"phase2-autheap\" properties. " -#| "Certificate data is specified using a \"scheme\"; two are currently " -#| "supported: blob and path. When using the blob scheme (which is backwards " -#| "compatible with NM 0.7.x) this property should be set to the " -#| "certificate's DER encoded data. When using the path scheme, this property " -#| "should be set to the full UTF-8 encoded path of the certificate, prefixed " -#| "with the string \"file://\" and ending with a terminating NUL byte. This " -#| "property can be unset even if the EAP method supports CA certificates, " -#| "but this allows man-in-the-middle attacks and is NOT recommended." msgid "" "Contains the \"phase 2\" CA certificate if used by the EAP method specified " "in the \"phase2-auth\" or \"phase2-autheap\" properties. Certificate data is " @@ -7149,16 +7120,16 @@ msgstr "" "Містить сертифікат служби сертифікації «phase 2», якщо використано способом " "EAP, вказаним у властивості «phase2-auth» або «phase2-autheap». Дані " "сертифіката визначаються за допомогою «схеми». У поточній версії передбачено " -"три варіанти: blob, path і адреса pkcs#11. Якщо використовується схема blob," -" значенням цієї властивості мають бути дані сертифіката " -"у кодуванні DER. Якщо використовується схема path, для цієї властивості слід " -"встановити повний шлях у кодуванні UTF-8 до сертифіката із рядком-префіксом " -"«file://» та завершальним байтом NUL. Встановлення цієї властивості можна " -"скасувати, навіть якщо у способі EAP передбачено підтримку сертифікатів " -"служб сертифікації, але це уможливлює втручання сторонніх осіб у ланцюжки " -"передавання даних, тому ми наполегливо не рекомендуємо це робити. Зауважте," -" що вмикання NMSetting8021x:system-ca-certs перевизначить цей параметр на" -" використання вбудованого шляху, якщо вбудований шлях не є каталогом." +"три варіанти: blob, path і адреса pkcs#11. Якщо використовується схема blob, " +"значенням цієї властивості мають бути дані сертифіката у кодуванні DER. Якщо " +"використовується схема path, для цієї властивості слід встановити повний " +"шлях у кодуванні UTF-8 до сертифіката із рядком-префіксом «file://» та " +"завершальним байтом NUL. Встановлення цієї властивості можна скасувати, " +"навіть якщо у способі EAP передбачено підтримку сертифікатів служб " +"сертифікації, але це уможливлює втручання сторонніх осіб у ланцюжки " +"передавання даних, тому ми наполегливо не рекомендуємо це робити. Зауважте, " +"що вмикання NMSetting8021x:system-ca-certs перевизначить цей параметр на " +"використання вбудованого шляху, якщо вбудований шлях не є каталогом." #: ../clients/common/settings-docs.h.in:72 msgid "" @@ -7178,10 +7149,6 @@ msgstr "" "Прапорці, які позначають, як обробляти властивість «phase2-ca-cert-password»." #: ../clients/common/settings-docs.h.in:74 -#| msgid "" -#| "UTF-8 encoded path to a directory containing PEM or DER formatted " -#| "certificates to be added to the verification chain in addition to the " -#| "certificate specified in the \"phase2-ca-cert\" property." msgid "" "UTF-8 encoded path to a directory containing PEM or DER formatted " "certificates to be added to the verification chain in addition to the " @@ -7191,9 +7158,9 @@ msgid "" msgstr "" "Шлях у кодуванні UTF-8 до каталогу, де зберігаються сертифікати у " "форматуванні PEM або DER, які слід додати до ланцюжка перевірки на додачу до " -"сертифікатів, вказаних за допомогою властивості «phase2-ca-cert». Якщо" -" увімкнено NMSetting8021x:system-ca-certs і вбудований шлях до CA є наявним" -" каталогом, цей параметр буде проігноровано." +"сертифікатів, вказаних за допомогою властивості «phase2-ca-cert». Якщо " +"увімкнено NMSetting8021x:system-ca-certs і вбудований шлях до CA є наявним " +"каталогом, цей параметр буде проігноровано." #: ../clients/common/settings-docs.h.in:75 msgid "" @@ -7841,8 +7808,12 @@ msgstr "" "IP-адресу містка. Якщо вимкнено, буде використано типову адресу 0.0.0.0." #: ../clients/common/settings-docs.h.in:131 +#| msgid "" +#| "Sets bridge's multicast router. multicast-snooping must be enabled for " +#| "this option to work. Supported values are: 'auto', 'disabled', 'enabled'. " +#| "If not specified the default value is 'auto'." msgid "" -"Sets bridge's multicast router. multicast-snooping must be enabled for this " +"Sets bridge's multicast router. Multicast-snooping must be enabled for this " "option to work. Supported values are: 'auto', 'disabled', 'enabled'. If not " "specified the default value is 'auto'." msgstr "" @@ -9584,34 +9555,65 @@ msgstr "" "рівняння зі встановленням відповідності правої і лівої його частин." #: ../clients/common/settings-docs.h.in:286 +msgid "" +"A list of paths to match against the ID_PATH udev property of devices. " +"ID_PATH represents the topological persistent path of a device. It typically " +"contains a subsystem string (pci, usb, platform, etc.) and a subsystem-" +"specific identifier. For PCI devices the path has the form \"pci-$domain:" +"$bus:$device.$function\", where each variable is an hexadecimal value; for " +"example \"pci-0000:0a:00.0\". The path of a device can be obtained with " +"\"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the " +"\"path\" property exported by NetworkManager (\"nmcli -f general.path device " +"show $dev\"). Each element of the list is a shell wildcard pattern. When an " +"element is prefixed with exclamation mark (!) the condition is inverted. A " +"candidate path is considered matching when both these conditions are " +"satisfied: (a) any of the elements not prefixed with '!' matches or there " +"aren't such elements; (b) none of the elements prefixed with '!' match." +msgstr "" +"Список шляхів для порівняння із властивістю udev ID_PATH пристроїв. ID_PATH є" +" топологічно сталим шляхом пристрою. У ньому, типово, міститься рядок" +" підсистеми (pci, usb, platform тощо) і специфічний для підсистеми" +" ідентифікатор. Для пристроїв PCI шлях має формат" +" «pci-$домен:$шина:$пристрій.$функція», де кожна зі змінних є шістнадцятковим" +" значенням. Приклад: «pci-0000:0a:00.0». Шлях пристрою можна отримати за" +" допомогою команди «udevadm info /sys/class/net/$dev | grep ID_PATH=» або за" +" рядком властивості «path» у експортованих NetworkManager даних («nmcli -f" +" general.path device show $dev»). Кожен із елементів списку є взірцем" +" командної оболонки із символами-замінниками. Якщо до елемента додано префікс" +" — знак оклику (!), умова замінюється на протилежну. Шлях-кандидат вважається" +" відповідним, якщо задовольняються обидві такі умови: (а) запису відповідає" +" якийсь із елементів без префікса «!» або у списку немає таких елементів; (б)" +" запису не відповідає жоден із елементів із префіксом «!»." + +#: ../clients/common/settings-docs.h.in:287 msgid "The data path type. One of \"system\", \"netdev\" or empty." msgstr "" "Тип шляху до даних. Одне з таких значень: «system», «netdev» або порожнє " "значення." -#: ../clients/common/settings-docs.h.in:287 +#: ../clients/common/settings-docs.h.in:288 msgid "The bridge failure mode. One of \"secure\", \"standalone\" or empty." msgstr "" "Режим відмови містка. Одне з таких значень: «secure», «standalone» або " "порожнє значення." -#: ../clients/common/settings-docs.h.in:288 +#: ../clients/common/settings-docs.h.in:289 msgid "Enable or disable multicast snooping." msgstr "Увімкнути або вимкнути переставляння універсальної трансляції." -#: ../clients/common/settings-docs.h.in:289 +#: ../clients/common/settings-docs.h.in:290 msgid "Enable or disable RSTP." msgstr "Увімкнути або вимкнути RSTP." -#: ../clients/common/settings-docs.h.in:290 +#: ../clients/common/settings-docs.h.in:291 msgid "Enable or disable STP." msgstr "Увімкнути або вимкнути STP." -#: ../clients/common/settings-docs.h.in:291 +#: ../clients/common/settings-docs.h.in:292 msgid "Open vSwitch DPDK device arguments." msgstr "Параметри пристрою Open vSwitch DPDK." -#: ../clients/common/settings-docs.h.in:292 +#: ../clients/common/settings-docs.h.in:293 msgid "" "The interface type. Either \"internal\", \"system\", \"patch\", \"dpdk\", or " "empty." @@ -9619,39 +9621,39 @@ msgstr "" "Тип інтерфейсу. Рядок «internal», «system», «patch», «dpdk» або порожній " "рядок." -#: ../clients/common/settings-docs.h.in:293 +#: ../clients/common/settings-docs.h.in:294 msgid "" "Specifies the name of the interface for the other side of the patch. The " "patch on the other side must also set this interface as peer." msgstr "" -"Вказує назву інтерфейсу для іншого боку тимчасового з'єднання. Тимчасове" -" з'єднання на іншому боці також має встановлювати цей інтерфейс як" -" однорівневий вузол." +"Вказує назву інтерфейсу для іншого боку тимчасового з'єднання. Тимчасове " +"з'єднання на іншому боці також має встановлювати цей інтерфейс як " +"однорівневий вузол." -#: ../clients/common/settings-docs.h.in:294 +#: ../clients/common/settings-docs.h.in:295 msgid "The time port must be inactive in order to be considered down." msgstr "Щоб вважатися вимкненим, порт часу має бути неактивним." -#: ../clients/common/settings-docs.h.in:295 +#: ../clients/common/settings-docs.h.in:296 msgid "" "Bonding mode. One of \"active-backup\", \"balance-slb\", or \"balance-tcp\"." msgstr "" "Режим прив'язування. Одне з таких значень: «active-backup», «balance-slb» " "або «balance-tcp»." -#: ../clients/common/settings-docs.h.in:296 +#: ../clients/common/settings-docs.h.in:297 msgid "The time port must be active before it starts forwarding traffic." msgstr "Щоб почати переспрямовувати дані, слід активувати порт часу." -#: ../clients/common/settings-docs.h.in:297 +#: ../clients/common/settings-docs.h.in:298 msgid "LACP mode. One of \"active\", \"off\", or \"passive\"." msgstr "Режим LACP. Одне з таких значень: «active», «off» або «passive»." -#: ../clients/common/settings-docs.h.in:298 +#: ../clients/common/settings-docs.h.in:299 msgid "The VLAN tag in the range 0-4095." msgstr "Теґ VLAN у діапазоні від 0 до 4095." -#: ../clients/common/settings-docs.h.in:299 +#: ../clients/common/settings-docs.h.in:300 msgid "" "The VLAN mode. One of \"access\", \"native-tagged\", \"native-untagged\", " "\"trunk\" or unset." @@ -9659,7 +9661,7 @@ msgstr "" "Режим VLAN. Одне з таких значень: «access», «native-tagged», «native-" "untagged», «trunk» або порожнє значення." -#: ../clients/common/settings-docs.h.in:300 +#: ../clients/common/settings-docs.h.in:301 msgid "" "If non-zero, instruct pppd to set the serial port to the specified " "baudrate. This value should normally be left as 0 to automatically choose " @@ -9669,7 +9671,7 @@ msgstr "" "вказану швидкість передавання даних у бодах. Зазвичай, для цієї властивості " "слід залишити нульове значення, щоб швидкість було вибрано автоматично." -#: ../clients/common/settings-docs.h.in:301 +#: ../clients/common/settings-docs.h.in:302 msgid "" "If TRUE, specify that pppd should set the serial port to use hardware flow " "control with RTS and CTS signals. This value should normally be set to " @@ -9679,7 +9681,7 @@ msgstr "" "керування потоком апаратних даних за допомогою сигналів RTS і CTS. За " "звичних умов, для цієї властивості має бути встановлено значення FALSE." -#: ../clients/common/settings-docs.h.in:302 +#: ../clients/common/settings-docs.h.in:303 msgid "" "If non-zero, instruct pppd to presume the connection to the peer has failed " "if the specified number of LCP echo-requests go unanswered by the peer. The " @@ -9691,7 +9693,7 @@ msgstr "" "кількість луна-запитів LCP. Якщо використовується ця властивість, для " "властивості «lcp-echo-interval» слід встановити ненульове значення." -#: ../clients/common/settings-docs.h.in:303 +#: ../clients/common/settings-docs.h.in:304 msgid "" "If non-zero, instruct pppd to send an LCP echo-request frame to the peer " "every n seconds (where n is the specified value). Note that some PPP peers " @@ -9703,7 +9705,7 @@ msgstr "" "відповідатимуть на луна-запити, а деякі — ні. Визначити, чи відповідатиме " "певний вузол, у автоматичному режимі неможливо." -#: ../clients/common/settings-docs.h.in:304 +#: ../clients/common/settings-docs.h.in:305 msgid "" "If TRUE, stateful MPPE is used. See pppd documentation for more information " "on stateful MPPE." @@ -9711,7 +9713,7 @@ msgstr "" "Якщо TRUE, використовуватиметься режим MPPE зі станами (stateful). " "Докладніший опис режиму MPPE зі станами наведено у документації із pppd." -#: ../clients/common/settings-docs.h.in:305 +#: ../clients/common/settings-docs.h.in:306 msgid "" "If non-zero, instruct pppd to request that the peer send packets no larger " "than the specified size. If non-zero, the MRU should be between 128 and " @@ -9721,20 +9723,20 @@ msgstr "" "щодо того, щоб він надсилав пакети, не більші за вказаний розмір. Якщо має " "ненульове значення, MRU має бути від 128 до 16384." -#: ../clients/common/settings-docs.h.in:306 +#: ../clients/common/settings-docs.h.in:307 msgid "" "If non-zero, instruct pppd to send packets no larger than the specified size." msgstr "" "Якщо має ненульове значення, наказує pppd надсилати пакети, не більші за " "вказаний розмір." -#: ../clients/common/settings-docs.h.in:307 +#: ../clients/common/settings-docs.h.in:308 msgid "If TRUE, Van Jacobsen TCP header compression will not be requested." msgstr "" "Якщо має значення TRUE, запит щодо стискання заголовків TCP ван Якобсена не " "надсилатиметься." -#: ../clients/common/settings-docs.h.in:308 +#: ../clients/common/settings-docs.h.in:309 msgid "" "If TRUE, do not require the other side (usually the PPP server) to " "authenticate itself to the client. If FALSE, require authentication from " @@ -9745,35 +9747,35 @@ msgstr "" "FALSE, вимагати проходження розпізнавання з боку віддаленого вузла. У " "більшості випадків слід використовувати значення TRUE." -#: ../clients/common/settings-docs.h.in:309 +#: ../clients/common/settings-docs.h.in:310 msgid "If TRUE, BSD compression will not be requested." msgstr "Якщо TRUE, стискання BSD не вимагатиметься." -#: ../clients/common/settings-docs.h.in:310 +#: ../clients/common/settings-docs.h.in:311 msgid "If TRUE, \"deflate\" compression will not be requested." msgstr "Якщо TRUE, стискання «deflate» не вимагатиметься." -#: ../clients/common/settings-docs.h.in:311 +#: ../clients/common/settings-docs.h.in:312 msgid "If TRUE, the CHAP authentication method will not be used." msgstr "Якщо TRUE, спосіб розпізнавання CHAP не використовуватиметься." -#: ../clients/common/settings-docs.h.in:312 +#: ../clients/common/settings-docs.h.in:313 msgid "If TRUE, the EAP authentication method will not be used." msgstr "Якщо TRUE, спосіб розпізнавання EAP не використовуватиметься." -#: ../clients/common/settings-docs.h.in:313 +#: ../clients/common/settings-docs.h.in:314 msgid "If TRUE, the MSCHAP authentication method will not be used." msgstr "Якщо TRUE, спосіб розпізнавання MSCHAP не використовуватиметься." -#: ../clients/common/settings-docs.h.in:314 +#: ../clients/common/settings-docs.h.in:315 msgid "If TRUE, the MSCHAPv2 authentication method will not be used." msgstr "Якщо TRUE, спосіб розпізнавання MSCHAPv2 не використовуватиметься." -#: ../clients/common/settings-docs.h.in:315 +#: ../clients/common/settings-docs.h.in:316 msgid "If TRUE, the PAP authentication method will not be used." msgstr "Якщо TRUE, спосіб розпізнавання PAP не використовуватиметься." -#: ../clients/common/settings-docs.h.in:316 +#: ../clients/common/settings-docs.h.in:317 msgid "" "If TRUE, MPPE (Microsoft Point-to-Point Encryption) will be required for the " "PPP session. If either 64-bit or 128-bit MPPE is not available the session " @@ -9784,7 +9786,7 @@ msgstr "" "128-бітове MPPE виявиться недоступним, сеанс не буде створено. Зауважте, що " "MPPE не використовується для мобільних широкосмугових з'єднань." -#: ../clients/common/settings-docs.h.in:317 +#: ../clients/common/settings-docs.h.in:318 msgid "" "If TRUE, 128-bit MPPE (Microsoft Point-to-Point Encryption) will be required " "for the PPP session, and the \"require-mppe\" property must also be set to " @@ -9795,7 +9797,7 @@ msgstr "" "для властивості «require-mppe» також має бути встановлено TRUE. Якщо 128-" "бітове MPPE виявиться недоступним, сеанс не буде створено." -#: ../clients/common/settings-docs.h.in:318 +#: ../clients/common/settings-docs.h.in:319 msgid "" "If given, specifies the parent interface name on which this PPPoE connection " "should be created. If this property is not specified, the connection is " @@ -9807,11 +9809,11 @@ msgstr "" "з'єднання буде активовано на інтерфейсі, який вказано за допомогою параметра " "«interface-name» NMSettingConnection." -#: ../clients/common/settings-docs.h.in:319 +#: ../clients/common/settings-docs.h.in:320 msgid "Password used to authenticate with the PPPoE service." msgstr "Пароль, який використовуватиметься для розпізнавання на службі PPPoE." -#: ../clients/common/settings-docs.h.in:321 +#: ../clients/common/settings-docs.h.in:322 msgid "" "If specified, instruct PPPoE to only initiate sessions with access " "concentrators that provide the specified service. For most providers, this " @@ -9824,33 +9826,33 @@ msgstr "" "якщо ви маєте справу із концентраторами із декількома способами доступу або " "відомо, що вказана служба є необхідною." -#: ../clients/common/settings-docs.h.in:322 +#: ../clients/common/settings-docs.h.in:323 msgid "Username used to authenticate with the PPPoE service." msgstr "" "Ім'я користувача, яке використовуватиметься для розпізнавання на службі " "PPPoE." -#: ../clients/common/settings-docs.h.in:323 +#: ../clients/common/settings-docs.h.in:324 msgid "Whether the proxy configuration is for browser only." msgstr "" "Визначає, чи використовуються налаштування проксі лише для програм для " "перегляду інтернету." -#: ../clients/common/settings-docs.h.in:324 +#: ../clients/common/settings-docs.h.in:325 msgid "" "Method for proxy configuration, Default is NM_SETTING_PROXY_METHOD_NONE (0)" msgstr "" "Спосіб налаштовування проксі. Типовим є NM_SETTING_PROXY_METHOD_NONE (0)" -#: ../clients/common/settings-docs.h.in:325 +#: ../clients/common/settings-docs.h.in:326 msgid "PAC script for the connection." msgstr "Скрипт PAC для з'єднання." -#: ../clients/common/settings-docs.h.in:326 +#: ../clients/common/settings-docs.h.in:327 msgid "PAC URL for obtaining PAC file." msgstr "Адреса PAC для отримання файла PAC." -#: ../clients/common/settings-docs.h.in:327 +#: ../clients/common/settings-docs.h.in:328 msgid "" "Speed to use for communication over the serial port. Note that this value " "usually has no effect for mobile broadband modems as they generally ignore " @@ -9861,20 +9863,20 @@ msgstr "" "загалом, для них параметри швидкості ігноруються — просто використовується " "найвища доступна швидкість." -#: ../clients/common/settings-docs.h.in:328 +#: ../clients/common/settings-docs.h.in:329 msgid "Byte-width of the serial communication. The 8 in \"8n1\" for example." msgstr "Байтова ширина послідовного обміну даними. Наприклад, 8 у «8n1»." -#: ../clients/common/settings-docs.h.in:329 +#: ../clients/common/settings-docs.h.in:330 msgid "Parity setting of the serial port." msgstr "Параметр парності послідовного порту." -#: ../clients/common/settings-docs.h.in:330 +#: ../clients/common/settings-docs.h.in:331 msgid "Time to delay between each byte sent to the modem, in microseconds." msgstr "" "Затримка у часі між надсиланнями одного байта на модем, у мікросекундах." -#: ../clients/common/settings-docs.h.in:331 +#: ../clients/common/settings-docs.h.in:332 msgid "" "Number of stop bits for communication on the serial port. Either 1 or 2. " "The 1 in \"8n1\" for example." @@ -9882,7 +9884,7 @@ msgstr "" "Кількість бітів зупинки для обміну даними на послідовному порту. Може мати " "значення 1 або 2. Наприклад, 1 у «8n1»." -#: ../clients/common/settings-docs.h.in:332 +#: ../clients/common/settings-docs.h.in:333 msgid "" "Whether to autoprobe virtual functions by a compatible driver. If set to " "NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver " @@ -9902,7 +9904,7 @@ msgstr "" "використовуватимуться загальні типові параметри. Якщо загальні типові " "параметри не вказано, припускатиметься варіант NM_TERNARY_TRUE (1)." -#: ../clients/common/settings-docs.h.in:333 +#: ../clients/common/settings-docs.h.in:334 msgid "" "The total number of virtual functions to create. Note that when the sriov " "setting is present NetworkManager enforces the number of virtual functions " @@ -9917,7 +9919,7 @@ msgstr "" "внесенню будь-яких змін до параметрів SR-IOV, не додавайте параметр sriov до " "параметрів з'єднання." -#: ../clients/common/settings-docs.h.in:334 +#: ../clients/common/settings-docs.h.in:335 msgid "" "Array of virtual function descriptors. Each VF descriptor is a dictionary " "mapping attribute names to GVariant values. The 'index' entry is mandatory " @@ -9943,15 +9945,15 @@ msgstr "" "форму: «ІДЕНТИФІКАТОР[.ПРІОРИТЕТНІСТЬ[.ПРОТОКОЛ]]». Значенням ПРОТОКОЛ може " "бути або «q» для 802.1Q (типовий варіант) або «ad» для 802.1ad." -#: ../clients/common/settings-docs.h.in:335 +#: ../clients/common/settings-docs.h.in:336 msgid "Array of TC queueing disciplines." msgstr "Масив дисциплін TC у черзі." -#: ../clients/common/settings-docs.h.in:336 +#: ../clients/common/settings-docs.h.in:337 msgid "Array of TC traffic filters." msgstr "Список TC фільтрів обміну даними." -#: ../clients/common/settings-docs.h.in:337 +#: ../clients/common/settings-docs.h.in:338 msgid "" "The JSON configuration for the team network interface. The property should " "contain raw JSON configuration data suitable for teamd, because the value is " @@ -9964,8 +9966,8 @@ msgstr "" "використовуватимуться типові налаштування. Щоб дізнатися більше про " "форматування даних, ознайомитеся із підручником (man) з teamd.conf." -#: ../clients/common/settings-docs.h.in:338 -#: ../clients/common/settings-docs.h.in:356 +#: ../clients/common/settings-docs.h.in:339 +#: ../clients/common/settings-docs.h.in:357 msgid "" "Link watchers configuration for the connection: each link watcher is defined " "by a dictionary, whose keys depend upon the selected link watcher. Available " @@ -9986,23 +9988,23 @@ msgstr "" "«validate-inactive», «send-always». Докладніше про це на сторінці підручника " "(man) щодо teamd.conf." -#: ../clients/common/settings-docs.h.in:339 +#: ../clients/common/settings-docs.h.in:340 msgid "Corresponds to the teamd mcast_rejoin.count." msgstr "Відповідає mcast_rejoin.count у teamd." -#: ../clients/common/settings-docs.h.in:340 +#: ../clients/common/settings-docs.h.in:341 msgid "Corresponds to the teamd mcast_rejoin.interval." msgstr "Відповідає mcast_rejoin.interval у teamd." -#: ../clients/common/settings-docs.h.in:341 +#: ../clients/common/settings-docs.h.in:342 msgid "Corresponds to the teamd notify_peers.count." msgstr "Відповідає notify_peers.count у teamd." -#: ../clients/common/settings-docs.h.in:342 +#: ../clients/common/settings-docs.h.in:343 msgid "Corresponds to the teamd notify_peers.interval." msgstr "Відповідає notify_peers.interval у teamd." -#: ../clients/common/settings-docs.h.in:343 +#: ../clients/common/settings-docs.h.in:344 msgid "" "Corresponds to the teamd runner.name. Permitted values are: \"roundrobin\", " "\"broadcast\", \"activebackup\", \"loadbalance\", \"lacp\", \"random\"." @@ -10010,43 +10012,43 @@ msgstr "" "Відповідає runner.name у teamd. Можливі такі значення: «roundrobin», " "«broadcast», «activebackup», «loadbalance», «lacp», «random»." -#: ../clients/common/settings-docs.h.in:344 +#: ../clients/common/settings-docs.h.in:345 msgid "Corresponds to the teamd runner.active." msgstr "Відповідає runner.active у teamd." -#: ../clients/common/settings-docs.h.in:345 +#: ../clients/common/settings-docs.h.in:346 msgid "Corresponds to the teamd runner.agg_select_policy." msgstr "Відповідає runner.agg_select_policy у teamd." -#: ../clients/common/settings-docs.h.in:346 +#: ../clients/common/settings-docs.h.in:347 msgid "Corresponds to the teamd runner.fast_rate." msgstr "Відповідає runner.fast_rate у teamd." -#: ../clients/common/settings-docs.h.in:347 +#: ../clients/common/settings-docs.h.in:348 msgid "Corresponds to the teamd runner.hwaddr_policy." msgstr "Відповідає runner.hwaddr_policy у teamd." -#: ../clients/common/settings-docs.h.in:348 +#: ../clients/common/settings-docs.h.in:349 msgid "Corresponds to the teamd runner.min_ports." msgstr "Відповідає runner.min_ports у teamd." -#: ../clients/common/settings-docs.h.in:349 +#: ../clients/common/settings-docs.h.in:350 msgid "Corresponds to the teamd runner.sys_prio." msgstr "Відповідає runner.sys_prio у teamd." -#: ../clients/common/settings-docs.h.in:350 +#: ../clients/common/settings-docs.h.in:351 msgid "Corresponds to the teamd runner.tx_balancer.name." msgstr "Відповідає runner.tx_balancer.name у teamd." -#: ../clients/common/settings-docs.h.in:351 +#: ../clients/common/settings-docs.h.in:352 msgid "Corresponds to the teamd runner.tx_balancer.interval." msgstr "Відповідає runner.tx_balancer.interval у teamd." -#: ../clients/common/settings-docs.h.in:352 +#: ../clients/common/settings-docs.h.in:353 msgid "Corresponds to the teamd runner.tx_hash." msgstr "Відповідає runner.tx_hash у teamd." -#: ../clients/common/settings-docs.h.in:353 +#: ../clients/common/settings-docs.h.in:354 msgid "" "The JSON configuration for the team port. The property should contain raw " "JSON configuration data suitable for teamd, because the value is passed " @@ -10059,19 +10061,19 @@ msgstr "" "використовуватимуться типові налаштування. Щоб дізнатися більше про " "форматування даних, ознайомитеся із підручником (man) з teamd.conf." -#: ../clients/common/settings-docs.h.in:354 +#: ../clients/common/settings-docs.h.in:355 msgid "Corresponds to the teamd ports.PORTIFNAME.lacp_key." msgstr "Відповідає ports.PORTIFNAME.lacp_key у teamd." -#: ../clients/common/settings-docs.h.in:355 +#: ../clients/common/settings-docs.h.in:356 msgid "Corresponds to the teamd ports.PORTIFNAME.lacp_prio." msgstr "Відповідає ports.PORTIFNAME.lacp_prio у teamd." -#: ../clients/common/settings-docs.h.in:357 +#: ../clients/common/settings-docs.h.in:358 msgid "Corresponds to the teamd ports.PORTIFNAME.prio." msgstr "Відповідає ports.PORTIFNAME.prio у teamd." -#: ../clients/common/settings-docs.h.in:358 +#: ../clients/common/settings-docs.h.in:359 msgid "" "Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means the " "parameter is skipped from the json config." @@ -10079,11 +10081,11 @@ msgstr "" "Відповідає ports.PORTIFNAME.queue_id у teamd. Значення -1 означає, що " "параметр пропускається у налаштуваннях json." -#: ../clients/common/settings-docs.h.in:359 +#: ../clients/common/settings-docs.h.in:360 msgid "Corresponds to the teamd ports.PORTIFNAME.sticky." msgstr "Відповідає ports.PORTIFNAME.sticky у teamd." -#: ../clients/common/settings-docs.h.in:360 +#: ../clients/common/settings-docs.h.in:361 msgid "" "The group ID which will own the device. If set to NULL everyone will be able " "to use the device." @@ -10091,7 +10093,7 @@ msgstr "" "Ідентифікатор групи-власника пристрою. Якщо встановлено значення NULL, " "пристроєм зможе користуватися будь-хто." -#: ../clients/common/settings-docs.h.in:361 +#: ../clients/common/settings-docs.h.in:362 msgid "" "The operating mode of the virtual device. Allowed values are " "NM_SETTING_TUN_MODE_TUN (1) to create a layer 3 device and " @@ -10101,7 +10103,7 @@ msgstr "" "NM_SETTING_TUN_MODE_TUN (1) для створення пристрою шару 3 і " "NM_SETTING_TUN_MODE_TAP (2) для створення пристрою Ethernet-подібного шару 2." -#: ../clients/common/settings-docs.h.in:362 +#: ../clients/common/settings-docs.h.in:363 msgid "" "If the property is set to TRUE, the interface will support multiple file " "descriptors (queues) to parallelize packet sending or receiving. Otherwise, " @@ -10112,7 +10114,7 @@ msgstr "" "надсилання або отримування пакетів. Якщо ж встановлено значення FALSE, " "інтерфейсом підтримуватиметься лише одна черга." -#: ../clients/common/settings-docs.h.in:363 +#: ../clients/common/settings-docs.h.in:364 msgid "" "The user ID which will own the device. If set to NULL everyone will be able " "to use the device." @@ -10120,7 +10122,7 @@ msgstr "" "Ідентифікатор користувача-власника пристрою. Якщо встановлено значення NULL, " "пристроєм зможе користуватися будь-хто." -#: ../clients/common/settings-docs.h.in:364 +#: ../clients/common/settings-docs.h.in:365 msgid "" "If TRUE the interface will prepend a 4 byte header describing the physical " "interface to the packets." @@ -10128,7 +10130,7 @@ msgstr "" "Якщо TRUE, інтерфейс дописуватиме на початку пакетів заголовок у 4 байти із " "описом фізичного інтерфейсу." -#: ../clients/common/settings-docs.h.in:365 +#: ../clients/common/settings-docs.h.in:366 msgid "" "If TRUE the IFF_VNET_HDR the tunnel packets will include a virtio network " "header." @@ -10136,7 +10138,7 @@ msgstr "" "Якщо IFF_VNET_HDR має значення TRUE, тунельовані пакети включатимуть " "заголовок мережі virtio." -#: ../clients/common/settings-docs.h.in:366 +#: ../clients/common/settings-docs.h.in:367 msgid "" "A dictionary of key/value pairs with user data. This data is ignored by " "NetworkManager and can be used at the users discretion. The keys only " @@ -10149,7 +10151,7 @@ msgstr "" "формату ASCII, але значення можуть бути довільними рядками UTF8, довжина " "яких не перевищує певного значення." -#: ../clients/common/settings-docs.h.in:367 +#: ../clients/common/settings-docs.h.in:368 msgid "" "For outgoing packets, a list of mappings from Linux SKB priorities to 802.1p " "priorities. The mapping is given in the format \"from:to\" where both \"from" @@ -10159,7 +10161,7 @@ msgstr "" "802.1p. Прив'язка визначається у форматі «з:до», де обидва значення, «з» і " "«до» є цілими додатними числами, наприклад «7:3»." -#: ../clients/common/settings-docs.h.in:368 +#: ../clients/common/settings-docs.h.in:369 msgid "" "One or more flags which control the behavior and features of the VLAN " "interface. Flags include NM_VLAN_FLAG_REORDER_HEADERS (0x1) (reordering of " @@ -10181,7 +10183,7 @@ msgstr "" "зберегти зворотну сумісність, типовим значенням у програмному інтерфейсі D-" "Bus лишається 0, а нестача властивості у D-Bus також розглядається як 0." -#: ../clients/common/settings-docs.h.in:369 +#: ../clients/common/settings-docs.h.in:370 msgid "" "The VLAN identifier that the interface created by this connection should be " "assigned. The valid range is from 0 to 4094, without the reserved id 4095." @@ -10190,7 +10192,7 @@ msgstr "" "з'єднанням. Коректним діапазоном є діапазон від 0 до 4094, без " "зарезервованого ідентифікатора 4095." -#: ../clients/common/settings-docs.h.in:370 +#: ../clients/common/settings-docs.h.in:371 msgid "" "For incoming packets, a list of mappings from 802.1p priorities to Linux SKB " "priorities. The mapping is given in the format \"from:to\" where both \"from" @@ -10200,7 +10202,7 @@ msgstr "" "Linux. Прив'язка визначається у форматі «з:до», де обидва значення, «з» і " "«до» є цілими додатними числами, наприклад «7:3»." -#: ../clients/common/settings-docs.h.in:371 +#: ../clients/common/settings-docs.h.in:372 msgid "" "If given, specifies the parent interface name or parent connection UUID from " "which this VLAN interface should be created. If this property is not " @@ -10212,7 +10214,7 @@ msgstr "" "значення для цієї властивості не вказано, запис з'єднання має містити " "параметр «802-3-ethernet» із властивістю «mac-address»." -#: ../clients/common/settings-docs.h.in:372 +#: ../clients/common/settings-docs.h.in:373 msgid "" "Dictionary of key/value pairs of VPN plugin specific data. Both keys and " "values must be strings." @@ -10220,7 +10222,7 @@ msgstr "" "Словник із пар ключ-значення для специфічних даних додатка VPN. Величинами " "ключа і значення можуть бути лише текстові рядки." -#: ../clients/common/settings-docs.h.in:373 +#: ../clients/common/settings-docs.h.in:374 msgid "" "If the VPN service supports persistence, and this property is TRUE, the VPN " "will attempt to stay connected across link changes and outages, until " @@ -10231,7 +10233,7 @@ msgstr "" "час зміни параметрів зв'язку або неможливості обміну даними, аж доки " "з'єднання не буде розірвано явним чином." -#: ../clients/common/settings-docs.h.in:374 +#: ../clients/common/settings-docs.h.in:375 msgid "" "Dictionary of key/value pairs of VPN plugin specific secrets like passwords " "or private keys. Both keys and values must be strings." @@ -10240,7 +10242,7 @@ msgstr "" "VPN, зокрема паролів або закритих ключів. Величинами ключа і значення можуть " "бути лише текстові рядки." -#: ../clients/common/settings-docs.h.in:375 +#: ../clients/common/settings-docs.h.in:376 msgid "" "D-Bus service name of the VPN plugin that this setting uses to connect to " "its network. i.e. org.freedesktop.NetworkManager.vpnc for the vpnc plugin." @@ -10249,7 +10251,7 @@ msgstr "" "додатка з його мережею. Приклад: org.freedesktop.NetworkManager.vpnc для " "додатка vpnc." -#: ../clients/common/settings-docs.h.in:376 +#: ../clients/common/settings-docs.h.in:377 msgid "" "Timeout for the VPN service to establish the connection. Some services may " "take quite a long time to connect. Value of 0 means a default timeout, which " @@ -10262,7 +10264,7 @@ msgstr "" "допомогою параметра vpn.timeout у файлі налаштувань). Значення, які " "перевищують нуль, визначають час очікування у секундах." -#: ../clients/common/settings-docs.h.in:377 +#: ../clients/common/settings-docs.h.in:378 msgid "" "If the VPN connection requires a user name for authentication, that name " "should be provided here. If the connection is available to more than one " @@ -10278,15 +10280,15 @@ msgstr "" "порожнє, NetworkManager автоматично використає ім'я користувача, який " "надіслав запит щодо встановлення з'єднання VPN." -#: ../clients/common/settings-docs.h.in:378 +#: ../clients/common/settings-docs.h.in:379 msgid "The routing table for this VRF." msgstr "Таблиця маршрутизації для цього VRF." -#: ../clients/common/settings-docs.h.in:379 +#: ../clients/common/settings-docs.h.in:380 msgid "Specifies the lifetime in seconds of FDB entries learnt by the kernel." msgstr "Визначає час життя у секундах записів FDB, вивчених ядром." -#: ../clients/common/settings-docs.h.in:380 +#: ../clients/common/settings-docs.h.in:381 msgid "" "Specifies the UDP destination port to communicate to the remote VXLAN tunnel " "endpoint." @@ -10294,22 +10296,22 @@ msgstr "" "Визначає порт призначення UDP для обміну даними із віддаленою кінцевою " "точкою тунелю VXLAN." -#: ../clients/common/settings-docs.h.in:381 +#: ../clients/common/settings-docs.h.in:382 msgid "" "Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to use." msgstr "" "Визначає ідентифікатор мережі VXLAN (або ідентифікатор сегмента VXLAN), яким " "слід скористатися." -#: ../clients/common/settings-docs.h.in:382 +#: ../clients/common/settings-docs.h.in:383 msgid "Specifies whether netlink LL ADDR miss notifications are generated." msgstr "Визначає, чи будуть створюватися сповіщення netlink LL ADDR miss." -#: ../clients/common/settings-docs.h.in:383 +#: ../clients/common/settings-docs.h.in:384 msgid "Specifies whether netlink IP ADDR miss notifications are generated." msgstr "Визначає, чи будуть створюватися сповіщення netlink IP ADDR miss." -#: ../clients/common/settings-docs.h.in:384 +#: ../clients/common/settings-docs.h.in:385 msgid "" "Specifies whether unknown source link layer addresses and IP addresses are " "entered into the VXLAN device forwarding database." @@ -10317,7 +10319,7 @@ msgstr "" "Вказує, чи вводяться невідомі адреси шару посилань та IP-адреси до бази " "даних переспрямовування пристроїв VXLAN." -#: ../clients/common/settings-docs.h.in:385 +#: ../clients/common/settings-docs.h.in:386 msgid "" "Specifies the maximum number of FDB entries. A value of zero means that the " "kernel will store unlimited entries." @@ -10325,24 +10327,24 @@ msgstr "" "Вказує максимальну кількість записів FDB. Нульове значення означає, що ядро " "зберігатиме необмежену кількість записів." -#: ../clients/common/settings-docs.h.in:386 +#: ../clients/common/settings-docs.h.in:387 msgid "If given, specifies the source IP address to use in outgoing packets." msgstr "" "Якщо задано, визначає початкову IP-адресу, якою слід скористатися для " "вихідних пакетів." -#: ../clients/common/settings-docs.h.in:387 +#: ../clients/common/settings-docs.h.in:388 msgid "" "If given, specifies the parent interface name or parent connection UUID." msgstr "" "Якщо задано, визначає назву батьківського інтерфейсу або UUID батьківського " "з'єднання." -#: ../clients/common/settings-docs.h.in:388 +#: ../clients/common/settings-docs.h.in:389 msgid "Specifies whether ARP proxy is turned on." msgstr "Визначає, чи увімкнено ARP-проксі." -#: ../clients/common/settings-docs.h.in:389 +#: ../clients/common/settings-docs.h.in:390 msgid "" "Specifies the unicast destination IP address to use in outgoing packets when " "the destination link layer address is not known in the VXLAN device " @@ -10353,11 +10355,11 @@ msgstr "" "переспрямовування пристроїв VXLAN, або IP-адреса універсальної трансляції, з " "якою слід встановити зв'язок." -#: ../clients/common/settings-docs.h.in:390 +#: ../clients/common/settings-docs.h.in:391 msgid "Specifies whether route short circuit is turned on." msgstr "Визначає, чи увімкнено коротке замикання маршруту." -#: ../clients/common/settings-docs.h.in:391 +#: ../clients/common/settings-docs.h.in:392 msgid "" "Specifies the maximum UDP source port to communicate to the remote VXLAN " "tunnel endpoint." @@ -10365,7 +10367,7 @@ msgstr "" "Визначає максимальний початковий порт UDP для обміну даними із віддаленою " "кінцевою точкою тунелю VXLAN." -#: ../clients/common/settings-docs.h.in:392 +#: ../clients/common/settings-docs.h.in:393 msgid "" "Specifies the minimum UDP source port to communicate to the remote VXLAN " "tunnel endpoint." @@ -10373,16 +10375,16 @@ msgstr "" "Визначає мінімальний початковий порт UDP для обміну даними із віддаленою " "кінцевою точкою тунелю VXLAN." -#: ../clients/common/settings-docs.h.in:393 +#: ../clients/common/settings-docs.h.in:394 msgid "Specifies the TOS value to use in outgoing packets." msgstr "Визначає значення TOS, яке слід використовувати для вихідних пакетів." -#: ../clients/common/settings-docs.h.in:394 +#: ../clients/common/settings-docs.h.in:395 msgid "Specifies the time-to-live value to use in outgoing packets." msgstr "" "Визначає значення часу життя, яке слід використовувати для вихідних пакетів." -#: ../clients/common/settings-docs.h.in:395 +#: ../clients/common/settings-docs.h.in:396 msgid "" "The P2P device that should be connected to. Currently this is the only way " "to create or join a group." @@ -10390,7 +10392,7 @@ msgstr "" "Пристрій P2P, з яким слід встановити з'єднання. У поточній версії це єдиний " "спосіб створення групи або долучення до неї." -#: ../clients/common/settings-docs.h.in:396 +#: ../clients/common/settings-docs.h.in:397 msgid "" "The Wi-Fi Display (WFD) Information Elements (IEs) to set. Wi-Fi Display " "requires a protocol specific information element to be set in certain Wi-Fi " @@ -10404,7 +10406,7 @@ msgstr "" "Вказати ці елементи з метою встановлення з'єднання можна тут. Цей параметр є " "корисним лише для реалізації клієнта дисплея Wi-Fi." -#: ../clients/common/settings-docs.h.in:397 +#: ../clients/common/settings-docs.h.in:398 msgid "" "Flags indicating which mode of WPS is to be used. There's little point in " "changing the default setting as NetworkManager will automatically determine " @@ -10414,7 +10416,7 @@ msgstr "" "типове значення не варто, оскільки NetworkManager автоматично визначає " "найкращий режим." -#: ../clients/common/settings-docs.h.in:398 +#: ../clients/common/settings-docs.h.in:399 msgid "" "If specified, this connection will only apply to the WiMAX device whose MAC " "address matches. This property does not change the MAC address of the device " @@ -10424,7 +10426,7 @@ msgstr "" "відповідною адресою MAC. Ця властивість не змінює MAC-адреси пристрою (таку " "зміну називають підміною MAC). Застаріле: 1" -#: ../clients/common/settings-docs.h.in:399 +#: ../clients/common/settings-docs.h.in:400 msgid "" "Network Service Provider (NSP) name of the WiMAX network this connection " "should use. Deprecated: 1" @@ -10432,7 +10434,7 @@ msgstr "" "Назва надавача мережевих послуг (NSP) для мережі WiMAX, яку має " "використовувати це з'єднання. Застаріле: 1" -#: ../clients/common/settings-docs.h.in:400 +#: ../clients/common/settings-docs.h.in:401 msgid "" "The use of fwmark is optional and is by default off. Setting it to 0 " "disables it. Otherwise it is a 32-bit fwmark for outgoing packets. Note that " @@ -10444,7 +10446,7 @@ msgstr "" "fwmark для вихідних пакетів. Зауважте, що вмикання «ip4-auto-default-route» " "або «ip6-auto-default-route» неявним чином призводить до вибору fwmark." -#: ../clients/common/settings-docs.h.in:401 +#: ../clients/common/settings-docs.h.in:402 msgid "" "Whether to enable special handling of the IPv4 default route. If enabled, " "the IPv4 default route from wireguard.peer-routes will be placed to a " @@ -10472,11 +10474,11 @@ msgstr "" "і не буде жодного вузла, який використовує типовий маршрут (default-route) у " "дозволених IP-адресах (allowed-ips)." -#: ../clients/common/settings-docs.h.in:402 +#: ../clients/common/settings-docs.h.in:403 msgid "Like ip4-auto-default-route, but for the IPv6 default route." msgstr "Те саме, що ip4-auto-default-route, але для типового маршруту IPv6." -#: ../clients/common/settings-docs.h.in:403 +#: ../clients/common/settings-docs.h.in:404 msgid "" "The listen-port. If listen-port is not specified, the port will be chosen " "randomly when the interface comes up." @@ -10484,7 +10486,7 @@ msgstr "" "Порт для очікування на дані. Якщо порт для очікування на дані не вказано, " "номер буде вибрано випадковим чином під час підняття інтерфейсу." -#: ../clients/common/settings-docs.h.in:404 +#: ../clients/common/settings-docs.h.in:405 msgid "" "If non-zero, only transmit packets of the specified size or smaller, " "breaking larger packets up into multiple fragments. If zero a default MTU is " @@ -10497,7 +10499,7 @@ msgstr "" "відміну від параметра MTU wg-quick, тут не беруться до уваги поточні " "маршрути на момент активації." -#: ../clients/common/settings-docs.h.in:405 +#: ../clients/common/settings-docs.h.in:406 msgid "" "Whether to automatically add routes for the AllowedIPs ranges of the peers. " "If TRUE (the default), NetworkManager will automatically add routes in the " @@ -10519,15 +10521,15 @@ msgstr "" "«0.0.0.0/0» або «::/0», а для профілю увімкнено ipv4.never-default або ipv6." "never-default, маршрут вузла для цього вузла не буде додано автоматично." -#: ../clients/common/settings-docs.h.in:406 +#: ../clients/common/settings-docs.h.in:407 msgid "The 256 bit private-key in base64 encoding." msgstr "256-бітовий закритий ключ у кодуванні base64." -#: ../clients/common/settings-docs.h.in:407 +#: ../clients/common/settings-docs.h.in:408 msgid "Flags indicating how to handle the \"private-key\" property." msgstr "Прапорці, які позначають, як обробляти властивість «private-key»." -#: ../clients/common/settings-docs.h.in:408 +#: ../clients/common/settings-docs.h.in:409 msgid "" "IEEE 802.15.4 channel. A positive integer or -1, meaning \"do not set, use " "whatever the device is already set to\"." @@ -10535,7 +10537,7 @@ msgstr "" "Канал IEEE 802.15.4. Додане ціле значення або -1, що означає «не " "встановлювати, використовувати той, який вже встановлено пристроєм»." -#: ../clients/common/settings-docs.h.in:409 +#: ../clients/common/settings-docs.h.in:410 msgid "" "If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) " "MAC layer device whose permanent MAC address matches." @@ -10543,7 +10545,7 @@ msgstr "" "Якщо вказано, це з'єднання застосовуватиметься лише до пристрою шару MAC " "IEEE 802.15.4 (WPAN) із відповідною сталою адресою MAC." -#: ../clients/common/settings-docs.h.in:410 +#: ../clients/common/settings-docs.h.in:411 msgid "" "IEEE 802.15.4 channel page. A positive integer or -1, meaning \"do not set, " "use whatever the device is already set to\"." @@ -10551,11 +10553,11 @@ msgstr "" "Сторінка каналу IEEE 80215.4. Додане ціле значення або -1, що означає «не " "встановлювати, використовувати ту, яку вже встановлено пристроєм»." -#: ../clients/common/settings-docs.h.in:411 +#: ../clients/common/settings-docs.h.in:412 msgid "IEEE 802.15.4 Personal Area Network (PAN) identifier." msgstr "Ідентифікатор Personal Area Network (PAN) IEEE 802.15.4." -#: ../clients/common/settings-docs.h.in:412 +#: ../clients/common/settings-docs.h.in:413 msgid "Short IEEE 802.15.4 address to be used within a restricted environment." msgstr "" "Коротка адреса IEEE 802.15.4, яку слід використовувати у обмеженому " @@ -10633,7 +10635,7 @@ msgstr "Помилка редактора: %s" msgid "Could not re-read file: %s" msgstr "Не вдалося повторно прочитати файл: %s" -#: ../clients/tui/nm-editor-utils.c:135 ../libnm/nm-device.c:1522 +#: ../clients/tui/nm-editor-utils.c:135 ../libnm/nm-device.c:1567 msgid "Ethernet" msgstr "Ethernet" @@ -10642,7 +10644,7 @@ msgstr "Ethernet" msgid "Ethernet connection %d" msgstr "З'єднання Ethernet %d" -#: ../clients/tui/nm-editor-utils.c:143 ../libnm/nm-device.c:1524 +#: ../clients/tui/nm-editor-utils.c:143 ../libnm/nm-device.c:1569 msgid "Wi-Fi" msgstr "Wi-Fi" @@ -10652,7 +10654,7 @@ msgid "Wi-Fi connection %d" msgstr "З'єднання Wi-Fi %d" #: ../clients/tui/nm-editor-utils.c:152 ../libnm-core/nm-connection.c:2713 -#: ../libnm/nm-device.c:1540 +#: ../libnm/nm-device.c:1585 msgid "InfiniBand" msgstr "InfiniBand" @@ -10661,7 +10663,7 @@ msgstr "InfiniBand" msgid "InfiniBand connection %d" msgstr "З'єднання InfiniBand %d" -#: ../clients/tui/nm-editor-utils.c:161 ../libnm/nm-device.c:1538 +#: ../clients/tui/nm-editor-utils.c:161 ../libnm/nm-device.c:1583 msgid "Mobile Broadband" msgstr "Мобільна радіомережа" @@ -10680,8 +10682,8 @@ msgid "DSL connection %d" msgstr "З'єднання DSL %d" #: ../clients/tui/nm-editor-utils.c:179 ../libnm-core/nm-connection.c:2705 -#: ../libnm/nm-device.c:1542 -#: ../src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5177 +#: ../libnm/nm-device.c:1587 +#: ../src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5216 msgid "Bond" msgstr "Прив'язка" @@ -10691,8 +10693,8 @@ msgid "Bond connection %d" msgstr "Прив'язане з'єднання %d" #: ../clients/tui/nm-editor-utils.c:188 ../libnm-core/nm-connection.c:2709 -#: ../libnm/nm-device.c:1546 -#: ../src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5560 +#: ../libnm/nm-device.c:1591 +#: ../src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5599 msgid "Bridge" msgstr "Місток" @@ -10702,8 +10704,8 @@ msgid "Bridge connection %d" msgstr "З'єднання містка %d" #: ../clients/tui/nm-editor-utils.c:197 ../libnm-core/nm-connection.c:2707 -#: ../libnm/nm-device.c:1544 -#: ../src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5250 +#: ../libnm/nm-device.c:1589 +#: ../src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5289 msgid "Team" msgstr "Команда" @@ -10713,7 +10715,7 @@ msgid "Team connection %d" msgstr "Командне з'єднання %d" #: ../clients/tui/nm-editor-utils.c:206 ../clients/tui/nmt-page-vlan.c:69 -#: ../libnm-core/nm-connection.c:2711 ../libnm/nm-device.c:1548 +#: ../libnm-core/nm-connection.c:2711 ../libnm/nm-device.c:1593 msgid "VLAN" msgstr "VLAN" @@ -11397,7 +11399,6 @@ msgstr "Не вдалося активувати: %s" #: ../clients/tui/nmtui-connect.c:230 #, c-format -#| msgid "Could not activate connection: %s" msgid "Could not deactivate connection: %s" msgstr "Не вдалося вимкнути з'єднання: %s" @@ -11896,7 +11897,7 @@ msgstr "неочікуваний UUID %s замість %s" #: ../libnm-core/nm-setting-connection.c:975 #: ../libnm-core/nm-setting-connection.c:1004 #: ../libnm-core/nm-setting-connection.c:1266 -#: ../libnm-core/nm-setting-ip-config.c:4935 +#: ../libnm-core/nm-setting-ip-config.c:4974 #: ../libnm-core/nm-setting-ip-tunnel.c:367 #: ../libnm-core/nm-setting-olpc-mesh.c:84 #: ../libnm-core/nm-setting-ovs-patch.c:77 ../libnm-core/nm-setting-pppoe.c:130 @@ -11916,6 +11917,280 @@ msgstr "IP-тунель" msgid "Method returned type '%s', but expected '%s'" msgstr "Методом повернуто тип «%s», хоча мав бути «%s»" +#: ../libnm-core/nm-keyfile/nm-keyfile-utils.c:171 +#, c-format +msgid "Value cannot be interpreted as a list of numbers." +msgstr "Значення не може бути оброблено як список чисел." + +#: ../libnm-core/nm-keyfile/nm-keyfile-utils.c:307 +#, c-format +msgid "value is not an integer in range [%lld, %lld]" +msgstr "значення не є цілим числом у діапазоні [%lld, %lld]" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:271 +msgid "ignoring missing number" +msgstr "ігноруємо пропущене число" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:283 +#, c-format +msgid "ignoring invalid number '%s'" +msgstr "ігноруємо некоректне число «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:312 +#, c-format +msgid "ignoring invalid %s address: %s" +msgstr "ігноруємо некоректну адресу %s: %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:359 +#, c-format +msgid "ignoring invalid gateway '%s' for %s route" +msgstr "ігноруємо некоректний шлюз «%s» для маршруту %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:391 +#, c-format +msgid "ignoring invalid %s route: %s" +msgstr "ігноруємо некоректний маршрут %s: %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:566 +#, c-format +msgid "unexpected character '%c' for address %s: '%s' (position %td)" +msgstr "неочікуваний символ «%c» для адреси %s: «%s» (позиція %td)" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:582 +#, c-format +msgid "unexpected character '%c' for %s: '%s' (position %td)" +msgstr "неочікуваний символ «%c» для %s: «%s» (позиція %td)" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:597 +#, c-format +msgid "unexpected character '%c' in prefix length for %s: '%s' (position %td)" +msgstr "неочікуваний символ «%c» у префіксі довжини для %s: «%s» (позиція %td)" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:614 +#, c-format +msgid "garbage at the end of value %s: '%s'" +msgstr "зайві дані наприкінці значення %s: «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:624 +#, c-format +msgid "deprecated semicolon at the end of value %s: '%s'" +msgstr "застаріла крапка з комою наприкінці значення %s: «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:647 +#, c-format +msgid "invalid prefix length for %s '%s', defaulting to %d" +msgstr "некоректний префікс довжини для %s «%s», повертаємося до типового, %d" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:659 +#, c-format +msgid "missing prefix length for %s '%s', defaulting to %d" +msgstr "пропущено префікс довжини для %s «%s», повертаємося до типового, %d" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1001 +#: ../libnm-core/nm-setting-user.c:358 +#, c-format +msgid "invalid value for \"%s\": %s" +msgstr "некоректне значення для «%s»: %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1041 +#, c-format +msgid "ignoring invalid DNS server IPv%c address '%s'" +msgstr "ігноруємо некоректну адресу IPv%c сервера DNS «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1132 +msgid "ignoring invalid MAC address" +msgstr "ігноруємо некоректну MAC-адресу" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1391 +msgid "ignoring invalid SSID" +msgstr "ігноруємо некоректний SSID" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1409 +msgid "ignoring invalid raw password" +msgstr "ігноруємо некоректний необроблений пароль" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1554 +msgid "invalid key/cert value" +msgstr "некоректне значення ключа/сертифіката" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1568 +#, c-format +msgid "invalid key/cert value path \"%s\"" +msgstr "некоректний шлях до ключа/сертифіката, «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1592 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1688 +#, c-format +msgid "certificate or key file '%s' does not exist" +msgstr "файла сертифіката або ключа «%s» не існує" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1604 +#, c-format +msgid "invalid PKCS#11 URI \"%s\"" +msgstr "некоректна адреса PKCS#11 «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1652 +msgid "invalid key/cert value data:;base64, is not base64" +msgstr "некоректні дані значення ключа/сертифіката data:;base64, не є base64" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1664 +msgid "invalid key/cert value data:;base64,file://" +msgstr "некоректне значення ключа/сертифіката data:;base64,file://" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1703 +msgid "invalid key/cert value is not a valid blob" +msgstr "" +"некоректне значення ключа/сертифіката, не є коректним значення «%s» не є " +"коректним великим бінарним об'єктом" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1808 +#, c-format +msgid "invalid parity value '%s'" +msgstr "некоректне значення парності, «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1826 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3391 +#, c-format +msgid "invalid setting: %s" +msgstr "некоректний параметр: %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1847 +#, c-format +msgid "ignoring invalid team configuration: %s" +msgstr "ігноруємо некоректне налаштування команди: %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1932 +#, c-format +msgid "invalid qdisc: %s" +msgstr "некоректний qdisc: %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:1981 +#, c-format +msgid "invalid tfilter: %s" +msgstr "некоректний tfilter: %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3234 +#, c-format +msgid "error loading setting value: %s" +msgstr "помилка під час завантаження значення параметра: %s" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3262 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3273 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3291 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3302 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3313 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3365 +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3376 +msgid "value cannot be interpreted as integer" +msgstr "значення не може бути оброблено як ціле число" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3338 +#, c-format +msgid "ignoring invalid byte element '%u' (not between 0 and 255 inclusive)" +msgstr "" +"ігноруємо некоректний байтовий елемент «%u» (не у діапазоні від 0 до 255, " +"включно)" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3416 +#, c-format +msgid "invalid setting name '%s'" +msgstr "некоректна назва параметра, «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3465 +#, c-format +msgid "invalid key '%s.%s'" +msgstr "некоректний ключ «%s.%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3484 +#, c-format +msgid "key '%s.%s' is not boolean" +msgstr "ключ «%s.%s» не є булевим значенням" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3504 +#, c-format +msgid "key '%s.%s' is not a uint32" +msgstr "ключ «%s.%s» не є значенням uint32" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3565 +#, c-format +msgid "invalid peer public key in section '%s'" +msgstr "некоректний відкритий ключ вузла у розділі «%s»" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3580 +#, c-format +msgid "key '%s.%s' is not a valid 256 bit key in base64 encoding" +msgstr "ключ «%s.%s» не є коректним 256-бітовим ключем у кодуванні base64" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3597 +#, c-format +msgid "key '%s.%s' is not a valid secret flag" +msgstr "ключ «%s.%s» не є коректним прапорцем реєстраційних даних" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3613 +#, c-format +msgid "key '%s.%s' is not a integer in range 0 to 2^32" +msgstr "ключ «%s.%s» не є цілими числом у діапазоні від 0 до 2^32" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3629 +#, c-format +msgid "key '%s.%s' is not a valid endpoint" +msgstr "ключ «%s.%s» не є коректною кінцевою точкою" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3655 +#, c-format +msgid "key '%s.%s' has invalid allowed-ips" +msgstr "для ключа «%s.%s» вказано некоректне значення allowed-ips" + +#: ../libnm-core/nm-keyfile/nm-keyfile.c:3670 +#, c-format +msgid "peer '%s' is invalid: %s" +msgstr "вузол «%s» є некоректним: %s" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:221 +#, c-format +msgid "'%s' is not valid: properties should be specified as 'key=value'" +msgstr "" +"«%s» є некоректним: властивості має бути вказано у форматі «ключ=значення»" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:236 +#, c-format +msgid "'%s' is not a valid key" +msgstr "«%s» не є коректним ключем" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:242 +#, c-format +msgid "duplicate key '%s'" +msgstr "дублікат ключа «%s»" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:256 +#, c-format +msgid "number for '%s' is out of range" +msgstr "число для «%s» лежить поза припустимим діапазоном" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:259 +#, c-format +msgid "value for '%s' must be a number" +msgstr "значення «%s» має бути числом" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:270 +#, c-format +msgid "value for '%s' must be a boolean" +msgstr "значення «%s» має бути булевим" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:279 +msgid "missing 'name' attribute" +msgstr "пропущено атрибут «name»" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:286 +#, c-format +msgid "invalid 'name' \"%s\"" +msgstr "некоректне значення «name» — «%s»" + +#: ../libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c:298 +#, c-format +msgid "attribute '%s' is invalid for \"%s\"" +msgstr "атрибут «%s» є некоректним для «%s»" + #: ../libnm-core/nm-setting-6lowpan.c:79 #, c-format msgid "property is not specified" @@ -11991,7 +12266,7 @@ msgstr "" #: ../libnm-core/nm-setting-connection.c:1238 #: ../libnm-core/nm-setting-gsm.c:283 ../libnm-core/nm-setting-gsm.c:341 #: ../libnm-core/nm-setting-gsm.c:378 ../libnm-core/nm-setting-gsm.c:387 -#: ../libnm-core/nm-setting-ip-config.c:4942 +#: ../libnm-core/nm-setting-ip-config.c:4981 #: ../libnm-core/nm-setting-ip4-config.c:167 #: ../libnm-core/nm-setting-ip4-config.c:174 #: ../libnm-core/nm-setting-pppoe.c:137 ../libnm-core/nm-setting-pppoe.c:146 @@ -12096,7 +12371,6 @@ msgid "'%s=%s' is not a valid configuration for '%s'" msgstr "«%s=%s» не є коректним налаштуванням для «%s»" #: ../libnm-core/nm-setting-bond.c:877 ../libnm-core/nm-setting-bond.c:890 -#: ../libnm-core/nm-setting-bridge.c:1295 #, c-format msgid "'%s' option requires '%s' option to be enabled" msgstr "використання параметра «%s» вимагає вмикання параметра «%s»" @@ -12182,7 +12456,7 @@ msgstr "не є коректним протоколом фільтрування msgid "is not a valid option" msgstr "не є коректним параметром" -#: ../libnm-core/nm-setting-bridge.c:1306 +#: ../libnm-core/nm-setting-bridge.c:1292 #, c-format msgid "'%s' option must be a power of 2" msgstr "Значенням параметра «%s» має бути степінь 2" @@ -12306,12 +12580,10 @@ msgid "unsupported ethtool setting" msgstr "непідтримуваний параметр ethtool" #: ../libnm-core/nm-setting-ethtool.c:311 -#| msgid "coalesce setting has invalid variant type" msgid "setting has invalid variant type" msgstr "для параметра вказано некоректний тип варіанта" #: ../libnm-core/nm-setting-ethtool.c:323 -#| msgid "'%s' option must be a power of 2" msgid "coalesce option must be either 0 or 1" msgstr "значенням параметра coalesce має бути 0 або 1" @@ -12411,252 +12683,270 @@ msgstr "Некоректний префікс адреси IPv6, «%u»" msgid "Invalid routing metric '%s'" msgstr "Некоректна метрика маршрутизації, «%s»" -#: ../libnm-core/nm-setting-ip-config.c:1271 +#: ../libnm-core/nm-setting-ip-config.c:1272 #: ../libnm-core/nm-setting-sriov.c:413 msgid "unknown attribute" msgstr "невідомий атрибут" -#: ../libnm-core/nm-setting-ip-config.c:1281 +#: ../libnm-core/nm-setting-ip-config.c:1282 #: ../libnm-core/nm-setting-sriov.c:423 #, c-format msgid "invalid attribute type '%s'" msgstr "некоректний тип атрибута «%s»" -#: ../libnm-core/nm-setting-ip-config.c:1292 +#: ../libnm-core/nm-setting-ip-config.c:1293 #, c-format msgid "attribute is not valid for a IPv4 route" msgstr "атрибут не є коректним для маршрутизації IPv4" -#: ../libnm-core/nm-setting-ip-config.c:1293 +#: ../libnm-core/nm-setting-ip-config.c:1294 #, c-format msgid "attribute is not valid for a IPv6 route" msgstr "атрибут не є коректним для маршрутизації IPv6" -#: ../libnm-core/nm-setting-ip-config.c:1307 -#: ../libnm-core/nm-setting-ip-config.c:1335 +#: ../libnm-core/nm-setting-ip-config.c:1308 +#: ../libnm-core/nm-setting-ip-config.c:1336 #, c-format msgid "'%s' is not a valid IPv4 address" msgstr "«%s» не є коректною адресою IPv4" -#: ../libnm-core/nm-setting-ip-config.c:1308 -#: ../libnm-core/nm-setting-ip-config.c:1336 +#: ../libnm-core/nm-setting-ip-config.c:1309 +#: ../libnm-core/nm-setting-ip-config.c:1337 #, c-format msgid "'%s' is not a valid IPv6 address" msgstr "«%s» не є коректною адресою IPv6" -#: ../libnm-core/nm-setting-ip-config.c:1326 +#: ../libnm-core/nm-setting-ip-config.c:1327 #, c-format msgid "invalid prefix %s" msgstr "некоректний префікс %s" -#: ../libnm-core/nm-setting-ip-config.c:2502 +#: ../libnm-core/nm-setting-ip-config.c:1350 +#, c-format +#| msgid "'%s' is not a valid interface type" +msgid "%s is not a valid route type" +msgstr "%s не є коректним типом маршруту" + +#: ../libnm-core/nm-setting-ip-config.c:1400 +#, c-format +#| msgid "%d. route is invalid" +msgid "route scope is invalid" +msgstr "область маршрутів є некоректною" + +#: ../libnm-core/nm-setting-ip-config.c:2541 msgid "invalid priority" msgstr "некоректна пріоритетність" -#: ../libnm-core/nm-setting-ip-config.c:2513 +#: ../libnm-core/nm-setting-ip-config.c:2552 msgid "missing table" msgstr "не вказано таблиці" -#: ../libnm-core/nm-setting-ip-config.c:2519 +#: ../libnm-core/nm-setting-ip-config.c:2558 msgid "invalid action" msgstr "некоректна дія" -#: ../libnm-core/nm-setting-ip-config.c:2526 +#: ../libnm-core/nm-setting-ip-config.c:2565 msgid "has from/src but the prefix-length is zero" msgstr "" "містить from/src, але значення довжини префікса (prefix-length) є нульовим" -#: ../libnm-core/nm-setting-ip-config.c:2533 +#: ../libnm-core/nm-setting-ip-config.c:2572 msgid "missing from/src for a non zero prefix-length" msgstr "пропущено from/src для ненульового значення довжини префікса" -#: ../libnm-core/nm-setting-ip-config.c:2538 +#: ../libnm-core/nm-setting-ip-config.c:2577 msgid "invalid from/src" msgstr "некоректне значення from/src" -#: ../libnm-core/nm-setting-ip-config.c:2543 +#: ../libnm-core/nm-setting-ip-config.c:2582 msgid "invalid prefix length for from/src" msgstr "некоректна довжина префікса для from/src" -#: ../libnm-core/nm-setting-ip-config.c:2550 +#: ../libnm-core/nm-setting-ip-config.c:2589 msgid "has to/dst but the prefix-length is zero" msgstr "" "містить to/dst, але значення довжини префікса (prefix-length) є нульовим" -#: ../libnm-core/nm-setting-ip-config.c:2557 +#: ../libnm-core/nm-setting-ip-config.c:2596 msgid "missing to/dst for a non zero prefix-length" msgstr "пропущено to/dst для ненульового значення довжини префікса" -#: ../libnm-core/nm-setting-ip-config.c:2562 +#: ../libnm-core/nm-setting-ip-config.c:2601 msgid "invalid to/dst" msgstr "некоректне значення to/dst" -#: ../libnm-core/nm-setting-ip-config.c:2567 +#: ../libnm-core/nm-setting-ip-config.c:2606 msgid "invalid prefix length for to/dst" msgstr "некоректна довжина префікса для to/dst" -#: ../libnm-core/nm-setting-ip-config.c:2575 +#: ../libnm-core/nm-setting-ip-config.c:2614 msgid "invalid iifname" msgstr "некоректна назва інтерфейсу" -#: ../libnm-core/nm-setting-ip-config.c:2583 +#: ../libnm-core/nm-setting-ip-config.c:2622 msgid "invalid oifname" msgstr "некоректна назва інтерфейсу (oifname)" -#: ../libnm-core/nm-setting-ip-config.c:2589 +#: ../libnm-core/nm-setting-ip-config.c:2628 msgid "invalid source port range" msgstr "некоректний діапазон номерів порту джерела" -#: ../libnm-core/nm-setting-ip-config.c:2595 +#: ../libnm-core/nm-setting-ip-config.c:2634 msgid "invalid destination port range" msgstr "некоректний діапазон номерів порту призначення" -#: ../libnm-core/nm-setting-ip-config.c:2603 +#: ../libnm-core/nm-setting-ip-config.c:2642 msgid "suppress_prefixlength out of range" msgstr "suppress_prefixlength поза припустимим діапазоном" -#: ../libnm-core/nm-setting-ip-config.c:2608 +#: ../libnm-core/nm-setting-ip-config.c:2647 msgid "suppress_prefixlength is only allowed with the to-table action" msgstr "" "suppress_prefixlength можна використовувати лише разом із дією to-table" -#: ../libnm-core/nm-setting-ip-config.c:2715 +#: ../libnm-core/nm-setting-ip-config.c:2754 #, c-format msgid "duplicate key %s" msgstr "дублікат ключа %s" -#: ../libnm-core/nm-setting-ip-config.c:2729 +#: ../libnm-core/nm-setting-ip-config.c:2768 #, c-format msgid "invalid key \"%s\"" msgstr "некоректний ключ «%s»" -#: ../libnm-core/nm-setting-ip-config.c:2742 +#: ../libnm-core/nm-setting-ip-config.c:2781 #, c-format msgid "invalid variant type '%s' for \"%s\"" msgstr "некоректний тип варіанта «%s» для «%s»" -#: ../libnm-core/nm-setting-ip-config.c:2751 +#: ../libnm-core/nm-setting-ip-config.c:2790 msgid "missing \"" msgstr "не вистачає \"" -#: ../libnm-core/nm-setting-ip-config.c:2757 +#: ../libnm-core/nm-setting-ip-config.c:2796 msgid "invalid \"" msgstr "некоректна \"" -#: ../libnm-core/nm-setting-ip-config.c:2954 +#: ../libnm-core/nm-setting-ip-config.c:2993 msgid "Unsupported to-string-flags argument" msgstr "Непідтримуваний аргумент to-string-flags" -#: ../libnm-core/nm-setting-ip-config.c:2961 +#: ../libnm-core/nm-setting-ip-config.c:3000 msgid "Unsupported extra-argument" msgstr "Непідтримуваний додатковий аргумент" -#: ../libnm-core/nm-setting-ip-config.c:3228 +#: ../libnm-core/nm-setting-ip-config.c:3267 #, c-format msgid "unsupported key \"%s\"" msgstr "непідтримуваний ключ «%s»" -#: ../libnm-core/nm-setting-ip-config.c:3233 +#: ../libnm-core/nm-setting-ip-config.c:3272 #, c-format msgid "duplicate key \"%s\"" msgstr "дублікат ключа «%s»" -#: ../libnm-core/nm-setting-ip-config.c:3238 +#: ../libnm-core/nm-setting-ip-config.c:3277 #, c-format msgid "invalid value for \"%s\"" msgstr "некоректне значення «%s»" -#: ../libnm-core/nm-setting-ip-config.c:3248 +#: ../libnm-core/nm-setting-ip-config.c:3287 msgid "empty text does not describe a rule" msgstr "порожній текст не описує правило" -#: ../libnm-core/nm-setting-ip-config.c:3254 +#: ../libnm-core/nm-setting-ip-config.c:3293 #, c-format msgid "missing argument for \"%s\"" msgstr "пропущено аргумент «%s»" -#: ../libnm-core/nm-setting-ip-config.c:3266 +#: ../libnm-core/nm-setting-ip-config.c:3305 msgid "invalid \"from\" part" msgstr "некоректна частина «from»" -#: ../libnm-core/nm-setting-ip-config.c:3280 +#: ../libnm-core/nm-setting-ip-config.c:3319 msgid "invalid \"to\" part" msgstr "некоректна частина «to»" -#: ../libnm-core/nm-setting-ip-config.c:3289 +#: ../libnm-core/nm-setting-ip-config.c:3328 #, c-format msgid "cannot detect address family for rule" msgstr "не вдалося визначити сімейство адрес для правила" -#: ../libnm-core/nm-setting-ip-config.c:3349 -#: ../libnm-core/nm-setting-ip-config.c:3443 +#: ../libnm-core/nm-setting-ip-config.c:3388 +#: ../libnm-core/nm-setting-ip-config.c:3482 #, c-format msgid "rule is invalid: %s" msgstr "правило є некоректним: %s" -#: ../libnm-core/nm-setting-ip-config.c:3426 +#: ../libnm-core/nm-setting-ip-config.c:3465 msgid "invalid address family" msgstr "некоректне сімейство адрес" -#: ../libnm-core/nm-setting-ip-config.c:4699 +#: ../libnm-core/nm-setting-ip-config.c:4738 #, c-format msgid "rule #%u is invalid: %s" msgstr "правило %u є некоректним: %s" -#: ../libnm-core/nm-setting-ip-config.c:4955 +#: ../libnm-core/nm-setting-ip-config.c:4994 #, c-format msgid "%d. DNS server address is invalid" msgstr "%d. Адреса сервера DNS є некоректною." -#: ../libnm-core/nm-setting-ip-config.c:4971 +#: ../libnm-core/nm-setting-ip-config.c:5010 #, c-format msgid "%d. IP address is invalid" msgstr "%d. IP-адреса є некоректною." -#: ../libnm-core/nm-setting-ip-config.c:4983 +#: ../libnm-core/nm-setting-ip-config.c:5022 #, c-format msgid "%d. IP address has 'label' property with invalid type" msgstr "%d. IP-адреса має властивість «label» некоректного типу" -#: ../libnm-core/nm-setting-ip-config.c:4992 +#: ../libnm-core/nm-setting-ip-config.c:5031 #, c-format msgid "%d. IP address has invalid label '%s'" msgstr "%d. IP-адреса має некоректну мітку, «%s»" -#: ../libnm-core/nm-setting-ip-config.c:5006 +#: ../libnm-core/nm-setting-ip-config.c:5045 msgid "gateway cannot be set if there are no addresses configured" msgstr "шлюз не може бути встановлено, якщо не налаштовано адрес" -#: ../libnm-core/nm-setting-ip-config.c:5015 +#: ../libnm-core/nm-setting-ip-config.c:5054 msgid "gateway is invalid" msgstr "шлюз є некоректним" -#: ../libnm-core/nm-setting-ip-config.c:5029 +#: ../libnm-core/nm-setting-ip-config.c:5069 #, c-format msgid "%d. route is invalid" msgstr "%d. Некоректний маршрут" -#: ../libnm-core/nm-setting-ip-config.c:5045 +#: ../libnm-core/nm-setting-ip-config.c:5079 +#, c-format +#| msgid "invalid attribute type '%s'" +msgid "invalid attribute: %s" +msgstr "некоректний атрибут: %s" + +#: ../libnm-core/nm-setting-ip-config.c:5098 #, c-format msgid "%u. rule has wrong address-family" msgstr "%u. у правилі вказано помилкове сімейство адрес" -#: ../libnm-core/nm-setting-ip-config.c:5054 +#: ../libnm-core/nm-setting-ip-config.c:5107 #, c-format msgid "%u. rule is invalid: %s" msgstr "%u. правило є некоректним: %s" -#: ../libnm-core/nm-setting-ip-config.c:5068 +#: ../libnm-core/nm-setting-ip-config.c:5121 #, c-format msgid "'%s' is not a valid IAID" msgstr "«%s» не є коректним IAID" -#: ../libnm-core/nm-setting-ip-config.c:5082 +#: ../libnm-core/nm-setting-ip-config.c:5135 #, c-format msgid "the property cannot be set when '%s' is disabled" msgstr "властивість не можна встановлювати, якщо вимкнено «%s»" -#: ../libnm-core/nm-setting-ip-config.c:5104 +#: ../libnm-core/nm-setting-ip-config.c:5157 #, c-format msgid "a gateway is incompatible with '%s'" msgstr "шлюз є несумісним з «%s»" @@ -12800,8 +13090,8 @@ msgstr "можна використовувати лише у режимі psk" msgid "non promiscuous operation is allowed only in passthru mode" msgstr "розбірливі дії можливі лише у режимі передавання (passthru)" -#: ../libnm-core/nm-setting-match.c:580 ../libnm-core/nm-setting-match.c:594 -#: ../libnm-core/nm-setting-match.c:608 +#: ../libnm-core/nm-setting-match.c:738 ../libnm-core/nm-setting-match.c:752 +#: ../libnm-core/nm-setting-match.c:766 ../libnm-core/nm-setting-match.c:780 #, c-format msgid "is empty" msgstr "є порожнім" @@ -13091,11 +13381,6 @@ msgstr "досягнуто максимальної кількості запи msgid "invalid key \"%s\": %s" msgstr "некоректний ключ «%s»: %s" -#: ../libnm-core/nm-setting-user.c:358 ../shared/nm-keyfile/nm-keyfile.c:1001 -#, c-format -msgid "invalid value for \"%s\": %s" -msgstr "некоректне значення для «%s»: %s" - #: ../libnm-core/nm-setting-user.c:373 #, c-format msgid "maximum number of user data entries reached (%u instead of %u)" @@ -13449,7 +13734,7 @@ msgid "team config is not valid UTF-8" msgstr "файл налаштувань team не є коректними даними у кодуванні UTF-8" #: ../libnm-core/nm-team-utils.c:2104 -#: ../src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c:9074 +#: ../src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c:9088 #, c-format msgid "invalid json" msgstr "некоректний код JSON" @@ -13632,13 +13917,11 @@ msgstr "некоректне значення uint32 «%s» атрибута «% #: ../libnm-core/nm-utils.c:5682 #, c-format -#| msgid "invalid uint32 value '%s' for attribute '%s'" msgid "invalid int32 value '%s' for attribute '%s'" msgstr "некоректне значення int32 «%s» атрибута «%s»" #: ../libnm-core/nm-utils.c:5691 #, c-format -#| msgid "invalid uint8 value '%s' for attribute '%s'" msgid "invalid uint64 value '%s' for attribute '%s'" msgstr "некоректне значення uint64 «%s» атрибута «%s»" @@ -13969,95 +14252,95 @@ msgstr "У пристрою немає можливостей WPA2/RSN, потр msgid "The connection was not a wpan connection." msgstr "З'єднання не належить до типу wpan." -#: ../libnm/nm-device.c:1526 +#: ../libnm/nm-device.c:1571 msgid "Bluetooth" msgstr "Bluetooth" -#: ../libnm/nm-device.c:1528 +#: ../libnm/nm-device.c:1573 msgid "OLPC Mesh" msgstr "Сітка OLPC" -#: ../libnm/nm-device.c:1530 +#: ../libnm/nm-device.c:1575 msgid "Open vSwitch Interface" msgstr "Інтерфейс Open vSwitch" -#: ../libnm/nm-device.c:1532 +#: ../libnm/nm-device.c:1577 msgid "Open vSwitch Port" msgstr "Порт Open vSwitch" -#: ../libnm/nm-device.c:1534 +#: ../libnm/nm-device.c:1579 msgid "Open vSwitch Bridge" msgstr "Місток Open vSwitch" -#: ../libnm/nm-device.c:1536 +#: ../libnm/nm-device.c:1581 msgid "WiMAX" msgstr "WiMAX" -#: ../libnm/nm-device.c:1550 +#: ../libnm/nm-device.c:1595 msgid "ADSL" msgstr "ADSL" -#: ../libnm/nm-device.c:1552 +#: ../libnm/nm-device.c:1597 msgid "MACVLAN" msgstr "MACVLAN" -#: ../libnm/nm-device.c:1554 +#: ../libnm/nm-device.c:1599 msgid "VXLAN" msgstr "VXLAN" -#: ../libnm/nm-device.c:1556 +#: ../libnm/nm-device.c:1601 msgid "IPTunnel" msgstr "IPTunnel" -#: ../libnm/nm-device.c:1558 +#: ../libnm/nm-device.c:1603 msgid "Tun" msgstr "TUN" -#: ../libnm/nm-device.c:1560 +#: ../libnm/nm-device.c:1605 msgid "Veth" msgstr "Veth" -#: ../libnm/nm-device.c:1562 +#: ../libnm/nm-device.c:1607 msgid "MACsec" msgstr "MACsec" -#: ../libnm/nm-device.c:1564 +#: ../libnm/nm-device.c:1609 msgid "Dummy" msgstr "Фіктивний" -#: ../libnm/nm-device.c:1566 +#: ../libnm/nm-device.c:1611 msgid "PPP" msgstr "PPP" -#: ../libnm/nm-device.c:1568 +#: ../libnm/nm-device.c:1613 msgid "IEEE 802.15.4" msgstr "IEEE 802.15.4" -#: ../libnm/nm-device.c:1570 +#: ../libnm/nm-device.c:1615 msgid "6LoWPAN" msgstr "6LoWPAN" -#: ../libnm/nm-device.c:1572 +#: ../libnm/nm-device.c:1617 msgid "WireGuard" msgstr "WireGuard" -#: ../libnm/nm-device.c:1574 +#: ../libnm/nm-device.c:1619 msgid "Wi-Fi P2P" msgstr "P2P Wi-Fi" -#: ../libnm/nm-device.c:1576 +#: ../libnm/nm-device.c:1621 msgid "VRF" msgstr "VRF" -#: ../libnm/nm-device.c:1608 +#: ../libnm/nm-device.c:1653 msgid "Wired" msgstr "Дротове" -#: ../libnm/nm-device.c:1640 +#: ../libnm/nm-device.c:1685 msgid "PCI" msgstr "PCI" -#: ../libnm/nm-device.c:1642 +#: ../libnm/nm-device.c:1687 msgid "USB" msgstr "USB" @@ -14067,18 +14350,18 @@ msgstr "USB" #. * "%2$s (%1$s)" if there's no grammatical way to combine #. * the strings otherwise. #. -#: ../libnm/nm-device.c:1942 ../libnm/nm-device.c:1961 +#: ../libnm/nm-device.c:1987 ../libnm/nm-device.c:2006 #, c-format msgctxt "long device name" msgid "%s %s" msgstr "%s %s" -#: ../libnm/nm-device.c:2638 +#: ../libnm/nm-device.c:2683 #, c-format msgid "The connection was not valid: %s" msgstr "З'єднання не є коректним: %s" -#: ../libnm/nm-device.c:2647 +#: ../libnm/nm-device.c:2692 #, c-format msgid "The interface names of the device and the connection didn't match." msgstr "Назви інтерфейсу пристрою і з'єднання не збігаються." @@ -14258,36 +14541,36 @@ msgstr "" "Правила системи забороняють вмикання або вимикання перевірки придатності до " "з'єднання" -#: ../shared/nm-glib-aux/nm-shared-utils.c:2205 +#: ../shared/nm-glib-aux/nm-shared-utils.c:2211 #, c-format msgid "object class '%s' has no property named '%s'" msgstr "у класі об'єктів «%s» немає властивості із назвою «%s»" -#: ../shared/nm-glib-aux/nm-shared-utils.c:2212 +#: ../shared/nm-glib-aux/nm-shared-utils.c:2218 #, c-format msgid "property '%s' of object class '%s' is not writable" msgstr "властивість «%s» класу об'єктів «%s» є непридатною до запису" -#: ../shared/nm-glib-aux/nm-shared-utils.c:2219 +#: ../shared/nm-glib-aux/nm-shared-utils.c:2225 #, c-format msgid "" "construct property \"%s\" for object '%s' can't be set after construction" msgstr "" "властивість construct «%s» об'єкта «%s» не можна встановлювати після побудови" -#: ../shared/nm-glib-aux/nm-shared-utils.c:2227 +#: ../shared/nm-glib-aux/nm-shared-utils.c:2233 #, c-format msgid "'%s::%s' is not a valid property name; '%s' is not a GObject subtype" msgstr "«%s::%s» не є коректною назвою властивості; «%s» не є підтипом GObject" -#: ../shared/nm-glib-aux/nm-shared-utils.c:2236 +#: ../shared/nm-glib-aux/nm-shared-utils.c:2242 #, c-format msgid "unable to set property '%s' of type '%s' from value of type '%s'" msgstr "" "не вдалося встановити значення властивості «%s» типу «%s» на основі значення " "типу «%s»" -#: ../shared/nm-glib-aux/nm-shared-utils.c:2247 +#: ../shared/nm-glib-aux/nm-shared-utils.c:2253 #, c-format msgid "" "value \"%s\" of type '%s' is invalid or out of range for property '%s' of " @@ -14296,319 +14579,51 @@ msgstr "" "значення «%s» типу «%s» є некоректним для властивості «%s» типу «%s» або не " "належить до припустимого діапазону значень" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4649 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4666 msgid "interface name is missing" msgstr "пропущено назву інтерфейсу" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4655 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4672 msgid "interface name is too short" msgstr "назва інтерфейсу є надто короткою" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4664 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4681 msgid "interface name is reserved" msgstr "таку назву інтерфейсу зарезервовано" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4676 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4693 msgid "interface name contains an invalid character" msgstr "назва інтерфейсу містить некоректний символ" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4682 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4699 msgid "interface name is longer than 15 characters" msgstr "назва інтерфейсу є довшою за 15 символів" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4705 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4722 #, c-format msgid "'%%' is not allowed in interface names" msgstr "«%%» не можна використовувати у назвах інтерфейсів" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4718 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4735 #, c-format msgid "'%s' is not allowed as interface name" msgstr "«%s» не можна використовувати як назву інтерфейсу" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4739 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4756 msgid "" "interface name must be alphanumerical with no forward or backward slashes" msgstr "" "назва інтерфейсу має складатися з літер і цифр без початкового і " "завершального символів похилої риски" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4756 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4773 msgid "interface name must not be empty" msgstr "назва інтерфейсу не може бути порожньою" -#: ../shared/nm-glib-aux/nm-shared-utils.c:4762 +#: ../shared/nm-glib-aux/nm-shared-utils.c:4779 msgid "interface name must be UTF-8 encoded" msgstr "назва інтерфейсу має бути набором символів у кодуванні UTF-8" -#: ../shared/nm-keyfile/nm-keyfile-utils.c:171 -#, c-format -msgid "Value cannot be interpreted as a list of numbers." -msgstr "Значення не може бути оброблено як список чисел." - -#: ../shared/nm-keyfile/nm-keyfile-utils.c:307 -#, c-format -msgid "value is not an integer in range [%lld, %lld]" -msgstr "значення не є цілим числом у діапазоні [%lld, %lld]" - -#: ../shared/nm-keyfile/nm-keyfile.c:271 -msgid "ignoring missing number" -msgstr "ігноруємо пропущене число" - -#: ../shared/nm-keyfile/nm-keyfile.c:283 -#, c-format -msgid "ignoring invalid number '%s'" -msgstr "ігноруємо некоректне число «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:312 -#, c-format -msgid "ignoring invalid %s address: %s" -msgstr "ігноруємо некоректну адресу %s: %s" - -#: ../shared/nm-keyfile/nm-keyfile.c:359 -#, c-format -msgid "ignoring invalid gateway '%s' for %s route" -msgstr "ігноруємо некоректний шлюз «%s» для маршруту %s" - -#: ../shared/nm-keyfile/nm-keyfile.c:391 -#, c-format -msgid "ignoring invalid %s route: %s" -msgstr "ігноруємо некоректний маршрут %s: %s" - -#: ../shared/nm-keyfile/nm-keyfile.c:566 -#, c-format -msgid "unexpected character '%c' for address %s: '%s' (position %td)" -msgstr "неочікуваний символ «%c» для адреси %s: «%s» (позиція %td)" - -#: ../shared/nm-keyfile/nm-keyfile.c:582 -#, c-format -msgid "unexpected character '%c' for %s: '%s' (position %td)" -msgstr "неочікуваний символ «%c» для %s: «%s» (позиція %td)" - -#: ../shared/nm-keyfile/nm-keyfile.c:597 -#, c-format -msgid "unexpected character '%c' in prefix length for %s: '%s' (position %td)" -msgstr "неочікуваний символ «%c» у префіксі довжини для %s: «%s» (позиція %td)" - -#: ../shared/nm-keyfile/nm-keyfile.c:614 -#, c-format -msgid "garbage at the end of value %s: '%s'" -msgstr "зайві дані наприкінці значення %s: «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:624 -#, c-format -msgid "deprecated semicolon at the end of value %s: '%s'" -msgstr "застаріла крапка з комою наприкінці значення %s: «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:647 -#, c-format -msgid "invalid prefix length for %s '%s', defaulting to %d" -msgstr "некоректний префікс довжини для %s «%s», повертаємося до типового, %d" - -#: ../shared/nm-keyfile/nm-keyfile.c:659 -#, c-format -msgid "missing prefix length for %s '%s', defaulting to %d" -msgstr "пропущено префікс довжини для %s «%s», повертаємося до типового, %d" - -#: ../shared/nm-keyfile/nm-keyfile.c:1041 -#, c-format -msgid "ignoring invalid DNS server IPv%c address '%s'" -msgstr "ігноруємо некоректну адресу IPv%c сервера DNS «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:1132 -msgid "ignoring invalid MAC address" -msgstr "ігноруємо некоректну MAC-адресу" - -#: ../shared/nm-keyfile/nm-keyfile.c:1391 -msgid "ignoring invalid SSID" -msgstr "ігноруємо некоректний SSID" - -#: ../shared/nm-keyfile/nm-keyfile.c:1409 -msgid "ignoring invalid raw password" -msgstr "ігноруємо некоректний необроблений пароль" - -#: ../shared/nm-keyfile/nm-keyfile.c:1554 -msgid "invalid key/cert value" -msgstr "некоректне значення ключа/сертифіката" - -#: ../shared/nm-keyfile/nm-keyfile.c:1568 -#, c-format -msgid "invalid key/cert value path \"%s\"" -msgstr "некоректний шлях до ключа/сертифіката, «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:1592 -#: ../shared/nm-keyfile/nm-keyfile.c:1688 -#, c-format -msgid "certificate or key file '%s' does not exist" -msgstr "файла сертифіката або ключа «%s» не існує" - -#: ../shared/nm-keyfile/nm-keyfile.c:1604 -#, c-format -msgid "invalid PKCS#11 URI \"%s\"" -msgstr "некоректна адреса PKCS#11 «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:1652 -msgid "invalid key/cert value data:;base64, is not base64" -msgstr "некоректні дані значення ключа/сертифіката data:;base64, не є base64" - -#: ../shared/nm-keyfile/nm-keyfile.c:1664 -msgid "invalid key/cert value data:;base64,file://" -msgstr "некоректне значення ключа/сертифіката data:;base64,file://" - -#: ../shared/nm-keyfile/nm-keyfile.c:1703 -msgid "invalid key/cert value is not a valid blob" -msgstr "" -"некоректне значення ключа/сертифіката, не є коректним значення «%s» не є " -"коректним великим бінарним об'єктом" - -#: ../shared/nm-keyfile/nm-keyfile.c:1808 -#, c-format -msgid "invalid parity value '%s'" -msgstr "некоректне значення парності, «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:1826 -#: ../shared/nm-keyfile/nm-keyfile.c:3391 -#, c-format -msgid "invalid setting: %s" -msgstr "некоректний параметр: %s" - -#: ../shared/nm-keyfile/nm-keyfile.c:1847 -#, c-format -msgid "ignoring invalid team configuration: %s" -msgstr "ігноруємо некоректне налаштування команди: %s" - -#: ../shared/nm-keyfile/nm-keyfile.c:1932 -#, c-format -msgid "invalid qdisc: %s" -msgstr "некоректний qdisc: %s" - -#: ../shared/nm-keyfile/nm-keyfile.c:1981 -#, c-format -msgid "invalid tfilter: %s" -msgstr "некоректний tfilter: %s" - -#: ../shared/nm-keyfile/nm-keyfile.c:3234 -#, c-format -msgid "error loading setting value: %s" -msgstr "помилка під час завантаження значення параметра: %s" - -#: ../shared/nm-keyfile/nm-keyfile.c:3262 -#: ../shared/nm-keyfile/nm-keyfile.c:3273 -#: ../shared/nm-keyfile/nm-keyfile.c:3291 -#: ../shared/nm-keyfile/nm-keyfile.c:3302 -#: ../shared/nm-keyfile/nm-keyfile.c:3313 -#: ../shared/nm-keyfile/nm-keyfile.c:3365 -#: ../shared/nm-keyfile/nm-keyfile.c:3376 -msgid "value cannot be interpreted as integer" -msgstr "значення не може бути оброблено як ціле число" - -#: ../shared/nm-keyfile/nm-keyfile.c:3338 -#, c-format -msgid "ignoring invalid byte element '%u' (not between 0 and 255 inclusive)" -msgstr "" -"ігноруємо некоректний байтовий елемент «%u» (не у діапазоні від 0 до 255, " -"включно)" - -#: ../shared/nm-keyfile/nm-keyfile.c:3416 -#, c-format -msgid "invalid setting name '%s'" -msgstr "некоректна назва параметра, «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:3465 -#, c-format -msgid "invalid key '%s.%s'" -msgstr "некоректний ключ «%s.%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:3484 -#, c-format -msgid "key '%s.%s' is not boolean" -msgstr "ключ «%s.%s» не є булевим значенням" - -#: ../shared/nm-keyfile/nm-keyfile.c:3504 -#, c-format -msgid "key '%s.%s' is not a uint32" -msgstr "ключ «%s.%s» не є значенням uint32" - -#: ../shared/nm-keyfile/nm-keyfile.c:3565 -#, c-format -msgid "invalid peer public key in section '%s'" -msgstr "некоректний відкритий ключ вузла у розділі «%s»" - -#: ../shared/nm-keyfile/nm-keyfile.c:3580 -#, c-format -msgid "key '%s.%s' is not a valid 256 bit key in base64 encoding" -msgstr "ключ «%s.%s» не є коректним 256-бітовим ключем у кодуванні base64" - -#: ../shared/nm-keyfile/nm-keyfile.c:3597 -#, c-format -msgid "key '%s.%s' is not a valid secret flag" -msgstr "ключ «%s.%s» не є коректним прапорцем реєстраційних даних" - -#: ../shared/nm-keyfile/nm-keyfile.c:3613 -#, c-format -msgid "key '%s.%s' is not a integer in range 0 to 2^32" -msgstr "ключ «%s.%s» не є цілими числом у діапазоні від 0 до 2^32" - -#: ../shared/nm-keyfile/nm-keyfile.c:3629 -#, c-format -msgid "key '%s.%s' is not a valid endpoint" -msgstr "ключ «%s.%s» не є коректною кінцевою точкою" - -#: ../shared/nm-keyfile/nm-keyfile.c:3655 -#, c-format -msgid "key '%s.%s' has invalid allowed-ips" -msgstr "для ключа «%s.%s» вказано некоректне значення allowed-ips" - -#: ../shared/nm-keyfile/nm-keyfile.c:3670 -#, c-format -msgid "peer '%s' is invalid: %s" -msgstr "вузол «%s» є некоректним: %s" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:221 -#, c-format -msgid "'%s' is not valid: properties should be specified as 'key=value'" -msgstr "" -"«%s» є некоректним: властивості має бути вказано у форматі «ключ=значення»" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:236 -#, c-format -msgid "'%s' is not a valid key" -msgstr "«%s» не є коректним ключем" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:242 -#, c-format -msgid "duplicate key '%s'" -msgstr "дублікат ключа «%s»" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:256 -#, c-format -msgid "number for '%s' is out of range" -msgstr "число для «%s» лежить поза припустимим діапазоном" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:259 -#, c-format -msgid "value for '%s' must be a number" -msgstr "значення «%s» має бути числом" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:270 -#, c-format -msgid "value for '%s' must be a boolean" -msgstr "значення «%s» має бути булевим" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:279 -msgid "missing 'name' attribute" -msgstr "пропущено атрибут «name»" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:286 -#, c-format -msgid "invalid 'name' \"%s\"" -msgstr "некоректне значення «name» — «%s»" - -#: ../shared/nm-libnm-core-aux/nm-libnm-core-aux.c:298 -#, c-format -msgid "attribute '%s' is invalid for \"%s\"" -msgstr "атрибут «%s» є некоректним для «%s»" - #. TRANSLATORS: the first %s is a prefix for the connection id, such #. * as "Wired Connection" or "VPN Connection". The %d is a number #. * that is combined with the first argument to create a unique From 9f77d26ad0ffaa51d9b262ea4d9b28bbc58b6f68 Mon Sep 17 00:00:00 2001 From: Sayed Shah Date: Tue, 9 Jun 2020 16:22:51 -0400 Subject: [PATCH 010/199] build: create check for python black If python black is install then it would check the formating of all of the python files and test the for it. Otherwise, it would just simply ignore the python black if python black is not installed. --- Makefile.am | 5 +++++ configure.ac | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/Makefile.am b/Makefile.am index 285e07778f..71643080b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5235,6 +5235,11 @@ CLEANFILES += \ ############################################################################### include Makefile.examples +if WITH_PYTHON_BLACK +check-python-black: + $(BLACK) --check $(top_srcdir) +check_local += check-python-black +endif ############################################################################### diff --git a/configure.ac b/configure.ac index 175ee554ed..2ace7ecaee 100644 --- a/configure.ac +++ b/configure.ac @@ -1272,6 +1272,10 @@ else have_introspection=no fi +# check for python black. And check if all files are formatted with python black +AC_PATH_PROG(BLACK, black) +AM_CONDITIONAL(WITH_PYTHON_BLACK, test "${BLACK}" != "") + # check for pregenerated manpages and documentation to be installed use_pregen_docs=no if test "$build_docs" != "yes" -a \ From c537852231a63431ee95ceb14968382e37e7aaea Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 19 Jun 2020 12:36:49 +0200 Subject: [PATCH 011/199] build: optionally skip python black check by setting NMTST_SKIP_PYTHON_BLACK=1 --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 71643080b0..db9f4c80c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5235,9 +5235,10 @@ CLEANFILES += \ ############################################################################### include Makefile.examples + if WITH_PYTHON_BLACK check-python-black: - $(BLACK) --check $(top_srcdir) + test "$$NMTST_SKIP_PYTHON_BLACK" != 1 && $(BLACK) --check $(top_srcdir) check_local += check-python-black endif From 70f3ad6785d9e0e6a65b10789d7322ab802afb03 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 19 Jun 2020 12:47:07 +0200 Subject: [PATCH 012/199] gitlab-ci: run checkpatch test against fedora:32 target --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5e1ea7a99a..fa5ad46ad4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -74,7 +74,7 @@ stages: - date '+%Y%m%d-%H%M%S'; test "$NM_BUILD_TARBALL" != 1 || mv /tmp/NetworkManager-1*.tar.xz /tmp/NetworkManager-1*.src.rpm ./ checkpatch: - image: fedora:29 + image: fedora:32 stage: test script: - date '+%Y%m%d-%H%M%S'; dnf install -y git From 8c3ee4e8574d84258f34068486b33e10f0e87313 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 19 Jun 2020 12:43:38 +0200 Subject: [PATCH 013/199] gitlab-ci: enable python black check in gitlab-ci --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fa5ad46ad4..389da67218 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -77,8 +77,9 @@ checkpatch: image: fedora:32 stage: test script: - - date '+%Y%m%d-%H%M%S'; dnf install -y git + - date '+%Y%m%d-%H%M%S'; dnf install -y git black - date '+%Y%m%d-%H%M%S'; NM_CHECKPATCH_FETCH_UPSTREAM=1 contrib/scripts/checkpatch-feature-branch.sh 2>&1 | tee checkpatch-out.txt + - date '+%Y%m%d-%H%M%S'; black --check . allow_failure: true artifacts: when: on_failure From 4d6b96b48f2985bd8b0a1175a4411e23ed42eda0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 7 Jun 2020 14:32:20 +0200 Subject: [PATCH 014/199] shared: make NMUtilsNamedValue.value_ptr non const If the value pointer is const, it is commonly inconvenient and requires a cast. Requiring casts on a common base does not increase type safety, but is annoying. --- shared/nm-glib-aux/nm-shared-utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index eeb8be5b7d..7d4611bff6 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1446,7 +1446,7 @@ typedef struct { }; union { const char *value_str; - gconstpointer value_ptr; + gpointer value_ptr; }; } NMUtilsNamedValue; From ee9e1ceefc76a2f8af3b51b1cc6e5f2865f4abdc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 6 Jun 2020 20:58:08 +0200 Subject: [PATCH 015/199] shared: avoid allocating temporary buffer for nm_utils_named_values_from_strdict() Iterating hash tables gives an undefined order. Often we want to have a stable order, for example when printing the content of a hash or when converting it to a "a{sv}" variant. How to achieve that best? I think we should only iterate the hash once, and not require additional lookups. nm_utils_named_values_from_strdict() achieves that by returning the key and the value together. Also, often we only need the list for a short time, so we can avoid heap allocating the list, if it is short enough. This works by allowing the caller to provide a pre-allocated buffer (usually on the stack) and only as fallback allocate a new list. --- libnm-core/nm-setting-bond.c | 2 +- shared/nm-glib-aux/nm-shared-utils.c | 43 +++++++++++++++++++++------- shared/nm-glib-aux/nm-shared-utils.h | 20 ++++++------- src/nm-core-utils.c | 9 ++++-- 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/libnm-core/nm-setting-bond.c b/libnm-core/nm-setting-bond.c index 8986e434e5..da759efcaa 100644 --- a/libnm-core/nm-setting-bond.c +++ b/libnm-core/nm-setting-bond.c @@ -368,7 +368,7 @@ static void _ensure_options_idx_cache (NMSettingBondPrivate *priv) { if (!G_UNLIKELY (priv->options_idx_cache)) - priv->options_idx_cache = nm_utils_named_values_from_str_dict_with_sort (priv->options, NULL, _get_option_sort, NULL); + priv->options_idx_cache = nm_utils_named_values_from_strdict_full (priv->options, NULL, _get_option_sort, NULL, NULL, 0, NULL); } /** diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 39e98a31df..baa91646e8 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -2909,28 +2909,44 @@ nm_utils_fd_read_loop_exact (int fd, void *buf, size_t nbytes, bool do_poll) /*****************************************************************************/ +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, name) == 0); + NMUtilsNamedValue * -nm_utils_named_values_from_str_dict_with_sort (GHashTable *hash, - guint *out_len, - GCompareDataFunc compare_func, - gpointer user_data) +nm_utils_named_values_from_strdict_full (GHashTable *hash, + guint *out_len, + GCompareDataFunc compare_func, + gpointer user_data, + NMUtilsNamedValue *provided_buffer, + guint provided_buffer_len, + NMUtilsNamedValue **out_allocated_buffer) { GHashTableIter iter; NMUtilsNamedValue *values; guint i, len; + nm_assert (provided_buffer_len == 0 || provided_buffer); + nm_assert (!out_allocated_buffer || !*out_allocated_buffer); + if ( !hash || !(len = g_hash_table_size (hash))) { NM_SET_OUT (out_len, 0); return NULL; } + if (provided_buffer_len >= len + 1) { + /* the buffer provided by the caller is large enough. Use it. */ + values = provided_buffer; + } else { + /* allocate a new buffer. */ + values = g_new (NMUtilsNamedValue, len + 1); + NM_SET_OUT (out_allocated_buffer, values); + } + i = 0; - values = g_new (NMUtilsNamedValue, len + 1); g_hash_table_iter_init (&iter, hash); while (g_hash_table_iter_next (&iter, (gpointer *) &values[i].name, - (gpointer *) &values[i].value_ptr)) + &values[i].value_ptr)) i++; nm_assert (i == len); values[i].name = NULL; @@ -4925,7 +4941,7 @@ _nm_utils_format_variant_attributes_full (GString *str, for (i = 0; i < num_values; i++) { name = values[i].name; - variant = (GVariant *) values[i].value_ptr; + variant = values[i].value_ptr; value = NULL; if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)) @@ -4969,17 +4985,24 @@ _nm_utils_format_variant_attributes (GHashTable *attributes, char attr_separator, char key_value_separator) { + gs_free NMUtilsNamedValue *values_free = NULL; + NMUtilsNamedValue values_prepared[20]; + const NMUtilsNamedValue *values; GString *str = NULL; - gs_free NMUtilsNamedValue *values = NULL; guint len; g_return_val_if_fail (attr_separator, NULL); g_return_val_if_fail (key_value_separator, NULL); - if (!attributes || !g_hash_table_size (attributes)) + if (!attributes) return NULL; - values = nm_utils_named_values_from_str_dict (attributes, &len); + values = nm_utils_named_values_from_strdict (attributes, + &len, + values_prepared, + &values_free); + if (len == 0) + return NULL; str = g_string_new (""); _nm_utils_format_variant_attributes_full (str, diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 7d4611bff6..a74422043a 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1452,18 +1452,16 @@ typedef struct { #define NM_UTILS_NAMED_VALUE_INIT(n, v) { .name = (n), .value_ptr = (v) } -NMUtilsNamedValue *nm_utils_named_values_from_str_dict_with_sort (GHashTable *hash, - guint *out_len, - GCompareDataFunc compare_func, - gpointer user_data); +NMUtilsNamedValue *nm_utils_named_values_from_strdict_full (GHashTable *hash, + guint *out_len, + GCompareDataFunc compare_func, + gpointer user_data, + NMUtilsNamedValue *provided_buffer, + guint provided_buffer_len, + NMUtilsNamedValue **out_allocated_buffer); -static inline NMUtilsNamedValue * -nm_utils_named_values_from_str_dict (GHashTable *hash, guint *out_len) -{ - G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, name) == 0); - - return nm_utils_named_values_from_str_dict_with_sort (hash, out_len, nm_strcmp_p_with_data, NULL); -} +#define nm_utils_named_values_from_strdict(hash, out_len, array, out_allocated_buffer) \ + nm_utils_named_values_from_strdict_full ((hash), (out_len), nm_strcmp_p_with_data, NULL, (array), G_N_ELEMENTS (array), (out_allocated_buffer)) gssize nm_utils_named_value_list_find (const NMUtilsNamedValue *arr, gsize len, diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 019d1e600f..2492fc10aa 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -4111,12 +4111,17 @@ nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing) GVariant * nm_utils_strdict_to_variant (GHashTable *options) { + gs_free NMUtilsNamedValue *values_free = NULL; + NMUtilsNamedValue values_prepared[20]; + const NMUtilsNamedValue *values; GVariantBuilder builder; - gs_free NMUtilsNamedValue *values = NULL; guint i; guint n; - values = nm_utils_named_values_from_str_dict (options, &n); + values = nm_utils_named_values_from_strdict (options, + &n, + values_prepared, + &values_free); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); for (i = 0; i < n; i++) { From 91d6461761b187593483507fb6631b3aa5084289 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 7 Jun 2020 00:47:29 +0200 Subject: [PATCH 016/199] ifcfg-rh: use nm_utils_named_values_from_strdict() in write_secrets() --- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index e6526944c7..2eb3cf0ce2 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -114,10 +114,13 @@ write_secrets (shvarFile *ifcfg, GError **error) { nm_auto_shvar_file_close shvarFile *keyfile = NULL; - gs_free const char **secrets_keys = NULL; - guint i, secrets_keys_n; + gs_free NMUtilsNamedValue *secrets_arr_free = NULL; + NMUtilsNamedValue secrets_arr_static[30]; + const NMUtilsNamedValue *secrets_arr; + guint secrets_len; GError *local = NULL; gboolean any_secrets = FALSE; + guint i; keyfile = utils_get_keys_ifcfg (svFileGetName (ifcfg), TRUE); if (!keyfile) { @@ -126,10 +129,13 @@ write_secrets (shvarFile *ifcfg, return FALSE; } - secrets_keys = nm_utils_strdict_get_keys (secrets, TRUE, &secrets_keys_n); - for (i = 0; i < secrets_keys_n; i++) { - const char *k = secrets_keys[i]; - const char *v = g_hash_table_lookup (secrets, k); + secrets_arr = nm_utils_named_values_from_strdict (secrets, + &secrets_len, + secrets_arr_static, + &secrets_arr_free); + for (i = 0; i < secrets_len; i++) { + const char *k = secrets_arr[i].name; + const char *v = secrets_arr[i].value_str; if (v) { svSetValueStr (keyfile, k, v); From cdb38df7e5c29994472bcca5206de2a773d7fd3a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 7 Jun 2020 00:04:52 +0200 Subject: [PATCH 017/199] shared,core: rename and move function to nm_utils_strdict_to_variant_asv() --- shared/nm-glib-aux/nm-shared-utils.c | 27 +++++++++++++++++++++++++++ shared/nm-glib-aux/nm-shared-utils.h | 1 + src/nm-core-utils.c | 27 --------------------------- src/nm-core-utils.h | 2 -- src/nm-dhcp-config.c | 2 +- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index baa91646e8..918964e785 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -527,6 +527,33 @@ out: /*****************************************************************************/ +GVariant * +nm_utils_strdict_to_variant_asv (GHashTable *strdict) +{ + gs_free NMUtilsNamedValue *values_free = NULL; + NMUtilsNamedValue values_prepared[20]; + const NMUtilsNamedValue *values; + GVariantBuilder builder; + guint i; + guint n; + + values = nm_utils_named_values_from_strdict (strdict, + &n, + values_prepared, + &values_free); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + for (i = 0; i < n; i++) { + g_variant_builder_add (&builder, + "{sv}", + values[i].name, + g_variant_new_string (values[i].value_str)); + } + return g_variant_builder_end (&builder); +} + +/*****************************************************************************/ + /** * nm_strquote: * @buf: the output buffer of where to write the quoted @str argument. diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index a74422043a..67997e6b58 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -422,6 +422,7 @@ gboolean nm_utils_gbytes_equal_mem (GBytes *bytes, GVariant *nm_utils_gbytes_to_variant_ay (GBytes *bytes); GVariant *nm_utils_strdict_to_variant_ass (GHashTable *strdict); +GVariant *nm_utils_strdict_to_variant_asv (GHashTable *strdict); /*****************************************************************************/ diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 2492fc10aa..bc80dabf35 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -4108,33 +4108,6 @@ nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing) /*****************************************************************************/ -GVariant * -nm_utils_strdict_to_variant (GHashTable *options) -{ - gs_free NMUtilsNamedValue *values_free = NULL; - NMUtilsNamedValue values_prepared[20]; - const NMUtilsNamedValue *values; - GVariantBuilder builder; - guint i; - guint n; - - values = nm_utils_named_values_from_strdict (options, - &n, - values_prepared, - &values_free); - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - for (i = 0; i < n; i++) { - g_variant_builder_add (&builder, - "{sv}", - values[i].name, - g_variant_new_string (values[i].value_str)); - } - return g_variant_builder_end (&builder); -} - -/*****************************************************************************/ - static guint32 get_max_rate_ht_20 (int mcs) { diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index e30d7b3651..b36c9b581f 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -449,8 +449,6 @@ gboolean nm_utils_validate_plugin (const char *path, struct stat *stat, GError * char **nm_utils_read_plugin_paths (const char *dirname, const char *prefix); char *nm_utils_format_con_diff_for_audit (GHashTable *diff); -GVariant *nm_utils_strdict_to_variant (GHashTable *options); - /*****************************************************************************/ /* this enum is compatible with ICMPV6_ROUTER_PREF_* (from , diff --git a/src/nm-dhcp-config.c b/src/nm-dhcp-config.c index 3b9211df99..fd55c3ff43 100644 --- a/src/nm-dhcp-config.c +++ b/src/nm-dhcp-config.c @@ -75,7 +75,7 @@ nm_dhcp_config_set_options (NMDhcpConfig *self, priv = NM_DHCP_CONFIG_GET_PRIVATE (self); nm_g_variant_unref (priv->options); - priv->options = g_variant_ref_sink (nm_utils_strdict_to_variant (options)); + priv->options = g_variant_ref_sink (nm_utils_strdict_to_variant_asv (options)); _notify (self, PROP_OPTIONS); } From fff812e25523997bfa6997a15eecba4aeda52e2e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 7 Jun 2020 01:04:05 +0200 Subject: [PATCH 018/199] shared: refactor nm_utils_strdict_to_variant_ass() to use nm_utils_named_values_from_strdict() It is pretty much the same code this way, but shorter. --- shared/nm-glib-aux/nm-shared-utils.c | 55 ++++++++-------------------- 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 918964e785..68e6ee5ba1 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -478,50 +478,25 @@ nm_utils_gbytes_to_variant_ay (GBytes *bytes) GVariant * nm_utils_strdict_to_variant_ass (GHashTable *strdict) { - GHashTableIter iter; - const char *key, *value; + gs_free NMUtilsNamedValue *values_free = NULL; + NMUtilsNamedValue values_prepared[20]; + const NMUtilsNamedValue *values; GVariantBuilder builder; - guint i, len; + guint i; + guint n; + + values = nm_utils_named_values_from_strdict (strdict, + &n, + values_prepared, + &values_free); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); - - if (!strdict) - goto out; - len = g_hash_table_size (strdict); - if (!len) - goto out; - - g_hash_table_iter_init (&iter, strdict); - if (!g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) - nm_assert_not_reached (); - - if (len == 1) - g_variant_builder_add (&builder, "{ss}", key, value); - else { - gs_free NMUtilsNamedValue *idx_free = NULL; - NMUtilsNamedValue *idx; - - if (len > 300 / sizeof (NMUtilsNamedValue)) { - idx_free = g_new (NMUtilsNamedValue, len); - idx = idx_free; - } else - idx = g_alloca (sizeof (NMUtilsNamedValue) * len); - - i = 0; - do { - idx[i].name = key; - idx[i].value_str = value; - i++; - } while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)); - nm_assert (i == len); - - nm_utils_named_value_list_sort (idx, len, NULL, NULL); - - for (i = 0; i < len; i++) - g_variant_builder_add (&builder, "{ss}", idx[i].name, idx[i].value_str); + for (i = 0; i < n; i++) { + g_variant_builder_add (&builder, + "{ss}", + values[i].name, + values[i].value_str); } - -out: return g_variant_builder_end (&builder); } From 83146b3ec25bf8affa951f0458dc1ccfc1368425 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 7 Jun 2020 01:10:11 +0200 Subject: [PATCH 019/199] libnm: add missing since gtk-doc for nm_tc_action_get_attribute_names() --- libnm-core/nm-setting-tc-config.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libnm-core/nm-setting-tc-config.c b/libnm-core/nm-setting-tc-config.c index 8658231562..1c9de13b75 100644 --- a/libnm-core/nm-setting-tc-config.c +++ b/libnm-core/nm-setting-tc-config.c @@ -585,6 +585,8 @@ nm_tc_action_get_kind (NMTCAction *action) * Gets an array of attribute names defined on @action. * * Returns: (transfer full): a %NULL-terminated array of attribute names, + * + * Since: 1.12 **/ char ** nm_tc_action_get_attribute_names (NMTCAction *action) @@ -614,6 +616,8 @@ _nm_tc_action_get_attributes (NMTCAction *action) * * Returns: (transfer none): the value of the attribute with name @name on * @action, or %NULL if @action has no such attribute. + * + * Since: 1.12 **/ GVariant * nm_tc_action_get_attribute (NMTCAction *action, const char *name) @@ -634,6 +638,8 @@ nm_tc_action_get_attribute (NMTCAction *action, const char *name) * @value: (transfer none) (allow-none): the value * * Sets or clears the named attribute on @action to the given value. + * + * Since: 1.12 **/ void nm_tc_action_set_attribute (NMTCAction *action, const char *name, GVariant *value) From 19b6d38932f3496364899eb9393080c804f4a488 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 7 Jun 2020 01:16:04 +0200 Subject: [PATCH 020/199] libnm: use nm_utils_named_values_from_strdict() in "nm-setting-tc-config.c" --- libnm-core/nm-setting-tc-config.c | 46 ++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/libnm-core/nm-setting-tc-config.c b/libnm-core/nm-setting-tc-config.c index 1c9de13b75..2ece266976 100644 --- a/libnm-core/nm-setting-tc-config.c +++ b/libnm-core/nm-setting-tc-config.c @@ -174,13 +174,14 @@ nm_tc_qdisc_equal (NMTCQdisc *qdisc, NMTCQdisc *other) static guint _nm_tc_qdisc_hash (NMTCQdisc *qdisc) { - gs_free const char **names = NULL; - GVariant *variant; + NMUtilsNamedValue attrs_static[30]; + gs_free NMUtilsNamedValue *attrs_free = NULL; + const NMUtilsNamedValue *attrs; NMHashState h; guint length; guint i; - names = nm_utils_strdict_get_keys (qdisc->attributes, TRUE, &length); + attrs = nm_utils_named_values_from_strdict (qdisc->attributes, &length, attrs_static, &attrs_free); nm_hash_init (&h, 43869703); nm_hash_update_vals (&h, @@ -189,13 +190,13 @@ _nm_tc_qdisc_hash (NMTCQdisc *qdisc) length); nm_hash_update_str0 (&h, qdisc->kind); for (i = 0; i < length; i++) { + const char *key = attrs[i].name; + GVariant *variant = attrs[i].value_ptr; const GVariantType *vtype; - variant = g_hash_table_lookup (qdisc->attributes, names[i]); - vtype = g_variant_get_type (variant); - nm_hash_update_str (&h, names[i]); + nm_hash_update_str (&h, key); nm_hash_update_str (&h, (const char *) vtype); if (g_variant_type_is_basic (vtype)) nm_hash_update_val (&h, g_variant_hash (variant)); @@ -798,24 +799,31 @@ nm_tc_tfilter_equal (NMTCTfilter *tfilter, NMTCTfilter *other) static guint _nm_tc_tfilter_hash (NMTCTfilter *tfilter) { - gs_free const char **names = NULL; - guint i, attr_hash; - GVariant *variant; NMHashState h; - guint length; nm_hash_init (&h, 63624437); nm_hash_update_vals (&h, tfilter->handle, tfilter->parent); nm_hash_update_str0 (&h, tfilter->kind); + if (tfilter->action) { + gs_free NMUtilsNamedValue *attrs_free = NULL; + NMUtilsNamedValue attrs_static[30]; + const NMUtilsNamedValue *attrs; + guint length; + guint i; + nm_hash_update_str0 (&h, tfilter->action->kind); - names = nm_utils_strdict_get_keys (tfilter->action->attributes, TRUE, &length); + + attrs = nm_utils_named_values_from_strdict (tfilter->action->attributes, &length, attrs_static, &attrs_free); for (i = 0; i < length; i++) { - nm_hash_update_str (&h, names[i]); - variant = g_hash_table_lookup (tfilter->action->attributes, names[i]); + GVariant *variant = attrs[i].value_ptr; + + nm_hash_update_str (&h, attrs[i].name); if (g_variant_type_is_basic (g_variant_get_type (variant))) { + guint attr_hash; + /* g_variant_hash() works only for basic types, thus * we ignore any non-basic attribute. Actions differing * only for non-basic attributes will collide. */ @@ -824,6 +832,7 @@ _nm_tc_tfilter_hash (NMTCTfilter *tfilter) } } } + return nm_hash_complete (&h); } @@ -1380,9 +1389,11 @@ _qdiscs_to_variant (GPtrArray *qdiscs) if (qdiscs) { for (i = 0; i < qdiscs->len; i++) { + NMUtilsNamedValue attrs_static[30]; + gs_free NMUtilsNamedValue *attrs_free = NULL; + const NMUtilsNamedValue *attrs; NMTCQdisc *qdisc = qdiscs->pdata[i]; guint length; - gs_free const char **attrs = nm_utils_strdict_get_keys (qdisc->attributes, TRUE, &length); GVariantBuilder qdisc_builder; guint y; @@ -1397,9 +1408,12 @@ _qdiscs_to_variant (GPtrArray *qdiscs) g_variant_builder_add (&qdisc_builder, "{sv}", "parent", g_variant_new_uint32 (nm_tc_qdisc_get_parent (qdisc))); + attrs = nm_utils_named_values_from_strdict (qdisc->attributes, &length, attrs_static, &attrs_free); for (y = 0; y < length; y++) { - g_variant_builder_add (&qdisc_builder, "{sv}", attrs[y], - g_hash_table_lookup (qdisc->attributes, attrs[y])); + g_variant_builder_add (&qdisc_builder, + "{sv}", + attrs[y].name, + attrs[y].value_ptr); } g_variant_builder_add (&builder, "a{sv}", &qdisc_builder); From bb6c2d73713f69ceb6c827dcc7fb7dac91595ece Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 6 Jun 2020 20:49:48 +0200 Subject: [PATCH 021/199] libnm: ensure stable behavior in _nm_ip_route_attribute_validate_all() Check the attributes in a defined, stable order. This is necessary, so that consistently the same error gets reported. --- libnm-core/nm-setting-ip-config.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index bc81129177..f7a022b6cb 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -1363,9 +1363,12 @@ nm_ip_route_attribute_validate (const char *name, gboolean _nm_ip_route_attribute_validate_all (const NMIPRoute *route, GError **error) { - GHashTableIter iter; - const char *key; + NMUtilsNamedValue attrs_static[G_N_ELEMENTS (ip_route_attribute_spec)]; + gs_free NMUtilsNamedValue *attrs_free = NULL; + const NMUtilsNamedValue *attrs; + guint attrs_len; GVariant *val; + guint i; guint8 u8; g_return_val_if_fail (route, FALSE); @@ -1374,9 +1377,15 @@ _nm_ip_route_attribute_validate_all (const NMIPRoute *route, GError **error) if (!route->attributes) return TRUE; - g_hash_table_iter_init (&iter, route->attributes); - while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { - if (!nm_ip_route_attribute_validate (key, val, route->family, NULL, error)) + attrs = nm_utils_named_values_from_strdict (route->attributes, + &attrs_len, + attrs_static, + &attrs_free); + for (i = 0; i < attrs_len; i++) { + const char *key = attrs[i].name; + GVariant *val2 = attrs[i].value_ptr; + + if (!nm_ip_route_attribute_validate (key, val2, route->family, NULL, NULL)) return FALSE; } From 83c79bc7a82ea513574cd08a38115a485921b1fa Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 20 Jun 2020 12:10:32 +0200 Subject: [PATCH 022/199] shared: allow empty NMStrBuf buffers with un-allocated memory Previously, for simplicity, NMStrBuf did not support buffers without any data allocated. However, supporting that has very little overhead/complexity, so do it. Now you can initialize buffers to have no data allocated, and when appending data, it will automatically grow. --- shared/nm-glib-aux/nm-shared-utils.c | 2 ++ shared/nm-glib-aux/nm-str-buf.h | 41 ++++++++++++++++++---------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 68e6ee5ba1..cb43182c41 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -4859,6 +4859,8 @@ nm_str_buf_append_printf (NMStrBuf *strbuf, available = strbuf->_priv_allocated - strbuf->_priv_len; + nm_assert (available < G_MAXULONG); + va_start (args, format); l = g_vsnprintf (&strbuf->_priv_str[strbuf->_priv_len], available, diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index 8c73bfaf3d..7121ba609a 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -35,24 +35,25 @@ static inline void _nm_str_buf_assert (NMStrBuf *strbuf) { nm_assert (strbuf); - nm_assert (strbuf->_priv_str); - nm_assert (strbuf->_priv_allocated > 0); + nm_assert ((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0)); nm_assert (strbuf->_priv_len <= strbuf->_priv_allocated); } +#define NM_STR_BUF_INIT(len, do_bzero_mem) \ + ((NMStrBuf) { \ + ._priv_str = (len) ? g_malloc (len) : NULL, \ + ._priv_allocated = (len), \ + ._priv_len = 0, \ + ._priv_do_bzero_mem = (do_bzero_mem), \ + }) + static inline void nm_str_buf_init (NMStrBuf *strbuf, gsize len, bool do_bzero_mem) { nm_assert (strbuf); - nm_assert (len > 0); - - strbuf->_priv_str = g_malloc (len); - strbuf->_priv_allocated = len; - strbuf->_priv_len = 0; - strbuf->_priv_do_bzero_mem = do_bzero_mem; - + *strbuf = NM_STR_BUF_INIT (len, do_bzero_mem); _nm_str_buf_assert (strbuf); } @@ -66,9 +67,6 @@ nm_str_buf_maybe_expand (NMStrBuf *strbuf, gboolean reserve_exact) { _nm_str_buf_assert (strbuf); - - /* currently we always require to reserve a non-zero number of bytes. */ - nm_assert (reserve > 0); nm_assert (strbuf->_priv_len < G_MAXSIZE - reserve); /* @reserve is the extra space that we require. */ @@ -263,10 +261,16 @@ nm_str_buf_is_initalized (NMStrBuf *strbuf) * is of length "strbuf->len", which may be larger if the * returned string contains NUL characters (binary). The terminating * NUL character is always present after "strbuf->len" characters. + * If currently no buffer is allocated, this will return %NULL. */ static inline const char * nm_str_buf_get_str (NMStrBuf *strbuf) { + _nm_str_buf_assert (strbuf); + + if (!strbuf->_priv_str) + return NULL; + nm_str_buf_maybe_expand (strbuf, 1, FALSE); strbuf->_priv_str[strbuf->_priv_len] = '\0'; return strbuf->_priv_str; @@ -288,16 +292,23 @@ nm_str_buf_get_str_unsafe (NMStrBuf *strbuf) * Returns: (transfer full): the string of the buffer * which must be freed by the caller. The @strbuf * is afterwards in undefined state, though it can be - * reused after nm_str_buf_init(). */ + * reused after nm_str_buf_init(). + * Note that if no string is allocated yet (after nm_str_buf_init() with + * length zero), this will return %NULL. */ static inline char * nm_str_buf_finalize (NMStrBuf *strbuf, gsize *out_len) { - nm_str_buf_maybe_expand (strbuf, 1, TRUE); - strbuf->_priv_str[strbuf->_priv_len] = '\0'; + _nm_str_buf_assert (strbuf); NM_SET_OUT (out_len, strbuf->_priv_len); + if (!strbuf->_priv_str) + return NULL; + + nm_str_buf_maybe_expand (strbuf, 1, TRUE); + strbuf->_priv_str[strbuf->_priv_len] = '\0'; + /* the buffer is in invalid state afterwards, however, we clear it * so far, that nm_auto_str_buf and nm_str_buf_destroy() is happy. */ return g_steal_pointer (&strbuf->_priv_str); From fd34fe50a2100ce5d9440047ec65f25097cb6a32 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 12:38:45 +0200 Subject: [PATCH 023/199] shared: fix string truncation in nm_str_buf_append_printf() If g_vsnprintf() returns that it wants to write 5 characters, it really needs space for 5+1 characters. If we have 5 characters available, it would have written "0123\0", which leaves the buffer broken. Fixes: eda47170ed2e ('shared: add NMStrBuf util') --- shared/nm-glib-aux/nm-shared-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index cb43182c41..39dfe6f473 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -4871,7 +4871,7 @@ nm_str_buf_append_printf (NMStrBuf *strbuf, nm_assert (l >= 0); nm_assert (l < G_MAXINT); - if ((gsize) l > available) { + if ((gsize) l >= available) { gsize l2 = ((gsize) l) + 1u; nm_str_buf_maybe_expand (strbuf, l2, FALSE); From 4aefad567387cf11c460f77beeb9f05bd05e46c0 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 17 Jun 2020 10:01:07 +0200 Subject: [PATCH 024/199] settings: fix assertion when updating default wired connection The connection is expected to have the NM_GENERATED flag, since it has a default wired device. Fixes: d35d3c468a30 ('settings: rework tracking settings connections and settings plugins') https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/471 --- src/settings/nm-settings.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 5899b07945..0a1e7b47d6 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -1996,11 +1996,10 @@ nm_settings_update_connection (NMSettings *self, */ device = nm_settings_connection_default_wired_get_device (sett_conn); if (device) { + nm_assert (cur_in_memory); - nm_assert (!NM_FLAGS_ANY (nm_settings_connection_get_flags (sett_conn), - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED - | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE - | NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL)); + nm_assert (NM_FLAGS_HAS (nm_settings_connection_get_flags (sett_conn), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)); default_wired_clear_tag (self, device, sett_conn, FALSE); From d69f057a65a63e7f62a1f2cea789c6367547202b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2020 11:57:25 +0200 Subject: [PATCH 025/199] shared: add nm_strvarray_get_strv_non_empty() helper --- shared/nm-glib-aux/nm-shared-utils.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 67997e6b58..0831f11c3d 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -2022,6 +2022,18 @@ nm_strvarray_add (GArray *array, const char *str) g_array_append_val (array, s); } +static inline const char *const* +nm_strvarray_get_strv_non_empty (GArray *arr, guint *length) +{ + if (!arr || arr->len == 0) { + NM_SET_OUT (length, 0); + return NULL; + } + + NM_SET_OUT (length, arr->len); + return &g_array_index (arr, const char *, 0); +} + static inline const char *const* nm_strvarray_get_strv (GArray **arr, guint *length) { From 62263e706fb7e3ac9ab628af60e4f52faf67a2ea Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2020 11:55:09 +0200 Subject: [PATCH 026/199] libnm: return NULL for boxed strv properties of NMSettingMatch The API does not allow to distinguish between an unset (NULL) or empty strv array. For example, nm_setting_match_get_paths() never returns %NULL, but returns an empty strv array. On the other hand, the GObject properties of type G_TYPE_STRV have a default value of %NULL. That means, also the getter should map both unset and empty to %NULL. Note that this is a change in behavior w.r.t. 1.24.0 API, where match.interface-name property would return an empty strv array. Regrading the other API, this is no change because it is new API and we will fix it before 1.26.0 release. --- libnm-core/nm-setting-match.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libnm-core/nm-setting-match.c b/libnm-core/nm-setting-match.c index 6071c88290..599fcf9916 100644 --- a/libnm-core/nm-setting-match.c +++ b/libnm-core/nm-setting-match.c @@ -659,16 +659,16 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_INTERFACE_NAME: - g_value_set_boxed (value, nm_strvarray_get_strv (&self->interface_name, NULL)); + g_value_set_boxed (value, nm_strvarray_get_strv_non_empty (self->interface_name, NULL)); break; case PROP_KERNEL_COMMAND_LINE: - g_value_set_boxed (value, nm_strvarray_get_strv (&self->kernel_command_line, NULL)); + g_value_set_boxed (value, nm_strvarray_get_strv_non_empty (self->kernel_command_line, NULL)); break; case PROP_DRIVER: - g_value_set_boxed (value, nm_strvarray_get_strv (&self->driver, NULL)); + g_value_set_boxed (value, nm_strvarray_get_strv_non_empty (self->driver, NULL)); break; case PROP_PATH: - g_value_set_boxed (value, nm_strvarray_get_strv (&self->path, NULL)); + g_value_set_boxed (value, nm_strvarray_get_strv_non_empty (self->path, NULL)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); From 8a13b02d9642c4f8208c6ee0078a28d6127d84d4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2020 13:22:40 +0200 Subject: [PATCH 027/199] libnm: avoid deprecation warning about NMUtilsPredicateStr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NMUtilsPredicateStr got introduced in 1.26.0 API. However, marking the typedef to be available only in 1.26, causes a compiler warning when using the header: /usr/include/libnm/nm-setting.h:372:39: error: ‘NMUtilsPredicateStr’ is deprecated: Not available before 1.26 [-Werror=deprecated-declarations] 372 | NMUtilsPredicateStr predicate); | ^~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Avoid that. It's not a problem in practice, because all users of the typedef are functions that are marked to be available in 1.26 themselves. --- libnm-core/nm-core-types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index ce59ec036e..0237e67625 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -65,7 +65,6 @@ typedef struct _NMSettingWirelessSecurity NMSettingWirelessSecurity; typedef struct _NMSettingWpan NMSettingWpan; typedef struct _NMSimpleConnection NMSimpleConnection; -NM_AVAILABLE_IN_1_26 typedef gboolean (*NMUtilsPredicateStr) (const char *str); #endif /* __NM_CORE_TYPES_H__ */ From c6809df4cdf2f909ffcd98e842447fca523f1c0b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2020 21:19:42 +0200 Subject: [PATCH 028/199] shared: make NM_STR_BUF_INIT() an inline function In the previous form, NM_STR_BUF_INIT() was a macro. That makes sense, however it's not really possible to make that a macro without evaluating the reservation length multiple times. That means, NMStrBuf strbuf = NM_STR_BUF_INIT (nmtst_get_rand_uint32 () % 100, FALSE); leads to a crash. That is unfortunate, so instead make it an inline function that returns a NMStrBut struct. Usually, we avoid functions that returns structs, but here we do it. --- shared/nm-glib-aux/nm-str-buf.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index 7121ba609a..b582e2c8a6 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -39,13 +39,18 @@ _nm_str_buf_assert (NMStrBuf *strbuf) nm_assert (strbuf->_priv_len <= strbuf->_priv_allocated); } -#define NM_STR_BUF_INIT(len, do_bzero_mem) \ - ((NMStrBuf) { \ - ._priv_str = (len) ? g_malloc (len) : NULL, \ - ._priv_allocated = (len), \ - ._priv_len = 0, \ - ._priv_do_bzero_mem = (do_bzero_mem), \ - }) +static inline NMStrBuf +NM_STR_BUF_INIT (gsize allocated, gboolean do_bzero_mem) +{ + NMStrBuf strbuf = { + ._priv_str = allocated ? g_malloc (allocated) : NULL, + ._priv_allocated = allocated, + ._priv_len = 0, + ._priv_do_bzero_mem = do_bzero_mem, + }; + + return strbuf; +} static inline void nm_str_buf_init (NMStrBuf *strbuf, From a2142e884b9090f5b5f42b55381a1f848c2426bb Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2020 21:25:17 +0200 Subject: [PATCH 029/199] shared: add nm_str_buf_append_c_repeated() helper --- shared/nm-glib-aux/nm-str-buf.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index b582e2c8a6..13af81c01d 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -166,6 +166,19 @@ nm_str_buf_erase (NMStrBuf *strbuf, /*****************************************************************************/ +static inline void +nm_str_buf_append_c_repeated (NMStrBuf *strbuf, + char ch, + guint len) +{ + if (len > 0) { + nm_str_buf_maybe_expand (strbuf, len + 1, FALSE); + do { + strbuf->_priv_str[strbuf->_priv_len++] = ch; + } while (--len > 0); + } +} + static inline void nm_str_buf_append_c (NMStrBuf *strbuf, char ch) From 2a6ecf21285d2a7c0c806b6add360437493ff3ba Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2020 19:21:17 +0200 Subject: [PATCH 030/199] tests: add nmtst_extract_first_word_all() for testing We usually don't want to use internal API of systemd for our own purposes. Here, we will use it to check our implementation against systemd's. Add an accessor to extract_first_word() for testing. --- shared/systemd/nm-sd-utils-shared.c | 40 +++++++++++++++++++++++++++++ shared/systemd/nm-sd-utils-shared.h | 4 +++ 2 files changed, 44 insertions(+) diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c index 4444e6c7f6..4fe82ca053 100644 --- a/shared/systemd/nm-sd-utils-shared.c +++ b/shared/systemd/nm-sd-utils-shared.c @@ -137,3 +137,43 @@ nm_sd_http_url_is_valid_https (const char *url) nm_assert (_http_url_is_valid (url, FALSE) == http_url_is_valid (url)); return _http_url_is_valid (url, TRUE); } + +/*****************************************************************************/ + +int +nmtst_systemd_extract_first_word_all (const char *str, char ***out_strv) +{ + gs_unref_ptrarray GPtrArray *arr = NULL; + + /* we implement a str split function to parse `/proc/cmdline`. This + * code should behave like systemd, which uses extract_first_word() + * for that. + * + * As we want to unit-test our implementation to match systemd, + * expose this function for testing. */ + + g_assert (out_strv); + g_assert (!*out_strv); + + if (!str) + return 0; + + arr = g_ptr_array_new_with_free_func (g_free); + + for (;;) { + gs_free char *word = NULL; + int r; + + r = extract_first_word (&str, &word, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX); + if (r < 0) + return r; + if (r == 0) + break; + g_ptr_array_add (arr, g_steal_pointer (&word)); + } + + g_ptr_array_add (arr, NULL); + + *out_strv = (char **) g_ptr_array_free (g_steal_pointer (&arr), FALSE); + return 1; +} diff --git a/shared/systemd/nm-sd-utils-shared.h b/shared/systemd/nm-sd-utils-shared.h index a3ca1edc03..75e38b8422 100644 --- a/shared/systemd/nm-sd-utils-shared.h +++ b/shared/systemd/nm-sd-utils-shared.h @@ -38,4 +38,8 @@ gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot); gboolean nm_sd_http_url_is_valid_https (const char *url); +/*****************************************************************************/ + +int nmtst_systemd_extract_first_word_all (const char *str, char ***out_strv); + #endif /* __NM_SD_UTILS_SHARED_H__ */ From 10779d545a6fe0af8f29e065d251882ff25411fc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2020 19:43:35 +0200 Subject: [PATCH 031/199] shared: add nm_utils_strsplit_quoted() We want to parse "/proc/cmdline". That is space separated with support for quoting and escaping. Our implementation becomes part of stable behavior, and we should interpret the kernel command line the same way as the system does. That means, our implementation should match systemd's. --- libnm-core/tests/test-general.c | 229 +++++++++++++++++++++++++++ shared/nm-glib-aux/nm-shared-utils.c | 94 +++++++++++ shared/nm-glib-aux/nm-shared-utils.h | 4 + 3 files changed, 327 insertions(+) diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 714dcd4236..f70a7d5a65 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -13,6 +13,8 @@ #include "nm-std-aux/c-list-util.h" #include "nm-glib-aux/nm-enum-utils.h" +#include "nm-glib-aux/nm-str-buf.h" +#include "systemd/nm-sd-utils-shared.h" #include "nm-utils.h" #include "nm-setting-private.h" @@ -8869,7 +8871,232 @@ test_connection_ovs_ifname (gconstpointer test_data) } } +/*****************************************************************************/ +static gboolean +_strsplit_quoted_char_needs_escaping (char ch) +{ + return NM_IN_SET (ch, '\'', '\"', '\\') + || strchr (NM_ASCII_WHITESPACES, ch); +} + +static char * +_strsplit_quoted_create_str_rand (gssize len) +{ + NMStrBuf strbuf = NM_STR_BUF_INIT (nmtst_get_rand_uint32 () % 200, nmtst_get_rand_bool ()); + + g_assert (len >= -1); + + if (len == -1) + len = nmtst_get_rand_word_length (NULL); + + while (len-- > 0) { + char ch; + + ch = nmtst_rand_select ('a', ' ', '\\', '"', '\'', nmtst_get_rand_uint32 () % 255 + 1); + g_assert (ch); + nm_str_buf_append_c (&strbuf, ch); + } + + if (!strbuf.allocated) + nm_str_buf_maybe_expand (&strbuf, 1, nmtst_get_rand_bool ()); + return nm_str_buf_finalize (&strbuf, NULL); +} + +static char ** +_strsplit_quoted_create_strv_rand (void) +{ + guint len = nmtst_get_rand_word_length (NULL); + char **ptr; + guint i; + + ptr = g_new (char *, len + 1); + for (i = 0; i < len; i++) + ptr[i] = _strsplit_quoted_create_str_rand (-1); + ptr[i] = NULL; + return ptr; +} + +static char * +_strsplit_quoted_join_strv_rand (const char *const*strv) +{ + NMStrBuf strbuf = NM_STR_BUF_INIT (nmtst_get_rand_uint32 () % 200, nmtst_get_rand_bool ()); + char *result; + gsize l; + gsize l2; + gsize *p_l2 = nmtst_get_rand_bool () ? &l2 : NULL; + gsize i; + + g_assert (strv); + + nm_str_buf_append_c_repeated (&strbuf, ' ', nmtst_get_rand_word_length (NULL) / 4); + for (i = 0; strv[i]; i++) { + const char *s = strv[i]; + gsize j; + char quote; + + nm_str_buf_append_c_repeated (&strbuf, ' ', 1 + nmtst_get_rand_word_length (NULL) / 4); + + j = 0; + quote = '\0'; + while (TRUE) { + char ch = s[j++]; + + /* extract_first_word*/ + if (quote != '\0') { + if (ch == '\0') { + nm_str_buf_append_c (&strbuf, quote); + break; + } + if ( ch == quote + || ch == '\\' + || nmtst_get_rand_uint32 () % 5 == 0) + nm_str_buf_append_c (&strbuf, '\\'); + nm_str_buf_append_c (&strbuf, ch); + if (nmtst_get_rand_uint32 () % 3 == 0) { + nm_str_buf_append_c (&strbuf, quote); + quote = '\0'; + goto next_maybe_quote; + } + continue; + } + + if (ch == '\0') { + if (s == strv[i]) { + quote = nmtst_rand_select ('\'', '"'); + nm_str_buf_append_c_repeated (&strbuf, quote, 2); + } + break; + } + + if ( _strsplit_quoted_char_needs_escaping (ch) + || nmtst_get_rand_uint32 () % 5 == 0) + nm_str_buf_append_c (&strbuf, '\\'); + + nm_str_buf_append_c (&strbuf, ch); + +next_maybe_quote: + if (nmtst_get_rand_uint32 () % 5 == 0) { + quote = nmtst_rand_select ('\'', '\"'); + nm_str_buf_append_c (&strbuf, quote); + if (nmtst_get_rand_uint32 () % 5 == 0) { + nm_str_buf_append_c (&strbuf, quote); + quote = '\0'; + } + } + } + } + nm_str_buf_append_c_repeated (&strbuf, ' ', nmtst_get_rand_word_length (NULL) / 4); + + nm_str_buf_maybe_expand (&strbuf, 1, nmtst_get_rand_bool ()); + + l = strbuf.len; + result = nm_str_buf_finalize (&strbuf, p_l2); + g_assert (!p_l2 || l == *p_l2); + g_assert (strlen (result) == l); + return result; +} + +static void +_strsplit_quoted_assert_strv (const char *topic, + const char *str, + const char *const*strv1, + const char *const*strv2) +{ + nm_auto_str_buf NMStrBuf s1 = { }; + nm_auto_str_buf NMStrBuf s2 = { }; + gs_free char *str_escaped = NULL; + int i; + + g_assert (str); + g_assert (strv1); + g_assert (strv2); + + if (_nm_utils_strv_equal ((char **) strv1, (char **) strv2)) + return; + + for (i = 0; strv1[i]; i++) { + gs_free char *s = g_strescape (strv1[i], NULL); + + g_print (">>> [%s] strv1[%d] = \"%s\"\n", topic, i, s); + if (i > 0) + nm_str_buf_append_c (&s1, ' '); + nm_str_buf_append_printf (&s1, "\"%s\"", s); + } + + for (i = 0; strv2[i]; i++) { + gs_free char *s = g_strescape (strv2[i], NULL); + + g_print (">>> [%s] strv2[%d] = \"%s\"\n", topic, i, s); + if (i > 0) + nm_str_buf_append_c (&s2, ' '); + nm_str_buf_append_printf (&s2, "\"%s\"", s); + } + + nm_str_buf_maybe_expand (&s1, 1, FALSE); + nm_str_buf_maybe_expand (&s2, 1, FALSE); + + str_escaped = g_strescape (str, NULL); + g_error ("compared words differs: [%s] str=\"%s\"; strv1=%s; strv2=%s", topic, str_escaped, nm_str_buf_get_str (&s1), nm_str_buf_get_str (&s2)); +} + +static void +_strsplit_quoted_test (const char *str, + const char *const*strv_expected) +{ + gs_strfreev char **strv_systemd = NULL; + gs_strfreev char **strv_nm = NULL; + int r; + + g_assert (str); + + r = nmtst_systemd_extract_first_word_all (str, &strv_systemd); + g_assert_cmpint (r, ==, 1); + g_assert (strv_systemd); + + if (!strv_expected) + strv_expected = (const char *const*) strv_systemd; + + _strsplit_quoted_assert_strv ("systemd", str, strv_expected, (const char *const*) strv_systemd); + + strv_nm = nm_utils_strsplit_quoted (str); + g_assert (strv_nm); + _strsplit_quoted_assert_strv ("nm", str, strv_expected, (const char *const*) strv_nm); +} + +static void +test_strsplit_quoted (void) +{ + int i_run; + + _strsplit_quoted_test ("", NM_MAKE_STRV ()); + _strsplit_quoted_test (" ", NM_MAKE_STRV ()); + _strsplit_quoted_test (" ", NM_MAKE_STRV ()); + _strsplit_quoted_test (" \t", NM_MAKE_STRV ()); + _strsplit_quoted_test ("a b", NM_MAKE_STRV ("a", "b")); + _strsplit_quoted_test ("a\\ b", NM_MAKE_STRV ("a b")); + _strsplit_quoted_test (" a\\ \"b\"", NM_MAKE_STRV ("a b")); + _strsplit_quoted_test (" a\\ \"b\" c \n", NM_MAKE_STRV ("a b", "c")); + + for (i_run = 0; i_run < 1000; i_run++) { + gs_strfreev char **strv = NULL; + gs_free char *str = NULL; + + /* create random strv array and join them carefully so that splitting + * them will yield the original value. */ + strv = _strsplit_quoted_create_strv_rand (); + str = _strsplit_quoted_join_strv_rand ((const char *const*) strv); + _strsplit_quoted_test (str, (const char *const*) strv); + } + + /* Create random words and assert that systemd and our implementation can + * both split them (and in the exact same way). */ + for (i_run = 0; i_run < 1000; i_run++) { + gs_free char *s = _strsplit_quoted_create_str_rand (nmtst_get_rand_uint32 () % 150); + + _strsplit_quoted_test (s, NULL); + } +} /*****************************************************************************/ @@ -9047,5 +9274,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/test_nm_ip_addr_zero", test_nm_ip_addr_zero); + g_test_add_func ("/core/general/test_strsplit_quoted", test_strsplit_quoted); + return g_test_run (); } diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 39dfe6f473..a2e90273c5 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -2022,6 +2022,100 @@ nm_utils_escaped_tokens_options_split (char *str, /*****************************************************************************/ +/** + * nm_utils_strsplit_quoted: + * @str: the string to split (e.g. from /proc/cmdline). + * + * This basically does that systemd's extract_first_word() does + * with the flags "EXTRACT_UNQUOTE | EXTRACT_RELAX". This is what + * systemd uses to parse /proc/cmdline, and we do too. + * + * Splits the string. We have nm_utils_strsplit_set() which + * supports a variety of flags. However, extending that already + * complex code to also support quotation and escaping is hard. + * Instead, add a naive implementation. + * + * Returns: (transfer full): the split string. + */ +char ** +nm_utils_strsplit_quoted (const char *str) +{ + gs_unref_ptrarray GPtrArray *arr = NULL; + gs_free char *str_out = NULL; + guint8 ch_lookup[256]; + + nm_assert (str); + + _char_lookup_table_init (ch_lookup, NM_ASCII_WHITESPACES); + + for (;;) { + char quote; + gsize j; + + while (_char_lookup_has (ch_lookup, str[0])) + str++; + + if (str[0] == '\0') + break; + + if (!str_out) + str_out = g_new (char, strlen (str) + 1); + + quote = '\0'; + j = 0; + for (;;) { + if (str[0] == '\\') { + str++; + if (str[0] == '\0') + break; + str_out[j++] = str[0]; + str++; + continue; + } + if (quote) { + if (str[0] == '\0') + break; + if (str[0] == quote) { + quote = '\0'; + str++; + continue; + } + str_out[j++] = str[0]; + str++; + continue; + } + if (str[0] == '\0') + break; + if (NM_IN_SET (str[0], '\'', '"')) { + quote = str[0]; + str++; + continue; + } + if (_char_lookup_has (ch_lookup, str[0])) { + str++; + break; + } + str_out[j++] = str[0]; + str++; + } + + if (!arr) + arr = g_ptr_array_new (); + g_ptr_array_add (arr, g_strndup (str_out, j)); + } + + if (!arr) + return g_new0 (char *, 1); + + g_ptr_array_add (arr, NULL); + + /* We want to return an optimally sized strv array, with no excess + * memory allocated. Hence, clone once more. */ + return nm_memdup (arr->pdata, sizeof (char *) * arr->len); +} + +/*****************************************************************************/ + /** * nm_utils_strv_find_first: * @list: the strv list to search diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 0831f11c3d..893ec11c0d 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -681,6 +681,10 @@ nm_utils_escaped_tokens_escape_gstr (const char *str, /*****************************************************************************/ +char **nm_utils_strsplit_quoted (const char *str); + +/*****************************************************************************/ + static inline const char ** nm_utils_escaped_tokens_options_split_list (const char *str) { From 27041e9f05da0473d56866e54218414c480bbfb4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Jun 2020 00:12:45 +0200 Subject: [PATCH 032/199] core: use nm_utils_strsplit_quoted() for splitting the kernel command line The kernel command line supports escaping and quoting (at least, according to systemd's parser, which is our example to follow). Use nm_utils_strsplit_quoted() which supports that. --- src/nm-core-utils.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index bc80dabf35..dc76d1fd9d 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -2778,19 +2778,13 @@ nm_utils_proc_cmdline_split (void) again: proc_cmdline = g_atomic_pointer_get (&proc_cmdline_cached); if (G_UNLIKELY (!proc_cmdline)) { - gs_free const char **split = NULL; + gs_strfreev char **split = NULL; - /* FIXME(release-blocker): support quotation, like systemd's proc_cmdline_extract_first(). - * For that, add a new NMUtilsStrsplitSetFlags flag. */ - split = nm_utils_strsplit_set_full (nm_utils_proc_cmdline (), - NM_ASCII_WHITESPACES, - NM_UTILS_STRSPLIT_SET_FLAGS_NONE); - proc_cmdline = split - ?: NM_PTRARRAY_EMPTY (const char *); - if (!g_atomic_pointer_compare_and_exchange (&proc_cmdline_cached, NULL, proc_cmdline)) + split = nm_utils_strsplit_quoted (nm_utils_proc_cmdline ()); + if (!g_atomic_pointer_compare_and_exchange (&proc_cmdline_cached, NULL, (gpointer) split)) goto again; - g_steal_pointer (&split); + proc_cmdline = (const char *const*) g_steal_pointer (&split); } return proc_cmdline; From f6d654b18f059a0fe2ba82ae05c0c22295c86af4 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 22 Jun 2020 11:56:51 +0200 Subject: [PATCH 033/199] initrd: generate connections with IPv6 method 'auto' instead of 'ignore' When the initrd generator creates a connection with IPv6 method 'ignore', the kernel will do IPv6 autoconfiguration on the interface. However, it is preferable to let NetworkManager configure the interface directly instead of relying on kernel. Therefore, change the IPv6 method to 'auto'. Note that we still set ipv6.may-fail to 'yes' so that a failure during IPv6 autoconfiguration doesn't bring down the interface. --- src/initrd/nmi-cmdline-reader.c | 2 +- src/initrd/tests/test-cmdline-reader.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c index 7513b4c976..2f4a8582fb 100644 --- a/src/initrd/nmi-cmdline-reader.c +++ b/src/initrd/nmi-cmdline-reader.c @@ -479,7 +479,7 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) NULL); if (nm_setting_ip_config_get_num_addresses (s_ip6) == 0) { g_object_set (s_ip6, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); } } else if (nm_streq0 (kind, "dhcp6")) { diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c index 5379c3a3bf..74a6e65cd2 100644 --- a/src/initrd/tests/test-cmdline-reader.c +++ b/src/initrd/tests/test-cmdline-reader.c @@ -191,6 +191,7 @@ test_if_ip4_manual (void) "hostname1.example.com:eth4"); NMConnection *connection; NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; NMIPAddress *ip_addr; gs_free char *hostname = NULL; @@ -237,6 +238,11 @@ test_if_ip4_manual (void) g_assert_cmpint (nm_ip_address_get_prefix (ip_addr), ==, 26); g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "203.0.113.1"); g_assert_cmpstr (nm_setting_ip_config_get_dhcp_hostname (s_ip4), ==, "hostname1.example.com"); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (nm_setting_ip_config_get_may_fail (s_ip6)); } static void @@ -1086,7 +1092,7 @@ test_bootif (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); } @@ -1124,7 +1130,7 @@ test_bootif_hwtype (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); connection = g_hash_table_lookup (connections, "bootif_connection"); From a39eb9ac148dc5566a908d65833033d74da8f16d Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 22 Jun 2020 12:00:22 +0200 Subject: [PATCH 034/199] initrd: set ipv6.method=auto when the autoconfiguration field is 'none' The 7th field of: ip=:[]:::::{none|off|dhcp|on|any|dhcp6|auto6|ibft}:[:[][:]] specifies which kind of autoconfiguration to do. 'none' and 'off' mean static addresses. The old network module of dracut used to leave kernel IPv6 autoconfiguration enabled when IPv4 static addresses were configured. With NM, this corresponds to enabling IPv6 auto method. https://bugzilla.redhat.com/show_bug.cgi?id=1848943 --- src/initrd/nmi-cmdline-reader.c | 2 +- src/initrd/tests/test-cmdline-reader.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c index 2f4a8582fb..69e5e56d07 100644 --- a/src/initrd/nmi-cmdline-reader.c +++ b/src/initrd/nmi-cmdline-reader.c @@ -464,7 +464,7 @@ reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) if (NM_IN_STRSET (kind, "none", "off")) { if (nm_setting_ip_config_get_num_addresses (s_ip6) == 0) { g_object_set (s_ip6, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DISABLED, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); } if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) { diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c index 74a6e65cd2..110770554c 100644 --- a/src/initrd/tests/test-cmdline-reader.c +++ b/src/initrd/tests/test-cmdline-reader.c @@ -186,7 +186,7 @@ test_if_ip4_manual (void) { gs_unref_hashtable GHashTable *connections = NULL; const char *const*ARGV = NM_MAKE_STRV ("ip=192.0.2.2::192.0.2.1:255.255.255.0:" - "hostname0.example.com:eth3::192.0.2.53", + "hostname0.example.com:eth3:none:192.0.2.53", "ip=203.0.113.2::203.0.113.1:26:" "hostname1.example.com:eth4"); NMConnection *connection; @@ -220,6 +220,11 @@ test_if_ip4_manual (void) g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.0.2.1"); g_assert_cmpstr (nm_setting_ip_config_get_dhcp_hostname (s_ip4), ==, "hostname0.example.com"); + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (nm_setting_ip_config_get_may_fail (s_ip6)); + connection = g_hash_table_lookup (connections, "eth4"); g_assert (connection); nmtst_assert_connection_verifies_without_normalization (connection); From 3124a05d8328629a6a1ea49802cad26254d70690 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 18 Jun 2020 09:46:55 +0200 Subject: [PATCH 035/199] libnm: omit nm_device_*_get_hw_address() from introspection output When the get_hw_address() method is called on a device object through GObject-introspection, the device-specific (e.g. nm_device_ethernet_get_hw_address()) C function is called instead of the more generic nm_device_get_hw_address(). Those device-specific functions were deprecated in commit 067a3d6c0861 ('nm-device: expose via D-Bus the 'hw-address' property') and so libnm will print out deprecation warnings like: DeprecationWarning: NM.DeviceEthernet.get_hw_address is deprecated Omit the device-specific function from the introspection output so that the generic function will be called instead. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/544 --- libnm/nm-device-6lowpan.c | 2 +- libnm/nm-device-bond.c | 2 +- libnm/nm-device-bridge.c | 2 +- libnm/nm-device-bt.c | 2 +- libnm/nm-device-dummy.c | 2 +- libnm/nm-device-ethernet.c | 2 +- libnm/nm-device-generic.c | 2 +- libnm/nm-device-infiniband.c | 2 +- libnm/nm-device-macsec.c | 2 +- libnm/nm-device-macvlan.c | 2 +- libnm/nm-device-olpc-mesh.c | 2 +- libnm/nm-device-team.c | 2 +- libnm/nm-device-tun.c | 2 +- libnm/nm-device-vlan.c | 2 +- libnm/nm-device-vxlan.c | 2 +- libnm/nm-device-wifi-p2p.c | 2 +- libnm/nm-device-wifi.c | 2 +- libnm/nm-device-wpan.c | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libnm/nm-device-6lowpan.c b/libnm/nm-device-6lowpan.c index 0b428c2d8b..b4f378496c 100644 --- a/libnm/nm-device-6lowpan.c +++ b/libnm/nm-device-6lowpan.c @@ -51,7 +51,7 @@ nm_device_6lowpan_get_parent (NMDevice6Lowpan *device) } /** - * nm_device_6lowpan_get_hw_address: + * nm_device_6lowpan_get_hw_address: (skip) * @device: a #NMDevice6Lowpan * * Gets the hardware (MAC) address of the #NMDevice6Lowpan diff --git a/libnm/nm-device-bond.c b/libnm/nm-device-bond.c index cb236af931..ebc438a957 100644 --- a/libnm/nm-device-bond.c +++ b/libnm/nm-device-bond.c @@ -42,7 +42,7 @@ G_DEFINE_TYPE (NMDeviceBond, nm_device_bond, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_bond_get_hw_address: + * nm_device_bond_get_hw_address: (skip) * @device: a #NMDeviceBond * * Gets the hardware (MAC) address of the #NMDeviceBond diff --git a/libnm/nm-device-bridge.c b/libnm/nm-device-bridge.c index 977db1464e..9552c2df84 100644 --- a/libnm/nm-device-bridge.c +++ b/libnm/nm-device-bridge.c @@ -41,7 +41,7 @@ G_DEFINE_TYPE (NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_bridge_get_hw_address: + * nm_device_bridge_get_hw_address: (skip) * @device: a #NMDeviceBridge * * Gets the hardware (MAC) address of the #NMDeviceBridge diff --git a/libnm/nm-device-bt.c b/libnm/nm-device-bt.c index 8df952655b..e8dc02ffa0 100644 --- a/libnm/nm-device-bt.c +++ b/libnm/nm-device-bt.c @@ -42,7 +42,7 @@ G_DEFINE_TYPE (NMDeviceBt, nm_device_bt, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_bt_get_hw_address: + * nm_device_bt_get_hw_address: (skip) * @device: a #NMDeviceBt * * Gets the hardware (MAC) address of the #NMDeviceBt diff --git a/libnm/nm-device-dummy.c b/libnm/nm-device-dummy.c index 3bf8e09f4a..4b62fbf0ac 100644 --- a/libnm/nm-device-dummy.c +++ b/libnm/nm-device-dummy.c @@ -28,7 +28,7 @@ G_DEFINE_TYPE (NMDeviceDummy, nm_device_dummy, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_dummy_get_hw_address: + * nm_device_dummy_get_hw_address: (skip) * @device: a #NMDeviceDummy * * Gets the hardware (MAC) address of the #NMDeviceDummy diff --git a/libnm/nm-device-ethernet.c b/libnm/nm-device-ethernet.c index 944f7b8139..7152784af7 100644 --- a/libnm/nm-device-ethernet.c +++ b/libnm/nm-device-ethernet.c @@ -46,7 +46,7 @@ G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_ethernet_get_hw_address: + * nm_device_ethernet_get_hw_address: (skip) * @device: a #NMDeviceEthernet * * Gets the active hardware (MAC) address of the #NMDeviceEthernet diff --git a/libnm/nm-device-generic.c b/libnm/nm-device-generic.c index 3751cb5147..2b9c96a8f2 100644 --- a/libnm/nm-device-generic.c +++ b/libnm/nm-device-generic.c @@ -37,7 +37,7 @@ G_DEFINE_TYPE (NMDeviceGeneric, nm_device_generic, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_generic_get_hw_address: + * nm_device_generic_get_hw_address: (skip) * @device: a #NMDeviceGeneric * * Gets the hardware address of the #NMDeviceGeneric diff --git a/libnm/nm-device-infiniband.c b/libnm/nm-device-infiniband.c index ad47c2ed4c..194bb1993f 100644 --- a/libnm/nm-device-infiniband.c +++ b/libnm/nm-device-infiniband.c @@ -38,7 +38,7 @@ G_DEFINE_TYPE (NMDeviceInfiniband, nm_device_infiniband, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_infiniband_get_hw_address: + * nm_device_infiniband_get_hw_address: (skip) * @device: a #NMDeviceInfiniband * * Gets the hardware (MAC) address of the #NMDeviceInfiniband diff --git a/libnm/nm-device-macsec.c b/libnm/nm-device-macsec.c index d8352f9c09..1396cb6650 100644 --- a/libnm/nm-device-macsec.c +++ b/libnm/nm-device-macsec.c @@ -77,7 +77,7 @@ nm_device_macsec_get_parent (NMDeviceMacsec *device) } /** - * nm_device_macsec_get_hw_address: + * nm_device_macsec_get_hw_address: (skip) * @device: a #NMDeviceMacsec * * Gets the hardware (MAC) address of the #NMDeviceMacsec diff --git a/libnm/nm-device-macvlan.c b/libnm/nm-device-macvlan.c index 83dc0e25b8..3b3ce115c9 100644 --- a/libnm/nm-device-macvlan.c +++ b/libnm/nm-device-macvlan.c @@ -116,7 +116,7 @@ nm_device_macvlan_get_tap (NMDeviceMacvlan *device) } /** - * nm_device_macvlan_get_hw_address: + * nm_device_macvlan_get_hw_address: (skip) * @device: a #NMDeviceMacvlan * * Gets the hardware (MAC) address of the #NMDeviceMacvlan diff --git a/libnm/nm-device-olpc-mesh.c b/libnm/nm-device-olpc-mesh.c index d6fa03f19e..ebdce2a8d4 100644 --- a/libnm/nm-device-olpc-mesh.c +++ b/libnm/nm-device-olpc-mesh.c @@ -40,7 +40,7 @@ G_DEFINE_TYPE (NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_olpc_mesh_get_hw_address: + * nm_device_olpc_mesh_get_hw_address: (skip) * @device: a #NMDeviceOlpcMesh * * Gets the hardware (MAC) address of the #NMDeviceOlpcMesh diff --git a/libnm/nm-device-team.c b/libnm/nm-device-team.c index 5e97a7df83..08588665e2 100644 --- a/libnm/nm-device-team.c +++ b/libnm/nm-device-team.c @@ -43,7 +43,7 @@ G_DEFINE_TYPE (NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_team_get_hw_address: + * nm_device_team_get_hw_address: (skip) * @device: a #NMDeviceTeam * * Gets the hardware (MAC) address of the #NMDeviceTeam diff --git a/libnm/nm-device-tun.c b/libnm/nm-device-tun.c index 26e4a318ad..e7ea07faff 100644 --- a/libnm/nm-device-tun.c +++ b/libnm/nm-device-tun.c @@ -50,7 +50,7 @@ G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_tun_get_hw_address: + * nm_device_tun_get_hw_address: (skip) * @device: a #NMDeviceTun * * Gets the hardware (MAC) address of the #NMDeviceTun diff --git a/libnm/nm-device-vlan.c b/libnm/nm-device-vlan.c index fdc2193696..5debf789b8 100644 --- a/libnm/nm-device-vlan.c +++ b/libnm/nm-device-vlan.c @@ -43,7 +43,7 @@ G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_vlan_get_hw_address: + * nm_device_vlan_get_hw_address: (skip) * @device: a #NMDeviceVlan * * Gets the hardware (MAC) address of the #NMDeviceVlan diff --git a/libnm/nm-device-vxlan.c b/libnm/nm-device-vxlan.c index c048a980ce..9c8e4fc9ff 100644 --- a/libnm/nm-device-vxlan.c +++ b/libnm/nm-device-vxlan.c @@ -69,7 +69,7 @@ G_DEFINE_TYPE (NMDeviceVxlan, nm_device_vxlan, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_vxlan_get_hw_address: + * nm_device_vxlan_get_hw_address: (skip) * @device: a #NMDeviceVxlan * * Gets the hardware (MAC) address of the #NMDeviceVxlan diff --git a/libnm/nm-device-wifi-p2p.c b/libnm/nm-device-wifi-p2p.c index 972983d16e..9927ee874b 100644 --- a/libnm/nm-device-wifi-p2p.c +++ b/libnm/nm-device-wifi-p2p.c @@ -51,7 +51,7 @@ G_DEFINE_TYPE (NMDeviceWifiP2P, nm_device_wifi_p2p, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_wifi_p2p_get_hw_address: + * nm_device_wifi_p2p_get_hw_address: (skip) * @device: a #NMDeviceWifiP2P * * Gets the actual hardware (MAC) address of the #NMDeviceWifiP2P diff --git a/libnm/nm-device-wifi.c b/libnm/nm-device-wifi.c index 5c12b67620..5d7feca312 100644 --- a/libnm/nm-device-wifi.c +++ b/libnm/nm-device-wifi.c @@ -65,7 +65,7 @@ G_DEFINE_TYPE (NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_wifi_get_hw_address: + * nm_device_wifi_get_hw_address: (skip) * @device: a #NMDeviceWifi * * Gets the actual hardware (MAC) address of the #NMDeviceWifi diff --git a/libnm/nm-device-wpan.c b/libnm/nm-device-wpan.c index 9cbf4ae042..8a52e031e8 100644 --- a/libnm/nm-device-wpan.c +++ b/libnm/nm-device-wpan.c @@ -25,7 +25,7 @@ G_DEFINE_TYPE (NMDeviceWpan, nm_device_wpan, NM_TYPE_DEVICE) /*****************************************************************************/ /** - * nm_device_wpan_get_hw_address: + * nm_device_wpan_get_hw_address: (skip) * @device: a #NMDeviceWpan * * Gets the active hardware (MAC) address of the #NMDeviceWpan From d0a2eb8f050d753fa2ca65bbab00ef192bec66d2 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 25 Jun 2020 14:03:57 +0200 Subject: [PATCH 036/199] libnm: fix wrong assertion in nm_client_check_connectivity_finish() https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/476 Fixes: b44d883d920d ('libnm: implement nm_client_check_connectivity_async() by using GDBusConnection directly') --- libnm/nm-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnm/nm-client.c b/libnm/nm-client.c index 604a510d24..d7f61152dc 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -4576,7 +4576,7 @@ nm_client_check_connectivity_finish (NMClient *client, guint32 connectivity; g_return_val_if_fail (NM_IS_CLIENT (client), NM_CONNECTIVITY_UNKNOWN); - g_return_val_if_fail (nm_g_task_is_valid (client, result, nm_client_check_connectivity_async), NM_CONNECTIVITY_UNKNOWN); + g_return_val_if_fail (nm_g_task_is_valid (result, client, nm_client_check_connectivity_async), NM_CONNECTIVITY_UNKNOWN); ret = g_task_propagate_pointer (G_TASK (result), error); if (!ret) From 081650eb67cf85e741d8e30babb9b7884b4fd36f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 22:40:17 +0200 Subject: [PATCH 037/199] shared: avoid copying empty string in nm_str_buf_append_printf() --- shared/nm-glib-aux/nm-shared-utils.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index a2e90273c5..48635df343 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -4966,7 +4966,12 @@ nm_str_buf_append_printf (NMStrBuf *strbuf, nm_assert (l < G_MAXINT); if ((gsize) l >= available) { - gsize l2 = ((gsize) l) + 1u; + gsize l2; + + if (l == 0) + return; + + l2 = ((gsize) l) + 1u; nm_str_buf_maybe_expand (strbuf, l2, FALSE); From de4df9f5297b6d20cec0a2044f2563dd3c98d149 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 26 Jun 2020 09:28:32 +0200 Subject: [PATCH 038/199] shared: return non-const pointer from nm_str_buf_get_str() It's more convenient in certain cases. The user is allowed to modified the content of the returned buffer. --- shared/nm-glib-aux/nm-str-buf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index 13af81c01d..da082abe67 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -281,7 +281,7 @@ nm_str_buf_is_initalized (NMStrBuf *strbuf) * NUL character is always present after "strbuf->len" characters. * If currently no buffer is allocated, this will return %NULL. */ -static inline const char * +static inline char * nm_str_buf_get_str (NMStrBuf *strbuf) { _nm_str_buf_assert (strbuf); From 506f95ecaf45bf344034a16c3ab353885ed57763 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 20 Jun 2020 20:27:48 +0200 Subject: [PATCH 039/199] shared: add NM_UTILS_GET_NEXT_REALLOC_SIZE_32 and _40 macros --- shared/nm-glib-aux/nm-shared-utils.h | 2 ++ shared/nm-glib-aux/tests/test-shared-general.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 893ec11c0d..589275739c 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1985,6 +1985,8 @@ void nm_indirect_g_free (gpointer arg); * via nm_utils_get_next_realloc_size() gives you 232, and so on. By using * these sizes, it results in one less allocation, if you anyway don't know the * exact size in advance. */ +#define NM_UTILS_GET_NEXT_REALLOC_SIZE_32 ((gsize) 32) +#define NM_UTILS_GET_NEXT_REALLOC_SIZE_40 ((gsize) 40) #define NM_UTILS_GET_NEXT_REALLOC_SIZE_104 ((gsize) 104) #define NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 ((gsize) 1000) diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c index 5c8bdf18e8..a435e28195 100644 --- a/shared/nm-glib-aux/tests/test-shared-general.c +++ b/shared/nm-glib-aux/tests/test-shared-general.c @@ -636,6 +636,8 @@ test_nm_utils_get_next_realloc_size (void) { G_MAXSIZE - 24u, G_MAXSIZE, G_MAXSIZE }, { G_MAXSIZE - 1u, G_MAXSIZE, G_MAXSIZE }, { G_MAXSIZE, G_MAXSIZE, G_MAXSIZE }, + { NM_UTILS_GET_NEXT_REALLOC_SIZE_32, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, NM_UTILS_GET_NEXT_REALLOC_SIZE_32 }, + { NM_UTILS_GET_NEXT_REALLOC_SIZE_40, NM_UTILS_GET_NEXT_REALLOC_SIZE_40, NM_UTILS_GET_NEXT_REALLOC_SIZE_40 }, { NM_UTILS_GET_NEXT_REALLOC_SIZE_104, NM_UTILS_GET_NEXT_REALLOC_SIZE_104, NM_UTILS_GET_NEXT_REALLOC_SIZE_104 }, { NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 }, }; From d53abfd9898e33d375693837cc491168a986b450 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 11:25:33 +0200 Subject: [PATCH 040/199] shared: add nm_str_buf_append0() and nm_str_buf_append_len0() helper These are basically nm_str_buf_append()/nm_str_buf_append_len() and nm_str_buf_get_str() in one. --- shared/nm-glib-aux/nm-str-buf.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index da082abe67..a2253ae89a 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -225,6 +225,25 @@ nm_str_buf_append_len (NMStrBuf *strbuf, } } +static inline char * +nm_str_buf_append_len0 (NMStrBuf *strbuf, + const char *str, + gsize len) +{ + _nm_str_buf_assert (strbuf); + + /* this is basically like nm_str_buf_append_len() and + * nm_str_buf_get_str() in one. */ + + nm_str_buf_maybe_expand (strbuf, len + 1u, FALSE); + if (len > 0) { + memcpy (&strbuf->_priv_str[strbuf->_priv_len], str, len); + strbuf->_priv_len += len; + } + strbuf->_priv_str[strbuf->_priv_len] = '\0'; + return strbuf->_priv_str; +} + static inline void nm_str_buf_append (NMStrBuf *strbuf, const char *str) @@ -234,6 +253,15 @@ nm_str_buf_append (NMStrBuf *strbuf, nm_str_buf_append_len (strbuf, str, strlen (str)); } +static inline char * +nm_str_buf_append0 (NMStrBuf *strbuf, + const char *str) +{ + nm_assert (str); + + return nm_str_buf_append_len0 (strbuf, str, strlen (str)); +} + void nm_str_buf_append_printf (NMStrBuf *strbuf, const char *format, ...) _nm_printf (2, 3); From 069be33fbdc0a6f925795b9ac7bdc7712b9799ba Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 20 Jun 2020 19:43:23 +0200 Subject: [PATCH 041/199] shared: add nm_hexchar() helper --- shared/nm-glib-aux/nm-shared-utils.c | 3 +++ shared/nm-glib-aux/nm-shared-utils.h | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 48635df343..8290016448 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -23,6 +23,9 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMUtilsNamedValue, value_ptr) == sizeof (const /*****************************************************************************/ +const char _nm_hexchar_table_lower[16] = "0123456789abcdef"; +const char _nm_hexchar_table_upper[16] = "0123456789ABCDEF"; + const void *const _NM_PTRARRAY_EMPTY[1] = { NULL }; /*****************************************************************************/ diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 589275739c..43b8288b0a 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -1809,6 +1809,17 @@ int nm_utils_getpagesize (void); /*****************************************************************************/ +extern const char _nm_hexchar_table_lower[16]; +extern const char _nm_hexchar_table_upper[16]; + +static inline char +nm_hexchar (int x, gboolean upper_case) +{ + return upper_case + ? _nm_hexchar_table_upper[x & 15] + : _nm_hexchar_table_lower[x & 15]; +} + char *nm_utils_bin2hexstr_full (gconstpointer addr, gsize length, char delimiter, From 85e27b1f9c8b6977d2dd23982e9a869f2996ee04 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 20 Jun 2020 19:43:56 +0200 Subject: [PATCH 042/199] shared: add nm_str_buf_append_c_hex() helper --- shared/nm-glib-aux/nm-str-buf.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index a2253ae89a..a8cbc847e0 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -211,6 +211,16 @@ nm_str_buf_append_c4 (NMStrBuf *strbuf, strbuf->_priv_str[strbuf->_priv_len++] = ch3; } +static inline void +nm_str_buf_append_c_hex (NMStrBuf *strbuf, + char ch, + gboolean upper_case) +{ + nm_str_buf_maybe_expand (strbuf, 3, FALSE); + strbuf->_priv_str[strbuf->_priv_len++] = nm_hexchar (((guchar) ch) >> 4, upper_case); + strbuf->_priv_str[strbuf->_priv_len++] = nm_hexchar ((guchar) ch, upper_case); +} + static inline void nm_str_buf_append_len (NMStrBuf *strbuf, const char *str, From 5222f1b5ff0782248426b42d77996c9c7e226654 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 12:11:24 +0200 Subject: [PATCH 043/199] shared: add nm_str_buf_append_required_delimiter() --- shared/nm-glib-aux/nm-str-buf.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index a8cbc847e0..e798e736a5 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -286,6 +286,19 @@ nm_str_buf_ensure_trailing_c (NMStrBuf *strbuf, char ch) nm_str_buf_append_c (strbuf, ch); } +static inline NMStrBuf * +nm_str_buf_append_required_delimiter (NMStrBuf *strbuf, + char delimiter) +{ + _nm_str_buf_assert (strbuf); + + /* appends the @delimiter if it is required (that is, if the + * string is not empty). */ + if (strbuf->len > 0) + nm_str_buf_append_c (strbuf, delimiter); + return strbuf; +} + /*****************************************************************************/ static inline gboolean From a5a56565822b892a83273b4444ff866c5cdea112 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 20 Jun 2020 20:17:25 +0200 Subject: [PATCH 044/199] shared: add nm_utils_escaped_tokens_escape_unnecessary() util --- shared/nm-glib-aux/nm-shared-utils.h | 39 +++++++++++++++++----------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 43b8288b0a..c16a89b3af 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -631,23 +631,24 @@ nm_utils_escaped_tokens_escape (const char *str, out_to_free); } -static inline GString * -nm_utils_escaped_tokens_escape_gstr_assert (const char *str, - const char *delimiters, - GString *gstring) +/** + * nm_utils_escaped_tokens_escape_unnecessary: + * @str: the string to check for "escape" + * @delimiters: the delimiters + * + * This asserts that calling nm_utils_escaped_tokens_escape() + * on @str has no effect and returns @str directly. This is only + * for asserting that @str is safe to not require any escaping. + * + * Returns: @str + */ +static inline const char * +nm_utils_escaped_tokens_escape_unnecessary (const char *str, + const char *delimiters) { #if NM_MORE_ASSERTS > 0 - /* Just appends @str to @gstring, but also assert that - * no escaping is necessary. - * - * Use nm_utils_escaped_tokens_escape_gstr_assert() instead - * of nm_utils_escaped_tokens_escape_gstr(), if you *know* that - * @str contains no delimiters, no backslashes, and no trailing - * whitespace that requires escaping. */ - nm_assert (str); - nm_assert (gstring); nm_assert (delimiters); { @@ -660,8 +661,16 @@ nm_utils_escaped_tokens_escape_gstr_assert (const char *str, } #endif - g_string_append (gstring, str); - return gstring; + return str; +} + +static inline void +nm_utils_escaped_tokens_escape_gstr_assert (const char *str, + const char *delimiters, + GString *gstring) +{ + g_string_append (gstring, + nm_utils_escaped_tokens_escape_unnecessary (str, delimiters)); } static inline GString * From d83908b6a165b9674cfd379f47f8d8a50075ec84 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 12:14:43 +0200 Subject: [PATCH 045/199] shared: add nm_utils_escaped_tokens_escape_strbuf*() helpers --- shared/nm-glib-aux/nm-str-buf.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index e798e736a5..3b472ca557 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -301,6 +301,34 @@ nm_str_buf_append_required_delimiter (NMStrBuf *strbuf, /*****************************************************************************/ +/* Calls nm_utils_escaped_tokens_escape() on @str and appends the + * result to @strbuf. */ +static inline void +nm_utils_escaped_tokens_escape_strbuf (const char *str, + const char *delimiters, + NMStrBuf *strbuf) +{ + gs_free char *str_to_free = NULL; + + nm_assert (str); + + nm_str_buf_append (strbuf, + nm_utils_escaped_tokens_escape (str, delimiters, &str_to_free)); +} + +/* Calls nm_utils_escaped_tokens_escape_unnecessary() on @str and appends the + * string to @strbuf. */ +static inline void +nm_utils_escaped_tokens_escape_strbuf_assert (const char *str, + const char *delimiters, + NMStrBuf *strbuf) +{ + nm_str_buf_append (strbuf, + nm_utils_escaped_tokens_escape_unnecessary (str, delimiters)); +} + +/*****************************************************************************/ + static inline gboolean nm_str_buf_is_initalized (NMStrBuf *strbuf) { From 45b346554a65258f4a26ebf8f9b3200514265270 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 13:32:47 +0200 Subject: [PATCH 046/199] shared: add nm_str_buf_reset() helper --- shared/nm-glib-aux/nm-str-buf.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index 3b472ca557..61246969de 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -299,6 +299,24 @@ nm_str_buf_append_required_delimiter (NMStrBuf *strbuf, return strbuf; } +static inline void +nm_str_buf_reset (NMStrBuf *strbuf, + const char *str) +{ + _nm_str_buf_assert (strbuf); + + if (strbuf->_priv_len > 0) { + if (strbuf->_priv_do_bzero_mem) { + /* we only clear the memory that we wrote to. */ + nm_explicit_bzero (strbuf->_priv_str, strbuf->_priv_len); + } + strbuf->_priv_len = 0; + } + + if (str) + nm_str_buf_append (strbuf, str); +} + /*****************************************************************************/ /* Calls nm_utils_escaped_tokens_escape() on @str and appends the From f7715c6680d3cae82812e26353208058f082c985 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 20 Jun 2020 20:32:48 +0200 Subject: [PATCH 047/199] libnm: use NMStrBuf in "nm-setting-bridge.c" --- libnm-core/nm-core-internal.h | 4 ---- libnm-core/nm-setting-bridge.c | 35 ++++++++++------------------------ 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 1d67b09408..a5ccaeaa5c 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -894,10 +894,6 @@ gboolean nm_utils_base64secret_normalize (const char *base64_key, /*****************************************************************************/ -void _nm_bridge_vlan_str_append_rest (const NMBridgeVlan *vlan, - GString *string, - gboolean leading_space); - gboolean nm_utils_connection_is_adhoc_wpa (NMConnection *connection); const char *nm_utils_wifi_freq_to_band (guint32 freq); diff --git a/libnm-core/nm-setting-bridge.c b/libnm-core/nm-setting-bridge.c index 2ead27393e..0595af8730 100644 --- a/libnm-core/nm-setting-bridge.c +++ b/libnm-core/nm-setting-bridge.c @@ -10,6 +10,7 @@ #include #include +#include "nm-glib-aux/nm-str-buf.h" #include "nm-connection-private.h" #include "nm-utils.h" #include "nm-utils-private.h" @@ -407,25 +408,6 @@ nm_bridge_vlan_new_clone (const NMBridgeVlan *vlan) return copy; } -void -_nm_bridge_vlan_str_append_rest (const NMBridgeVlan *vlan, - GString *string, - gboolean leading_space) -{ - if (nm_bridge_vlan_is_pvid (vlan)) { - if (leading_space) - g_string_append_c (string, ' '); - g_string_append (string, "pvid"); - leading_space = TRUE; - } - if (nm_bridge_vlan_is_untagged (vlan)) { - if (leading_space) - g_string_append_c (string, ' '); - g_string_append (string, "untagged"); - leading_space = TRUE; - } -} - /** * nm_bridge_vlan_to_str: * @vlan: the %NMBridgeVlan @@ -440,7 +422,7 @@ _nm_bridge_vlan_str_append_rest (const NMBridgeVlan *vlan, char * nm_bridge_vlan_to_str (const NMBridgeVlan *vlan, GError **error) { - GString *string; + NMStrBuf string; g_return_val_if_fail (vlan, NULL); g_return_val_if_fail (!error || !*error, NULL); @@ -449,16 +431,19 @@ nm_bridge_vlan_to_str (const NMBridgeVlan *vlan, GError **error) * future if more parameters are added to the object that could * make it invalid. */ - string = g_string_sized_new (28); + nm_str_buf_init (&string, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); if (vlan->vid_start == vlan->vid_end) - g_string_append_printf (string, "%u", vlan->vid_start); + nm_str_buf_append_printf (&string, "%u", vlan->vid_start); else - g_string_append_printf (string, "%u-%u", vlan->vid_start, vlan->vid_end); + nm_str_buf_append_printf (&string, "%u-%u", vlan->vid_start, vlan->vid_end); - _nm_bridge_vlan_str_append_rest (vlan, string, TRUE); + if (nm_bridge_vlan_is_pvid (vlan)) + nm_str_buf_append (&string, " pvid"); + if (nm_bridge_vlan_is_untagged (vlan)) + nm_str_buf_append (&string, " untagged"); - return g_string_free (string, FALSE); + return nm_str_buf_finalize (&string, NULL); } /** From 3be4f38a159928ec9818ebe96b025ecb3b7a3700 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 20 Jun 2020 19:31:58 +0200 Subject: [PATCH 048/199] keyfile: cleanup uses of GString in keyfile code - in _keyfile_key_decode(), don't use GString. We know the maximum string length before, so we can just allocated one buffer. - in qdisc and tfilter writers, reuse the same GString instance. No need to allocate a new temporary string buffer for each iteration. - at other places, replace GString by NMStrBuf. This avoids the heap allocated GString instance. Also, most operations can be inlined. This results in larger code side, but avoids function calls to glib. --- libnm-core/nm-keyfile/nm-keyfile-utils.c | 44 ++-- libnm-core/nm-keyfile/nm-keyfile.c | 249 ++++++++++++----------- 2 files changed, 155 insertions(+), 138 deletions(-) diff --git a/libnm-core/nm-keyfile/nm-keyfile-utils.c b/libnm-core/nm-keyfile/nm-keyfile-utils.c index 0ffce40b96..e8119b1bd3 100644 --- a/libnm-core/nm-keyfile/nm-keyfile-utils.c +++ b/libnm-core/nm-keyfile/nm-keyfile-utils.c @@ -504,8 +504,9 @@ static const char * _keyfile_key_encode (const char *name, char **out_to_free) { - gsize len, i; - GString *str; + NMStrBuf str; + gsize len; + gsize i; nm_assert (name); nm_assert (out_to_free && !*out_to_free); @@ -555,14 +556,15 @@ _keyfile_key_encode (const char *name, len = i + strlen (&name[i]); nm_assert (len == strlen (name)); - str = g_string_sized_new (len + 15); + + nm_str_buf_init (&str, len + 15u, FALSE); if (name[0] == ' ') { nm_assert (i == 0); - g_string_append (str, "\\20"); + nm_str_buf_append (&str, "\\20"); i = 1; } else - g_string_append_len (str, name, i); + nm_str_buf_append_len (&str, name, i); for (;; i++) { const guchar ch = (guchar) name[i]; @@ -577,21 +579,24 @@ _keyfile_key_encode (const char *name, && g_ascii_isxdigit (name[i + 1]) && g_ascii_isxdigit (name[i + 2])) || ( ch == ' ' - && name[i + 1] == '\0')) - g_string_append_printf (str, "\\%02X", ch); - else - g_string_append_c (str, (char) ch); + && name[i + 1] == '\0')) { + nm_str_buf_append_c (&str, '\\'); + nm_str_buf_append_c_hex (&str, ch, TRUE); + } else + nm_str_buf_append_c (&str, (char) ch); } - return (*out_to_free = g_string_free (str, FALSE)); + return (*out_to_free = nm_str_buf_finalize (&str, NULL)); } static const char * _keyfile_key_decode (const char *key, char **out_to_free) { - gsize i, len; - GString *str; + char *out; + gsize len; + gsize i; + gsize j; nm_assert (key); nm_assert (out_to_free && !*out_to_free); @@ -617,9 +622,12 @@ _keyfile_key_decode (const char *key, return ""; nm_assert (len == strlen (key)); - str = g_string_sized_new (len + 3); - g_string_append_len (str, key, i); + out = g_new (char, len + 1u); + + memcpy (out, key, sizeof (char) * i); + + j = i; for (;;) { const char ch = key[i]; char ch1, ch2; @@ -633,16 +641,18 @@ _keyfile_key_decode (const char *key, && g_ascii_isxdigit ((ch2 = key[i + 2]))) { v = (g_ascii_xdigit_value (ch1) << 4) + g_ascii_xdigit_value (ch2); if (v != 0) { - g_string_append_c (str, (char) v); + out[j++] = (char) v; i += 3; continue; } } - g_string_append_c (str, ch); + out[j++] = ch; i++; } - return (*out_to_free = g_string_free (str, FALSE)); + nm_assert (j <= len); + out[j] = '\0'; + return (*out_to_free = out); } /*****************************************************************************/ diff --git a/libnm-core/nm-keyfile/nm-keyfile.c b/libnm-core/nm-keyfile/nm-keyfile.c index 77af2b6492..aeaf527450 100644 --- a/libnm-core/nm-keyfile/nm-keyfile.c +++ b/libnm-core/nm-keyfile/nm-keyfile.c @@ -16,6 +16,7 @@ #include #include +#include "nm-glib-aux/nm-str-buf.h" #include "nm-glib-aux/nm-secret-utils.h" #include "systemd/nm-sd-utils-shared.h" #include "nm-libnm-core-intern/nm-common-macros.h" @@ -2107,79 +2108,81 @@ write_ip_values (GKeyFile *file, const char *gateway, gboolean is_route) { - nm_auto_free_gstring GString *output = NULL; - int addr_family; - guint i; - const char *addr; - const char *gw; - guint32 plen; - char key_name[64]; - char *key_name_idx; + if (array->len > 0) { + nm_auto_str_buf NMStrBuf output = NM_STR_BUF_INIT (2*INET_ADDRSTRLEN + 10, FALSE); + int addr_family; + guint i; + const char *addr; + const char *gw; + guint32 plen; + char key_name[64]; + char *key_name_idx; - if (!array->len) - return; + addr_family = nm_streq (setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME) + ? AF_INET + : AF_INET6; - addr_family = nm_streq (setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME) - ? AF_INET - : AF_INET6; + strcpy (key_name, is_route ? "route" : "address"); + key_name_idx = key_name + strlen (key_name); - strcpy (key_name, is_route ? "route" : "address"); - key_name_idx = key_name + strlen (key_name); + for (i = 0; i < array->len; i++) { + gint64 metric = -1; - output = g_string_sized_new (2*INET_ADDRSTRLEN + 10); - for (i = 0; i < array->len; i++) { - gint64 metric = -1; + if (is_route) { + NMIPRoute *route = array->pdata[i]; - if (is_route) { - NMIPRoute *route = array->pdata[i]; + addr = nm_ip_route_get_dest (route); + plen = nm_ip_route_get_prefix (route); + gw = nm_ip_route_get_next_hop (route); + metric = nm_ip_route_get_metric (route); + } else { + NMIPAddress *address = array->pdata[i]; - addr = nm_ip_route_get_dest (route); - plen = nm_ip_route_get_prefix (route); - gw = nm_ip_route_get_next_hop (route); - metric = nm_ip_route_get_metric (route); - } else { - NMIPAddress *address = array->pdata[i]; - - addr = nm_ip_address_get_address (address); - plen = nm_ip_address_get_prefix (address); - gw = (i == 0) - ? gateway - : NULL; - } - - g_string_set_size (output, 0); - g_string_append_printf (output, "%s/%u", addr, plen); - if ( metric != -1 - || gw) { - /* Older versions of the plugin do not support the form - * "a.b.c.d/plen,,metric", so, we always have to write the - * gateway, even if there isn't one. - * The current version supports reading of the above form. - */ - if (!gw) { - if (addr_family == AF_INET) - gw = "0.0.0.0"; - else - gw = "::"; + addr = nm_ip_address_get_address (address); + plen = nm_ip_address_get_prefix (address); + gw = (i == 0) + ? gateway + : NULL; } - g_string_append_printf (output, ",%s", gw); - if ( is_route - && metric != -1) - g_string_append_printf (output, ",%lu", (unsigned long) metric); - } + nm_str_buf_set_size (&output, 0, FALSE, FALSE); + nm_str_buf_append_printf (&output, "%s/%u", addr, plen); + if ( metric != -1 + || gw) { + /* Older versions of the plugin do not support the form + * "a.b.c.d/plen,,metric", so, we always have to write the + * gateway, even if there isn't one. + * The current version supports reading of the above form. + */ + if (!gw) { + if (addr_family == AF_INET) + gw = "0.0.0.0"; + else + gw = "::"; + } - sprintf (key_name_idx, "%u", i + 1); - nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, output->str); + nm_str_buf_append_c (&output, ','); + nm_str_buf_append (&output, gw); + if ( is_route + && metric != -1) + nm_str_buf_append_printf (&output, ",%lu", (unsigned long) metric); + } - if (is_route) { - gs_free char *attributes = NULL; + sprintf (key_name_idx, "%u", i + 1); + nm_keyfile_plugin_kf_set_string (file, + setting_name, + key_name, + nm_str_buf_get_str (&output)); - attributes = nm_utils_format_variant_attributes (_nm_ip_route_get_attributes (array->pdata[i]), - ',', '='); - if (attributes) { - g_strlcat (key_name, "_options", sizeof (key_name)); - nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, attributes); + if (is_route) { + gs_free char *attributes = NULL; + + attributes = nm_utils_format_variant_attributes (_nm_ip_route_get_attributes (array->pdata[i]), + ',', '='); + if (attributes) { + g_strlcat (key_name, "_options", sizeof (key_name)); + nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, attributes); + } } } } @@ -2220,34 +2223,29 @@ bridge_vlan_writer (KeyfileWriterInfo *info, const char *key, const GValue *value) { - NMBridgeVlan *vlan; GPtrArray *vlans; - GString *string; - guint i; - vlans = (GPtrArray *) g_value_get_boxed (value); - if (!vlans || !vlans->len) - return; + vlans = g_value_get_boxed (value); + if ( vlans + && vlans->len > 0) { + const guint string_initial_size = vlans->len * 10u; + nm_auto_str_buf NMStrBuf string = NM_STR_BUF_INIT (string_initial_size, FALSE); + guint i; - string = g_string_new (""); - for (i = 0; i < vlans->len; i++) { - gs_free char *vlan_str = NULL; + for (i = 0; i < vlans->len; i++) { + gs_free char *vlan_str = NULL; - vlan = vlans->pdata[i]; - vlan_str = nm_bridge_vlan_to_str (vlan, NULL); - if (!vlan_str) - continue; - if (string->len > 0) - g_string_append (string, ","); - nm_utils_escaped_tokens_escape_gstr_assert (vlan_str, ",", string); + vlan_str = nm_bridge_vlan_to_str (vlans->pdata[i], NULL); + if (i > 0) + nm_str_buf_append_c (&string, ','); + nm_utils_escaped_tokens_escape_strbuf_assert (vlan_str, ",", &string); + } + + nm_keyfile_plugin_kf_set_string (info->keyfile, + nm_setting_get_name (setting), + "vlans", + nm_str_buf_get_str (&string)); } - - nm_keyfile_plugin_kf_set_string (info->keyfile, - nm_setting_get_name (setting), - "vlans", - string->str); - - g_string_free (string, TRUE); } @@ -2348,17 +2346,21 @@ qdisc_writer (KeyfileWriterInfo *info, const char *key, const GValue *value) { - gsize i; + nm_auto_free_gstring GString *key_name = NULL; + nm_auto_free_gstring GString *value_str = NULL; GPtrArray *array; + guint i; - array = (GPtrArray *) g_value_get_boxed (value); - if (!array || !array->len) + array = g_value_get_boxed (value); + if ( !array + || !array->len) return; for (i = 0; i < array->len; i++) { NMTCQdisc *qdisc = array->pdata[i]; - GString *key_name = g_string_sized_new (16); - GString *value_str = g_string_sized_new (60); + + nm_gstring_prepare (&key_name); + nm_gstring_prepare (&value_str); g_string_append (key_name, "qdisc."); _nm_utils_string_append_tc_parent (key_name, NULL, @@ -2369,9 +2371,6 @@ qdisc_writer (KeyfileWriterInfo *info, NM_SETTING_TC_CONFIG_SETTING_NAME, key_name->str, value_str->str); - - g_string_free (key_name, TRUE); - g_string_free (value_str, TRUE); } } @@ -2381,17 +2380,21 @@ tfilter_writer (KeyfileWriterInfo *info, const char *key, const GValue *value) { - gsize i; + nm_auto_free_gstring GString *key_name = NULL; + nm_auto_free_gstring GString *value_str = NULL; GPtrArray *array; + guint i; - array = (GPtrArray *) g_value_get_boxed (value); - if (!array || !array->len) + array = g_value_get_boxed (value); + if ( !array + || !array->len) return; for (i = 0; i < array->len; i++) { NMTCTfilter *tfilter = array->pdata[i]; - GString *key_name = g_string_sized_new (16); - GString *value_str = g_string_sized_new (60); + + nm_gstring_prepare (&key_name); + nm_gstring_prepare (&value_str); g_string_append (key_name, "tfilter."); _nm_utils_string_append_tc_parent (key_name, NULL, @@ -2402,9 +2405,6 @@ tfilter_writer (KeyfileWriterInfo *info, NM_SETTING_TC_CONFIG_SETTING_NAME, key_name->str, value_str->str); - - g_string_free (key_name, TRUE); - g_string_free (value_str, TRUE); } } @@ -4309,46 +4309,53 @@ char * nm_keyfile_utils_create_filename (const char *name, gboolean with_extension) { - GString *str; - const char *f = name; /* keyfile used to escape with '*', do not change that behavior. * * But for newly added escapings, use '_' instead. * Also, @with_extension is new-style. */ const char ESCAPE_CHAR = with_extension ? '_' : '*'; const char ESCAPE_CHAR2 = '_'; + NMStrBuf str; + char *p; + gsize len; + gsize i; g_return_val_if_fail (name && name[0], NULL); - str = g_string_sized_new (60); + nm_str_buf_init (&str, 0, FALSE); + + len = strlen (name); + + p = nm_str_buf_append_len0 (&str, name, len); /* Convert '/' to ESCAPE_CHAR */ - for (f = name; f[0]; f++) { - if (f[0] == '/') - g_string_append_c (str, ESCAPE_CHAR); - else - g_string_append_c (str, f[0]); + for (i = 0; i < len; i++) { + if (p[i] == '/') + p[i] = ESCAPE_CHAR; } /* nm_keyfile_utils_create_filename() must avoid anything that ignore_filename() would reject. * We can escape here more aggressivly then what we would read back. */ - if (str->str[0] == '.') - str->str[0] = ESCAPE_CHAR2; - if (str->str[str->len - 1] == '~') - str->str[str->len - 1] = ESCAPE_CHAR2; - if ( check_mkstemp_suffix (str->str) - || check_suffix (str->str, PEM_TAG) - || check_suffix (str->str, DER_TAG)) - g_string_append_c (str, ESCAPE_CHAR2); + if (p[0] == '.') + p[0] = ESCAPE_CHAR2; + if (p[str.len - 1] == '~') + p[str.len - 1] = ESCAPE_CHAR2; + + if ( check_mkstemp_suffix (p) + || check_suffix (p, PEM_TAG) + || check_suffix (p, DER_TAG)) + nm_str_buf_append_c (&str, ESCAPE_CHAR2); if (with_extension) - g_string_append (str, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION); + nm_str_buf_append (&str, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION); + + p = nm_str_buf_finalize (&str, NULL); /* nm_keyfile_utils_create_filename() must mirror ignore_filename() */ - nm_assert (!strchr (str->str, '/')); - nm_assert (!nm_keyfile_utils_ignore_filename (str->str, with_extension)); + nm_assert (!strchr (p, '/')); + nm_assert (!nm_keyfile_utils_ignore_filename (p, with_extension)); - return g_string_free (str, FALSE);; + return p; } /*****************************************************************************/ From 936e457cc08d387deba8670282145362716c2b55 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 12:11:38 +0200 Subject: [PATCH 049/199] libnm: use NMStrBuf in nm_ip_routing_rule_to_string() --- libnm-core/nm-setting-ip-config.c | 133 +++++++++++++++--------------- 1 file changed, 67 insertions(+), 66 deletions(-) diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index f7a022b6cb..c377452170 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -11,6 +11,7 @@ #include #include +#include "nm-glib-aux/nm-str-buf.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" #include "nm-utils.h" @@ -3404,7 +3405,7 @@ next_words_consumed: } static void -_rr_string_append_inet_addr (GString *str, +_rr_string_append_inet_addr (NMStrBuf *str, gboolean is_from /* or else is-to */, gboolean required, int addr_family, @@ -3415,26 +3416,26 @@ _rr_string_append_inet_addr (GString *str, if (addr_len == 0) { if (required) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "%s %s/0", - is_from ? "from" : "to", - (addr_family == AF_INET) - ? "0.0.0.0" - : "::"); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (str, ' '), + "%s %s/0", + is_from ? "from" : "to", + (addr_family == AF_INET) + ? "0.0.0.0" + : "::"); } return; } - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "%s %s", - is_from ? "from" : "to", - nm_utils_inet_ntop (addr_family, - addr_bin, - addr_str)); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (str, ' '), + "%s %s", + is_from ? "from" : "to", + nm_utils_inet_ntop (addr_family, + addr_bin, + addr_str)); if (addr_len != nm_utils_addr_family_to_size (addr_family) * 8) { - g_string_append_printf (str, - "/%u", - addr_len); + nm_str_buf_append_printf (str, + "/%u", + addr_len); } } @@ -3457,8 +3458,8 @@ nm_ip_routing_rule_to_string (const NMIPRoutingRule *self, GHashTable *extra_args, GError **error) { - nm_auto_free_gstring GString *str = NULL; int addr_family; + NMStrBuf str; g_return_val_if_fail (NM_IS_IP_ROUTING_RULE (self, TRUE), NULL); @@ -3494,18 +3495,18 @@ nm_ip_routing_rule_to_string (const NMIPRoutingRule *self, } } - str = g_string_sized_new (30); + nm_str_buf_init (&str, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); if (self->priority_has) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "priority %u", - (guint) self->priority); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "priority %u", + (guint) self->priority); } if (self->invert) - g_string_append (nm_gstring_add_space_delimiter (str), "not"); + nm_str_buf_append (nm_str_buf_append_required_delimiter (&str, ' '), "not"); - _rr_string_append_inet_addr (str, + _rr_string_append_inet_addr (&str, TRUE, ( !self->to_has || !self->to_valid), @@ -3515,7 +3516,7 @@ nm_ip_routing_rule_to_string (const NMIPRoutingRule *self, ? self->from_len : 0); - _rr_string_append_inet_addr (str, + _rr_string_append_inet_addr (&str, FALSE, FALSE, addr_family, @@ -3525,88 +3526,88 @@ nm_ip_routing_rule_to_string (const NMIPRoutingRule *self, : 0); if (self->tos != 0) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "tos 0x%02x", - (guint) self->tos); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "tos 0x%02x", + (guint) self->tos); } if (self->ipproto != 0) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "ipproto %u", - (guint) self->ipproto); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "ipproto %u", + (guint) self->ipproto); } if ( self->fwmark != 0 || self->fwmask != 0) { if (self->fwmark != 0) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "fwmark 0x%x", - self->fwmark); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "fwmark 0x%x", + self->fwmark); } else { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "fwmark 0"); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "fwmark 0"); } if (self->fwmask != 0xFFFFFFFFu) { if (self->fwmask != 0) - g_string_append_printf (str, "/0x%x", self->fwmask); + nm_str_buf_append_printf (&str, "/0x%x", self->fwmask); else - g_string_append_printf (str, "/0"); + nm_str_buf_append_printf (&str, "/0"); } } if ( self->sport_start != 0 || self->sport_end != 0) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "sport %u", - self->sport_start); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "sport %u", + self->sport_start); if (self->sport_start != self->sport_end) { - g_string_append_printf (str, - "-%u", - self->sport_end); + nm_str_buf_append_printf (&str, + "-%u", + self->sport_end); } } if ( self->dport_start != 0 || self->dport_end != 0) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "dport %u", - self->dport_start); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "dport %u", + self->dport_start); if (self->dport_start != self->dport_end) { - g_string_append_printf (str, - "-%u", - self->dport_end); + nm_str_buf_append_printf (&str, + "-%u", + self->dport_end); } } if (self->iifname) { - g_string_append (nm_gstring_add_space_delimiter (str), - "iif "); - nm_utils_escaped_tokens_escape_gstr (self->iifname, - NM_ASCII_SPACES, - str); + nm_str_buf_append (nm_str_buf_append_required_delimiter (&str, ' '), + "iif "); + nm_utils_escaped_tokens_escape_strbuf (self->iifname, + NM_ASCII_SPACES, + &str); } if (self->oifname) { - g_string_append (nm_gstring_add_space_delimiter (str), - "oif "); - nm_utils_escaped_tokens_escape_gstr (self->oifname, - NM_ASCII_SPACES, - str); + nm_str_buf_append (nm_str_buf_append_required_delimiter (&str, ' '), + "oif "); + nm_utils_escaped_tokens_escape_strbuf (self->oifname, + NM_ASCII_SPACES, + &str); } if (self->table != 0) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "table %u", - (guint) self->table); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "table %u", + (guint) self->table); } if (self->suppress_prefixlength != -1) { - g_string_append_printf (nm_gstring_add_space_delimiter (str), - "suppress_prefixlength %d", - (int) self->suppress_prefixlength); + nm_str_buf_append_printf (nm_str_buf_append_required_delimiter (&str, ' '), + "suppress_prefixlength %d", + (int) self->suppress_prefixlength); } - return g_string_free (g_steal_pointer (&str), FALSE); + return nm_str_buf_finalize (&str, NULL); } /*****************************************************************************/ From 2edb3aa81aa7580fcd62d0ca542ce52ec0ed5304 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 13:17:04 +0200 Subject: [PATCH 050/199] libnm: use NMStrBuf in _nm_utils_uuid_generate_from_strings() --- libnm-core/nm-utils.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index c88afb3238..85effe21a8 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -20,6 +20,7 @@ #include "nm-json.h" #endif +#include "nm-glib-aux/nm-str-buf.h" #include "nm-glib-aux/nm-enum-utils.h" #include "nm-glib-aux/nm-time-utils.h" #include "nm-glib-aux/nm-secret-utils.h" @@ -3300,30 +3301,29 @@ nm_utils_uuid_generate_from_string (const char *s, gssize slen, int uuid_type, g char * _nm_utils_uuid_generate_from_strings (const char *string1, ...) { - GString *str; - va_list args; - const char *s; - char *uuid; - if (!string1) return nm_utils_uuid_generate_from_string (NULL, 0, NM_UTILS_UUID_TYPE_VERSION3, NM_UTILS_UUID_NS); - str = g_string_sized_new (120); /* effectively allocates power of 2 (128)*/ + { + nm_auto_str_buf NMStrBuf str = NM_STR_BUF_INIT (NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); + va_list args; + const char *s; - g_string_append_len (str, string1, strlen (string1) + 1); + nm_str_buf_append_len (&str, string1, strlen (string1) + 1u); - va_start (args, string1); - s = va_arg (args, const char *); - while (s) { - g_string_append_len (str, s, strlen (s) + 1); + va_start (args, string1); s = va_arg (args, const char *); + while (s) { + nm_str_buf_append_len (&str, s, strlen (s) + 1u); + s = va_arg (args, const char *); + } + va_end (args); + + return nm_utils_uuid_generate_from_string (nm_str_buf_get_str_unsafe (&str), + str.len, + NM_UTILS_UUID_TYPE_VERSION3, + NM_UTILS_UUID_NS); } - va_end (args); - - uuid = nm_utils_uuid_generate_from_string (str->str, str->len, NM_UTILS_UUID_TYPE_VERSION3, NM_UTILS_UUID_NS); - - g_string_free (str, TRUE); - return uuid; } /*****************************************************************************/ From 6adf4b9a560be16bf7b8e7b5c0a7e6d767cbbb67 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 13:10:45 +0200 Subject: [PATCH 051/199] libnm: use NMStrBuf in nm_utils_file_search_in_paths() --- libnm-core/nm-utils.c | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 85effe21a8..1c39d94e78 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -3571,9 +3571,6 @@ nm_utils_file_search_in_paths (const char *progname, gpointer user_data, GError **error) { - GString *tmp; - const char *ret; - g_return_val_if_fail (!error || !*error, NULL); g_return_val_if_fail (progname && progname[0] && !strchr (progname, '/'), NULL); g_return_val_if_fail (file_test_flags || predicate, NULL); @@ -3582,32 +3579,35 @@ nm_utils_file_search_in_paths (const char *progname, * it simpler to pass in a path from configure checks. */ if ( try_first && try_first[0] == '/' - && (file_test_flags == 0 || g_file_test (try_first, file_test_flags)) - && (!predicate || predicate (try_first, user_data))) + && ( file_test_flags == 0 + || g_file_test (try_first, file_test_flags)) + && ( !predicate + || predicate (try_first, user_data))) return g_intern_string (try_first); - if (!paths || !*paths) - goto NOT_FOUND; + if ( paths + && paths[0]) { + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT (NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); - tmp = g_string_sized_new (50); - for (; *paths; paths++) { - if (!*paths) - continue; - g_string_append (tmp, *paths); - if (tmp->str[tmp->len - 1] != '/') - g_string_append_c (tmp, '/'); - g_string_append (tmp, progname); - if ( (file_test_flags == 0 || g_file_test (tmp->str, file_test_flags)) - && (!predicate || predicate (tmp->str, user_data))) { - ret = g_intern_string (tmp->str); - g_string_free (tmp, TRUE); - return ret; + for (; *paths; paths++) { + const char *path = *paths; + const char *s; + + if (!path[0]) + continue; + + nm_str_buf_reset (&strbuf, path); + nm_str_buf_ensure_trailing_c (&strbuf, '/'); + s = nm_str_buf_append0 (&strbuf, progname); + + if ( ( file_test_flags == 0 + || g_file_test (s, file_test_flags)) + && ( !predicate + || predicate (s, user_data))) + return g_intern_string (s); } - g_string_set_size (tmp, 0); } - g_string_free (tmp, TRUE); -NOT_FOUND: g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Could not find \"%s\" binary"), progname); return NULL; } From 39454717529c018cea86557962ac10e224557ac5 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 21:48:59 +0200 Subject: [PATCH 052/199] libnm: use nm_streq() in "libnm-core/nm-utils.c" --- libnm-core/nm-utils.c | 66 ++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 1c39d94e78..39e9470bea 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -2068,8 +2068,8 @@ nm_utils_ip_addresses_from_variant (GVariant *value, g_variant_iter_init (&attrs_iter, addr_var); while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) { - if ( strcmp (attr_name, "address") != 0 - && strcmp (attr_name, "prefix") != 0) + if (!NM_IN_STRSET (attr_name, "address", + "prefix")) nm_ip_address_set_attribute (addr, attr_name, attr_val); g_variant_unref (attr_val); } @@ -2194,10 +2194,10 @@ nm_utils_ip_routes_from_variant (GVariant *value, g_variant_iter_init (&attrs_iter, route_var); while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_val)) { - if ( strcmp (attr_name, "dest") != 0 - && strcmp (attr_name, "prefix") != 0 - && strcmp (attr_name, "next-hop") != 0 - && strcmp (attr_name, "metric") != 0) + if (!NM_IN_STRSET (attr_name, "dest", + "prefix", + "next-hop", + "metric")) nm_ip_route_set_attribute (route, attr_name, attr_val); g_variant_unref (attr_val); } @@ -2377,7 +2377,8 @@ _nm_utils_string_append_tc_qdisc_rest (GString *string, NMTCQdisc *qdisc) const char *kind = nm_tc_qdisc_get_kind (qdisc); gs_free char *str = NULL; - if (handle != TC_H_UNSPEC && strcmp (kind, "ingress") != 0) { + if ( handle != TC_H_UNSPEC + && !nm_streq (kind, "ingress")) { g_string_append (string, "handle "); _string_append_tc_handle (string, handle); g_string_append_c (string, ' '); @@ -2469,7 +2470,7 @@ _tc_read_common_opts (const char *str, variant = g_hash_table_lookup (ht, "kind"); if (variant) { *kind = g_variant_dup_string (variant, NULL); - if (strcmp (*kind, "ingress") == 0) { + if (nm_streq (*kind, "ingress")) { if (*parent == TC_H_UNSPEC) *parent = TC_H_INGRESS; if (*handle == TC_H_UNSPEC) @@ -2525,7 +2526,7 @@ nm_utils_tc_qdisc_from_str (const char *str, GError **error) return NULL; for (i = 0; rest && tc_qdisc_attribute_spec[i]; i++) { - if (strcmp (tc_qdisc_attribute_spec[i]->kind, kind) == 0) { + if (nm_streq (tc_qdisc_attribute_spec[i]->kind, kind)) { options = nm_utils_parse_variant_attributes (rest, ' ', ' ', FALSE, tc_qdisc_attribute_spec[i]->attrs, @@ -2671,9 +2672,9 @@ nm_utils_tc_action_from_str (const char *str, GError **error) } kind = g_variant_get_string (variant, NULL); - if (strcmp (kind, "simple") == 0) + if (nm_streq (kind, "simple")) attrs = tc_action_simple_attribute_spec; - else if (strcmp (kind, "mirred") == 0) + else if (nm_streq (kind, "mirred")) attrs = tc_action_mirred_attribute_spec; else attrs = NULL; @@ -3750,11 +3751,11 @@ nm_utils_wifi_channel_to_freq (guint32 channel, const char *band) { int i = 0; - if (!strcmp (band, "a")) { + if (nm_streq (band, "a")) { while (a_table[i].chan && (a_table[i].chan != channel)) i++; return a_table[i].freq; - } else if (!strcmp (band, "bg")) { + } else if (nm_streq (band, "bg")) { while (bg_table[i].chan && (bg_table[i].chan != channel)) i++; return bg_table[i].freq; @@ -3776,17 +3777,17 @@ nm_utils_wifi_channel_to_freq (guint32 channel, const char *band) guint32 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band) { - size_t a_size = sizeof (a_table) / sizeof (struct cf_pair); - size_t bg_size = sizeof (bg_table) / sizeof (struct cf_pair); + size_t a_size = G_N_ELEMENTS (a_table); + size_t bg_size = G_N_ELEMENTS (bg_table); struct cf_pair *pair = NULL; - if (!strcmp (band, "a")) { + if (nm_streq (band, "a")) { if (channel < a_table[0].chan) return a_table[0].chan; if (channel > a_table[a_size - 2].chan) return a_table[a_size - 2].chan; pair = &a_table[0]; - } else if (!strcmp (band, "bg")) { + } else if (nm_streq (band, "bg")) { if (channel < bg_table[0].chan) return bg_table[0].chan; if (channel > bg_table[bg_size - 2].chan) @@ -3826,9 +3827,9 @@ nm_utils_wifi_is_channel_valid (guint32 channel, const char *band) struct cf_pair *table = NULL; int i = 0; - if (!strcmp (band, "a")) + if (nm_streq (band, "a")) table = a_table; - else if (!strcmp (band, "bg")) + else if (nm_streq (band, "bg")) table = bg_table; else return FALSE; @@ -5080,8 +5081,8 @@ nm_utils_bond_mode_string_to_int (const char *mode) return -1; for (i = 0; i < G_N_ELEMENTS (bond_mode_table); i++) { - if ( strcmp (mode, bond_mode_table[i].str) == 0 - || strcmp (mode, bond_mode_table[i].num) == 0) + if (NM_IN_STRSET (mode, bond_mode_table[i].str, + bond_mode_table[i].num)) return i; } return -1; @@ -5139,13 +5140,13 @@ _nm_utils_strstrdictkey_equal (gconstpointer a, gconstpointer b) return FALSE; if (k1->type & STRSTRDICTKEY_ALL_SET) { - if (strcmp (k1->data, k2->data) != 0) + if (!nm_streq (k1->data, k2->data)) return FALSE; if (k1->type == STRSTRDICTKEY_ALL_SET) { gsize l = strlen (k1->data) + 1; - return strcmp (&k1->data[l], &k2->data[l]) == 0; + return nm_streq (&k1->data[l], &k2->data[l]); } } @@ -5196,7 +5197,7 @@ validate_dns_option (const char *name, return !!*name; for (desc = option_descs; desc->name; desc++) { - if (!strcmp (name, desc->name) && + if (nm_streq (name, desc->name) && numeric == desc->numeric && (!desc->ipv6_only || ipv6)) return TRUE; @@ -5286,26 +5287,21 @@ _nm_utils_dns_option_validate (const char *option, */ gssize _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option) { - gboolean ret; - char *option_name, *tmp_name; + gs_free char *option_name = NULL; guint i; if (!_nm_utils_dns_option_validate (option, &option_name, NULL, FALSE, NULL)) return -1; for (i = 0; i < array->len; i++) { - if (_nm_utils_dns_option_validate (array->pdata[i], &tmp_name, NULL, FALSE, NULL)) { - ret = strcmp (tmp_name, option_name); - g_free (tmp_name); - if (!ret) { - g_free (option_name); - return i; - } - } + gs_free char *tmp_name = NULL; + if (_nm_utils_dns_option_validate (array->pdata[i], &tmp_name, NULL, FALSE, NULL)) { + if (nm_streq (tmp_name, option_name)) + return i; + } } - g_free (option_name); return -1; } From bd7d8b6f3d41247e1c5ec9ea0895b7d106a139b4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 22 Jun 2020 09:21:06 +0200 Subject: [PATCH 053/199] libnm: don't use assert for validating arguments to nm_utils_wifi_find_next_channel() --- libnm-core/nm-utils.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 39e9470bea..d8713adb31 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -3793,10 +3793,8 @@ nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band) if (channel > bg_table[bg_size - 2].chan) return bg_table[bg_size - 2].chan; pair = &bg_table[0]; - } else { - g_assert_not_reached (); - return 0; - } + } else + g_return_val_if_reached (0); while (pair->chan) { if (channel == pair->chan) From 5f202414d9bb42312c4f4875deb2628eadadf5be Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 21:59:32 +0200 Subject: [PATCH 054/199] libnm: refactor wifi frequency handling in libnm - mark global variables as const. This allows the linker to mark the variable as read only. - for nm_utils_wifi_[25]ghz_freqs(), don't generate a list based on bg_table/a_table. Instead, keep static array of frequencies. Since we have unit tests that check the consistency, this has little maintenance effort. - add unit tests --- libnm-core/nm-utils.c | 184 +++++++++++++++++++++----------- libnm-core/tests/test-general.c | 50 +++++++++ 2 files changed, 173 insertions(+), 61 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index d8713adb31..ca6b70ce20 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -3621,7 +3621,7 @@ struct cf_pair { guint32 freq; }; -static struct cf_pair a_table[] = { +static const struct cf_pair a_table[] = { /* A band */ { 7, 5035 }, { 8, 5040 }, @@ -3668,10 +3668,60 @@ static struct cf_pair a_table[] = { { 188, 4945 }, { 192, 4960 }, { 196, 4980 }, - { 0, -1 } + { 0, 0 } }; -static struct cf_pair bg_table[] = { +static const guint a_table_freqs[G_N_ELEMENTS (a_table)] = { + /* A band */ + 5035, + 5040, + 5045, + 5055, + 5060, + 5080, + 5170, + 5180, + 5190, + 5200, + 5210, + 5220, + 5230, + 5240, + 5250, + 5260, + 5280, + 5290, + 5300, + 5320, + 5500, + 5520, + 5540, + 5560, + 5580, + 5600, + 5620, + 5640, + 5660, + 5680, + 5700, + 5745, + 5760, + 5765, + 5785, + 5800, + 5805, + 5825, + 4915, + 4920, + 4925, + 4935, + 4945, + 4960, + 4980, + 0, +}; + +static const struct cf_pair bg_table[] = { /* B/G band */ { 1, 2412 }, { 2, 2417 }, @@ -3687,7 +3737,26 @@ static struct cf_pair bg_table[] = { { 12, 2467 }, { 13, 2472 }, { 14, 2484 }, - { 0, -1 } + { 0, 0 } +}; + +static const guint bg_table_freqs[G_N_ELEMENTS (bg_table)] = { + /* B/G band */ + 2412, + 2417, + 2422, + 2427, + 2432, + 2437, + 2442, + 2447, + 2452, + 2457, + 2462, + 2467, + 2472, + 2484, + 0, }; /** @@ -3704,16 +3773,16 @@ nm_utils_wifi_freq_to_channel (guint32 freq) int i = 0; if (freq > 4900) { - while (a_table[i].chan && (a_table[i].freq != freq)) + while ( a_table[i].freq + && (a_table[i].freq != freq)) i++; return a_table[i].chan; - } else { - while (bg_table[i].chan && (bg_table[i].freq != freq)) - i++; - return bg_table[i].chan; } - return 0; + while ( bg_table[i].freq + && (bg_table[i].freq != freq)) + i++; + return bg_table[i].chan; } /** @@ -3749,16 +3818,24 @@ nm_utils_wifi_freq_to_band (guint32 freq) guint32 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band) { - int i = 0; + int i; + + g_return_val_if_fail (band, 0); if (nm_streq (band, "a")) { - while (a_table[i].chan && (a_table[i].chan != channel)) - i++; - return a_table[i].freq; - } else if (nm_streq (band, "bg")) { - while (bg_table[i].chan && (bg_table[i].chan != channel)) - i++; - return bg_table[i].freq; + for (i = 0; a_table[i].chan; i++) { + if (a_table[i].chan == channel) + return a_table[i].freq; + } + return ((guint32) -1); + } + + if (nm_streq (band, "bg")) { + for (i = 0; bg_table[i].chan; i++) { + if (bg_table[i].chan == channel) + return bg_table[i].freq; + } + return ((guint32) -1); } return 0; @@ -3779,7 +3856,7 @@ nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band) { size_t a_size = G_N_ELEMENTS (a_table); size_t bg_size = G_N_ELEMENTS (bg_table); - struct cf_pair *pair = NULL; + const struct cf_pair *pair; if (nm_streq (band, "a")) { if (channel < a_table[0].chan) @@ -3822,49 +3899,32 @@ nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band) gboolean nm_utils_wifi_is_channel_valid (guint32 channel, const char *band) { - struct cf_pair *table = NULL; - int i = 0; + guint32 freq; - if (nm_streq (band, "a")) - table = a_table; - else if (nm_streq (band, "bg")) - table = bg_table; - else - return FALSE; + freq = nm_utils_wifi_channel_to_freq (channel, band); - while (table[i].chan && (table[i].chan != channel)) - i++; - - if (table[i].chan != 0) - return TRUE; - else - return FALSE; + return !NM_IN_SET (freq, 0u, (guint32) -1); } -static const guint * -_wifi_freqs (gboolean bg_band) -{ - static guint *freqs_2ghz = NULL; - static guint *freqs_5ghz = NULL; - guint *freqs; - - freqs = bg_band ? freqs_2ghz : freqs_5ghz; - if (G_UNLIKELY (freqs == NULL)) { - struct cf_pair *table; - int i; - - table = bg_band ? bg_table : a_table; - freqs = g_new0 (guint, bg_band ? G_N_ELEMENTS (bg_table) : G_N_ELEMENTS (a_table)); - for (i = 0; table[i].chan; i++) - freqs[i] = table[i].freq; - freqs[i] = 0; - if (bg_band) - freqs_2ghz = freqs; - else - freqs_5ghz = freqs; - } - return freqs; -} +#define _nm_assert_wifi_freqs(table, table_freqs) \ + G_STMT_START { \ + if (NM_MORE_ASSERT_ONCE (5)) { \ + int i, j; \ + \ + G_STATIC_ASSERT (G_N_ELEMENTS (table) > 0); \ + G_STATIC_ASSERT (G_N_ELEMENTS (table) == G_N_ELEMENTS (table_freqs)); \ + \ + for (i = 0; i < G_N_ELEMENTS (table); i++) { \ + nm_assert ((i == G_N_ELEMENTS (table) - 1) == (table[i].chan == 0)); \ + nm_assert ((i == G_N_ELEMENTS (table) - 1) == (table[i].freq == 0)); \ + nm_assert (table[i].freq == table_freqs[i]); \ + for (j = 0; j < i; j++) { \ + nm_assert (table[j].chan != table[i].chan); \ + nm_assert (table[j].freq != table[i].freq); \ + } \ + } \ + } \ + } G_STMT_END /** * nm_utils_wifi_2ghz_freqs: @@ -3878,7 +3938,8 @@ _wifi_freqs (gboolean bg_band) const guint * nm_utils_wifi_2ghz_freqs (void) { - return _wifi_freqs (TRUE); + _nm_assert_wifi_freqs (bg_table, bg_table_freqs); + return bg_table_freqs; } /** @@ -3893,7 +3954,8 @@ nm_utils_wifi_2ghz_freqs (void) const guint * nm_utils_wifi_5ghz_freqs (void) { - return _wifi_freqs (FALSE); + _nm_assert_wifi_freqs (a_table, a_table_freqs); + return a_table_freqs; } /** @@ -5027,7 +5089,7 @@ typedef struct { const char *num; } BondMode; -static BondMode bond_mode_table[] = { +static const BondMode bond_mode_table[] = { [0] = { "balance-rr", "0" }, [1] = { "active-backup", "1" }, [2] = { "balance-xor", "2" }, diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index f70a7d5a65..a1c716f473 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -9100,6 +9100,55 @@ test_strsplit_quoted (void) /*****************************************************************************/ +static void +_do_wifi_ghz_freqs (const guint *freqs, const char *band) +{ + int len; + int j; + int i; + + g_assert (NM_IN_STRSET (band, "a", "bg")); + g_assert (freqs); + g_assert (freqs[0] != 0); + + for (i = 0; freqs[i]; i++) { + for (j = 0; j < i; j++) + g_assert (freqs[i] != freqs[j]); + } + len = i; + + g_assert (nm_utils_wifi_freq_to_channel (0) == 0); + g_assert (nm_utils_wifi_channel_to_freq (0, "bg") == -1); + g_assert (nm_utils_wifi_channel_to_freq (0, "foo") == 0); + g_assert (!nm_utils_wifi_is_channel_valid (0, "bg")); + g_assert (!nm_utils_wifi_is_channel_valid (0, "foo")); + + for (i = 0; i < len; i++) { + guint freq = freqs[i]; + guint32 chan; + guint32 freq2; + + chan = nm_utils_wifi_freq_to_channel (freq); + g_assert (chan != 0); + + freq2 = nm_utils_wifi_channel_to_freq (chan, band); + g_assert (freq2 == freq); + + g_assert (nm_utils_wifi_is_channel_valid (chan, band)); + } + + g_assert (freqs[len] == 0); +} + +static void +test_nm_utils_wifi_ghz_freqs (void) +{ + _do_wifi_ghz_freqs (nm_utils_wifi_2ghz_freqs (), "bg"); + _do_wifi_ghz_freqs (nm_utils_wifi_5ghz_freqs (), "a"); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -9273,6 +9322,7 @@ int main (int argc, char **argv) g_test_add_data_func ("/core/general/test_integrate_maincontext/2", GUINT_TO_POINTER (2), test_integrate_maincontext); g_test_add_func ("/core/general/test_nm_ip_addr_zero", test_nm_ip_addr_zero); + g_test_add_func ("/core/general/test_nm_utils_wifi_ghz_freqs", test_nm_utils_wifi_ghz_freqs); g_test_add_func ("/core/general/test_strsplit_quoted", test_strsplit_quoted); From 652e0c843bfcdf3d59816d0b3c81d4f99a843c81 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 22:03:55 +0200 Subject: [PATCH 055/199] supplicant: use nm_streq() in "nm-supplicant-config.c" --- src/supplicant/nm-supplicant-config.c | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index 058792d026..62c6742458 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -11,7 +11,6 @@ #include #include "nm-core-internal.h" - #include "nm-supplicant-settings-verify.h" #include "nm-setting.h" #include "nm-libnm-core-intern/nm-auth-subject.h" @@ -464,9 +463,9 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); mode = nm_setting_wireless_get_mode (setting); - is_adhoc = (mode && !strcmp (mode, "adhoc")) ? TRUE : FALSE; - is_ap = (mode && !strcmp (mode, "ap")) ? TRUE : FALSE; - is_mesh = (mode && !strcmp (mode, "mesh")) ? TRUE : FALSE; + is_adhoc = nm_streq0 (mode, "adhoc"); + is_ap = nm_streq0 (mode, "ap"); + is_mesh = nm_streq0 (mode, "mesh"); if (is_adhoc || is_ap) priv->ap_scan = 2; else @@ -540,9 +539,9 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, } else { const char *freqs = NULL; - if (!strcmp (band, "a")) + if (nm_streq (band, "a")) freqs = wifi_freqs_to_string (FALSE); - else if (!strcmp (band, "bg")) + else if (nm_streq (band, "bg")) freqs = wifi_freqs_to_string (TRUE); if (freqs && !nm_supplicant_config_add_option (self, "freq_list", freqs, strlen (freqs), NULL, error)) @@ -888,10 +887,10 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, } /* Only WPA-specific things when using WPA */ - if ( !strcmp (key_mgmt, "wpa-psk") - || !strcmp (key_mgmt, "wpa-eap") - || !strcmp (key_mgmt, "sae") - || !strcmp (key_mgmt, "owe")) { + if (NM_IN_STRSET (key_mgmt, "wpa-psk", + "wpa-eap", + "sae", + "owe")) { if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, proto, protos, "proto", ' ', TRUE, NULL, error)) return FALSE; if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, pairwise, pairwise, "pairwise", ' ', TRUE, NULL, error)) @@ -914,7 +913,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, } /* WEP keys if required */ - if (!strcmp (key_mgmt, "none")) { + if (nm_streq (key_mgmt, "none")) { NMWepKeyType wep_type = nm_setting_wireless_security_get_wep_key_type (setting); const char *wep0 = nm_setting_wireless_security_get_wep_key (setting, 0); const char *wep1 = nm_setting_wireless_security_get_wep_key (setting, 1); @@ -939,9 +938,9 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, } } - if (auth_alg && !strcmp (auth_alg, "leap")) { + if (nm_streq0 (auth_alg, "leap")) { /* LEAP */ - if (!strcmp (key_mgmt, "ieee8021x")) { + if (nm_streq (key_mgmt, "ieee8021x")) { const char *tmp; tmp = nm_setting_wireless_security_get_leap_username (setting); @@ -961,7 +960,8 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, } } else { /* 802.1x for Dynamic WEP and WPA-Enterprise */ - if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) { + if (NM_IN_STRSET (key_mgmt, "ieee8021x", + "wpa-eap")) { if (!setting_8021x) { g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, "Cannot set key-mgmt %s with missing 8021x setting", key_mgmt); @@ -971,7 +971,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, return FALSE; } - if (!strcmp (key_mgmt, "wpa-eap")) { + if (nm_streq (key_mgmt, "wpa-eap")) { /* When using WPA-Enterprise, we want to use Proactive Key Caching (also * called Opportunistic Key Caching) to avoid full EAP exchanges when * roaming between access points in the same mobility group. @@ -1135,9 +1135,9 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, phase1 = g_string_new (NULL); peapver = nm_setting_802_1x_get_phase1_peapver (setting); if (peapver) { - if (!strcmp (peapver, "0")) + if (nm_streq (peapver, "0")) g_string_append (phase1, "peapver=0"); - else if (!strcmp (peapver, "1")) + else if (nm_streq (peapver, "1")) g_string_append (phase1, "peapver=1"); } @@ -1153,7 +1153,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, g_string_append_c (phase1, ' '); g_string_append_printf (phase1, "fast_provisioning=%s", value); - if (strcmp (value, "0") != 0) + if (!nm_streq (value, "0")) fast_provisoning_allowed = TRUE; } From 3b4a4bef7b276cbd2ff587d6586ebbce456859eb Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 21 Jun 2020 22:04:59 +0200 Subject: [PATCH 056/199] supplicant: use NMStrBuf in wifi_freqs_to_string() And don't access global data without atomic operations. --- src/supplicant/nm-supplicant-config.c | 42 ++++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index 62c6742458..1e09697721 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -10,6 +10,7 @@ #include +#include "nm-glib-aux/nm-str-buf.h" #include "nm-core-internal.h" #include "nm-supplicant-settings-verify.h" #include "nm-setting.h" @@ -341,26 +342,39 @@ wifi_freqs_to_string (gboolean bg_band) { static const char *str_2ghz = NULL; static const char *str_5ghz = NULL; - const char *str; + const char **f_p; + const char *f; - str = bg_band ? str_2ghz : str_5ghz; + f_p = bg_band + ? &str_2ghz + : &str_5ghz; - if (G_UNLIKELY (str == NULL)) { - GString *tmp; +again: + f = g_atomic_pointer_get (f_p); + + if (G_UNLIKELY (!f)) { + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT (400, FALSE); const guint *freqs; int i; - freqs = bg_band ? nm_utils_wifi_2ghz_freqs () : nm_utils_wifi_5ghz_freqs (); - tmp = g_string_sized_new (bg_band ? 70 : 225); - for (i = 0; freqs[i]; i++) - g_string_append_printf (tmp, i == 0 ? "%d" : " %d", freqs[i]); - str = g_string_free (tmp, FALSE); - if (bg_band) - str_2ghz = str; - else - str_5ghz = str; + freqs = bg_band + ? nm_utils_wifi_2ghz_freqs () + : nm_utils_wifi_5ghz_freqs (); + for (i = 0; freqs[i]; i++) { + if (i > 0) + nm_str_buf_append_c (&strbuf, ' '); + nm_str_buf_append_printf (&strbuf, "%u", freqs[i]); + } + + f = g_strdup (nm_str_buf_get_str (&strbuf)); + + if (!g_atomic_pointer_compare_and_exchange (f_p, NULL, f)) { + g_free ((char *) f); + goto again; + } } - return str; + + return f; } gboolean From 1641cc1d03941e543da716bc68ff059c5a984f37 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 26 Jun 2020 10:18:49 +0200 Subject: [PATCH 057/199] docs: fix escaping XML in "tools/generate-docs-nm-settings-docs-gir.py" The gtk-doc text that the tool receives is not XML, it's a plain text. When setting the plain text as XML attribute, we need to properly escape it. The previous XML escape code was naive, and didn't cover for a plain ampersand. --- tools/generate-docs-nm-settings-docs-gir.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/generate-docs-nm-settings-docs-gir.py b/tools/generate-docs-nm-settings-docs-gir.py index 0eb0da9785..ebda99560a 100755 --- a/tools/generate-docs-nm-settings-docs-gir.py +++ b/tools/generate-docs-nm-settings-docs-gir.py @@ -8,6 +8,7 @@ from __future__ import print_function import os import gi +import xml.sax.saxutils as saxutils gi.require_version("GIRepository", "2.0") from gi.repository import GIRepository @@ -179,8 +180,8 @@ def settings_sort_key(x): return (x_prefix != "setting_connection", x_prefix) -def escape(val): - return str(val).replace('"', """) +def xml_quoteattr(val): + return saxutils.quoteattr(str(val)) def usage(): @@ -275,11 +276,17 @@ for settingxml in settings: default_value_as_xml = "" if default_value is not None: - default_value_as_xml = ' default="%s"' % (escape(default_value)) + default_value_as_xml = " default=%s" % (xml_quoteattr(default_value)) outfile.write( - ' \n' - % (prop, prop_upper, value_type, default_value_as_xml, escape(value_desc)) + ' \n' + % ( + prop, + prop_upper, + value_type, + default_value_as_xml, + xml_quoteattr(value_desc), + ) ) outfile.write(" \n") From e0f481714871d587c215c8b6511474043728f8de Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Jun 2020 08:39:04 +0200 Subject: [PATCH 058/199] core: move matching of kernel command line to separate function --- src/devices/nm-device.c | 86 ++++------------------------------------- src/nm-core-utils.c | 85 ++++++++++++++++++++++++++++++++++++++++ src/nm-core-utils.h | 5 +++ 3 files changed, 97 insertions(+), 79 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 63fa5a5cc9..99b3c5f68c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -6353,85 +6353,13 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError ** return FALSE; } - { - const char *const*proc_cmdline; - gboolean pos_patterns = FALSE; - guint i; - - patterns = nm_setting_match_get_kernel_command_lines (s_match, &num_patterns); - proc_cmdline = nm_utils_proc_cmdline_split (); - - for (i = 0; i < num_patterns; i++) { - const char *patterns_i = patterns[i]; - const char *const*proc_cmdline_i; - gboolean negative = FALSE; - gboolean found = FALSE; - const char *equal; - - if (patterns_i[0] == '!') { - ++patterns_i; - negative = TRUE; - } else - pos_patterns = TRUE; - - equal = strchr (patterns_i, '='); - - proc_cmdline_i = proc_cmdline; - while (*proc_cmdline_i) { - if (equal) { - /* if pattern contains = compare full key=value */ - found = nm_streq (*proc_cmdline_i, patterns_i); - } else { - gsize l = strlen (patterns_i); - - /* otherwise consider pattern as key only */ - if ( strncmp (*proc_cmdline_i, patterns_i, l) == 0 - && NM_IN_SET ((*proc_cmdline_i)[l], '\0', '=')) - found = TRUE; - } - if ( found - && negative) { - /* first negative match */ - nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not satisfy match.kernel-command-line property %s", - patterns[i]); - return FALSE; - } - proc_cmdline_i++; - } - - /* FIXME(release-blocker): match.interface-name and match.driver have the meaning, - * that any of the matches may yield success. For match.kernel-command-line, we - * do here that all must match. This inconsistency is undesired. - * - * 1) improve gtk-doc documentation explaining how these options match. - * - * 2) possibly unify the behavior so that kernel-command-line behaves like other - * matches (and ANY may match). Note that this would be contrary to systemd's - * Conditions, which by default requires that ALL conditions match (AND). We - * should be consistent within our match options, and not with systemd here. - * - * 2b) Note that systemd supports special token like "=|", to indicate that - * ANY behavior. If we want, we could also introduce two special prefixes - * "&..." and "|...", to support either. It's slightly complicated how - * these work in combinations with "!". - * Unless we fully decide what we do about this, NMSettingMatch.verify() should - * reject matches that start with '&' or '|', because these will be reserved for - * future use. - * - * 3) while fixing this, this code should move to a separate function so we - * can unit test the match of kernel command lines. - */ - if ( pos_patterns - && !found) { - /* positive patterns configured but no match */ - nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not satisfy any match.kernel-command-line property %s...", - patterns[0]); - return FALSE; - } - } - } + patterns = nm_setting_match_get_kernel_command_lines (s_match, &num_patterns); + if ( num_patterns > 0 + && !nm_utils_kernel_cmdline_match_check (nm_utils_proc_cmdline_split (), + patterns, + num_patterns, + error)) + return FALSE; device_driver = nm_device_get_driver (self); patterns = nm_setting_match_get_drivers (s_match, &num_patterns); diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index dc76d1fd9d..8019775a96 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -1731,6 +1731,91 @@ nm_wildcard_match_check (const char *str, /*****************************************************************************/ +gboolean +nm_utils_kernel_cmdline_match_check (const char *const*proc_cmdline, + const char *const*patterns, + guint num_patterns, + GError **error) +{ + gboolean pos_patterns = FALSE; + guint i; + + for (i = 0; i < num_patterns; i++) { + const char *patterns_i = patterns[i]; + const char *const*proc_cmdline_i; + gboolean negative = FALSE; + gboolean found = FALSE; + const char *equal; + + if (patterns_i[0] == '!') { + ++patterns_i; + negative = TRUE; + } else + pos_patterns = TRUE; + + equal = strchr (patterns_i, '='); + + proc_cmdline_i = proc_cmdline; + while (*proc_cmdline_i) { + if (equal) { + /* if pattern contains = compare full key=value */ + found = nm_streq (*proc_cmdline_i, patterns_i); + } else { + gsize l = strlen (patterns_i); + + /* otherwise consider pattern as key only */ + if ( strncmp (*proc_cmdline_i, patterns_i, l) == 0 + && NM_IN_SET ((*proc_cmdline_i)[l], '\0', '=')) + found = TRUE; + } + if ( found + && negative) { + /* first negative match */ + nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not satisfy match.kernel-command-line property %s", + patterns[i]); + return FALSE; + } + proc_cmdline_i++; + } + + /* FIXME(release-blocker): match.interface-name and match.driver have the meaning, + * that any of the matches may yield success. For match.kernel-command-line, we + * do here that all must match. This inconsistency is undesired. + * + * 1) improve gtk-doc documentation explaining how these options match. + * + * 2) possibly unify the behavior so that kernel-command-line behaves like other + * matches (and ANY may match). Note that this would be contrary to systemd's + * Conditions, which by default requires that ALL conditions match (AND). We + * should be consistent within our match options, and not with systemd here. + * + * 2b) Note that systemd supports special token like "=|", to indicate that + * ANY behavior. If we want, we could also introduce two special prefixes + * "&..." and "|...", to support either. It's slightly complicated how + * these work in combinations with "!". + * Unless we fully decide what we do about this, NMSettingMatch.verify() should + * reject matches that start with '&' or '|', because these will be reserved for + * future use. + * + * 3) while fixing this, this code should move to a separate function so we + * can unit test the match of kernel command lines. + */ + if ( pos_patterns + && !found) { + /* positive patterns configured but no match */ + nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not satisfy any match.kernel-command-line property %s...", + patterns[0]); + return FALSE; + } + } + + return TRUE; +} + +/*****************************************************************************/ + char * nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id) { diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index b36c9b581f..1b911894c9 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -230,6 +230,11 @@ gboolean nm_wildcard_match_check (const char *str, const char *const *patterns, guint num_patterns); +gboolean nm_utils_kernel_cmdline_match_check (const char *const*proc_cmdline, + const char *const*patterns, + guint num_patterns, + GError **error); + /*****************************************************************************/ gboolean nm_utils_connection_has_default_route (NMConnection *connection, From fa56e52a4f07a33408d3f3b47bbbc80d63c03c60 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Jun 2020 08:40:21 +0200 Subject: [PATCH 059/199] core/tests: add unit test for nm_utils_kernel_cmdline_match_check() --- src/tests/test-core.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/tests/test-core.c b/src/tests/test-core.c index b90a8fac69..d1bf28743e 100644 --- a/src/tests/test-core.c +++ b/src/tests/test-core.c @@ -2117,6 +2117,39 @@ test_nm_utils_dhcp_client_id_systemd_node_specific (gconstpointer test_data) /*****************************************************************************/ +static void +_kernel_cmdline_match (gboolean expected_match, + const char *const*proc_cmdline, + const char *const*patterns) +{ + gs_free_error GError *error = NULL; + GError **p_error = nmtst_get_rand_bool () ? &error : NULL; + gboolean match; + + nm_assert (proc_cmdline); + nm_assert (patterns); + + match = nm_utils_kernel_cmdline_match_check (proc_cmdline, patterns, NM_PTRARRAY_LEN (patterns), p_error); + if (expected_match) + nmtst_assert_success (match, error); + else { + g_assert (!p_error || error); + g_assert (!match); + } +} + +static void +test_kernel_cmdline_match_check (void) +{ + _kernel_cmdline_match (TRUE, NM_MAKE_STRV (""), NM_MAKE_STRV ("")); + _kernel_cmdline_match (FALSE, NM_MAKE_STRV (""), NM_MAKE_STRV ("a")); + _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a"), NM_MAKE_STRV ("a")); + _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a=b"), NM_MAKE_STRV ("a")); + _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a=b", "b"), NM_MAKE_STRV ("a", "b")); +} + +/*****************************************************************************/ + static void test_connectivity_state_cmp (void) { @@ -2229,6 +2262,7 @@ main (int argc, char **argv) g_test_add_data_func ("/general/nm_utils_dhcp_client_id_systemd_node_specific/1", GINT_TO_POINTER (1), test_nm_utils_dhcp_client_id_systemd_node_specific); g_test_add_func ("/core/general/test_connectivity_state_cmp", test_connectivity_state_cmp); + g_test_add_func ("/core/general/test_kernel_cmdline_match_check", test_kernel_cmdline_match_check); return g_test_run (); } From 824ad6275df1f00daa57a002c46a87257ef218a2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 23 Jun 2020 09:39:48 +0200 Subject: [PATCH 060/199] libnm/match: extend syntax for match patterns with '|', '&', '!' and '\\' For simple matches like match.interface-name, match.driver, and match.path, arguably what we had was fine. There each element (like "eth*") is a wildcard for a single name (like "eth1"). However, for match.kernel-command-line, the elements match individual command line options, so we should have more flexibility of whether a parameter is optional or mandatory. Extend the syntax for that. - the elements can now be prefixed by either '|' or '&'. This makes optional or mandatory elements, respectively. The entire match evaluates to true if all mandatory elements match (if any) and at least one of the optional elements (if any). As before, if neither '|' nor '&' is specified, then the element is optional (that means, "foo" is the same as "|foo"). - the exclamation mark is still used to invert the match. If used alone (like "!foo") it is a shortcut for defining a mandatory match ("&!foo"). - the backslash can now be used to escape the special characters above. Basically, the special characters ('|', '&', '!') are stripped from the start of the element. If what is left afterwards is a backslash, it also gets stripped and the remainder is the pattern. For example, "\\&foo" has the pattern "&foo" where '&' is no longer treated specially. This special handling of the backslash is only done at the beginning of the element (after the optional special characters). The remaining string is part of the pattern, where backslashes might have their own meaning. This change is mostly backward compatible, except for existing matches that started with one of the special characters '|', '&', '!', and '\\'. --- clients/common/settings-docs.h.in | 8 +- libnm-core/nm-setting-match.c | 43 ++++--- src/nm-core-utils.c | 187 ++++++++++++++++++------------ src/tests/test-core.c | 22 +++- 4 files changed, 163 insertions(+), 97 deletions(-) diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index d9bb757515..7b891500d8 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -280,10 +280,10 @@ #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an \"802-3-ethernet\" setting with a \"mac-address\" property.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_PROMISCUOUS N_("Whether the interface should be put in promiscuous mode.") #define DESCRIBE_DOC_NM_SETTING_MACVLAN_TAP N_("Whether the interface should be a MACVTAP.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_DRIVER N_("A list of driver names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate driver name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate interface name is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching.") -#define DESCRIBE_DOC_NM_SETTING_MATCH_PATH N_("A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form \"pci-$domain:$bus:$device.$function\", where each variable is an hexadecimal value; for example \"pci-0000:0a:00.0\". The path of a device can be obtained with \"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the \"path\" property exported by NetworkManager (\"nmcli -f general.path device show $dev\"). Each element of the list is a shell wildcard pattern. When an element is prefixed with exclamation mark (!) the condition is inverted. A candidate path is considered matching when both these conditions are satisfied: (a) any of the elements not prefixed with '!' matches or there aren't such elements; (b) none of the elements prefixed with '!' match.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_DRIVER N_("A list of driver names to match. Each element is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element \"foo\" behaves the same as \"|foo\". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that \"!foo\" is a shortcut for the mandatory match \"&!foo\". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, \"&\\!a\" is an mandatory match for literally \"!a\".") +#define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or if prefixed with the exclamation mark unset). The argument must either be a single word, or an assignment (i.e. two words, separated \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") +#define DESCRIBE_DOC_NM_SETTING_MATCH_PATH N_("A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form \"pci-$domain:$bus:$device.$function\", where each variable is an hexadecimal value; for example \"pci-0000:0a:00.0\". The path of a device can be obtained with \"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the \"path\" property exported by NetworkManager (\"nmcli -f general.path device show $dev\"). Each element of the list is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", \"netdev\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", \"standalone\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.") diff --git a/libnm-core/nm-setting-match.c b/libnm-core/nm-setting-match.c index 599fcf9916..940cc68dda 100644 --- a/libnm-core/nm-setting-match.c +++ b/libnm-core/nm-setting-match.c @@ -817,13 +817,19 @@ nm_setting_match_class_init (NMSettingMatchClass *klass) * NMSettingMatch:interface-name * * A list of interface names to match. Each element is a shell wildcard - * pattern. When an element is prefixed with exclamation mark (!) the - * condition is inverted. + * pattern. * - * A candidate interface name is considered matching when both these - * conditions are satisfied: (a) any of the elements not prefixed with '!' - * matches or there aren't such elements; (b) none of the elements - * prefixed with '!' match. + * An element can be prefixed with a pipe symbol (|) or an ampersand (&). + * The former means that the element is optional and the latter means that + * it is mandatory. If there are any optional elements, than the match + * evaluates to true if at least one of the optional element matches + * (logical OR). If there are any mandatory elements, then they all + * must match (logical AND). By default, an element is optional. This means + * that an element "foo" behaves the same as "|foo". An element can also be inverted + * with exclamation mark (!) between the pipe symbol (or the ampersand) and before + * the pattern. Note that "!foo" is a shortcut for the mandatory match "&!foo". Finally, + * a backslash can be used at the beginning of the element (after the optional special characters) + * to escape the start of the pattern. For example, "&\\!a" is an mandatory match for literally "!a". * * Since: 1.14 **/ @@ -845,6 +851,10 @@ nm_setting_match_class_init (NMSettingMatchClass *klass) * of an assignment. In the latter case, the exact assignment is looked for * with right and left hand side matching. * + * See NMSettingMatch:interface-name for how special characters '|', '&', + * '!' and '\\' are used for optional and mandatory matches and inverting the + * pattern. + * * Since: 1.26 **/ obj_properties[PROP_KERNEL_COMMAND_LINE] = @@ -858,11 +868,10 @@ nm_setting_match_class_init (NMSettingMatchClass *klass) * NMSettingMatch:driver * * A list of driver names to match. Each element is a shell wildcard pattern. - * When an element is prefixed with exclamation mark (!) the condition is - * inverted. A candidate driver name is considered matching when both these - * conditions are satisfied: (a) any of the elements not prefixed with '!' - * matches or there aren't such elements; (b) none of the elements prefixed - * with '!' match. + * + * See NMSettingMatch:interface-name for how special characters '|', '&', + * '!' and '\\' are used for optional and mandatory matches and inverting the + * pattern. * * Since: 1.26 **/ @@ -873,7 +882,6 @@ nm_setting_match_class_init (NMSettingMatchClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - /** * NMSettingMatch:path * @@ -891,14 +899,11 @@ nm_setting_match_class_init (NMSettingMatchClass *klass) * property exported by NetworkManager ("nmcli -f general.path device * show $dev"). * - * Each element of the list is a shell wildcard pattern. When an - * element is prefixed with exclamation mark (!) the condition is - * inverted. + * Each element of the list is a shell wildcard pattern. * - * A candidate path is considered matching when both these - * conditions are satisfied: (a) any of the elements not prefixed with '!' - * matches or there aren't such elements; (b) none of the elements - * prefixed with '!' match. + * See NMSettingMatch:interface-name for how special characters '|', '&', + * '!' and '\\' are used for optional and mandatory matches and inverting the + * pattern. * * Since: 1.26 **/ diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 8019775a96..f5699b7e95 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -1698,30 +1698,109 @@ nm_match_spec_join (GSList *specs) return g_string_free (str, FALSE); } +static void +_pattern_parse (const char *input, + const char **out_pattern, + gboolean *out_is_inverted, + gboolean *out_is_mandatory) +{ + gboolean is_inverted = FALSE; + gboolean is_mandatory = FALSE; + + if (input[0] == '&') { + input++; + is_mandatory = TRUE; + if (input[0] == '!') { + input++; + is_inverted = TRUE; + } + goto out; + } + + if (input[0] == '|') { + input++; + if (input[0] == '!') { + input++; + is_inverted = TRUE; + } + goto out; + } + + if (input[0] == '!') { + input++; + is_inverted = TRUE; + is_mandatory = TRUE; + goto out; + } + +out: + if (input[0] == '\\') + input++; + + *out_pattern = input; + *out_is_inverted = is_inverted; + *out_is_mandatory = is_mandatory; +} + gboolean nm_wildcard_match_check (const char *str, const char *const *patterns, guint num_patterns) { - gsize i, neg = 0; + gboolean has_optional = FALSE; + gboolean has_any_optional = FALSE; + guint i; for (i = 0; i < num_patterns; i++) { - if (patterns[i][0] == '!') { - neg++; - if (!str) - continue; - if (!fnmatch (patterns[i] + 1, str, 0)) + gboolean is_inverted; + gboolean is_mandatory; + gboolean match; + const char *p; + + _pattern_parse (patterns[i], &p, &is_inverted, &is_mandatory); + + match = (fnmatch (p, str, 0) == 0); + if (is_inverted) + match = !match; + + if (is_mandatory) { + if (!match) return FALSE; + } else { + has_any_optional = TRUE; + if (match) + has_optional = TRUE; } } - if (neg == num_patterns) - return TRUE; + return has_optional + || !has_any_optional; +} - if (str) { - for (i = 0; i < num_patterns; i++) { - if ( patterns[i][0] != '!' - && !fnmatch (patterns[i], str, 0)) +/*****************************************************************************/ + +static gboolean +_kernel_cmdline_match (const char *const*proc_cmdline, + const char *pattern) +{ + + if (proc_cmdline) { + gboolean has_equal = (!!strchr (pattern, '=')); + gsize pattern_len = strlen (pattern); + + for (; proc_cmdline[0]; proc_cmdline++) { + const char *c = proc_cmdline[0]; + + if (has_equal) { + /* if pattern contains '=' compare full key=value */ + if (nm_streq (c, pattern)) + return TRUE; + continue; + } + + /* otherwise consider pattern as key only */ + if ( strncmp (c, pattern, pattern_len) == 0 + && NM_IN_SET (c[pattern_len], '\0', '=')) return TRUE; } } @@ -1729,86 +1808,48 @@ nm_wildcard_match_check (const char *str, return FALSE; } -/*****************************************************************************/ - gboolean nm_utils_kernel_cmdline_match_check (const char *const*proc_cmdline, const char *const*patterns, guint num_patterns, GError **error) { - gboolean pos_patterns = FALSE; + gboolean has_optional = FALSE; + gboolean has_any_optional = FALSE; guint i; for (i = 0; i < num_patterns; i++) { - const char *patterns_i = patterns[i]; - const char *const*proc_cmdline_i; - gboolean negative = FALSE; - gboolean found = FALSE; - const char *equal; + const char *element = patterns[i]; + gboolean is_inverted = FALSE; + gboolean is_mandatory = FALSE; + gboolean match; + const char *p; - if (patterns_i[0] == '!') { - ++patterns_i; - negative = TRUE; - } else - pos_patterns = TRUE; + _pattern_parse (element, &p, &is_inverted, &is_mandatory); - equal = strchr (patterns_i, '='); + match = _kernel_cmdline_match (proc_cmdline, p); + if (is_inverted) + match = !match; - proc_cmdline_i = proc_cmdline; - while (*proc_cmdline_i) { - if (equal) { - /* if pattern contains = compare full key=value */ - found = nm_streq (*proc_cmdline_i, patterns_i); - } else { - gsize l = strlen (patterns_i); - - /* otherwise consider pattern as key only */ - if ( strncmp (*proc_cmdline_i, patterns_i, l) == 0 - && NM_IN_SET ((*proc_cmdline_i)[l], '\0', '=')) - found = TRUE; - } - if ( found - && negative) { - /* first negative match */ + if (is_mandatory) { + if (!match) { nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "device does not satisfy match.kernel-command-line property %s", patterns[i]); return FALSE; } - proc_cmdline_i++; + } else { + has_any_optional = TRUE; + if (match) + has_optional = TRUE; } + } - /* FIXME(release-blocker): match.interface-name and match.driver have the meaning, - * that any of the matches may yield success. For match.kernel-command-line, we - * do here that all must match. This inconsistency is undesired. - * - * 1) improve gtk-doc documentation explaining how these options match. - * - * 2) possibly unify the behavior so that kernel-command-line behaves like other - * matches (and ANY may match). Note that this would be contrary to systemd's - * Conditions, which by default requires that ALL conditions match (AND). We - * should be consistent within our match options, and not with systemd here. - * - * 2b) Note that systemd supports special token like "=|", to indicate that - * ANY behavior. If we want, we could also introduce two special prefixes - * "&..." and "|...", to support either. It's slightly complicated how - * these work in combinations with "!". - * Unless we fully decide what we do about this, NMSettingMatch.verify() should - * reject matches that start with '&' or '|', because these will be reserved for - * future use. - * - * 3) while fixing this, this code should move to a separate function so we - * can unit test the match of kernel command lines. - */ - if ( pos_patterns - && !found) { - /* positive patterns configured but no match */ - nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not satisfy any match.kernel-command-line property %s...", - patterns[0]); - return FALSE; - } + if ( !has_optional + && has_any_optional) { + nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not satisfy any match.kernel-command-line property"); + return FALSE; } return TRUE; diff --git a/src/tests/test-core.c b/src/tests/test-core.c index d1bf28743e..099786ef68 100644 --- a/src/tests/test-core.c +++ b/src/tests/test-core.c @@ -968,10 +968,17 @@ test_wildcard_match (void) do_test_wildcard_match ("b", TRUE, "!!a"); do_test_wildcard_match ("!a", FALSE, "!!a"); - do_test_wildcard_match ("\\", TRUE, "\\\\"); + do_test_wildcard_match ("\\", TRUE, "\\\\\\"); do_test_wildcard_match ("\\\\", FALSE, "\\\\"); do_test_wildcard_match ("", FALSE, "\\\\"); + do_test_wildcard_match ("\\a", TRUE, "\\\\\\a"); + do_test_wildcard_match ("b", TRUE, "&!a"); + do_test_wildcard_match ("a", FALSE, "&!a"); + do_test_wildcard_match ("!a", TRUE, "&\\!a"); + do_test_wildcard_match ("!a", TRUE, "|\\!a"); + do_test_wildcard_match ("!a", TRUE, "\\!a"); + do_test_wildcard_match ("name", FALSE, "name[123]"); do_test_wildcard_match ("name1", TRUE, "name[123]"); do_test_wildcard_match ("name2", TRUE, "name[123]"); @@ -979,6 +986,12 @@ test_wildcard_match (void) do_test_wildcard_match ("name4", FALSE, "name[123]"); do_test_wildcard_match ("[a]", TRUE, "\\[a\\]"); + + do_test_wildcard_match ("aa", FALSE, "!a*"); + do_test_wildcard_match ("aa", FALSE, "&!a*"); + do_test_wildcard_match ("aa", FALSE, "|!a*"); + do_test_wildcard_match ("aa", FALSE, "&!a*", "aa"); + do_test_wildcard_match ("aa", TRUE, "|!a*", "aa"); } static NMConnection * @@ -2146,6 +2159,13 @@ test_kernel_cmdline_match_check (void) _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a"), NM_MAKE_STRV ("a")); _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a=b"), NM_MAKE_STRV ("a")); _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a=b", "b"), NM_MAKE_STRV ("a", "b")); + _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a=b", "b"), NM_MAKE_STRV ("&a", "&b")); + _kernel_cmdline_match (FALSE, NM_MAKE_STRV ("a=b", "bc"), NM_MAKE_STRV ("&a", "&b")); + _kernel_cmdline_match (FALSE, NM_MAKE_STRV ("a=b", "b"), NM_MAKE_STRV ("&a", "&b", "c")); + _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a=b", "b"), NM_MAKE_STRV ("&a", "&b", "b", "c")); + _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a=b", "b", "c=dd"), NM_MAKE_STRV ("&a", "&b", "c")); + _kernel_cmdline_match (FALSE, NM_MAKE_STRV ("a", "b"), NM_MAKE_STRV ("a", "&c")); + _kernel_cmdline_match (TRUE, NM_MAKE_STRV ("a", "b"), NM_MAKE_STRV ("a", "|\\c")); } /*****************************************************************************/ From 427fbc85f0f325e3ff4c887ffd0d145cc1112306 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Thu, 18 Jun 2020 18:21:48 +0200 Subject: [PATCH 061/199] nmcs-http: fix multiple HTTP request bug Since just a single pointer is used to store the socket's GSource if more than 1 consecutive request was done through the same HTTP provider the 2nd request would clear the GSource associated to the second request causing the 1st HTTP request to never complete and end up in a expired timeout. Use a hashtable instead so we can correctly track all requests. https://bugzilla.redhat.com/show_bug.cgi?id=1821787 Fixes: 69f048bf0ca3 ('cloud-setup: add tool for automatic IP configuration in cloud') --- clients/cloud-setup/nm-http-client.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index 94f3fe2b8a..16dbd5bbe0 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -16,7 +16,7 @@ typedef struct { GMainContext *context; CURLM *mhandle; GSource *mhandle_source_timeout; - GSource *mhandle_source_socket; + GHashTable *source_sockets_hashtable; } NMHttpClientPrivate; struct _NMHttpClient { @@ -615,12 +615,13 @@ _mhandle_socket_cb (int fd, static int _mhandle_socketfunction_cb (CURL *e_handle, curl_socket_t fd, int what, void *user_data, void *socketp) { + GSource *source_socket; NMHttpClient *self = user_data; NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); (void) _NM_ENSURE_TYPE (int, fd); - nm_clear_g_source_inst (&priv->mhandle_source_socket); + g_hash_table_remove (priv->source_sockets_hashtable, GINT_TO_POINTER (fd)); if (what != CURL_POLL_REMOVE) { GIOCondition condition = 0; @@ -635,13 +636,17 @@ _mhandle_socketfunction_cb (CURL *e_handle, curl_socket_t fd, int what, void *us condition = 0; if (condition) { - priv->mhandle_source_socket = nm_g_unix_fd_source_new (fd, - condition, - G_PRIORITY_DEFAULT, - _mhandle_socket_cb, - self, + source_socket = nm_g_unix_fd_source_new (fd, + condition, + G_PRIORITY_DEFAULT, + _mhandle_socket_cb, + self, NULL); - g_source_attach (priv->mhandle_source_socket, priv->context); + g_source_attach (source_socket, priv->context); + + g_hash_table_insert (priv->source_sockets_hashtable, + GINT_TO_POINTER (fd), + source_socket); } } @@ -678,6 +683,11 @@ _mhandle_timerfunction_cb (CURLM *multi, long timeout_msec, void *user_data) static void nm_http_client_init (NMHttpClient *self) { + NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); + priv->source_sockets_hashtable = g_hash_table_new_full (nm_direct_hash, + NULL, + NULL, + (GDestroyNotify) nm_g_source_destroy_and_unref); } static void @@ -714,9 +724,9 @@ dispose (GObject *object) NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); nm_clear_pointer (&priv->mhandle, curl_multi_cleanup); + nm_clear_pointer (&priv->source_sockets_hashtable, g_hash_table_unref); nm_clear_g_source_inst (&priv->mhandle_source_timeout); - nm_clear_g_source_inst (&priv->mhandle_source_socket); G_OBJECT_CLASS (nm_http_client_parent_class)->dispose (object); } From e09bd2339a224a13067b0adcf9cb84a4f13ef003 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Thu, 18 Jun 2020 18:26:59 +0200 Subject: [PATCH 062/199] nmcs-http: remove the timeout once expired libcurl's documentation for CURLMOPT_TIMERFUNCTION requires the application to install a non-repeating timer. https://curl.haxx.se/libcurl/c/CURLMOPT_TIMERFUNCTION.html So let's remove the GSource once expired. Fixes: 69f048bf0ca3 ('cloud-setup: add tool for automatic IP configuration in cloud') --- clients/cloud-setup/nm-http-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index 16dbd5bbe0..817f0e2eba 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -657,7 +657,7 @@ static gboolean _mhandle_timeout_cb (gpointer user_data) { _mhandle_action (user_data, CURL_SOCKET_TIMEOUT, 0); - return G_SOURCE_CONTINUE; + return G_SOURCE_REMOVE; } static int From 3bd30f6064c3e879427bc47e0c258c7797cd3fe6 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Thu, 18 Jun 2020 18:15:58 +0200 Subject: [PATCH 063/199] nmcs: add error message when a HTTP request times out https://bugzilla.redhat.com/show_bug.cgi?id=1821787 --- clients/cloud-setup/nm-cloud-setup-utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clients/cloud-setup/nm-cloud-setup-utils.c b/clients/cloud-setup/nm-cloud-setup-utils.c index 13c9566a8b..a32003cb35 100644 --- a/clients/cloud-setup/nm-cloud-setup-utils.c +++ b/clients/cloud-setup/nm-cloud-setup-utils.c @@ -345,7 +345,8 @@ _poll_timeout_cb (gpointer user_data) { PollTaskData *poll_task_data = user_data; - _poll_return (poll_task_data, FALSE, NULL); + _poll_return (poll_task_data, FALSE, nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "timeout expired")); return G_SOURCE_CONTINUE; } From aa5959a595d12697c5714d50a19d0fdc69b69cff Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Tue, 23 Jun 2020 17:58:42 +0200 Subject: [PATCH 064/199] nm-shared-utils: add util to parse out lines from a string https://bugzilla.redhat.com/show_bug.cgi?id=1821787 --- shared/nm-glib-aux/nm-shared-utils.c | 41 ++++++++++++++++++++++++++++ shared/nm-glib-aux/nm-shared-utils.h | 5 ++++ 2 files changed, 46 insertions(+) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 8290016448..1569662f8c 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -1074,6 +1074,47 @@ nm_utils_parse_inaddr_prefix (int addr_family, return TRUE; } +gboolean +nm_utils_parse_next_line (const char **inout_ptr, + gsize *inout_len, + const char **out_line, + gsize *out_line_len) +{ + const char *line_start; + const char *line_end; + + g_return_val_if_fail (inout_ptr, FALSE); + g_return_val_if_fail (inout_len, FALSE); + g_return_val_if_fail (out_line, FALSE); + + if (*inout_len <= 0) + goto error; + + line_start = *inout_ptr; + line_end = memchr (line_start, '\n', *inout_len); + if (!line_end) + line_end = memchr (line_start, '\0', *inout_len); + if (!line_end) { + line_end = line_start + *inout_len; + NM_SET_OUT (inout_len, 0); + } else + NM_SET_OUT (inout_len, *inout_len - (line_end - line_start) - 1); + + NM_SET_OUT (out_line, line_start); + NM_SET_OUT (out_line_len, (gsize) (line_end - line_start)); + + if (*inout_len > 0) + NM_SET_OUT (inout_ptr, line_end + 1); + else + NM_SET_OUT (inout_ptr, NULL); + return TRUE; + +error: + NM_SET_OUT (out_line, NULL); + NM_SET_OUT (out_line_len, 0); + return FALSE; +} + /*****************************************************************************/ gboolean diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index c16a89b3af..142190ae4b 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -817,6 +817,11 @@ gboolean nm_utils_parse_inaddr_prefix (int addr_family, char **out_addr, int *out_prefix); +gboolean nm_utils_parse_next_line (const char **inout_ptr, + gsize *inout_len, + const char **out_line, + gsize *out_line_len); + gint64 nm_g_ascii_strtoll (const char *nptr, char **endptr, guint base); From d46da9072a0ea009a30cd0ffe6379cab5a8125d2 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Thu, 18 Jun 2020 18:17:33 +0200 Subject: [PATCH 065/199] nmcs: fix indentation --- clients/cloud-setup/nm-http-client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index 817f0e2eba..bf42906271 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -159,8 +159,8 @@ _ehandle_complete (EHandleData *edata, nm_clear_pointer (&edata->timeout_source, nm_g_source_destroy_and_unref); - nm_clear_g_cancellable_disconnect (g_task_get_cancellable (edata->task), - &edata->cancellable_id); + nm_clear_g_cancellable_disconnect (g_task_get_cancellable (edata->task), + &edata->cancellable_id); if (error_take) { if (nm_utils_error_is_cancelled (error_take)) From 1095cef9a14f916176a85639e35743339c320739 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Thu, 11 Jun 2020 16:35:14 +0200 Subject: [PATCH 066/199] main: remove unused argument --- clients/cloud-setup/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/clients/cloud-setup/main.c b/clients/cloud-setup/main.c index 4e1a9a4e4e..b89943c61c 100644 --- a/clients/cloud-setup/main.c +++ b/clients/cloud-setup/main.c @@ -276,7 +276,6 @@ _nmc_skip_connection (NMConnection *connection) static gboolean _nmc_mangle_connection (NMDevice *device, NMConnection *connection, - gboolean is_single_nic, const NMCSProviderGetConfigIfaceData *config_data, gboolean *out_changed) { @@ -438,7 +437,6 @@ try_again: if (!_nmc_mangle_connection (device, applied_connection, - is_single_nic, config_data, &changed)) { _LOGD ("config device %s: device has no suitable applied connection. Skip", hwaddr); From 053bce438b231e5837164eb9e5ce9fa02c047b27 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Thu, 18 Jun 2020 18:19:45 +0200 Subject: [PATCH 067/199] nmcs-http: add param to GET API to set custom HTTP headers https://bugzilla.redhat.com/show_bug.cgi?id=1821787 --- clients/cloud-setup/nm-http-client.c | 29 +++++++++++++++++++++++++ clients/cloud-setup/nm-http-client.h | 2 ++ clients/cloud-setup/nmcs-provider-ec2.c | 4 ++++ 3 files changed, 35 insertions(+) diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index bf42906271..946ed8ce93 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -119,6 +119,7 @@ typedef struct { CURL *ehandle; char *url; GString *recv_data; + struct curl_slist *headers; gssize max_data; gulong cancellable_id; } EHandleData; @@ -145,6 +146,8 @@ _ehandle_free (EHandleData *edata) if (edata->recv_data) g_string_free (edata->recv_data, TRUE); + if (edata->headers) + curl_slist_free_all (edata->headers); g_free (edata->url); nm_g_slice_free (edata); } @@ -260,12 +263,14 @@ nm_http_client_get (NMHttpClient *self, const char *url, int timeout_msec, gssize max_data, + const char *const *http_headers, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { NMHttpClientPrivate *priv; EHandleData *edata; + guint i; g_return_if_fail (NM_IS_HTTP_CLIENT (self)); g_return_if_fail (url); @@ -281,6 +286,7 @@ nm_http_client_get (NMHttpClient *self, .recv_data = g_string_sized_new (NM_MIN (max_data, 245)), .max_data = max_data, .url = g_strdup (url), + .headers = NULL, }; nmcs_wait_for_objects_register (edata->task); @@ -302,6 +308,23 @@ nm_http_client_get (NMHttpClient *self, curl_easy_setopt (edata->ehandle, CURLOPT_WRITEDATA, edata); curl_easy_setopt (edata->ehandle, CURLOPT_PRIVATE, edata); + if (http_headers) { + for (i = 0; http_headers[i]; ++i) { + struct curl_slist *tmp; + + tmp = curl_slist_append (edata->headers, + http_headers[i]); + if (!tmp) { + curl_slist_free_all (tmp); + _LOGE ("curl: curl_slist_append() failed adding %s", http_headers[i]); + continue; + } + edata->headers = tmp; + } + + curl_easy_setopt (edata->ehandle, CURLOPT_HTTPHEADER, edata->headers); + } + if (timeout_msec > 0) { edata->timeout_source = _source_attach (self, nm_g_timeout_source_new (timeout_msec, @@ -362,6 +385,7 @@ nm_http_client_get_finish (NMHttpClient *self, typedef struct { GTask *task; char *uri; + const char *const *http_headers; NMHttpClientPollGetCheckFcn check_fcn; gpointer check_user_data; GBytes *response_data; @@ -378,6 +402,7 @@ _poll_get_data_free (gpointer data) g_free (poll_get_data->uri); nm_clear_pointer (&poll_get_data->response_data, g_bytes_unref); + g_strfreev ((char **) poll_get_data->http_headers); nm_g_slice_free (poll_get_data); } @@ -397,6 +422,7 @@ _poll_get_probe_start_fcn (GCancellable *cancellable, poll_get_data->uri, poll_get_data->request_timeout_ms, poll_get_data->request_max_data, + poll_get_data->http_headers, cancellable, callback, user_data); @@ -476,6 +502,7 @@ nm_http_client_poll_get (NMHttpClient *self, gssize request_max_data, int poll_timeout_ms, int ratelimit_timeout_ms, + const char *const *http_headers, GCancellable *cancellable, NMHttpClientPollGetCheckFcn check_fcn, gpointer check_user_data, @@ -502,6 +529,7 @@ nm_http_client_poll_get (NMHttpClient *self, .check_fcn = check_fcn, .check_user_data = check_user_data, .response_code = -1, + .http_headers = NM_CAST_STRV_CC (g_strdupv ((char **) http_headers)), }; nmcs_wait_for_objects_register (poll_get_data->task); @@ -684,6 +712,7 @@ static void nm_http_client_init (NMHttpClient *self) { NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE (self); + priv->source_sockets_hashtable = g_hash_table_new_full (nm_direct_hash, NULL, NULL, diff --git a/clients/cloud-setup/nm-http-client.h b/clients/cloud-setup/nm-http-client.h index 86ee938ee6..ef7c984a9b 100644 --- a/clients/cloud-setup/nm-http-client.h +++ b/clients/cloud-setup/nm-http-client.h @@ -29,6 +29,7 @@ void nm_http_client_get (NMHttpClient *self, const char *uri, int timeout_msec, gssize max_data, + const char *const *http_headers, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); @@ -50,6 +51,7 @@ void nm_http_client_poll_get (NMHttpClient *self, gssize request_max_data, int poll_timeout_ms, int ratelimit_timeout_ms, + const char *const *http_headers, GCancellable *cancellable, NMHttpClientPollGetCheckFcn check_fcn, gpointer check_user_data, diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c index 82ed094970..c8db31f97f 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ b/clients/cloud-setup/nmcs-provider-ec2.c @@ -138,6 +138,7 @@ detect (NMCSProvider *provider, 256*1024, 7000, 1000, + NULL, g_task_get_cancellable (task), _detect_get_meta_data_check_cb, NULL, @@ -396,6 +397,7 @@ _get_config_metadata_ready_cb (GObject *source, 512*1024, 10000, 1000, + NULL, iface_data->cancellable, NULL, NULL, @@ -413,6 +415,7 @@ _get_config_metadata_ready_cb (GObject *source, 512*1024, 10000, 1000, + NULL, iface_data->cancellable, NULL, NULL, @@ -529,6 +532,7 @@ get_config (NMCSProvider *provider, 256 * 1024, 15000, 1000, + NULL, g_task_get_cancellable (get_config_data->task), _get_config_metadata_ready_check, metadata_data, From 75a84677caab9161e3b347ddc20a4b387873d048 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Thu, 18 Jun 2020 18:11:41 +0200 Subject: [PATCH 068/199] nmcs-main: support adding additional routes This allows a provider to only add additional routes to the applied profile https://bugzilla.redhat.com/show_bug.cgi?id=1821787 --- clients/cloud-setup/main.c | 125 ++++++++++++++++------------ clients/cloud-setup/nmcs-provider.c | 1 + clients/cloud-setup/nmcs-provider.h | 8 +- 3 files changed, 79 insertions(+), 55 deletions(-) diff --git a/clients/cloud-setup/main.c b/clients/cloud-setup/main.c index b89943c61c..ad3a47cbe0 100644 --- a/clients/cloud-setup/main.c +++ b/clients/cloud-setup/main.c @@ -280,16 +280,17 @@ _nmc_mangle_connection (NMDevice *device, gboolean *out_changed) { NMSettingIPConfig *s_ip; - gboolean addrs_changed; - gboolean routes_changed; - gboolean rules_changed; gsize i; in_addr_t gateway; gint64 rt_metric; guint32 rt_table; + NMIPRoute *route_entry; + gboolean addrs_changed = FALSE; + gboolean rules_changed = FALSE; + gboolean routes_changed = FALSE; gs_unref_ptrarray GPtrArray *addrs_new = NULL; gs_unref_ptrarray GPtrArray *rules_new = NULL; - nm_auto_unref_ip_route NMIPRoute *route_new = NULL; + gs_unref_ptrarray GPtrArray *routes_new = NULL; if (!nm_streq0 (nm_connection_get_connection_type (connection), NM_SETTING_WIRED_SETTING_NAME)) return FALSE; @@ -298,62 +299,80 @@ _nmc_mangle_connection (NMDevice *device, if (!s_ip) return FALSE; - addrs_new = g_ptr_array_new_full (config_data->ipv4s_len, (GDestroyNotify) nm_ip_address_unref); - for (i = 0; i < config_data->ipv4s_len; i++) { - NMIPAddress *entry; + addrs_new = g_ptr_array_new_full (config_data->ipv4s_len, + (GDestroyNotify) nm_ip_address_unref); + rules_new = g_ptr_array_new_full (config_data->ipv4s_len, + (GDestroyNotify) nm_ip_routing_rule_unref); + routes_new = g_ptr_array_new_full (config_data->iproutes_len + !!config_data->ipv4s_len, + (GDestroyNotify) nm_ip_route_unref); - entry = nm_ip_address_new_binary (AF_INET, - &config_data->ipv4s_arr[i], - config_data->cidr_prefix, - NULL); - if (entry) - g_ptr_array_add (addrs_new, entry); + if ( config_data->has_ipv4s + && config_data->has_cidr) { + for (i = 0; i < config_data->ipv4s_len; i++) { + NMIPAddress *entry; + + entry = nm_ip_address_new_binary (AF_INET, + &config_data->ipv4s_arr[i], + config_data->cidr_prefix, + NULL); + if (entry) + g_ptr_array_add (addrs_new, entry); + } + + gateway = nm_utils_ip4_address_clear_host_address (config_data->cidr_addr, config_data->cidr_prefix); + ((guint8 *) &gateway)[3] += 1; + + rt_metric = 10; + rt_table = 30400 + config_data->iface_idx; + + route_entry = nm_ip_route_new_binary (AF_INET, + &nm_ip_addr_zero, + 0, + &gateway, + rt_metric, + NULL); + nm_ip_route_set_attribute (route_entry, + NM_IP_ROUTE_ATTRIBUTE_TABLE, + g_variant_new_uint32 (rt_table)); + g_ptr_array_add (routes_new, route_entry); + + for (i = 0; i < config_data->ipv4s_len; i++) { + NMIPRoutingRule *entry; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + + entry = nm_ip_routing_rule_new (AF_INET); + nm_ip_routing_rule_set_priority (entry, rt_table); + nm_ip_routing_rule_set_from (entry, + _nm_utils_inet4_ntop (config_data->ipv4s_arr[i], sbuf), + 32); + nm_ip_routing_rule_set_table (entry, rt_table); + + nm_assert (nm_ip_routing_rule_validate (entry, NULL)); + + g_ptr_array_add (rules_new, entry); + } } - gateway = nm_utils_ip4_address_clear_host_address (config_data->cidr_addr, config_data->cidr_prefix); - ((guint8 *) &gateway)[3] += 1; + for (i = 0; i < config_data->iproutes_len; ++i) + g_ptr_array_add (routes_new, config_data->iproutes_arr[i]); - rt_metric = 10; - rt_table = 30400 + config_data->iface_idx; - - route_new = nm_ip_route_new_binary (AF_INET, - &nm_ip_addr_zero, - 0, - &gateway, - rt_metric, - NULL); - nm_ip_route_set_attribute (route_new, - NM_IP_ROUTE_ATTRIBUTE_TABLE, - g_variant_new_uint32 (rt_table)); - - rules_new = g_ptr_array_new_full (config_data->ipv4s_len, (GDestroyNotify) nm_ip_routing_rule_unref); - for (i = 0; i < config_data->ipv4s_len; i++) { - NMIPRoutingRule *entry; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - entry = nm_ip_routing_rule_new (AF_INET); - nm_ip_routing_rule_set_priority (entry, rt_table); - nm_ip_routing_rule_set_from (entry, - _nm_utils_inet4_ntop (config_data->ipv4s_arr[i], sbuf), - 32); - nm_ip_routing_rule_set_table (entry, rt_table); - - nm_assert (nm_ip_routing_rule_validate (entry, NULL)); - - g_ptr_array_add (rules_new, entry); + if (addrs_new->len) { + addrs_changed = nmcs_setting_ip_replace_ipv4_addresses (s_ip, + (NMIPAddress **) addrs_new->pdata, + addrs_new->len); } - addrs_changed = nmcs_setting_ip_replace_ipv4_addresses (s_ip, - (NMIPAddress **) addrs_new->pdata, - addrs_new->len); + if (routes_new->len) { + routes_changed = nmcs_setting_ip_replace_ipv4_routes (s_ip, + (NMIPRoute **) routes_new->pdata, + routes_new->len); + } - routes_changed = nmcs_setting_ip_replace_ipv4_routes (s_ip, - &route_new, - 1); - - rules_changed = nmcs_setting_ip_replace_ipv4_rules (s_ip, - (NMIPRoutingRule **) rules_new->pdata, - rules_new->len); + if (rules_new->len) { + rules_changed = nmcs_setting_ip_replace_ipv4_rules (s_ip, + (NMIPRoutingRule **) rules_new->pdata, + rules_new->len); + } NM_SET_OUT (out_changed, addrs_changed || routes_changed diff --git a/clients/cloud-setup/nmcs-provider.c b/clients/cloud-setup/nmcs-provider.c index 1f1b6e600d..bc21d8769e 100644 --- a/clients/cloud-setup/nmcs-provider.c +++ b/clients/cloud-setup/nmcs-provider.c @@ -114,6 +114,7 @@ _iface_data_free (gpointer data) NMCSProviderGetConfigIfaceData *iface_data = data; g_free (iface_data->ipv4s_arr); + g_free (iface_data->iproutes_arr); nm_g_slice_free (iface_data); } diff --git a/clients/cloud-setup/nmcs-provider.h b/clients/cloud-setup/nmcs-provider.h index e5a44da19f..e5950f930e 100644 --- a/clients/cloud-setup/nmcs-provider.h +++ b/clients/cloud-setup/nmcs-provider.h @@ -18,6 +18,9 @@ typedef struct { bool has_ipv4s:1; bool has_cidr:1; + NMIPRoute **iproutes_arr; + gsize iproutes_len; + /* TRUE, if the configuration was requested via hwaddrs argument to * nmcs_provider_get_config(). */ bool was_requested:1; @@ -29,8 +32,9 @@ nmcs_provider_get_config_iface_data_is_valid (const NMCSProviderGetConfigIfaceDa { return config_data && config_data->iface_idx >= 0 - && config_data->has_cidr - && config_data->has_ipv4s; + && ( ( config_data->has_ipv4s + && config_data->has_cidr) + || config_data->iproutes_len); } NMCSProviderGetConfigIfaceData *nmcs_provider_get_config_iface_data_new (gboolean was_requested); From a2b699f40f29fb1d37cda8c9a10365229f55b0c8 Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Thu, 18 Jun 2020 18:30:13 +0200 Subject: [PATCH 069/199] nmcs-gcp: add support for Google Cloud Platform load balancers This add a provider implementation for GCP that when detected fetches the ip addresses of configured internal load balancers. Once this information is fetched from the metadata server it instructs NetworkManager to add local routes for each found forwarded-ip. https://bugzilla.redhat.com/show_bug.cgi?id=1821787 --- Makefile.am | 2 + clients/cloud-setup/main.c | 2 + clients/cloud-setup/meson.build | 1 + clients/cloud-setup/nm-cloud-setup.service.in | 1 + clients/cloud-setup/nmcs-provider-gcp.c | 520 ++++++++++++++++++ clients/cloud-setup/nmcs-provider-gcp.h | 24 + 6 files changed, 550 insertions(+) create mode 100644 clients/cloud-setup/nmcs-provider-gcp.c create mode 100644 clients/cloud-setup/nmcs-provider-gcp.h diff --git a/Makefile.am b/Makefile.am index db9f4c80c6..1f90ff8fae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4829,6 +4829,8 @@ clients_cloud_setup_nm_cloud_setup_SOURCES = \ clients/cloud-setup/nmcs-provider.h \ clients/cloud-setup/nmcs-provider-ec2.c \ clients/cloud-setup/nmcs-provider-ec2.h \ + clients/cloud-setup/nmcs-provider-gcp.c \ + clients/cloud-setup/nmcs-provider-gcp.h \ $(NULL) clients_cloud_setup_nm_cloud_setup_CPPFLAGS = \ diff --git a/clients/cloud-setup/main.c b/clients/cloud-setup/main.c index ad3a47cbe0..78260b9732 100644 --- a/clients/cloud-setup/main.c +++ b/clients/cloud-setup/main.c @@ -6,6 +6,7 @@ #include "nm-cloud-setup-utils.h" #include "nmcs-provider-ec2.h" +#include "nmcs-provider-gcp.h" #include "nm-libnm-core-intern/nm-libnm-core-utils.h" /*****************************************************************************/ @@ -84,6 +85,7 @@ _provider_detect (GCancellable *sigterm_cancellable) }; const GType gtypes[] = { NMCS_TYPE_PROVIDER_EC2, + NMCS_TYPE_PROVIDER_GCP, }; int i; gulong cancellable_signal_id; diff --git a/clients/cloud-setup/meson.build b/clients/cloud-setup/meson.build index d8f96539e0..805d46813b 100644 --- a/clients/cloud-setup/meson.build +++ b/clients/cloud-setup/meson.build @@ -28,6 +28,7 @@ sources = files( 'nm-cloud-setup-utils.c', 'nm-http-client.c', 'nmcs-provider-ec2.c', + 'nmcs-provider-gcp.c', 'nmcs-provider.c', ) diff --git a/clients/cloud-setup/nm-cloud-setup.service.in b/clients/cloud-setup/nm-cloud-setup.service.in index 69a1a29ccb..9866acd8b0 100644 --- a/clients/cloud-setup/nm-cloud-setup.service.in +++ b/clients/cloud-setup/nm-cloud-setup.service.in @@ -12,6 +12,7 @@ ExecStart=@libexecdir@/nm-cloud-setup # Opt-in by setting the right environment variable for # the provider. #Environment=NM_CLOUD_SETUP_EC2=yes +#Environment=NM_CLOUD_SETUP_GCP=yes CapabilityBoundingSet= LockPersonality=yes diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c new file mode 100644 index 0000000000..ba4016dd15 --- /dev/null +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include "nmcs-provider-gcp.h" + +#include "nm-cloud-setup-utils.h" + +/*****************************************************************************/ + +#define HTTP_TIMEOUT_MS 3000 +#define HTTP_REQ_MAX_DATA 512*1024 +#define HTTP_POLL_TIMEOUT_MS 10000 +#define HTTP_RATE_LIMIT_MS 1000 + +#define NM_GCP_HOST "metadata.google.internal" +#define NM_GCP_BASE "http://" NM_GCP_HOST +#define NM_GCP_API_VERSION "/v1" +#define NM_GCP_METADATA_URL_BASE NM_GCP_BASE "/computeMetadata" NM_GCP_API_VERSION "/instance" +#define NM_GCP_METADATA_URL_NET "/network-interfaces/" + +#define NM_GCP_METADATA_HEADER "Metadata-Flavor: Google" + +#define _gcp_uri_concat(...) nmcs_utils_uri_build_concat (NM_GCP_METADATA_URL_BASE, __VA_ARGS__) +#define _gcp_uri_interfaces(...) _gcp_uri_concat (NM_GCP_METADATA_URL_NET, ##__VA_ARGS__) + +/*****************************************************************************/ + +struct _NMCSProviderGCP { + NMCSProvider parent; +}; + +struct _NMCSProviderGCPClass { + NMCSProviderClass parent; +}; + +G_DEFINE_TYPE (NMCSProviderGCP, nmcs_provider_gcp, NMCS_TYPE_PROVIDER); + +/*****************************************************************************/ + +static void +_detect_get_meta_data_done_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_object GTask *task = user_data; + gs_free_error GError *get_error = NULL; + gs_free_error GError *error = NULL; + gboolean success; + + success = nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + NULL, + &get_error); + + if (nm_utils_error_is_cancelled (get_error)) { + g_task_return_error (task, g_steal_pointer (&get_error)); + return; + } + + if (get_error) { + nm_utils_error_set (&error, + NM_UTILS_ERROR_UNKNOWN, + "failure to get GCP metadata: %s", + get_error->message); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + if (!success) { + nm_utils_error_set (&error, + NM_UTILS_ERROR_UNKNOWN, + "failure to detect GCP metadata"); + g_task_return_error (task, g_steal_pointer (&error)); + return; + } + + g_task_return_boolean (task, TRUE); +} + +static void +detect (NMCSProvider *provider, + GTask *task) +{ + NMHttpClient *http_client; + gs_free char *uri = NULL; + + http_client = nmcs_provider_get_http_client (provider); + + nm_http_client_poll_get (http_client, + (uri = _gcp_uri_concat ("id")), + HTTP_TIMEOUT_MS, + 256*1024, + 7000, + 1000, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (task), + NULL, + NULL, + _detect_get_meta_data_done_cb, + task); +} + +/*****************************************************************************/ + +typedef struct { + NMCSProviderGetConfigTaskData *config_data; + guint n_ifaces_pending; + GError *error; + bool success:1; +} GCPData; + +typedef struct { + NMCSProviderGetConfigIfaceData *iface_get_config; + GCPData *gcp_data; + gssize iface_idx; + guint n_fips_pending; +} GCPIfaceData; + +static void +_get_config_maybe_task_return (GCPData *gcp_data, + GError *error_take) +{ + NMCSProviderGetConfigTaskData *config_data = gcp_data->config_data; + gs_free_error GError *gcp_error = NULL; + + if (error_take) { + nm_clear_error (&gcp_data->error); + gcp_data->error = error_take; + } + + if (gcp_data->n_ifaces_pending) + return; + + gcp_error = gcp_data->error; + + if (!gcp_data->success) { + nm_assert (gcp_error); + + if (nm_utils_error_is_cancelled (gcp_error)) + _LOGD ("get-config: cancelled"); + else + _LOGD ("get-config: failed: %s", gcp_error->message); + g_task_return_error (config_data->task, g_steal_pointer (&gcp_error)); + } else { + _LOGD ("get-config: success"); + g_task_return_pointer (config_data->task, + g_hash_table_ref (config_data->result_dict), + (GDestroyNotify) g_hash_table_unref); + } + + nm_g_slice_free (gcp_data); + g_object_unref (config_data->task); +} + +static void +_get_config_fip_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + NMCSProviderGetConfigIfaceData *iface_get_config; + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData *iface_data = user_data; + gs_free_error GError *error = NULL; + const char *fip_str = NULL; + NMIPRoute **routes_arr; + NMIPRoute *route_new; + GCPData *gcp_data; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + &response, + &error); + + if (error) + goto iface_done; + + fip_str = g_bytes_get_data (response, NULL); + if (!nm_utils_ipaddr_valid (AF_INET, fip_str)) { + error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "forwarded-ip is not a valid ip address"); + goto iface_done; + } + + _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: adding forwarded-ip %s", + iface_data->iface_idx, + fip_str); + + iface_get_config = iface_data->iface_get_config; + iface_get_config->iface_idx = iface_data->iface_idx; + routes_arr = iface_get_config->iproutes_arr; + + route_new = nm_ip_route_new (AF_INET, + fip_str, + 32, + NULL, + 100, + &error); + if (error) + goto iface_done; + + nm_ip_route_set_attribute (route_new, + NM_IP_ROUTE_ATTRIBUTE_TYPE, + g_variant_new_string ("local")); + routes_arr[iface_get_config->iproutes_len] = route_new; + ++iface_get_config->iproutes_len; + gcp_data->success = TRUE; + +iface_done: + --iface_data->n_fips_pending; + if (iface_data->n_fips_pending == 0) { + nm_g_slice_free (iface_data); + --gcp_data->n_ifaces_pending; + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); + } +} + +static void +_get_config_ips_list_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_ptrarray GPtrArray *uri_arr = NULL; + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData *iface_data = user_data; + gs_free_error GError *error = NULL; + const char *response_str = NULL; + gsize response_len; + GCPData *gcp_data; + const char *line; + gsize line_len; + guint i; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + &response, + &error); + + if (error) + goto fips_error; + + + uri_arr = g_ptr_array_new_with_free_func (g_free); + response_str = g_bytes_get_data (response, &response_len); + + while (nm_utils_parse_next_line (&response_str, + &response_len, + &line, + &line_len)) { + nm_auto_free_gstring GString *gstr = NULL; + gint64 fip_index; + + gstr = g_string_new_len (line, line_len); + fip_index = _nm_utils_ascii_str_to_int64 (gstr->str, 10, 0, G_MAXINT64, -1); + + if (fip_index < 0) { + continue; + } + + g_string_printf (gstr, + "%"G_GSSIZE_FORMAT"/forwarded-ips/%"G_GINT64_FORMAT, + iface_data->iface_idx, + fip_index); + g_ptr_array_add (uri_arr, g_string_free (g_steal_pointer (&gstr), FALSE)); + } + + iface_data->n_fips_pending = uri_arr->len; + + _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: found %u forwarded ips", + iface_data->iface_idx, + iface_data->n_fips_pending); + + if (iface_data->n_fips_pending == 0) { + error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "found no forwarded ip"); + goto fips_error; + } + + iface_data->iface_get_config->iproutes_arr = + g_new (NMIPRoute *, iface_data->n_fips_pending); + + for (i = 0; i < uri_arr->len; ++i) { + const char *str = uri_arr->pdata[i]; + gs_free const char *uri = NULL; + + nm_http_client_poll_get (NM_HTTP_CLIENT (source), + (uri = _gcp_uri_interfaces (str)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (gcp_data->config_data->task), + NULL, + NULL, + _get_config_fip_cb, + iface_data); + } + return; + +fips_error: + nm_g_slice_free (iface_data); + --gcp_data->n_ifaces_pending; + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); +} + +static void +_get_config_iface_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_bytes GBytes *response = NULL; + GCPIfaceData *iface_data = user_data; + gs_free_error GError *error = NULL; + gs_free const char *hwaddr = NULL; + gs_free const char *uri = NULL; + gs_free char *str = NULL; + GCPData *gcp_data; + + gcp_data = iface_data->gcp_data; + + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + &response, + &error); + + if (error) + goto iface_error; + + hwaddr = nmcs_utils_hwaddr_normalize (g_bytes_get_data (response, NULL), -1); + iface_data->iface_get_config = g_hash_table_lookup (gcp_data->config_data->result_dict, + hwaddr); + if (!iface_data->iface_get_config) { + _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: did not find a matching device", + iface_data->iface_idx); + error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "no matching hwaddr found for GCP interface"); + goto iface_error; + } + + _LOGI ("GCP interface[%"G_GSSIZE_FORMAT"]: found a matching device with hwaddr %s", + iface_data->iface_idx, + hwaddr); + + str = g_strdup_printf ("%"G_GSSIZE_FORMAT"/forwarded-ips/", + iface_data->iface_idx); + + nm_http_client_poll_get (NM_HTTP_CLIENT (source), + (uri = _gcp_uri_interfaces (str)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (gcp_data->config_data->task), + NULL, + NULL, + _get_config_ips_list_cb, + iface_data); + return; + +iface_error: + nm_g_slice_free (iface_data); + --gcp_data->n_ifaces_pending; + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); +} + +static void +_get_net_ifaces_list_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; + nm_auto_free_gstring GString *gstr = NULL; + gs_unref_bytes GBytes *response = NULL; + gs_free_error GError *error = NULL; + GCPData *gcp_data = user_data; + const char *response_str; + const char *token_start; + const char *token_end; + gsize response_len; + const char *line; + gsize line_len; + guint i; + + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + &response, + &error); + + if (error) { + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); + return; + } + + response_str = g_bytes_get_data (response, &response_len); + ifaces_arr = g_ptr_array_new (); + gstr = g_string_new (NULL); + + while (nm_utils_parse_next_line (&response_str, + &response_len, + &line, + &line_len)) { + GCPIfaceData *iface_data; + gssize iface_idx; + + token_start = line; + token_end = memchr (token_start, '/', line_len); + + if (!token_end) + continue; + + g_string_truncate (gstr, 0); + g_string_append_len (gstr, token_start, token_end - token_start); + iface_idx = _nm_utils_ascii_str_to_int64 (gstr->str, 10, 0, G_MAXSSIZE, -1); + + if (iface_idx < 0) + continue; + + iface_data = g_slice_new (GCPIfaceData); + *iface_data = (GCPIfaceData) { + .iface_get_config = NULL, + .gcp_data = gcp_data, + .iface_idx = iface_idx, + .n_fips_pending = 0, + }; + g_ptr_array_add (ifaces_arr, iface_data); + } + + gcp_data->n_ifaces_pending = ifaces_arr->len; + _LOGI ("found GCP interfaces: %u", ifaces_arr->len); + + for (i = 0; i < ifaces_arr->len; ++i) { + GCPIfaceData *data = ifaces_arr->pdata[i]; + gs_free const char *uri = NULL; + + _LOGD ("GCP interface[%"G_GSSIZE_FORMAT"]: retrieving configuration", + data->iface_idx); + + g_string_printf (gstr, "%"G_GSSIZE_FORMAT"/mac", data->iface_idx); + + nm_http_client_poll_get (NM_HTTP_CLIENT (source), + (uri = _gcp_uri_interfaces (gstr->str)), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (gcp_data->config_data->task), + NULL, + NULL, + _get_config_iface_cb, + data); + + } + + if (ifaces_arr->len == 0) { + error = nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "no GCP interfaces found"); + _get_config_maybe_task_return (gcp_data, g_steal_pointer (&error)); + } +} + + +static void +get_config (NMCSProvider *provider, + NMCSProviderGetConfigTaskData *get_config_data) +{ + gs_free const char *uri = NULL; + GCPData *gcp_data; + + gcp_data = g_slice_new (GCPData); + *gcp_data = (GCPData) { + .config_data = get_config_data, + .n_ifaces_pending = 0, + .error = NULL, + .success = FALSE, + + }; + + nm_http_client_poll_get (nmcs_provider_get_http_client (provider), + (uri = _gcp_uri_interfaces ()), + HTTP_TIMEOUT_MS, + HTTP_REQ_MAX_DATA, + HTTP_POLL_TIMEOUT_MS, + HTTP_RATE_LIMIT_MS, + NM_MAKE_STRV (NM_GCP_METADATA_HEADER), + g_task_get_cancellable (gcp_data->config_data->task), + NULL, + NULL, + _get_net_ifaces_list_cb, + gcp_data); +} + +/*****************************************************************************/ + +static void +nmcs_provider_gcp_init (NMCSProviderGCP *self) +{ +} + +static void +nmcs_provider_gcp_class_init (NMCSProviderGCPClass *klass) +{ + NMCSProviderClass *provider_class = NMCS_PROVIDER_CLASS (klass); + + provider_class->_name = "GCP"; + provider_class->_env_provider_enabled = NMCS_ENV_VARIABLE ("NM_CLOUD_SETUP_GCP"); + provider_class->detect = detect; + provider_class->get_config = get_config; +} diff --git a/clients/cloud-setup/nmcs-provider-gcp.h b/clients/cloud-setup/nmcs-provider-gcp.h new file mode 100644 index 0000000000..b0d3ec7d02 --- /dev/null +++ b/clients/cloud-setup/nmcs-provider-gcp.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#ifndef __NMCS_PROVIDER_GCP_H__ +#define __NMCS_PROVIDER_GCP_H__ + +#include "nmcs-provider.h" + +/*****************************************************************************/ + +typedef struct _NMCSProviderGCP NMCSProviderGCP; +typedef struct _NMCSProviderGCPClass NMCSProviderGCPClass; + +#define NMCS_TYPE_PROVIDER_GCP (nmcs_provider_gcp_get_type ()) +#define NMCS_PROVIDER_GCP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCP)) +#define NMCS_PROVIDER_GCP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCPClass)) +#define NMCS_IS_PROVIDER_GCP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMCS_TYPE_PROVIDER_GCP)) +#define NMCS_IS_PROVIDER_GCP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMCS_TYPE_PROVIDER_GCP)) +#define NMCS_PROVIDER_GCP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NMCS_TYPE_PROVIDER_GCP, NMCSProviderGCPClass)) + +GType nmcs_provider_gcp_get_type (void); + +/*****************************************************************************/ + +#endif /* __NMCS_PROVIDER_GCP_H__ */ From cfe349b971411c144da610c0b7674c507dbd8c4d Mon Sep 17 00:00:00 2001 From: Antonio Cardace Date: Fri, 26 Jun 2020 16:52:13 +0200 Subject: [PATCH 070/199] NEWS: update --- NEWS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 4013d654ee..6d4aec5f71 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,9 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE! profiles. * Fix support for OVS patch interfaces. * Support more tc qdiscs: tbf and sfq. +* Add new provider in nm-cloud-setup for Google Cloud Platform which + automatically detects and configures the host to receive traffic + from internal load balancers. ============================================= NetworkManager-1.24 From 071104124b1159bf2e82ac62b9f0b03de64eb38d Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 26 Jun 2020 11:37:01 +0200 Subject: [PATCH 071/199] device: clean up exported IP6 config when flushing addresses After flushing addresses and routes, it's also necessary to update the exported IP6 configuration. https://bugzilla.redhat.com/show_bug.cgi?id=1848888 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/551 Fixes: e302f5ff77a9 ('device: flush IP configuration of slaves during activation') --- src/devices/nm-device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 99b3c5f68c..90178b68fe 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -10862,8 +10862,11 @@ act_stage3_ip_config_start (NMDevice *self, platform = nm_device_get_platform (self); if (ifindex > 0) { + gs_unref_object NMIP6Config *config = nm_device_ip6_config_new (self); + nm_platform_ip_route_flush (platform, AF_INET6, ifindex); nm_platform_ip_address_flush (platform, AF_INET6, ifindex); + nm_device_set_ip_config (self, AF_INET6, (NMIPConfig *) config, FALSE, NULL); } } else { gboolean ipv6ll_handle_old = priv->ipv6ll_handle; From 8e9e6fd02420e9406d6327a544f32cdb03227352 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 28 Jun 2020 18:04:22 +0200 Subject: [PATCH 072/199] release: fix release script for "rc" --- contrib/fedora/rpm/release.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh index 461d79ef7e..ae94bf479f 100755 --- a/contrib/fedora/rpm/release.sh +++ b/contrib/fedora/rpm/release.sh @@ -180,11 +180,12 @@ case "$RELEASE_MODE" in number_is_odd "${VERSION_ARR[1]}" || die "cannot do devel release on top of version $VERSION_STR" if [ "$RELEASE_MODE" = devel ]; then [ "$((${VERSION_ARR[2]} + 1))" -lt 90 ] || die "devel release must have a micro version smaller than 90 but current version is $VERSION_STR" + [ "$CUR_BRANCH" == master ] || die "devel release can only be on master" else [ "${VERSION_ARR[2]}" -ge 90 ] || die "rc release must have a micro version larger than ${VERSION_ARR[0]}.90 but current version is $VERSION_STR" RC_VERSION="$((${VERSION_ARR[2]} - 90))" + [ "$CUR_BRANCH" == "nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))" ] || die "devel release can only be on \"nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))\" branch" fi - [ "$CUR_BRANCH" == master ] || die "devel release can only be on master" ;; *) die "Release mode $RELEASE_MODE not yet implemented" From 7f93fd8e7b4b6b3193b5397af79e3bf08b1fd981 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 28 Jun 2020 18:33:12 +0200 Subject: [PATCH 073/199] release: fix RC_VERSION for release script The release candidate -rc1 has version "1.y.90", -rc2 has "1.y.91", and so on. Fix the script. --- contrib/fedora/rpm/release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh index ae94bf479f..b9c371a320 100755 --- a/contrib/fedora/rpm/release.sh +++ b/contrib/fedora/rpm/release.sh @@ -183,7 +183,7 @@ case "$RELEASE_MODE" in [ "$CUR_BRANCH" == master ] || die "devel release can only be on master" else [ "${VERSION_ARR[2]}" -ge 90 ] || die "rc release must have a micro version larger than ${VERSION_ARR[0]}.90 but current version is $VERSION_STR" - RC_VERSION="$((${VERSION_ARR[2]} - 90))" + RC_VERSION="$((${VERSION_ARR[2]} - 88))" [ "$CUR_BRANCH" == "nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))" ] || die "devel release can only be on \"nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))\" branch" fi ;; From 99f834842aba42fe14fc1bbd28faf6f58c797bc4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 28 Jun 2020 18:49:15 +0200 Subject: [PATCH 074/199] release: fix "rc" release build and add option to suppress check for local branches --- contrib/fedora/rpm/release.sh | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh index b9c371a320..f25dfdc572 100755 --- a/contrib/fedora/rpm/release.sh +++ b/contrib/fedora/rpm/release.sh @@ -22,7 +22,7 @@ die_usage() { echo "FAIL: $@" echo echo "Usage:" - echo " $0 [devel|rc1|rc|major|minor] [--no-test] [--no-find-backports] [--no-cleanup]" + echo " $0 [devel|rc1|rc|major|minor] [--no-test] [--no-find-backports] [--no-cleanup] [--allow-local-branches]" exit 1 } @@ -120,6 +120,7 @@ VERSION_STR="$(IFS=.; echo "${VERSION_ARR[*]}")" RELEASE_MODE="" DRY_RUN=1 FIND_BACKPORTS=1 +ALLOW_LOCAL_BRANCHES=0 while [ "$#" -ge 1 ]; do A="$1" shift @@ -143,6 +144,12 @@ while [ "$#" -ge 1 ]; do --no-cleanup) DO_CLEANUP=0 ;; + --allow-local-branches) + # by default, the script errors out if the relevant branch (master, nm-1-Y) are not the same + # as the remote branch on origin. You should not do a release if you have local changes + # that differ from upstream. Set this flag to override that check. + ALLOW_LOCAL_BRANCHES=1 + ;; *) die_usage "unknown argument \"$A\"" ;; @@ -194,8 +201,10 @@ esac git fetch || die "git fetch failed" -git_same_ref "$CUR_BRANCH" "refs/heads/$CUR_BRANCH" || die "Current branch $CUR_BRANCH is not a branch??" -git_same_ref "$CUR_BRANCH" "refs/remotes/$ORIGIN/$CUR_BRANCH" || die "Current branch $CUR_BRANCH seems not up to date. Git pull?" +if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then + git_same_ref "$CUR_BRANCH" "refs/heads/$CUR_BRANCH" || die "Current branch $CUR_BRANCH is not a branch??" + git_same_ref "$CUR_BRANCH" "refs/remotes/$ORIGIN/$CUR_BRANCH" || die "Current branch $CUR_BRANCH seems not up to date. Git pull?" +fi NEWER_BRANCHES=() if [ "$CUR_BRANCH" != master ]; then @@ -207,13 +216,17 @@ if [ "$CUR_BRANCH" != master ]; then git show-ref --verify --quiet "refs/heads/$b" && die "unexpectedly branch $b exists" break fi - git_same_ref "$b" "refs/heads/$b" || die "branch $b is not a branch??" - git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date. Git pull?" + if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then + git_same_ref "$b" "refs/heads/$b" || die "branch $b is not a branch??" + git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date. Git pull?" + fi NEWER_BRANCHES+=("refs/heads/$b") done b=master - git_same_ref "$b" "refs/heads/$b" || die "branch $b is not a branch??" - git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date. Git pull?" + if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then + git_same_ref "$b" "refs/heads/$b" || die "branch $b is not a branch??" + git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date. Git pull?" + fi fi if [ $FIND_BACKPORTS = 1 ]; then @@ -248,6 +261,7 @@ case "$RELEASE_MODE" in git tag -s -a -m "Tag $b (development)" "$b-dev" HEAD || die "failed to tag devel version" TAGS+=("$b-dev") CLEANUP_REFS+=("refs/tags/$b-dev") + TAR_VERSION="$BUILD_TAG" ;; devel) git checkout -B "$TMP_BRANCH" @@ -260,6 +274,7 @@ case "$RELEASE_MODE" in TAGS+=("$b-dev") CLEANUP_REFS+=("refs/tags/$b-dev") BUILD_TAG="$b-dev" + TAR_VERSION="$b" ;; rc) git checkout -B "$TMP_BRANCH" @@ -273,6 +288,7 @@ case "$RELEASE_MODE" in TAGS+=("$t") CLEANUP_REFS+=("refs/tags/$t") BUILD_TAG="$t" + TAR_VERSION="$b" ;; *) die "Release mode $RELEASE_MODE not yet implemented" @@ -286,7 +302,7 @@ if [ -n "$BUILD_TAG" ]; then ./contrib/fedora/rpm/build_clean.sh -r || die "build release failed" - RELEASE_FILE="NetworkManager-${BUILD_TAG%-dev}.tar.xz" + RELEASE_FILE="NetworkManager-$TAR_VERSION.tar.xz" test -f "./$RELEASE_FILE" \ && test -f "./$RELEASE_FILE.sig" \ From 0748bd989df4e474a7c045b5f41a4eb704434c70 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 28 Jun 2020 19:16:20 +0200 Subject: [PATCH 075/199] release: cleanup temporary release-branch and avoid prompt for ftpadmin install --- contrib/fedora/rpm/release.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh index f25dfdc572..465e763f1d 100755 --- a/contrib/fedora/rpm/release.sh +++ b/contrib/fedora/rpm/release.sh @@ -243,6 +243,8 @@ BUILD_TAG= CLEANUP_CHECKOUT_BRANCH="$CUR_BRANCH" +CLEANUP_REFS+=("$TMP_BRANCH") + case "$RELEASE_MODE" in minor) git checkout -B "$TMP_BRANCH" @@ -315,7 +317,7 @@ fi if [ -n "$RELEASE_FILE" ]; then do_command rsync -va --append-verify -P "/tmp/$RELEASE_FILE" master.gnome.org: || die "failed to rsync \"/tmp/$RELEASE_FILE\"" - do_command ssh master.gnome.org ftpadmin install "$RELEASE_FILE" || die "ftpadmin install failed" + do_command ssh master.gnome.org ftpadmin install --unattended "$RELEASE_FILE" || die "ftpadmin install failed" fi git checkout -B "$CUR_BRANCH" "$TMP_BRANCH" || die "cannot checkout $CUR_BRANCH" From 53bb23b403b82bce248018deaa409a8f0aa5d1d4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:08:04 +0200 Subject: [PATCH 076/199] build: for signing use key from git's user.signingkey --- contrib/fedora/rpm/build.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/fedora/rpm/build.sh b/contrib/fedora/rpm/build.sh index b499743c4b..d84dc44729 100755 --- a/contrib/fedora/rpm/build.sh +++ b/contrib/fedora/rpm/build.sh @@ -207,7 +207,11 @@ rpmbuild --define "_topdir $TEMP" $RPM_BUILD_OPTION "$TEMPSPEC" $NM_RPMBUILD_ARG LS_EXTRA=() if [ "$SIGN_SOURCE" = 1 ]; then - gpg --output "$SOURCE.sig" --armor --detach-sig "$SOURCE" || die "ERROR: failure to sign $SOURCE" + SIGNKEY="$(git config --get user.signingkey)" + if [ "$SIGNKEY" != "" ]; then + SIGNKEY="--local-user $(printf '%q' "$SIGNKEY")" + fi + gpg $SIGNKEY --output "$SOURCE.sig" --armor --detach-sig "$SOURCE" || die "ERROR: failure to sign $SOURCE" LS_EXTRA+=("$SOURCE.sig") fi From edf70036602238f5429c527bb3a892808b3a4195 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 29 Jun 2020 09:05:52 +0200 Subject: [PATCH 077/199] version: add 1.28 macros --- libnm-core/nm-version.h | 14 ++++++++++++++ shared/nm-version-macros.h.in | 1 + 2 files changed, 15 insertions(+) diff --git a/libnm-core/nm-version.h b/libnm-core/nm-version.h index 203840376e..a43d710f9d 100644 --- a/libnm-core/nm-version.h +++ b/libnm-core/nm-version.h @@ -243,6 +243,20 @@ # define NM_AVAILABLE_IN_1_26 #endif +#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_28 +# define NM_DEPRECATED_IN_1_28 G_DEPRECATED +# define NM_DEPRECATED_IN_1_28_FOR(f) G_DEPRECATED_FOR(f) +#else +# define NM_DEPRECATED_IN_1_28 +# define NM_DEPRECATED_IN_1_28_FOR(f) +#endif + +#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_28 +# define NM_AVAILABLE_IN_1_28 G_UNAVAILABLE(1,28) +#else +# define NM_AVAILABLE_IN_1_28 +#endif + /* * Synchronous API for calling D-Bus in libnm is deprecated. See * https://developer.gnome.org/libnm/stable/usage.html#sync-api diff --git a/shared/nm-version-macros.h.in b/shared/nm-version-macros.h.in index 83da86ce10..c4d6efbcbe 100644 --- a/shared/nm-version-macros.h.in +++ b/shared/nm-version-macros.h.in @@ -65,6 +65,7 @@ #define NM_VERSION_1_22 (NM_ENCODE_VERSION (1, 22, 0)) #define NM_VERSION_1_24 (NM_ENCODE_VERSION (1, 24, 0)) #define NM_VERSION_1_26 (NM_ENCODE_VERSION (1, 26, 0)) +#define NM_VERSION_1_28 (NM_ENCODE_VERSION (1, 28, 0)) /* For releases, NM_API_VERSION is equal to NM_VERSION. * From 66651d56600d020ce8cc9f118bfca47656138f7f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 30 Jun 2020 13:13:26 +0200 Subject: [PATCH 078/199] contrib: improve release script with howto comments and help option --- contrib/fedora/rpm/release.sh | 104 ++++++++++++++++++++++++---------- 1 file changed, 74 insertions(+), 30 deletions(-) diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh index 465e763f1d..aac28c5707 100755 --- a/contrib/fedora/rpm/release.sh +++ b/contrib/fedora/rpm/release.sh @@ -1,12 +1,41 @@ #!/bin/bash +# Script for doing NetworkManager releases. # -# You need to start with a clean working directory of NetworkManager -# and all branches up to date. +# Run with --help for usage. # +# There are 5 modes: +# +# - "devel" : on master branch to tag "1.25.2-dev" +# - "rc1" : the first release candidate on "master" branch which branches off +# "nm-1-26" branch. The tag is "1.26-rc1" with version number 1.25.90. +# - "rc" : further release candidates on RC branch "nm-1-26". For example +# "1.26-rc2" with version number 1.25.91. +# - "major" : on stable branch nm-1-26 to release 1.26.0. This also merged +# the release with master branch and does a devel tag like "1.27.2-dev" +# - "minor" : on a stable branch nm-1-26 to do minor release 1.26.4 and bump +# to "1.26.5-dev". +# +# Requisites: +# +# * You need to start with a clean working directory (git clean -fdx) +# +# * Run in a "clean" environment, no unusual environment variables set. +# +# * First, ensure that you have ssh keys for master.gnome.org installed (and ssh-agent running) +# Also, ensure you have a GPG key that you want to use for signing. Also, have gpg-agent running +# and possibly configure `git config --get user.signingkey` for the proper key. +# +# * Your git repository needs a remote "origin" that points to the upstream git repository. +# +# * All your (relevant) local branches (master and nm-1-*) must be up to date with their +# remote tracking branches for origin. +# +# Run with --no-test to do the actual release. die() { - echo "FAIL: $@" + echo -n "FAIL: " + echo_color 31 "$@" exit 1 } @@ -18,11 +47,21 @@ echo_color() { echo -e -n '\033[0m' } -die_usage() { - echo "FAIL: $@" - echo +print_usage() { echo "Usage:" - echo " $0 [devel|rc1|rc|major|minor] [--no-test] [--no-find-backports] [--no-cleanup] [--allow-local-branches]" + echo " $BASH_SOURCE [devel|rc1|rc|major|minor] [--no-test] [--no-find-backports] [--no-cleanup] [--allow-local-branches]" +} + +die_help() { + print_usage + exit 0 +} + +die_usage() { + echo -n "FAIL: " + echo_color 31 "$@" + echo + print_usage exit 1 } @@ -108,32 +147,15 @@ cd "$DIR" && test -f ./src/NetworkManagerUtils.h && test -f ./contrib/fedora/rpm/build_clean.sh || die "cannot find NetworkManager base directory" -TMP="$(git status --porcelain)" || die "git status failed" -test -z "$TMP" || die "git working directory is not clean (git status --porcelain)" - -TMP="$(LANG=C git clean -ndx)" || die "git clean -ndx failed" -test -z "$TMP" || die "git working directory is not clean (git clean -ndx)" - -VERSION_ARR=( $(parse_version) ) || die "cannot detect NetworkManager version" -VERSION_STR="$(IFS=.; echo "${VERSION_ARR[*]}")" - RELEASE_MODE="" DRY_RUN=1 FIND_BACKPORTS=1 ALLOW_LOCAL_BRANCHES=0 +HELP_AND_EXIT=1 while [ "$#" -ge 1 ]; do A="$1" shift - if [ -z "$RELEASE_MODE" ]; then - case "$A" in - devel|rc1|rc|major|minor) - RELEASE_MODE="$A" - ;; - *) - ;; - esac - continue - fi + HELP_AND_EXIT=0 case "$A" in --no-test) DRY_RUN=0 @@ -150,14 +172,32 @@ while [ "$#" -ge 1 ]; do # that differ from upstream. Set this flag to override that check. ALLOW_LOCAL_BRANCHES=1 ;; + --help|-h) + die_help + ;; + devel|rc1|rc|major|minor) + [ -z "$RELEASE_MODE" ] || die_usage "duplicate release-mode" + RELEASE_MODE="$A" + ;; *) die_usage "unknown argument \"$A\"" ;; esac done +[ "$HELP_AND_EXIT" = 1 ] && die_help + [ -n "$RELEASE_MODE" ] || die_usage "specify the desired release mode" -echo "Current version before release: $VERSION_STR (do $RELEASE_MODE release)" +VERSION_ARR=( $(parse_version) ) || die "cannot detect NetworkManager version" +VERSION_STR="$(IFS=.; echo "${VERSION_ARR[*]}")" + +echo "Current version before release: $VERSION_STR (do \"$RELEASE_MODE\" release)" + +TMP="$(git status --porcelain)" || die "git status failed" +test -z "$TMP" || die "git working directory is not clean (git status --porcelain)" + +TMP="$(LANG=C git clean -ndx)" || die "git clean -ndx failed" +test -z "$TMP" || die "git working directory is not clean? (git clean -ndx)" CUR_BRANCH="$(git rev-parse --abbrev-ref HEAD)" TMP_BRANCH=release-branch @@ -203,7 +243,7 @@ git fetch || die "git fetch failed" if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then git_same_ref "$CUR_BRANCH" "refs/heads/$CUR_BRANCH" || die "Current branch $CUR_BRANCH is not a branch??" - git_same_ref "$CUR_BRANCH" "refs/remotes/$ORIGIN/$CUR_BRANCH" || die "Current branch $CUR_BRANCH seems not up to date. Git pull?" + git_same_ref "$CUR_BRANCH" "refs/remotes/$ORIGIN/$CUR_BRANCH" || die "Current branch $CUR_BRANCH seems not up to date with refs/remotes/$ORIGIN/$CUR_BRANCH. Git pull?" fi NEWER_BRANCHES=() @@ -218,17 +258,21 @@ if [ "$CUR_BRANCH" != master ]; then fi if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then git_same_ref "$b" "refs/heads/$b" || die "branch $b is not a branch??" - git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date. Git pull?" + git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date with refs/remotes/$ORIGIN/$b. Git pull?" fi NEWER_BRANCHES+=("refs/heads/$b") done b=master if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then git_same_ref "$b" "refs/heads/$b" || die "branch $b is not a branch??" - git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date. Git pull?" + git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date with refs/remotes/$ORIGIN/$b. Git pull?" fi fi +if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then + cmp <(git show origin/master:contrib/fedora/rpm/release.sh) "$BASH_SOURCE" || die "$BASH_SOURCE is not identical to \`git show origin/master:contrib/fedora/rpm/release.sh\`" +fi + if [ $FIND_BACKPORTS = 1 ]; then git show "$ORIGIN/automation:contrib/rh-utils/find-backports.sh" > ./.git/nm-find-backports.sh \ && chmod +x ./.git/nm-find-backports.sh \ From ae626ade0f5834a4b4c897a930faa8b32964b97f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 30 Jun 2020 13:53:37 +0200 Subject: [PATCH 079/199] contrib: consistency check meson.build in release script --- contrib/fedora/rpm/release.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh index aac28c5707..9dba4e995a 100755 --- a/contrib/fedora/rpm/release.sh +++ b/contrib/fedora/rpm/release.sh @@ -79,11 +79,11 @@ do_command() { } parse_version() { - local MAJ="$(sed -n '1,20 s/^m4_define(\[nm_major_version\], \[\([0-9]\+\)\])$/\1/p' configure.ac)" - local MIN="$(sed -n '1,20 s/^m4_define(\[nm_minor_version\], \[\([0-9]\+\)\])$/\1/p' configure.ac)" - local MIC="$(sed -n '1,20 s/^m4_define(\[nm_micro_version\], \[\([0-9]\+\)\])$/\1/p' configure.ac)" + local MAJ="$(sed -n '1,20 s/^m4_define(\[nm_major_version\], \[\([0-9]\+\)\])$/\1/p' ./configure.ac)" + local MIN="$(sed -n '1,20 s/^m4_define(\[nm_minor_version\], \[\([0-9]\+\)\])$/\1/p' ./configure.ac)" + local MIC="$(sed -n '1,20 s/^m4_define(\[nm_micro_version\], \[\([0-9]\+\)\])$/\1/p' ./configure.ac)" - re='^[0-9]+ [0-9]+ [0-9]+$' + re='^[0-9][1-9]* [0-9][1-9]* [0-9][1-9]*$' [[ "$MAJ $MIN $MIC" =~ $re ]] || return 1 echo "$MAJ $MIN $MIC" } @@ -193,6 +193,8 @@ VERSION_STR="$(IFS=.; echo "${VERSION_ARR[*]}")" echo "Current version before release: $VERSION_STR (do \"$RELEASE_MODE\" release)" +grep -q "version: '${VERSION_ARR[0]}.${VERSION_ARR[1]}.${VERSION_ARR[2]}'," ./meson.build || die "meson.build does not have expected version" + TMP="$(git status --porcelain)" || die "git status failed" test -z "$TMP" || die "git working directory is not clean (git status --porcelain)" @@ -204,14 +206,16 @@ TMP_BRANCH=release-branch if [ "$CUR_BRANCH" = master ]; then number_is_odd "${VERSION_ARR[1]}" || die "Unexpected version number on master. Should be an odd development version" + [ "$RELEASE_MODE" = devel -o "$RELEASE_MODE" = rc1 ] || "Unexpected branch name \"$CUR_BRANCH\" for \"$RELEASE_MODE\"" else - re='^nm-[0-9]+-[0-9]+$' + re='^nm-[0-9][1-9]*-[0-9][1-9]*$' [[ "$CUR_BRANCH" =~ $re ]] || die "Unexpected current branch $CUR_BRANCH. Should be master or nm-?-??" if number_is_odd "${VERSION_ARR[1]}"; then # we are on a release candiate branch. - [ "$RELEASE_MODE" = rc ] || "Unexpected branch name \"$CUR_BRANCH\" for \"$RELEASE_MODE\"" + [ "$RELEASE_MODE" = rc -o "$RELEASE_MODE" = major ] || "Unexpected branch name \"$CUR_BRANCH\" for \"$RELEASE_MODE\"" [ "$CUR_BRANCH" == "nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))" ] || die "Unexpected current branch $CUR_BRANCH. Should be nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))" else + [ "$RELEASE_MODE" = minor ] || "Unexpected branch name \"$CUR_BRANCH\" for \"$RELEASE_MODE\"" [ "$CUR_BRANCH" == "nm-${VERSION_ARR[0]}-${VERSION_ARR[1]}" ] || die "Unexpected current branch $CUR_BRANCH. Should be nm-${VERSION_ARR[0]}-${VERSION_ARR[1]}" fi fi From 15ec888597b453a73ed6cbcf84e6ee52f820db2e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 12:07:08 +0200 Subject: [PATCH 080/199] ifcfg-rh: use nm_gstring_add_space_delimiter() in write_bridge_setting() --- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 66 +++++++------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 2eb3cf0ce2..1626a913e6 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1511,157 +1511,135 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire u32 = nm_setting_bridge_get_hello_time (s_bridge); if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_HELLO_TIME)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "hello_time=%u", u32); } u32 = nm_setting_bridge_get_max_age (s_bridge); if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_MAX_AGE)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "max_age=%u", u32); } } u32 = nm_setting_bridge_get_ageing_time (s_bridge); if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_AGEING_TIME)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "ageing_time=%u", u32); } s = nm_setting_bridge_get_group_address (s_bridge); if (s) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "group_address=%s", s); } u32 = nm_setting_bridge_get_group_forward_mask (s_bridge); if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_GROUP_FORWARD_MASK)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "group_fwd_mask=%u", u32); } u32 = nm_setting_bridge_get_multicast_hash_max (s_bridge); if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_MULTICAST_HASH_MAX)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_hash_max=%u", u32); } u32 = nm_setting_bridge_get_multicast_last_member_count (s_bridge); if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_COUNT)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_last_member_count=%u", u32); } u64 = nm_setting_bridge_get_multicast_last_member_interval (s_bridge); if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_last_member_interval=%"G_GUINT64_FORMAT, u64); } u64 = nm_setting_bridge_get_multicast_membership_interval (s_bridge); if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_membership_interval=%"G_GUINT64_FORMAT, u64); } b = nm_setting_bridge_get_multicast_querier (s_bridge); if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERIER)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_querier=%u", (guint) b); } u64 = nm_setting_bridge_get_multicast_querier_interval (s_bridge); if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERIER_INTERVAL)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_querier_interval=%"G_GUINT64_FORMAT, u64); } u64 = nm_setting_bridge_get_multicast_query_interval (s_bridge); if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_INTERVAL)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_query_interval=%"G_GUINT64_FORMAT, u64); } u64 = nm_setting_bridge_get_multicast_query_response_interval (s_bridge); if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_query_response_interval=%"G_GUINT64_FORMAT, u64); } b = nm_setting_bridge_get_multicast_query_use_ifaddr (s_bridge); if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_query_use_ifaddr=%u", (guint) b); } b = nm_setting_bridge_get_multicast_snooping (s_bridge); if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_MULTICAST_SNOOPING)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_snooping=%u", (guint32) b); } u32 = nm_setting_bridge_get_multicast_startup_query_count (s_bridge); if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_startup_query_count=%u", u32); } u64 = nm_setting_bridge_get_multicast_startup_query_interval (s_bridge); if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_startup_query_interval=%"G_GUINT64_FORMAT, u64); } s = nm_setting_bridge_get_multicast_router (s_bridge); if (s) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_router=%s", s); } b = nm_setting_bridge_get_vlan_filtering (s_bridge); if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_VLAN_FILTERING)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "vlan_filtering=%u", (guint32) b); } u32 = nm_setting_bridge_get_vlan_default_pvid (s_bridge); if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "default_pvid=%u", u32); } s = nm_setting_bridge_get_vlan_protocol (s_bridge); if (s) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "vlan_protocol=%s", s); } b = nm_setting_bridge_get_vlan_stats_enabled (s_bridge); if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_VLAN_STATS_ENABLED)) { - if (opts->len) - g_string_append_c (opts, ' '); + nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "vlan_stats_enabled=%u", (guint) b); } From 58d193432d2fa8ef10d3e4b791d2f1de1f2051ba Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 12:11:59 +0200 Subject: [PATCH 081/199] ifcfg-rh: use guint type for handling nm_setting_bridge_get_ageing_time() return value It returns guint, not guint32. Use the appropriate type. --- src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 1626a913e6..8a63238e5e 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1481,6 +1481,7 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire NMSettingBridge *s_bridge; guint32 u32; guint64 u64; + guint u; gboolean b; const char *s; GString *opts; @@ -1522,10 +1523,10 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire } } - u32 = nm_setting_bridge_get_ageing_time (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_AGEING_TIME)) { + u = nm_setting_bridge_get_ageing_time (s_bridge); + if (u != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_AGEING_TIME)) { nm_gstring_add_space_delimiter (opts); - g_string_append_printf (opts, "ageing_time=%u", u32); + g_string_append_printf (opts, "ageing_time=%u", u); } s = nm_setting_bridge_get_group_address (s_bridge); From 13327555d6d8dd18d0ad6c450d6cb990a4ecd491 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 12:21:07 +0200 Subject: [PATCH 082/199] ifcfg-rh: hard code the defaults for bridge settings in write_bridge_setting() Code like "get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY)" looks up the default value of the GObject property. That default value is known at build type. Looking it up is an unnecessary overhead, for something that is already known. Also, the code isn't generic (meaning, it doesn't iterate of a set of properties names and treats them without explicitly naming each property). If we already name the property for which we want the default value, we can just as well name the default value. Additionally, add an assertion that what we would look up matches to what we think is the default. --- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 81 ++++++++++--------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 8a63238e5e..0fca9d0986 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1421,23 +1421,29 @@ write_team_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, return TRUE; } -static gboolean -get_setting_default_boolean (gpointer setting, const char *prop) -{ - return NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), prop)); -} +#define get_setting_default_checked_boolean(dflt, setting, prop) \ + ({ \ + const gboolean _dflt = (dflt); \ + \ + nm_assert (NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), prop)) == _dflt); \ + _dflt; \ + }) -static guint -get_setting_default_uint (gpointer setting, const char *prop) -{ - return NM_G_PARAM_SPEC_GET_DEFAULT_UINT (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), prop)); -} +#define get_setting_default_checked_uint(dflt, setting, prop) \ + ({ \ + const guint _dflt = (dflt); \ + \ + nm_assert (NM_G_PARAM_SPEC_GET_DEFAULT_UINT (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), prop)) == _dflt); \ + _dflt; \ + }) -static guint64 -get_setting_default_uint64 (gpointer setting, const char *prop) -{ - return NM_G_PARAM_SPEC_GET_DEFAULT_UINT64 (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), prop)); -} +#define get_setting_default_checked_uint64(dflt, setting, prop) \ + ({ \ + const guint64 _dflt = (dflt); \ + \ + nm_assert (NM_G_PARAM_SPEC_GET_DEFAULT_UINT64 (g_object_class_find_property (G_OBJECT_GET_CLASS (setting), prop)) == _dflt); \ + _dflt; \ + }) static gboolean write_bridge_vlans (NMSetting *setting, @@ -1505,26 +1511,26 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire svSetValueStr (ifcfg, "STP", "yes"); u32 = nm_setting_bridge_get_forward_delay (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY)) + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_FORWARD_DELAY_DEF, s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY)) svSetValueInt64 (ifcfg, "DELAY", u32); g_string_append_printf (opts, "priority=%u", nm_setting_bridge_get_priority (s_bridge)); u32 = nm_setting_bridge_get_hello_time (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_HELLO_TIME)) { + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_HELLO_TIME_DEF, s_bridge, NM_SETTING_BRIDGE_HELLO_TIME)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "hello_time=%u", u32); } u32 = nm_setting_bridge_get_max_age (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_MAX_AGE)) { + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_MAX_AGE_DEF, s_bridge, NM_SETTING_BRIDGE_MAX_AGE)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "max_age=%u", u32); } } u = nm_setting_bridge_get_ageing_time (s_bridge); - if (u != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_AGEING_TIME)) { + if (u != get_setting_default_checked_uint (NM_BRIDGE_AGEING_TIME_DEF, s_bridge, NM_SETTING_BRIDGE_AGEING_TIME)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "ageing_time=%u", u); } @@ -1536,80 +1542,79 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire } u32 = nm_setting_bridge_get_group_forward_mask (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_GROUP_FORWARD_MASK)) { + if (u32 != get_setting_default_checked_uint (0, s_bridge, NM_SETTING_BRIDGE_GROUP_FORWARD_MASK)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "group_fwd_mask=%u", u32); } - u32 = nm_setting_bridge_get_multicast_hash_max (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_MULTICAST_HASH_MAX)) { + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_MULTICAST_HASH_MAX_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_HASH_MAX)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_hash_max=%u", u32); } u32 = nm_setting_bridge_get_multicast_last_member_count (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_COUNT)) { + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_COUNT)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_last_member_count=%u", u32); } u64 = nm_setting_bridge_get_multicast_last_member_interval (s_bridge); - if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL)) { + if (u64 != get_setting_default_checked_uint64 (NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_last_member_interval=%"G_GUINT64_FORMAT, u64); } u64 = nm_setting_bridge_get_multicast_membership_interval (s_bridge); - if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL)) { + if (u64 != get_setting_default_checked_uint64 (NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_membership_interval=%"G_GUINT64_FORMAT, u64); } b = nm_setting_bridge_get_multicast_querier (s_bridge); - if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERIER)) { + if (b != get_setting_default_checked_boolean (NM_BRIDGE_MULTICAST_QUERIER_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERIER)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_querier=%u", (guint) b); } u64 = nm_setting_bridge_get_multicast_querier_interval (s_bridge); - if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERIER_INTERVAL)) { + if (u64 != get_setting_default_checked_uint64 (NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERIER_INTERVAL)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_querier_interval=%"G_GUINT64_FORMAT, u64); } u64 = nm_setting_bridge_get_multicast_query_interval (s_bridge); - if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_INTERVAL)) { + if (u64 != get_setting_default_checked_uint64 (NM_BRIDGE_MULTICAST_QUERY_INTERVAL_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_INTERVAL)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_query_interval=%"G_GUINT64_FORMAT, u64); } u64 = nm_setting_bridge_get_multicast_query_response_interval (s_bridge); - if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL)) { + if (u64 != get_setting_default_checked_uint64 (NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_query_response_interval=%"G_GUINT64_FORMAT, u64); } b = nm_setting_bridge_get_multicast_query_use_ifaddr (s_bridge); - if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR)) { + if (b != get_setting_default_checked_boolean (NM_BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_query_use_ifaddr=%u", (guint) b); } b = nm_setting_bridge_get_multicast_snooping (s_bridge); - if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_MULTICAST_SNOOPING)) { + if (b != get_setting_default_checked_boolean (NM_BRIDGE_MULTICAST_SNOOPING_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_SNOOPING)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_snooping=%u", (guint32) b); } u32 = nm_setting_bridge_get_multicast_startup_query_count (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT)) { + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_startup_query_count=%u", u32); } u64 = nm_setting_bridge_get_multicast_startup_query_interval (s_bridge); - if (u64 != get_setting_default_uint64 (s_bridge, NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL)) { + if (u64 != get_setting_default_checked_uint64 (NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_DEF, s_bridge, NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "multicast_startup_query_interval=%"G_GUINT64_FORMAT, u64); } @@ -1621,13 +1626,13 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire } b = nm_setting_bridge_get_vlan_filtering (s_bridge); - if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_VLAN_FILTERING)) { + if (b != get_setting_default_checked_boolean (FALSE, s_bridge, NM_SETTING_BRIDGE_VLAN_FILTERING)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "vlan_filtering=%u", (guint32) b); } u32 = nm_setting_bridge_get_vlan_default_pvid (s_bridge); - if (u32 != get_setting_default_uint (s_bridge, NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID)) { + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_VLAN_DEFAULT_PVID_DEF, s_bridge, NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "default_pvid=%u", u32); } @@ -1639,7 +1644,7 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire } b = nm_setting_bridge_get_vlan_stats_enabled (s_bridge); - if (b != get_setting_default_boolean (s_bridge, NM_SETTING_BRIDGE_VLAN_STATS_ENABLED)) { + if (b != get_setting_default_checked_boolean (NM_BRIDGE_VLAN_STATS_ENABLED_DEF, s_bridge, NM_SETTING_BRIDGE_VLAN_STATS_ENABLED)) { nm_gstring_add_space_delimiter (opts); g_string_append_printf (opts, "vlan_stats_enabled=%u", (guint) b); } @@ -1677,11 +1682,11 @@ write_bridge_port_setting (NMConnection *connection, shvarFile *ifcfg, GError ** string = g_string_sized_new (32); u32 = nm_setting_bridge_port_get_priority (s_port); - if (u32 != get_setting_default_uint (NM_SETTING (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY)) + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_PORT_PRIORITY_DEF, s_port, NM_SETTING_BRIDGE_PORT_PRIORITY)) g_string_append_printf (string, "priority=%u", u32); u32 = nm_setting_bridge_port_get_path_cost (s_port); - if (u32 != get_setting_default_uint (NM_SETTING (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST)) { + if (u32 != get_setting_default_checked_uint (NM_BRIDGE_PORT_PATH_COST_DEF, s_port, NM_SETTING_BRIDGE_PORT_PATH_COST)) { if (string->len) g_string_append_c (string, ' '); g_string_append_printf (string, "path_cost=%u", u32); From b9aa7ef81c2de70a3673b38ae0f36c5ad4e666ab Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 12:40:26 +0200 Subject: [PATCH 083/199] libnm/doc: clarify values for "bridge.multicast-router" Kernel (sysfs) and iproute2 only use numbers for the multicast_router option. It's confusing that we name the options differently. Anyway, that cannot be changed anymore. Clarify the meanings in the documentation. https://bugzilla.redhat.com/show_bug.cgi?id=1845608 --- clients/common/settings-docs.h.in | 2 +- libnm-core/nm-setting-bridge.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 7b891500d8..526341a401 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -128,7 +128,7 @@ #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERY_INTERVAL N_("Interval (in deciseconds) between queries sent by the bridge after the end of the startup phase.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL N_("Set the Max Response Time/Max Response Delay (in deciseconds) for IGMP/MLD queries sent by the bridge.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR N_("If enabled the bridge's own IP address is used as the source address for IGMP queries otherwise the default of 0.0.0.0 is used.") -#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_ROUTER N_("Sets bridge's multicast router. Multicast-snooping must be enabled for this option to work. Supported values are: 'auto', 'disabled', 'enabled'. If not specified the default value is 'auto'.") +#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_ROUTER N_("Sets bridge's multicast router. Multicast-snooping must be enabled for this option to work. Supported values are: 'auto', 'disabled', 'enabled' to which kernel assigns the numbers 1, 0, and 2, respectively. If not specified the default value is 'auto' (1).") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_SNOOPING N_("Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT N_("Set the number of IGMP queries to send during startup phase.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL N_("Sets the time (in deciseconds) between queries sent out at startup to determine membership information.") diff --git a/libnm-core/nm-setting-bridge.c b/libnm-core/nm-setting-bridge.c index 0595af8730..02ad4f010c 100644 --- a/libnm-core/nm-setting-bridge.c +++ b/libnm-core/nm-setting-bridge.c @@ -1973,8 +1973,9 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass) * Sets bridge's multicast router. Multicast-snooping must be enabled * for this option to work. * - * Supported values are: 'auto', 'disabled', 'enabled'. - * If not specified the default value is 'auto'. + * Supported values are: 'auto', 'disabled', 'enabled' to which kernel + * assigns the numbers 1, 0, and 2, respectively. + * If not specified the default value is 'auto' (1). **/ /* ---ifcfg-rh--- * property: multicast-router From 5423a92b0f7c6a301e2474eaaab293de82e824ce Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 21 May 2019 14:36:01 +0200 Subject: [PATCH 084/199] wifi: renew dynamic IP configuration after roaming There are some APs that require a DHCP transaction before allowing other traffic. This is meant to improve security by preventing the use of static addresses. Currently we don't renew DHCP after roaming to a new AP and this can lead to broken connectivity with APs that implement the check described above. Also, even if unlikely, the new AP could be in a different layer 3 network and so the old address could be no longer valid. Renew dynamic IP configuration after we detect the supplicant decided to roam to a new AP. Note that we only trigger a DHCP client restart; the DHCP client already implements the logic to renew the previous address and fall back to a full request in case of NAK or timeout. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/449 --- src/devices/wifi/nm-device-wifi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 2d97f9b117..cf849bcdc8 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -2564,6 +2564,15 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, new_bssid ?: "(none)", (new_ssid_s = _nm_utils_ssid_to_string (new_ssid))); + if (new_bssid) { + /* The new AP could be in a different layer 3 network + * and so the old DHCP lease could be no longer valid. + * Also, some APs (e.g. Cisco) can be configured to drop + * all traffic until DHCP completes. To support such + * cases, renew the lease when roaming to a new AP. */ + nm_device_update_dynamic_ip_setup (NM_DEVICE (self)); + } + set_current_ap (self, new_ap, TRUE); } } From 3d542b55ed989d8a719c8896650b4263bca93d6b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 30 Jun 2020 17:23:28 +0200 Subject: [PATCH 085/199] platform/tests: avoid test failures accepting route added signals /route/ip6: NMPlatformSignalAssert: ../src/platform/tests/test-route.c:331, test_ip6_route(): failure to accept signal [0,2] times: ip6-route-changed-added ifindex 0 (3 times received) --- src/platform/tests/test-route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 19debfb501..2e916e9a9b 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -328,7 +328,7 @@ test_ip6_route (void) g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, pref_src, 128, in6addr_any, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0)); - accept_signals (route_added, 0, 2); + accept_signals (route_added, 0, 3); _wait_for_ipv6_addr_non_tentative (NM_PLATFORM_GET, 200, ifindex, 1, &pref_src); From 03dc75902662eecb3deee5a3dfc77e132def26cf Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 30 Jun 2020 17:34:05 +0200 Subject: [PATCH 086/199] modem: suppress deprecated warning from libmm for MM_MODEM_CAPABILITY_LTE_ADVANCED On Ubuntu 20.10, we build against ModemManager 1.14.0 and get a compiler warning: ../src/devices/wwan/nm-modem-broadband.c: In function 'try_create_connect_properties': ../src/devices/wwan/nm-modem-broadband.c:492:2: error: 'MMModemCapabilityDeprecated' is deprecated [-Werror=deprecated-declarations] 492 | if (MODEM_CAPS_3GPP (ctx->caps)) { | ^~ Suppress it. An alternative would be to drop the flag entirely. It seems the flag was never used (and never will be used). But if that's true, there is little harm done checking it. If it's not true, we better keep checking for older versions. https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/commit/0cd76bf1c411707b6ba1c4222d791e2115ef6840 --- src/devices/wwan/nm-modem-broadband.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index f172e57fef..0929adafc4 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -20,9 +20,22 @@ #define NM_MODEM_BROADBAND_MODEM "modem" -#define MODEM_CAPS_3GPP(caps) (caps & (MM_MODEM_CAPABILITY_GSM_UMTS | \ - MM_MODEM_CAPABILITY_LTE | \ - MM_MODEM_CAPABILITY_LTE_ADVANCED)) +static gboolean +MODEM_CAPS_3GPP (MMModemCapability caps) +{ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + /* MM_MODEM_CAPABILITY_LTE_ADVANCED is marked as deprecated since ModemManager 1.14.0. + * + * The flag probably was never used, it certainly isn't used since 1.14.0. + * + * Still, just to be sure, there is no harm in checking it here. Suppress the + * warning, it should have no bad effect. + */ + return NM_FLAGS_ANY (caps, ( MM_MODEM_CAPABILITY_GSM_UMTS + | MM_MODEM_CAPABILITY_LTE + | MM_MODEM_CAPABILITY_LTE_ADVANCED)); + G_GNUC_END_IGNORE_DEPRECATIONS +} #define MODEM_CAPS_3GPP2(caps) (caps & (MM_MODEM_CAPABILITY_CDMA_EVDO)) From 1cf11ccbca12b545d6da8e963e9eeab7a2028b1e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 14 Jun 2020 23:44:53 +0200 Subject: [PATCH 087/199] libnm: fix leak in nm_utils_is_json_object() Fixes: 32f78ae6c3ba ('libnm: expose nm_utils_is_json_object() utility function') --- libnm-core/nm-utils.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index ca6b70ce20..de26ecb2e7 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -5484,7 +5484,7 @@ gboolean nm_utils_is_json_object (const char *str, GError **error) { #if WITH_JSON_VALIDATION - json_t *json; + nm_auto_decref_json json_t *json = NULL; json_error_t jerror; g_return_val_if_fail (!error || !*error, FALSE); @@ -5521,7 +5521,6 @@ nm_utils_is_json_object (const char *str, GError **error) return FALSE; } - json_decref (json); return TRUE; #else /* !WITH_JSON_VALIDATION */ g_return_val_if_fail (!error || !*error, FALSE); From 47817a576cb055552b1fe74ad48c500edea187ae Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 29 Jun 2020 17:35:21 +0200 Subject: [PATCH 088/199] ifcfg-rh: add generic shvar getter and setter for ternary variables --- src/settings/plugins/ifcfg-rh/shvar.c | 23 +++++++++++++++++++++++ src/settings/plugins/ifcfg-rh/shvar.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index cd63661d9a..a447720690 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -1214,6 +1214,20 @@ svGetValueBoolean (shvarFile *s, const char *key, int fallback) return svParseBoolean (value, fallback); } +/* svGetValueTernary: + * @s: fhe file + * @key: the name of the key to read + * + * Reads a value @key and converts it to a NMTernary value. + * + * Returns: the parsed NMTernary + */ +NMTernary +svGetValueTernary (shvarFile *s, const char *key) +{ + return svGetValueBoolean (s, key, NM_TERNARY_DEFAULT); +} + /* svGetValueInt64: * @s: fhe file * @key: the name of the key to read @@ -1428,6 +1442,15 @@ svSetValueBoolean (shvarFile *s, const char *key, gboolean value) return svSetValue (s, key, value ? "yes" : "no"); } +gboolean +svSetValueTernary (shvarFile *s, const char *key, NMTernary value) +{ + if (NM_IN_SET (value, NM_TERNARY_TRUE, NM_TERNARY_FALSE)) + return svSetValueBoolean (s, key, (gboolean) value); + else + return svUnsetValue (s, key); +} + gboolean svSetValueBoolean_cond_true (shvarFile *s, const char *key, gboolean value) { diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index 410284f8cb..852dd4c1de 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -66,6 +66,8 @@ const char **svGetKeysSorted (shvarFile *s, */ int svGetValueBoolean (shvarFile *s, const char *key, int def); +NMTernary svGetValueTernary (shvarFile *s, const char *key); + gint64 svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, gint64 max, gint64 fallback); gboolean svGetValueEnum (shvarFile *s, const char *key, @@ -84,6 +86,7 @@ gboolean svSetValueBoolean_cond_true (shvarFile *s, const char *key, gboolean va gboolean svSetValueInt64 (shvarFile *s, const char *key, gint64 value); gboolean svSetValueInt64_cond (shvarFile *s, const char *key, gboolean do_set, gint64 value); gboolean svSetValueEnum (shvarFile *s, const char *key, GType gtype, int value); +gboolean svSetValueTernary (shvarFile *s, const char *key, NMTernary value); gboolean svUnsetValue (shvarFile *s, const char *key); gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type); From dbfe219d5bf4151b93570ae575b7fc127427e5b6 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 29 Jun 2020 17:33:12 +0200 Subject: [PATCH 089/199] all: add ap-isolation property to wifi setting Add a new 'ap-isolation' property to the wifi setting, useful to prevent communication between wireless clients. --- Makefile.am | 1 + clients/common/nm-meta-setting-desc.c | 3 + clients/common/settings-docs.h.in | 1 + .../test_004.expected | 10 ++- libnm-core/nm-setting-wireless.c | 76 ++++++++++++++++++- libnm-core/nm-setting-wireless.h | 4 + libnm/libnm.ver | 5 ++ man/NetworkManager.conf.xml | 4 + src/devices/nm-device.c | 1 + .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 9 +++ .../plugins/ifcfg-rh/nms-ifcfg-rh-utils.c | 1 + .../plugins/ifcfg-rh/nms-ifcfg-rh-utils.h | 2 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 2 + .../ifcfg-Test_Write_WiFi_AP_Mode.cexpected | 19 +++++ .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 49 ++++++++++++ 15 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected diff --git a/Makefile.am b/Makefile.am index 1f90ff8fae..44f2468e08 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3075,6 +3075,7 @@ EXTRA_DIST += \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected \ + src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected \ src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected \ diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index dd5fd6f317..c98837611d 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -7492,6 +7492,9 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = { ), ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_AP_ISOLATION, + .property_type = &_pt_gobject_enum, + ), NULL }; diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 526341a401..7ef0b9f5c0 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -4,6 +4,7 @@ #define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_CHANNEL N_("Channel on which the mesh network to join is located.") #define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS N_("Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request.") #define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_SSID N_("SSID of the mesh network to join.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_AP_ISOLATION N_("Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. The increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to NM_TERNARY_FALSE (0), devices can talk to each other. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0).") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_BAND N_("802.11 frequency band of the network. One of \"a\" for 5GHz 802.11a or \"bg\" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if \"a\" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_BSSID N_("If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_CHANNEL N_("Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the \"band\" property to be set.") diff --git a/clients/tests/test-client.check-on-disk/test_004.expected b/clients/tests/test-client.check-on-disk/test_004.expected index 5ee00fc9e4..0313fce54d 100644 --- a/clients/tests/test-client.check-on-disk/test_004.expected +++ b/clients/tests/test-client.check-on-disk/test_004.expected @@ -58,12 +58,12 @@ location: clients/tests/test-client.py:test_004()/7 cmd: $NMCLI connection mod con-xx1 ipv4.addresses 192.168.77.5/24 ipv4.routes '2.3.4.5/32 192.168.77.1' ipv6.addresses 1:2:3:4::6/64 ipv6.routes 1:2:3:4:5:6::5/128 lang: C returncode: 0 -size: 4464 +size: 4517 location: clients/tests/test-client.py:test_004()/8 cmd: $NMCLI con s con-xx1 lang: C returncode: 0 -stdout: 4336 bytes +stdout: 4389 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -106,6 +106,7 @@ connection.wait-device-timeout: -1 802-11-wireless.hidden: no 802-11-wireless.powersave: 0 (default) 802-11-wireless.wake-on-wlan: 0x1 (default) +802-11-wireless.ap-isolation: -1 (default) ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -160,12 +161,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4492 +size: 4545 location: clients/tests/test-client.py:test_004()/9 cmd: $NMCLI con s con-xx1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4354 bytes +stdout: 4407 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -208,6 +209,7 @@ connection.wait-device-timeout: -1 802-11-wireless.hidden: nie 802-11-wireless.powersave: 0 (default) 802-11-wireless.wake-on-wlan: 0x1 (default) +802-11-wireless.ap-isolation: -1 (default) ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- diff --git a/libnm-core/nm-setting-wireless.c b/libnm-core/nm-setting-wireless.c index 124f9c45cf..d8a530a83c 100644 --- a/libnm-core/nm-setting-wireless.c +++ b/libnm-core/nm-setting-wireless.c @@ -43,6 +43,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingWireless, PROP_POWERSAVE, PROP_MAC_ADDRESS_RANDOMIZATION, PROP_WAKE_ON_WLAN, + PROP_AP_ISOLATION, ); typedef struct { @@ -55,13 +56,14 @@ typedef struct { char *device_mac_address; char *cloned_mac_address; char *generate_mac_address_mask; + NMSettingMacRandomization mac_address_randomization; + NMTernary ap_isolation; guint32 channel; guint32 rate; guint32 tx_power; guint32 mtu; guint32 powersave; guint32 wowl; - NMSettingMacRandomization mac_address_randomization; bool hidden:1; } NMSettingWirelessPrivate; @@ -739,6 +741,22 @@ _to_dbus_fcn_seen_bssids (const NMSettInfoSetting *sett_info, return g_variant_new_strv ((const char *const*) priv->seen_bssids->pdata, priv->seen_bssids->len); } +/** + * nm_setting_wireless_get_ap_isolation: + * @setting: the #NMSettingWireless + * + * Returns: the #NMSettingWireless:ap-isolation property of the setting + * + * Since: 1.28 + */ +NMTernary +nm_setting_wireless_get_ap_isolation (NMSettingWireless *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), NM_TERNARY_DEFAULT); + + return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->ap_isolation; +} + /*****************************************************************************/ static gboolean @@ -934,6 +952,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if ( priv->ap_isolation != NM_TERNARY_DEFAULT + && !nm_streq0 (priv->mode, NM_SETTING_WIRELESS_MODE_AP)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("AP isolation can be set only in AP mode")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_AP_ISOLATION); + return FALSE; + } + /* from here on, check for NM_SETTING_VERIFY_NORMALIZABLE conditions. */ if (priv->cloned_mac_address) { @@ -1094,6 +1123,9 @@ get_property (GObject *object, guint prop_id, case PROP_WAKE_ON_WLAN: g_value_set_uint (value, nm_setting_wireless_get_wake_on_wlan (setting)); break; + case PROP_AP_ISOLATION: + g_value_set_enum (value, priv->ap_isolation); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1203,6 +1235,9 @@ set_property (GObject *object, guint prop_id, case PROP_WAKE_ON_WLAN: priv->wowl = g_value_get_uint (value); break; + case PROP_AP_ISOLATION: + priv->ap_isolation = g_value_get_enum (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1221,6 +1256,7 @@ nm_setting_wireless_init (NMSettingWireless *setting) g_array_set_clear_func (priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item); priv->wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; + priv->ap_isolation = NM_TERNARY_DEFAULT; } /** @@ -1769,6 +1805,44 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * NMSettingWireless:ap-isolation + * + * Configures AP isolation, which prevents communication between + * wireless devices connected to this AP. This property can be set + * to a value different from %NM_TERNARY_DEFAULT only when the + * interface is configured in AP mode. + * + * If set to %NM_TERNARY_TRUE, devices are not able to communicate + * with each other. The increases security because it protects + * devices against attacks from other clients in the network. At + * the same time, it prevents devices to access resources on the + * same wireless networks as file shares, printers, etc. + * + * If set to %NM_TERNARY_FALSE, devices can talk to each other. + * + * When set to %NM_TERNARY_DEFAULT, the global default is used; in + * case the global default is unspecified it is assumed to be + * %NM_TERNARY_FALSE. + * + * Since: 1.28 + **/ + /* ---ifcfg-rh--- + * property: ap-isolation + * variable: AP_ISOLATION(+) + * values: "yes", "no" + * default: missing variable means global default + * description: Whether AP isolation is enabled + * ---end--- + */ + obj_properties[PROP_AP_ISOLATION] = + g_param_spec_enum (NM_SETTING_WIRELESS_AP_ISOLATION, "", "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); _nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_WIRELESS, diff --git a/libnm-core/nm-setting-wireless.h b/libnm-core/nm-setting-wireless.h index 093e2ef085..0ae64486f4 100644 --- a/libnm-core/nm-setting-wireless.h +++ b/libnm-core/nm-setting-wireless.h @@ -84,6 +84,7 @@ typedef enum { /*< flags >*/ #define NM_SETTING_WIRELESS_POWERSAVE "powersave" #define NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION "mac-address-randomization" #define NM_SETTING_WIRELESS_WAKE_ON_WLAN "wake-on-wlan" +#define NM_SETTING_WIRELESS_AP_ISOLATION "ap-isolation" /** * NM_SETTING_WIRELESS_MODE_ADHOC: @@ -205,6 +206,9 @@ gboolean nm_setting_wireless_ap_security_compatible (NMSettingWireless NM_AVAILABLE_IN_1_12 NMSettingWirelessWakeOnWLan nm_setting_wireless_get_wake_on_wlan (NMSettingWireless *setting); +NM_AVAILABLE_IN_1_28 +NMTernary nm_setting_wireless_get_ap_isolation (NMSettingWireless *setting); + G_END_DECLS #endif /* __NM_SETTING_WIRELESS_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 44437435d3..f4c61c20bf 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1741,3 +1741,8 @@ global: nm_setting_option_set_boolean; nm_setting_option_set_uint32; } libnm_1_24_0; + +libnm_1_28_0 { +global: + nm_setting_wireless_get_ap_isolation; +} libnm_1_26_0; diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index 76a535fb5d..5241b4d52f 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -805,6 +805,10 @@ ipv6.ip6-privacy=0 vpn.timeout If left unspecified, default value of 60 seconds is used. + + wifi.ap-isolation + If left unspecified, AP isolation is disabled. + wifi.cloned-mac-address If left unspecified, it defaults to "preserve". diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 90178b68fe..0f0829ea4a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -18330,6 +18330,7 @@ nm_device_class_init (NMDeviceClass *klass) /* Connection defaults from plugins */ NM_CON_DEFAULT_NOP ("cdma.mtu"); NM_CON_DEFAULT_NOP ("gsm.mtu"); +NM_CON_DEFAULT_NOP ("wifi.ap-isolation"); NM_CON_DEFAULT_NOP ("wifi.powersave"); NM_CON_DEFAULT_NOP ("wifi.wake-on-wlan"); NM_CON_DEFAULT_NOP ("wifi-sec.pmf"); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 1a9df92cee..9101484385 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -4021,6 +4021,7 @@ make_wireless_setting (shvarFile *ifcfg, gint64 chan = 0; NMSettingMacRandomization mac_randomization; NMSettingWirelessPowersave powersave = NM_SETTING_WIRELESS_POWERSAVE_DEFAULT; + NMTernary ternary; s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); @@ -4224,6 +4225,14 @@ make_wireless_setting (shvarFile *ifcfg, mac_randomization, NULL); + ternary = svGetValueTernary (ifcfg, "AP_ISOLATION"); + if (ternary != NM_TERNARY_DEFAULT) { + g_object_set (s_wireless, + NM_SETTING_WIRELESS_AP_ISOLATION, + ternary, + NULL); + } + return NM_SETTING (s_wireless); error: diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index d1500dbdb9..e967481500 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -805,6 +805,7 @@ nms_ifcfg_rh_utils_is_numbered_tag_impl (const char *key, const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE ("ACD_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("ADDRESS", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("AP_ISOLATION", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("ARPING_WAIT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("AUTH_RETRIES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), _KEY_TYPE ("AUTOCONNECT_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 459c5ae958..a864137ecd 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -33,7 +33,7 @@ typedef struct { NMSIfcfgKeyTypeFlags key_flags; } NMSIfcfgKeyTypeInfo; -extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[240]; +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[241]; const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info (const char *key, gssize *out_idx); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 0fca9d0986..67de73073a 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -953,6 +953,8 @@ write_wireless_setting (NMConnection *connection, break; } + svSetValueTernary (ifcfg, "AP_ISOLATION", nm_setting_wireless_get_ap_isolation (s_wireless)); + svSetValueStr (ifcfg, "TYPE", TYPE_WIRELESS); return TRUE; diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected new file mode 100644 index 0000000000..ccec2b81ae --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected @@ -0,0 +1,19 @@ +ESSID=MySSID +MODE=Ap +CHANNEL=196 +MAC_ADDRESS_RANDOMIZATION=default +AP_ISOLATION=yes +TYPE=Wireless +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write Wi-Fi AP Mode" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 40d1bb8c53..4916ceed68 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -3966,6 +3966,54 @@ test_write_wifi_band_a (void) nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); } +static void +test_write_wifi_ap_mode (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + gs_unref_bytes GBytes *ssid = NULL; + + connection = nm_simple_connection_new (); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Write Wi-Fi AP Mode", + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (), + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + + /* Wifi setting */ + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + ssid = g_bytes_new ("MySSID", NM_STRLEN ("MySSID")); + + g_object_set (s_wifi, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_MODE, "ap", + NM_SETTING_WIRELESS_BAND, "a", + NM_SETTING_WIRELESS_CHANNEL, (guint) 196, + NM_SETTING_WIRELESS_AP_ISOLATION, NM_TERNARY_TRUE, + NULL); + + nmtst_assert_connection_verifies (connection); + + _writer_new_connec_exp (connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR"/ifcfg-Test_Write_WiFi_AP_Mode.cexpected", + &testfile); + + reread = _connection_from_file (testfile, NULL, TYPE_WIRELESS, NULL); + + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + static void test_read_wifi_band_a_channel_mismatch (void) { @@ -10645,6 +10693,7 @@ int main (int argc, char **argv) g_test_add_func (TPATH "wifi/write-wpa-then-wep-with-perms", test_write_wifi_wpa_then_wep_with_perms); g_test_add_func (TPATH "wifi/write-hidden", test_write_wifi_hidden); g_test_add_func (TPATH "wifi/write-band-a", test_write_wifi_band_a); + g_test_add_func (TPATH "wifi/write-ap-mode", test_write_wifi_ap_mode); g_test_add_func (TPATH "s390/read-qeth-static", test_read_wired_qeth_static); g_test_add_func (TPATH "s390/write-qeth-dhcp", test_write_wired_qeth_dhcp); From 4db4801038fea7a63a32da0ac1b577664dbbfabb Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 29 Jun 2020 17:46:37 +0200 Subject: [PATCH 090/199] supplicant,device: support AP isolation Support setting the ApIsolate property of the supplicant interface during association and resetting it to zero during disconnection. --- src/devices/wifi/nm-device-wifi.c | 12 +++ src/supplicant/nm-supplicant-config.c | 12 +++ src/supplicant/nm-supplicant-config.h | 4 + src/supplicant/nm-supplicant-interface.c | 119 ++++++++++++++++++++--- 4 files changed, 132 insertions(+), 15 deletions(-) diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index cf849bcdc8..3872a39efb 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -2810,6 +2810,7 @@ build_supplicant_config (NMDeviceWifi *self, NMSettingWirelessSecurity *s_wireless_sec; NMSettingWirelessSecurityPmf pmf; NMSettingWirelessSecurityFils fils; + NMTernary ap_isolation; g_return_val_if_fail (priv->sup_iface, NULL); @@ -2837,6 +2838,17 @@ build_supplicant_config (NMDeviceWifi *self, goto error; } + ap_isolation = nm_setting_wireless_get_ap_isolation (s_wireless); + if (ap_isolation == NM_TERNARY_DEFAULT) { + ap_isolation = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi.ap-isolation", + NM_DEVICE (self), + NM_TERNARY_FALSE, + NM_TERNARY_TRUE, + NM_TERNARY_FALSE); + } + nm_supplicant_config_set_ap_isolation (config, ap_isolation == NM_TERNARY_TRUE); + s_wireless_sec = nm_connection_get_setting_wireless_security (connection); if (s_wireless_sec) { NMSetting8021x *s_8021x; diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index 1e09697721..2949f32f68 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -34,6 +34,7 @@ typedef struct { guint32 ap_scan; bool fast_required:1; bool dispose_has_run:1; + bool ap_isolation:1; } NMSupplicantConfigPrivate; struct _NMSupplicantConfig { @@ -1521,3 +1522,14 @@ nm_supplicant_config_add_no_security (NMSupplicantConfig *self, GError **error) return nm_supplicant_config_add_option (self, "key_mgmt", "NONE", -1, NULL, error); } +gboolean +nm_supplicant_config_get_ap_isolation (NMSupplicantConfig *self) +{ + return self->_priv.ap_isolation; +} + +void +nm_supplicant_config_set_ap_isolation (NMSupplicantConfig *self, gboolean ap_isolation) +{ + self->_priv.ap_isolation = ap_isolation; +} diff --git a/src/supplicant/nm-supplicant-config.h b/src/supplicant/nm-supplicant-config.h index e1da9a1eca..530c2cdd0b 100644 --- a/src/supplicant/nm-supplicant-config.h +++ b/src/supplicant/nm-supplicant-config.h @@ -69,4 +69,8 @@ gboolean nm_supplicant_config_add_setting_macsec (NMSupplicantConfig *self, gboolean nm_supplicant_config_enable_pmf_akm (NMSupplicantConfig *self, GError **error); + +void nm_supplicant_config_set_ap_isolation (NMSupplicantConfig *self, gboolean ap_isolation); +gboolean nm_supplicant_config_get_ap_isolation (NMSupplicantConfig *self); + #endif /* __NETWORKMANAGER_SUPPLICANT_CONFIG_H__ */ diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index 3dda0fbf25..933afb2974 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -44,6 +44,7 @@ typedef struct { gpointer user_data; guint fail_on_idle_id; guint blobs_left; + guint calls_left; struct _AddNetworkData *add_network_data; } AssocData; @@ -157,6 +158,8 @@ typedef struct _NMSupplicantInterfacePrivate { bool prop_scan_active:1; bool prop_scan_ssid:1; + bool ap_isolate_supported:1; + bool ap_isolate_needs_reset:1; } NMSupplicantInterfacePrivate; struct _NMSupplicantInterfaceClass { @@ -436,6 +439,20 @@ _remove_network (NMSupplicantInterface *self) g_variant_new ("(o)", net_path), G_VARIANT_TYPE ("()"), "remove-network"); + + if ( priv->ap_isolate_supported + && priv->ap_isolate_needs_reset) { + _dbus_connection_call_simple (self, + DBUS_INTERFACE_PROPERTIES, + "Set", + g_variant_new ("(ssv)", + NM_WPAS_DBUS_IFACE_INTERFACE, + "ApIsolate", + g_variant_new_string ("0")), + G_VARIANT_TYPE ("()"), + "reset-ap-isolation"); + } + priv->ap_isolate_needs_reset = FALSE; } /*****************************************************************************/ @@ -1868,6 +1885,9 @@ _properties_changed_main (NMSupplicantInterface *self, } } + if (nm_g_variant_lookup (properties, "ApIsolate", "&s", &v_s)) + priv->ap_isolate_supported = TRUE; + if (do_log_driver_info) { _LOGD ("supplicant interface for ifindex=%d, ifname=%s%s%s, driver=%s%s%s (requested %s)", priv->ifindex, @@ -2227,27 +2247,13 @@ assoc_add_network_cb (GObject *source, GAsyncResult *result, gpointer user_data) } static void -assoc_set_ap_scan_cb (GVariant *ret, GError *error, gpointer user_data) +add_network (NMSupplicantInterface *self) { - NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; AddNetworkData *add_network_data; - if (nm_utils_error_is_cancelled (error)) - return; - - self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (error) { - assoc_return (self, error, "failure to set AP scan mode"); - return; - } - - _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: interface ap_scan set to %d", - NM_HASH_OBFUSCATE_PTR (priv->assoc_data), - nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)); - /* the association does not keep @self alive. We want to be able to remove * the network again, even if @self is already gone. Hence, track the data * separately. @@ -2276,6 +2282,62 @@ assoc_set_ap_scan_cb (GVariant *ret, GError *error, gpointer user_data) add_network_data); } +static void +assoc_set_ap_isolation (GVariant *ret, GError *error, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + gboolean value; + + if (nm_utils_error_is_cancelled (error)) + return; + + self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (error) { + assoc_return (self, error, "failure to set AP isolation"); + return; + } + + value = nm_supplicant_config_get_ap_isolation (priv->assoc_data->cfg); + _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: interface AP isolation set to %d", + NM_HASH_OBFUSCATE_PTR (priv->assoc_data), + value); + + priv->ap_isolate_needs_reset = value; + + nm_assert (priv->assoc_data->calls_left > 0); + if (--priv->assoc_data->calls_left == 0) + add_network (self); +} + +static void +assoc_set_ap_scan_cb (GVariant *ret, GError *error, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + + if (nm_utils_error_is_cancelled (error)) + return; + + self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (error) { + assoc_return (self, error, "failure to set AP scan mode"); + return; + } + + _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: interface ap_scan set to %d", + NM_HASH_OBFUSCATE_PTR (priv->assoc_data), + nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)); + + nm_assert (priv->assoc_data->calls_left > 0); + if (--priv->assoc_data->calls_left == 0) + add_network (self); +} + static gboolean assoc_fail_on_idle_cb (gpointer user_data) { @@ -2312,6 +2374,7 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, { NMSupplicantInterfacePrivate *priv; AssocData *assoc_data; + gboolean ap_isolation; g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); g_return_if_fail (NM_IS_SUPPLICANT_CONFIG (cfg)); @@ -2343,6 +2406,7 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, } assoc_data->cancellable = g_cancellable_new(); + assoc_data->calls_left++; nm_dbus_connection_call_set (priv->dbus_connection, priv->name_owner->str, priv->object_path->str, @@ -2353,6 +2417,31 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, assoc_data->cancellable, assoc_set_ap_scan_cb, self); + + ap_isolation = nm_supplicant_config_get_ap_isolation (priv->assoc_data->cfg); + if (!priv->ap_isolate_supported) { + if (ap_isolation) { + _LOGW ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: requested AP isolation but the supplicant doesn't support it", + NM_HASH_OBFUSCATE_PTR (assoc_data)); + } + } else { + assoc_data->calls_left++; + /* It would be smarter to change the property only when necessary. + * However, wpa_supplicant doesn't send the PropertiesChanged + * signal for ApIsolate, and so to know the current value we would + * need first a Get call. It seems simpler to just set the value + * we want. */ + nm_dbus_connection_call_set (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + "ApIsolate", + g_variant_new_string (ap_isolation ? "1" : "0"), + DBUS_TIMEOUT_MSEC, + assoc_data->cancellable, + assoc_set_ap_isolation, + self); + } } /*****************************************************************************/ From 3b896cc64237262055cc44abb7e914c905e33ecf Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 2 Jul 2020 16:28:37 +0200 Subject: [PATCH 091/199] ndisc/tests: make assertion checks a macro and not a function in test-ndisc-fake By having it a function, the assertion failure does not show the line number of the origin. Make them a macro, so that we see where exactly it failed. --- src/ndisc/tests/test-ndisc-fake.c | 75 ++++++++++++++++--------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/ndisc/tests/test-ndisc-fake.c b/src/ndisc/tests/test-ndisc-fake.c index 91fe9802d7..1054bf0648 100644 --- a/src/ndisc/tests/test-ndisc-fake.c +++ b/src/ndisc/tests/test-ndisc-fake.c @@ -47,44 +47,45 @@ match_gateway (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts g_assert_cmpint (gw->preference, ==, pref); } -static void -match_address (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt, guint32 preferred) -{ - const NMNDiscAddress *a; - char buf[INET6_ADDRSTRLEN]; +#define match_address(rdata, idx, addr, ts, lt, pref) \ + G_STMT_START { \ + const NMNDiscData *_rdata = (rdata); \ + guint _idx = (idx); \ + const NMNDiscAddress *_a; \ + \ + g_assert (_rdata); \ + g_assert_cmpint (_idx, <, _rdata->addresses_n); \ + g_assert (_rdata->addresses); \ + \ + _a = &_rdata->addresses[_idx]; \ + \ + nmtst_assert_ip6_address (&_a->address, (addr)); \ + g_assert_cmpint (_a->timestamp, ==, (ts)); \ + g_assert_cmpint (_a->lifetime, ==, (lt)); \ + g_assert_cmpint (_a->preferred, ==, (pref)); \ + } G_STMT_END - g_assert (rdata); - g_assert_cmpint (idx, <, rdata->addresses_n); - g_assert (rdata->addresses); - - a = &rdata->addresses[idx]; - - g_assert_cmpstr (inet_ntop (AF_INET6, &a->address, buf, sizeof (buf)), ==, addr); - g_assert_cmpint (a->timestamp, ==, ts); - g_assert_cmpint (a->lifetime, ==, lt); - g_assert_cmpint (a->preferred, ==, preferred); -} - -static void -match_route (const NMNDiscData *rdata, guint idx, const char *nw, int plen, const char *gw, guint32 ts, guint32 lt, NMIcmpv6RouterPref pref) -{ - const NMNDiscRoute *route; - char buf[INET6_ADDRSTRLEN]; - - g_assert (rdata); - g_assert_cmpint (idx, <, rdata->routes_n); - g_assert (rdata->routes); - g_assert (plen > 0 && plen <= 128); - - route = &rdata->routes[idx]; - - g_assert_cmpstr (inet_ntop (AF_INET6, &route->network, buf, sizeof (buf)), ==, nw); - g_assert_cmpint ((int) route->plen, ==, plen); - g_assert_cmpstr (inet_ntop (AF_INET6, &route->gateway, buf, sizeof (buf)), ==, gw); - g_assert_cmpint (route->timestamp, ==, ts); - g_assert_cmpint (route->lifetime, ==, lt); - g_assert_cmpint (route->preference, ==, pref); -} +#define match_route(rdata, idx, nw, pl, gw, ts, lt, pref) \ + G_STMT_START { \ + const NMNDiscData *_rdata = (rdata); \ + guint _idx = (idx); \ + const NMNDiscRoute *_r; \ + int _plen = (pl); \ + \ + g_assert (_rdata); \ + g_assert_cmpint (_idx, <, _rdata->routes_n); \ + g_assert (_rdata->routes); \ + g_assert (_plen > 0 && _plen <= 128); \ + \ + _r = &_rdata->routes[idx]; \ + \ + nmtst_assert_ip6_address (&_r->network, (nw)); \ + g_assert_cmpint ((int) _r->plen, ==, _plen); \ + nmtst_assert_ip6_address (&_r->gateway, (gw)); \ + g_assert_cmpint (_r->timestamp, ==, (ts)); \ + g_assert_cmpint (_r->lifetime, ==, (lt)); \ + g_assert_cmpint (_r->preference, ==, (pref)); \ + } G_STMT_END static void match_dns_server (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts, guint32 lt) From 1acd64b7a2663a91484f30d87e8c8928bca60fe9 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 2 Jul 2020 17:37:12 +0200 Subject: [PATCH 092/199] examples: run python black on "examples/python/gi/nm-wg-set" black by default only considers files that have a ".py" extension. --- examples/python/gi/nm-wg-set | 279 +++++++++++++++++++++++------------ 1 file changed, 185 insertions(+), 94 deletions(-) diff --git a/examples/python/gi/nm-wg-set b/examples/python/gi/nm-wg-set index 1f5279ee69..4f074605c1 100755 --- a/examples/python/gi/nm-wg-set +++ b/examples/python/gi/nm-wg-set @@ -61,23 +61,32 @@ import sys import os import gi -gi.require_version('NM', '1.0') + +gi.require_version("NM", "1.0") from gi.repository import NM + class MyError(Exception): pass + def pr(v): import pprint + pprint.pprint(v, indent=4, depth=5, width=60) + ############################################################################### + def connection_is_wireguard(conn): s_con = conn.get_setting(NM.SettingConnection) - return s_con \ - and s_con.get_connection_type() == NM.SETTING_WIREGUARD_SETTING_NAME \ - and conn.get_setting(NM.SettingWireGuard) + return ( + s_con + and s_con.get_connection_type() == NM.SETTING_WIREGUARD_SETTING_NAME + and conn.get_setting(NM.SettingWireGuard) + ) + def connection_to_str(conn): if connection_is_wireguard(conn): @@ -85,52 +94,57 @@ def connection_to_str(conn): if iface: extra = ', interface: "%s"' % (iface) else: - extra = '' + extra = "" else: - extra = ', type: %s' % (conn.get_setting(NM.SettingConnection).get_connection_type()) + extra = ", type: %s" % ( + conn.get_setting(NM.SettingConnection).get_connection_type() + ) return '"%s" (%s%s)' % (conn.get_id(), conn.get_uuid(), extra) + def connections_wg(connections): l = list([c for c in connections if connection_is_wireguard(c)]) - l.sort(key = connection_to_str) + l.sort(key=connection_to_str) return l + def connections_find(connections, con_spec, con_id): connections = list(sorted(connections, key=connection_to_str)) l = [] - if con_spec in [None, 'id']: + if con_spec in [None, "id"]: for c in connections: if con_id == c.get_id(): if c not in l: l.append(c) - if con_spec in [None, 'interface']: + if con_spec in [None, "interface"]: for c in connections: s_con = c.get_setting(NM.SettingConnection) - if s_con \ - and con_id == s_con.get_interface_name(): + if s_con and con_id == s_con.get_interface_name(): if c not in l: l.append(c) - if con_spec in [None, 'uuid']: + if con_spec in [None, "uuid"]: for c in connections: if con_id == c.get_uuid(): if c not in l: l.append(c) - l.sort(key = connection_to_str) + l.sort(key=connection_to_str) return l def print_hint(nm_client): - print('Maybe you want to create a profile first with') - print(' nmcli connection add type wireguard ifname wg0 $MORE_ARGS') + print("Maybe you want to create a profile first with") + print(" nmcli connection add type wireguard ifname wg0 $MORE_ARGS") connections = connections_wg(nm_client.get_connections()) if connections: - print('Or edit one of the following WireGuard profiles:') + print("Or edit one of the following WireGuard profiles:") for c in connections: - print (' - %s' % (connection_to_str(c))) + print(" - %s" % (connection_to_str(c))) + ############################################################################### + def argv_get_one(argv, idx, type_ctor=None, topic=None): if topic is not None: @@ -146,7 +160,7 @@ def argv_get_one(argv, idx, type_ctor=None, topic=None): try: v = argv[idx] except: - raise MyError('missing argument') + raise MyError("missing argument") if type_ctor is not None: try: v = type_ctor(v) @@ -154,16 +168,18 @@ def argv_get_one(argv, idx, type_ctor=None, topic=None): raise MyError('invalid argument "%s" (%s)' % (v, e.message)) return v + ############################################################################### + def arg_parse_secret_flags(arg): try: f = arg.strip() n = { - 'none': NM.SettingSecretFlags.NONE, - 'not-saved': NM.SettingSecretFlags.NOT_SAVED, - 'not-required': NM.SettingSecretFlags.NOT_REQUIRED, - 'agent-owned': NM.SettingSecretFlags.AGENT_OWNED, + "none": NM.SettingSecretFlags.NONE, + "not-saved": NM.SettingSecretFlags.NOT_SAVED, + "not-required": NM.SettingSecretFlags.NOT_REQUIRED, + "agent-owned": NM.SettingSecretFlags.AGENT_OWNED, }.get(f) if n is not None: return n @@ -171,7 +187,8 @@ def arg_parse_secret_flags(arg): except Exception as e: raise MyError('invalid secret flags "%s"' % (arg)) -def _arg_parse_int(arg, vmin, vmax, key, base = 0): + +def _arg_parse_int(arg, vmin, vmax, key, base=0): try: v = int(arg, base) if v >= vmin and vmax <= 0xFFFFFFFF: @@ -180,18 +197,22 @@ def _arg_parse_int(arg, vmin, vmax, key, base = 0): raise MyError('invalid %s "%s"' % (key, arg)) raise MyError("%s out of range" % (key)) + def arg_parse_listen_port(arg): return _arg_parse_int(arg, 0, 0xFFFF, "listen-port") + def arg_parse_fwmark(arg): - return _arg_parse_int(arg, 0, 0xFFFFFFFF, "fwmark", base = 0) + return _arg_parse_int(arg, 0, 0xFFFFFFFF, "fwmark", base=0) + def arg_parse_persistent_keep_alive(arg): return _arg_parse_int(arg, 0, 0xFFFFFFFF, "persistent-keepalive") + def arg_parse_allowed_ips(arg): - l = [s.strip() for s in arg.strip().split(',')] - l = [s for s in l if s != ''] + l = [s.strip() for s in arg.strip().split(",")] + l = [s for s in l if s != ""] l = list(l) # use a peer to parse and validate the allowed-ips. peer = NM.WireGuardPeer() @@ -200,40 +221,47 @@ def arg_parse_allowed_ips(arg): raise MyError('invalid allowed-ip "%s"' % (aip)) return l + ############################################################################### + def secret_flags_to_string(flags): nick = { - NM.SettingSecretFlags.NONE: 'none', - NM.SettingSecretFlags.NOT_SAVED: 'not-saved', - NM.SettingSecretFlags.NOT_REQUIRED: 'not-required', - NM.SettingSecretFlags.AGENT_OWNED: 'agent-owned', - }.get(flags) + NM.SettingSecretFlags.NONE: "none", + NM.SettingSecretFlags.NOT_SAVED: "not-saved", + NM.SettingSecretFlags.NOT_REQUIRED: "not-required", + NM.SettingSecretFlags.AGENT_OWNED: "agent-owned", + }.get(flags) num = str(int(flags)) if nick is None: return num - return '%s (%s)' % (num, nick) + return "%s (%s)" % (num, nick) + def secret_to_string(secret): - if os.environ.get('WG_HIDE_KEYS', '') != 'never': - return '(hidden)' + if os.environ.get("WG_HIDE_KEYS", "") != "never": + return "(hidden)" if not secret: - return '' + return "" return secret + def val_to_str(val): if val == NM.Ternary.DEFAULT: - return 'default' + return "default" if val == NM.Ternary.TRUE: - return 'true' + return "true" if val == NM.Ternary.FALSE: - return 'false' + return "false" return repr(val) + ############################################################################### + def wg_read_private_key(privkey_file): import base64 + try: with open(privkey_file, "r") as f: data = f.read() @@ -244,17 +272,20 @@ def wg_read_private_key(privkey_file): except Exception as e: raise MyError('failed to read private key "%s": %s' % (privkey_file, e.message)) -def wg_peer_is_valid(peer, msg = None): + +def wg_peer_is_valid(peer, msg=None): try: peer.is_valid(True, True) except gi.repository.GLib.Error as e: if msg is None: - raise MyError('%s' % (e.message)) + raise MyError("%s" % (e.message)) else: - raise MyError('%s' % (msg)) + raise MyError("%s" % (msg)) + ############################################################################### + def do_get(nm_client, connection): s_con = conn.get_setting(NM.SettingConnection) s_wg = conn.get_setting(NM.SettingWireGuard) @@ -262,24 +293,55 @@ def do_get(nm_client, connection): # Fetching secrets is not implemented. For now show them all as # . - print('interface: %s' % (s_con.get_interface_name())) - print('uuid: %s' % (conn.get_uuid())) - print('id: %s' % (conn.get_id())) - print('private-key: %s' % (secret_to_string(s_wg.get_private_key()))) - print('private-key-flags: %s' % (secret_flags_to_string(s_wg.get_private_key_flags()))) - print('listen-port: %s' % (s_wg.get_listen_port())) - print('fwmark: 0x%x' % (s_wg.get_fwmark())) - print('peer-routes: %s' % (val_to_str(s_wg.get_peer_routes()))) - print('ip4-auto-default-route: %s' % (val_to_str(s_wg.get_ip4_auto_default_route()))) - print('ip6-auto-default-route: %s' % (val_to_str(s_wg.get_ip6_auto_default_route()))) + print("interface: %s" % (s_con.get_interface_name())) + print("uuid: %s" % (conn.get_uuid())) + print("id: %s" % (conn.get_id())) + print( + "private-key: %s" % (secret_to_string(s_wg.get_private_key())) + ) + print( + "private-key-flags: %s" + % (secret_flags_to_string(s_wg.get_private_key_flags())) + ) + print("listen-port: %s" % (s_wg.get_listen_port())) + print("fwmark: 0x%x" % (s_wg.get_fwmark())) + print("peer-routes: %s" % (val_to_str(s_wg.get_peer_routes()))) + print( + "ip4-auto-default-route: %s" + % (val_to_str(s_wg.get_ip4_auto_default_route())) + ) + print( + "ip6-auto-default-route: %s" + % (val_to_str(s_wg.get_ip6_auto_default_route())) + ) for i in range(s_wg.get_peers_len()): peer = s_wg.get_peer(i) - print('peer[%d].public-key: %s' % (i, peer.get_public_key())) - print('peer[%d].preshared-key: %s' % (i, secret_to_string(peer.get_preshared_key()))) - print('peer[%d].preshared-key-flags: %s' % (i, secret_flags_to_string(peer.get_preshared_key_flags()))) - print('peer[%d].endpoint: %s' % (i, peer.get_endpoint() if peer.get_endpoint() else '')) - print('peer[%d].persistent-keepalive: %s' % (i, peer.get_persistent_keepalive())) - print('peer[%d].allowed-ips: %s' % (i, ','.join([peer.get_allowed_ip(j) for j in range(peer.get_allowed_ips_len())]))) + print("peer[%d].public-key: %s" % (i, peer.get_public_key())) + print( + "peer[%d].preshared-key: %s" + % (i, secret_to_string(peer.get_preshared_key())) + ) + print( + "peer[%d].preshared-key-flags: %s" + % (i, secret_flags_to_string(peer.get_preshared_key_flags())) + ) + print( + "peer[%d].endpoint: %s" + % (i, peer.get_endpoint() if peer.get_endpoint() else "") + ) + print( + "peer[%d].persistent-keepalive: %s" % (i, peer.get_persistent_keepalive()) + ) + print( + "peer[%d].allowed-ips: %s" + % ( + i, + ",".join( + [peer.get_allowed_ip(j) for j in range(peer.get_allowed_ips_len())] + ), + ) + ) + def do_set(nm_client, conn, argv): s_wg = conn.get_setting(NM.SettingWireGuard) @@ -291,9 +353,7 @@ def do_set(nm_client, conn, argv): try: idx = 0 while True: - if peer \ - and ( idx >= len(argv) \ - or argv[idx] == 'peer'): + if peer and (idx >= len(argv) or argv[idx] == "peer"): if peer_remove: pp_peer, pp_idx = s_wg.get_peer_by_public_key(peer.get_public_key()) if pp_peer: @@ -312,29 +372,40 @@ def do_set(nm_client, conn, argv): peer_secret_flags = None if idx >= len(argv): - break; + break - if not peer and argv[idx] == 'private-key': + if not peer and argv[idx] == "private-key": key = argv_get_one(argv, idx + 1, None, idx) - if key == '': + if key == "": s_wg.set_property(NM.SETTING_WIREGUARD_PRIVATE_KEY, None) else: - s_wg.set_property(NM.SETTING_WIREGUARD_PRIVATE_KEY, wg_read_private_key(key)) + s_wg.set_property( + NM.SETTING_WIREGUARD_PRIVATE_KEY, wg_read_private_key(key) + ) idx += 2 continue - if not peer and argv[idx] == 'private-key-flags': - s_wg.set_property(NM.SETTING_WIREGUARD_PRIVATE_KEY_FLAGS, argv_get_one(argv, idx + 1, arg_parse_secret_flags, idx)) + if not peer and argv[idx] == "private-key-flags": + s_wg.set_property( + NM.SETTING_WIREGUARD_PRIVATE_KEY_FLAGS, + argv_get_one(argv, idx + 1, arg_parse_secret_flags, idx), + ) idx += 2 continue - if not peer and argv[idx] == 'listen-port': - s_wg.set_property(NM.SETTING_WIREGUARD_LISTEN_PORT, argv_get_one(argv, idx + 1, arg_parse_listen_port, idx)) + if not peer and argv[idx] == "listen-port": + s_wg.set_property( + NM.SETTING_WIREGUARD_LISTEN_PORT, + argv_get_one(argv, idx + 1, arg_parse_listen_port, idx), + ) idx += 2 continue - if not peer and argv[idx] == 'fwmark': - s_wg.set_property(NM.SETTING_WIREGUARD_FWMARK, argv_get_one(argv, idx + 1, arg_parse_fwmark, idx)) + if not peer and argv[idx] == "fwmark": + s_wg.set_property( + NM.SETTING_WIREGUARD_FWMARK, + argv_get_one(argv, idx + 1, arg_parse_fwmark, idx), + ) idx += 2 continue - if argv[idx] == 'peer': + if argv[idx] == "peer": public_key = argv_get_one(argv, idx + 1, None, idx) peer, peer_idx = s_wg.get_peer_by_public_key(public_key) if peer: @@ -347,13 +418,13 @@ def do_set(nm_client, conn, argv): peer_remove = False idx += 2 continue - if peer and argv[idx] == 'remove': + if peer and argv[idx] == "remove": peer_remove = True idx += 1 continue - if peer and argv[idx] == 'preshared-key': + if peer and argv[idx] == "preshared-key": psk = argv_get_one(argv, idx + 1, None, idx) - if psk == '': + if psk == "": peer.set_preshared_key(None, True) if peer_secret_flags is not None: peer_secret_flags = NM.SettingSecretFlags.NOT_REQUIRED @@ -363,20 +434,26 @@ def do_set(nm_client, conn, argv): peer_secret_flags = NM.SettingSecretFlags.NONE idx += 2 continue - if peer and argv[idx] == 'preshared-key-flags': - peer_secret_flags = argv_get_one(argv, idx + 1, arg_parse_secret_flags, idx) + if peer and argv[idx] == "preshared-key-flags": + peer_secret_flags = argv_get_one( + argv, idx + 1, arg_parse_secret_flags, idx + ) idx += 2 continue - if peer and argv[idx] == 'endpoint': + if peer and argv[idx] == "endpoint": peer.set_endpoint(argv_get_one(argv, idx + 1, None, idx), True) idx += 2 continue - if peer and argv[idx] == 'persistent-keepalive': - peer.set_persistent_keepalive(argv_get_one(argv, idx + 1, arg_parse_persistent_keep_alive, idx)) + if peer and argv[idx] == "persistent-keepalive": + peer.set_persistent_keepalive( + argv_get_one(argv, idx + 1, arg_parse_persistent_keep_alive, idx) + ) idx += 2 continue - if peer and argv[idx] == 'allowed-ips': - allowed_ips = list(argv_get_one(argv, idx + 1, arg_parse_allowed_ips, idx)) + if peer and argv[idx] == "allowed-ips": + allowed_ips = list( + argv_get_one(argv, idx + 1, arg_parse_allowed_ips, idx) + ) peer.clear_allowed_ips() for aip in allowed_ips: peer.append_allowed_ip(aip, False) @@ -386,21 +463,22 @@ def do_set(nm_client, conn, argv): raise MyError('invalid argument "%s"' % (argv[idx])) except MyError as e: - print('Error: %s' % (e.message)) + print("Error: %s" % (e.message)) sys.exit(1) try: conn.commit_changes(True, None) except Exception as e: - print('failure to commit connection: %s' % (e)) + print("failure to commit connection: %s" % (e)) sys.exit(1) - print('Success') + print("Success") sys.exit(0) + ############################################################################### -if __name__ == '__main__': +if __name__ == "__main__": nm_client = NM.Client.new(None) @@ -409,13 +487,17 @@ if __name__ == '__main__': con_spec = None if len(argv) >= 1: - if argv[0] in [ 'id', 'uuid', 'interface' ]: + if argv[0] in ["id", "uuid", "interface"]: con_spec = argv[0] del argv[0] if len(argv) < 1: - print('Requires an existing NetworkManager connection profile as first argument') - print('Select it based on the connection ID, UUID, or interface-name (optionally qualify the selection with [id|uuid|interface])') + print( + "Requires an existing NetworkManager connection profile as first argument" + ) + print( + "Select it based on the connection ID, UUID, or interface-name (optionally qualify the selection with [id|uuid|interface])" + ) print_hint(nm_client) sys.exit(1) con_id = argv[0] @@ -423,19 +505,29 @@ if __name__ == '__main__': connections = connections_find(nm_client.get_connections(), con_spec, con_id) if len(connections) == 0: - print('No matching connection %s\"%s\" found.' % ((con_spec+' ' if con_spec else ''), con_id)) + print( + 'No matching connection %s"%s" found.' + % ((con_spec + " " if con_spec else ""), con_id) + ) print_hint(nm_client) sys.exit(1) if len(connections) > 1: - print("Connection %s\"%s\" is not unique (%s)" % ((con_spec+' ' if con_spec else ''), con_id, ', '.join(['['+connection_to_str(c)+']' for c in connections]))) + print( + 'Connection %s"%s" is not unique (%s)' + % ( + (con_spec + " " if con_spec else ""), + con_id, + ", ".join(["[" + connection_to_str(c) + "]" for c in connections]), + ) + ) if not con_spec: - print('Maybe qualify the name with [id|uuid|interface]?') + print("Maybe qualify the name with [id|uuid|interface]?") sys.exit(1) conn = connections[0] if not connection_is_wireguard(conn): - print('Connection %s is not a WireGuard profile' % (connection_to_str(conn))) - print('See available profiles with `nmcli connection show`') + print("Connection %s is not a WireGuard profile" % (connection_to_str(conn))) + print("See available profiles with `nmcli connection show`") sys.exit(1) try: @@ -449,4 +541,3 @@ if __name__ == '__main__': do_get(nm_client, conn) else: do_set(nm_client, conn, argv) - From 38b7556c6566fb580063b8c7dd3a5723caae5961 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 2 Jul 2020 17:44:21 +0200 Subject: [PATCH 093/199] build: check "examples/python/gi/nm-wg-set" with black --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 44f2468e08..4db3d51ee3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5241,7 +5241,7 @@ include Makefile.examples if WITH_PYTHON_BLACK check-python-black: - test "$$NMTST_SKIP_PYTHON_BLACK" != 1 && $(BLACK) --check $(top_srcdir) + test "$$NMTST_SKIP_PYTHON_BLACK" != 1 && $(BLACK) --check $(top_srcdir) $(top_srcdir)/examples/python/gi/nm-wg-set check_local += check-python-black endif From 9fa59c156bd1f5e281ee65ab954adf32628ea5f5 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 2 Jul 2020 17:44:29 +0200 Subject: [PATCH 094/199] gitlab-ci: check "examples/python/gi/nm-wg-set" with black --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 389da67218..253bf7593b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -79,7 +79,7 @@ checkpatch: script: - date '+%Y%m%d-%H%M%S'; dnf install -y git black - date '+%Y%m%d-%H%M%S'; NM_CHECKPATCH_FETCH_UPSTREAM=1 contrib/scripts/checkpatch-feature-branch.sh 2>&1 | tee checkpatch-out.txt - - date '+%Y%m%d-%H%M%S'; black --check . + - date '+%Y%m%d-%H%M%S'; black --check . examples/python/gi/nm-wg-set allow_failure: true artifacts: when: on_failure From 2c50438987527a30d99c07601b8f1d1c9557cdaf Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 2 Jul 2020 17:38:10 +0200 Subject: [PATCH 095/199] device: restart DHCP only for devices that are active or activating do_sleep_wake() tries to restart DHCP for all devices, even ones that are disconnecting. When a device is disconnecting, it still has a DHCP client instance but we shouldn't restart it because it makes no sense; and especially, the device could be already removed. https://bugzilla.redhat.com/show_bug.cgi?id=1852612 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/561 --- src/devices/nm-device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0f0829ea4a..65262cda25 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3822,6 +3822,10 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); + if ( priv->state < NM_DEVICE_STATE_IP_CONFIG + || priv->state > NM_DEVICE_STATE_ACTIVATED) + return; + g_hash_table_remove_all (priv->ip6_saved_properties); if (priv->dhcp_data_4.client) { From 8209095ee1c462c69d5203cdef11c61bfb0aa546 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 2 Jul 2020 23:14:01 +0200 Subject: [PATCH 096/199] ndisc/tests: relax the assertion in "test-ndisc-fake.c" test:ERROR:../src/ndisc/tests/test-ndisc-fake.c:373:test_preference_changed_cb: assertion failed (_a->timestamp == (data->timestamp1 + 3)): (9 == 10) --- src/ndisc/tests/test-ndisc-fake.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ndisc/tests/test-ndisc-fake.c b/src/ndisc/tests/test-ndisc-fake.c index 1054bf0648..f02e5d3ff7 100644 --- a/src/ndisc/tests/test-ndisc-fake.c +++ b/src/ndisc/tests/test-ndisc-fake.c @@ -52,6 +52,7 @@ match_gateway (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts const NMNDiscData *_rdata = (rdata); \ guint _idx = (idx); \ const NMNDiscAddress *_a; \ + guint _ts = (ts); \ \ g_assert (_rdata); \ g_assert_cmpint (_idx, <, _rdata->addresses_n); \ @@ -60,7 +61,8 @@ match_gateway (const NMNDiscData *rdata, guint idx, const char *addr, guint32 ts _a = &_rdata->addresses[_idx]; \ \ nmtst_assert_ip6_address (&_a->address, (addr)); \ - g_assert_cmpint (_a->timestamp, ==, (ts)); \ + g_assert_cmpint (_a->timestamp, >=, _ts); \ + g_assert_cmpint (_a->timestamp, <=, _ts + 1); \ g_assert_cmpint (_a->lifetime, ==, (lt)); \ g_assert_cmpint (_a->preferred, ==, (pref)); \ } G_STMT_END @@ -370,7 +372,7 @@ test_preference_changed_cb (NMNDisc *ndisc, const NMNDiscData *rdata, guint chan match_gateway (rdata, 0, "fe80::1", data->timestamp1 + 2, 10, NM_ICMPV6_ROUTER_PREF_HIGH); match_gateway (rdata, 1, "fe80::2", data->timestamp1 + 1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM); g_assert_cmpint (rdata->addresses_n, ==, 2); - match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1 + 3, 9, 9); + match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1 + 2, 9, 9); match_address (rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10); g_assert_cmpint (rdata->routes_n, ==, 2); match_route (rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1 + 2, 10, 15); From 460afe6d502f2a8f158739c176302fd7fa072913 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:18 +0200 Subject: [PATCH 097/199] cloud-setup: fix allocating buffer for GetConfigMetadataMac in _get_config_metadata_ready_check() It's not a severe issue, because the GetConfigMetadataData struct is larger than GetConfigMetadataMac. Fixes: 69f048bf0ca3 ('cloud-setup: add tool for automatic IP configuration in cloud') --- clients/cloud-setup/nmcs-provider-ec2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c index c8db31f97f..3b5f6d36a8 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ b/clients/cloud-setup/nmcs-provider-ec2.c @@ -487,7 +487,7 @@ _get_config_metadata_ready_check (long response_code, if (!response_parsed) response_parsed = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); - mac_data = g_malloc (sizeof (GetConfigMetadataData) + 1 + p_start_l); + mac_data = g_malloc (sizeof (GetConfigMetadataMac) + 1 + p_start_l); mac_data->iface_idx = iface_idx_counter++; memcpy (mac_data->path, p_start, p_start_l); mac_data->path[p_start_l] = '\0'; From e3bbd267c3c2c39991a012057da80e52dd43ae16 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:28 +0200 Subject: [PATCH 098/199] cloud-setup: add gtk-doc comment for nm_http_client_get_finish() NMHttpClient guarantees that the returned response is %NUL terminated after the returned length of the buffer. That guarantee is important and should be documented. --- clients/cloud-setup/nm-http-client.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index 946ed8ce93..76db6c6ff7 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -351,6 +351,21 @@ nm_http_client_get (NMHttpClient *self, } } +/** + * nm_http_client_get_finish: + * @self: the #NMHttpClient instance + * @result: the #GAsyncResult which to complete. + * @out_response_code: (allow-none) (out): the HTTP response code or -1 on other error. + * @out_response_data: (allow-none) (transfer full): the HTTP response data, if any. + * The GBytes buffer is guaranteed to have a trailing NUL character *after* the + * returned buffer size. That means, you can always trust that the buffer is NUL terminated + * and that there is one additional hidden byte after the data. + * Also, the returned buffer is allocated just for you. While GBytes is immutable, you are + * allowed to modify the buffer as it's not used by anybody else. + * @error: the error + * + * Returns: %TRUE on success. + */ gboolean nm_http_client_get_finish (NMHttpClient *self, GAsyncResult *result, From befd971b45163bebfa0a052fd63b4bd4bb47d6ee Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:29 +0200 Subject: [PATCH 099/199] cloud-setup: assert that NMHttpClient returns NUL terminated buffer The behavior is documented at various places, so this assert is less to actually assert it, but as making this condition obvious to the reader of the code. --- clients/cloud-setup/nmcs-provider-ec2.c | 2 ++ clients/cloud-setup/nmcs-provider-gcp.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c index 3b5f6d36a8..a3b4c9a0d3 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ b/clients/cloud-setup/nmcs-provider-ec2.c @@ -449,6 +449,8 @@ _get_config_metadata_ready_check (long response_code, } r_data = g_bytes_get_data (response_data, &r_len); + /* NMHttpClient guarantees that there is a trailing NUL after the data. */ + nm_assert (r_data[r_len] == 0); while (r_len > 0) { const guint8 *p_eol; diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c index ba4016dd15..676dd1f27b 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -246,10 +246,11 @@ _get_config_ips_list_cb (GObject *source, if (error) goto fips_error; + response_str = g_bytes_get_data (response, &response_len); + /* NMHttpClient guarantees that there is a trailing NUL after the data. */ + nm_assert (response_str[response_len] == 0); uri_arr = g_ptr_array_new_with_free_func (g_free); - response_str = g_bytes_get_data (response, &response_len); - while (nm_utils_parse_next_line (&response_str, &response_len, &line, @@ -403,6 +404,9 @@ _get_net_ifaces_list_cb (GObject *source, } response_str = g_bytes_get_data (response, &response_len); + /* NMHttpClient guarantees that there is a trailing NUL after the data. */ + nm_assert (response_str[response_len] == 0); + ifaces_arr = g_ptr_array_new (); gstr = g_string_new (NULL); From e7357419cd767aff36807ea8cabc0155271ddd88 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:30 +0200 Subject: [PATCH 100/199] shared: add nm_str_buf_finalize_to_gbytes() helper --- shared/nm-glib-aux/nm-str-buf.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h index 61246969de..f4a3542c4f 100644 --- a/shared/nm-glib-aux/nm-str-buf.h +++ b/shared/nm-glib-aux/nm-str-buf.h @@ -429,6 +429,23 @@ nm_str_buf_finalize (NMStrBuf *strbuf, return g_steal_pointer (&strbuf->_priv_str); } +static inline GBytes * +nm_str_buf_finalize_to_gbytes (NMStrBuf *strbuf) +{ + char *s; + gsize l; + + /* this always returns a non-NULL, newly allocated GBytes instance. + * The data buffer always has an additional NUL character after + * the data, and the data is allocated with malloc. + * + * That means, the caller who takes ownership of the GBytes can + * safely modify the content of the buffer (including the additional + * NUL sentinel). */ + s = nm_str_buf_finalize (strbuf, &l); + return g_bytes_new_take (s ?: g_new0 (char, 1), l); +} + /** * nm_str_buf_destroy: * @strbuf: an initialized #NMStrBuf From e2bd72235863504e899c173b510739ac24ff19a0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:31 +0200 Subject: [PATCH 101/199] shared: refactor nm_utils_parse_next_line() and add tests - add unit test for nm_utils_parse_next_line() - as line delimiter also accept "\r\n" and "\r" (beside "\n", "\0" and EOF). - fix returning lines with embedded "\0" characters. The line ends on the first "\n" or "\0", whatever comes first. The code before didn't ensure that with: line_end = memchr (line_start, '\n', *inout_len); if (!line_end) line_end = memchr (line_start, '\0', *inout_len); --- shared/nm-glib-aux/nm-shared-utils.c | 64 ++++++----- .../nm-glib-aux/tests/test-shared-general.c | 104 ++++++++++++++++++ 2 files changed, 143 insertions(+), 25 deletions(-) diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 1569662f8c..9fc4e510ac 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -1080,39 +1080,53 @@ nm_utils_parse_next_line (const char **inout_ptr, const char **out_line, gsize *out_line_len) { + gboolean eol_is_carriage_return; const char *line_start; - const char *line_end; + gsize line_len; - g_return_val_if_fail (inout_ptr, FALSE); - g_return_val_if_fail (inout_len, FALSE); - g_return_val_if_fail (out_line, FALSE); + nm_assert (inout_ptr); + nm_assert (inout_len); + nm_assert (*inout_len == 0 || *inout_ptr); + nm_assert (out_line); + nm_assert (out_line_len); - if (*inout_len <= 0) - goto error; + if (G_UNLIKELY (*inout_len == 0)) + return FALSE; line_start = *inout_ptr; - line_end = memchr (line_start, '\n', *inout_len); - if (!line_end) - line_end = memchr (line_start, '\0', *inout_len); - if (!line_end) { - line_end = line_start + *inout_len; - NM_SET_OUT (inout_len, 0); - } else - NM_SET_OUT (inout_len, *inout_len - (line_end - line_start) - 1); - NM_SET_OUT (out_line, line_start); - NM_SET_OUT (out_line_len, (gsize) (line_end - line_start)); + eol_is_carriage_return = FALSE; + for (line_len = 0; ; line_len++) { + if (line_len >= *inout_len) { + /* if we consumed the entire line, we place the pointer at + * one character after the end. */ + *inout_ptr = &line_start[line_len]; + *inout_len = 0; + goto done; + } + switch (line_start[line_len]) { + case '\r': + eol_is_carriage_return = TRUE; + /* fall-through*/ + case '\0': + case '\n': + *inout_ptr = &line_start[line_len + 1]; + *inout_len = *inout_len - line_len - 1u; + if ( eol_is_carriage_return + && *inout_len > 0 + && (*inout_ptr)[0] == '\n') { + /* also consume "\r\n" as one. */ + (*inout_len)--; + (*inout_ptr)++; + } + goto done; + } + } - if (*inout_len > 0) - NM_SET_OUT (inout_ptr, line_end + 1); - else - NM_SET_OUT (inout_ptr, NULL); +done: + *out_line = line_start; + *out_line_len = line_len; return TRUE; - -error: - NM_SET_OUT (out_line, NULL); - NM_SET_OUT (out_line_len, 0); - return FALSE; } /*****************************************************************************/ diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c index a435e28195..f389770a7a 100644 --- a/shared/nm-glib-aux/tests/test-shared-general.c +++ b/shared/nm-glib-aux/tests/test-shared-general.c @@ -773,6 +773,109 @@ test_nm_str_buf (void) /*****************************************************************************/ +static void +test_nm_utils_parse_next_line (void) +{ + const char *data; + const char *data0; + gsize data_len; + const char *line_start; + gsize line_len; + int i_run; + gsize j, k; + + data = NULL; + data_len = 0; + g_assert (!nm_utils_parse_next_line (&data, &data_len, &line_start, &line_len)); + + for (i_run = 0; i_run < 1000; i_run++) { + gs_unref_ptrarray GPtrArray *strv = g_ptr_array_new_with_free_func (g_free); + gs_unref_ptrarray GPtrArray *strv2 = g_ptr_array_new_with_free_func (g_free); + gsize strv_len = nmtst_get_rand_word_length (NULL); + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT (0, nmtst_get_rand_bool ()); + + /* create a list of random words. */ + for (j = 0; j < strv_len; j++) { + gsize w_len = nmtst_get_rand_word_length (NULL); + NMStrBuf w_buf = NM_STR_BUF_INIT (nmtst_get_rand_uint32 () % (w_len + 1), nmtst_get_rand_bool ()); + + for (k = 0; k < w_len; k++) + nm_str_buf_append_c (&w_buf, '0' + (k % 10)); + nm_str_buf_maybe_expand (&w_buf, 1, TRUE); + g_ptr_array_add (strv, nm_str_buf_finalize (&w_buf, NULL)); + } + + /* join the list of random words with (random) line delimiters + * ("\0", "\n", "\r" or EOF). */ + for (j = 0; j < strv_len; j++) { + nm_str_buf_append (&strbuf, strv->pdata[j]); +again: + switch (nmtst_get_rand_uint32 () % 5) { + case 0: + nm_str_buf_append_c (&strbuf, '\0'); + break; + case 1: + if ( strbuf.len > 0 + && (nm_str_buf_get_str_unsafe (&strbuf))[strbuf.len - 1] == '\r') { + /* the previous line was empty and terminated by "\r". We + * must not join with "\n". Retry. */ + goto again; + } + nm_str_buf_append_c (&strbuf, '\n'); + break; + case 2: + nm_str_buf_append_c (&strbuf, '\r'); + break; + case 3: + nm_str_buf_append (&strbuf, "\r\n"); + break; + case 4: + /* the last word randomly is delimited or not, but not if the last + * word is "". */ + if (j + 1 < strv_len) { + /* it's not the last word. Retry. */ + goto again; + } + g_assert (j == strv_len - 1); + if (((const char *) strv->pdata[j])[0] == '\0') { + /* if the last word was "", we need a delimiter (to parse it back). + * Retry. */ + goto again; + } + /* The final delimiter gets omitted. It's EOF. */ + break; + } + } + + data0 = nm_str_buf_get_str_unsafe (&strbuf); + if ( !data0 + && nmtst_get_rand_bool ()) { + nm_str_buf_maybe_expand (&strbuf, 1, TRUE); + data0 = nm_str_buf_get_str_unsafe (&strbuf); + g_assert (data0); + } + data_len = strbuf.len; + g_assert ((data_len > 0 && data0) || data_len == 0); + data = data0; + while (nm_utils_parse_next_line (&data, &data_len, &line_start, &line_len)) { + g_assert (line_start); + g_assert (line_start >= data0); + g_assert (line_start < &data0[strbuf.len]); + g_assert (!memchr (line_start, '\0', line_len)); + g_ptr_array_add (strv2, g_strndup (line_start, line_len)); + } + g_assert (data_len == 0); + if (data0) + g_assert (data == &data0[strbuf.len]); + else + g_assert (!data); + + g_assert (_nm_utils_strv_cmp_n ((const char *const*) strv->pdata, strv->len, (const char *const*) strv2->pdata, strv2->len) == 0); + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -794,6 +897,7 @@ int main (int argc, char **argv) g_test_add_func ("/general/test_string_table_lookup", test_string_table_lookup); g_test_add_func ("/general/test_nm_utils_get_next_realloc_size", test_nm_utils_get_next_realloc_size); g_test_add_func ("/general/test_nm_str_buf", test_nm_str_buf); + g_test_add_func ("/general/test_nm_utils_parse_next_line", test_nm_utils_parse_next_line); return g_test_run (); } From 4f542384c3357f913c7c9b2642cf54065addf181 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:32 +0200 Subject: [PATCH 102/199] cloud-setup: use nm_utils_parse_next_line() in _get_config_metadata_ready_check() nm_utils_parse_next_line() has more flexible handling of line endings (for example, also accpting "\0", "\r", "\r\n"). Use it. --- clients/cloud-setup/nmcs-provider-ec2.c | 43 ++++++++----------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c index a3b4c9a0d3..1427534b68 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ b/clients/cloud-setup/nmcs-provider-ec2.c @@ -436,7 +436,9 @@ _get_config_metadata_ready_check (long response_code, GetConfigMetadataData *metadata_data = check_user_data; gs_unref_hashtable GHashTable *response_parsed = NULL; const guint8 *r_data; + const char *cur_line; gsize r_len; + gsize cur_line_len; GHashTableIter h_iter; gboolean has_all; const char *c_hwaddr; @@ -452,47 +454,30 @@ _get_config_metadata_ready_check (long response_code, /* NMHttpClient guarantees that there is a trailing NUL after the data. */ nm_assert (r_data[r_len] == 0); - while (r_len > 0) { - const guint8 *p_eol; - const char *p_start; - gsize p_start_l; - gsize p_start_l_2; - char *hwaddr; + while (nm_utils_parse_next_line ((const char **) &r_data, &r_len, &cur_line, &cur_line_len)) { GetConfigMetadataMac *mac_data; + char *hwaddr; - p_start = (const char *) r_data; - - p_eol = memchr (r_data, '\n', r_len); - if (p_eol) { - p_start_l = (p_eol - r_data); - r_len -= p_start_l + 1; - r_data = &p_eol[1]; - } else { - p_start_l = r_len; - r_data = &r_data[r_len]; - r_len = 0; - } - - if (p_start_l == 0) + if (cur_line_len == 0) continue; - p_start_l_2 = p_start_l; - if (p_start[p_start_l_2 - 1] == '/') { - /* trim the trailing "/". */ - p_start_l_2--; - } + /* Truncate the string. It's safe to do, because we own @response_data an it has an + * extra NUL character after the buffer. */ + ((char *) cur_line)[cur_line_len] = '\0'; - hwaddr = nmcs_utils_hwaddr_normalize (p_start, p_start_l_2); + hwaddr = nmcs_utils_hwaddr_normalize (cur_line, + cur_line[cur_line_len - 1u] == '/' + ? (gssize) (cur_line_len - 1u) + : -1); if (!hwaddr) continue; if (!response_parsed) response_parsed = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); - mac_data = g_malloc (sizeof (GetConfigMetadataMac) + 1 + p_start_l); + mac_data = g_malloc (sizeof (GetConfigMetadataMac) + 1u + cur_line_len); mac_data->iface_idx = iface_idx_counter++; - memcpy (mac_data->path, p_start, p_start_l); - mac_data->path[p_start_l] = '\0'; + memcpy (mac_data->path, cur_line, cur_line_len + 1u); g_hash_table_insert (response_parsed, hwaddr, mac_data); } From 39733352d629885621a8bb7a315061bbe6477ef4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:33 +0200 Subject: [PATCH 103/199] cloud-setup: use NMStrBuf in nmcs_utils_uri_build_concat_v() --- clients/cloud-setup/nm-cloud-setup-utils.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/clients/cloud-setup/nm-cloud-setup-utils.c b/clients/cloud-setup/nm-cloud-setup-utils.c index a32003cb35..d08eb1144e 100644 --- a/clients/cloud-setup/nm-cloud-setup-utils.c +++ b/clients/cloud-setup/nm-cloud-setup-utils.c @@ -6,6 +6,7 @@ #include "nm-glib-aux/nm-time-utils.h" #include "nm-glib-aux/nm-logging-base.h" +#include "nm-glib-aux/nm-str-buf.h" /*****************************************************************************/ @@ -565,15 +566,13 @@ nmcs_utils_uri_build_concat_v (const char *base, const char **components, gsize n_components) { - GString *uri; + NMStrBuf strbuf = NM_STR_BUF_INIT (NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); nm_assert (base); nm_assert (base[0]); nm_assert (!NM_STR_HAS_SUFFIX (base, "/")); - uri = g_string_sized_new (100); - - g_string_append (uri, base); + nm_str_buf_append (&strbuf, base); if ( n_components > 0 && components[0] @@ -583,18 +582,18 @@ nmcs_utils_uri_build_concat_v (const char *base, * * We only do that for the first component. */ } else - g_string_append_c (uri, '/'); + nm_str_buf_append_c (&strbuf, '/'); while (n_components > 0) { if (!components[0]) { - /* we allow NULL, to indicate nothing to append*/ + /* we allow NULL, to indicate nothing to append */ } else - g_string_append (uri, components[0]); + nm_str_buf_append (&strbuf, components[0]); components++; n_components--; } - return g_string_free (uri, FALSE); + return nm_str_buf_finalize (&strbuf, NULL); } /*****************************************************************************/ From c9c54709b843d2c195985a9267a6297f02396683 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:33 +0200 Subject: [PATCH 104/199] cloud-setup: use NMStrBuf in NMHttpClient to track response --- clients/cloud-setup/nm-http-client.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index 76db6c6ff7..24d42e3d5f 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -7,6 +7,7 @@ #include #include "nm-cloud-setup-utils.h" +#include "nm-glib-aux/nm-str-buf.h" #define NM_CURL_DEBUG 0 @@ -118,7 +119,7 @@ typedef struct { CURLcode ehandle_result; CURL *ehandle; char *url; - GString *recv_data; + NMStrBuf recv_data; struct curl_slist *headers; gssize max_data; gulong cancellable_id; @@ -144,8 +145,7 @@ _ehandle_free (EHandleData *edata) g_object_unref (edata->task); - if (edata->recv_data) - g_string_free (edata->recv_data, TRUE); + nm_str_buf_destroy (&edata->recv_data); if (edata->headers) curl_slist_free_all (edata->headers); g_free (edata->url); @@ -191,12 +191,15 @@ _ehandle_complete (EHandleData *edata, _LOG2E (edata, "failed to get response code from curl easy handle"); _LOG2D (edata, "success getting %"G_GSIZE_FORMAT" bytes (response code %ld)", - edata->recv_data->len, + edata->recv_data.len, response_code); _LOG2T (edata, "received %"G_GSIZE_FORMAT" bytes: [[%s]]", - edata->recv_data->len, - nm_utils_buf_utf8safe_escape (edata->recv_data->str, edata->recv_data->len, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &str_tmp_1)); + edata->recv_data.len, + nm_utils_buf_utf8safe_escape (nm_str_buf_get_str (&edata->recv_data), + edata->recv_data.len, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, + &str_tmp_1)); _ehandle_free_ehandle (edata); @@ -205,7 +208,7 @@ _ehandle_complete (EHandleData *edata, .response_code = response_code, /* This ensures that response_data is always NUL terminated. This is an important guarantee * that NMHttpClient makes. */ - .response_data = g_string_free_to_bytes (g_steal_pointer (&edata->recv_data)), + .response_data = nm_str_buf_finalize_to_gbytes (&edata->recv_data), }; g_task_return_pointer (edata->task, get_result, _get_result_free); @@ -225,14 +228,14 @@ _get_writefunction_cb (char *ptr, size_t size, size_t nmemb, void *user_data) nmemb *= size; if (edata->max_data >= 0) { - nm_assert (edata->recv_data->len <= edata->max_data); - nconsume = (((gsize) edata->max_data) - edata->recv_data->len); + nm_assert (edata->recv_data.len <= edata->max_data); + nconsume = (((gsize) edata->max_data) - edata->recv_data.len); if (nconsume > nmemb) nconsume = nmemb; } else nconsume = nmemb; - g_string_append_len (edata->recv_data, ptr, nconsume); + nm_str_buf_append_len (&edata->recv_data, ptr, nconsume); return nconsume; } @@ -283,7 +286,7 @@ nm_http_client_get (NMHttpClient *self, edata = g_slice_new (EHandleData); *edata = (EHandleData) { .task = nm_g_task_new (self, cancellable, nm_http_client_get, callback, user_data), - .recv_data = g_string_sized_new (NM_MIN (max_data, 245)), + .recv_data = NM_STR_BUF_INIT (0, FALSE), .max_data = max_data, .url = g_strdup (url), .headers = NULL, From 62aec7acd3601f1a433181fdc80bbe0167c5539e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:34 +0200 Subject: [PATCH 105/199] cloud-setup: don't use a GString in _get_config_ips_list_cb() nm_utils_parse_next_line() operates on the response buffer obtained from NMHttpClient. We own this buffer, and we also can rely on the fact that the buffer has a trailing NUL byte after the data. There is no need to clone the string to a GString, just use it directly. --- clients/cloud-setup/nmcs-provider-gcp.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c index 676dd1f27b..13f317e12e 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -255,21 +255,20 @@ _get_config_ips_list_cb (GObject *source, &response_len, &line, &line_len)) { - nm_auto_free_gstring GString *gstr = NULL; gint64 fip_index; - gstr = g_string_new_len (line, line_len); - fip_index = _nm_utils_ascii_str_to_int64 (gstr->str, 10, 0, G_MAXINT64, -1); + /* Truncate the string. It's safe to do, because we own @response_data an it has an + * extra NUL character after the buffer. */ + ((char *) line)[line_len] = '\0'; - if (fip_index < 0) { + fip_index = _nm_utils_ascii_str_to_int64 (line, 10, 0, G_MAXINT64, -1); + if (fip_index < 0) continue; - } - g_string_printf (gstr, - "%"G_GSSIZE_FORMAT"/forwarded-ips/%"G_GINT64_FORMAT, - iface_data->iface_idx, - fip_index); - g_ptr_array_add (uri_arr, g_string_free (g_steal_pointer (&gstr), FALSE)); + g_ptr_array_add (uri_arr, + g_strdup_printf ("%"G_GSSIZE_FORMAT"/forwarded-ips/%"G_GINT64_FORMAT, + iface_data->iface_idx, + fip_index)); } iface_data->n_fips_pending = uri_arr->len; From 3d61b2894111a07ce958f6a554691b199ad990b8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:35 +0200 Subject: [PATCH 106/199] cloud-setup: don't use a GString in loop in _get_net_ifaces_list_cb() nm_utils_parse_next_line() operates on the response buffer obtained from NMHttpClient. We own this buffer, and we also can rely on the fact that the buffer has a trailing NUL byte after the data. There is no need to copy the string to a GString, just use it directly. --- clients/cloud-setup/nmcs-provider-gcp.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c index 13f317e12e..069abfcc7a 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -384,8 +384,6 @@ _get_net_ifaces_list_cb (GObject *source, gs_free_error GError *error = NULL; GCPData *gcp_data = user_data; const char *response_str; - const char *token_start; - const char *token_end; gsize response_len; const char *line; gsize line_len; @@ -416,16 +414,16 @@ _get_net_ifaces_list_cb (GObject *source, GCPIfaceData *iface_data; gssize iface_idx; - token_start = line; - token_end = memchr (token_start, '/', line_len); - - if (!token_end) + if (line_len == 0) continue; - g_string_truncate (gstr, 0); - g_string_append_len (gstr, token_start, token_end - token_start); - iface_idx = _nm_utils_ascii_str_to_int64 (gstr->str, 10, 0, G_MAXSSIZE, -1); + /* Truncate the string. It's safe to do, because we own @response_data an it has an + * extra NUL character after the buffer. */ + ((char *) line)[line_len] = '\0'; + if (line[line_len - 1] == '/') + ((char *) line)[--line_len] = '\0'; + iface_idx = _nm_utils_ascii_str_to_int64 (line, 10, 0, G_MAXSSIZE, -1); if (iface_idx < 0) continue; @@ -487,7 +485,6 @@ get_config (NMCSProvider *provider, .n_ifaces_pending = 0, .error = NULL, .success = FALSE, - }; nm_http_client_poll_get (nmcs_provider_get_http_client (provider), From 2fbc8717ca343fd6bafbe36a10d04db293fc4d88 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:36 +0200 Subject: [PATCH 107/199] cloud-setup: use stack allocated buffer for temporary strings in "nmcs-provider-gcp.c" The maximum length of these strings is known and small. Use a buffer on the stack for them. --- clients/cloud-setup/nmcs-provider-gcp.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c index 069abfcc7a..a879a4eb3a 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -321,7 +321,7 @@ _get_config_iface_cb (GObject *source, gs_free_error GError *error = NULL; gs_free const char *hwaddr = NULL; gs_free const char *uri = NULL; - gs_free char *str = NULL; + char sbuf[100]; GCPData *gcp_data; gcp_data = iface_data->gcp_data; @@ -350,11 +350,10 @@ _get_config_iface_cb (GObject *source, iface_data->iface_idx, hwaddr); - str = g_strdup_printf ("%"G_GSSIZE_FORMAT"/forwarded-ips/", - iface_data->iface_idx); + nm_sprintf_buf (sbuf, "%"G_GSSIZE_FORMAT"/forwarded-ips/", iface_data->iface_idx); nm_http_client_poll_get (NM_HTTP_CLIENT (source), - (uri = _gcp_uri_interfaces (str)), + (uri = _gcp_uri_interfaces (sbuf)), HTTP_TIMEOUT_MS, HTTP_REQ_MAX_DATA, HTTP_POLL_TIMEOUT_MS, @@ -379,7 +378,6 @@ _get_net_ifaces_list_cb (GObject *source, gpointer user_data) { gs_unref_ptrarray GPtrArray *ifaces_arr = NULL; - nm_auto_free_gstring GString *gstr = NULL; gs_unref_bytes GBytes *response = NULL; gs_free_error GError *error = NULL; GCPData *gcp_data = user_data; @@ -405,7 +403,6 @@ _get_net_ifaces_list_cb (GObject *source, nm_assert (response_str[response_len] == 0); ifaces_arr = g_ptr_array_new (); - gstr = g_string_new (NULL); while (nm_utils_parse_next_line (&response_str, &response_len, @@ -443,14 +440,15 @@ _get_net_ifaces_list_cb (GObject *source, for (i = 0; i < ifaces_arr->len; ++i) { GCPIfaceData *data = ifaces_arr->pdata[i]; gs_free const char *uri = NULL; + char sbuf[100]; _LOGD ("GCP interface[%"G_GSSIZE_FORMAT"]: retrieving configuration", data->iface_idx); - g_string_printf (gstr, "%"G_GSSIZE_FORMAT"/mac", data->iface_idx); + nm_sprintf_buf (sbuf, "%"G_GSSIZE_FORMAT"/mac", data->iface_idx); nm_http_client_poll_get (NM_HTTP_CLIENT (source), - (uri = _gcp_uri_interfaces (gstr->str)), + (uri = _gcp_uri_interfaces (sbuf)), HTTP_TIMEOUT_MS, HTTP_REQ_MAX_DATA, HTTP_POLL_TIMEOUT_MS, From ceb75f8ab4f28b076ddcdf34ace4f106bf88d914 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:38 +0200 Subject: [PATCH 108/199] cloud-setup: remove debugging message from _poll_cancelled_cb() --- clients/cloud-setup/nm-cloud-setup-utils.c | 1 - 1 file changed, 1 deletion(-) diff --git a/clients/cloud-setup/nm-cloud-setup-utils.c b/clients/cloud-setup/nm-cloud-setup-utils.c index d08eb1144e..9db3b742c9 100644 --- a/clients/cloud-setup/nm-cloud-setup-utils.c +++ b/clients/cloud-setup/nm-cloud-setup-utils.c @@ -357,7 +357,6 @@ _poll_cancelled_cb (GObject *object, gpointer user_data) PollTaskData *poll_task_data = user_data; GError *error = NULL; - _LOGD (">> poll cancelled"); nm_clear_g_signal_handler (g_task_get_cancellable (poll_task_data->task), &poll_task_data->cancellable_id); nm_utils_error_set_cancelled (&error, FALSE, NULL); From eb2dfa9b4117f34205e8153efcfc19925bba7b4d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:39 +0200 Subject: [PATCH 109/199] cloud-setup: always report success or an GError from nm_http_client_poll_get_finish()/nmcs_utils_poll_finish() Since commit 3bd30f6064c3 ('nmcs: add error message when a HTTP request times out'), the case where polling returns %FALSE without an error is no longer possible. This is preferable, because it follows a consistent API where a function clearly fails or succeeds. So, checking for the error code and the returned boolean is redundant and unnecessary. --- clients/cloud-setup/nm-cloud-setup-utils.c | 16 ++++++++-------- clients/cloud-setup/nm-http-client.c | 14 ++++++++------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/clients/cloud-setup/nm-cloud-setup-utils.c b/clients/cloud-setup/nm-cloud-setup-utils.c index 9db3b742c9..39f3b100a1 100644 --- a/clients/cloud-setup/nm-cloud-setup-utils.c +++ b/clients/cloud-setup/nm-cloud-setup-utils.c @@ -258,7 +258,6 @@ _poll_task_data_free (gpointer data) static void _poll_return (PollTaskData *poll_task_data, - gboolean success, GError *error_take) { nm_clear_g_source_inst (&poll_task_data->source_next_poll); @@ -271,7 +270,7 @@ _poll_return (PollTaskData *poll_task_data, if (error_take) g_task_return_error (poll_task_data->task, g_steal_pointer (&error_take)); else - g_task_return_boolean (poll_task_data->task, success); + g_task_return_boolean (poll_task_data->task, TRUE); g_object_unref (poll_task_data->task); } @@ -302,7 +301,7 @@ _poll_done_cb (GObject *source, if ( error || is_finished) { - _poll_return (poll_task_data, TRUE, g_steal_pointer (&error)); + _poll_return (poll_task_data, g_steal_pointer (&error)); return; } @@ -346,8 +345,8 @@ _poll_timeout_cb (gpointer user_data) { PollTaskData *poll_task_data = user_data; - _poll_return (poll_task_data, FALSE, nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, - "timeout expired")); + _poll_return (poll_task_data, nm_utils_error_new (NM_UTILS_ERROR_UNKNOWN, + "timeout expired")); return G_SOURCE_CONTINUE; } @@ -360,13 +359,13 @@ _poll_cancelled_cb (GObject *object, gpointer user_data) nm_clear_g_signal_handler (g_task_get_cancellable (poll_task_data->task), &poll_task_data->cancellable_id); nm_utils_error_set_cancelled (&error, FALSE, NULL); - _poll_return (poll_task_data, FALSE, error); + _poll_return (poll_task_data, error); } /** * nmcs_utils_poll: * @poll_timeout_ms: if >= 0, then this is the overall timeout for how long we poll. - * When this timeout expires, the request completes with failure (but no error set). + * When this timeout expires, the request completes with failure (and error set). * @ratelimit_timeout_ms: if > 0, we ratelimit the starts from one prope_start_fcn * call to the next. * @sleep_timeout_ms: if > 0, then we wait after a probe finished this timeout @@ -459,7 +458,8 @@ nmcs_utils_poll (int poll_timeout_ms, * %FALSE will be returned. * If the probe returned a failure, this returns %FALSE and the error * provided by @probe_finish_fcn. - * If the request times out, this returns %FALSE without error set. + * If the request times out, this returns %FALSE with error set. + * Error is always set if (and only if) the function returns %FALSE. */ gboolean nmcs_utils_poll_finish (GAsyncResult *result, diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index 24d42e3d5f..7f042c8af6 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -505,10 +505,12 @@ _poll_get_done_cb (GObject *source, success = nmcs_utils_poll_finish (result, NULL, &error); + nm_assert ((!!success) == (!error)); + if (error) g_task_return_error (poll_get_data->task, g_steal_pointer (&error)); else - g_task_return_boolean (poll_get_data->task, success); + g_task_return_boolean (poll_get_data->task, TRUE); g_object_unref (poll_get_data->task); } @@ -587,10 +589,11 @@ nm_http_client_poll_get_finish (NMHttpClient *self, task = G_TASK (result); success = g_task_propagate_boolean (task, &local_error); - if ( local_error - || !success) { - if (local_error) - g_propagate_error (error, g_steal_pointer (&local_error)); + + nm_assert ((!!success) == (!local_error)); + + if (local_error) { + g_propagate_error (error, g_steal_pointer (&local_error)); NM_SET_OUT (out_response_code, -1); NM_SET_OUT (out_response_data, NULL); return FALSE; @@ -600,7 +603,6 @@ nm_http_client_poll_get_finish (NMHttpClient *self, NM_SET_OUT (out_response_code, poll_get_data->response_code); NM_SET_OUT (out_response_data, g_steal_pointer (&poll_get_data->response_data)); - return TRUE; } From 53bdd81800fab05a6474d370d52105a1740b1905 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:40 +0200 Subject: [PATCH 110/199] cloud-setup: ensure that nm_http_client_get_finish() always returns success or error --- clients/cloud-setup/nm-http-client.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c index 7f042c8af6..294259f261 100644 --- a/clients/cloud-setup/nm-http-client.c +++ b/clients/cloud-setup/nm-http-client.c @@ -367,7 +367,7 @@ nm_http_client_get (NMHttpClient *self, * allowed to modify the buffer as it's not used by anybody else. * @error: the error * - * Returns: %TRUE on success. + * Returns: %TRUE on success or %FALSE with an error code. */ gboolean nm_http_client_get_finish (NMHttpClient *self, @@ -382,6 +382,9 @@ nm_http_client_get_finish (NMHttpClient *self, g_return_val_if_fail (nm_g_task_is_valid (result, self, nm_http_client_get), FALSE); get_result = g_task_propagate_pointer (G_TASK (result), error); + + nm_assert ((!!get_result) == (!error)); + if (!get_result) { NM_SET_OUT (out_response_code, -1); NM_SET_OUT (out_response_data, NULL); @@ -394,7 +397,6 @@ nm_http_client_get_finish (NMHttpClient *self, NM_SET_OUT (out_response_data, g_steal_pointer (&get_result->response_data)); _get_result_free (get_result); - return TRUE; } @@ -465,11 +467,14 @@ _poll_get_probe_finish_fcn (GObject *source, &response_data, &local_error); - if (!success) { + nm_assert ((!!success) == (!local_error)); + + if (local_error) { if (nm_utils_error_is_cancelled (local_error)) { g_propagate_error (error, g_steal_pointer (&local_error)); return TRUE; } + /* any other error. Continue polling. */ return FALSE; } @@ -486,8 +491,10 @@ _poll_get_probe_finish_fcn (GObject *source, return TRUE; } - if (!success) + if (!success) { + /* Not yet ready. Continue polling. */ return FALSE; + } poll_get_data->response_code = response_code; poll_get_data->response_data = g_steal_pointer (&response_data); From 9702f79db6ffce2a3319d0a710fe9498380d17e0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 29 Jun 2020 09:52:41 +0200 Subject: [PATCH 111/199] cloud-setup: don't check redundant error results from nm_http_client_poll_get_finish() nm_http_client_poll_get_finish() can only either succeed (returning TRUE and setting no GError), or failing (returning FALSE and setting GError). Checking for both is redundant and unnecessary. --- clients/cloud-setup/nmcs-provider-ec2.c | 42 +++++++++---------------- clients/cloud-setup/nmcs-provider-gcp.c | 19 +++-------- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/clients/cloud-setup/nmcs-provider-ec2.c b/clients/cloud-setup/nmcs-provider-ec2.c index 1427534b68..1578a33bed 100644 --- a/clients/cloud-setup/nmcs-provider-ec2.c +++ b/clients/cloud-setup/nmcs-provider-ec2.c @@ -90,13 +90,12 @@ _detect_get_meta_data_done_cb (GObject *source, gs_unref_object GTask *task = user_data; gs_free_error GError *get_error = NULL; gs_free_error GError *error = NULL; - gboolean success; - success = nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), - result, - NULL, - NULL, - &get_error); + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + NULL, + &get_error); if (nm_utils_error_is_cancelled (get_error)) { g_task_return_error (task, g_steal_pointer (&get_error)); @@ -112,14 +111,6 @@ _detect_get_meta_data_done_cb (GObject *source, return; } - if (!success) { - nm_utils_error_set (&error, - NM_UTILS_ERROR_UNKNOWN, - "failure to detect EC2 metadata"); - g_task_return_error (task, g_steal_pointer (&error)); - return; - } - g_task_return_boolean (task, TRUE); } @@ -191,31 +182,28 @@ _get_config_fetch_done_cb (NMHttpClient *http_client, gboolean is_local_ipv4) { GetConfigIfaceData *iface_data; - NMCSProviderGetConfigTaskData *get_config_data; const char *hwaddr = NULL; gs_unref_bytes GBytes *response_data = NULL; gs_free_error GError *error = NULL; - gboolean success; - NMCSProviderGetConfigIfaceData *config_iface_data; nm_utils_user_data_unpack (user_data, &iface_data, &hwaddr); - success = nm_http_client_poll_get_finish (http_client, - result, - NULL, - &response_data, - &error); + nm_http_client_poll_get_finish (http_client, + result, + NULL, + &response_data, + &error); + if (nm_utils_error_is_cancelled (error)) return; - get_config_data = iface_data->get_config_data; - - config_iface_data = g_hash_table_lookup (get_config_data->result_dict, hwaddr); - - if (success) { + if (!error) { + NMCSProviderGetConfigIfaceData *config_iface_data; in_addr_t tmp_addr; int tmp_prefix; + config_iface_data = g_hash_table_lookup (iface_data->get_config_data->result_dict, hwaddr); + if (is_local_ipv4) { gs_free const char **s_addrs = NULL; gsize i, len; diff --git a/clients/cloud-setup/nmcs-provider-gcp.c b/clients/cloud-setup/nmcs-provider-gcp.c index a879a4eb3a..7a8f3ef893 100644 --- a/clients/cloud-setup/nmcs-provider-gcp.c +++ b/clients/cloud-setup/nmcs-provider-gcp.c @@ -46,13 +46,12 @@ _detect_get_meta_data_done_cb (GObject *source, gs_unref_object GTask *task = user_data; gs_free_error GError *get_error = NULL; gs_free_error GError *error = NULL; - gboolean success; - success = nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), - result, - NULL, - NULL, - &get_error); + nm_http_client_poll_get_finish (NM_HTTP_CLIENT (source), + result, + NULL, + NULL, + &get_error); if (nm_utils_error_is_cancelled (get_error)) { g_task_return_error (task, g_steal_pointer (&get_error)); @@ -68,14 +67,6 @@ _detect_get_meta_data_done_cb (GObject *source, return; } - if (!success) { - nm_utils_error_set (&error, - NM_UTILS_ERROR_UNKNOWN, - "failure to detect GCP metadata"); - g_task_return_error (task, g_steal_pointer (&error)); - return; - } - g_task_return_boolean (task, TRUE); } From 7337ab895951c37258d0634dd709f218109bd49f Mon Sep 17 00:00:00 2001 From: Sayed Shah Date: Wed, 1 Jul 2020 17:20:40 -0400 Subject: [PATCH 112/199] all: fix typo in man pages There should be a comma after 'Otherwise' and 'Currently'. https://bugzilla.redhat.com/show_bug.cgi?id=1852452 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/560 --- TODO | 6 ++--- clients/cli/connections.c | 4 ++-- clients/cli/devices.c | 2 +- clients/cli/settings.c | 4 ++-- clients/common/nm-client-utils.c | 2 +- clients/common/nm-meta-setting-desc.c | 2 +- clients/common/qrcodegen.c | 2 +- clients/common/settings-docs.h.in | 24 +++++++++---------- clients/tui/nmt-mtu-entry.c | 2 +- configure.ac | 4 ++-- ...edesktop.NetworkManager.Device.WifiP2P.xml | 2 +- ...desktop.NetworkManager.Device.Wireless.xml | 2 +- ...g.freedesktop.NetworkManager.IP4Config.xml | 2 +- ...top.NetworkManager.Settings.Connection.xml | 4 ++-- ...rg.freedesktop.NetworkManager.Settings.xml | 4 ++-- .../org.freedesktop.NetworkManager.xml | 2 +- libnm-core/nm-connection.c | 2 +- libnm-core/nm-dbus-utils.c | 2 +- libnm-core/nm-setting-8021x.c | 12 +++++----- libnm-core/nm-setting-connection.c | 10 ++++---- libnm-core/nm-setting-infiniband.c | 4 ++-- libnm-core/nm-setting-ip-config.c | 8 +++---- libnm-core/nm-setting-ip-tunnel.c | 2 +- libnm-core/nm-setting-ip4-config.c | 2 +- libnm-core/nm-setting-sriov.c | 2 +- libnm-core/nm-setting-vlan.c | 2 +- libnm-core/nm-setting-wifi-p2p.c | 2 +- libnm-core/nm-setting-wireguard.c | 6 ++--- libnm-core/nm-setting.c | 2 +- libnm/nm-active-connection.c | 2 +- libnm/nm-client.c | 6 ++--- libnm/nm-device.c | 4 ++-- man/NetworkManager.conf.xml | 8 +++---- man/nmcli-examples.xml | 4 ++-- man/nmcli.xml | 4 ++-- shared/n-dhcp4/src/n-dhcp4-client.c | 2 +- shared/nm-glib-aux/nm-io-utils.c | 2 +- shared/nm-glib-aux/nm-shared-utils.c | 4 ++-- src/NetworkManagerUtils.c | 4 ++-- src/devices/nm-device-ethernet.c | 2 +- src/devices/nm-device.c | 6 ++--- src/devices/ovs/nm-ovsdb.c | 4 ++-- src/devices/wifi/nm-device-iwd.c | 4 ++-- src/devices/wifi/nm-device-wifi.c | 2 +- src/dhcp/nm-dhcp-dhclient-utils.c | 2 +- src/dhcp/nm-dhcp-dhclient.c | 2 +- src/ndisc/nm-lndp-ndisc.c | 2 +- src/nm-active-connection.c | 2 +- src/nm-auth-utils.c | 2 +- src/nm-config.c | 2 +- src/nm-core-utils.c | 4 ++-- src/nm-dbus-manager.c | 2 +- src/nm-manager.c | 8 +++---- src/platform/nm-linux-platform.c | 2 +- src/platform/tests/test-route.c | 2 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 2 +- src/supplicant/nm-supplicant-interface.c | 2 +- src/vpn/nm-vpn-connection.c | 2 +- 58 files changed, 109 insertions(+), 109 deletions(-) diff --git a/TODO b/TODO index e24ef78e26..0732bcc404 100644 --- a/TODO +++ b/TODO @@ -23,7 +23,7 @@ possibly get inspired by nm-connection-editor. * Add Azure support to nm-cloud-setup. -nm-cloud-setup currently only works for EC2 (and only for IPv4). Add support for Azure +Currently, nm-cloud-setup only works for EC2 (and only for IPv4). Add support for Azure cloud. See for example SUSE's cloud-netconfig which supports Azure (https://github.com/SUSE-Enceladus/cloud-netconfig, https://www.suse.com/c/multi-nic-cloud-netconfig-ec2-azure/). Note that cloud-netconfig @@ -33,7 +33,7 @@ anyway be almost impossible, because one is written in bash and the other in C. * Improve our gitlab-ci integration. -Currently our .gitlab-ci starts various base containers and first installs +Currently, our .gitlab-ci starts various base containers and first installs the necessary dependencies. That takes time and consumes bandwidth, we should instead use more suitable containers. We should instead use ci-templates from https://gitlab.freedesktop.org/freedesktop/ci-templates. @@ -110,7 +110,7 @@ connected before the drop. * VPN IP Methods Some VPNs (openvpn with TAP for example) require that DHCP is run on a -pseudo-ethernet device to obtain addressing information. This is not currently +pseudo-ethernet device to obtain addressing information. Currenty, this is not possible, but NM already has all the code for DHCP. Thus, a new "method" key should be defined in include/NetworkManagerVPN.h to allow for DHCP to be performed if the VPN service daemon requests it in the IP4Config or IP6Config diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 44e34d56a6..b0f04f4017 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -5376,7 +5376,7 @@ read_properties: const char *slave_type = nm_setting_connection_get_slave_type (s_con); /* If only bother when there's a type, which is not guaranteed at this point. - * Otherwise the validation will fail anyway. */ + * Otherwise, the validation will fail anyway. */ if (type) { gs_free char *try_name = NULL; gs_free char *default_name = NULL; @@ -6713,7 +6713,7 @@ editor_sub_usage (const char *command) g_print (_("remove [||