diff options
| author | Michael Biebl <biebl@debian.org> | 2017-12-12 15:53:07 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-12-12 15:53:07 +0100 |
| commit | afcd268ea7b1149fbfb66bce4eca659b675da0a2 (patch) | |
| tree | c3fca2203ad17434daf3ccf576582bd66aa41ab2 /src/settings | |
| parent | 417f6015c3dc8c47cf27daa59f64e0e36c521b9c (diff) | |
New upstream version 1.10.2 upstream/1.10.2
Diffstat (limited to 'src/settings')
40 files changed, 1643 insertions, 1207 deletions
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index bcd17843..a68db47e 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -62,6 +62,8 @@ typedef struct { GHashTable *agents; CList requests; + + guint64 agent_version_id; } NMAgentManagerPrivate; struct _NMAgentManager { @@ -137,6 +139,16 @@ static gboolean _con_get_try_complete_early (Request *req); /*****************************************************************************/ +guint64 +nm_agent_manager_get_agent_version_id (NMAgentManager *self) +{ + g_return_val_if_fail (NM_IS_AGENT_MANAGER (self), 0); + + return NM_AGENT_MANAGER_GET_PRIVATE (self)->agent_version_id; +} + +/*****************************************************************************/ + typedef enum { REQUEST_TYPE_INVALID, REQUEST_TYPE_CON_GET, @@ -170,7 +182,7 @@ struct _NMAgentManagerCallId { /* Current agent being asked for secrets */ NMSecretAgent *current; - NMSecretAgentCallId current_call_id; + NMSecretAgentCallId *current_call_id; /* Stores the sorted list of NMSecretAgents which will be asked for secrets */ GSList *pending; @@ -336,6 +348,7 @@ agent_register_permissions_done (NMAuthChain *chain, if (result == NM_AUTH_CALL_RESULT_YES) nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, TRUE); + priv->agent_version_id += 1; sender = nm_secret_agent_get_dbus_owner (agent); g_hash_table_insert (priv->agents, g_strdup (sender), agent); _LOGD (agent, "agent registered"); @@ -609,7 +622,7 @@ req_complete (Request *req, nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &req->lst_request)); - c_list_unlink_init (&req->lst_request); + c_list_unlink (&req->lst_request); req_complete_release (req, secrets, agent_dbus_owner, agent_username, error); } @@ -832,7 +845,7 @@ out: static void _con_get_request_done (NMSecretAgent *agent, - NMSecretAgentCallId call_id, + NMSecretAgentCallId *call_id, GVariant *secrets, GError *error, gpointer user_data) @@ -1213,7 +1226,7 @@ nm_agent_manager_get_secrets (NMAgentManager *self, GVariant *existing_secrets, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMAgentSecretsResultFunc callback, gpointer callback_data) { @@ -1267,7 +1280,7 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self, nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &request_id->lst_request)); - c_list_unlink_init (&request_id->lst_request); + c_list_unlink (&request_id->lst_request); req_complete_cancel (request_id, FALSE); } @@ -1276,7 +1289,7 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self, static void _con_save_request_done (NMSecretAgent *agent, - NMSecretAgentCallId call_id, + NMSecretAgentCallId *call_id, GVariant *secrets, GError *error, gpointer user_data) @@ -1362,7 +1375,7 @@ nm_agent_manager_save_secrets (NMAgentManager *self, static void _con_del_request_done (NMSecretAgent *agent, - NMSecretAgentCallId call_id, + NMSecretAgentCallId *call_id, GVariant *secrets, GError *error, gpointer user_data) @@ -1558,6 +1571,7 @@ nm_agent_manager_init (NMAgentManager *self) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + priv->agent_version_id = 1; c_list_init (&priv->requests); priv->agents = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); } @@ -1588,7 +1602,7 @@ dispose (GObject *object) cancel_more: c_list_for_each (iter, &priv->requests) { - c_list_unlink_init (iter); + c_list_unlink (iter); req_complete_cancel (c_list_entry (iter, Request, lst_request), TRUE); goto cancel_more; } @@ -1627,7 +1641,7 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) object_class->dispose = dispose; signals[AGENT_REGISTERED] = - g_signal_new ("agent-registered", + g_signal_new (NM_AGENT_MANAGER_AGENT_REGISTERED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index 7f812693..f6845818 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -33,6 +33,8 @@ #define NM_IS_AGENT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AGENT_MANAGER)) #define NM_AGENT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass)) +#define NM_AGENT_MANAGER_AGENT_REGISTERED "agent-registered" + typedef struct _NMAgentManagerCallId *NMAgentManagerCallId; typedef struct _NMAgentManagerClass NMAgentManagerClass; @@ -41,6 +43,8 @@ GType nm_agent_manager_get_type (void); NMAgentManager *nm_agent_manager_get (void); +guint64 nm_agent_manager_get_agent_version_id (NMAgentManager *self); + /* If no agent fulfilled the secrets request, agent_dbus_owner will be NULL */ typedef void (*NMAgentSecretsResultFunc) (NMAgentManager *manager, NMAgentManagerCallId call_id, @@ -60,7 +64,7 @@ NMAgentManagerCallId nm_agent_manager_get_secrets (NMAgentManager *manager, GVariant *existing_secrets, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMAgentSecretsResultFunc callback, gpointer callback_data); diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index 5fe4dd17..192e9877 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -50,16 +50,13 @@ typedef struct { char *owner_username; char *dbus_owner; NMSecretAgentCapabilities capabilities; - GSList *permissions; - NMDBusSecretAgent *proxy; NMBusManager *bus_mgr; GDBusConnection *connection; - gboolean connection_is_private; - gulong on_disconnected_id; - CList requests; + gulong on_disconnected_id; + bool connection_is_private:1; } NMSecretAgentPrivate; struct _NMSecretAgent { @@ -99,6 +96,13 @@ G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) /*****************************************************************************/ +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_capabilities_to_string, NMSecretAgentCapabilities, + NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, "vpn-hints"), +); + +/*****************************************************************************/ + struct _NMSecretAgentCallId { CList lst; NMSecretAgent *agent; @@ -111,9 +115,7 @@ struct _NMSecretAgentCallId { gpointer callback_data; }; -typedef struct _NMSecretAgentCallId Request; - -static Request * +static NMSecretAgentCallId * request_new (NMSecretAgent *self, const char *dbus_command, /* this must be a static string. */ const char *path, @@ -121,9 +123,9 @@ request_new (NMSecretAgent *self, NMSecretAgentCallback callback, gpointer callback_data) { - Request *r; + NMSecretAgentCallId *r; - r = g_slice_new0 (Request); + r = g_slice_new0 (NMSecretAgentCallId); r->agent = self; r->path = g_strdup (path); r->setting_name = g_strdup (setting_name); @@ -139,21 +141,21 @@ request_new (NMSecretAgent *self, #define request_new(self,dbus_command,path,setting_name,callback,callback_data) request_new(self,""dbus_command"",path,setting_name,callback,callback_data) static void -request_free (Request *r) +request_free (NMSecretAgentCallId *r) { NMSecretAgent *self = r->agent; _LOGt ("request "LOG_REQ_FMT": destroyed", LOG_REQ_ARG (r)); - c_list_unlink (&r->lst); + c_list_unlink_stale (&r->lst); g_free (r->path); g_free (r->setting_name); if (r->cancellable) g_object_unref (r->cancellable); - g_slice_free (Request, r); + g_slice_free (NMSecretAgentCallId, r); } static gboolean -request_check_return (Request *r) +request_check_return (NMSecretAgentCallId *r) { if (!r->cancellable) return FALSE; @@ -163,7 +165,7 @@ request_check_return (Request *r) nm_assert (c_list_contains (&NM_SECRET_AGENT_GET_PRIVATE (r->agent)->requests, &r->lst)); - c_list_unlink_init (&r->lst); + c_list_unlink (&r->lst); return TRUE; } @@ -329,7 +331,7 @@ get_callback (GObject *proxy, GAsyncResult *result, gpointer user_data) { - Request *r = user_data; + NMSecretAgentCallId *r = user_data; if (request_check_return (r)) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); @@ -345,7 +347,7 @@ get_callback (GObject *proxy, request_free (r); } -NMSecretAgentCallId +NMSecretAgentCallId * nm_secret_agent_get_secrets (NMSecretAgent *self, const char *path, NMConnection *connection, @@ -358,7 +360,7 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, NMSecretAgentPrivate *priv; static const char *no_hints[] = { NULL }; GVariant *dict; - Request *r; + NMSecretAgentCallId *r; g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); @@ -411,7 +413,7 @@ cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data) } static void -do_cancel_secrets (NMSecretAgent *self, Request *r, gboolean disposing) +do_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId *r, gboolean disposing) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); GCancellable *cancellable; @@ -467,9 +469,9 @@ do_cancel_secrets (NMSecretAgent *self, Request *r, gboolean disposing) * callback before nm_secret_agent_cancel_secrets() returns. */ void -nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId call_id) +nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId *call_id) { - Request *r = call_id; + NMSecretAgentCallId *r = call_id; g_return_if_fail (NM_IS_SECRET_AGENT (self)); g_return_if_fail (r); @@ -477,7 +479,7 @@ nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId call_id nm_assert (c_list_contains (&NM_SECRET_AGENT_GET_PRIVATE (self)->requests, &r->lst)); - c_list_unlink_init (&r->lst); + c_list_unlink (&r->lst); do_cancel_secrets (self, r, FALSE); } @@ -489,7 +491,7 @@ agent_save_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { - Request *r = user_data; + NMSecretAgentCallId *r = user_data; if (request_check_return (r)) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); @@ -504,7 +506,7 @@ agent_save_cb (GObject *proxy, request_free (r); } -NMSecretAgentCallId +NMSecretAgentCallId * nm_secret_agent_save_secrets (NMSecretAgent *self, const char *path, NMConnection *connection, @@ -513,7 +515,7 @@ nm_secret_agent_save_secrets (NMSecretAgent *self, { NMSecretAgentPrivate *priv; GVariant *dict; - Request *r; + NMSecretAgentCallId *r; g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); @@ -541,7 +543,7 @@ agent_delete_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { - Request *r = user_data; + NMSecretAgentCallId *r = user_data; if (request_check_return (r)) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); @@ -556,7 +558,7 @@ agent_delete_cb (GObject *proxy, request_free (r); } -NMSecretAgentCallId +NMSecretAgentCallId * nm_secret_agent_delete_secrets (NMSecretAgent *self, const char *path, NMConnection *connection, @@ -565,7 +567,7 @@ nm_secret_agent_delete_secrets (NMSecretAgent *self, { NMSecretAgentPrivate *priv; GVariant *dict; - Request *r; + NMSecretAgentCallId *r; g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); @@ -668,6 +670,7 @@ nm_secret_agent_new (GDBusMethodInvocation *context, char *owner_username = NULL; char *description = NULL; char buf_subject[64]; + char buf_caps[150]; gulong uid; GDBusConnection *connection; @@ -696,12 +699,13 @@ nm_secret_agent_new (GDBusMethodInvocation *context, priv->connection = g_object_ref (connection); priv->connection_is_private = !!nm_bus_manager_connection_get_private_name (priv->bus_mgr, connection); - _LOGt ("constructed: %s, owner=%s%s%s (%s), private-connection=%d, unique-name=%s%s%s", + _LOGt ("constructed: %s, owner=%s%s%s (%s), private-connection=%d, unique-name=%s%s%s, capabilities=%s", (description = _create_description (dbus_owner, identifier, uid)), NM_PRINT_FMT_QUOTE_STRING (owner_username), nm_auth_subject_to_string (subject, buf_subject, sizeof (buf_subject)), priv->connection_is_private, - NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->connection))); + NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->connection)), + _capabilities_to_string (capabilities, buf_caps, sizeof (buf_caps))); priv->identifier = g_strdup (identifier); priv->owner_username = owner_username; @@ -759,8 +763,8 @@ dispose (GObject *object) again: c_list_for_each (iter, &priv->requests) { - c_list_unlink_init (iter); - do_cancel_secrets (self, c_list_entry (iter, Request, lst), TRUE); + c_list_unlink (iter); + do_cancel_secrets (self, c_list_entry (iter, NMSecretAgentCallId, lst), TRUE); goto again; } diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h index 54c5b398..64b103aa 100644 --- a/src/settings/nm-secret-agent.h +++ b/src/settings/nm-secret-agent.h @@ -33,8 +33,7 @@ #define NM_SECRET_AGENT_DISCONNECTED "disconnected" typedef struct _NMSecretAgentClass NMSecretAgentClass; - -typedef struct _NMSecretAgentCallId *NMSecretAgentCallId; +typedef struct _NMSecretAgentCallId NMSecretAgentCallId; GType nm_secret_agent_get_type (void); @@ -67,12 +66,12 @@ gboolean nm_secret_agent_has_permission (NMSecretAgent *agent, const char *permission); typedef void (*NMSecretAgentCallback) (NMSecretAgent *agent, - NMSecretAgentCallId call_id, + NMSecretAgentCallId *call_id, GVariant *new_secrets, /* NULL for save & delete */ GError *error, gpointer user_data); -NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *agent, +NMSecretAgentCallId *nm_secret_agent_get_secrets (NMSecretAgent *agent, const char *path, NMConnection *connection, const char *setting_name, @@ -82,18 +81,18 @@ NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *agent, gpointer callback_data); void nm_secret_agent_cancel_secrets (NMSecretAgent *agent, - NMSecretAgentCallId call_id); - -NMSecretAgentCallId nm_secret_agent_save_secrets (NMSecretAgent *agent, - const char *path, - NMConnection *connection, - NMSecretAgentCallback callback, - gpointer callback_data); - -NMSecretAgentCallId nm_secret_agent_delete_secrets (NMSecretAgent *agent, - const char *path, - NMConnection *connection, - NMSecretAgentCallback callback, - gpointer callback_data); + NMSecretAgentCallId *call_id); + +NMSecretAgentCallId *nm_secret_agent_save_secrets (NMSecretAgent *agent, + const char *path, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); + +NMSecretAgentCallId *nm_secret_agent_delete_secrets (NMSecretAgent *agent, + const char *path, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); #endif /* __NETWORKMANAGER_SECRET_AGENT_H__ */ diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index ed69115c..b6e89404 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -25,6 +25,8 @@ #include <string.h> +#include "nm-utils/c-list.h" + #include "nm-common-macros.h" #include "nm-config.h" #include "nm-config-data.h" @@ -42,9 +44,8 @@ #define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps" #define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids" -#define AUTOCONNECT_RETRIES_UNSET -2 -#define AUTOCONNECT_RETRIES_FOREVER -1 -#define AUTOCONNECT_RETRIES_DEFAULT 4 +#define AUTOCONNECT_RETRIES_UNSET -2 +#define AUTOCONNECT_RETRIES_FOREVER -1 #define AUTOCONNECT_RESET_RETRIES_TIMER 300 /*****************************************************************************/ @@ -52,7 +53,6 @@ static void nm_settings_connection_connection_interface_init (NMConnectionInterface *iface); NM_GOBJECT_PROPERTIES_DEFINE (NMSettingsConnection, - PROP_VISIBLE, PROP_UNSAVED, PROP_READY, PROP_FLAGS, @@ -74,21 +74,18 @@ typedef struct _NMSettingsConnectionPrivate { NMSessionMonitor *session_monitor; gulong session_changed_id; - NMSettingsConnectionFlags flags; + NMSettingsConnectionFlags flags:5; bool removed:1; bool ready:1; - /* Is this connection visible by some session? */ - bool visible:1; - bool timestamp_set:1; - NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:3; + NMSettingsAutoconnectBlockedReason autoconnect_blocked_reason:4; GSList *pending_auths; /* List of pending authentication requests */ - GSList *get_secret_requests; /* in-progress secrets requests */ + CList call_ids_lst_head; /* in-progress secrets requests */ /* Caches secrets from on-disk connections; were they not cached any * call to nm_connection_clear_secrets() wipes them out and we'd have @@ -105,13 +102,17 @@ typedef struct _NMSettingsConnectionPrivate { */ NMConnection *agent_secrets; - guint64 timestamp; /* Up-to-date timestamp of connection use */ + char *filename; + GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */ + guint64 timestamp; /* Up-to-date timestamp of connection use */ + + guint64 last_secret_agent_version_id; + int autoconnect_retries; - gint32 autoconnect_blocked_until; + gint32 autoconnect_retries_blocked_until; - char *filename; } NMSettingsConnectionPrivate; G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_EXPORTED_OBJECT, @@ -170,6 +171,16 @@ nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection * /*****************************************************************************/ +guint64 +nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self) +{ + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), 0); + + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->last_secret_agent_version_id; +} + +/*****************************************************************************/ + /* Return TRUE to keep, FALSE to drop */ typedef gboolean (*ForEachSecretFunc) (NMSettingSecretFlags flags, gpointer user_data); @@ -308,20 +319,9 @@ find_secret (NMConnection *self, static void set_visible (NMSettingsConnection *self, gboolean new_visible) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - - if (new_visible == priv->visible) - return; - priv->visible = new_visible; - _notify (self, PROP_VISIBLE); -} - -gboolean -nm_settings_connection_is_visible (NMSettingsConnection *self) -{ - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); - - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->visible; + nm_settings_connection_set_flags (self, + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE, + new_visible); } void @@ -389,7 +389,8 @@ nm_settings_connection_check_permission (NMSettingsConnection *self, priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - if (priv->visible == FALSE) + if (!NM_FLAGS_HAS (nm_settings_connection_get_flags (self), + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) return FALSE; s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); @@ -487,33 +488,87 @@ secrets_cleared_cb (NMSettingsConnection *self) } static void -set_unsaved (NMSettingsConnection *self, gboolean now_unsaved) +set_persist_mode (NMSettingsConnection *self, NMSettingsConnectionPersistMode persist_mode) { - NMSettingsConnectionFlags flags = nm_settings_connection_get_flags (self); + NMSettingsConnectionFlags flags = NM_SETTINGS_CONNECTION_FLAGS_NONE; + const NMSettingsConnectionFlags ALL = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED + | NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED + | NM_SETTINGS_CONNECTION_FLAGS_VOLATILE; - if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != !!now_unsaved) { - if (now_unsaved) - flags |= NM_SETTINGS_CONNECTION_FLAGS_UNSAVED; - else { - flags &= ~(NM_SETTINGS_CONNECTION_FLAGS_UNSAVED | - NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | - NM_SETTINGS_CONNECTION_FLAGS_VOLATILE); - } - nm_settings_connection_set_flags_all (self, flags); + switch (persist_mode) { + case NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK: + flags = NM_SETTINGS_CONNECTION_FLAGS_NONE; + break; + case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY: + case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED: + case NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY: + flags = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED; + break; + case NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED: + case NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY: + flags = NM_SETTINGS_CONNECTION_FLAGS_UNSAVED | + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE; + break; + case NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED: + /* only set the connection as unsaved, but preserve the nm-generated + * and volatile flag. */ + nm_settings_connection_set_flags (self, + NM_SETTINGS_CONNECTION_FLAGS_UNSAVED, + TRUE); + return; + case NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP: + /* Nothing to do */ + return; } + + nm_settings_connection_set_flags_full (self, ALL, flags); } static void connection_changed_cb (NMSettingsConnection *self, gpointer unused) { - set_unsaved (self, TRUE); + set_persist_mode (self, NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED); _emit_updated (self, FALSE); } -gboolean -nm_settings_connection_replace_settings_prepare (NMSettingsConnection *self, - NMConnection *new_connection, - GError **error) +static gboolean +_delete (NMSettingsConnection *self, GError **error) +{ + NMSettingsConnectionClass *klass; + GError *local = NULL; + const char *filename; + + nm_assert (NM_IS_SETTINGS_CONNECTION (self)); + + klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); + if (!klass->delete) { + g_set_error (&local, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "delete not supported"); + goto fail; + } + if (!klass->delete (self, + &local)) + goto fail; + + filename = nm_settings_connection_get_filename (self); + if (filename) { + _LOGD ("delete: success deleting connection (\"%s\")", filename); + nm_settings_connection_set_filename (self, NULL); + } else + _LOGT ("delete: success deleting connection (no-file)"); + return TRUE; +fail: + _LOGD ("delete: failure deleting connection: %s", local->message); + g_propagate_error (error, local); + return FALSE; +} + +static gboolean +_update_prepare (NMSettingsConnection *self, + NMConnection *new_connection, + GError **error) { NMSettingsConnectionPrivate *priv; @@ -538,173 +593,136 @@ nm_settings_connection_replace_settings_prepare (NMSettingsConnection *self, } gboolean -nm_settings_connection_replace_settings_full (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean prepare_new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error) +nm_settings_connection_update (NMSettingsConnection *self, + NMConnection *new_connection, + NMSettingsConnectionPersistMode persist_mode, + NMSettingsConnectionCommitReason commit_reason, + const char *log_diff_name, + GError **error) { NMSettingsConnectionPrivate *priv; + NMSettingsConnectionClass *klass = NULL; + gs_unref_object NMConnection *reread_connection = NULL; + NMConnection *replace_connection; + gboolean replaced = FALSE; + gs_free char *logmsg_change = NULL; + GError *local = NULL; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (new_connection), FALSE); priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - if ( prepare_new_connection - && !nm_settings_connection_replace_settings_prepare (self, - new_connection, - error)) - return FALSE; + if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) { + klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); + if (!klass->commit_changes) { + g_set_error (&local, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "writing settings not supported"); + goto out; + } + } - /* Do nothing if there's nothing to update */ - if (nm_connection_compare (NM_CONNECTION (self), - new_connection, - NM_SETTING_COMPARE_FLAG_EXACT)) { - return TRUE; + if ( new_connection + && !_update_prepare (self, + new_connection, + &local)) + goto out; + + if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) { + if (!klass->commit_changes (self, + new_connection ?: NM_CONNECTION (self), + commit_reason, + &reread_connection, + &logmsg_change, + &local)) + goto out; + + if ( reread_connection + && !_update_prepare (self, + reread_connection, + &local)) + goto out; } + replace_connection = reread_connection ?: new_connection; + /* Disconnect the changed signal to ensure we don't set Unsaved when * it's not required. */ g_signal_handlers_block_by_func (self, G_CALLBACK (connection_changed_cb), NULL); - if (log_diff_name) - nm_utils_log_connection_diff (new_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ "); + /* Do nothing if there's nothing to update */ + if ( replace_connection + && !nm_connection_compare (NM_CONNECTION (self), + replace_connection, + NM_SETTING_COMPARE_FLAG_EXACT)) { + if (log_diff_name) + nm_utils_log_connection_diff (replace_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ "); - nm_connection_replace_settings_from_connection (NM_CONNECTION (self), new_connection); + nm_connection_replace_settings_from_connection (NM_CONNECTION (self), replace_connection); - _LOGD ("replace settings from connection %p (%s)", new_connection, nm_connection_get_id (NM_CONNECTION (self))); + replaced = TRUE; + } nm_settings_connection_set_flags (self, NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_FLAGS_VOLATILE, FALSE); - /* Cache the just-updated system secrets in case something calls - * nm_connection_clear_secrets() and clears them. - */ - update_system_secrets_cache (self); + if (replaced) { + /* Cache the just-updated system secrets in case something calls + * nm_connection_clear_secrets() and clears them. + */ + update_system_secrets_cache (self); - /* Add agent and always-ask secrets back; they won't necessarily be - * in the replacement connection data if it was eg reread from disk. - */ - if (priv->agent_secrets) { - GVariant *dict; + /* Add agent and always-ask secrets back; they won't necessarily be + * in the replacement connection data if it was eg reread from disk. + */ + if (priv->agent_secrets) { + GVariant *dict; - dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); - if (dict) { - (void) nm_connection_update_secrets (NM_CONNECTION (self), NULL, dict, NULL); - g_variant_unref (dict); + dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + if (dict) { + (void) nm_connection_update_secrets (NM_CONNECTION (self), NULL, dict, NULL); + g_variant_unref (dict); + } } } nm_settings_connection_recheck_visibility (self); - /* Manually emit changed signal since we disconnected the handler, but - * only update Unsaved if the caller wanted us to. - */ - if (update_unsaved) - set_unsaved (self, TRUE); + if ( replaced + && persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP) + set_persist_mode (self, NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED); + else + set_persist_mode (self, persist_mode); + + if (NM_IN_SET (persist_mode, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY)) + _delete (self, NULL); + else if (NM_IN_SET (persist_mode, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED, + NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED)) + nm_settings_connection_set_filename (self, NULL); g_signal_handlers_unblock_by_func (self, G_CALLBACK (connection_changed_cb), NULL); _emit_updated (self, TRUE); - return TRUE; -} - -/* Update the settings of this connection to match that of 'new_connection', - * taking care to make a private copy of secrets. - */ -gboolean -nm_settings_connection_replace_settings (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error) -{ - return nm_settings_connection_replace_settings_full (self, - new_connection, - TRUE, - update_unsaved, - log_diff_name, - error); -} - -gboolean -nm_settings_connection_commit_changes (NMSettingsConnection *self, - NMConnection *new_connection, - NMSettingsConnectionCommitReason commit_reason, - GError **error) -{ - NMSettingsConnectionClass *klass; - gs_free_error GError *local = NULL; - gs_unref_object NMConnection *reread_connection = NULL; - gs_free char *logmsg_change = NULL; - - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); - - klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); - if (!klass->commit_changes) { - _LOGW ("write: setting plugin %s does not support to write connection", - G_OBJECT_TYPE_NAME (self)); - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "writing settings not supported"); - return FALSE; - } - - if ( new_connection - && !nm_settings_connection_replace_settings_prepare (self, - new_connection, - &local)) { - _LOGW ("write: failed to prepare connection for writing: %s", - local->message); - g_propagate_error (error, g_steal_pointer (&local)); - return FALSE; - } - - if (!klass->commit_changes (self, - new_connection, - commit_reason, - &reread_connection, - &logmsg_change, - &local)) { - _LOGW ("write: failure to write setting: %s", - local->message); - g_propagate_error (error, g_steal_pointer (&local)); +out: + if (local) { + _LOGI ("write: failure to update connection: %s", local->message); + g_propagate_error (error, local); return FALSE; } - if (reread_connection || new_connection) { - if (!nm_settings_connection_replace_settings_full (self, - reread_connection ?: new_connection, - !reread_connection, - FALSE, - new_connection - ? "update-during-write" - : "replace-and-commit-disk", - &local)) { - /* this can't really happen, because at this point replace-settings - * is no longer supposed to fail. It's a bug. */ - _LOGE ("write: replacing setting failed: %s", - local->message); - g_propagate_error (error, g_steal_pointer (&local)); - g_return_val_if_reached (FALSE); - } + if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) { + if (reread_connection) + _LOGI ("write: successfully updated (%s), connection was modified in the process", logmsg_change); + else if (new_connection) + _LOGI ("write: successfully updated (%s)", logmsg_change); + else + _LOGI ("write: successfully commited (%s)", logmsg_change); } - - set_unsaved (self, FALSE); - - if (reread_connection) - _LOGI ("write: successfully updated (%s), connection was modified in the process", logmsg_change); - else if (new_connection) - _LOGI ("write: successfully updated (%s)", logmsg_change); - else - _LOGI ("write: successfully commited (%s)", logmsg_change); - return TRUE; } @@ -749,25 +767,14 @@ nm_settings_connection_delete (NMSettingsConnection *self, GError **error) { gs_unref_object NMSettingsConnection *self_keep_alive = NULL; - NMSettingsConnectionClass *klass; NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMConnection *for_agents; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); - klass = NM_SETTINGS_CONNECTION_GET_CLASS (self); - self_keep_alive = g_object_ref (self); - if (!klass->delete) { - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "delete not supported"); - return FALSE; - } - if (!klass->delete (self, - error)) + if (!_delete (self, error)) return FALSE; set_visible (self, FALSE); @@ -795,18 +802,19 @@ nm_settings_connection_delete (NMSettingsConnection *self, typedef enum { - GET_SECRETS_INFO_TYPE_REQ, - GET_SECRETS_INFO_TYPE_IDLE, -} GetSecretsInfoType; + CALL_ID_TYPE_REQ, + CALL_ID_TYPE_IDLE, +} CallIdType; struct _NMSettingsConnectionCallId { NMSettingsConnection *self; + CList call_ids_lst; gboolean had_applied_connection; NMConnection *applied_connection; NMSettingsConnectionSecretsFunc callback; gpointer callback_data; - GetSecretsInfoType type; + CallIdType type; union { struct { NMAgentManagerCallId id; @@ -818,59 +826,36 @@ struct _NMSettingsConnectionCallId { } t; }; -typedef struct _NMSettingsConnectionCallId GetSecretsInfo; - -static GetSecretsInfo * -_get_secrets_info_new (NMSettingsConnection *self, - NMConnection *applied_connection, - NMSettingsConnectionSecretsFunc callback, - gpointer callback_data) -{ - GetSecretsInfo *info; - - info = g_slice_new0 (GetSecretsInfo); - - info->self = self; - if (applied_connection) { - info->had_applied_connection = TRUE; - info->applied_connection = applied_connection; - g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &info->applied_connection); - } - info->callback = callback; - info->callback_data = callback_data; - - return info; -} - static void -_get_secrets_info_callback (GetSecretsInfo *info, +_get_secrets_info_callback (NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error) { - if (info->callback) { - info->callback (info->self, - info, - agent_username, - setting_name, - error, - info->callback_data); + if (call_id->callback) { + call_id->callback (call_id->self, + call_id, + agent_username, + setting_name, + error, + call_id->callback_data); } } static void -_get_secrets_info_free (GetSecretsInfo *info) +_get_secrets_info_free (NMSettingsConnectionCallId *call_id) { - g_return_if_fail (info && info->self); + g_return_if_fail (call_id && call_id->self); + nm_assert (!c_list_is_linked (&call_id->call_ids_lst)); - if (info->applied_connection) - g_object_remove_weak_pointer (G_OBJECT (info->applied_connection), (gpointer *) &info->applied_connection); + if (call_id->applied_connection) + g_object_remove_weak_pointer (G_OBJECT (call_id->applied_connection), (gpointer *) &call_id->applied_connection); - if (info->type == GET_SECRETS_INFO_TYPE_IDLE) - g_clear_error (&info->t.idle.error); + if (call_id->type == CALL_ID_TYPE_IDLE) + g_clear_error (&call_id->t.idle.error); - memset (info, 0, sizeof (*info)); - g_slice_free (GetSecretsInfo, info); + memset (call_id, 0, sizeof (*call_id)); + g_slice_free (NMSettingsConnectionCallId, call_id); } static gboolean @@ -907,7 +892,7 @@ secret_is_system_owned (NMSettingSecretFlags flags, static void get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ - GetSecretsInfo *info, /* only needed for logging */ + NMSettingsConnectionCallId *call_id, /* only needed for logging */ NMConnection *connection, const char *agent_dbus_owner, gboolean agent_has_modify, @@ -930,7 +915,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) secrets returned from agent %s", setting_name, - info, + call_id, agent_dbus_owner); } @@ -949,7 +934,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) interaction forbidden but agent %s returned system secrets", setting_name, - info, + call_id, agent_dbus_owner); } @@ -961,7 +946,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) agent failed to authenticate but provided system secrets", setting_name, - info); + call_id); } cmp_flags->required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; @@ -971,7 +956,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ if (is_self) { _LOGD ("(%s:%p) existing secrets returned", setting_name, - info); + call_id); } } @@ -1004,10 +989,12 @@ nm_settings_connection_new_secrets (NMSettingsConnection *self, update_system_secrets_cache (self); update_agent_secrets_cache (self, NULL); - nm_settings_connection_commit_changes (self, - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - NULL); + nm_settings_connection_update (self, + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "new-secrets", + NULL); return TRUE; } @@ -1023,7 +1010,7 @@ get_secrets_done_cb (NMAgentManager *manager, GError *error, gpointer user_data) { - GetSecretsInfo *info = user_data; + NMSettingsConnectionCallId *call_id = user_data; NMSettingsConnection *self; NMSettingsConnectionPrivate *priv; NMConnection *applied_connection; @@ -1035,36 +1022,36 @@ get_secrets_done_cb (NMAgentManager *manager, if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - self = info->self; + self = call_id->self; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (g_slist_find (priv->get_secret_requests, info)); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink (&call_id->call_ids_lst); if (error) { _LOGD ("(%s:%p) secrets request error: %s", - setting_name, info, error->message); + setting_name, call_id, error->message); - _get_secrets_info_callback (info, NULL, setting_name, error); + _get_secrets_info_callback (call_id, NULL, setting_name, error); goto out; } - if ( info->had_applied_connection - && !info->applied_connection) { + if ( call_id->had_applied_connection + && !call_id->applied_connection) { g_set_error_literal (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "Applied connection deleted since requesting secrets"); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } - if ( info->had_applied_connection - && !nm_settings_connection_has_unmodified_applied_connection (self, info->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) { + if ( call_id->had_applied_connection + && !nm_settings_connection_has_unmodified_applied_connection (self, call_id->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) { g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "The connection was modified since activation"); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } @@ -1072,12 +1059,12 @@ get_secrets_done_cb (NMAgentManager *manager, g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "Connection didn't have requested setting '%s'.", setting_name); - _get_secrets_info_callback (info, NULL, setting_name, local); + _get_secrets_info_callback (call_id, NULL, setting_name, local); goto out; } get_cmp_flags (self, - info, + call_id, NM_CONNECTION (self), agent_dbus_owner, agent_has_modify, @@ -1089,7 +1076,7 @@ get_secrets_done_cb (NMAgentManager *manager, _LOGD ("(%s:%p) secrets request completed", setting_name, - info); + call_id); dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); @@ -1119,36 +1106,38 @@ get_secrets_done_cb (NMAgentManager *manager, if (agent_had_system) { _LOGD ("(%s:%p) saving new secrets to backing storage", setting_name, - info); - - nm_settings_connection_commit_changes (self, - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - NULL); + call_id); + + nm_settings_connection_update (self, + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "get-new-secrets", + NULL); } else { _LOGD ("(%s:%p) new agent secrets processed", setting_name, - info); + call_id); } } else { _LOGD ("(%s:%p) failed to update with agent secrets: %s", setting_name, - info, + call_id, local->message); } g_variant_unref (filtered_secrets); } else { _LOGD ("(%s:%p) failed to update with existing secrets: %s", setting_name, - info, + call_id, local->message); } - applied_connection = info->applied_connection; + applied_connection = call_id->applied_connection; if (applied_connection) { get_cmp_flags (self, - info, + call_id, applied_connection, agent_dbus_owner, agent_has_modify, @@ -1169,31 +1158,31 @@ get_secrets_done_cb (NMAgentManager *manager, } } - _get_secrets_info_callback (info, agent_username, setting_name, local); + _get_secrets_info_callback (call_id, agent_username, setting_name, local); g_clear_error (&local); if (dict) g_variant_unref (dict); out: - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); } static gboolean -get_secrets_idle_cb (GetSecretsInfo *info) +get_secrets_idle_cb (NMSettingsConnectionCallId *call_id) { NMSettingsConnectionPrivate *priv; - g_return_val_if_fail (info && NM_IS_SETTINGS_CONNECTION (info->self), G_SOURCE_REMOVE); + g_return_val_if_fail (call_id && NM_IS_SETTINGS_CONNECTION (call_id->self), G_SOURCE_REMOVE); - priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (info->self); + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (call_id->self); - g_return_val_if_fail (g_slist_find (priv->get_secret_requests, info), G_SOURCE_REMOVE); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink (&call_id->call_ids_lst); - _get_secrets_info_callback (info, NULL, NULL, info->t.idle.error); + _get_secrets_info_callback (call_id, NULL, NULL, call_id->t.idle.error); - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); return G_SOURCE_REMOVE; } @@ -1222,13 +1211,13 @@ get_secrets_idle_cb (GetSecretsInfo *info) * * Returns: a call ID which may be used to cancel the ongoing secrets request. **/ -NMSettingsConnectionCallId +NMSettingsConnectionCallId * nm_settings_connection_get_secrets (NMSettingsConnection *self, NMConnection *applied_connection, NMAuthSubject *subject, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - const char **hints, + const char *const*hints, NMSettingsConnectionSecretsFunc callback, gpointer callback_data) { @@ -1236,7 +1225,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, GVariant *existing_secrets; NMAgentManagerCallId call_id_a; gs_free char *joined_hints = NULL; - GetSecretsInfo *info; + NMSettingsConnectionCallId *call_id; GError *local = NULL; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NULL); @@ -1244,12 +1233,16 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, || ( NM_IS_CONNECTION (applied_connection) && (((NMConnection *) self) != applied_connection)), NULL); - info = _get_secrets_info_new (self, - applied_connection, - callback, - callback_data); - - priv->get_secret_requests = g_slist_append (priv->get_secret_requests, info); + call_id = g_slice_new0 (NMSettingsConnectionCallId); + call_id->self = self; + if (applied_connection) { + call_id->had_applied_connection = TRUE; + call_id->applied_connection = applied_connection; + g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &call_id->applied_connection); + } + call_id->callback = callback; + call_id->callback_data = callback_data; + c_list_link_tail (&priv->call_ids_lst_head, &call_id->call_ids_lst); /* Use priv->secrets to work around the fact that nm_connection_clear_secrets() * will clear secrets on this object's settings. @@ -1278,6 +1271,14 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, existing_secrets = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); if (existing_secrets) g_variant_ref_sink (existing_secrets); + + /* we remember the current version-id of the secret-agents. The version-id is strictly increasing, + * as new agents register the number. We know hence, that this request was made against a certain + * set of secret-agents. + * If after making this request a new secret-agent registeres, the version-id increases. + * Then we know that the this request probably did not yet include the latest secret-agent. */ + priv->last_secret_agent_version_id = nm_agent_manager_get_agent_version_id (priv->agent_mgr); + call_id_a = nm_agent_manager_get_secrets (priv->agent_mgr, nm_connection_get_path (NM_CONNECTION (self)), NM_CONNECTION (self), @@ -1287,7 +1288,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, flags, hints, get_secrets_done_cb, - info); + call_id); g_assert (call_id_a); if (existing_secrets) g_variant_unref (existing_secrets); @@ -1299,45 +1300,44 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, (hints && hints[0]) ? (joined_hints = g_strjoinv (",", (char **) hints)) : "(none)"); if (call_id_a) { - info->type = GET_SECRETS_INFO_TYPE_REQ; - info->t.req.id = call_id_a; + call_id->type = CALL_ID_TYPE_REQ; + call_id->t.req.id = call_id_a; } else { schedule_dummy: - info->type = GET_SECRETS_INFO_TYPE_IDLE; - g_propagate_error (&info->t.idle.error, local); - info->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, info); + call_id->type = CALL_ID_TYPE_IDLE; + g_propagate_error (&call_id->t.idle.error, local); + call_id->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, call_id); } - return info; + return call_id; } static void _get_secrets_cancel (NMSettingsConnection *self, - GetSecretsInfo *info, + NMSettingsConnectionCallId *call_id, gboolean is_disposing) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); gs_free_error GError *error = NULL; - if (!g_slist_find (priv->get_secret_requests, info)) - g_return_if_reached (); + nm_assert (c_list_contains (&priv->call_ids_lst_head, &call_id->call_ids_lst)); - priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + c_list_unlink (&call_id->call_ids_lst); - if (info->type == GET_SECRETS_INFO_TYPE_REQ) - nm_agent_manager_cancel_secrets (priv->agent_mgr, info->t.req.id); + if (call_id->type == CALL_ID_TYPE_REQ) + nm_agent_manager_cancel_secrets (priv->agent_mgr, call_id->t.req.id); else - g_source_remove (info->t.idle.id); + g_source_remove (call_id->t.idle.id); nm_utils_error_set_cancelled (&error, is_disposing, "NMSettingsConnection"); - _get_secrets_info_callback (info, NULL, NULL, error); + _get_secrets_info_callback (call_id, NULL, NULL, error); - _get_secrets_info_free (info); + _get_secrets_info_free (call_id); } void nm_settings_connection_cancel_secrets (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id) + NMSettingsConnectionCallId *call_id) { _LOGD ("(%p) secrets canceled", call_id); @@ -1581,8 +1581,9 @@ typedef struct { NMAgentManager *agent_mgr; NMAuthSubject *subject; NMConnection *new_settings; - gboolean save_to_disk; + NMSettingsUpdate2Flags flags; char *audit_args; + bool is_update2:1; } UpdateInfo; static void @@ -1646,7 +1647,13 @@ update_complete (NMSettingsConnection *self, { if (error) g_dbus_method_invocation_return_gerror (info->context, error); - else + else if (info->is_update2) { + GVariantBuilder result; + + g_variant_builder_init (&result, G_VARIANT_TYPE ("a{sv}")); + g_dbus_method_invocation_return_value (info->context, + g_variant_new ("(@a{sv})", g_variant_builder_end (&result))); + } else g_dbus_method_invocation_return_value (info->context, NULL); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, self, !error, info->audit_args, @@ -1656,8 +1663,7 @@ update_complete (NMSettingsConnection *self, g_clear_object (&info->agent_mgr); g_clear_object (&info->new_settings); g_free (info->audit_args); - memset (info, 0, sizeof (*info)); - g_free (info); + g_slice_free (UpdateInfo, info); } static void @@ -1670,6 +1676,8 @@ update_auth_cb (NMSettingsConnection *self, UpdateInfo *info = data; NMSettingsConnectionCommitReason commit_reason; gs_free_error GError *local = NULL; + NMSettingsConnectionPersistMode persist_mode; + const char *log_diff_name; if (error) { update_complete (self, info, error); @@ -1690,7 +1698,9 @@ update_auth_cb (NMSettingsConnection *self, */ update_agent_secrets_cache (self, info->new_settings); } + } + if (info->new_settings) { if (nm_audit_manager_audit_enabled (nm_audit_manager_get ())) { gs_unref_hashtable GHashTable *diff = NULL; gboolean same; @@ -1704,36 +1714,47 @@ update_auth_cb (NMSettingsConnection *self, } } - if (!info->save_to_disk) { - if (info->new_settings) { - nm_settings_connection_replace_settings (self, - info->new_settings, - TRUE, - "replace-unsaved", - &local); - } - goto out; - } - - if (info->new_settings) { - if (!nm_settings_connection_replace_settings_prepare (self, - info->new_settings, - &local)) - goto out; - } - commit_reason = NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION; if ( info->new_settings && !nm_streq0 (nm_connection_get_id (NM_CONNECTION (self)), nm_connection_get_id (info->new_settings))) commit_reason |= NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED; - nm_settings_connection_commit_changes (self, - info->new_settings, - commit_reason, - &local); + if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_TO_DISK)) + persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK; + else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY)) + persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY; + else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED)) { + persist_mode = NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE) + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED + : NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED; + } else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY)) { + persist_mode = NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE) + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY + : NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY; + } else + persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP; + + if ( persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK + || ( persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP + && !nm_settings_connection_get_unsaved (self))) + log_diff_name = info->new_settings ? "update-settings" : "write-out-to-disk"; + else + log_diff_name = info->new_settings ? "update-unsaved" : "make-unsaved"; + + if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)) { + nm_settings_connection_autoconnect_blocked_reason_set (self, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, + TRUE); + } + + nm_settings_connection_update (self, + info->new_settings, + persist_mode, + commit_reason, + log_diff_name, + &local); -out: if (!local) { gs_unref_object NMConnection *for_agent = NULL; @@ -1782,10 +1803,11 @@ get_update_modify_permission (NMConnection *old, NMConnection *new) } static void -settings_connection_update_helper (NMSettingsConnection *self, - GDBusMethodInvocation *context, - GVariant *new_settings, - gboolean save_to_disk) +settings_connection_update (NMSettingsConnection *self, + gboolean is_update2, + GDBusMethodInvocation *context, + GVariant *new_settings, + NMSettingsUpdate2Flags flags) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMAuthSubject *subject = NULL; @@ -1795,8 +1817,6 @@ settings_connection_update_helper (NMSettingsConnection *self, const char *permission; char *error_desc = NULL; - g_assert (new_settings != NULL || save_to_disk == TRUE); - /* If the connection is read-only, that has to be changed at the source of * the problem (ex a system settings plugin that can't write connections out) * instead of over D-Bus. @@ -1806,12 +1826,22 @@ settings_connection_update_helper (NMSettingsConnection *self, /* Check if the settings are valid first */ if (new_settings) { - tmp = _nm_simple_connection_new_from_dbus (new_settings, - NM_SETTING_PARSE_FLAGS_STRICT - | NM_SETTING_PARSE_FLAGS_NORMALIZE, - &error); - if (!tmp) + if (!g_variant_is_of_type (new_settings, NM_VARIANT_TYPE_CONNECTION)) { + g_set_error_literal (&error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "settings is of invalid type"); goto error; + } + + if (g_variant_n_children (new_settings) > 0) { + tmp = _nm_simple_connection_new_from_dbus (new_settings, + NM_SETTING_PARSE_FLAGS_STRICT + | NM_SETTING_PARSE_FLAGS_NORMALIZE, + &error); + if (!tmp) + goto error; + } } subject = _new_auth_subject (context, &error); @@ -1832,11 +1862,12 @@ settings_connection_update_helper (NMSettingsConnection *self, goto error; } - info = g_malloc0 (sizeof (*info)); + info = g_slice_new0 (UpdateInfo); + info->is_update2 = is_update2; info->context = context; info->agent_mgr = g_object_ref (priv->agent_mgr); info->subject = subject; - info->save_to_disk = save_to_disk; + info->flags = flags; info->new_settings = tmp; permission = get_update_modify_permission (NM_CONNECTION (self), @@ -1859,7 +1890,7 @@ impl_settings_connection_update (NMSettingsConnection *self, GDBusMethodInvocation *context, GVariant *new_settings) { - settings_connection_update_helper (self, context, new_settings, TRUE); + settings_connection_update (self, FALSE, context, new_settings, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } static void @@ -1867,14 +1898,76 @@ impl_settings_connection_update_unsaved (NMSettingsConnection *self, GDBusMethodInvocation *context, GVariant *new_settings) { - settings_connection_update_helper (self, context, new_settings, FALSE); + settings_connection_update (self, FALSE, context, new_settings, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY); } static void impl_settings_connection_save (NMSettingsConnection *self, GDBusMethodInvocation *context) { - settings_connection_update_helper (self, context, NULL, TRUE); + settings_connection_update (self, FALSE, context, NULL, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); +} + +static void +impl_settings_connection_update2 (NMSettingsConnection *self, + GDBusMethodInvocation *context, + GVariant *settings, + guint32 flags_u, + GVariant *args) +{ + GError *error = NULL; + GVariantIter iter; + const char *args_name; + const NMSettingsUpdate2Flags flags = (NMSettingsUpdate2Flags) flags_u; + const NMSettingsUpdate2Flags ALL_PERSIST_MODES = NM_SETTINGS_UPDATE2_FLAG_TO_DISK + | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY + | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED + | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY; + + if (NM_FLAGS_ANY (flags_u, ~((guint32) (ALL_PERSIST_MODES | + NM_SETTINGS_UPDATE2_FLAG_VOLATILE | + NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT)))) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "Unknown flags"); + g_dbus_method_invocation_take_error (context, error); + return; + } + + if ( ( NM_FLAGS_ANY (flags, ALL_PERSIST_MODES) + && !nm_utils_is_power_of_two (flags & ALL_PERSIST_MODES)) + || ( NM_FLAGS_HAS (flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE) + && !NM_FLAGS_ANY (flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED | + NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY))) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "Conflicting flags"); + g_dbus_method_invocation_take_error (context, error); + return; + } + + if (!g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}"))) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "args is of invalid type"); + g_dbus_method_invocation_take_error (context, error); + return; + } + + g_variant_iter_init (&iter, args); + while (g_variant_iter_next (&iter, "{&sv}", &args_name, NULL)) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_ARGUMENTS, + "Unsupported argument '%s'", args_name); + g_dbus_method_invocation_take_error (context, error); + return; + } + + settings_connection_update (self, + TRUE, + context, + settings, + flags); } static void @@ -1951,7 +2044,7 @@ out_err: static void dbus_get_agent_secrets_cb (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id, + NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error, @@ -2052,10 +2145,12 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, nm_connection_get_path (NM_CONNECTION (self)), NM_CONNECTION (self)); - nm_settings_connection_commit_changes (self, - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - &local); + nm_settings_connection_update (self, + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "clear-secrets", + &local); nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, !local, NULL, subject, local ? local->message : NULL); @@ -2112,6 +2207,14 @@ nm_settings_connection_get_unsaved (NMSettingsConnection *self) /*****************************************************************************/ +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_settings_connection_flags_to_string, NMSettingsConnectionFlags, + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_UNSAVED, "unsaved"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED, "nm-generated"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_VOLATILE, "volatile"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_FLAGS_VISIBLE, "visible"), +); + NMSettingsConnectionFlags nm_settings_connection_get_flags (NMSettingsConnection *self) { @@ -2123,35 +2226,38 @@ nm_settings_connection_get_flags (NMSettingsConnection *self) NMSettingsConnectionFlags nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionFlags flags, gboolean set) { - NMSettingsConnectionFlags new_flags; - - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); - g_return_val_if_fail ((flags & ~NM_SETTINGS_CONNECTION_FLAGS_ALL) == 0, NM_SETTINGS_CONNECTION_FLAGS_NONE); - - new_flags = NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->flags; - if (set) - new_flags |= flags; - else - new_flags &= ~flags; - return nm_settings_connection_set_flags_all (self, new_flags); + return nm_settings_connection_set_flags_full (self, + flags, + set ? flags : NM_SETTINGS_CONNECTION_FLAGS_NONE); } NMSettingsConnectionFlags -nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConnectionFlags flags) +nm_settings_connection_set_flags_full (NMSettingsConnection *self, + NMSettingsConnectionFlags mask, + NMSettingsConnectionFlags value) { NMSettingsConnectionPrivate *priv; NMSettingsConnectionFlags old_flags; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NM_SETTINGS_CONNECTION_FLAGS_NONE); - g_return_val_if_fail ((flags & ~NM_SETTINGS_CONNECTION_FLAGS_ALL) == 0, NM_SETTINGS_CONNECTION_FLAGS_NONE); + nm_assert (mask && !NM_FLAGS_ANY (mask, ~NM_SETTINGS_CONNECTION_FLAGS_ALL)); + nm_assert (!NM_FLAGS_ANY (value, ~mask)); + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + value = (priv->flags & ~mask) | value; + old_flags = priv->flags; - if (old_flags != flags) { - _LOGT ("update settings-connection flags to 0x%x (was 0x%x)", (guint) flags, (guint) priv->flags); - priv->flags = flags; + if (old_flags != value) { + char buf1[255], buf2[255]; + + _LOGT ("update settings-connection flags to %s (was %s)", + _settings_connection_flags_to_string (value, buf1, sizeof (buf1)), + _settings_connection_flags_to_string (priv->flags, buf2, sizeof (buf2))); + priv->flags = value; + nm_assert (priv->flags == value); _notify (self, PROP_FLAGS); - if (NM_FLAGS_HAS (old_flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED)) + if (NM_FLAGS_HAS (old_flags, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED) != NM_FLAGS_HAS (value, NM_SETTINGS_CONNECTION_FLAGS_UNSAVED)) _notify (self, PROP_UNSAVED); } return old_flags; @@ -2533,6 +2639,54 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *self) /*****************************************************************************/ +static int +_autoconnect_retries_initial (NMSettingsConnection *self) +{ + NMSettingConnection *s_con; + int retries = -1; + + s_con = nm_connection_get_setting_connection ((NMConnection *) self); + if (s_con) + retries = nm_setting_connection_get_autoconnect_retries (s_con); + + /* -1 means 'default' */ + if (retries == -1) + retries = nm_config_data_get_autoconnect_retries_default (NM_CONFIG_GET_DATA); + + /* 0 means 'forever', which is translated to a retry count of -1 */ + if (retries == 0) + retries = AUTOCONNECT_RETRIES_FOREVER; + + nm_assert (retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0); + return retries; +} + +static void +_autoconnect_retries_set (NMSettingsConnection *self, + int retries, + gboolean is_reset) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + g_return_if_fail (retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0); + + if (priv->autoconnect_retries != retries) { + _LOGT ("autoconnect: retries set %d%s", retries, + is_reset ? " (reset)" : ""); + priv->autoconnect_retries = retries; + } + + if (retries) + priv->autoconnect_retries_blocked_until = 0; + else { + /* XXX: the blocked time must be identical for all connections, otherwise + * the tracking of resetting the retry count in NMPolicy needs adjustment + * in _connection_autoconnect_retries_set() (as it would need to re-evaluate + * the next-timeout everytime a connection gets blocked). */ + priv->autoconnect_retries_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER; + } +} + /** * nm_settings_connection_autoconnect_retries_get: * @self: the settings connection @@ -2547,30 +2701,10 @@ nm_settings_connection_autoconnect_retries_get (NMSettingsConnection *self) NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); if (G_UNLIKELY (priv->autoconnect_retries == AUTOCONNECT_RETRIES_UNSET)) { - NMSettingConnection *s_con; - int retries = -1; - - s_con = nm_connection_get_setting_connection ((NMConnection *) self); - if (s_con) - retries = nm_setting_connection_get_autoconnect_retries (s_con); - - /* -1 means 'default' */ - if (retries == -1) { - retries = nm_config_data_get_value_int64 (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_GROUP_MAIN, - "autoconnect-retries-default", - 10, 0, G_MAXINT32, - AUTOCONNECT_RETRIES_DEFAULT); - } - - /* 0 means 'forever', which is translated to a retry count of -1 */ - if (retries == 0) - retries = AUTOCONNECT_RETRIES_FOREVER; - - _LOGT ("autoconnect-retries: init %d", retries); - priv->autoconnect_retries = retries; + _autoconnect_retries_set (self, + _autoconnect_retries_initial (self), + TRUE); } - return priv->autoconnect_retries; } @@ -2578,86 +2712,90 @@ void nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self, int retries) { - NMSettingsConnectionPrivate *priv; - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); - nm_assert (retries == AUTOCONNECT_RETRIES_UNSET || retries >= 0); - - priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + g_return_if_fail (retries >= 0); - if (priv->autoconnect_retries != retries) { - _LOGT ("autoconnect-retries: set %d", retries); - priv->autoconnect_retries = retries; - } - if (retries) - priv->autoconnect_blocked_until = 0; - else - priv->autoconnect_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER; + _autoconnect_retries_set (self, retries, FALSE); } void nm_settings_connection_autoconnect_retries_reset (NMSettingsConnection *self) { - nm_settings_connection_autoconnect_retries_set (self, AUTOCONNECT_RETRIES_UNSET); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); + + _autoconnect_retries_set (self, + _autoconnect_retries_initial (self), + TRUE); } gint32 -nm_settings_connection_autoconnect_blocked_until_get (NMSettingsConnection *self) +nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection *self) { - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_until; + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_retries_blocked_until; } +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_autoconnect_blocked_reason_to_string, NMSettingsAutoconnectBlockedReason, + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, "user-request"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, "failed"), + NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, "no-secrets"), +); + NMSettingsAutoconnectBlockedReason -nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self) +nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self, NMSettingsAutoconnectBlockedReason mask) { - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason; + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason & (mask ?: NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL); } -void -nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason reason) +gboolean +nm_settings_connection_autoconnect_blocked_reason_set_full (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + NMSettingsAutoconnectBlockedReason value) { - g_return_if_fail (NM_IN_SET (reason, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS)); - NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_blocked_reason = reason; -} + NMSettingsAutoconnectBlockedReason v; + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + char buf[100]; -/*****************************************************************************/ + nm_assert (mask); + nm_assert (!NM_FLAGS_ANY (value, ~mask)); -/** - * nm_settings_connection_get_nm_generated: - * @self: an #NMSettingsConnection - * - * Gets the "nm-generated" flag on @self. - * - * A connection is "nm-generated" if it was generated by - * nm_device_generate_connection() and has not been modified or - * saved by the user since then. - */ -gboolean -nm_settings_connection_get_nm_generated (NMSettingsConnection *self) -{ - return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED); + v = priv->autoconnect_blocked_reason; + v = (v & ~mask) | (value & mask); + + if (priv->autoconnect_blocked_reason == v) + return FALSE; + + _LOGT ("autoconnect: blocked reason: %s", _autoconnect_blocked_reason_to_string (v, buf, sizeof (buf))); + priv->autoconnect_blocked_reason = v; + return TRUE; } -/** - * nm_settings_connection_get_volatile: - * @self: an #NMSettingsConnection - * - * Gets the "volatile" flag on @self. - * - * The connection is marked as volatile and will be removed when - * it disconnects. - */ gboolean -nm_settings_connection_get_volatile (NMSettingsConnection *self) +nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self) { - return NM_FLAGS_HAS (nm_settings_connection_get_flags (self), NM_SETTINGS_CONNECTION_FLAGS_VOLATILE); + NMSettingsConnectionPrivate *priv; + NMSettingsConnectionFlags flags; + + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), TRUE); + + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + if (priv->autoconnect_blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) + return TRUE; + if (priv->autoconnect_retries == 0) + return TRUE; + + flags = priv->flags; + if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_VOLATILE)) + return TRUE; + if (!NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_FLAGS_VISIBLE)) + return TRUE; + + return FALSE; } +/*****************************************************************************/ + gboolean nm_settings_connection_get_ready (NMSettingsConnection *self) { @@ -2738,8 +2876,8 @@ nm_settings_connection_init (NMSettingsConnection *self) priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionPrivate); self->_priv = priv; - priv->visible = FALSE; priv->ready = TRUE; + c_list_init (&priv->call_ids_lst_head); priv->session_monitor = g_object_ref (nm_session_monitor_get ()); priv->session_changed_id = g_signal_connect (priv->session_monitor, @@ -2771,17 +2909,14 @@ dispose (GObject *object) { NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NMSettingsConnectionCallId *call_id, *call_id_safe; _LOGD ("disposing"); /* Cancel in-progress secrets requests */ if (priv->agent_mgr) { - while (priv->get_secret_requests) { - GetSecretsInfo *info = priv->get_secret_requests->data; - - _get_secrets_cancel (self, info, TRUE); - g_return_if_fail (!priv->get_secret_requests || (info != priv->get_secret_requests->data)); - } + c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst) + _get_secrets_cancel (self, call_id, TRUE); } /* Disconnect handlers. @@ -2818,12 +2953,8 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); switch (prop_id) { - case PROP_VISIBLE: - g_value_set_boolean (value, priv->visible); - break; case PROP_UNSAVED: g_value_set_boolean (value, nm_settings_connection_get_unsaved (self)); break; @@ -2876,12 +3007,6 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) class->supports_secrets = supports_secrets; - obj_properties[PROP_VISIBLE] = - g_param_spec_boolean (NM_SETTINGS_CONNECTION_VISIBLE, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_UNSAVED] = g_param_spec_boolean (NM_SETTINGS_CONNECTION_UNSAVED, "", "", FALSE, @@ -2948,6 +3073,7 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) "GetSecrets", impl_settings_connection_get_secrets, "ClearSecrets", impl_settings_connection_clear_secrets, "Save", impl_settings_connection_save, + "Update2", impl_settings_connection_update2, NULL); } diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index faacd949..fc8ad1de 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -44,8 +44,9 @@ #define NM_SETTINGS_CONNECTION_UPDATED_INTERNAL "updated-internal" /* Properties */ -#define NM_SETTINGS_CONNECTION_VISIBLE "visible" #define NM_SETTINGS_CONNECTION_UNSAVED "unsaved" + +/* Internal properties */ #define NM_SETTINGS_CONNECTION_READY "ready" #define NM_SETTINGS_CONNECTION_FLAGS "flags" #define NM_SETTINGS_CONNECTION_FILENAME "filename" @@ -61,22 +62,25 @@ * @NM_SETTINGS_CONNECTION_FLAGS_VOLATILE: The connection will be deleted * when it disconnects. That is for in-memory connections (unsaved), which are * currently active but cleanup on disconnect. + * @NM_SETTINGS_CONNECTION_FLAGS_VISIBLE: The connection is visible * @NM_SETTINGS_CONNECTION_FLAGS_ALL: special mask, for all known flags * * #NMSettingsConnection flags. **/ -typedef enum -{ - NM_SETTINGS_CONNECTION_FLAGS_NONE = 0x00, - NM_SETTINGS_CONNECTION_FLAGS_UNSAVED = 0x01, - NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED = 0x02, - NM_SETTINGS_CONNECTION_FLAGS_VOLATILE = 0x04, +typedef enum { + NM_SETTINGS_CONNECTION_FLAGS_NONE = 0, + + NM_SETTINGS_CONNECTION_FLAGS_UNSAVED = (1LL << 0), + NM_SETTINGS_CONNECTION_FLAGS_NM_GENERATED = (1LL << 1), + NM_SETTINGS_CONNECTION_FLAGS_VOLATILE = (1LL << 2), + + NM_SETTINGS_CONNECTION_FLAGS_VISIBLE = (1LL << 3), __NM_SETTINGS_CONNECTION_FLAGS_LAST, NM_SETTINGS_CONNECTION_FLAGS_ALL = ((__NM_SETTINGS_CONNECTION_FLAGS_LAST - 1) << 1) - 1, } NMSettingsConnectionFlags; -typedef enum { /*< skip >*/ +typedef enum { NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE = 0, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION = (1LL << 0), NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED = (1LL << 1), @@ -84,13 +88,18 @@ typedef enum { /*< skip >*/ typedef enum { NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE = 0, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = 1, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = 2, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = 3, + + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = (1LL << 0), + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = (1LL << 1), + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = (1LL << 2), + + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL = ( NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST + | NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED + | NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS), } NMSettingsAutoconnectBlockedReason; struct _NMSettingsConnectionCallId; -typedef struct _NMSettingsConnectionCallId *NMSettingsConnectionCallId; +typedef struct _NMSettingsConnectionCallId NMSettingsConnectionCallId; typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass; @@ -120,37 +129,39 @@ struct _NMSettingsConnectionClass { GType nm_settings_connection_get_type (void); +guint64 nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self); + gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self, NMConnection *applied_connection, NMSettingCompareFlags compare_flage); -gboolean nm_settings_connection_commit_changes (NMSettingsConnection *self, - NMConnection *new_connection, - NMSettingsConnectionCommitReason commit_reason, - GError **error); - -gboolean nm_settings_connection_replace_settings_prepare (NMSettingsConnection *self, - NMConnection *new_connection, - GError **error); - -gboolean nm_settings_connection_replace_settings (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error); - -gboolean nm_settings_connection_replace_settings_full (NMSettingsConnection *self, - NMConnection *new_connection, - gboolean prepare_new_connection, - gboolean update_unsaved, - const char *log_diff_name, - GError **error); +typedef enum { + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + + /* unsaved, only sets the unsaved flag, but it doesn't touch + * the NM_GENERATED nor VOLATILE flag. */ + NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED, + + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, + NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED, + NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_ONLY, +} NMSettingsConnectionPersistMode; + +gboolean nm_settings_connection_update (NMSettingsConnection *self, + NMConnection *new_connection, + NMSettingsConnectionPersistMode persist_mode, + NMSettingsConnectionCommitReason commit_reason, + const char *log_diff_name, + GError **error); gboolean nm_settings_connection_delete (NMSettingsConnection *self, GError **error); typedef void (*NMSettingsConnectionSecretsFunc) (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id, + NMSettingsConnectionCallId *call_id, const char *agent_username, const char *setting_name, GError *error, @@ -162,19 +173,17 @@ gboolean nm_settings_connection_new_secrets (NMSettingsConnection *self, GVariant *secrets, GError **error); -NMSettingsConnectionCallId nm_settings_connection_get_secrets (NMSettingsConnection *self, - NMConnection *applied_connection, - NMAuthSubject *subject, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags, - const char **hints, - NMSettingsConnectionSecretsFunc callback, - gpointer callback_data); +NMSettingsConnectionCallId *nm_settings_connection_get_secrets (NMSettingsConnection *self, + NMConnection *applied_connection, + NMAuthSubject *subject, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + const char *const*hints, + NMSettingsConnectionSecretsFunc callback, + gpointer callback_data); void nm_settings_connection_cancel_secrets (NMSettingsConnection *self, - NMSettingsConnectionCallId call_id); - -gboolean nm_settings_connection_is_visible (NMSettingsConnection *self); + NMSettingsConnectionCallId *call_id); void nm_settings_connection_recheck_visibility (NMSettingsConnection *self); @@ -187,7 +196,7 @@ gboolean nm_settings_connection_get_unsaved (NMSettingsConnection *self); NMSettingsConnectionFlags nm_settings_connection_get_flags (NMSettingsConnection *self); NMSettingsConnectionFlags nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionFlags flags, gboolean set); -NMSettingsConnectionFlags nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConnectionFlags flags); +NMSettingsConnectionFlags nm_settings_connection_set_flags_full (NMSettingsConnection *self, NMSettingsConnectionFlags mask, NMSettingsConnectionFlags value); int nm_settings_connection_cmp_timestamp (NMSettingsConnection *ac, NMSettingsConnection *ab); int nm_settings_connection_cmp_timestamp_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data); @@ -218,14 +227,23 @@ void nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self, int retries); void nm_settings_connection_autoconnect_retries_reset (NMSettingsConnection *self); -gint32 nm_settings_connection_autoconnect_blocked_until_get (NMSettingsConnection *self); +gint32 nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection *self); -NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self); -void nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason reason); +NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask); +gboolean nm_settings_connection_autoconnect_blocked_reason_set_full (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + NMSettingsAutoconnectBlockedReason value); + +static inline gboolean +nm_settings_connection_autoconnect_blocked_reason_set (NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason mask, + gboolean set) +{ + return nm_settings_connection_autoconnect_blocked_reason_set_full (self, mask, set ? mask : NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); +} -gboolean nm_settings_connection_get_nm_generated (NMSettingsConnection *self); -gboolean nm_settings_connection_get_volatile (NMSettingsConnection *self); +gboolean nm_settings_connection_autoconnect_is_blocked (NMSettingsConnection *self); gboolean nm_settings_connection_get_ready (NMSettingsConnection *self); void nm_settings_connection_set_ready (NMSettingsConnection *self, diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index e2b467a2..21fdf9e0 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -75,7 +75,6 @@ #include "nm-audit-manager.h" #include "NetworkManagerUtils.h" #include "nm-dispatcher.h" -#include "nm-inotify-helper.h" #include "nm-hostname-manager.h" #include "introspection/org.freedesktop.NetworkManager.Settings.h" @@ -84,13 +83,8 @@ #define EXPORT(sym) void * __export_##sym = &sym; -EXPORT(nm_inotify_helper_get_type) -EXPORT(nm_inotify_helper_get) -EXPORT(nm_inotify_helper_add_watch) -EXPORT(nm_inotify_helper_remove_watch) - EXPORT(nm_settings_connection_get_type) -EXPORT(nm_settings_connection_replace_settings) +EXPORT(nm_settings_connection_update) /*****************************************************************************/ @@ -127,8 +121,7 @@ enum { CONNECTION_ADDED, CONNECTION_UPDATED, CONNECTION_REMOVED, - CONNECTION_VISIBILITY_CHANGED, - AGENT_REGISTERED, + CONNECTION_FLAGS_CHANGED, NEW_CONNECTION, /* exported, not used internally */ LAST_SIGNAL }; @@ -431,6 +424,9 @@ nm_settings_get_connections (NMSettings *self, guint *out_len) * @out_len: (allow-none): optional output argument * @func: caller-supplied function for filtering connections * @func_data: caller-supplied data passed to @func + * @sort_compare_func: (allow-none): optional function pointer for + * sorting the returned list. + * @sort_data: user data for @sort_compare_func. * * Returns: (transfer container) (element-type NMSettingsConnection): * an NULL terminated array of #NMSettingsConnection objects that were @@ -443,7 +439,9 @@ NMSettingsConnection ** nm_settings_get_connections_clone (NMSettings *self, guint *out_len, NMSettingsConnectionFilterFunc func, - gpointer func_data) + gpointer func_data, + GCompareDataFunc sort_compare_func, + gpointer sort_data) { NMSettingsConnection *const*list_cached; NMSettingsConnection **list; @@ -471,31 +469,15 @@ nm_settings_get_connections_clone (NMSettings *self, } else memcpy (list, list_cached, sizeof (list[0]) * ((gsize) len + 1)); + if ( len > 1 + && sort_compare_func) { + g_qsort_with_data (list, len, sizeof (NMSettingsConnection *), + sort_compare_func, sort_data); + } NM_SET_OUT (out_len, len); return list; } -/* Returns a list of NMSettingsConnections. - * The list is sorted in the order suitable for auto-connecting, i.e. - * first go connections with autoconnect=yes and most recent timestamp. - * Caller must free the list with g_free(), but not the list items. - */ -NMSettingsConnection ** -nm_settings_get_connections_sorted (NMSettings *self, guint *out_len) -{ - NMSettingsConnection **connections; - guint len; - - g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - - connections = nm_settings_get_connections_clone (self, &len, NULL, NULL); - if (len > 1) - g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); - - NM_SET_OUT (out_len, len); - return connections; -} - NMSettingsConnection * nm_settings_get_connection_by_path (NMSettings *self, const char *path) { @@ -838,13 +820,12 @@ connection_updated (NMSettingsConnection *connection, gboolean by_user, gpointer } static void -connection_visibility_changed (NMSettingsConnection *connection, - GParamSpec *pspec, - gpointer user_data) +connection_flags_changed (NMSettingsConnection *connection, + GParamSpec *pspec, + gpointer user_data) { - /* Re-emit for listeners like NMPolicy */ g_signal_emit (NM_SETTINGS (user_data), - signals[CONNECTION_VISIBILITY_CHANGED], + signals[CONNECTION_FLAGS_CHANGED], 0, connection); } @@ -867,7 +848,7 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_removed), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated), self); - g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_visibility_changed), self); + g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_flags_changed), self); if (!priv->startup_complete) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self); g_object_unref (self); @@ -889,18 +870,6 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_object_unref (connection); } -static void -secret_agent_registered (NMAgentManager *agent_mgr, - NMSecretAgent *agent, - gpointer user_data) -{ - /* Re-emit for listeners like NMPolicy */ - g_signal_emit (NM_SETTINGS (user_data), - signals[AGENT_REGISTERED], - 0, - agent); -} - #define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" #define NM_OPENCONNECT_KEY_GATEWAY "gateway" #define NM_OPENCONNECT_KEY_COOKIE "cookie" @@ -1003,8 +972,8 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) G_CALLBACK (connection_removed), self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, G_CALLBACK (connection_updated), self); - g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_VISIBLE, - G_CALLBACK (connection_visibility_changed), + g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_FLAGS, + G_CALLBACK (connection_flags_changed), self); if (!priv->startup_complete) { g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_READY, @@ -1037,6 +1006,25 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) } } +static gboolean +secrets_filter_cb (NMSetting *setting, + const char *secret, + NMSettingSecretFlags flags, + gpointer user_data) +{ + NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data); + + /* Returns TRUE to remove the secret */ + + /* Can't use bitops with SECRET_FLAG_NONE so handle that specifically */ + if ( (flags == NM_SETTING_SECRET_FLAG_NONE) + && (filter_flags == NM_SETTING_SECRET_FLAG_NONE)) + return FALSE; + + /* Otherwise if the secret has at least one of the desired flags keep it */ + return (flags & filter_flags) ? FALSE : TRUE; +} + /** * nm_settings_add_connection: * @self: the #NMSettings object @@ -1087,9 +1075,22 @@ nm_settings_add_connection (NMSettings *self, for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); GError *add_error = NULL; + gs_unref_object NMConnection *simple = NULL; + gs_unref_variant GVariant *secrets = NULL; + + /* Make a copy of agent-owned secrets because they won't be present in + * the connection returned by plugins, as plugins return only what was + * reread from the file. */ + simple = nm_simple_connection_new_clone (connection); + nm_connection_clear_secrets_with_flags (simple, + secrets_filter_cb, + GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); + secrets = nm_connection_to_dbus (simple, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); added = nm_settings_plugin_add_connection (plugin, connection, save_to_disk, &add_error); if (added) { + if (secrets) + nm_connection_update_secrets (NM_CONNECTION (added), NULL, secrets, NULL); claim_connection (self, added); return added; } @@ -1105,25 +1106,6 @@ nm_settings_add_connection (NMSettings *self, return NULL; } -static gboolean -secrets_filter_cb (NMSetting *setting, - const char *secret, - NMSettingSecretFlags flags, - gpointer user_data) -{ - NMSettingSecretFlags filter_flags = GPOINTER_TO_UINT (user_data); - - /* Returns TRUE to remove the secret */ - - /* Can't use bitops with SECRET_FLAG_NONE so handle that specifically */ - if ( (flags == NM_SETTING_SECRET_FLAG_NONE) - && (filter_flags == NM_SETTING_SECRET_FLAG_NONE)) - return FALSE; - - /* Otherwise if the secret has at least one of the desired flags keep it */ - return (flags & filter_flags) ? FALSE : TRUE; -} - static void send_agent_owned_secrets (NMSettings *self, NMSettingsConnection *connection, @@ -1886,16 +1868,8 @@ nm_settings_init (NMSettings *self) priv->connections = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); - /* Hold a reference to the agent manager so it stays alive; the only - * other holders are NMSettingsConnection objects which are often - * transient, and we don't want the agent manager to get destroyed and - * recreated often. - */ priv->agent_mgr = g_object_ref (nm_agent_manager_get ()); - priv->config = g_object_ref (nm_config_get ()); - - g_signal_connect (priv->agent_mgr, "agent-registered", G_CALLBACK (secret_agent_registered), self); } NMSettings * @@ -2012,23 +1986,14 @@ nm_settings_class_init (NMSettingsClass *class) g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); - signals[CONNECTION_VISIBILITY_CHANGED] = - g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, + signals[CONNECTION_FLAGS_CHANGED] = + g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); - signals[AGENT_REGISTERED] = - g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT); - - signals[NEW_CONNECTION] = g_signal_new ("new-connection", G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index eede76b0..0ecffb70 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -46,8 +46,7 @@ #define NM_SETTINGS_SIGNAL_CONNECTION_ADDED "connection-added" #define NM_SETTINGS_SIGNAL_CONNECTION_UPDATED "connection-updated" #define NM_SETTINGS_SIGNAL_CONNECTION_REMOVED "connection-removed" -#define NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED "connection-visibility-changed" -#define NM_SETTINGS_SIGNAL_AGENT_REGISTERED "agent-registered" +#define NM_SETTINGS_SIGNAL_CONNECTION_FLAGS_CHANGED "connection-flags-changed" /** * NMConnectionFilterFunc: @@ -100,10 +99,9 @@ NMSettingsConnection *const* nm_settings_get_connections (NMSettings *settings, NMSettingsConnection **nm_settings_get_connections_clone (NMSettings *self, guint *out_len, NMSettingsConnectionFilterFunc func, - gpointer func_data); - -NMSettingsConnection **nm_settings_get_connections_sorted (NMSettings *self, - guint *out_len); + gpointer func_data, + GCompareDataFunc sort_compare_func, + gpointer sort_data); NMSettingsConnection *nm_settings_add_connection (NMSettings *settings, NMConnection *connection, diff --git a/src/settings/plugins/ibft/nms-ibft-connection.c b/src/settings/plugins/ibft/nms-ibft-connection.c index 834ba834..2a7c5f4a 100644 --- a/src/settings/plugins/ibft/nms-ibft-connection.c +++ b/src/settings/plugins/ibft/nms-ibft-connection.c @@ -60,11 +60,12 @@ nms_ibft_connection_new (const GPtrArray *block, GError **error) object = g_object_new (NMS_TYPE_IBFT_CONNECTION, NULL); /* Update settings with what was read from iscsiadm */ - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), - source, - FALSE, - NULL, - error)) + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + source, + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + error)) g_clear_object (&object); return (NMSIbftConnection *) object; diff --git a/src/settings/plugins/ibft/nms-ibft-plugin.c b/src/settings/plugins/ibft/nms-ibft-plugin.c index 9b1f5ccd..ea4d1524 100644 --- a/src/settings/plugins/ibft/nms-ibft-plugin.c +++ b/src/settings/plugins/ibft/nms-ibft-plugin.c @@ -202,5 +202,5 @@ settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) G_MODULE_EXPORT GObject * nm_settings_plugin_factory (void) { - return g_object_ref (nms_ibft_plugin_get ()); + return G_OBJECT (g_object_ref (nms_ibft_plugin_get ())); } diff --git a/src/settings/nm-inotify-helper.c b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c index 4c65b02d..4c65b02d 100644 --- a/src/settings/nm-inotify-helper.c +++ b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c diff --git a/src/settings/nm-inotify-helper.h b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.h index 2715f3ee..b887ae37 100644 --- a/src/settings/nm-inotify-helper.h +++ b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.h @@ -43,4 +43,17 @@ int nm_inotify_helper_add_watch (NMInotifyHelper *helper, const char *path); void nm_inotify_helper_remove_watch (NMInotifyHelper *helper, int wd); +static inline gboolean +nm_inotify_helper_clear_watch (NMInotifyHelper *helper, int *wd) +{ + int x; + + if (wd && ((x = *wd) >= 0)) { + *wd = -1; + nm_inotify_helper_remove_watch (helper, x); + return TRUE; + } + return FALSE; +} + #endif /* __NM_INOTIFY_HELPER_H__ */ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c index 4c1d02ae..3cf5c978 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c @@ -36,13 +36,13 @@ #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" #include "platform/nm-platform.h" -#include "settings/nm-inotify-helper.h" #include "nm-config.h" #include "nms-ifcfg-rh-common.h" #include "nms-ifcfg-rh-reader.h" #include "nms-ifcfg-rh-writer.h" #include "nms-ifcfg-rh-utils.h" +#include "nm-inotify-helper.h" /*****************************************************************************/ @@ -96,14 +96,6 @@ G_DEFINE_TYPE (NMIfcfgConnection, nm_ifcfg_connection, NM_TYPE_SETTINGS_CONNECTI /*****************************************************************************/ -static NMInotifyHelper * -_get_inotify_helper (NMIfcfgConnectionPrivate *priv) -{ - if (!priv->inotify_helper) - priv->inotify_helper = g_object_ref (nm_inotify_helper_get ()); - return priv->inotify_helper; -} - static gboolean devtimeout_ready (gpointer user_data) { @@ -225,37 +217,17 @@ static void path_watch_stop (NMIfcfgConnection *self) { NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); - NMInotifyHelper *ih; - - ih = _get_inotify_helper (priv); - - nm_clear_g_signal_handler (ih, &priv->ih_event_id); - - if (priv->file_wd >= 0) { - nm_inotify_helper_remove_watch (ih, priv->file_wd); - priv->file_wd = -1; - } - g_free (priv->keyfile); - priv->keyfile = NULL; - if (priv->keyfile_wd >= 0) { - nm_inotify_helper_remove_watch (ih, priv->keyfile_wd); - priv->keyfile_wd = -1; - } + nm_clear_g_signal_handler (priv->inotify_helper, &priv->ih_event_id); - g_free (priv->routefile); - priv->routefile = NULL; - if (priv->routefile_wd >= 0) { - nm_inotify_helper_remove_watch (ih, priv->routefile_wd); - priv->routefile_wd = -1; - } + nm_inotify_helper_clear_watch (priv->inotify_helper, &priv->file_wd); + nm_inotify_helper_clear_watch (priv->inotify_helper, &priv->keyfile_wd); + nm_inotify_helper_clear_watch (priv->inotify_helper, &priv->routefile_wd); + nm_inotify_helper_clear_watch (priv->inotify_helper, &priv->route6file_wd); - g_free (priv->route6file); - priv->route6file = NULL; - if (priv->route6file_wd >= 0) { - nm_inotify_helper_remove_watch (ih, priv->route6file_wd); - priv->route6file_wd = -1; - } + nm_clear_g_free (&priv->keyfile); + nm_clear_g_free (&priv->routefile); + nm_clear_g_free (&priv->route6file); } static void @@ -280,7 +252,9 @@ filename_changed (GObject *object, if (nm_config_get_monitor_connection_files (nm_config_get ())) { NMInotifyHelper *ih; - ih = _get_inotify_helper (priv); + if (!priv->inotify_helper) + priv->inotify_helper = g_object_ref (nm_inotify_helper_get ()); + ih = priv->inotify_helper; priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (files_changed_cb), self); priv->file_wd = nm_inotify_helper_add_watch (ih, ifcfg_path); @@ -324,7 +298,7 @@ commit_changes (NMSettingsConnection *connection, nm_assert (!out_logmsg_change || !*out_logmsg_change); filename = nm_settings_connection_get_filename (connection); - if (!nms_ifcfg_rh_writer_write_connection (new_connection ?: NM_CONNECTION (connection), + if (!nms_ifcfg_rh_writer_write_connection (new_connection, IFCFG_DIR, filename, &ifcfg_path, @@ -415,6 +389,13 @@ set_property (GObject *object, guint prop_id, static void nm_ifcfg_connection_init (NMIfcfgConnection *connection) { + NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (connection); + + priv->file_wd = -1; + priv->keyfile_wd = -1; + priv->routefile_wd = -1; + priv->route6file_wd = -1; + g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_FILENAME, G_CALLBACK (filename_changed), NULL); } @@ -429,18 +410,12 @@ nm_ifcfg_connection_new (NMConnection *source, NMConnection *tmp; char *unhandled_spec = NULL; const char *unmanaged_spec = NULL, *unrecognized_spec = NULL; - gboolean update_unsaved = TRUE; g_assert (source || full_path); if (out_ignore_error) *out_ignore_error = FALSE; - if (full_path) { - /* The connection already is on the disk */ - update_unsaved = FALSE; - } - /* If we're given a connection already, prefer that instead of re-reading */ if (source) tmp = g_object_ref (source); @@ -464,11 +439,14 @@ nm_ifcfg_connection_new (NMConnection *source, NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, unrecognized_spec, NULL); /* Update our settings with what was read from the file */ - if (nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), - tmp, - update_unsaved, - NULL, - error)) + if (nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + tmp, + full_path + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP /* connection is already on disk */ + : NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + error)) nm_ifcfg_connection_check_devtimeout (NM_IFCFG_CONNECTION (object)); else g_clear_object (&object); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index da0920ef..04e74bbd 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -313,11 +313,12 @@ update_connection (SettingsPluginIfcfg *self, NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC, new_unrecognized, NULL); - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid), - NM_CONNECTION (connection_new), - FALSE, /* don't set Unsaved */ - "ifcfg-update", - &local)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (connection_by_uuid), + NM_CONNECTION (connection_new), + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "ifcfg-update", + &local)) { /* Shouldn't ever get here as 'connection_new' was verified by the reader already * and the UUID did not change. */ g_assert_not_reached (); @@ -1079,5 +1080,5 @@ settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) G_MODULE_EXPORT GObject * nm_settings_plugin_factory (void) { - return g_object_ref (settings_plugin_ifcfg_get ()); + return G_OBJECT (g_object_ref (settings_plugin_ifcfg_get ())); } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 66add713..b9900eec 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2008 - 2015 Red Hat, Inc. + * Copyright 2008 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -77,18 +77,6 @@ /*****************************************************************************/ -static gboolean -get_uint (const char *str, guint32 *value) -{ - gint64 tmp; - - tmp = _nm_utils_ascii_str_to_int64 (str, 0, 0, G_MAXUINT32, -1); - if (tmp == -1) - return FALSE; - *value = tmp; - return TRUE; -} - static void check_if_bond_slave (shvarFile *ifcfg, NMSettingConnection *s_con) @@ -512,13 +500,13 @@ typedef struct { bool int_base_16:1; - /* the type, one of PARSE_LINE_TYPE_* */ - char type; - /* whether the command line option was found, and @v is * initialized. */ bool has:1; + /* the type, one of PARSE_LINE_TYPE_* */ + char type; + union { guint8 uint8; guint32 uint32; @@ -541,6 +529,7 @@ enum { PARSE_LINE_ATTR_ROUTE_SRC, PARSE_LINE_ATTR_ROUTE_FROM, PARSE_LINE_ATTR_ROUTE_TOS, + PARSE_LINE_ATTR_ROUTE_ONLINK, PARSE_LINE_ATTR_ROUTE_WINDOW, PARSE_LINE_ATTR_ROUTE_CWND, PARSE_LINE_ATTR_ROUTE_INITCWND, @@ -562,6 +551,7 @@ enum { #define PARSE_LINE_TYPE_ADDR 'a' #define PARSE_LINE_TYPE_ADDR_WITH_PREFIX 'p' #define PARSE_LINE_TYPE_IFNAME 'i' +#define PARSE_LINE_TYPE_FLAG 'f' /** * parse_route_line: @@ -601,42 +591,45 @@ parse_route_line (const char *line, char buf1[256]; char buf2[256]; ParseLineInfo infos[] = { - [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, - .type = PARSE_LINE_TYPE_UINT32, }, - [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, - .type = PARSE_LINE_TYPE_ADDR, }, - [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, - .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (addr_family != AF_INET6), }, - [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, - .type = PARSE_LINE_TYPE_UINT8, - .int_base_16 = TRUE, - .ignore = (addr_family != AF_INET), }, - [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - - [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", - .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", - .type = PARSE_LINE_TYPE_ADDR, - .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", - .type = PARSE_LINE_TYPE_UINT32, - .disabled = (options_route != NULL), }, - - [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", - .type = PARSE_LINE_TYPE_IFNAME, - .ignore = TRUE, - .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, + .type = PARSE_LINE_TYPE_UINT32, }, + [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, + .type = PARSE_LINE_TYPE_ADDR, }, + [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (addr_family != AF_INET6), }, + [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, + .type = PARSE_LINE_TYPE_UINT8, + .int_base_16 = TRUE, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_ONLINK] = { .key = NM_IP_ROUTE_ATTRIBUTE_ONLINK, + .type = PARSE_LINE_TYPE_FLAG, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + + [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", + .type = PARSE_LINE_TYPE_ADDR, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", + .type = PARSE_LINE_TYPE_UINT32, + .disabled = (options_route != NULL), }, + + [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", + .type = PARSE_LINE_TYPE_IFNAME, + .ignore = TRUE, + .disabled = (options_route != NULL), }, }; nm_assert (line); @@ -705,6 +698,9 @@ parse_route_line (const char *line, case PARSE_LINE_TYPE_IFNAME: i_words++; goto parse_line_type_ifname; + case PARSE_LINE_TYPE_FLAG: + i_words++; + goto next; default: nm_assert_not_reached (); } @@ -913,6 +909,15 @@ next: ? nm_sprintf_buf (buf2, "/%u", (unsigned) info->v.addr.plen) : "")); break; + case PARSE_LINE_TYPE_FLAG: + /* XXX: the flag (for "onlink") only allows to explictly set "TRUE". + * There is no way to express an explicit "FALSE" setting + * of this attribute, hence, the file format cannot encode + * that configuration. */ + nm_ip_route_set_attribute (route, + info->key, + g_variant_new_boolean (TRUE)); + break; default: nm_assert_not_reached (); break; @@ -1141,7 +1146,7 @@ error: } static NMSetting * -make_user_setting (shvarFile *ifcfg, GError **error) +make_user_setting (shvarFile *ifcfg) { gboolean has_user_data = FALSE; gs_unref_object NMSettingUser *s_user = NULL; @@ -1189,7 +1194,7 @@ make_user_setting (shvarFile *ifcfg, GError **error) } static NMSetting * -make_proxy_setting (shvarFile *ifcfg, GError **error) +make_proxy_setting (shvarFile *ifcfg) { NMSettingProxy *s_proxy = NULL; gs_free char *value = NULL; @@ -1239,7 +1244,7 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) static NMSetting * make_ip4_setting (shvarFile *ifcfg, - const char *network_file, + shvarFile *network_ifcfg, gboolean routes_read, gboolean *out_has_defroute, GError **error) @@ -1255,7 +1260,6 @@ make_ip4_setting (shvarFile *ifcfg, int i; guint32 a; gboolean has_key; - shvarFile *network_ifcfg; shvarFile *route_ifcfg; gboolean never_default; gint64 timeout; @@ -1282,7 +1286,6 @@ make_ip4_setting (shvarFile *ifcfg, } /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */ - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { gs_free char *gatewaydev_value = NULL; const char *gatewaydev; @@ -1299,7 +1302,6 @@ make_ip4_setting (shvarFile *ifcfg, never_default = !!strcmp (v, gatewaydev); nm_clear_g_free (&value); - svCloseFile (network_ifcfg); } v = svGetValueStr (ifcfg, "BOOTPROTO", &value); @@ -1424,12 +1426,10 @@ make_ip4_setting (shvarFile *ifcfg, /* Gateway */ if (!gateway) { - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { gboolean read_success; read_success = read_ip4_address (network_ifcfg, "GATEWAY", &has_key, &a, error); - svCloseFile (network_ifcfg); if (!read_success) return NULL; if (has_key) { @@ -1665,16 +1665,15 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file static NMSetting * make_ip6_setting (shvarFile *ifcfg, - const char *network_file, + shvarFile *network_ifcfg, gboolean routes_read, GError **error) { NMSettingIPConfig *s_ip6 = NULL; + const char *v; char *value = NULL; char *str_value; char *route6_path = NULL; - gs_free char *dns_options_free = NULL; - const char *dns_options = NULL; gboolean ipv6init, ipv6forwarding, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; char *ipv6addr, *ipv6addr_secondaries; @@ -1684,7 +1683,6 @@ make_ip6_setting (shvarFile *ifcfg, int i_val; GError *local = NULL; gint priority; - shvarFile *network_ifcfg; gboolean never_default = FALSE; gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip; NMSettingIP6ConfigPrivacy ip6_privacy_val; @@ -1703,7 +1701,6 @@ make_ip6_setting (shvarFile *ifcfg, * they are global and override IPV6_DEFROUTE * When both are set, the device specified in IPV6_DEFAULTGW takes preference. */ - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { char *ipv6_defaultgw, *ipv6_defaultdev; char *default_dev = NULL; @@ -1712,7 +1709,6 @@ make_ip6_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "DEVICE"); ipv6_defaultgw = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); ipv6_defaultdev = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTDEV"); - dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free); if (ipv6_defaultgw) { default_dev = strchr (ipv6_defaultgw, '%'); @@ -1731,7 +1727,6 @@ make_ip6_setting (shvarFile *ifcfg, g_free (ipv6_defaultgw); g_free (ipv6_defaultdev); g_free (value); - svCloseFile (network_ifcfg); } /* Find out method property */ @@ -1739,11 +1734,8 @@ make_ip6_setting (shvarFile *ifcfg, str_value = svGetValueStr_cp (ifcfg, "IPV6INIT"); ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE); if (!str_value) { - network_ifcfg = svOpenFile (network_file, NULL); - if (network_ifcfg) { + if (network_ifcfg) ipv6init = svGetValueBoolean (network_ifcfg, "IPV6INIT", FALSE); - svCloseFile (network_ifcfg); - } } g_free (str_value); @@ -1865,11 +1857,8 @@ make_ip6_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "IPV6_DEFAULTGW"); if (!value) { /* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */ - network_ifcfg = svOpenFile (network_file, NULL); - if (network_ifcfg) { + if (network_ifcfg) value = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); - svCloseFile (network_ifcfg); - } } if (value) { char *ptr; @@ -1930,8 +1919,6 @@ make_ip6_setting (shvarFile *ifcfg, g_free (value); } - /* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */ - if (!routes_read) { /* NOP */ } else { @@ -1942,9 +1929,24 @@ make_ip6_setting (shvarFile *ifcfg, g_free (route6_path); } + /* DNS searches */ + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6_DOMAIN", &value); + if (v) { + gs_free const char **searches = NULL; + + searches = nm_utils_strsplit_set (v, " "); + if (searches) { + for (iter = searches; *iter; iter++) { + if (!nm_setting_ip_config_add_dns_search (s_ip6, *iter)) + PARSE_WARNING ("duplicate DNS domain '%s'", *iter); + } + } + } + /* DNS options */ - parse_dns_options (s_ip6, svGetValue (ifcfg, "RES_OPTIONS", &value)); - parse_dns_options (s_ip6, dns_options); + nm_clear_g_free (&value); + parse_dns_options (s_ip6, svGetValue (ifcfg, "IPV6_RES_OPTIONS", &value)); g_free (value); /* DNS priority */ @@ -1962,6 +1964,59 @@ error: return NULL; } +static NMSetting * +make_tc_setting (shvarFile *ifcfg) +{ + NMSettingTCConfig *s_tc = NULL; + char tag[256]; + int i; + + s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new (); + + for (i = 1;; i++) { + NMTCQdisc *qdisc = NULL; + gs_free char *value_to_free = NULL; + const char *value = NULL; + GError *local = NULL; + + value = svGetValueStr (ifcfg, numbered_tag (tag, "QDISC", i), &value_to_free); + if (!value) + break; + + qdisc = nm_utils_tc_qdisc_from_str (value, &local); + if (!qdisc) + PARSE_WARNING ("ignoring bad qdisc: '%s': %s", value, local->message); + + if (!nm_setting_tc_config_add_qdisc (s_tc, qdisc)) + PARSE_WARNING ("duplicate qdisc"); + } + + for (i = 1;; i++) { + NMTCTfilter *tfilter = NULL; + gs_free char *value_to_free = NULL; + const char *value = NULL; + GError *local = NULL; + + value = svGetValueStr (ifcfg, numbered_tag (tag, "FILTER", i), &value_to_free); + if (!value) + break; + + tfilter = nm_utils_tc_tfilter_from_str (value, &local); + if (!tfilter) + PARSE_WARNING ("ignoring bad tfilter: '%s': %s", value, local->message); + + if (!nm_setting_tc_config_add_tfilter (s_tc, tfilter)) + PARSE_WARNING ("duplicate filter"); + } + + if ( nm_setting_tc_config_get_num_qdiscs (s_tc) > 0 + || nm_setting_tc_config_get_num_tfilters (s_tc) > 0) + return NM_SETTING (s_tc); + + g_object_unref (s_tc); + return NULL; +} + typedef struct { const char *enable_key; const char *advertise_key; @@ -2195,7 +2250,6 @@ read_dcb_percent_array (shvarFile *ifcfg, static gboolean make_dcb_setting (shvarFile *ifcfg, - const char *network_file, NMSetting **out_setting, GError **error) { @@ -2350,54 +2404,39 @@ add_one_wep_key (shvarFile *ifcfg, NMSettingWirelessSecurity *s_wsec, GError **error) { - char *key = NULL; - char *value = NULL; - gboolean success = FALSE; + gs_free char *value_free = NULL; + const char *value; + const char *key = NULL; g_return_val_if_fail (ifcfg != NULL, FALSE); g_return_val_if_fail (shvar_key != NULL, FALSE); g_return_val_if_fail (key_idx <= 3, FALSE); g_return_val_if_fail (s_wsec != NULL, FALSE); - value = svGetValueStr_cp (ifcfg, shvar_key); + value = svGetValueStr (ifcfg, shvar_key, &value_free); if (!value) return TRUE; /* Validate keys */ if (passphrase) { - if (strlen (value) && strlen (value) < 64) { - key = g_strdup (value); - g_object_set (G_OBJECT (s_wsec), - NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, - NM_WEP_KEY_TYPE_PASSPHRASE, - NULL); - } + if (value[0] && strlen (value) < 64) + key = value; } else { - if (strlen (value) == 10 || strlen (value) == 26) { + if (NM_IN_SET (strlen (value), 10, 26)) { /* Hexadecimal WEP key */ - char *p = value; - - while (*p) { - if (!g_ascii_isxdigit (*p)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid hexadecimal WEP key."); - goto out; - } - p++; + if (NM_STRCHAR_ANY (value, ch, !g_ascii_isxdigit (ch))) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid hexadecimal WEP key."); + return FALSE; } - key = g_strdup (value); + key = value; } else if ( !strncmp (value, "s:", 2) - && (strlen (value) == 7 || strlen (value) == 15)) { + && NM_IN_SET (strlen (value), 7, 15)) { /* ASCII key */ - char *p = value + 2; - - while (*p) { - if (!g_ascii_isprint ((int) (*p))) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid ASCII WEP key."); - goto out; - } - p++; + if (NM_STRCHAR_ANY (value + 2, ch, !g_ascii_isprint (ch))) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid ASCII WEP key."); + return FALSE; } /* Remove 's:' prefix. @@ -2406,51 +2445,50 @@ add_one_wep_key (shvarFile *ifcfg, * before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly, * ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users. */ - key = g_strdup (value + 2); + key = value + 2; } } - if (key) { - nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); - g_free (key); - success = TRUE; - } else { + if (!key) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid WEP key length."); + return FALSE; } -out: - g_free (value); - return success; + nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); + return TRUE; } static gboolean read_wep_keys (shvarFile *ifcfg, + NMWepKeyType key_type, guint8 def_idx, NMSettingWirelessSecurity *s_wsec, GError **error) { - /* Try hex/ascii keys first */ - if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error)) - return FALSE; + if (key_type != NM_WEP_KEY_TYPE_PASSPHRASE) { + if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error)) + return FALSE; + } - /* And then passphrases */ - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error)) - return FALSE; + if (key_type != NM_WEP_KEY_TYPE_KEY) { + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error)) + return FALSE; + } return TRUE; } @@ -2515,19 +2553,40 @@ make_wep_setting (shvarFile *ifcfg, /* Read keys in the ifcfg file if they are system-owned */ if (key_flags == NM_SETTING_SECRET_FLAG_NONE) { - if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error)) + NMWepKeyType key_type; + const char *v; + gs_free char *to_free = NULL; + + v = svGetValueStr (ifcfg, "KEY_TYPE", &to_free); + if (!v) + key_type = NM_WEP_KEY_TYPE_UNKNOWN; + else if (nm_streq (v, "key")) + key_type = NM_WEP_KEY_TYPE_KEY; + else if (nm_streq (v, "passphrase")) + key_type = NM_WEP_KEY_TYPE_PASSPHRASE; + else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid KEY_TYPE value '%s'", v); + return FALSE; + } + + if (!read_wep_keys (ifcfg, key_type, default_key_idx, s_wsec, error)) return NULL; /* Try to get keys from the "shadow" key file */ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); if (keys_ifcfg) { - if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) { + if (!read_wep_keys (keys_ifcfg, key_type, default_key_idx, s_wsec, error)) { svCloseFile (keys_ifcfg); return NULL; } svCloseFile (keys_ifcfg); g_assert (error == NULL || *error == NULL); } + + g_object_set (G_OBJECT (s_wsec), + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, key_type, + NULL); } value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); @@ -3577,25 +3636,25 @@ make_wireless_security_setting (shvarFile *ifcfg, return NULL; /* unencrypted */ } -static char ** +static const char ** transform_hwaddr_blacklist (const char *blacklist) { - char **strv, **iter; - int shift = 0; - - strv = _nm_utils_strsplit_set (blacklist, " \t", 0); - for (iter = strv; iter && *iter; iter++) { - if (shift) { - *(iter - shift) = *iter; - *iter = NULL; - } - if (!nm_utils_hwaddr_valid (*(iter - shift), ETH_ALEN)) { - PARSE_WARNING ("invalid MAC in HWADDR_BLACKLIST '%s'", *(iter - shift)); - g_free (*(iter - shift)); - *(iter - shift) = NULL; - shift++; + const char **strv; + gsize i, j; + + strv = nm_utils_strsplit_set (blacklist, " \t"); + if (!strv) + return NULL; + for (i = 0, j = 0; strv[j]; j++) { + const char *s = strv[j]; + + if (!nm_utils_hwaddr_valid (s, ETH_ALEN)) { + PARSE_WARNING ("invalid MAC in HWADDR_BLACKLIST '%s'", s); + continue; } + strv[i++] = s; } + strv[i] = NULL; return strv; } @@ -3630,13 +3689,12 @@ make_wireless_setting (shvarFile *ifcfg, g_object_set (s_wireless, NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK, value, NULL); g_free (value); - value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST"); - if (value) { - char **strv; + cvalue = svGetValueStr (ifcfg, "HWADDR_BLACKLIST", &value); + if (cvalue) { + gs_free const char **strv = NULL; - strv = transform_hwaddr_blacklist (value); + strv = transform_hwaddr_blacklist (cvalue); g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, strv, NULL); - g_strfreev (strv); g_free (value); } @@ -4096,6 +4154,7 @@ make_wired_setting (shvarFile *ifcfg, GError **error) { gs_unref_object NMSettingWired *s_wired = NULL; + const char *cvalue; gs_free char *value = NULL; char *nettype; @@ -4204,11 +4263,11 @@ make_wired_setting (shvarFile *ifcfg, NULL); nm_clear_g_free (&value); - value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST"); - if (value) { - gs_strfreev char **strv = NULL; + cvalue = svGetValueStr (ifcfg, "HWADDR_BLACKLIST", &value); + if (cvalue) { + gs_free const char **strv = NULL; - strv = transform_hwaddr_blacklist (value); + strv = transform_hwaddr_blacklist (cvalue); g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, strv, NULL); nm_clear_g_free (&value); } @@ -4633,66 +4692,114 @@ team_connection_from_ifcfg (const char *file, return connection; } +typedef enum { + BRIDGE_OPT_TYPE_MAIN, + BRIDGE_OPT_TYPE_OPTION, + BRIDGE_OPT_TYPE_PORT_MAIN, + BRIDGE_OPT_TYPE_PORT_OPTION, +} BridgeOptType; + typedef void (*BridgeOptFunc) (NMSetting *setting, gboolean stp, const char *key, - const char *value); + const char *value, + BridgeOptType opt_type); static void handle_bridge_option (NMSetting *setting, gboolean stp, const char *key, - const char *value) + const char *value, + BridgeOptType opt_type) { - guint32 u = 0; + static const struct { + const char *key; + const char *property_name; + BridgeOptType opt_type; + gboolean only_with_stp; + gboolean extended_bool; + } m/*etadata*/[] = { + { "DELAY", NM_SETTING_BRIDGE_FORWARD_DELAY, BRIDGE_OPT_TYPE_MAIN, .only_with_stp = TRUE }, + { "priority", NM_SETTING_BRIDGE_PRIORITY, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "hello_time", NM_SETTING_BRIDGE_HELLO_TIME, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "max_age", NM_SETTING_BRIDGE_MAX_AGE, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "ageing_time", NM_SETTING_BRIDGE_AGEING_TIME, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_snooping", NM_SETTING_BRIDGE_MULTICAST_SNOOPING, BRIDGE_OPT_TYPE_OPTION }, + { "group_fwd_mask", NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, BRIDGE_OPT_TYPE_OPTION }, + { "priority", NM_SETTING_BRIDGE_PORT_PRIORITY, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "path_cost", NM_SETTING_BRIDGE_PORT_PATH_COST, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "hairpin_mode", NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, BRIDGE_OPT_TYPE_PORT_OPTION, .extended_bool = TRUE, }, + }; + const char *error_message = NULL; + int i; + gint64 v; - if (!strcmp (key, "priority")) { - if (stp == FALSE) - PARSE_WARNING ("'priority' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL); - else - PARSE_WARNING ("invalid priority value '%s'", value); - } else if (!strcmp (key, "hello_time")) { - if (stp == FALSE) - PARSE_WARNING ("'hello_time' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL); - else - PARSE_WARNING ("invalid hello_time value '%s'", value); - } else if (!strcmp (key, "max_age")) { - if (stp == FALSE) - PARSE_WARNING ("'max_age' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL); - else - PARSE_WARNING ("invalid max_age value '%s'", value); - } else if (!strcmp (key, "ageing_time")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_AGEING_TIME, u, NULL); - else - PARSE_WARNING ("invalid ageing_time value '%s'", value); - } else if (!strcmp (key, "multicast_snooping")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_MULTICAST_SNOOPING, - (gboolean) u, NULL); - else - PARSE_WARNING ("invalid multicast_snooping value '%s'", value); - } else if (!strcmp (key, "group_fwd_mask")) { - if (get_uint (value, &u) && u <= 0xFFFF && !NM_FLAGS_ANY (u, 7)) - g_object_set (setting, NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, - (gboolean) u, NULL); - else - PARSE_WARNING ("invalid group_fwd_mask value '%s'", value); - } else - PARSE_WARNING ("unhandled bridge option '%s'", key); + for (i = 0; i < G_N_ELEMENTS (m); i++) { + GParamSpec *param_spec; + + if (opt_type != m[i].opt_type) + continue; + if (!nm_streq (key, m[i].key)) + continue; + if (m[i].only_with_stp && !stp) { + PARSE_WARNING ("'%s' invalid when STP is disabled", key); + return; + } + + param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), m[i].property_name); + switch (param_spec->value_type) { + case G_TYPE_BOOLEAN: + if (m[i].extended_bool) { + if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1")) + v = TRUE; + else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) + v = FALSE; + else { + error_message = "is not a boolean"; + goto warn; + } + } else { + v = _nm_utils_ascii_str_to_int64 (value, 10, 0, 1, -1); + if (v == -1) { + error_message = g_strerror (errno); + goto warn; + } + } + if (!nm_g_object_set_property_boolean (G_OBJECT (setting), m[i].property_name, v, NULL)) { + error_message = "number is out of range"; + goto warn; + } + return; + case G_TYPE_UINT: + v = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT, -1); + if (v == -1) { + error_message = g_strerror (errno); + goto warn; + } + if (!nm_g_object_set_property_uint (G_OBJECT (setting), m[i].property_name, v, NULL)) { + error_message = "number is out of range"; + goto warn; + } + return; + default: + nm_assert_not_reached (); + continue; + } + +warn: + PARSE_WARNING ("invalid %s value '%s': %s", key, value, error_message); + return; + } + + PARSE_WARNING ("unhandled bridge option '%s'", key); } static void handle_bridging_opts (NMSetting *setting, gboolean stp, const char *value, - BridgeOptFunc func) + BridgeOptFunc func, + BridgeOptType opt_type) { gs_free const char **items = NULL; const char *const *iter; @@ -4707,7 +4814,7 @@ handle_bridging_opts (NMSetting *setting, key = *keys; val = *(keys + 1); if (val && key[0] && val[0]) - func (setting, stp, key, val); + func (setting, stp, key, val, opt_type); } } } @@ -4717,30 +4824,29 @@ make_bridge_setting (shvarFile *ifcfg, const char *file, GError **error) { - NMSettingBridge *s_bridge; - char *value; - guint32 u; + gs_unref_object NMSettingBridge *s_bridge = NULL; + gs_free char *value_to_free = NULL; + const char *value; gboolean stp = FALSE; gboolean stp_set = FALSE; - value = svGetValueStr_cp (ifcfg, "DEVICE"); + value = svGetValueStr (ifcfg, "DEVICE", &value_to_free); if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "mandatory DEVICE keyword missing"); return NULL; } - g_free (value); + nm_clear_g_free (&value_to_free); s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ()); - value = svGetValueStr_cp (ifcfg, "MACADDR"); + value = svGetValueStr (ifcfg, "BRIDGE_MACADDR", &value_to_free); if (value) { - value = g_strstrip (value); g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, value, NULL); - g_free (value); + nm_clear_g_free (&value_to_free); } - value = svGetValueStr_cp (ifcfg, "STP"); + value = svGetValueStr (ifcfg, "STP", &value_to_free); if (value) { if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) { g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL); @@ -4751,7 +4857,7 @@ make_bridge_setting (shvarFile *ifcfg, stp_set = TRUE; } else PARSE_WARNING ("invalid STP value '%s'", value); - g_free (value); + nm_clear_g_free (&value_to_free); } if (!stp_set) { @@ -4759,25 +4865,19 @@ make_bridge_setting (shvarFile *ifcfg, g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL); } - value = svGetValueStr_cp (ifcfg, "DELAY"); + value = svGetValueStr (ifcfg, "DELAY", &value_to_free); if (value) { - if (stp) { - if (get_uint (value, &u)) - g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, u, NULL); - else - PARSE_WARNING ("invalid forward delay value '%s'", value); - } else - PARSE_WARNING ("DELAY invalid when STP is disabled"); - g_free (value); + handle_bridge_option (NM_SETTING (s_bridge), stp, "DELAY", value, BRIDGE_OPT_TYPE_MAIN); + nm_clear_g_free (&value_to_free); } - value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS"); + value = svGetValueStr (ifcfg, "BRIDGING_OPTS", &value_to_free); if (value) { - handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option); - g_free (value); + handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option, BRIDGE_OPT_TYPE_OPTION); + nm_clear_g_free (&value_to_free); } - return (NMSetting *) s_bridge; + return (NMSetting *) g_steal_pointer (&s_bridge); } static NMConnection * @@ -4788,6 +4888,8 @@ bridge_connection_from_ifcfg (const char *file, NMConnection *connection = NULL; NMSetting *con_setting = NULL; NMSetting *bridge_setting = NULL; + NMSetting *wired_setting = NULL; + NMSetting8021x *s_8021x = NULL; g_return_val_if_fail (file != NULL, NULL); g_return_val_if_fail (ifcfg != NULL, NULL); @@ -4810,57 +4912,40 @@ bridge_connection_from_ifcfg (const char *file, } nm_connection_add_setting (connection, bridge_setting); - return connection; -} + wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error); + if (!wired_setting) { + g_object_unref (connection); + return NULL; + } + nm_connection_add_setting (connection, wired_setting); -static void -handle_bridge_port_option (NMSetting *setting, - gboolean stp, - const char *key, - const char *value) -{ - guint32 u = 0; + if (s_8021x) + nm_connection_add_setting (connection, NM_SETTING (s_8021x)); - if (!strcmp (key, "priority")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_PRIORITY, u, NULL); - else - PARSE_WARNING ("invalid priority value '%s'", value); - } else if (!strcmp (key, "path_cost")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_PATH_COST, u, NULL); - else - PARSE_WARNING ("invalid path_cost value '%s'", value); - } else if (!strcmp (key, "hairpin_mode")) { - if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1")) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, TRUE, NULL); - else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, FALSE, NULL); - else - PARSE_WARNING ("invalid hairpin_mode value '%s'", value); - } else - PARSE_WARNING ("unhandled bridge port option '%s'", key); + return connection; } static NMSetting * make_bridge_port_setting (shvarFile *ifcfg) { NMSetting *s_port = NULL; - char *value; + gs_free char *value_to_free = NULL; + const char *value; g_return_val_if_fail (ifcfg != NULL, FALSE); - value = svGetValueStr_cp (ifcfg, "BRIDGE_UUID"); + value = svGetValueStr (ifcfg, "BRIDGE_UUID", &value_to_free); if (!value) - value = svGetValueStr_cp (ifcfg, "BRIDGE"); + value = svGetValueStr (ifcfg, "BRIDGE", &value_to_free); if (value) { - g_free (value); + nm_clear_g_free (&value_to_free); s_port = nm_setting_bridge_port_new (); - value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS"); - if (value) - handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option); - g_free (value); + value = svGetValueStr (ifcfg, "BRIDGING_OPTS", &value_to_free); + if (value) { + handle_bridging_opts (s_port, FALSE, value, handle_bridge_option, BRIDGE_OPT_TYPE_PORT_OPTION); + nm_clear_g_free (&value_to_free); + } } return s_port; @@ -5206,10 +5291,11 @@ connection_from_file_full (const char *filename, gboolean *out_ignore_error) { nm_auto_shvar_file_close shvarFile *parsed = NULL; + nm_auto_shvar_file_close shvarFile *network_ifcfg = NULL; gs_unref_object NMConnection *connection = NULL; gs_free char *type = NULL; char *devtype, *bootproto; - NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL, *s_user; + NMSetting *s_ip4, *s_ip6, *s_tc, *s_proxy, *s_port, *s_dcb = NULL, *s_user; const char *ifcfg_name = NULL; gboolean has_ip4_defroute = FALSE; gboolean has_complex_routes_v4; @@ -5233,6 +5319,8 @@ connection_from_file_full (const char *filename, if (!parsed) return NULL; + network_ifcfg = svOpenFile (network_file, NULL); + if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) { connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled); if (!connection) { @@ -5442,7 +5530,7 @@ connection_from_file_full (const char *filename, } s_ip6 = make_ip6_setting (parsed, - network_file, + network_ifcfg, !has_complex_routes_v4 && !has_complex_routes_v6, error); if (!s_ip6) @@ -5451,7 +5539,7 @@ connection_from_file_full (const char *filename, nm_connection_add_setting (connection, s_ip6); s_ip4 = make_ip4_setting (parsed, - network_file, + network_ifcfg, !has_complex_routes_v4 && !has_complex_routes_v6, &has_ip4_defroute, error); @@ -5464,17 +5552,21 @@ connection_from_file_full (const char *filename, nm_connection_add_setting (connection, s_ip4); } - /* There is only one DOMAIN variable and it is read and put to IPv4 config - * But if IPv4 is disabled or the config fails for some reason, we read - * DOMAIN and put the values into IPv6 config instead. + s_tc = make_tc_setting (parsed); + if (s_tc) + nm_connection_add_setting (connection, s_tc); + + /* For backwards compatibility, if IPv4 is disabled or the + * config fails for some reason, we read DOMAIN and put the + * values into IPv6 config instead of IPv4. */ check_dns_search_domains (parsed, s_ip4, s_ip6); - s_proxy = make_proxy_setting (parsed, error); + s_proxy = make_proxy_setting (parsed); if (s_proxy) nm_connection_add_setting (connection, s_proxy); - s_user = make_user_setting (parsed, error); + s_user = make_user_setting (parsed); if (s_user) nm_connection_add_setting (connection, s_user); @@ -5488,7 +5580,7 @@ connection_from_file_full (const char *filename, if (s_port) nm_connection_add_setting (connection, s_port); - if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) + if (!make_dcb_setting (parsed, &s_dcb, error)) return NULL; if (s_dcb) nm_connection_add_setting (connection, s_dcb); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 6434ad7d..862e640e 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2008 - 2012 Red Hat, Inc. + * (C) Copyright 2008 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -243,12 +243,6 @@ utils_get_route_ifcfg (const char *parent, gboolean should_create) return utils_get_extra_ifcfg (parent, ROUTE_TAG, should_create); } -shvarFile * -utils_get_route6_ifcfg (const char *parent, gboolean should_create) -{ - return utils_get_extra_ifcfg (parent, ROUTE6_TAG, should_create); -} - /* Finds out if route file has new or older format * Returns TRUE - new syntax (ADDRESS<n>=a.b.c.d ...), error opening file or empty * FALSE - older syntax, i.e. argument to 'ip route add' (1.2.3.0/24 via 11.22.33.44) diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index e7abf4d8..3756af7c 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2008 - 2012 Red Hat, Inc. + * (C) Copyright 2008 - 2017 Red Hat, Inc. */ #ifndef _UTILS_H_ @@ -45,7 +45,6 @@ char *utils_get_route6_path (const char *parent); shvarFile *utils_get_extra_ifcfg (const char *parent, const char *tag, gboolean should_create); shvarFile *utils_get_keys_ifcfg (const char *parent, gboolean should_create); shvarFile *utils_get_route_ifcfg (const char *parent, gboolean should_create); -shvarFile *utils_get_route6_ifcfg (const char *parent, gboolean should_create); gboolean utils_has_route_file_new_syntax (const char *filename); gboolean utils_has_complex_routes (const char *filename, int addr_family); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 5c8de7d1..5cb8ee98 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -150,7 +150,7 @@ write_secrets (shvarFile *ifcfg, /* sort the keys. */ secrets_keys = (const char **) g_hash_table_get_keys_as_array (secrets, &secrets_keys_n); - if (secrets_keys) { + if (secrets_keys_n > 1) { g_qsort_with_data (secrets_keys, secrets_keys_n, sizeof (const char *), @@ -662,12 +662,26 @@ write_wireless_security_setting (NMConnection *connection, /* And write the new ones out */ if (wep) { + NMWepKeyType key_type; + const char *key_type_str = NULL; + /* Default WEP TX key index */ svSetValueInt64 (ifcfg, "DEFAULTKEY", nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec) + 1); - for (i = 0; i < 4; i++) { - NMWepKeyType key_type; + key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec); + switch (key_type) { + case NM_WEP_KEY_TYPE_KEY: + key_type_str = "key"; + break; + case NM_WEP_KEY_TYPE_PASSPHRASE: + key_type_str = "passphrase"; + break; + case NM_WEP_KEY_TYPE_UNKNOWN: + break; + } + svSetValue (ifcfg, "KEY_TYPE", key_type_str); + for (i = 0; i < 4; i++) { key = nm_setting_wireless_security_get_wep_key (s_wsec, i); if (key) { gs_free char *ascii_key = NULL; @@ -678,7 +692,6 @@ write_wireless_security_setting (NMConnection *connection, * are some passphrases that are indistinguishable from WEP hex * keys. */ - key_type = nm_setting_wireless_security_get_wep_key_type (s_wsec); if (key_type == NM_WEP_KEY_TYPE_UNKNOWN) { if (nm_utils_wep_key_valid (key, NM_WEP_KEY_TYPE_KEY)) key_type = NM_WEP_KEY_TYPE_KEY; @@ -1309,25 +1322,19 @@ write_bond_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, svUnsetValue (ifcfg, "BONDING_OPTS"); num_opts = nm_setting_bond_get_num_options (s_bond); - if (num_opts > 0) { - GString *str = g_string_sized_new (64); - - for (i = 0; i < nm_setting_bond_get_num_options (s_bond); i++) { - const char *key, *value; - - if (!nm_setting_bond_get_option (s_bond, i, &key, &value)) - continue; + if (num_opts) { + nm_auto_free_gstring GString *str = NULL; + const char *name, *value; + str = g_string_sized_new (64); + for (i = 0; i < num_opts; i++) { if (str->len) g_string_append_c (str, ' '); - - g_string_append_printf (str, "%s=%s", key, value); + nm_setting_bond_get_option (s_bond, i, &name, &value); + g_string_append_printf (str, "%s=%s", name, value); } - if (str->len) - svSetValueStr (ifcfg, "BONDING_OPTS", str->str); - - g_string_free (str, TRUE); + svSetValueStr (ifcfg, "BONDING_OPTS", str->str); } svSetValueStr (ifcfg, "TYPE", TYPE_BOND); @@ -1414,7 +1421,7 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire svUnsetValue (ifcfg, "DELAY"); mac = nm_setting_bridge_get_mac_address (s_bridge); - svSetValueStr (ifcfg, "MACADDR", mac); + svSetValueStr (ifcfg, "BRIDGE_MACADDR", mac); /* Bridge options */ opts = g_string_sized_new (32); @@ -1928,8 +1935,11 @@ get_route_attributes_string (NMIPRoute *route, int family) g_string_append_printf (str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte (attr)); } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_TABLE)) { g_string_append_printf (str, "%s %u", names[i], (unsigned) g_variant_get_uint32 (attr)); - } else if ( nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) - || nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_FROM)) { + } else if (nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_ONLINK)) { + if (g_variant_get_boolean (attr)) + g_string_append (str, "onlink"); + } else if (NM_IN_STRSET (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC, + NM_IP_ROUTE_ATTRIBUTE_FROM)) { char *arg = nm_streq (names[i], NM_IP_ROUTE_ATTRIBUTE_SRC) ? "src" : "from"; g_string_append_printf (str, "%s %s", arg, g_variant_get_string (attr, NULL)); @@ -2116,6 +2126,73 @@ write_user_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) } static gboolean +write_tc_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingTCConfig *s_tc; + guint i, num, n; + char tag[64]; + + svUnsetAll (ifcfg, SV_KEY_TYPE_TC); + + s_tc = nm_connection_get_setting_tc_config (connection); + if (!s_tc) + return TRUE; + + num = nm_setting_tc_config_get_num_qdiscs (s_tc); + for (n = 1, i = 0; i < num; i++) { + NMTCQdisc *qdisc; + gs_free char *str = NULL; + + qdisc = nm_setting_tc_config_get_qdisc (s_tc, i); + str = nm_utils_tc_qdisc_to_str (qdisc, error); + if (!str) + return FALSE; + + svSetValueStr (ifcfg, numbered_tag (tag, "QDISC", n), str); + n++; + } + + + num = nm_setting_tc_config_get_num_tfilters (s_tc); + for (n = 1, i = 0; i < num; i++) { + NMTCTfilter *tfilter; + gs_free char *str = NULL; + + tfilter = nm_setting_tc_config_get_tfilter (s_tc, i); + str = nm_utils_tc_tfilter_to_str (tfilter, error); + if (!str) + return FALSE; + + svSetValueStr (ifcfg, numbered_tag (tag, "FILTER", n), str); + n++; + } + + return TRUE; +} + +static void +write_res_options (shvarFile *ifcfg, NMSettingIPConfig *s_ip, const char *var) +{ + nm_auto_free_gstring GString *value = NULL; + guint i, num_options; + + if (!nm_setting_ip_config_has_dns_options (s_ip)) { + svUnsetValue (ifcfg, var); + return; + } + + value = g_string_new (NULL); + num_options = nm_setting_ip_config_get_num_dns_options (s_ip); + for (i = 0; i < num_options; i++) { + if (i > 0) + g_string_append_c (value, ' '); + g_string_append (value, nm_setting_ip_config_get_dns_option (s_ip, i)); + } + + svSetValue (ifcfg, var, value->str); +} + +static gboolean write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, shvarFile **out_route_content_svformat, @@ -2146,6 +2223,7 @@ write_ip4_setting (NMConnection *connection, * Some IPv4 setting related options are not cleared, * for no strong reason. */ svUnsetValue (ifcfg, "BOOTPROTO"); + svUnsetValue (ifcfg, "RES_OPTIONS"); svUnsetAll (ifcfg, SV_KEY_TYPE_IP4_ADDRESS); return TRUE; } @@ -2342,6 +2420,8 @@ write_ip4_setting (NMConnection *connection, else svUnsetValue (ifcfg, "IPV4_DNS_PRIORITY"); + write_res_options (ifcfg, s_ip4, "RES_OPTIONS"); + return TRUE; } @@ -2483,6 +2563,7 @@ write_ip6_setting (NMConnection *connection, svUnsetValue (ifcfg, "IPV6_FAILURE_FATAL"); svUnsetValue (ifcfg, "IPV6_ROUTE_METRIC"); svUnsetValue (ifcfg, "IPV6_ADDR_GEN_MODE"); + svUnsetValue (ifcfg, "IPV6_RES_OPTIONS"); return TRUE; } @@ -2557,21 +2638,20 @@ write_ip6_setting (NMConnection *connection, } } - /* Write out DNS domains - 'DOMAIN' key is shared for both IPv4 and IPv6 domains */ + /* Write out DNS domains */ num = nm_setting_ip_config_get_num_dns_searches (s_ip6); if (num > 0) { - gs_free char *ip4_domains = NULL; nm_auto_free_gstring GString *searches = NULL; - searches = g_string_new (svGetValueStr (ifcfg, "DOMAIN", &ip4_domains)); + searches = g_string_new (NULL); for (i = 0; i < num; i++) { if (searches->len > 0) g_string_append_c (searches, ' '); g_string_append (searches, nm_setting_ip_config_get_dns_search (s_ip6, i)); } - svSetValueStr (ifcfg, "DOMAIN", searches->str); - } - + svSetValueStr (ifcfg, "IPV6_DOMAIN", searches->str); + } else + svUnsetValue (ifcfg, "IPV6_DOMAIN"); /* handle IPV6_DEFROUTE */ /* IPV6_DEFROUTE has the opposite meaning from 'never-default' */ @@ -2638,66 +2718,9 @@ write_ip6_setting (NMConnection *connection, else svUnsetValue (ifcfg, "IPV6_DNS_PRIORITY"); - NM_SET_OUT (out_route6_content, write_route_file (s_ip6)); + write_res_options (ifcfg, s_ip6, "IPV6_RES_OPTIONS"); - return TRUE; -} - -static void -add_dns_option (GPtrArray *array, const char *option) -{ - if (_nm_utils_dns_option_find_idx (array, option) < 0) - g_ptr_array_add (array, (gpointer) option); -} - -static gboolean -write_res_options (NMConnection *connection, shvarFile *ifcfg, GError **error) -{ - NMSettingIPConfig *s_ip6; - NMSettingIPConfig *s_ip4; - const char *method; - int i, num_options; - gs_unref_ptrarray GPtrArray *array = NULL; - GString *value; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - - if (!s_ip4) { - /* slave-type: clear res-options */ - svUnsetValue (ifcfg, "RES_OPTIONS"); - return TRUE; - } - - array = g_ptr_array_new (); - - method = nm_setting_ip_config_get_method (s_ip4); - if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { - num_options = nm_setting_ip_config_get_num_dns_options (s_ip4); - for (i = 0; i < num_options; i++) - add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip4, i)); - } - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - method = nm_setting_ip_config_get_method (s_ip6); - if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { - num_options = nm_setting_ip_config_get_num_dns_options (s_ip6); - for (i = 0; i < num_options; i++) - add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip6, i)); - } - - if ( array->len > 0 - || nm_setting_ip_config_has_dns_options (s_ip4) - || nm_setting_ip_config_has_dns_options (s_ip6)) { - value = g_string_new (NULL); - for (i = 0; i < array->len; i++) { - if (i > 0) - g_string_append_c (value, ' '); - g_string_append (value, array->pdata[i]); - } - svSetValue (ifcfg, "RES_OPTIONS", value->str); - g_string_free (value, TRUE); - } else - svUnsetValue (ifcfg, "RES_OPTIONS"); + NM_SET_OUT (out_route6_content, write_route_file (s_ip6)); return TRUE; } @@ -2882,6 +2905,9 @@ do_write_construct (NMConnection *connection, if (!write_user_setting (connection, ifcfg, error)) return FALSE; + if (!write_tc_setting (connection, ifcfg, error)) + return FALSE; + svUnsetValue (ifcfg, "DHCP_HOSTNAME"); svUnsetValue (ifcfg, "DHCP_FQDN"); @@ -2930,9 +2956,6 @@ do_write_construct (NMConnection *connection, error)) return FALSE; - if (!write_res_options (connection, ifcfg, error)) - return FALSE; - write_connection_setting (s_con, ifcfg); NM_SET_OUT (out_ifcfg, g_steal_pointer (&ifcfg)); diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index df03bf65..2b64f3fc 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -776,7 +776,7 @@ line_free (shvarLine *line) ASSERT_shvarLine (line); g_free (line->line); g_free (line->key_with_prefix); - c_list_unlink (&line->lst); + c_list_unlink_stale (&line->lst); g_slice_free (shvarLine, line); } @@ -1171,6 +1171,11 @@ svUnsetAll (shvarFile *s, SvKeyType match_key_type) if (g_str_has_prefix (line->key, "NM_USER_")) goto do_clear; } + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_TC)) { + if ( IS_NUMBERED_TAG (line->key, "QDISC") + || IS_NUMBERED_TAG (line->key, "FILTER")) + goto do_clear; + } continue; do_clear: @@ -1318,7 +1323,7 @@ svWriteFile (shvarFile *s, int mode, GError **error) return FALSE; } - tmpfd = dup (s->fd); + tmpfd = fcntl (s->fd, F_DUPFD_CLOEXEC, 0); if (tmpfd == -1) { int errsv = errno; @@ -1373,7 +1378,8 @@ svCloseFile (shvarFile *s) g_return_if_fail (s != NULL); - nm_close (s->fd); + if (s->fd >= 0) + nm_close (s->fd); g_free (s->fileName); c_list_for_each_safe (current, safe, &s->lst_head) line_free (c_list_entry (current, shvarLine, lst)); diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index c48bbfd3..dbc4d950 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -90,7 +90,8 @@ typedef enum { SV_KEY_TYPE_ANY = (1LL << 0), SV_KEY_TYPE_ROUTE_SVFORMAT = (1LL << 1), SV_KEY_TYPE_IP4_ADDRESS = (1LL << 2), - SV_KEY_TYPE_USER = (1LL << 3), + SV_KEY_TYPE_TC = (1LL << 3), + SV_KEY_TYPE_USER = (1LL << 4), } SvKeyType; gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type); diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected index 854d2490..5d81dfef 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected @@ -1,4 +1,4 @@ -BONDING_OPTS=mode=balance-rr +BONDING_OPTS="downdelay=5 miimon=100 mode=balance-rr updelay=10" TYPE=Bond BONDING_MASTER=yes PROXY_METHOD=none diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected index 460278e1..2df1fbb3 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Infiniband_Port.cexpected @@ -1,6 +1,6 @@ CONNECTED_MODE=no TYPE=InfiniBand -TEAM_PORT_CONFIG="{ \"inf1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"inf1\": {\"prio\": -10, \"sticky\": true}}" NAME="Test Write Team Infiniband Port" UUID=${UUID} DEVICE=inf1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected index 0b1deb80..ff55cefe 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Team_Port.cexpected @@ -1,4 +1,4 @@ -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" NAME="Test Write Team Port" UUID=${UUID} ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected new file mode 100644 index 00000000..c0e47c48 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected @@ -0,0 +1,20 @@ +HWADDR=31:33:33:37:BE:CD +MTU=1492 +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=none +IPADDR=1.1.1.3 +PREFIX=24 +IPADDR1=1.1.1.5 +PREFIX1=24 +GATEWAY=1.1.1.1 +DNS1=4.2.2.1 +DNS2=4.2.2.2 +DOMAIN="foobar.com lab.foobar.com" +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write Wired Static Routes" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options index 62e301e3..cea2471a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options @@ -8,7 +8,8 @@ NM_CONTROLLED=yes PEERDNS=yes DNS1=10.2.0.4 DOMAIN="lorem.com ipsum.org dolor.edu" -RES_OPTIONS="ndots:3 single-request-reopen inet6" +RES_OPTIONS="ndots:3 single-request-reopen" +IPV6_RES_OPTIONS="inet6" IPV6INIT=yes IPV6_AUTOCONF=no IPV6ADDR="1001:abba::1234/56" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 index 7edc736a..209447b8 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 @@ -2,5 +2,5 @@ DEVICE=team0 ONBOOT=no DEVICETYPE=Team BOOTPROTO=dhcp -TEAM_CONFIG="{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }" +TEAM_CONFIG="{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 index d01e37c5..26e448cc 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 @@ -1,5 +1,5 @@ DEVICE=team0 ONBOOT=no BOOTPROTO=dhcp -TEAM_CONFIG="{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }" +TEAM_CONFIG="{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 index 966bec67..80355c26 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-1 @@ -1,5 +1,5 @@ TYPE=Ethernet -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" DEVICE=p4p1 TEAM_MASTER=team0 DEVICETYPE=TeamPort diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 index 992510ee..4284737a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-port-2 @@ -1,4 +1,4 @@ TYPE=Ethernet -TEAM_PORT_CONFIG="{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }" +TEAM_PORT_CONFIG="{\"p4p1\": {\"prio\": -10, \"sticky\": true}}" DEVICE=p4p1 TEAM_MASTER=team0 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only index 59ec32e5..94189064 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-only @@ -7,7 +7,7 @@ USERCTL=yes NM_CONTROLLED=yes PEERDNS=yes DNS1=1:2:3:4::a -DOMAIN="lorem.com ipsum.org dolor.edu" +IPV6_DOMAIN="lorem.com ipsum.org dolor.edu" IPV6INIT=yes IPV6_AUTOCONF=no IPV6ADDR="1001:abba::1234/56" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static index 6d49c01c..34acf9fe 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static @@ -19,3 +19,4 @@ IPV6ADDR_SECONDARIES="dead:beaf::2/56" DNS3=1:2:3:4::a DNS4=1:2:3:4::b RES_OPTIONS= +IPV6_RES_OPTIONS= diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index 10a63b67..8d6aaac2 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -7,3 +7,9 @@ NETMASK1=255.255.255.255 GATEWAY1=192.168.1.7 METRIC1=3 OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 initcwnd lock 13 initrwnd 14" + +ADDRESS2=44.55.66.78 +NETMASK2=255.255.255.255 +GATEWAY2=192.168.1.8 +METRIC2=3 +OPTIONS2="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 onlink window 30000 initcwnd lock 13 initrwnd 14" diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 5044a2d7..6bf27556 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -1318,7 +1318,7 @@ test_read_wired_static_routes (void) g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); /* Routes */ - g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 2); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 3); ip4_route = nm_setting_ip_config_get_route (s_ip4, 0); g_assert (ip4_route); @@ -1343,6 +1343,23 @@ test_read_wired_static_routes (void) nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); + ip4_route = nm_setting_ip_config_get_route (s_ip4, 2); + g_assert (ip4_route); + g_assert_cmpstr (nm_ip_route_get_dest (ip4_route), ==, "44.55.66.78"); + g_assert_cmpint (nm_ip_route_get_prefix (ip4_route), ==, 32); + g_assert_cmpstr (nm_ip_route_get_next_hop (ip4_route), ==, "192.168.1.8"); + g_assert_cmpint (nm_ip_route_get_metric (ip4_route), ==, 3); + nmtst_assert_route_attribute_byte (ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITCWND, 13); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_INITRWND, 14); + nmtst_assert_route_attribute_uint32 (ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); + nmtst_assert_route_attribute_string (ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); + nmtst_assert_route_attribute_boolean (ip4_route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, TRUE); + g_object_unref (connection); } @@ -2145,8 +2162,9 @@ test_read_dns_options (void) NMSettingIPConfig *s_ip4, *s_ip6; char *unmanaged = NULL; const char *option; - const char *options[] = { "ndots:3", "single-request-reopen", "inet6" }; - guint32 i, options_len = sizeof (options) / sizeof (options[0]); + const char *options4[] = { "ndots:3", "single-request-reopen" }; + const char *options6[] = { "inet6" }; + guint32 i, num; connection = _connection_from_file (TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dns-options", NULL, TYPE_ETHERNET, &unmanaged); @@ -2158,18 +2176,20 @@ test_read_dns_options (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - i = nm_setting_ip_config_get_num_dns_options (s_ip4); - g_assert_cmpint (i, ==, options_len); - - i = nm_setting_ip_config_get_num_dns_options (s_ip6); - g_assert_cmpint (i, ==, options_len); + num = nm_setting_ip_config_get_num_dns_options (s_ip4); + g_assert_cmpint (num, ==, G_N_ELEMENTS (options4)); - for (i = 0; i < options_len; i++) { + for (i = 0; i < num; i++) { option = nm_setting_ip_config_get_dns_option (s_ip4, i); - g_assert_cmpstr (options[i], ==, option); + g_assert_cmpstr (options4[i], ==, option); + } + + num = nm_setting_ip_config_get_num_dns_options (s_ip6); + g_assert_cmpint (num, ==, G_N_ELEMENTS (options6)); + for (i = 0; i < num; i++) { option = nm_setting_ip_config_get_dns_option (s_ip6, i); - g_assert_cmpstr (options[i], ==, option); + g_assert_cmpstr (options6[i], ==, option); } g_object_unref (connection); @@ -2280,6 +2300,8 @@ test_write_dns_options (void) nm_setting_ip_config_add_address (s_ip4, addr); nm_ip_address_unref (addr); + nm_setting_ip_config_add_dns_option (s_ip4, "debug"); + /* IP6 setting */ s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); nm_connection_add_setting (connection, NM_SETTING (s_ip6)); @@ -2295,26 +2317,16 @@ test_write_dns_options (void) nm_setting_ip_config_add_address (s_ip6, addr6); nm_ip_address_unref (addr6); - nm_setting_ip_config_add_dns_option (s_ip4, "debug"); nm_setting_ip_config_add_dns_option (s_ip6, "timeout:3"); nmtst_assert_connection_verifies (connection); - _writer_new_connection_FIXME (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); - /* RES_OPTIONS is copied to both IPv4 and IPv6 settings */ - nm_setting_ip_config_clear_dns_options (s_ip4, TRUE); - nm_setting_ip_config_add_dns_option (s_ip4, "debug"); - nm_setting_ip_config_add_dns_option (s_ip4, "timeout:3"); - - nm_setting_ip_config_clear_dns_options (s_ip6, TRUE); - nm_setting_ip_config_add_dns_option (s_ip6, "debug"); - nm_setting_ip_config_add_dns_option (s_ip6, "timeout:3"); - nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); } @@ -2674,7 +2686,7 @@ test_read_wifi_wep_passphrase (void) g_assert (s_wsec); g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "none"); g_assert_cmpint (nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec), ==, 0); - g_assert_cmpint (nm_setting_wireless_security_get_wep_key_type (s_wsec), ==, NM_WEP_KEY_TYPE_PASSPHRASE); + g_assert_cmpint (nm_setting_wireless_security_get_wep_key_type (s_wsec), ==, NM_WEP_KEY_TYPE_UNKNOWN); g_assert_cmpstr (nm_setting_wireless_security_get_wep_key (s_wsec, 0), ==, "foobar222blahblah"); g_assert (!nm_setting_wireless_security_get_wep_key (s_wsec, 1)); g_assert (!nm_setting_wireless_security_get_wep_key (s_wsec, 2)); @@ -4175,23 +4187,15 @@ test_write_wired_static (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection_FIXME (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile); route6file = utils_get_route6_path (testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); - /* FIXME: currently DNS domains from IPv6 setting are stored in 'DOMAIN' key in ifcfg-file - * However after re-reading they are dropped into IPv4 setting. - * So, in order to comparison succeeded, move DNS domains back to IPv6 setting. - */ reread_s_ip4 = nm_connection_get_setting_ip4_config (reread); reread_s_ip6 = nm_connection_get_setting_ip6_config (reread); - nm_setting_ip_config_add_dns_search (reread_s_ip6, nm_setting_ip_config_get_dns_search (reread_s_ip4, 2)); - nm_setting_ip_config_add_dns_search (reread_s_ip6, nm_setting_ip_config_get_dns_search (reread_s_ip4, 3)); - nm_setting_ip_config_remove_dns_search (reread_s_ip4, 3); - nm_setting_ip_config_remove_dns_search (reread_s_ip4, 2); g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip4), ==, 204); g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip6), ==, 206); @@ -4329,17 +4333,8 @@ test_write_wired_static_with_generic (void) route6file = utils_get_route6_path (testfile); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); - - /* FIXME: currently DNS domains from IPv6 setting are stored in 'DOMAIN' key in ifcfg-file - * However after re-reading they are dropped into IPv4 setting. - * So, in order to comparison succeeded, move DNS domains back to IPv6 setting. - */ reread_s_ip4 = nm_connection_get_setting_ip4_config (reread); reread_s_ip6 = nm_connection_get_setting_ip6_config (reread); - nm_setting_ip_config_add_dns_search (reread_s_ip6, nm_setting_ip_config_get_dns_search (reread_s_ip4, 2)); - nm_setting_ip_config_add_dns_search (reread_s_ip6, nm_setting_ip_config_get_dns_search (reread_s_ip4, 3)); - nm_setting_ip_config_remove_dns_search (reread_s_ip4, 3); - nm_setting_ip_config_remove_dns_search (reread_s_ip4, 2); g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip4), ==, 204); g_assert_cmpint (nm_setting_ip_config_get_route_metric (reread_s_ip6), ==, 206); @@ -4748,6 +4743,7 @@ test_write_wired_static_routes (void) NMIPAddress *addr; NMIPRoute *route; GError *error = NULL; + gboolean reread_same = FALSE; connection = nm_simple_connection_new (); @@ -4792,11 +4788,15 @@ test_write_wired_static_routes (void) /* Write out routes */ route = nm_ip_route_new (AF_INET, "1.2.3.0", 24, "222.173.190.239", 0, &error); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (3455)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (TRUE)); g_assert_no_error (error); nm_setting_ip_config_add_route (s_ip4, route); nm_ip_route_unref (route); route = nm_ip_route_new (AF_INET, "3.2.1.0", 24, "202.254.186.190", 77, &error); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (30000)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (FALSE)); g_assert_no_error (error); nm_setting_ip_config_add_route (s_ip4, route); nm_ip_route_unref (route); @@ -4818,15 +4818,28 @@ test_write_wired_static_routes (void) nmtst_assert_connection_verifies (connection); - _writer_new_connection (connection, - TEST_SCRATCH_DIR "/network-scripts/", - &testfile); + _writer_new_connection_reread (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + TEST_IFCFG_DIR "/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected", + &reread, + &reread_same); + /* ifcfg does not support setting onlink=0. It gets lost during write+re-read. + * Assert that it's missing, and patch it to check whether the rest of the + * connection equals. */ + g_assert (!reread_same); + nmtst_assert_connection_verifies_without_normalization (reread); + s_ip4 = nm_connection_get_setting_ip4_config (reread); + g_assert (s_ip4); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 2); + route = nm_setting_ip_config_get_route (s_ip4, 1); + g_assert (route); + g_assert (!nm_ip_route_get_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK)); + nm_ip_route_set_attribute (route, NM_IP_ROUTE_ATTRIBUTE_ONLINK, g_variant_new_boolean (FALSE)); - reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); routefile = utils_get_route_path (testfile); - - nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); } static void @@ -5728,6 +5741,7 @@ test_write_wifi_wep_40_ascii (void) g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, 2, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_KEY, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL); nm_setting_wireless_security_set_wep_key (s_wsec, 0, "lorem"); @@ -5815,6 +5829,7 @@ test_write_wifi_wep_104_ascii (void) g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, 0, + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, NM_WEP_KEY_TYPE_UNKNOWN, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); nm_setting_wireless_security_set_wep_key (s_wsec, 0, "LoremIpsumSit"); @@ -7368,6 +7383,7 @@ test_read_bridge_main (void) { NMConnection *connection; NMSettingBridge *s_bridge; + NMSettingWired *s_wired; const char *mac; char expected_mac_address[ETH_ALEN] = { 0x00, 0x16, 0x41, 0x11, 0x22, 0x33 }; @@ -7390,7 +7406,9 @@ test_read_bridge_main (void) g_assert (!nm_setting_bridge_get_multicast_snooping (s_bridge)); /* MAC address */ - mac = nm_setting_bridge_get_mac_address (s_bridge); + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + mac = nm_setting_wired_get_cloned_mac_address (s_wired); g_assert (mac); g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac_address, ETH_ALEN)); @@ -7405,8 +7423,8 @@ test_write_bridge_main (void) gs_unref_object NMConnection *reread = NULL; NMSettingConnection *s_con; NMSettingBridge *s_bridge; - NMSettingIPConfig *s_ip4; - NMSettingIPConfig *s_ip6; + NMSettingIPConfig *s_ip4, *s_ip6; + NMSettingWired *s_wired; NMIPAddress *addr; static const char *mac = "31:33:33:37:be:cd"; GError *error = NULL; @@ -7458,6 +7476,10 @@ test_write_bridge_main (void) NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + nm_connection_add_setting (connection, nm_setting_proxy_new ()); nmtst_assert_connection_verifies_without_normalization (connection); @@ -8023,6 +8045,10 @@ test_write_bond_main (void) s_bond = (NMSettingBond *) nm_setting_bond_new (); nm_connection_add_setting (connection, NM_SETTING (s_bond)); + nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY, "5"); + nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_UPDELAY, "10"); + nm_setting_bond_add_option (s_bond, NM_SETTING_BOND_OPTION_MIIMON, "100"); + /* IP4 setting */ s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); nm_connection_add_setting (connection, NM_SETTING (s_ip4)); @@ -8669,7 +8695,7 @@ test_read_team_master (gconstpointer user_data) NMConnection *connection; NMSettingConnection *s_con; NMSettingTeam *s_team; - const char *expected_config = "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"; + const char *expected_config = "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"; connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL); @@ -8722,7 +8748,7 @@ test_write_team_master (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; - const char *expected_config = "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"; + const char *expected_config = "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -8791,7 +8817,7 @@ test_read_team_port (gconstpointer user_data) NMConnection *connection; NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; - const char *expected_config = "{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"p4p1\": {\"prio\": -10, \"sticky\": true}}"; connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL); @@ -8816,7 +8842,7 @@ test_write_team_port (void) NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; NMSettingWired *s_wired; - const char *expected_config = "{ \"p4p1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"p4p1\": {\"prio\": -10, \"sticky\": true}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -8871,7 +8897,7 @@ test_write_team_infiniband_port (void) NMSettingConnection *s_con; NMSettingTeamPort *s_team_port; NMSettingInfiniband *s_inf; - const char *expected_config = "{ \"inf1\": { \"prio\": -10, \"sticky\": true } }"; + const char *expected_config = "{\"inf1\": {\"prio\": -10, \"sticky\": true}}"; shvarFile *f; connection = nm_simple_connection_new (); @@ -9232,7 +9258,9 @@ test_svUnescape (void) V0 ("Bob outside LAN", NULL), V1 ("x", "x"), V1 ("'{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }'", - "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"), + "{ \"device\": \"team0\", \"link_watch\": { \"name\": \"ethtool\" } }"), + V1 ("'{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}'", + "{\"device\": \"team0\", \"link_watch\": {\"name\": \"ethtool\"}}"), V1 ("x\"\"b", "xb"), V1 ("x\"c\"b", "xcb"), V1 ("\"c\"b", "cb"), diff --git a/src/settings/plugins/ifnet/nms-ifnet-connection.c b/src/settings/plugins/ifnet/nms-ifnet-connection.c index 5dbb124c..e7cd19cd 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-connection.c +++ b/src/settings/plugins/ifnet/nms-ifnet-connection.c @@ -93,7 +93,7 @@ commit_changes (NMSettingsConnection *connection, g_signal_emit (connection, signals[IFNET_CANCEL_MONITORS], 0); if (priv->conn_name) { - success = ifnet_update_parsers_by_connection (NM_CONNECTION (connection), + success = ifnet_update_parsers_by_connection (new_connection, priv->conn_name, CONF_NET_FILE, WPA_SUPPLICANT_CONF, @@ -102,7 +102,7 @@ commit_changes (NMSettingsConnection *connection, error); } else { added = TRUE; - success = ifnet_add_new_connection (NM_CONNECTION (connection), + success = ifnet_add_new_connection (new_connection, CONF_NET_FILE, WPA_SUPPLICANT_CONF, &new_name, @@ -186,11 +186,14 @@ nm_ifnet_connection_new (NMConnection *source, const char *conn_name) object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION, NULL); NM_IFNET_CONNECTION_GET_PRIVATE ((NMIfnetConnection *) object)->conn_name = g_strdup (conn_name); - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), - tmp, - update_unsaved, - NULL, - NULL)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + tmp, + update_unsaved + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED + : NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + NULL)) { g_object_unref (object); return NULL; } diff --git a/src/settings/plugins/ifnet/nms-ifnet-plugin.c b/src/settings/plugins/ifnet/nms-ifnet-plugin.c index 998b04b4..38d23f30 100644 --- a/src/settings/plugins/ifnet/nms-ifnet-plugin.c +++ b/src/settings/plugins/ifnet/nms-ifnet-plugin.c @@ -269,11 +269,12 @@ reload_connections (NMSettingsPlugin *config) } } else { /* Update existing connection with new settings */ - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (old), - NM_CONNECTION (new), - FALSE, /* don't set Unsaved */ - "ifnet-update", - &error)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (old), + NM_CONNECTION (new), + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "ifnet-update", + &error)) { /* Shouldn't ever get here as 'new' was verified by the reader already * and the UUID did not change. */ g_assert_not_reached (); @@ -519,5 +520,5 @@ settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) G_MODULE_EXPORT GObject * nm_settings_plugin_factory (void) { - return g_object_ref (settings_plugin_ifnet_get ()); + return G_OBJECT (g_object_ref (settings_plugin_ifnet_get ())); } diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c index 0928772a..bfad9d15 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -139,10 +139,12 @@ bind_device_to_connection (SettingsPluginIfupdown *self, g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS, address, NULL); } - nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), - NULL, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - NULL); + nm_settings_connection_update (NM_SETTINGS_CONNECTION (exported), + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "ifupdown-new", + NULL); } static void @@ -539,6 +541,6 @@ settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) G_MODULE_EXPORT GObject * nm_settings_plugin_factory (void) { - return g_object_ref (settings_plugin_ifupdown_get ()); + return G_OBJECT (g_object_ref (settings_plugin_ifupdown_get ())); } diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c index 300aa9f7..5a6d8a76 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c @@ -65,7 +65,7 @@ commit_changes (NMSettingsConnection *connection, nm_assert (out_reread_connection && !*out_reread_connection); nm_assert (!out_logmsg_change || !*out_logmsg_change); - if (!nms_keyfile_writer_connection (new_connection ?: NM_CONNECTION (connection), + if (!nms_keyfile_writer_connection (new_connection, nm_settings_connection_get_filename (connection), NM_FLAGS_ALL (commit_reason, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED), @@ -159,11 +159,14 @@ nms_keyfile_connection_new (NMConnection *source, NULL); /* Update our settings with what was read from the file */ - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), - tmp, - update_unsaved, - NULL, - error)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), + tmp, + update_unsaved + ? NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED + : NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + error)) { g_object_unref (object); object = NULL; } diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index ee4db320..bc64b3ca 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -258,11 +258,12 @@ update_connection (NMSKeyfilePlugin *self, else _LOGI ("update and persist "NMS_KEYFILE_CONNECTION_LOG_FMT, NMS_KEYFILE_CONNECTION_LOG_ARG (connection_new)); - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection_by_uuid), - NM_CONNECTION (connection_new), - FALSE, /* don't set Unsaved */ - "keyfile-update", - &local)) { + if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (connection_by_uuid), + NM_CONNECTION (connection_new), + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + "keyfile-update", + &local)) { /* Shouldn't ever get here as 'connection_new' was verified by the reader already * and the UUID did not change. */ g_assert_not_reached (); diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_TC_Config b/src/settings/plugins/keyfile/tests/keyfiles/Test_TC_Config new file mode 100644 index 00000000..14280eef --- /dev/null +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_TC_Config @@ -0,0 +1,11 @@ + +[connection] +id=Test TC Config +uuid=32a51666-95ea-1337-b371-dcf5e54b1001 +type=802-3-ethernet + +[tc] +qdisc.root=handle 1234 fq_codel +qdisc.ffff:fff1=ingress +tfilter.1234:=matchall action drop +tfilter.ffff:=matchall action simple sdata Hello diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index 2584a722..f27efddd 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 - 2014 Red Hat, Inc. + * Copyright (C) 2008 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -27,6 +27,7 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> +#include <linux/pkt_sched.h> #include "nm-core-internal.h" @@ -2624,6 +2625,125 @@ test_write_flags_property (void) /*****************************************************************************/ static void +test_read_tc_config (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingTCConfig *s_tc; + NMTCQdisc *qdisc1, *qdisc2; + NMTCAction *action1, *action2; + NMTCTfilter *tfilter1, *tfilter2; + gs_free_error GError *error = NULL; + gboolean success; + + connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_TC_Config", NULL); + g_assert (connection); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_tc = nm_connection_get_setting_tc_config (connection); + g_assert (s_tc); + + g_assert (nm_setting_tc_config_get_num_qdiscs (s_tc) == 2); + + qdisc1 = nm_setting_tc_config_get_qdisc (s_tc, 0); + g_assert (qdisc1); + g_assert (g_strcmp0 (nm_tc_qdisc_get_kind (qdisc1), "fq_codel") == 0); + g_assert (nm_tc_qdisc_get_handle (qdisc1) == TC_H_MAKE (0x1234 << 16, 0x0000)); + g_assert (nm_tc_qdisc_get_parent (qdisc1) == TC_H_ROOT); + + qdisc2 = nm_setting_tc_config_get_qdisc (s_tc, 1); + g_assert (qdisc2); + g_assert (g_strcmp0 (nm_tc_qdisc_get_kind (qdisc2), "ingress") == 0); + g_assert (nm_tc_qdisc_get_handle (qdisc2) == TC_H_MAKE (TC_H_INGRESS, 0)); + g_assert (nm_tc_qdisc_get_parent (qdisc2) == TC_H_INGRESS); + + g_assert (nm_setting_tc_config_get_num_tfilters (s_tc) == 2); + + tfilter1 = nm_setting_tc_config_get_tfilter (s_tc, 0); + g_assert (tfilter1); + g_assert (g_strcmp0 (nm_tc_tfilter_get_kind (tfilter1), "matchall") == 0); + g_assert (nm_tc_tfilter_get_handle (tfilter1) == TC_H_UNSPEC); + g_assert (nm_tc_tfilter_get_parent (tfilter1) == TC_H_MAKE (0x1234 << 16, 0x0000)); + + action1 = nm_tc_tfilter_get_action (tfilter1); + g_assert (action1); + g_assert (g_strcmp0 (nm_tc_action_get_kind (action1), "drop") == 0); + + tfilter2 = nm_setting_tc_config_get_tfilter (s_tc, 1); + g_assert (tfilter2); + g_assert (g_strcmp0 (nm_tc_tfilter_get_kind (tfilter2), "matchall") == 0); + g_assert (nm_tc_tfilter_get_handle (tfilter2) == TC_H_UNSPEC); + g_assert (nm_tc_tfilter_get_parent (tfilter2) == TC_H_MAKE (TC_H_INGRESS, 0)); + + action2 = nm_tc_tfilter_get_action (tfilter2); + g_assert (action2); + g_assert (g_strcmp0 (nm_tc_action_get_kind (action2), "simple") == 0); + g_assert (g_strcmp0 (g_variant_get_bytestring (nm_tc_action_get_attribute (action2, "sdata")), + "Hello") == 0); +} + +static void +test_write_tc_config (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSetting *s_tc; + NMTCQdisc *qdisc1, *qdisc2; + NMTCTfilter *tfilter1, *tfilter2; + NMTCAction *action; + GError *error = NULL; + + connection = nmtst_create_minimal_connection ("Test TC", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + s_tc = nm_setting_tc_config_new (); + + qdisc1 = nm_tc_qdisc_new ("fq_codel", TC_H_ROOT, &error); + nmtst_assert_success (qdisc1, error); + nm_tc_qdisc_set_handle (qdisc1, TC_H_MAKE (0x1234 << 16, 0x0000)); + nm_setting_tc_config_add_qdisc (NM_SETTING_TC_CONFIG (s_tc), qdisc1); + + qdisc2 = nm_tc_qdisc_new ("ingress", TC_H_INGRESS, &error); + nmtst_assert_success (qdisc2, error); + nm_tc_qdisc_set_handle (qdisc2, TC_H_MAKE (TC_H_INGRESS, 0)); + nm_setting_tc_config_add_qdisc (NM_SETTING_TC_CONFIG (s_tc), qdisc2); + + tfilter1 = nm_tc_tfilter_new ("matchall", + TC_H_MAKE (0x1234 << 16, 0x0000), + &error); + nmtst_assert_success (tfilter1, error); + action = nm_tc_action_new ("drop", &error); + nmtst_assert_success (action, error); + nm_tc_tfilter_set_action (tfilter1, action); + nm_tc_action_unref (action); + nm_setting_tc_config_add_tfilter (NM_SETTING_TC_CONFIG (s_tc), tfilter1); + nm_tc_tfilter_unref (tfilter1); + + tfilter2 = nm_tc_tfilter_new ("matchall", + TC_H_MAKE (TC_H_INGRESS, 0), + &error); + nmtst_assert_success (tfilter2, error); + action = nm_tc_action_new ("simple", &error); + nmtst_assert_success (action, error); + nm_tc_action_set_attribute (action, "sdata", g_variant_new_bytestring ("Hello")); + nm_tc_tfilter_set_action (tfilter2, action); + nm_tc_action_unref (action); + nm_setting_tc_config_add_tfilter (NM_SETTING_TC_CONFIG (s_tc), tfilter2); + nm_tc_tfilter_unref (tfilter2); + + nm_connection_add_setting (connection, s_tc); + + nmtst_connection_normalize (connection); + write_test_connection_and_reread (connection, FALSE); + + nm_tc_qdisc_unref (qdisc1); + nm_tc_qdisc_unref (qdisc2); +} + +/*****************************************************************************/ + +static void _escape_filename (const char *filename, gboolean would_be_ignored) { gs_free char *esc = NULL; @@ -2748,6 +2868,9 @@ int main (int argc, char **argv) g_test_add_func ("/keyfile/test_read_flags_property", test_read_flags_property); g_test_add_func ("/keyfile/test_write_flags_property", test_write_flags_property); + g_test_add_func ("/keyfile/test_read_tc_config", test_read_tc_config); + g_test_add_func ("/keyfile/test_write_tc_config", test_write_tc_config); + g_test_add_func ("/keyfile/test_nm_keyfile_plugin_utils_escape_filename", test_nm_keyfile_plugin_utils_escape_filename); return g_test_run (); |