diff options
Diffstat (limited to 'src/nm-manager.c')
| -rw-r--r-- | src/nm-manager.c | 149 |
1 files changed, 97 insertions, 52 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c index d112fcf7..132cf5a0 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1,19 +1,5 @@ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * +// SPDX-License-Identifier: GPL-2.0+ +/* * Copyright (C) 2007 - 2009 Novell, Inc. * Copyright (C) 2007 - 2017 Red Hat, Inc. */ @@ -25,6 +11,10 @@ #include <stdlib.h> #include <fcntl.h> #include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sendfile.h> +#include <limits.h> #include "nm-glib-aux/nm-c-list.h" @@ -1168,16 +1158,16 @@ _reload_auth_cb (NMAuthChain *chain, NM_MANAGER_ERROR_PERMISSION_DENIED, "Not authorized to reload configuration"); } else { - if (NM_FLAGS_ANY (flags, ~NM_MANAGER_RELOAD_FLAGS_ALL)) { + if (NM_FLAGS_ANY (flags, ~NM_MANAGER_RELOAD_FLAG_ALL)) { /* invalid flags */ } else if (flags == 0) reload_type = NM_CONFIG_CHANGE_CAUSE_SIGHUP; else { - if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAGS_CONF)) + if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAG_CONF)) reload_type |= NM_CONFIG_CHANGE_CAUSE_CONF; - if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAGS_DNS_RC)) + if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAG_DNS_RC)) reload_type |= NM_CONFIG_CHANGE_CAUSE_DNS_RC; - if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAGS_DNS_FULL)) + if (NM_FLAGS_HAS (flags, NM_MANAGER_RELOAD_FLAG_DNS_FULL)) reload_type |= NM_CONFIG_CHANGE_CAUSE_DNS_FULL; } @@ -1729,7 +1719,10 @@ nm_manager_get_state (NMManager *manager) /*****************************************************************************/ static NMDevice * -find_parent_device_for_connection (NMManager *self, NMConnection *connection, NMDeviceFactory *cached_factory) +find_parent_device_for_connection (NMManager *self, + NMConnection *connection, + NMDeviceFactory *cached_factory, + const char **out_parent_spec) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDeviceFactory *factory; @@ -1739,6 +1732,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM NMDevice *candidate; g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + NM_SET_OUT (out_parent_spec, NULL); if (!cached_factory) { factory = nm_device_factory_manager_find_factory_for_connection (connection); @@ -1751,6 +1745,8 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM if (!parent_name) return NULL; + NM_SET_OUT (out_parent_spec, parent_name); + /* Try as an interface name of a parent device */ parent = find_device_by_iface (self, parent_name, NULL, NULL); if (parent) @@ -1792,6 +1788,9 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM * @self: the #NMManager * @connection: the #NMConnection to get the interface for * @out_parent: on success, the parent device if any + * @out_parent_spec: on return, a string specifying the parent device + * in the connection. This can be a device name, a MAC address or a + * connection UUID. * @error: an error if determining the virtual interface name failed * * Given @connection, returns the interface name that the connection @@ -1805,14 +1804,15 @@ char * nm_manager_get_connection_iface (NMManager *self, NMConnection *connection, NMDevice **out_parent, + const char **out_parent_spec, GError **error) { NMDeviceFactory *factory; char *iface = NULL; NMDevice *parent = NULL; - if (out_parent) - *out_parent = NULL; + NM_SET_OUT (out_parent, NULL); + NM_SET_OUT (out_parent_spec, NULL); factory = nm_device_factory_manager_find_factory_for_connection (connection); if (!factory) { @@ -1835,7 +1835,7 @@ nm_manager_get_connection_iface (NMManager *self, goto return_ifname_fom_connection; } - parent = find_parent_device_for_connection (self, connection, factory); + parent = find_parent_device_for_connection (self, connection, factory, out_parent_spec); iface = nm_device_factory_get_connection_iface (factory, connection, parent ? nm_device_get_ip_iface (parent) : NULL, @@ -1932,6 +1932,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) gs_free NMSettingsConnection **connections = NULL; guint i; gs_free char *iface = NULL; + const char *parent_spec; NMDevice *device = NULL, *parent = NULL; NMDevice *dev_candidate; GError *error = NULL; @@ -1940,7 +1941,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) g_return_val_if_fail (NM_IS_MANAGER (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - iface = nm_manager_get_connection_iface (self, connection, &parent, &error); + iface = nm_manager_get_connection_iface (self, connection, &parent, &parent_spec, &error); if (!iface) { _LOG3D (LOGD_DEVICE, connection, "can't get a name of a virtual device: %s", error->message); @@ -1948,6 +1949,11 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) return NULL; } + if (parent_spec && !parent) { + /* parent is not ready, wait */ + return NULL; + } + /* See if there's a device that is already compatible with this connection */ c_list_for_each_entry (dev_candidate, &priv->devices_lst_head, devices_lst) { if (nm_device_check_connection_compatible (dev_candidate, connection, NULL)) { @@ -2018,7 +2024,8 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) s_con = nm_connection_get_setting_connection (candidate); g_assert (s_con); - if (!nm_setting_connection_get_autoconnect (s_con)) + if ( !nm_setting_connection_get_autoconnect (s_con) + || nm_settings_connection_autoconnect_is_blocked (connections[i])) continue; /* Create any backing resources the device needs */ @@ -2061,10 +2068,10 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) gs_free char *ifname = NULL; NMDevice *parent; - parent = find_parent_device_for_connection (self, connection, NULL); + parent = find_parent_device_for_connection (self, connection, NULL, NULL); if (parent == device) { /* Only try to activate devices that don't already exist */ - ifname = nm_manager_get_connection_iface (self, connection, &parent, &error); + ifname = nm_manager_get_connection_iface (self, connection, &parent, NULL, &error); if (ifname) { if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname)) connection_changed (self, sett_conn); @@ -2133,7 +2140,7 @@ connection_changed_on_idle (NMManager *self, if (priv->connection_changed_on_idle_id == 0) priv->connection_changed_on_idle_id = g_idle_add (connection_changed_on_idle_cb, self); - if (!nm_c_list_elem_find_first (&priv->connection_changed_on_idle_lst, sett_conn)) { + if (!nm_c_list_elem_find_first_ptr (&priv->connection_changed_on_idle_lst, sett_conn)) { c_list_link_tail (&priv->connection_changed_on_idle_lst, &nm_c_list_elem_new_stale (g_object_ref (sett_conn))->lst); } @@ -2690,6 +2697,34 @@ get_existing_connection (NMManager *self, } static gboolean +copy_lease (const char *src, const char *dst) +{ + nm_auto_close int src_fd = -1; + int dst_fd; + ssize_t res, size = SSIZE_MAX; + + src_fd = open (src, O_RDONLY|O_CLOEXEC); + if (src_fd < 0) + return FALSE; + + dst_fd = open (dst, O_CREAT|O_EXCL|O_CLOEXEC|O_WRONLY, 0644); + if (dst_fd < 0) + return FALSE; + + while ((res = sendfile (dst_fd, src_fd, NULL, size)) > 0) + size -= res; + + nm_close (dst_fd); + + if (res != 0) { + unlink (dst); + return FALSE; + } + + return TRUE; +} + +static gboolean recheck_assume_connection (NMManager *self, NMDevice *device) { @@ -2730,7 +2765,8 @@ recheck_assume_connection (NMManager *self, nm_settings_connection_get_uuid (sett_conn), nm_device_get_iface (device)); - if (rename (initramfs_lease, connection_lease) == 0) { + if (copy_lease (initramfs_lease, connection_lease)) { + unlink (initramfs_lease); /* * We've managed to steal the lease used by initramfs before it * killed off the dhclient. We need to take ownership of the configured @@ -3207,22 +3243,6 @@ factory_device_added_cb (NMDeviceFactory *factory, } } -static gboolean -factory_component_added_cb (NMDeviceFactory *factory, - GObject *component, - gpointer user_data) -{ - NMManager *self = user_data; - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; - - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - if (nm_device_notify_component_added (device, component)) - return TRUE; - } - return FALSE; -} - static void _register_device_factory (NMDeviceFactory *factory, gpointer user_data) { @@ -3232,10 +3252,18 @@ _register_device_factory (NMDeviceFactory *factory, gpointer user_data) NM_DEVICE_FACTORY_DEVICE_ADDED, G_CALLBACK (factory_device_added_cb), self); - g_signal_connect (factory, - NM_DEVICE_FACTORY_COMPONENT_ADDED, - G_CALLBACK (factory_component_added_cb), - self); +} + +/*****************************************************************************/ + +void +nm_manager_notify_device_availibility_maybe_changed (NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMDevice *device; + + c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) + nm_device_notify_availability_maybe_changed (device); } /*****************************************************************************/ @@ -4574,6 +4602,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * NMAuthSubject *subject; GError *local = NULL; NMConnectionMultiConnect multi_connect; + const char *parent_spec; g_return_val_if_fail (NM_IS_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE); @@ -4626,7 +4655,14 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * parent = find_parent_device_for_connection (self, nm_settings_connection_get_connection (sett_conn), - NULL); + NULL, + &parent_spec); + + if (parent_spec && !parent) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, + "parent device '%s' not found", parent_spec); + return FALSE; + } if (parent && !nm_device_is_real (parent)) { NMSettingsConnection *parent_con; @@ -4638,6 +4674,15 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * return FALSE; } + if ( nm_active_connection_get_activation_reason (active) == NM_ACTIVATION_REASON_AUTOCONNECT + && nm_settings_connection_autoconnect_blocked_reason_get (parent_con, + NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST)) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, + "the parent connection of %s cannot autoactivate because it is blocked due to user request", + nm_device_get_iface (device)); + return FALSE; + } + parent_ac = nm_manager_activate_connection (self, parent_con, NULL, @@ -5181,7 +5226,7 @@ validate_activation_request (NMManager *self, } /* Look for an existing device with the connection's interface name */ - iface = nm_manager_get_connection_iface (self, connection, NULL, error); + iface = nm_manager_get_connection_iface (self, connection, NULL, NULL, error); if (!iface) return NULL; |