diff options
| author | Michael Biebl <biebl@debian.org> | 2019-07-31 10:51:42 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2019-07-31 10:51:42 +0200 |
| commit | 2e5fa45ddfbb5cffa1e78221f1cea706e2f298af (patch) | |
| tree | 86f69d36c56de3074280456eddc854a780b8e04b /libnm-core/nm-setting-wired.c | |
| parent | 85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (diff) | |
New upstream version 1.19.90 upstream/1.19.90
Diffstat (limited to 'libnm-core/nm-setting-wired.c')
| -rw-r--r-- | libnm-core/nm-setting-wired.c | 380 |
1 files changed, 299 insertions, 81 deletions
diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c index 182e7193..379bd173 100644 --- a/libnm-core/nm-setting-wired.c +++ b/libnm-core/nm-setting-wired.c @@ -1,5 +1,3 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ - /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -75,7 +73,11 @@ typedef struct { guint32 mtu; char **s390_subchannels; char *s390_nettype; - GHashTable *s390_options; + struct { + NMUtilsNamedValue *arr; + guint len; + guint n_alloc; + } s390_options; NMSettingWiredWakeOnLan wol; char *wol_password; } NMSettingWiredPrivate; @@ -87,15 +89,68 @@ G_DEFINE_TYPE (NMSettingWired, nm_setting_wired, NM_TYPE_SETTING) /*****************************************************************************/ static const char *valid_s390_opts[] = { - "portno", "layer2", "portname", "protocol", "priority_queueing", - "buffer_count", "isolation", "total", "inter", "inter_jumbo", "route4", - "route6", "fake_broadcast", "broadcast_mode", "canonical_macaddr", - "checksumming", "sniffer", "large_send", "ipato_enable", "ipato_invert4", - "ipato_add4", "ipato_invert6", "ipato_add6", "vipa_add4", "vipa_add6", - "rxip_add4", "rxip_add6", "lancmd_timeout", "ctcprot", - NULL + "broadcast_mode", + "buffer_count", + "canonical_macaddr", + "checksumming", + "ctcprot", + "fake_broadcast", + "inter", + "inter_jumbo", + "ipato_add4", + "ipato_add6", + "ipato_enable", + "ipato_invert4", + "ipato_invert6", + "isolation", + "lancmd_timeout", + "large_send", + "layer2", + "portname", + "portno", + "priority_queueing", + "protocol", + "route4", + "route6", + "rxip_add4", + "rxip_add6", + "sniffer", + "total", + "vipa_add4", + "vipa_add6", + NULL, }; +static gboolean +valid_s390_opts_check (const char *option) +{ +#if NM_MORE_ASSERTS > 5 + nm_assert (NM_PTRARRAY_LEN (valid_s390_opts) + 1 == G_N_ELEMENTS (valid_s390_opts)); + { + gsize i; + + for (i = 0; i < G_N_ELEMENTS (valid_s390_opts); i++) { + if (i == G_N_ELEMENTS (valid_s390_opts) - 1) + nm_assert (!valid_s390_opts[i]); + else { + nm_assert (valid_s390_opts[i]); + nm_assert (valid_s390_opts[i][0] != '\0'); + if (i > 0) + g_assert (strcmp (valid_s390_opts[i - 1], valid_s390_opts[i]) < 0); + } + } + } +#endif + + return option + && (nm_utils_array_find_binary_search (valid_s390_opts, + sizeof (const char *), + G_N_ELEMENTS (valid_s390_opts) - 1, + &option, + nm_strcmp_p_with_data, + NULL) >= 0); +} + /** * nm_setting_wired_get_port: * @setting: the #NMSettingWired @@ -417,7 +472,7 @@ nm_setting_wired_get_num_s390_options (NMSettingWired *setting) { g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), 0); - return g_hash_table_size (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options); + return NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options.len; } /** @@ -447,24 +502,17 @@ nm_setting_wired_get_s390_option (NMSettingWired *setting, const char **out_key, const char **out_value) { - const char *_key, *_value; - GHashTableIter iter; - guint i = 0; + NMSettingWiredPrivate *priv; g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE); - g_hash_table_iter_init (&iter, NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options); - while (g_hash_table_iter_next (&iter, (gpointer) &_key, (gpointer) &_value)) { - if (i == idx) { - if (out_key) - *out_key = _key; - if (out_value) - *out_value = _value; - return TRUE; - } - i++; - } - g_return_val_if_reached (FALSE); + priv = NM_SETTING_WIRED_GET_PRIVATE (setting); + + g_return_val_if_fail (idx < priv->s390_options.len, FALSE); + + NM_SET_OUT (out_key, priv->s390_options.arr[idx].name); + NM_SET_OUT (out_value, priv->s390_options.arr[idx].value_str); + return TRUE; } /** @@ -482,10 +530,21 @@ const char * nm_setting_wired_get_s390_option_by_key (NMSettingWired *setting, const char *key) { + NMSettingWiredPrivate *priv; + gssize idx; + g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NULL); g_return_val_if_fail (key && key[0], NULL); - return g_hash_table_lookup (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, key); + priv = NM_SETTING_WIRED_GET_PRIVATE (setting); + + idx = nm_utils_named_value_list_find (priv->s390_options.arr, + priv->s390_options.len, + key, + TRUE); + if (idx < 0) + return NULL; + return priv->s390_options.arr[idx].value_str; } /** @@ -507,14 +566,51 @@ nm_setting_wired_add_s390_option (NMSettingWired *setting, const char *key, const char *value) { + NMSettingWiredPrivate *priv; + gssize idx; + NMUtilsNamedValue *v; + g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE); - g_return_val_if_fail (key && key[0], FALSE); - g_return_val_if_fail (g_strv_contains (valid_s390_opts, key), FALSE); - g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (value, FALSE); + + if (!valid_s390_opts_check (key)) { + g_return_val_if_fail (key, FALSE); + return FALSE; + } + + priv = NM_SETTING_WIRED_GET_PRIVATE (setting); + + idx = nm_utils_named_value_list_find (priv->s390_options.arr, + priv->s390_options.len, + key, + TRUE); + if (idx < 0) { + gsize dst_idx = ~idx; + + if (priv->s390_options.n_alloc < priv->s390_options.len + 1) { + priv->s390_options.n_alloc = NM_MAX (4, + (priv->s390_options.len + 1) * 2); + priv->s390_options.arr = g_realloc (priv->s390_options.arr, + priv->s390_options.n_alloc * sizeof (NMUtilsNamedValue)); + } + if (dst_idx < priv->s390_options.len) { + memmove (&priv->s390_options.arr[dst_idx + 1], + &priv->s390_options.arr[dst_idx], + (priv->s390_options.len - dst_idx) * sizeof (NMUtilsNamedValue)); + } + priv->s390_options.arr[dst_idx] = (NMUtilsNamedValue) { + .name = g_strdup (key), + .value_str = g_strdup (value), + }; + priv->s390_options.len++; + } else { + v = &priv->s390_options.arr[idx]; + if (nm_streq (value, v->value_str)) + return TRUE; + g_free ((char *) v->value_str); + v->value_str = g_strdup (value); + } - g_hash_table_insert (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, - g_strdup (key), - g_strdup (value)); _notify (setting, PROP_S390_OPTIONS); return TRUE; } @@ -534,20 +630,64 @@ gboolean nm_setting_wired_remove_s390_option (NMSettingWired *setting, const char *key) { - gboolean found; + NMSettingWiredPrivate *priv; + gsize dst_idx; + gssize idx; g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE); - g_return_val_if_fail (key && key[0], FALSE); + g_return_val_if_fail (key, FALSE); + + priv = NM_SETTING_WIRED_GET_PRIVATE (setting); + + idx = nm_utils_named_value_list_find (priv->s390_options.arr, + priv->s390_options.len, + key, + TRUE); + if (idx < 0) + return FALSE; + + dst_idx = idx; + + g_free ((char *) priv->s390_options.arr[dst_idx].name); + g_free ((char *) priv->s390_options.arr[dst_idx].value_str); + if (dst_idx + 1 != priv->s390_options.len) { + memmove (&priv->s390_options.arr[dst_idx], + &priv->s390_options.arr[dst_idx + 1], + (priv->s390_options.len - dst_idx - 1) * sizeof (NMUtilsNamedValue)); + } + + priv->s390_options.len--; - found = g_hash_table_remove (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, key); - if (found) - _notify (setting, PROP_S390_OPTIONS); - return found; + _notify (setting, PROP_S390_OPTIONS); + return TRUE; +} + +static void +_s390_options_clear (NMSettingWiredPrivate *priv) +{ + guint i; + + for (i = 0; i < priv->s390_options.len; i++) { + g_free ((char *) priv->s390_options.arr[i].name); + g_free ((char *) priv->s390_options.arr[i].value_str); + } + nm_clear_g_free (&priv->s390_options.arr); + priv->s390_options.len = 0; + priv->s390_options.n_alloc = 0; +} + +void +_nm_setting_wired_clear_s390_options (NMSettingWired *setting) +{ + g_return_if_fail (NM_IS_SETTING_WIRED (setting)); + + _s390_options_clear (NM_SETTING_WIRED_GET_PRIVATE (setting)); } /** * nm_setting_wired_get_valid_s390_options: - * @setting: (allow-none): the #NMSettingWired + * @setting: (allow-none): the #NMSettingWired. This argument is unused + * and you may pass %NULL. * * Returns a list of valid s390 options. * @@ -602,10 +742,8 @@ static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting); - GHashTableIter iter; - const char *key, *value; - int i; GError *local = NULL; + guint i; if (!NM_IN_STRSET (priv->port, NULL, "tp", "aui", "bnc", "mii")) { g_set_error (error, @@ -628,10 +766,11 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } if (priv->device_mac_address && !nm_utils_hwaddr_valid (priv->device_mac_address, ETH_ALEN)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("is not a valid MAC address")); + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid MAC address"), + priv->device_mac_address); g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS); return FALSE; } @@ -672,16 +811,19 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } - g_hash_table_iter_init (&iter, priv->s390_options); - while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) { - if ( !g_strv_contains (valid_s390_opts, key) - || value[0] == '\0' - || (strlen (value) > 200)) { + for (i = 0; i < priv->s390_options.len; i++) { + const NMUtilsNamedValue *v = &priv->s390_options.arr[i]; + + nm_assert (v->name); + + if ( !valid_s390_opts_check (v->name) + || v->value_str[0] == '\0' + || strlen (v->value_str) > 200) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("invalid '%s' or its value '%s'"), - key, value); + v->name, v->value_str); g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_S390_OPTIONS); return FALSE; } @@ -690,10 +832,11 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) if ( priv->cloned_mac_address && !NM_CLONED_MAC_IS_SPECIAL (priv->cloned_mac_address) && !nm_utils_hwaddr_valid (priv->cloned_mac_address, ETH_ALEN)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("is not a valid MAC address")); + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid MAC address"), + priv->cloned_mac_address); g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_CLONED_MAC_ADDRESS); return FALSE; } @@ -732,10 +875,11 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } if (priv->wol_password && !nm_utils_hwaddr_valid (priv->wol_password, ETH_ALEN)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("is not a valid MAC address")); + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid MAC address"), + priv->wol_password); g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD); return FALSE; } @@ -762,26 +906,35 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) static NMTernary compare_property (const NMSettInfoSetting *sett_info, guint property_idx, - NMSetting *setting, - NMSetting *other, + NMConnection *con_a, + NMSetting *set_a, + NMConnection *con_b, + NMSetting *set_b, NMSettingCompareFlags flags) { if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_WIRED_CLONED_MAC_ADDRESS)) { - return !other - || nm_streq0 (NM_SETTING_WIRED_GET_PRIVATE (setting)->cloned_mac_address, - NM_SETTING_WIRED_GET_PRIVATE (other)->cloned_mac_address); + return !set_b + || nm_streq0 (NM_SETTING_WIRED_GET_PRIVATE (set_a)->cloned_mac_address, + NM_SETTING_WIRED_GET_PRIVATE (set_b)->cloned_mac_address); } return NM_SETTING_CLASS (nm_setting_wired_parent_class)->compare_property (sett_info, property_idx, - setting, - other, + con_a, + set_a, + con_b, + set_b, flags); } static GVariant * -_override_autoneg_get (NMSetting *setting, const char *property) +_override_autoneg_get (const NMSettInfoSetting *sett_info, + guint property_idx, + NMConnection *connection, + NMSetting *setting, + NMConnectionSerializationFlags flags, + const NMConnectionSerializationOptions *options) { return g_variant_new_boolean (nm_setting_wired_get_auto_negotiate ((NMSettingWired *) setting)); } @@ -802,6 +955,8 @@ get_property (GObject *object, guint prop_id, { NMSettingWired *setting = NM_SETTING_WIRED (object); NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting); + GHashTable *hash; + guint i; switch (prop_id) { case PROP_PORT: @@ -838,7 +993,16 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, nm_setting_wired_get_s390_nettype (setting)); break; case PROP_S390_OPTIONS: - g_value_take_boxed (value, _nm_utils_copy_strdict (priv->s390_options)); + hash = g_hash_table_new_full (nm_str_hash, + g_str_equal, + g_free, + g_free); + for (i = 0; i < priv->s390_options.len; i++) { + g_hash_table_insert (hash, + g_strdup (priv->s390_options.arr[i].name), + g_strdup (priv->s390_options.arr[i].value_str)); + } + g_value_take_boxed (value, hash); break; case PROP_WAKE_ON_LAN: g_value_set_uint (value, priv->wol); @@ -859,7 +1023,6 @@ set_property (GObject *object, guint prop_id, NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (object); const char * const *blacklist; const char *mac; - int i; switch (prop_id) { case PROP_PORT: @@ -894,6 +1057,8 @@ set_property (GObject *object, guint prop_id, blacklist = g_value_get_boxed (value); g_array_set_size (priv->mac_address_blacklist, 0); if (blacklist && *blacklist) { + guint i; + for (i = 0; blacklist[i]; i++) { mac = _nm_utils_hwaddr_canonical_or_invalid (blacklist[i], ETH_ALEN); g_array_append_val (priv->mac_address_blacklist, mac); @@ -913,8 +1078,63 @@ set_property (GObject *object, guint prop_id, priv->s390_nettype = g_value_dup_string (value); break; case PROP_S390_OPTIONS: - g_hash_table_unref (priv->s390_options); - priv->s390_options = _nm_utils_copy_strdict (g_value_get_boxed (value)); + { + GHashTable *hash; + + _s390_options_clear (priv); + + hash = g_value_get_boxed (value); + + priv->s390_options.n_alloc = hash ? g_hash_table_size (hash) : 0u; + + if (priv->s390_options.n_alloc > 0) { + gboolean invalid_content = FALSE; + GHashTableIter iter; + const char *key; + const char *val; + guint i, j; + + priv->s390_options.arr = g_new (NMUtilsNamedValue, priv->s390_options.n_alloc); + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { + if (!key || !val) { + invalid_content = TRUE; + continue; + } + nm_assert (priv->s390_options.len < priv->s390_options.n_alloc); + priv->s390_options.arr[priv->s390_options.len] = (NMUtilsNamedValue) { + .name = g_strdup (key), + .value_str = g_strdup (val), + }; + priv->s390_options.len++; + } + if (priv->s390_options.len > 1) { + nm_utils_named_value_list_sort (priv->s390_options.arr, + priv->s390_options.len, + NULL, + NULL); + /* prune duplicate keys. This is only possible if @hash does not use + * g_str_equal() as compare function (which would be a bug). + * Still, handle this, because we use later binary sort and rely + * on unique names. One bug here, should not bork the remainder + * of the program. */ + j = 1; + for (i = 1; i < priv->s390_options.len; i++) { + if (nm_streq (priv->s390_options.arr[j - 1].name, + priv->s390_options.arr[i].name)) { + g_free ((char *) priv->s390_options.arr[i].name); + g_free ((char *) priv->s390_options.arr[i].value_str); + invalid_content = TRUE; + continue; + } + priv->s390_options.arr[j++] = priv->s390_options.arr[i]; + } + priv->s390_options.len = j; + } + + g_return_if_fail (!invalid_content); + } + } break; case PROP_WAKE_ON_LAN: priv->wol = g_value_get_uint (value); @@ -936,8 +1156,6 @@ nm_setting_wired_init (NMSettingWired *setting) { NMSettingWiredPrivate *priv = NM_SETTING_WIRED_GET_PRIVATE (setting); - priv->s390_options = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); - /* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */ priv->mac_address_blacklist = g_array_new (TRUE, FALSE, sizeof (char *)); g_array_set_clear_func (priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item); @@ -965,7 +1183,7 @@ finalize (GObject *object) g_free (priv->duplex); g_free (priv->s390_nettype); - g_hash_table_destroy (priv->s390_options); + _s390_options_clear (priv); g_free (priv->device_mac_address); g_free (priv->cloned_mac_address); @@ -1198,11 +1416,11 @@ nm_setting_wired_class_init (NMSettingWiredClass *klass) G_PARAM_STATIC_STRINGS); _properties_override_add_override (properties_override, - obj_properties[PROP_CLONED_MAC_ADDRESS], - G_VARIANT_TYPE_BYTESTRING, - _nm_utils_hwaddr_cloned_get, - _nm_utils_hwaddr_cloned_set, - _nm_utils_hwaddr_cloned_not_set); + obj_properties[PROP_CLONED_MAC_ADDRESS], + G_VARIANT_TYPE_BYTESTRING, + _nm_utils_hwaddr_cloned_get, + _nm_utils_hwaddr_cloned_set, + _nm_utils_hwaddr_cloned_not_set); /* ---dbus--- * property: assigned-mac-address |