diff options
Diffstat (limited to 'src/NetworkManagerUtils.c')
| -rw-r--r-- | src/NetworkManagerUtils.c | 2315 |
1 files changed, 1344 insertions, 971 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index bcb12a56..4739e9dd 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2004 - 2016 Red Hat, Inc. * Copyright (C) 2005 - 2008 Novell, Inc. @@ -34,722 +34,712 @@ * Returns: a static string of the wifi-permission (if any) or %NULL. */ const char * -nm_utils_get_shared_wifi_permission (NMConnection *connection) +nm_utils_get_shared_wifi_permission(NMConnection *connection) { - NMSettingWireless *s_wifi; - NMSettingWirelessSecurity *s_wsec; - const char *method; - - method = nm_utils_get_ip_config_method (connection, AF_INET); - if (!nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) - return NULL; - - s_wifi = nm_connection_get_setting_wireless (connection); - if (s_wifi) { - s_wsec = nm_connection_get_setting_wireless_security (connection); - if (s_wsec) - return NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED; - else - return NM_AUTH_PERMISSION_WIFI_SHARE_OPEN; - } - - return NULL; + NMSettingWireless * s_wifi; + NMSettingWirelessSecurity *s_wsec; + const char * method; + + method = nm_utils_get_ip_config_method(connection, AF_INET); + if (!nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) + return NULL; + + s_wifi = nm_connection_get_setting_wireless(connection); + if (s_wifi) { + s_wsec = nm_connection_get_setting_wireless_security(connection); + if (s_wsec) + return NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED; + else + return NM_AUTH_PERMISSION_WIFI_SHARE_OPEN; + } + + return NULL; } /*****************************************************************************/ static char * -get_new_connection_name (NMConnection *const*existing_connections, - const char *preferred, - const char *fallback_prefix) +get_new_connection_name(NMConnection *const *existing_connections, + const char * preferred, + const char * fallback_prefix) { - gs_free const char **existing_names = NULL; - guint i, existing_len = 0; - - g_assert (fallback_prefix); - - if (existing_connections) { - existing_len = NM_PTRARRAY_LEN (existing_connections); - existing_names = g_new (const char *, existing_len); - for (i = 0; i < existing_len; i++) { - NMConnection *candidate; - const char *id; - - candidate = existing_connections[i]; - nm_assert (NM_IS_CONNECTION (candidate)); - - id = nm_connection_get_id (candidate); - nm_assert (id); - - existing_names[i] = id; - - if ( preferred - && nm_streq (preferred, id)) { - /* the preferred name is already taken. Forget about it. */ - preferred = NULL; - } - } - nm_assert (!existing_connections[i]); - } - - /* Return the preferred name if it was unique */ - if (preferred) - return g_strdup (preferred); - - /* Otherwise find the next available unique connection name using the given - * connection name template. - */ - for (i = 1; TRUE; i++) { - char *temp; - - /* 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 - * connection id. */ - temp = g_strdup_printf (C_("connection id fallback", "%s %u"), - fallback_prefix, i); - - if (nm_utils_strv_find_first ((char **) existing_names, - existing_len, - temp) < 0) - return temp; - - g_free (temp); - } + gs_free const char **existing_names = NULL; + guint i, existing_len = 0; + + g_assert(fallback_prefix); + + if (existing_connections) { + existing_len = NM_PTRARRAY_LEN(existing_connections); + existing_names = g_new(const char *, existing_len); + for (i = 0; i < existing_len; i++) { + NMConnection *candidate; + const char * id; + + candidate = existing_connections[i]; + nm_assert(NM_IS_CONNECTION(candidate)); + + id = nm_connection_get_id(candidate); + nm_assert(id); + + existing_names[i] = id; + + if (preferred && nm_streq(preferred, id)) { + /* the preferred name is already taken. Forget about it. */ + preferred = NULL; + } + } + nm_assert(!existing_connections[i]); + } + + /* Return the preferred name if it was unique */ + if (preferred) + return g_strdup(preferred); + + /* Otherwise, find the next available unique connection name using the given + * connection name template. + */ + for (i = 1; TRUE; i++) { + char *temp; + + /* 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 + * connection id. */ + temp = g_strdup_printf(C_("connection id fallback", "%s %u"), fallback_prefix, i); + + if (nm_utils_strv_find_first((char **) existing_names, existing_len, temp) < 0) + return temp; + + g_free(temp); + } } static char * -get_new_connection_ifname (NMPlatform *platform, - NMConnection *const*existing_connections, - const char *prefix) +get_new_connection_ifname(NMPlatform * platform, + NMConnection *const *existing_connections, + const char * prefix) { - guint i, j; + guint i, j; - for (i = 0; TRUE; i++) { - char *name; + for (i = 0; TRUE; i++) { + char *name; - name = g_strdup_printf ("%s%d", prefix, i); + name = g_strdup_printf("%s%d", prefix, i); - if (nm_platform_link_get_by_ifname (platform, name)) - goto next; + if (nm_platform_link_get_by_ifname(platform, name)) + goto next; - if (existing_connections) { - for (j = 0; existing_connections[j]; j++) { - if (nm_streq0 (nm_connection_get_interface_name (existing_connections[j]), - name)) - goto next; - } - } + if (existing_connections) { + for (j = 0; existing_connections[j]; j++) { + if (nm_streq0(nm_connection_get_interface_name(existing_connections[j]), name)) + goto next; + } + } - return name; + return name; next: - g_free (name); - } + g_free(name); + } } const char * -nm_utils_get_ip_config_method (NMConnection *connection, - int addr_family) +nm_utils_get_ip_config_method(NMConnection *connection, int addr_family) { - NMSettingConnection *s_con; - NMSettingIPConfig *s_ip; - const char *method; + NMSettingConnection *s_con; + NMSettingIPConfig * s_ip; + const char * method; - s_con = nm_connection_get_setting_connection (connection); + s_con = nm_connection_get_setting_connection(connection); - if (addr_family == AF_INET) { - g_return_val_if_fail (s_con != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + if (addr_family == AF_INET) { + g_return_val_if_fail(s_con != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - s_ip = nm_connection_get_setting_ip4_config (connection); - if (!s_ip) - return NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + s_ip = nm_connection_get_setting_ip4_config(connection); + if (!s_ip) + return NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - method = nm_setting_ip_config_get_method (s_ip); - g_return_val_if_fail (method != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - return method; - } + method = nm_setting_ip_config_get_method(s_ip); + g_return_val_if_fail(method != NULL, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + return method; + } - if (addr_family == AF_INET6) { - g_return_val_if_fail (s_con != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + if (addr_family == AF_INET6) { + g_return_val_if_fail(s_con != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - s_ip = nm_connection_get_setting_ip6_config (connection); - if (!s_ip) - return NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + s_ip = nm_connection_get_setting_ip6_config(connection); + if (!s_ip) + return NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - method = nm_setting_ip_config_get_method (s_ip); - g_return_val_if_fail (method != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - return method; - } + method = nm_setting_ip_config_get_method(s_ip); + g_return_val_if_fail(method != NULL, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + return method; + } - g_return_val_if_reached ("" /* bogus */); + g_return_val_if_reached("" /* bogus */); } gboolean -nm_utils_connection_has_default_route (NMConnection *connection, - int addr_family, - gboolean *out_is_never_default) +nm_utils_connection_has_default_route(NMConnection *connection, + int addr_family, + gboolean * out_is_never_default) { - const char *method; - NMSettingIPConfig *s_ip; - gboolean is_never_default = FALSE; - gboolean has_default_route = FALSE; - - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); - - if (!connection) - goto out; - - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - if (!s_ip) - goto out; - if (nm_setting_ip_config_get_never_default (s_ip)) { - is_never_default = TRUE; - goto out; - } - - method = nm_utils_get_ip_config_method (connection, addr_family); - if (addr_family == AF_INET) { - if (NM_IN_STRSET (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) - goto out; - } else { - if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - goto out; - } - - has_default_route = TRUE; + const char * method; + NMSettingIPConfig *s_ip; + gboolean is_never_default = FALSE; + gboolean has_default_route = FALSE; + + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); + g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE); + + if (!connection) + goto out; + + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); + if (!s_ip) + goto out; + if (nm_setting_ip_config_get_never_default(s_ip)) { + is_never_default = TRUE; + goto out; + } + + method = nm_utils_get_ip_config_method(connection, addr_family); + if (addr_family == AF_INET) { + if (NM_IN_STRSET(method, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) + goto out; + } else { + if (NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED, + NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) + goto out; + } + + has_default_route = TRUE; out: - NM_SET_OUT (out_is_never_default, is_never_default); - return has_default_route; + NM_SET_OUT(out_is_never_default, is_never_default); + return has_default_route; } /*****************************************************************************/ void -nm_utils_complete_generic (NMPlatform *platform, - NMConnection *connection, - const char *ctype, - NMConnection *const*existing_connections, - const char *preferred_id, - const char *fallback_id_prefix, - const char *ifname_prefix, - const char *ifname, - gboolean default_enable_ipv6) +nm_utils_complete_generic(NMPlatform * platform, + NMConnection * connection, + const char * ctype, + NMConnection *const *existing_connections, + const char * preferred_id, + const char * fallback_id_prefix, + const char * ifname_prefix, + const char * ifname, + gboolean default_enable_ipv6) { - NMSettingConnection *s_con; - char *id, *generated_ifname; - GHashTable *parameters; - - g_assert (fallback_id_prefix); - g_return_if_fail (ifname_prefix == NULL || ifname == NULL); - - s_con = nm_connection_get_setting_connection (connection); - if (!s_con) { - s_con = (NMSettingConnection *) nm_setting_connection_new (); - nm_connection_add_setting (connection, NM_SETTING (s_con)); - } - g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_TYPE, ctype, NULL); - - if (!nm_setting_connection_get_uuid (s_con)) { - char uuid[37]; - - g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), NULL); - } - - /* Add a connection ID if absent */ - if (!nm_setting_connection_get_id (s_con)) { - id = get_new_connection_name (existing_connections, preferred_id, fallback_id_prefix); - g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_ID, id, NULL); - g_free (id); - } - - /* Add an interface name, if requested */ - if (ifname) { - g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NULL); - } else if (ifname_prefix && !nm_setting_connection_get_interface_name (s_con)) { - generated_ifname = get_new_connection_ifname (platform, existing_connections, ifname_prefix); - g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_INTERFACE_NAME, generated_ifname, NULL); - g_free (generated_ifname); - } - - /* Normalize */ - parameters = g_hash_table_new (nm_str_hash, g_str_equal); - g_hash_table_insert (parameters, NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD, - default_enable_ipv6 ? NM_SETTING_IP6_CONFIG_METHOD_AUTO : NM_SETTING_IP6_CONFIG_METHOD_IGNORE); - nm_connection_normalize (connection, parameters, NULL, NULL); - g_hash_table_destroy (parameters); + NMSettingConnection *s_con; + char * id, *generated_ifname; + GHashTable * parameters; + + g_assert(fallback_id_prefix); + g_return_if_fail(ifname_prefix == NULL || ifname == NULL); + + s_con = nm_connection_get_setting_connection(connection); + if (!s_con) { + s_con = (NMSettingConnection *) nm_setting_connection_new(); + nm_connection_add_setting(connection, NM_SETTING(s_con)); + } + g_object_set(G_OBJECT(s_con), NM_SETTING_CONNECTION_TYPE, ctype, NULL); + + if (!nm_setting_connection_get_uuid(s_con)) { + char uuid[37]; + + g_object_set(G_OBJECT(s_con), + NM_SETTING_CONNECTION_UUID, + nm_utils_uuid_generate_buf(uuid), + NULL); + } + + /* Add a connection ID if absent */ + if (!nm_setting_connection_get_id(s_con)) { + id = get_new_connection_name(existing_connections, preferred_id, fallback_id_prefix); + g_object_set(G_OBJECT(s_con), NM_SETTING_CONNECTION_ID, id, NULL); + g_free(id); + } + + /* Add an interface name, if requested */ + if (ifname) { + g_object_set(G_OBJECT(s_con), NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NULL); + } else if (ifname_prefix && !nm_setting_connection_get_interface_name(s_con)) { + generated_ifname = get_new_connection_ifname(platform, existing_connections, ifname_prefix); + g_object_set(G_OBJECT(s_con), NM_SETTING_CONNECTION_INTERFACE_NAME, generated_ifname, NULL); + g_free(generated_ifname); + } + + /* Normalize */ + parameters = g_hash_table_new(nm_str_hash, g_str_equal); + g_hash_table_insert(parameters, + NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD, + default_enable_ipv6 ? NM_SETTING_IP6_CONFIG_METHOD_AUTO + : NM_SETTING_IP6_CONFIG_METHOD_IGNORE); + nm_connection_normalize(connection, parameters, NULL, NULL); + g_hash_table_destroy(parameters); } /*****************************************************************************/ static GHashTable * -check_property_in_hash (GHashTable *hash, - const char *s_name, - const char *p_name) +check_property_in_hash(GHashTable *hash, const char *s_name, const char *p_name) { - GHashTable *props; - - props = g_hash_table_lookup (hash, s_name); - if ( !props - || !g_hash_table_lookup (props, p_name)) { - return NULL; - } - return props; + GHashTable *props; + + props = g_hash_table_lookup(hash, s_name); + if (!props || !g_hash_table_lookup(props, p_name)) { + return NULL; + } + return props; } static void -remove_from_hash (GHashTable *s_hash, - GHashTable *p_hash, - const char *s_name, - const char *p_name) +remove_from_hash(GHashTable *s_hash, GHashTable *p_hash, const char *s_name, const char *p_name) { - if (!p_hash) - return; + if (!p_hash) + return; - g_hash_table_remove (p_hash, p_name); - if (g_hash_table_size (p_hash) == 0) - g_hash_table_remove (s_hash, s_name); + g_hash_table_remove(p_hash, p_name); + if (g_hash_table_size(p_hash) == 0) + g_hash_table_remove(s_hash, s_name); } static gboolean -check_ip6_method (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings) +check_ip6_method(NMConnection *orig, NMConnection *candidate, GHashTable *settings) { - GHashTable *props; - const char *orig_ip6_method, *candidate_ip6_method; - NMSettingIPConfig *candidate_ip6; - gboolean allow = FALSE; - - props = check_property_in_hash (settings, - NM_SETTING_IP6_CONFIG_SETTING_NAME, - NM_SETTING_IP_CONFIG_METHOD); - if (!props) - return TRUE; - - orig_ip6_method = nm_utils_get_ip_config_method (orig, AF_INET6); - candidate_ip6_method = nm_utils_get_ip_config_method (candidate, AF_INET6); - candidate_ip6 = nm_connection_get_setting_ip6_config (candidate); - - if ( nm_streq (orig_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) - && nm_streq (candidate_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) - && ( !candidate_ip6 - || nm_setting_ip_config_get_may_fail (candidate_ip6))) { - /* If the generated connection is 'link-local' and the candidate is both 'auto' - * and may-fail=TRUE, then the candidate is OK to use. may-fail is included - * in the decision because if the candidate is 'auto' but may-fail=FALSE, then - * the connection could not possibly have been previously activated on the - * device if the device has no non-link-local IPv6 address. - */ - allow = TRUE; - } else if ( NM_IN_STRSET (orig_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED, - NM_SETTING_IP6_CONFIG_METHOD_AUTO) - && nm_streq0 (candidate_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { - /* If the generated connection method is 'link-local', disabled' or 'auto' and - * the candidate method is 'ignore' we can take the connection, because NM didn't - * simply take care of IPv6. - */ - allow = TRUE; - } - - if (allow) { - remove_from_hash (settings, props, - NM_SETTING_IP6_CONFIG_SETTING_NAME, - NM_SETTING_IP_CONFIG_METHOD); - } - - return allow; + GHashTable * props; + const char * orig_ip6_method, *candidate_ip6_method; + NMSettingIPConfig *candidate_ip6; + gboolean allow = FALSE; + + props = check_property_in_hash(settings, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_METHOD); + if (!props) + return TRUE; + + orig_ip6_method = nm_utils_get_ip_config_method(orig, AF_INET6); + candidate_ip6_method = nm_utils_get_ip_config_method(candidate, AF_INET6); + candidate_ip6 = nm_connection_get_setting_ip6_config(candidate); + + if (nm_streq(orig_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) + && nm_streq(candidate_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) + && (!candidate_ip6 || nm_setting_ip_config_get_may_fail(candidate_ip6))) { + /* If the generated connection is 'link-local' and the candidate is both 'auto' + * and may-fail=TRUE, then the candidate is OK to use. may-fail is included + * in the decision because if the candidate is 'auto' but may-fail=FALSE, then + * the connection could not possibly have been previously activated on the + * device if the device has no non-link-local IPv6 address. + */ + allow = TRUE; + } else if (NM_IN_STRSET(orig_ip6_method, + NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED, + NM_SETTING_IP6_CONFIG_METHOD_AUTO) + && nm_streq0(candidate_ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + /* If the generated connection method is 'link-local', disabled' or 'auto' and + * the candidate method is 'ignore' we can take the connection, because NM didn't + * simply take care of IPv6. + */ + allow = TRUE; + } + + if (allow) { + remove_from_hash(settings, + props, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_METHOD); + } + + return allow; } static int -route_compare (NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric) +route_compare(NMIPRoute *route1, NMIPRoute *route2, gint64 default_metric) { - NMIPAddr a1; - NMIPAddr a2; - guint64 m1; - guint64 m2; - int family; - guint plen; - - family = nm_ip_route_get_family (route1); - NM_CMP_DIRECT (family, nm_ip_route_get_family (route2)); - - nm_assert_addr_family (family); - - plen = nm_ip_route_get_prefix (route1); - NM_CMP_DIRECT (plen, nm_ip_route_get_prefix (route2)); - - m1 = nm_ip_route_get_metric (route1); - m2 = nm_ip_route_get_metric (route2); - NM_CMP_DIRECT (m1 == -1 ? default_metric : m1, - m2 == -1 ? default_metric : m2); - - NM_CMP_DIRECT_STRCMP0 (nm_ip_route_get_next_hop (route1), - nm_ip_route_get_next_hop (route2)); - - if (!inet_pton (family, nm_ip_route_get_dest (route1), &a1)) - nm_assert_not_reached (); - if (!inet_pton (family, nm_ip_route_get_dest (route2), &a2)) - nm_assert_not_reached (); - nm_utils_ipx_address_clear_host_address (family, &a1, NULL, plen); - nm_utils_ipx_address_clear_host_address (family, &a2, NULL, plen); - NM_CMP_DIRECT_MEMCMP (&a1, &a2, nm_utils_addr_family_to_size (family)); - - return 0; + NMIPAddr a1; + NMIPAddr a2; + guint64 m1; + guint64 m2; + int family; + guint plen; + + family = nm_ip_route_get_family(route1); + NM_CMP_DIRECT(family, nm_ip_route_get_family(route2)); + + nm_assert_addr_family(family); + + plen = nm_ip_route_get_prefix(route1); + NM_CMP_DIRECT(plen, nm_ip_route_get_prefix(route2)); + + m1 = nm_ip_route_get_metric(route1); + m2 = nm_ip_route_get_metric(route2); + NM_CMP_DIRECT(m1 == -1 ? default_metric : m1, m2 == -1 ? default_metric : m2); + + NM_CMP_DIRECT_STRCMP0(nm_ip_route_get_next_hop(route1), nm_ip_route_get_next_hop(route2)); + + if (!inet_pton(family, nm_ip_route_get_dest(route1), &a1)) + nm_assert_not_reached(); + if (!inet_pton(family, nm_ip_route_get_dest(route2), &a2)) + nm_assert_not_reached(); + nm_utils_ipx_address_clear_host_address(family, &a1, NULL, plen); + nm_utils_ipx_address_clear_host_address(family, &a2, NULL, plen); + NM_CMP_DIRECT_MEMCMP(&a1, &a2, nm_utils_addr_family_to_size(family)); + + return 0; } static int -route_ptr_compare (const void *a, const void *b, gpointer metric) +route_ptr_compare(const void *a, const void *b, gpointer metric) { - return route_compare (*(NMIPRoute **) a, *(NMIPRoute **) b, *((gint64 *) metric)); + return route_compare(*(NMIPRoute **) a, *(NMIPRoute **) b, *((gint64 *) metric)); } static gboolean -check_ip_routes (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings, - gint64 default_metric, - gboolean v4) +check_ip_routes(NMConnection *orig, + NMConnection *candidate, + GHashTable * settings, + gint64 default_metric, + gboolean v4) { - gs_free NMIPRoute **routes1 = NULL; - NMIPRoute **routes2; - NMSettingIPConfig *s_ip1, *s_ip2; - gint64 m; - const char *s_name; - GHashTable *props; - guint i, i1, i2, num1, num2; - const guint8 PLEN = v4 ? 32 : 128; - - s_name = v4 ? NM_SETTING_IP4_CONFIG_SETTING_NAME : - NM_SETTING_IP6_CONFIG_SETTING_NAME; - - props = check_property_in_hash (settings, - s_name, - NM_SETTING_IP_CONFIG_ROUTES); - if (!props) - return TRUE; - - s_ip1 = (NMSettingIPConfig *) nm_connection_get_setting_by_name (orig, s_name); - s_ip2 = (NMSettingIPConfig *) nm_connection_get_setting_by_name (candidate, s_name); - - if (!s_ip1 || !s_ip2) - return FALSE; - - num1 = nm_setting_ip_config_get_num_routes (s_ip1); - num2 = nm_setting_ip_config_get_num_routes (s_ip2); - - routes1 = g_new (NMIPRoute *, (gsize) num1 + num2); - routes2 = &routes1[num1]; - - for (i = 0; i < num1; i++) - routes1[i] = nm_setting_ip_config_get_route (s_ip1, i); - for (i = 0; i < num2; i++) - routes2[i] = nm_setting_ip_config_get_route (s_ip2, i); - - m = nm_setting_ip_config_get_route_metric (s_ip2); - if (m != -1) - default_metric = m; - - g_qsort_with_data (routes1, num1, sizeof (NMIPRoute *), route_ptr_compare, &default_metric); - g_qsort_with_data (routes2, num2, sizeof (NMIPRoute *), route_ptr_compare, &default_metric); - - for (i1 = 0, i2 = 0; i2 < num2; i1++) { - if (i1 >= num1) - return FALSE; - if (route_compare (routes1[i1], routes2[i2], default_metric) == 0) { - i2++; - continue; - } - - /* if @orig (@routes1) contains /32 routes that are missing in @candidate, - * we accept that. - * - * A /32 may have been added automatically, as a direct-route to the gateway. - * The generated connection (@orig) would contain that route, so we shall ignore - * it. - * - * Likeweise for /128 for IPv6. */ - if (nm_ip_route_get_prefix (routes1[i1]) == PLEN) - continue; - - return FALSE; - } - - /* check that @orig has no left-over (except host routes that we ignore). */ - for (; i1 < num1; i1++) { - if (nm_ip_route_get_prefix (routes1[i1]) != PLEN) - return FALSE; - } - - remove_from_hash (settings, props, s_name, NM_SETTING_IP_CONFIG_ROUTES); - return TRUE; + gs_free NMIPRoute **routes1 = NULL; + NMIPRoute ** routes2; + NMSettingIPConfig * s_ip1, *s_ip2; + gint64 m; + const char * s_name; + GHashTable * props; + guint i, i1, i2, num1, num2; + const guint8 PLEN = v4 ? 32 : 128; + + s_name = v4 ? NM_SETTING_IP4_CONFIG_SETTING_NAME : NM_SETTING_IP6_CONFIG_SETTING_NAME; + + props = check_property_in_hash(settings, s_name, NM_SETTING_IP_CONFIG_ROUTES); + if (!props) + return TRUE; + + s_ip1 = (NMSettingIPConfig *) nm_connection_get_setting_by_name(orig, s_name); + s_ip2 = (NMSettingIPConfig *) nm_connection_get_setting_by_name(candidate, s_name); + + if (!s_ip1 || !s_ip2) + return FALSE; + + num1 = nm_setting_ip_config_get_num_routes(s_ip1); + num2 = nm_setting_ip_config_get_num_routes(s_ip2); + + routes1 = g_new(NMIPRoute *, (gsize) num1 + num2); + routes2 = &routes1[num1]; + + for (i = 0; i < num1; i++) + routes1[i] = nm_setting_ip_config_get_route(s_ip1, i); + for (i = 0; i < num2; i++) + routes2[i] = nm_setting_ip_config_get_route(s_ip2, i); + + m = nm_setting_ip_config_get_route_metric(s_ip2); + if (m != -1) + default_metric = m; + + g_qsort_with_data(routes1, num1, sizeof(NMIPRoute *), route_ptr_compare, &default_metric); + g_qsort_with_data(routes2, num2, sizeof(NMIPRoute *), route_ptr_compare, &default_metric); + + for (i1 = 0, i2 = 0; i2 < num2; i1++) { + if (i1 >= num1) + return FALSE; + if (route_compare(routes1[i1], routes2[i2], default_metric) == 0) { + i2++; + continue; + } + + /* if @orig (@routes1) contains /32 routes that are missing in @candidate, + * we accept that. + * + * A /32 may have been added automatically, as a direct-route to the gateway. + * The generated connection (@orig) would contain that route, so we shall ignore + * it. + * + * Likeweise for /128 for IPv6. */ + if (nm_ip_route_get_prefix(routes1[i1]) == PLEN) + continue; + + return FALSE; + } + + /* check that @orig has no left-over (except host routes that we ignore). */ + for (; i1 < num1; i1++) { + if (nm_ip_route_get_prefix(routes1[i1]) != PLEN) + return FALSE; + } + + remove_from_hash(settings, props, s_name, NM_SETTING_IP_CONFIG_ROUTES); + return TRUE; } static gboolean -check_ip4_method (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings, - gboolean device_has_carrier) +check_ip4_method(NMConnection *orig, + NMConnection *candidate, + GHashTable * settings, + gboolean device_has_carrier) { - GHashTable *props; - const char *orig_ip4_method, *candidate_ip4_method; - NMSettingIPConfig *candidate_ip4; - - props = check_property_in_hash (settings, - NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP_CONFIG_METHOD); - if (!props) - return TRUE; - - orig_ip4_method = nm_utils_get_ip_config_method (orig, AF_INET); - candidate_ip4_method = nm_utils_get_ip_config_method (candidate, AF_INET); - candidate_ip4 = nm_connection_get_setting_ip4_config (candidate); - - if ( nm_streq (orig_ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) - && nm_streq (candidate_ip4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) - && ( !candidate_ip4 - || nm_setting_ip_config_get_may_fail (candidate_ip4)) - && !device_has_carrier) { - /* If the generated connection is 'disabled' (device had no IP addresses) - * but it has no carrier, that most likely means that IP addressing could - * not complete and thus no IP addresses were assigned. In that case, allow - * matching to the "auto" method. - */ - remove_from_hash (settings, props, - NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP_CONFIG_METHOD); - return TRUE; - } - return FALSE; + GHashTable * props; + const char * orig_ip4_method, *candidate_ip4_method; + NMSettingIPConfig *candidate_ip4; + + props = check_property_in_hash(settings, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_METHOD); + if (!props) + return TRUE; + + orig_ip4_method = nm_utils_get_ip_config_method(orig, AF_INET); + candidate_ip4_method = nm_utils_get_ip_config_method(candidate, AF_INET); + candidate_ip4 = nm_connection_get_setting_ip4_config(candidate); + + if (nm_streq(orig_ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) + && nm_streq(candidate_ip4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) + && (!candidate_ip4 || nm_setting_ip_config_get_may_fail(candidate_ip4)) + && !device_has_carrier) { + /* If the generated connection is 'disabled' (device had no IP addresses) + * but it has no carrier, that most likely means that IP addressing could + * not complete and thus no IP addresses were assigned. In that case, allow + * matching to the "auto" method. + */ + remove_from_hash(settings, + props, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP_CONFIG_METHOD); + return TRUE; + } + return FALSE; } static gboolean -check_connection_interface_name (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings) +check_connection_interface_name(NMConnection *orig, NMConnection *candidate, GHashTable *settings) { - GHashTable *props; - const char *orig_ifname, *cand_ifname; - NMSettingConnection *s_con_orig, *s_con_cand; - - props = check_property_in_hash (settings, - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_INTERFACE_NAME); - if (!props) - return TRUE; - - /* If one of the interface names is NULL, we accept that connection */ - s_con_orig = nm_connection_get_setting_connection (orig); - s_con_cand = nm_connection_get_setting_connection (candidate); - orig_ifname = nm_setting_connection_get_interface_name (s_con_orig); - cand_ifname = nm_setting_connection_get_interface_name (s_con_cand); - - if (!orig_ifname || !cand_ifname) { - remove_from_hash (settings, props, - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_INTERFACE_NAME); - return TRUE; - } - return FALSE; + GHashTable * props; + const char * orig_ifname, *cand_ifname; + NMSettingConnection *s_con_orig, *s_con_cand; + + props = check_property_in_hash(settings, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME); + if (!props) + return TRUE; + + /* If one of the interface names is NULL, we accept that connection */ + s_con_orig = nm_connection_get_setting_connection(orig); + s_con_cand = nm_connection_get_setting_connection(candidate); + orig_ifname = nm_setting_connection_get_interface_name(s_con_orig); + cand_ifname = nm_setting_connection_get_interface_name(s_con_cand); + + if (!orig_ifname || !cand_ifname) { + remove_from_hash(settings, + props, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME); + return TRUE; + } + return FALSE; } static gboolean -check_connection_mac_address (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings) +check_connection_mac_address(NMConnection *orig, NMConnection *candidate, GHashTable *settings) { - GHashTable *props; - const char *orig_mac = NULL, *cand_mac = NULL; - NMSettingWired *s_wired_orig, *s_wired_cand; - - props = check_property_in_hash (settings, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_MAC_ADDRESS); - if (!props) - return TRUE; - - /* If one of the MAC addresses is NULL, we accept that connection */ - s_wired_orig = nm_connection_get_setting_wired (orig); - if (s_wired_orig) - orig_mac = nm_setting_wired_get_mac_address (s_wired_orig); - - s_wired_cand = nm_connection_get_setting_wired (candidate); - if (s_wired_cand) - cand_mac = nm_setting_wired_get_mac_address (s_wired_cand); - - if (!orig_mac || !cand_mac) { - remove_from_hash (settings, props, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_MAC_ADDRESS); - return TRUE; - } - return FALSE; + GHashTable * props; + const char * orig_mac = NULL, *cand_mac = NULL; + NMSettingWired *s_wired_orig, *s_wired_cand; + + props = check_property_in_hash(settings, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + if (!props) + return TRUE; + + /* If one of the MAC addresses is NULL, we accept that connection */ + s_wired_orig = nm_connection_get_setting_wired(orig); + if (s_wired_orig) + orig_mac = nm_setting_wired_get_mac_address(s_wired_orig); + + s_wired_cand = nm_connection_get_setting_wired(candidate); + if (s_wired_cand) + cand_mac = nm_setting_wired_get_mac_address(s_wired_cand); + + if (!orig_mac || !cand_mac) { + remove_from_hash(settings, + props, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + return TRUE; + } + return FALSE; } static gboolean -check_connection_infiniband_mac_address (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings) +check_connection_infiniband_mac_address(NMConnection *orig, + NMConnection *candidate, + GHashTable * settings) { - GHashTable *props; - const char *orig_mac = NULL, *cand_mac = NULL; - NMSettingInfiniband *s_infiniband_orig, *s_infiniband_cand; - - props = check_property_in_hash (settings, - NM_SETTING_INFINIBAND_SETTING_NAME, - NM_SETTING_INFINIBAND_MAC_ADDRESS); - if (!props) - return TRUE; - - /* If one of the MAC addresses is NULL, we accept that connection */ - s_infiniband_orig = nm_connection_get_setting_infiniband (orig); - if (s_infiniband_orig) - orig_mac = nm_setting_infiniband_get_mac_address (s_infiniband_orig); - - s_infiniband_cand = nm_connection_get_setting_infiniband (candidate); - if (s_infiniband_cand) - cand_mac = nm_setting_infiniband_get_mac_address (s_infiniband_cand); - - if (!orig_mac || !cand_mac) { - remove_from_hash (settings, props, - NM_SETTING_INFINIBAND_SETTING_NAME, - NM_SETTING_INFINIBAND_MAC_ADDRESS); - return TRUE; - } - return FALSE; + GHashTable * props; + const char * orig_mac = NULL, *cand_mac = NULL; + NMSettingInfiniband *s_infiniband_orig, *s_infiniband_cand; + + props = check_property_in_hash(settings, + NM_SETTING_INFINIBAND_SETTING_NAME, + NM_SETTING_INFINIBAND_MAC_ADDRESS); + if (!props) + return TRUE; + + /* If one of the MAC addresses is NULL, we accept that connection */ + s_infiniband_orig = nm_connection_get_setting_infiniband(orig); + if (s_infiniband_orig) + orig_mac = nm_setting_infiniband_get_mac_address(s_infiniband_orig); + + s_infiniband_cand = nm_connection_get_setting_infiniband(candidate); + if (s_infiniband_cand) + cand_mac = nm_setting_infiniband_get_mac_address(s_infiniband_cand); + + if (!orig_mac || !cand_mac) { + remove_from_hash(settings, + props, + NM_SETTING_INFINIBAND_SETTING_NAME, + NM_SETTING_INFINIBAND_MAC_ADDRESS); + return TRUE; + } + return FALSE; } static gboolean -check_connection_cloned_mac_address (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings) +check_connection_cloned_mac_address(NMConnection *orig, + NMConnection *candidate, + GHashTable * settings) { - GHashTable *props; - const char *orig_mac = NULL, *cand_mac = NULL; - NMSettingWired *s_wired_orig, *s_wired_cand; - - props = check_property_in_hash (settings, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_CLONED_MAC_ADDRESS); - if (!props) - return TRUE; - - /* If one of the MAC addresses is NULL, we accept that connection */ - s_wired_orig = nm_connection_get_setting_wired (orig); - if (s_wired_orig) - orig_mac = nm_setting_wired_get_cloned_mac_address (s_wired_orig); - - s_wired_cand = nm_connection_get_setting_wired (candidate); - if (s_wired_cand) - cand_mac = nm_setting_wired_get_cloned_mac_address (s_wired_cand); - - /* special cloned mac address entries are accepted. */ - if (NM_CLONED_MAC_IS_SPECIAL (orig_mac)) - orig_mac = NULL; - if (NM_CLONED_MAC_IS_SPECIAL (cand_mac)) - cand_mac = NULL; - - if (!orig_mac || !cand_mac) { - remove_from_hash (settings, props, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_CLONED_MAC_ADDRESS); - return TRUE; - } - return FALSE; + GHashTable * props; + const char * orig_mac = NULL, *cand_mac = NULL; + NMSettingWired *s_wired_orig, *s_wired_cand; + + props = check_property_in_hash(settings, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_CLONED_MAC_ADDRESS); + if (!props) + return TRUE; + + /* If one of the MAC addresses is NULL, we accept that connection */ + s_wired_orig = nm_connection_get_setting_wired(orig); + if (s_wired_orig) + orig_mac = nm_setting_wired_get_cloned_mac_address(s_wired_orig); + + s_wired_cand = nm_connection_get_setting_wired(candidate); + if (s_wired_cand) + cand_mac = nm_setting_wired_get_cloned_mac_address(s_wired_cand); + + /* special cloned mac address entries are accepted. */ + if (NM_CLONED_MAC_IS_SPECIAL(orig_mac)) + orig_mac = NULL; + if (NM_CLONED_MAC_IS_SPECIAL(cand_mac)) + cand_mac = NULL; + + if (!orig_mac || !cand_mac) { + remove_from_hash(settings, + props, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_CLONED_MAC_ADDRESS); + return TRUE; + } + return FALSE; } static gboolean -check_connection_s390_props (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings) +check_connection_s390_props(NMConnection *orig, NMConnection *candidate, GHashTable *settings) { - GHashTable *props1, *props2, *props3; - NMSettingWired *s_wired_orig, *s_wired_cand; - - props1 = check_property_in_hash (settings, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_S390_SUBCHANNELS); - props2 = check_property_in_hash (settings, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_S390_NETTYPE); - props3 = check_property_in_hash (settings, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_S390_OPTIONS); - if (!props1 && !props2 && !props3) - return TRUE; - - /* If the generated connection did not contain wired setting, - * allow it to match to a connection with a wired setting, - * but default (empty) s390-* properties */ - s_wired_orig = nm_connection_get_setting_wired (orig); - s_wired_cand = nm_connection_get_setting_wired (candidate); - if (!s_wired_orig && s_wired_cand) { - const char * const *subchans = nm_setting_wired_get_s390_subchannels (s_wired_cand); - const char *nettype = nm_setting_wired_get_s390_nettype (s_wired_cand); - guint32 num_options = nm_setting_wired_get_num_s390_options (s_wired_cand); - - if ((!subchans || !*subchans) && !nettype && num_options == 0) { - remove_from_hash (settings, props1, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_S390_SUBCHANNELS); - remove_from_hash (settings, props2, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_S390_NETTYPE); - remove_from_hash (settings, props3, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_S390_OPTIONS); - return TRUE; - } - } - return FALSE; + GHashTable * props1, *props2, *props3; + NMSettingWired *s_wired_orig, *s_wired_cand; + + props1 = check_property_in_hash(settings, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_S390_SUBCHANNELS); + props2 = check_property_in_hash(settings, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_S390_NETTYPE); + props3 = check_property_in_hash(settings, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_S390_OPTIONS); + if (!props1 && !props2 && !props3) + return TRUE; + + /* If the generated connection did not contain wired setting, + * allow it to match to a connection with a wired setting, + * but default (empty) s390-* properties */ + s_wired_orig = nm_connection_get_setting_wired(orig); + s_wired_cand = nm_connection_get_setting_wired(candidate); + if (!s_wired_orig && s_wired_cand) { + const char *const *subchans = nm_setting_wired_get_s390_subchannels(s_wired_cand); + const char * nettype = nm_setting_wired_get_s390_nettype(s_wired_cand); + guint32 num_options = nm_setting_wired_get_num_s390_options(s_wired_cand); + + if ((!subchans || !*subchans) && !nettype && num_options == 0) { + remove_from_hash(settings, + props1, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_S390_SUBCHANNELS); + remove_from_hash(settings, + props2, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_S390_NETTYPE); + remove_from_hash(settings, + props3, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_S390_OPTIONS); + return TRUE; + } + } + return FALSE; } static NMConnection * -check_possible_match (NMConnection *orig, - NMConnection *candidate, - GHashTable *settings, - gboolean device_has_carrier, - gint64 default_v4_metric, - gint64 default_v6_metric) +check_possible_match(NMConnection *orig, + NMConnection *candidate, + GHashTable * settings, + gboolean device_has_carrier, + gint64 default_v4_metric, + gint64 default_v6_metric) { - g_return_val_if_fail (settings != NULL, NULL); + g_return_val_if_fail(settings != NULL, NULL); - if (!check_ip6_method (orig, candidate, settings)) - return NULL; + if (!check_ip6_method(orig, candidate, settings)) + return NULL; - if (!check_ip4_method (orig, candidate, settings, device_has_carrier)) - return NULL; + if (!check_ip4_method(orig, candidate, settings, device_has_carrier)) + return NULL; - if (!check_ip_routes (orig, candidate, settings, default_v4_metric, TRUE)) - return NULL; + if (!check_ip_routes(orig, candidate, settings, default_v4_metric, TRUE)) + return NULL; - if (!check_ip_routes (orig, candidate, settings, default_v6_metric, FALSE)) - return NULL; + if (!check_ip_routes(orig, candidate, settings, default_v6_metric, FALSE)) + return NULL; - if (!check_connection_interface_name (orig, candidate, settings)) - return NULL; + if (!check_connection_interface_name(orig, candidate, settings)) + return NULL; - if (!check_connection_mac_address (orig, candidate, settings)) - return NULL; + if (!check_connection_mac_address(orig, candidate, settings)) + return NULL; - if (!check_connection_infiniband_mac_address (orig, candidate, settings)) - return NULL; + if (!check_connection_infiniband_mac_address(orig, candidate, settings)) + return NULL; - if (!check_connection_cloned_mac_address (orig, candidate, settings)) - return NULL; + if (!check_connection_cloned_mac_address(orig, candidate, settings)) + return NULL; - if (!check_connection_s390_props (orig, candidate, settings)) - return NULL; + if (!check_connection_s390_props(orig, candidate, settings)) + return NULL; - if (g_hash_table_size (settings) == 0) - return candidate; - else - return NULL; + if (g_hash_table_size(settings) == 0) + return candidate; + else + return NULL; } /** @@ -778,205 +768,213 @@ check_possible_match (NMConnection *orig, * matches well enough. */ NMConnection * -nm_utils_match_connection (NMConnection *const*connections, - NMConnection *original, - gboolean indicated, - gboolean device_has_carrier, - gint64 default_v4_metric, - gint64 default_v6_metric, - NMUtilsMatchFilterFunc match_filter_func, - gpointer match_filter_data) +nm_utils_match_connection(NMConnection *const * connections, + NMConnection * original, + gboolean indicated, + gboolean device_has_carrier, + gint64 default_v4_metric, + gint64 default_v6_metric, + NMUtilsMatchFilterFunc match_filter_func, + gpointer match_filter_data) { - NMConnection *best_match = NULL; - - if (!connections) - return NULL; - - for (; *connections; connections++) { - NMConnection *candidate = *connections; - GHashTable *diffs = NULL; - - nm_assert (NM_IS_CONNECTION (candidate)); - - if (match_filter_func) { - if (!match_filter_func (candidate, match_filter_data)) - continue; - } - - if (indicated) { - NMSettingConnection *s_orig, *s_cand; - - s_orig = nm_connection_get_setting_connection (original); - s_cand = nm_connection_get_setting_connection (candidate); - - /* It is indicated that this connection matches. Assume we have - * a match, but check for particular differences that let us - * reject the candidate. */ - if (!nm_streq0 (nm_setting_connection_get_connection_type (s_orig), - nm_setting_connection_get_connection_type (s_cand))) - continue; - if (!nm_streq0 (nm_setting_connection_get_slave_type (s_orig), - nm_setting_connection_get_slave_type (s_cand))) - continue; - - /* this is good enough for a match */ - } else if (!nm_connection_diff (original, candidate, NM_SETTING_COMPARE_FLAG_INFERRABLE, &diffs)) { - if (!best_match) { - best_match = check_possible_match (original, candidate, diffs, device_has_carrier, - default_v4_metric, default_v6_metric); - } - - if (!best_match && nm_logging_enabled (LOGL_DEBUG, LOGD_CORE)) { - GString *diff_string; - GHashTableIter s_iter, p_iter; - gpointer setting_name, setting; - gpointer property_name, value; - - diff_string = g_string_new (NULL); - g_hash_table_iter_init (&s_iter, diffs); - while (g_hash_table_iter_next (&s_iter, &setting_name, &setting)) { - g_hash_table_iter_init (&p_iter, setting); - while (g_hash_table_iter_next (&p_iter, &property_name, &value)) { - if (diff_string->len) - g_string_append (diff_string, ", "); - g_string_append_printf (diff_string, "%s.%s", - (char *) setting_name, - (char *) property_name); - } - } - - nm_log_dbg (LOGD_CORE, "Connection '%s' differs from candidate '%s' in %s", - nm_connection_get_id (original), - nm_connection_get_id (candidate), - diff_string->str); - g_string_free (diff_string, TRUE); - } - - g_hash_table_unref (diffs); - continue; - } - - /* Exact match */ - return candidate; - } - - /* Best match (if any) */ - return best_match; + NMConnection *best_match = NULL; + + if (!connections) + return NULL; + + for (; *connections; connections++) { + NMConnection *candidate = *connections; + GHashTable * diffs = NULL; + + nm_assert(NM_IS_CONNECTION(candidate)); + + if (match_filter_func) { + if (!match_filter_func(candidate, match_filter_data)) + continue; + } + + if (indicated) { + NMSettingConnection *s_orig, *s_cand; + + s_orig = nm_connection_get_setting_connection(original); + s_cand = nm_connection_get_setting_connection(candidate); + + /* It is indicated that this connection matches. Assume we have + * a match, but check for particular differences that let us + * reject the candidate. */ + if (!nm_streq0(nm_setting_connection_get_connection_type(s_orig), + nm_setting_connection_get_connection_type(s_cand))) + continue; + if (!nm_streq0(nm_setting_connection_get_slave_type(s_orig), + nm_setting_connection_get_slave_type(s_cand))) + continue; + + /* this is good enough for a match */ + } else if (!nm_connection_diff(original, + candidate, + NM_SETTING_COMPARE_FLAG_INFERRABLE, + &diffs)) { + if (!best_match) { + best_match = check_possible_match(original, + candidate, + diffs, + device_has_carrier, + default_v4_metric, + default_v6_metric); + } + + if (!best_match && nm_logging_enabled(LOGL_DEBUG, LOGD_CORE)) { + GString * diff_string; + GHashTableIter s_iter, p_iter; + gpointer setting_name, setting; + gpointer property_name, value; + + diff_string = g_string_new(NULL); + g_hash_table_iter_init(&s_iter, diffs); + while (g_hash_table_iter_next(&s_iter, &setting_name, &setting)) { + g_hash_table_iter_init(&p_iter, setting); + while (g_hash_table_iter_next(&p_iter, &property_name, &value)) { + if (diff_string->len) + g_string_append(diff_string, ", "); + g_string_append_printf(diff_string, + "%s.%s", + (char *) setting_name, + (char *) property_name); + } + } + + nm_log_dbg(LOGD_CORE, + "Connection '%s' differs from candidate '%s' in %s", + nm_connection_get_id(original), + nm_connection_get_id(candidate), + diff_string->str); + g_string_free(diff_string, TRUE); + } + + g_hash_table_unref(diffs); + continue; + } + + /* Exact match */ + return candidate; + } + + /* Best match (if any) */ + return best_match; } /*****************************************************************************/ int -nm_match_spec_device_by_pllink (const NMPlatformLink *pllink, - const char *match_device_type, - const char *match_dhcp_plugin, - const GSList *specs, - int no_match_value) +nm_match_spec_device_by_pllink(const NMPlatformLink *pllink, + const char * match_device_type, + const char * match_dhcp_plugin, + const GSList * specs, + int no_match_value) { - NMMatchSpecMatchType m; - - /* we can only match by certain properties that are available on the - * platform link (and even @pllink might be missing. - * - * It's still useful because of specs like "*" and "except:interface-name:eth0", - * which match even in that case. */ - m = nm_match_spec_device (specs, - pllink ? pllink->name : NULL, - match_device_type, - pllink ? pllink->driver : NULL, - NULL, - NULL, - NULL, - match_dhcp_plugin); - - switch (m) { - case NM_MATCH_SPEC_MATCH: - return TRUE; - case NM_MATCH_SPEC_NEG_MATCH: - return FALSE; - case NM_MATCH_SPEC_NO_MATCH: - return no_match_value; - } - nm_assert_not_reached (); - return no_match_value; + NMMatchSpecMatchType m; + + /* we can only match by certain properties that are available on the + * platform link (and even @pllink might be missing. + * + * It's still useful because of specs like "*" and "except:interface-name:eth0", + * which match even in that case. */ + m = nm_match_spec_device(specs, + pllink ? pllink->name : NULL, + match_device_type, + pllink ? pllink->driver : NULL, + NULL, + NULL, + NULL, + match_dhcp_plugin); + + switch (m) { + case NM_MATCH_SPEC_MATCH: + return TRUE; + case NM_MATCH_SPEC_NEG_MATCH: + return FALSE; + case NM_MATCH_SPEC_NO_MATCH: + return no_match_value; + } + nm_assert_not_reached(); + return no_match_value; } /*****************************************************************************/ NMPlatformRoutingRule * -nm_ip_routing_rule_to_platform (const NMIPRoutingRule *rule, - NMPlatformRoutingRule *out_pl) +nm_ip_routing_rule_to_platform(const NMIPRoutingRule *rule, NMPlatformRoutingRule *out_pl) { - nm_assert (rule); - nm_assert (nm_ip_routing_rule_validate (rule, NULL)); - nm_assert (out_pl); - - *out_pl = (NMPlatformRoutingRule) { - .addr_family = nm_ip_routing_rule_get_addr_family (rule), - .flags = ( nm_ip_routing_rule_get_invert (rule) - ? FIB_RULE_INVERT - : 0), - .priority = nm_ip_routing_rule_get_priority (rule), - .tos = nm_ip_routing_rule_get_tos (rule), - .ip_proto = nm_ip_routing_rule_get_ipproto (rule), - .fwmark = nm_ip_routing_rule_get_fwmark (rule), - .fwmask = nm_ip_routing_rule_get_fwmask (rule), - .sport_range = { - .start = nm_ip_routing_rule_get_source_port_start (rule), - .end = nm_ip_routing_rule_get_source_port_end (rule), - }, - .dport_range = { - .start = nm_ip_routing_rule_get_destination_port_start (rule), - .end = nm_ip_routing_rule_get_destination_port_end (rule), - }, - .src = *(nm_ip_routing_rule_get_from_bin (rule) ?: &nm_ip_addr_zero), - .dst = *(nm_ip_routing_rule_get_to_bin (rule) ?: &nm_ip_addr_zero), - .src_len = nm_ip_routing_rule_get_from_len (rule), - .dst_len = nm_ip_routing_rule_get_to_len (rule), - .action = nm_ip_routing_rule_get_action (rule), - .table = nm_ip_routing_rule_get_table (rule), - .suppress_prefixlen_inverse = ~((guint32) nm_ip_routing_rule_get_suppress_prefixlength (rule)), - }; - - nm_ip_routing_rule_get_xifname_bin (rule, TRUE, out_pl->iifname); - nm_ip_routing_rule_get_xifname_bin (rule, FALSE, out_pl->oifname); - - return out_pl; + nm_assert(rule); + nm_assert(nm_ip_routing_rule_validate(rule, NULL)); + nm_assert(out_pl); + + *out_pl = (NMPlatformRoutingRule){ + .addr_family = nm_ip_routing_rule_get_addr_family(rule), + .flags = (nm_ip_routing_rule_get_invert(rule) ? FIB_RULE_INVERT : 0), + .priority = nm_ip_routing_rule_get_priority(rule), + .tos = nm_ip_routing_rule_get_tos(rule), + .ip_proto = nm_ip_routing_rule_get_ipproto(rule), + .fwmark = nm_ip_routing_rule_get_fwmark(rule), + .fwmask = nm_ip_routing_rule_get_fwmask(rule), + .sport_range = + { + .start = nm_ip_routing_rule_get_source_port_start(rule), + .end = nm_ip_routing_rule_get_source_port_end(rule), + }, + .dport_range = + { + .start = nm_ip_routing_rule_get_destination_port_start(rule), + .end = nm_ip_routing_rule_get_destination_port_end(rule), + }, + .src = *(nm_ip_routing_rule_get_from_bin(rule) ?: &nm_ip_addr_zero), + .dst = *(nm_ip_routing_rule_get_to_bin(rule) ?: &nm_ip_addr_zero), + .src_len = nm_ip_routing_rule_get_from_len(rule), + .dst_len = nm_ip_routing_rule_get_to_len(rule), + .action = nm_ip_routing_rule_get_action(rule), + .table = nm_ip_routing_rule_get_table(rule), + .suppress_prefixlen_inverse = + ~((guint32) nm_ip_routing_rule_get_suppress_prefixlength(rule)), + }; + + nm_ip_routing_rule_get_xifname_bin(rule, TRUE, out_pl->iifname); + nm_ip_routing_rule_get_xifname_bin(rule, FALSE, out_pl->oifname); + + return out_pl; } /*****************************************************************************/ struct _NMShutdownWaitObjHandle { - CList lst; - gpointer watched_obj; - char *msg_reason; - bool free_msg_reason:1; - bool is_cancellable:1; + CList lst; + gpointer watched_obj; + char * msg_reason; + bool free_msg_reason : 1; + bool is_cancellable : 1; }; static CList _shutdown_waitobj_lst_head; static void -_shutdown_waitobj_unregister (NMShutdownWaitObjHandle *handle) +_shutdown_waitobj_unregister(NMShutdownWaitObjHandle *handle) { - c_list_unlink_stale (&handle->lst); - if (handle->free_msg_reason) - g_free (handle->msg_reason); - g_slice_free (NMShutdownWaitObjHandle, handle); + c_list_unlink_stale(&handle->lst); + if (handle->free_msg_reason) + g_free(handle->msg_reason); + g_slice_free(NMShutdownWaitObjHandle, handle); - /* FIXME(shutdown): check whether the object list is empty, and - * signal shutdown-complete */ + /* FIXME(shutdown): check whether the object list is empty, and + * signal shutdown-complete */ } static void -_shutdown_waitobj_cb (gpointer user_data, - GObject *where_the_object_was) +_shutdown_waitobj_cb(gpointer user_data, GObject *where_the_object_was) { - NMShutdownWaitObjHandle *handle = user_data; + NMShutdownWaitObjHandle *handle = user_data; - nm_assert (handle); - nm_assert (handle->watched_obj == where_the_object_was); - _shutdown_waitobj_unregister (handle); + nm_assert(handle); + nm_assert(handle->watched_obj == where_the_object_was); + _shutdown_waitobj_unregister(handle); } /** @@ -1021,52 +1019,52 @@ _shutdown_waitobj_cb (gpointer user_data, * destroying @watched_obj. */ NMShutdownWaitObjHandle * -nm_shutdown_wait_obj_register_full (gpointer watched_obj, - NMShutdownWaitType wait_type, - char *msg_reason, - gboolean free_msg_reason) +nm_shutdown_wait_obj_register_full(gpointer watched_obj, + NMShutdownWaitType wait_type, + char * msg_reason, + gboolean free_msg_reason) { - NMShutdownWaitObjHandle *handle; - - if (wait_type == NM_SHUTDOWN_WAIT_TYPE_OBJECT) - g_return_val_if_fail (G_IS_OBJECT (watched_obj), NULL); - else if (wait_type == NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE) - g_return_val_if_fail (G_IS_CANCELLABLE (watched_obj), NULL); - else if (wait_type == NM_SHUTDOWN_WAIT_TYPE_HANDLE) - g_return_val_if_fail (!watched_obj, NULL); - else - g_return_val_if_reached (NULL); - - if (G_UNLIKELY (!_shutdown_waitobj_lst_head.next)) - c_list_init (&_shutdown_waitobj_lst_head); - - handle = g_slice_new (NMShutdownWaitObjHandle); - *handle = (NMShutdownWaitObjHandle) { - /* depending on @free_msg_reason, we take ownership of @msg_reason. - * In either case, we just reference the string without cloning - * it. */ - .watched_obj = watched_obj, - .msg_reason = msg_reason, - .free_msg_reason = free_msg_reason, - .is_cancellable = (wait_type == NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE), - }; - c_list_link_tail (&_shutdown_waitobj_lst_head, &handle->lst); - if (watched_obj) - g_object_weak_ref (watched_obj, _shutdown_waitobj_cb, handle); - return handle; + NMShutdownWaitObjHandle *handle; + + if (wait_type == NM_SHUTDOWN_WAIT_TYPE_OBJECT) + g_return_val_if_fail(G_IS_OBJECT(watched_obj), NULL); + else if (wait_type == NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE) + g_return_val_if_fail(G_IS_CANCELLABLE(watched_obj), NULL); + else if (wait_type == NM_SHUTDOWN_WAIT_TYPE_HANDLE) + g_return_val_if_fail(!watched_obj, NULL); + else + g_return_val_if_reached(NULL); + + if (G_UNLIKELY(!_shutdown_waitobj_lst_head.next)) + c_list_init(&_shutdown_waitobj_lst_head); + + handle = g_slice_new(NMShutdownWaitObjHandle); + *handle = (NMShutdownWaitObjHandle){ + /* depending on @free_msg_reason, we take ownership of @msg_reason. + * In either case, we just reference the string without cloning + * it. */ + .watched_obj = watched_obj, + .msg_reason = msg_reason, + .free_msg_reason = free_msg_reason, + .is_cancellable = (wait_type == NM_SHUTDOWN_WAIT_TYPE_CANCELLABLE), + }; + c_list_link_tail(&_shutdown_waitobj_lst_head, &handle->lst); + if (watched_obj) + g_object_weak_ref(watched_obj, _shutdown_waitobj_cb, handle); + return handle; } void -nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle) +nm_shutdown_wait_obj_unregister(NMShutdownWaitObjHandle *handle) { - g_return_if_fail (handle); + g_return_if_fail(handle); - nm_assert (!handle->watched_obj || G_IS_OBJECT (handle->watched_obj)); - nm_assert (nm_c_list_contains_entry (&_shutdown_waitobj_lst_head, handle, lst)); + nm_assert(!handle->watched_obj || G_IS_OBJECT(handle->watched_obj)); + nm_assert(nm_c_list_contains_entry(&_shutdown_waitobj_lst_head, handle, lst)); - if (handle->watched_obj) - g_object_weak_unref (handle->watched_obj, _shutdown_waitobj_cb, handle); - _shutdown_waitobj_unregister (handle); + if (handle->watched_obj) + g_object_weak_unref(handle->watched_obj, _shutdown_waitobj_cb, handle); + _shutdown_waitobj_unregister(handle); } /*****************************************************************************/ @@ -1096,170 +1094,545 @@ nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle) * clearly a directory). * * Returns: if @abs_filename is a file inside @abs_path, returns the - * trailing part of @abs_filename which is the filename. Otherwise + * trailing part of @abs_filename which is the filename. Otherwise, * %NULL. */ const char * -nm_utils_file_is_in_path (const char *abs_filename, - const char *abs_path) +nm_utils_file_is_in_path(const char *abs_filename, const char *abs_path) { - const char *path; - - g_return_val_if_fail (abs_filename && abs_filename[0] == '/', NULL); - g_return_val_if_fail (abs_path && abs_path[0] == '/', NULL); - - path = nm_sd_utils_path_startswith (abs_filename, abs_path); - if (!path) - return NULL; - - nm_assert (path[0] != '/'); - nm_assert (path > abs_filename); - nm_assert (path <= &abs_filename[strlen (abs_filename)]); - - /* we require a non-empty remainder with no slashes. That is, only a filename. - * - * Note this will reject "/var/run/" as not being in "/var", - * while "/var/run" would pass. The function searches for files - * only, so a trailing slash (indicating a directory) is not allowed). - * This is despite that the function cannot determine whether "/var/run" - * is itself a file or a directory. "*/ - return path[0] && !strchr (path, '/') - ? path - : NULL; + const char *path; + + g_return_val_if_fail(abs_filename && abs_filename[0] == '/', NULL); + g_return_val_if_fail(abs_path && abs_path[0] == '/', NULL); + + path = nm_sd_utils_path_startswith(abs_filename, abs_path); + if (!path) + return NULL; + + nm_assert(path[0] != '/'); + nm_assert(path > abs_filename); + nm_assert(path <= &abs_filename[strlen(abs_filename)]); + + /* we require a non-empty remainder with no slashes. That is, only a filename. + * + * Note this will reject "/var/run/" as not being in "/var", + * while "/var/run" would pass. The function searches for files + * only, so a trailing slash (indicating a directory) is not allowed). + * This is despite that the function cannot determine whether "/var/run" + * is itself a file or a directory. "*/ + return path[0] && !strchr(path, '/') ? path : NULL; } /* The returned qdisc array is valid as long as s_tc is not modified */ GPtrArray * -nm_utils_qdiscs_from_tc_setting (NMPlatform *platform, - NMSettingTCConfig *s_tc, - int ip_ifindex) +nm_utils_qdiscs_from_tc_setting(NMPlatform *platform, NMSettingTCConfig *s_tc, int ip_ifindex) { - GPtrArray *qdiscs; - guint nqdiscs; - guint i; - - nqdiscs = nm_setting_tc_config_get_num_qdiscs (s_tc); - qdiscs = g_ptr_array_new_full (nqdiscs, (GDestroyNotify) nmp_object_unref); - - for (i = 0; i < nqdiscs; i++) { - NMTCQdisc *s_qdisc = nm_setting_tc_config_get_qdisc (s_tc, i); - NMPObject *q = nmp_object_new (NMP_OBJECT_TYPE_QDISC, NULL); - NMPlatformQdisc *qdisc = NMP_OBJECT_CAST_QDISC (q); - - qdisc->ifindex = ip_ifindex; - qdisc->kind = nm_tc_qdisc_get_kind (s_qdisc); - - qdisc->addr_family = AF_UNSPEC; - qdisc->handle = nm_tc_qdisc_get_handle (s_qdisc); - qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc); - qdisc->info = 0; - -#define GET_ATTR(name, dst, variant_type, type, dflt) G_STMT_START { \ - GVariant *_variant = nm_tc_qdisc_get_attribute (s_qdisc, ""name""); \ - \ - if ( _variant \ - && g_variant_is_of_type (_variant, G_VARIANT_TYPE_ ## variant_type)) \ - (dst) = g_variant_get_ ## type (_variant); \ - else \ - (dst) = (dflt); \ -} G_STMT_END - - if (strcmp (qdisc->kind, "fq_codel") == 0) { - GET_ATTR ("limit", qdisc->fq_codel.limit, UINT32, uint32, 0); - GET_ATTR ("flows", qdisc->fq_codel.flows, UINT32, uint32, 0); - GET_ATTR ("target", qdisc->fq_codel.target, UINT32, uint32, 0); - GET_ATTR ("interval", qdisc->fq_codel.interval, UINT32, uint32, 0); - GET_ATTR ("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0); - GET_ATTR ("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED); - GET_ATTR ("memory_limit", qdisc->fq_codel.memory_limit, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET); - GET_ATTR ("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE); - } else if (nm_streq (qdisc->kind, "sfq")) { - GET_ATTR ("limit", qdisc->sfq.limit, UINT32, uint32, 0); - GET_ATTR ("flows", qdisc->sfq.flows, UINT32, uint32, 0); - GET_ATTR ("divisor", qdisc->sfq.divisor, UINT32, uint32, 0); - GET_ATTR ("perturb", qdisc->sfq.perturb_period, INT32, int32, 0); - GET_ATTR ("quantum", qdisc->sfq.quantum, UINT32, uint32, 0); - GET_ATTR ("depth", qdisc->sfq.depth, UINT32, uint32, 0); - } else if (nm_streq (qdisc->kind, "tbf")) { - GET_ATTR ("rate", qdisc->tbf.rate, UINT64, uint64, 0); - GET_ATTR ("burst", qdisc->tbf.burst, UINT32, uint32, 0); - GET_ATTR ("limit", qdisc->tbf.limit, UINT32, uint32, 0); - GET_ATTR ("latency", qdisc->tbf.latency, UINT32, uint32, 0); - } -#undef GET_ADDR - - g_ptr_array_add (qdiscs, q); - } - - return qdiscs; + GPtrArray *qdiscs; + guint nqdiscs; + guint i; + + nqdiscs = nm_setting_tc_config_get_num_qdiscs(s_tc); + qdiscs = g_ptr_array_new_full(nqdiscs, (GDestroyNotify) nmp_object_unref); + + for (i = 0; i < nqdiscs; i++) { + NMTCQdisc * s_qdisc = nm_setting_tc_config_get_qdisc(s_tc, i); + NMPObject * q = nmp_object_new(NMP_OBJECT_TYPE_QDISC, NULL); + NMPlatformQdisc *qdisc = NMP_OBJECT_CAST_QDISC(q); + + qdisc->ifindex = ip_ifindex; + qdisc->kind = nm_tc_qdisc_get_kind(s_qdisc); + + qdisc->addr_family = AF_UNSPEC; + qdisc->handle = nm_tc_qdisc_get_handle(s_qdisc); + qdisc->parent = nm_tc_qdisc_get_parent(s_qdisc); + qdisc->info = 0; + +#define GET_ATTR(name, dst, variant_type, type, dflt) \ + G_STMT_START \ + { \ + GVariant *_variant = nm_tc_qdisc_get_attribute(s_qdisc, "" name ""); \ + \ + if (_variant && g_variant_is_of_type(_variant, G_VARIANT_TYPE_##variant_type)) \ + (dst) = g_variant_get_##type(_variant); \ + else \ + (dst) = (dflt); \ + } \ + G_STMT_END + + if (strcmp(qdisc->kind, "fq_codel") == 0) { + GET_ATTR("limit", qdisc->fq_codel.limit, UINT32, uint32, 0); + GET_ATTR("flows", qdisc->fq_codel.flows, UINT32, uint32, 0); + GET_ATTR("target", qdisc->fq_codel.target, UINT32, uint32, 0); + GET_ATTR("interval", qdisc->fq_codel.interval, UINT32, uint32, 0); + GET_ATTR("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0); + GET_ATTR("ce_threshold", + qdisc->fq_codel.ce_threshold, + UINT32, + uint32, + NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED); + GET_ATTR("memory_limit", + qdisc->fq_codel.memory_limit, + UINT32, + uint32, + NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET); + GET_ATTR("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE); + } else if (nm_streq(qdisc->kind, "sfq")) { + GET_ATTR("limit", qdisc->sfq.limit, UINT32, uint32, 0); + GET_ATTR("flows", qdisc->sfq.flows, UINT32, uint32, 0); + GET_ATTR("divisor", qdisc->sfq.divisor, UINT32, uint32, 0); + GET_ATTR("perturb", qdisc->sfq.perturb_period, INT32, int32, 0); + GET_ATTR("quantum", qdisc->sfq.quantum, UINT32, uint32, 0); + GET_ATTR("depth", qdisc->sfq.depth, UINT32, uint32, 0); + } else if (nm_streq(qdisc->kind, "tbf")) { + GET_ATTR("rate", qdisc->tbf.rate, UINT64, uint64, 0); + GET_ATTR("burst", qdisc->tbf.burst, UINT32, uint32, 0); + GET_ATTR("limit", qdisc->tbf.limit, UINT32, uint32, 0); + GET_ATTR("latency", qdisc->tbf.latency, UINT32, uint32, 0); + } +#undef GET_ATTR + + g_ptr_array_add(qdiscs, q); + } + + return qdiscs; } /* The returned tfilter array is valid as long as s_tc is not modified */ GPtrArray * -nm_utils_tfilters_from_tc_setting (NMPlatform *platform, - NMSettingTCConfig *s_tc, - int ip_ifindex) +nm_utils_tfilters_from_tc_setting(NMPlatform *platform, NMSettingTCConfig *s_tc, int ip_ifindex) +{ + GPtrArray *tfilters; + guint ntfilters; + guint i; + + ntfilters = nm_setting_tc_config_get_num_tfilters(s_tc); + tfilters = g_ptr_array_new_full(ntfilters, (GDestroyNotify) nmp_object_unref); + + for (i = 0; i < ntfilters; i++) { + NMTCTfilter * s_tfilter = nm_setting_tc_config_get_tfilter(s_tc, i); + NMTCAction * action; + NMPObject * t = nmp_object_new(NMP_OBJECT_TYPE_TFILTER, NULL); + NMPlatformTfilter *tfilter = NMP_OBJECT_CAST_TFILTER(t); + + tfilter->ifindex = ip_ifindex; + tfilter->kind = nm_tc_tfilter_get_kind(s_tfilter); + tfilter->addr_family = AF_UNSPEC; + tfilter->handle = nm_tc_tfilter_get_handle(s_tfilter); + tfilter->parent = nm_tc_tfilter_get_parent(s_tfilter); + tfilter->info = TC_H_MAKE(0, htons(ETH_P_ALL)); + + action = nm_tc_tfilter_get_action(s_tfilter); + if (action) { + GVariant *var; + + tfilter->action.kind = nm_tc_action_get_kind(action); + + if (strcmp(tfilter->action.kind, "simple") == 0) { + var = nm_tc_action_get_attribute(action, "sdata"); + if (var && g_variant_is_of_type(var, G_VARIANT_TYPE_BYTESTRING)) { + g_strlcpy(tfilter->action.simple.sdata, + g_variant_get_bytestring(var), + sizeof(tfilter->action.simple.sdata)); + } + } else if (strcmp(tfilter->action.kind, "mirred") == 0) { + if (nm_tc_action_get_attribute(action, "egress")) + tfilter->action.mirred.egress = TRUE; + + if (nm_tc_action_get_attribute(action, "ingress")) + tfilter->action.mirred.ingress = TRUE; + + if (nm_tc_action_get_attribute(action, "mirror")) + tfilter->action.mirred.mirror = TRUE; + + if (nm_tc_action_get_attribute(action, "redirect")) + tfilter->action.mirred.redirect = TRUE; + + var = nm_tc_action_get_attribute(action, "dev"); + if (var && g_variant_is_of_type(var, G_VARIANT_TYPE_STRING)) { + int ifindex; + + ifindex = + nm_platform_link_get_ifindex(platform, g_variant_get_string(var, NULL)); + if (ifindex > 0) + tfilter->action.mirred.ifindex = ifindex; + } + } + } + + g_ptr_array_add(tfilters, t); + } + + return tfilters; +} + +void +nm_utils_ip_route_attribute_to_platform(int addr_family, + NMIPRoute * s_route, + NMPlatformIPRoute *r, + guint32 route_table) +{ + GVariant * variant; + guint32 table; + NMIPAddr addr; + NMPlatformIP4Route *r4 = (NMPlatformIP4Route *) r; + NMPlatformIP6Route *r6 = (NMPlatformIP6Route *) r; + gboolean onlink; + + nm_assert(s_route); + nm_assert_addr_family(addr_family); + nm_assert(r); + +#define GET_ATTR(name, dst, variant_type, type, dflt) \ + G_STMT_START \ + { \ + GVariant *_variant = nm_ip_route_get_attribute(s_route, "" name ""); \ + \ + if (_variant && g_variant_is_of_type(_variant, G_VARIANT_TYPE_##variant_type)) \ + (dst) = g_variant_get_##type(_variant); \ + else \ + (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); + + 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; + + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_SCOPE, scope, BYTE, byte, RT_SCOPE_NOWHERE); + r4->scope_inv = nm_platform_route_scope_inv(scope); + } + + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_ONLINK, onlink, BOOLEAN, boolean, FALSE); + + r->r_rtm_flags = ((onlink) ? (unsigned) RTNH_F_ONLINK : 0u); + + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_WINDOW, r->window, UINT32, uint32, 0); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_CWND, r->cwnd, UINT32, uint32, 0); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_INITCWND, r->initcwnd, UINT32, uint32, 0); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_INITRWND, r->initrwnd, UINT32, uint32, 0); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_MTU, r->mtu, UINT32, uint32, 0); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, r->lock_window, BOOLEAN, boolean, FALSE); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, r->lock_cwnd, BOOLEAN, boolean, FALSE); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, r->lock_initcwnd, BOOLEAN, boolean, FALSE); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, r->lock_initrwnd, BOOLEAN, boolean, FALSE); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, r->lock_mtu, BOOLEAN, boolean, FALSE); + + if ((variant = nm_ip_route_get_attribute(s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) + && g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { + if (inet_pton(addr_family, g_variant_get_string(variant, NULL), &addr) == 1) { + if (addr_family == AF_INET) + r4->pref_src = addr.addr4; + else + r6->pref_src = addr.addr6; + } + } + + if (addr_family == AF_INET6 + && (variant = nm_ip_route_get_attribute(s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) + && g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { + int prefix; + + if (nm_utils_parse_inaddr_prefix_bin(addr_family, + g_variant_get_string(variant, NULL), + NULL, + &addr, + &prefix)) { + if (prefix < 0) + prefix = 128; + r6->src = addr.addr6; + r6->src_plen = prefix; + } + } +#undef GET_ATTR +} + +/*****************************************************************************/ + +static int +_addresses_sort_cmp_4(gconstpointer a, gconstpointer b, gpointer user_data) +{ + return nm_platform_ip4_address_pretty_sort_cmp( + NMP_OBJECT_CAST_IP4_ADDRESS(*((const NMPObject **) a)), + NMP_OBJECT_CAST_IP4_ADDRESS(*((const NMPObject **) b))); +} + +static int +_addresses_sort_cmp_6(gconstpointer a, gconstpointer b, gpointer user_data) +{ + return nm_platform_ip6_address_pretty_sort_cmp( + NMP_OBJECT_CAST_IP6_ADDRESS(*((const NMPObject **) a)), + NMP_OBJECT_CAST_IP6_ADDRESS(*((const NMPObject **) b)), + (((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT(user_data)) + == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR)); +} + +void +nm_utils_ip_addresses_to_dbus(int addr_family, + const NMDedupMultiHeadEntry *head_entry, + const NMPObject * best_default_route, + NMSettingIP6ConfigPrivacy ipv6_privacy, + GVariant ** out_address_data, + GVariant ** out_addresses) +{ + const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + GVariantBuilder builder_data; + GVariantBuilder builder_legacy; + char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + gs_free const NMPObject **addresses = NULL; + guint naddr; + guint i; + + nm_assert_addr_family(addr_family); + + if (out_address_data) + g_variant_builder_init(&builder_data, G_VARIANT_TYPE("aa{sv}")); + if (out_addresses) { + if (IS_IPv4) + g_variant_builder_init(&builder_legacy, G_VARIANT_TYPE("aau")); + else + g_variant_builder_init(&builder_legacy, G_VARIANT_TYPE("a(ayuay)")); + } + + if (!head_entry) + goto out; + + addresses = + (const NMPObject **) nm_dedup_multi_objs_to_array_head(head_entry, NULL, NULL, &naddr); + + nm_assert(addresses && naddr); + + g_qsort_with_data(addresses, + naddr, + sizeof(addresses[0]), + IS_IPv4 ? _addresses_sort_cmp_4 : _addresses_sort_cmp_6, + GINT_TO_POINTER(ipv6_privacy)); + + for (i = 0; i < naddr; i++) { + const NMPlatformIPXAddress *address = NMP_OBJECT_CAST_IPX_ADDRESS(addresses[i]); + + if (out_address_data) { + GVariantBuilder addr_builder; + gconstpointer p; + + g_variant_builder_init(&addr_builder, G_VARIANT_TYPE("a{sv}")); + + g_variant_builder_add( + &addr_builder, + "{sv}", + "address", + g_variant_new_string( + nm_utils_inet_ntop(addr_family, address->ax.address_ptr, addr_str))); + + g_variant_builder_add(&addr_builder, + "{sv}", + "prefix", + g_variant_new_uint32(address->ax.plen)); + + p = NULL; + if (IS_IPv4) { + if (address->a4.peer_address != address->a4.address) + p = &address->a4.peer_address; + } else { + if (!IN6_IS_ADDR_UNSPECIFIED(&address->a6.peer_address) + && !IN6_ARE_ADDR_EQUAL(&address->a6.peer_address, &address->a6.address)) + p = &address->a6.peer_address; + } + if (p) { + g_variant_builder_add( + &addr_builder, + "{sv}", + "peer", + g_variant_new_string(nm_utils_inet_ntop(addr_family, p, addr_str))); + } + + if (IS_IPv4) { + if (*address->a4.label) { + g_variant_builder_add(&addr_builder, + "{sv}", + NM_IP_ADDRESS_ATTRIBUTE_LABEL, + g_variant_new_string(address->a4.label)); + } + } + + g_variant_builder_add(&builder_data, "a{sv}", &addr_builder); + } + + if (out_addresses) { + if (IS_IPv4) { + const guint32 dbus_addr[3] = { + address->a4.address, + address->a4.plen, + (i == 0 && best_default_route) + ? NMP_OBJECT_CAST_IP4_ROUTE(best_default_route)->gateway + : (guint32) 0, + }; + + g_variant_builder_add(&builder_legacy, + "@au", + g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + dbus_addr, + 3, + sizeof(guint32))); + } else { + g_variant_builder_add( + &builder_legacy, + "(@ayu@ay)", + g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &address->a6.address, 16, 1), + address->a6.plen, + g_variant_new_fixed_array( + G_VARIANT_TYPE_BYTE, + (i == 0 && best_default_route) + ? &NMP_OBJECT_CAST_IP6_ROUTE(best_default_route)->gateway + : &in6addr_any, + 16, + 1)); + } + } + } + +out: + NM_SET_OUT(out_address_data, g_variant_builder_end(&builder_data)); + NM_SET_OUT(out_addresses, g_variant_builder_end(&builder_legacy)); +} + +void +nm_utils_ip_routes_to_dbus(int addr_family, + const NMDedupMultiHeadEntry *head_entry, + GVariant ** out_route_data, + GVariant ** out_routes) { - GPtrArray *tfilters; - guint ntfilters; - guint i; - - ntfilters = nm_setting_tc_config_get_num_tfilters (s_tc); - tfilters = g_ptr_array_new_full (ntfilters, (GDestroyNotify) nmp_object_unref); - - for (i = 0; i < ntfilters; i++) { - NMTCTfilter *s_tfilter = nm_setting_tc_config_get_tfilter (s_tc, i); - NMTCAction *action; - NMPObject *t = nmp_object_new (NMP_OBJECT_TYPE_TFILTER, NULL); - NMPlatformTfilter *tfilter = NMP_OBJECT_CAST_TFILTER (t); - - tfilter->ifindex = ip_ifindex; - tfilter->kind = nm_tc_tfilter_get_kind (s_tfilter); - tfilter->addr_family = AF_UNSPEC; - tfilter->handle = nm_tc_tfilter_get_handle (s_tfilter); - tfilter->parent = nm_tc_tfilter_get_parent (s_tfilter); - tfilter->info = TC_H_MAKE (0, htons (ETH_P_ALL)); - - action = nm_tc_tfilter_get_action (s_tfilter); - if (action) { - GVariant *var; - - tfilter->action.kind = nm_tc_action_get_kind (action); - - if (strcmp (tfilter->action.kind, "simple") == 0) { - var = nm_tc_action_get_attribute (action, "sdata"); - if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_BYTESTRING)) { - g_strlcpy (tfilter->action.simple.sdata, - g_variant_get_bytestring (var), - sizeof (tfilter->action.simple.sdata)); - } - } else if (strcmp (tfilter->action.kind, "mirred") == 0) { - if (nm_tc_action_get_attribute (action, "egress")) - tfilter->action.mirred.egress = TRUE; - - if (nm_tc_action_get_attribute (action, "ingress")) - tfilter->action.mirred.ingress = TRUE; - - if (nm_tc_action_get_attribute (action, "mirror")) - tfilter->action.mirred.mirror = TRUE; - - if (nm_tc_action_get_attribute (action, "redirect")) - tfilter->action.mirred.redirect = TRUE; - - var = nm_tc_action_get_attribute (action, "dev"); - if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_STRING)) { - int ifindex; - - ifindex = nm_platform_link_get_ifindex (platform, - g_variant_get_string (var, NULL)); - if (ifindex > 0) - tfilter->action.mirred.ifindex = ifindex; - } - } - } - - g_ptr_array_add (tfilters, t); - } - - return tfilters; + const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + NMDedupMultiIter iter; + const NMPObject *obj; + GVariantBuilder builder_data; + GVariantBuilder builder_legacy; + char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + + nm_assert_addr_family(addr_family); + + if (out_route_data) + g_variant_builder_init(&builder_data, G_VARIANT_TYPE("aa{sv}")); + if (out_routes) { + if (IS_IPv4) + g_variant_builder_init(&builder_legacy, G_VARIANT_TYPE("aau")); + else + g_variant_builder_init(&builder_legacy, G_VARIANT_TYPE("a(ayuayu)")); + } + + nm_dedup_multi_iter_init(&iter, head_entry); + while (nm_platform_dedup_multi_iter_next_obj(&iter, &obj, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))) { + const NMPlatformIPXRoute *r = NMP_OBJECT_CAST_IPX_ROUTE(obj); + struct in6_addr n; + + nm_assert(r); + nm_assert(r->rx.plen <= 8u * nm_utils_addr_family_to_size(addr_family)); + nm_assert(!IS_IPv4 + || r->r4.network + == nm_utils_ip4_address_clear_host_address(r->r4.network, r->r4.plen)); + nm_assert( + IS_IPv4 + || (memcmp(&r->r6.network, + nm_utils_ip6_address_clear_host_address(&n, &r->r6.network, r->r6.plen), + sizeof(n)) + == 0)); + + if (r->rx.type_coerced != nm_platform_route_type_coerce(RTN_UNICAST)) + continue; + + if (out_route_data) { + GVariantBuilder route_builder; + gconstpointer gateway; + + g_variant_builder_init(&route_builder, G_VARIANT_TYPE("a{sv}")); + + g_variant_builder_add( + &route_builder, + "{sv}", + "dest", + g_variant_new_string(nm_utils_inet_ntop(addr_family, r->rx.network_ptr, addr_str))); + + g_variant_builder_add(&route_builder, + "{sv}", + "prefix", + g_variant_new_uint32(r->rx.plen)); + + gateway = nm_platform_ip_route_get_gateway(addr_family, &r->rx); + if (!nm_ip_addr_is_null(addr_family, gateway)) { + g_variant_builder_add( + &route_builder, + "{sv}", + "next-hop", + g_variant_new_string(nm_utils_inet_ntop(addr_family, gateway, addr_str))); + } + + g_variant_builder_add(&route_builder, + "{sv}", + "metric", + g_variant_new_uint32(r->rx.metric)); + + if (!nm_platform_route_table_is_main(r->rx.table_coerced)) { + g_variant_builder_add( + &route_builder, + "{sv}", + "table", + g_variant_new_uint32( + nm_platform_route_table_uncoerce(r->rx.table_coerced, TRUE))); + } + + g_variant_builder_add(&builder_data, "a{sv}", &route_builder); + } + + if (out_routes) { + /* legacy versions of nm_ip[46]_route_set_prefix() in libnm-util assert that the + * plen is positive. Skip the default routes not to break older clients. */ + if (!nm_platform_route_table_is_main(r->rx.table_coerced) + || NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r)) + continue; + + if (IS_IPv4) { + const guint32 dbus_route[4] = { + r->r4.network, + r->r4.plen, + r->r4.gateway, + r->r4.metric, + }; + + g_variant_builder_add(&builder_legacy, + "@au", + g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, + dbus_route, + 4, + sizeof(guint32))); + } else { + g_variant_builder_add( + &builder_legacy, + "(@ayu@ayu)", + g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &r->r6.network, 16, 1), + (guint32) r->r6.plen, + g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &r->r6.gateway, 16, 1), + (guint32) r->r6.metric); + } + } + } + + NM_SET_OUT(out_route_data, g_variant_builder_end(&builder_data)); + NM_SET_OUT(out_routes, g_variant_builder_end(&builder_legacy)); } |