diff options
Diffstat (limited to 'src/devices/nm-device.c')
| -rw-r--r-- | src/devices/nm-device.c | 1840 |
1 files changed, 1311 insertions, 529 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index ac840ab9..bc532ff9 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -39,38 +39,39 @@ #include "nm-device-private.h" #include "NetworkManagerUtils.h" #include "nm-manager.h" -#include "nm-platform.h" -#include "nm-rdisc.h" -#include "nm-lndp-rdisc.h" -#include "nm-dhcp-manager.h" -#include "nm-activation-request.h" +#include "platform/nm-platform.h" +#include "ndisc/nm-ndisc.h" +#include "ndisc/nm-lndp-ndisc.h" +#include "dhcp/nm-dhcp-manager.h" +#include "nm-act-request.h" +#include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "nm-dnsmasq-manager.h" +#include "nm-pacrunner-manager.h" +#include "dnsmasq/nm-dnsmasq-manager.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" #include "nm-rfkill-manager.h" #include "nm-firewall-manager.h" -#include "nm-enum-types.h" -#include "nm-settings-connection.h" -#include "nm-settings.h" +#include "settings/nm-settings-connection.h" +#include "settings/nm-settings.h" #include "nm-auth-utils.h" #include "nm-dispatcher.h" #include "nm-config.h" -#include "nm-dns-manager.h" +#include "dns/nm-dns-manager.h" #include "nm-core-internal.h" #include "nm-default-route-manager.h" #include "nm-route-manager.h" +#include "systemd/nm-sd.h" #include "nm-lldp-listener.h" -#include "sd-ipv4ll.h" #include "nm-audit-manager.h" #include "nm-arping-manager.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF (NMDevice); -#include "nmdbus-device.h" -#include "nmdbus-device-statistics.h" +#include "introspection/org.freedesktop.NetworkManager.Device.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Statistics.h" G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT) @@ -82,6 +83,8 @@ enum { AUTH_REQUEST, IP4_CONFIG_CHANGED, IP6_CONFIG_CHANGED, + IP6_PREFIX_DELEGATED, + IP6_SUBNET_NEEDED, REMOVED, RECHECK_AUTO_ACTIVATE, RECHECK_ASSUME, @@ -120,6 +123,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice, PROP_PHYSICAL_PORT_ID, PROP_IS_MASTER, PROP_MASTER, + PROP_PARENT, PROP_HW_ADDRESS, PROP_PERM_HW_ADDRESS, PROP_HAS_PENDING_ACTION, @@ -134,7 +138,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice, #define DEFAULT_AUTOCONNECT TRUE -/***********************************************************/ +/*****************************************************************************/ #define PENDING_ACTION_DHCP4 "dhcp4" #define PENDING_ACTION_DHCP6 "dhcp6" @@ -222,10 +226,14 @@ typedef struct _NMDevicePrivate { GSList *pending_actions; GSList *dad6_failed_addrs; + NMDevice *parent_device; + char * udi; char * iface; /* may change, could be renamed by user */ int ifindex; + int parent_ifindex; + union { const guint8 hw_addr_len; /* read-only */ guint8 hw_addr_len_; @@ -253,6 +261,9 @@ typedef struct _NMDevicePrivate { bool firmware_missing:1; bool nm_plugin_missing:1; bool hw_addr_perm_fake:1; /* whether the permanent HW address could not be read and is a fake */ + + NMUtilsStableType current_stable_id_type:3; + GHashTable * available_connections; char * hw_addr; char * hw_addr_perm; @@ -295,15 +306,30 @@ typedef struct _NMDevicePrivate { bool ignore_carrier; gulong ignore_carrier_id; guint32 mtu; - bool up; /* IFF_UP */ + guint32 ip6_mtu; + guint32 mtu_initial; + guint32 ip6_mtu_initial; + + bool mtu_initialized:1; + + bool up:1; /* IFF_UP */ /* Generic DHCP stuff */ guint32 dhcp_timeout; char * dhcp_anycast_address; + char * current_stable_id; + + /* Proxy Configuration */ + NMProxyConfig *proxy_config; + NMPacrunnerManager *pacrunner_manager; + /* IP4 configuration info */ NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */ - IpState ip4_state; + union { + const IpState ip4_state; + IpState ip4_state_; + }; NMIP4Config * con_ip4_config; /* config from the setting */ NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ NMIP4Config * ext_ip4_config; /* Stuff added outside NM */ @@ -352,20 +378,22 @@ typedef struct _NMDevicePrivate { /* IP6 configuration info */ NMIP6Config * ip6_config; - IpState ip6_state; + union { + const IpState ip6_state; + IpState ip6_state_; + }; NMIP6Config * con_ip6_config; /* config from the setting */ NMIP6Config * wwan_ip6_config; NMIP6Config * ext_ip6_config; /* Stuff added outside NM */ NMIP6Config * ext_ip6_config_captured; /* Configuration captured from platform. */ GSList * vpn6_configs; /* VPNs which use this device */ bool nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */ - guint32 ip6_mtu; NMIP6Config * dad6_ip6_config; - NMRDisc * rdisc; - gulong rdisc_changed_id; - gulong rdisc_timeout_id; - NMSettingIP6ConfigPrivacy rdisc_use_tempaddr; + NMNDisc * ndisc; + gulong ndisc_changed_id; + gulong ndisc_timeout_id; + NMSettingIP6ConfigPrivacy ndisc_use_tempaddr; /* IP6 config from autoconf */ NMIP6Config * ac_ip6_config; @@ -376,8 +404,9 @@ typedef struct _NMDevicePrivate { struct { NMDhcpClient * client; - NMRDiscDHCPLevel mode; + NMNDiscDHCPLevel mode; gulong state_sigid; + gulong prefix_sigid; NMDhcp6Config * config; /* IP6 config from DHCP */ NMIP6Config * ip6_config; @@ -385,8 +414,11 @@ typedef struct _NMDevicePrivate { char * event_id; guint restart_id; guint num_tries_left; + guint needed_prefixes; } dhcp6; + gboolean needs_ip6_subnet; + /* allow autoconnect feature */ bool autoconnect; @@ -417,6 +449,8 @@ typedef struct _NMDevicePrivate { } NMDevicePrivate; +static void nm_device_set_proxy_config (NMDevice *self, GHashTable *options); + static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *config, guint32 default_route_metric, @@ -462,11 +496,11 @@ static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection, N static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason); static void nm_device_start_ip_check (NMDevice *self); static void realize_start_setup (NMDevice *self, const NMPlatformLink *plink); -static void nm_device_set_mtu (NMDevice *self, guint32 mtu); +static void _commit_mtu (NMDevice *self, const NMIP4Config *config); static void dhcp_schedule_restart (NMDevice *self, int family, const char *reason); static void _cancel_activation (NMDevice *self); -/***********************************************************/ +/*****************************************************************************/ #define QUEUED_PREFIX "queued state change to " @@ -570,7 +604,7 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_reason_to_string, NMDeviceStateReason, #define reason_to_string(reason) \ NM_UTILS_LOOKUP_STR (_reason_to_string, reason) -/***********************************************************/ +/*****************************************************************************/ NMSettings * nm_device_get_settings (NMDevice *self) @@ -604,18 +638,23 @@ init_ip6_config_dns_priority (NMDevice *self, NMIP6Config *config) nm_ip6_config_set_dns_priority (config, priority ?: NM_DNS_PRIORITY_DEFAULT_NORMAL); } -/***********************************************************/ +/*****************************************************************************/ gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value) { - return nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), value); + return nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)), value); } static guint32 -nm_device_ipv6_sysctl_get_int32 (NMDevice *self, const char *property, gint32 fallback) +nm_device_ipv6_sysctl_get_uint32 (NMDevice *self, const char *property, guint32 fallback) { - return nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property), fallback); + return nm_platform_sysctl_get_int_checked (NM_PLATFORM_GET, + NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), property)), + 10, + 0, + G_MAXUINT32, + fallback); } gboolean @@ -635,31 +674,111 @@ _add_capabilities (NMDevice *self, NMDeviceCapabilities capabilities) } } -/***********************************************************/ +/*****************************************************************************/ static const char * -_get_stable_id (NMConnection *connection, NMUtilsStableType *out_stable_type) +_get_stable_id (NMDevice *self, + NMConnection *connection, + NMUtilsStableType *out_stable_type) { - NMSettingConnection *s_con; - const char *stable_id; + NMDevicePrivate *priv; + nm_assert (NM_IS_DEVICE (self)); nm_assert (NM_IS_CONNECTION (connection)); nm_assert (out_stable_type); - s_con = nm_connection_get_setting_connection (connection); - g_return_val_if_fail (s_con, NULL); + priv = NM_DEVICE_GET_PRIVATE (self); + + /* we cache the generated stable ID for the time of an activation. + * + * The reason is, that we don't want the stable-id to change as long + * as the device is active. + * + * Especially with ${RANDOM} stable-id we want to generate *one* configuration + * for each activation. */ + if (G_UNLIKELY (!priv->current_stable_id)) { + gs_free char *default_id = NULL; + gs_free char *generated = NULL; + NMUtilsStableType stable_type; + NMSettingConnection *s_con; + const char *stable_id; + const char *uuid; - stable_id = nm_setting_connection_get_stable_id (s_con); - if (!stable_id) { - *out_stable_type = NM_UTILS_STABLE_TYPE_UUID; - return nm_connection_get_uuid (connection); + s_con = nm_connection_get_setting_connection (connection); + + stable_id = nm_setting_connection_get_stable_id (s_con); + + if (!stable_id) { + default_id = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "connection.stable-id", + self); + stable_id = default_id; + } + + uuid = nm_connection_get_uuid (connection); + + stable_type = nm_utils_stable_id_parse (stable_id, + uuid, + NULL, + &generated); + + /* current_stable_id_type is a bitfield! */ + priv->current_stable_id_type = stable_type; + nm_assert (stable_type <= (NMUtilsStableType) 0x3); + nm_assert (stable_type + (NMUtilsStableType) 1 > (NMUtilsStableType) 0); + nm_assert (priv->current_stable_id_type == stable_type); + + if (stable_type == NM_UTILS_STABLE_TYPE_UUID) + priv->current_stable_id = g_strdup (uuid); + else if (stable_type == NM_UTILS_STABLE_TYPE_STABLE_ID) + priv->current_stable_id = g_strdup (stable_id); + else if (stable_type == NM_UTILS_STABLE_TYPE_GENERATED) + priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_generated_complete (generated)); + else { + nm_assert (stable_type == NM_UTILS_STABLE_TYPE_RANDOM); + priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_random ()); + } + _LOGT (LOGD_DEVICE, + "stable-id: type=%d, \"%s\"" + "%s%s%s", + (int) priv->current_stable_id_type, + priv->current_stable_id, + NM_PRINT_FMT_QUOTED (stable_type == NM_UTILS_STABLE_TYPE_GENERATED, " from \"", generated, "\"", "")); } - *out_stable_type = NM_UTILS_STABLE_TYPE_STABLE_ID; - return stable_id; + *out_stable_type = priv->current_stable_id_type; + return priv->current_stable_id; +} + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_ip_state_to_string, IpState, + NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"), + NM_UTILS_LOOKUP_STR_ITEM (IP_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM (IP_WAIT, "wait"), + NM_UTILS_LOOKUP_STR_ITEM (IP_CONF, "conf"), + NM_UTILS_LOOKUP_STR_ITEM (IP_DONE, "done"), + NM_UTILS_LOOKUP_STR_ITEM (IP_FAIL, "fail"), +); + +static void +_set_ip_state (NMDevice *self, int addr_family, IpState new_state) +{ + IpState *p; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + + p = addr_family == AF_INET ? &priv->ip4_state_ : &priv->ip6_state_; + + if (*p != new_state) { + _LOGT (LOGD_DEVICE, "ip%c-state: set to %d (%s)", addr_family == AF_INET ? '4' : '6', + (int) new_state, _ip_state_to_string (new_state)); + *p = new_state; + } } -/***********************************************************/ +/*****************************************************************************/ const char * nm_device_get_udi (NMDevice *self) @@ -738,43 +857,224 @@ nm_device_get_ip_ifindex (NMDevice *self) return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; } -void +/** + * nm_device_set_ip_iface: + * @self: the #NMDevice + * @iface: the new IP interface name + * + * Updates the IP interface name and possibly the ifindex. + * + * Returns: %TRUE if the anything (name or ifindex) changed, %FALSE if nothing + * changed. + */ +gboolean nm_device_set_ip_iface (NMDevice *self, const char *iface) { NMDevicePrivate *priv; - char *old_ip_iface; + int ifindex; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); priv = NM_DEVICE_GET_PRIVATE (self); - if (!g_strcmp0 (iface, priv->ip_iface)) - return; - - old_ip_iface = priv->ip_iface; - priv->ip_ifindex = 0; - - priv->ip_iface = g_strdup (iface); - if (priv->ip_iface) { - priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface); - if (priv->ip_ifindex > 0) { - if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) - nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ip_ifindex, TRUE); + if (nm_streq0 (iface, priv->ip_iface)) { + if (!iface) + return FALSE; + ifindex = nm_platform_if_nametoindex (NM_PLATFORM_GET, iface); + if ( ifindex <= 0 + || priv->ip_ifindex == ifindex) + return FALSE; - if (!nm_platform_link_is_up (NM_PLATFORM_GET, priv->ip_ifindex)) - nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL); + priv->ip_ifindex = ifindex; + _LOGD (LOGD_DEVICE, "ip-ifname: update ifindex for ifname '%s': %d", iface, priv->ip_ifindex); + } else { + g_free (priv->ip_iface); + priv->ip_iface = g_strdup (iface); + + if (iface) { + /* The @iface name is not in sync with the platform cache. + * So, there is no point asking the platform cache to resolve + * the ifindex. Instead, we can only hope that the interface + * with this name still exists and we resolve the ifindex + * anew. + */ + priv->ip_ifindex = nm_platform_if_nametoindex (NM_PLATFORM_GET, iface); + if (priv->ip_ifindex > 0) + _LOGD (LOGD_DEVICE, "ip-ifname: set ifname '%s', ifindex %d", iface, priv->ip_ifindex); + else + _LOGW (LOGD_DEVICE, "ip-ifname: set ifname '%s', unknown ifindex", iface); } else { - /* Device IP interface must always be a kernel network interface */ - _LOGW (LOGD_PLATFORM, "failed to look up interface index"); + priv->ip_ifindex = 0; + _LOGD (LOGD_DEVICE, "ip-ifname: clear ifname"); } } + if (priv->ip_ifindex > 0) { + if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) + nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ip_ifindex, TRUE); + + if (!nm_platform_link_is_up (NM_PLATFORM_GET, priv->ip_ifindex)) + nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL); + } + /* We don't care about any saved values from the old iface */ g_hash_table_remove_all (priv->ip6_saved_properties); - /* Emit change notification */ - if (g_strcmp0 (old_ip_iface, priv->ip_iface)) - _notify (self, PROP_IP_IFACE); - g_free (old_ip_iface); + _notify (self, PROP_IP_IFACE); + return TRUE; +} + +static gboolean +_ip_iface_update (NMDevice *self, const char *ip_iface) +{ + NMDevicePrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + priv = NM_DEVICE_GET_PRIVATE (self); + + g_return_val_if_fail (priv->ip_iface, FALSE); + g_return_val_if_fail (priv->ip_ifindex > 0, FALSE); + g_return_val_if_fail (ip_iface, FALSE); + + if (!ip_iface[0]) + return FALSE; + + if (nm_streq (priv->ip_iface, ip_iface)) + return FALSE; + + _LOGI (LOGD_DEVICE, "ip-ifname: interface index %d renamed ip_iface (%d) from '%s' to '%s'", + priv->ifindex, priv->ip_ifindex, + priv->ip_iface, ip_iface); + g_free (priv->ip_iface); + priv->ip_iface = g_strdup (ip_iface); + _notify (self, PROP_IP_IFACE); + return TRUE; +} + +/*****************************************************************************/ + +int +nm_device_parent_get_ifindex (NMDevice *self) +{ + NMDevicePrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE (self), 0); + + priv = NM_DEVICE_GET_PRIVATE (self); + return priv->parent_ifindex; +} + +NMDevice * +nm_device_parent_get_device (NMDevice *self) +{ + NMDevicePrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + + priv = NM_DEVICE_GET_PRIVATE (self); + return priv->parent_device; +} + +static void +parent_changed_notify (NMDevice *self, + int old_ifindex, + NMDevice *old_parent, + int new_ifindex, + NMDevice *new_parent) +{ + /* empty handler to allow subclasses to always chain up the virtual function. */ +} + +static gboolean +_parent_set_ifindex (NMDevice *self, + int parent_ifindex, + gboolean force_check) +{ + NMDevicePrivate *priv; + NMDevice *parent_device; + gboolean changed = FALSE; + int old_ifindex; + NMDevice *old_device; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (parent_ifindex <= 0) + parent_ifindex = 0; + + old_ifindex = priv->parent_ifindex; + old_device = priv->parent_device; + + if (priv->parent_ifindex == parent_ifindex) { + if (parent_ifindex > 0) { + if ( !force_check + && priv->parent_device + && nm_device_get_ifindex (priv->parent_device) == parent_ifindex) + return FALSE; + } else { + if (!priv->parent_device) + return FALSE; + } + } else { + priv->parent_ifindex = parent_ifindex; + changed = TRUE; + } + + if (parent_ifindex > 0) { + parent_device = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + if (parent_device == self) + parent_device = NULL; + } else + parent_device = NULL; + + if (parent_device != priv->parent_device) { + priv->parent_device = parent_device; + changed = TRUE; + } + + if (changed) { + if (priv->parent_ifindex <= 0) + _LOGD (LOGD_DEVICE, "parent: clear"); + else if (!priv->parent_device) + _LOGD (LOGD_DEVICE, "parent: ifindex %d, no device", priv->parent_ifindex); + else { + _LOGD (LOGD_DEVICE, "parent: ifindex %d, device %p, %s", priv->parent_ifindex, + priv->parent_device, nm_device_get_iface (priv->parent_device)); + } + + NM_DEVICE_GET_CLASS (self)->parent_changed_notify (self, old_ifindex, old_device, priv->parent_ifindex, priv->parent_device); + + _notify (self, PROP_PARENT); + } + return changed; +} + +void +nm_device_parent_set_ifindex (NMDevice *self, + int parent_ifindex) +{ + _parent_set_ifindex (self, parent_ifindex, FALSE); +} + +gboolean +nm_device_parent_notify_changed (NMDevice *self, + NMDevice *change_candidate, + gboolean device_removed) +{ + NMDevicePrivate *priv; + + nm_assert (NM_IS_DEVICE (self)); + nm_assert (NM_IS_DEVICE (change_candidate)); + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->parent_ifindex > 0) { + if ( priv->parent_device == change_candidate + || priv->parent_ifindex == nm_device_get_ifindex (change_candidate)) + return _parent_set_ifindex (self, priv->parent_ifindex, device_removed); + } + return FALSE; } /*****************************************************************************/ @@ -1030,6 +1330,8 @@ nm_device_get_priority (NMDevice *self) case NM_DEVICE_TYPE_ETHERNET: case NM_DEVICE_TYPE_VETH: return 100; + case NM_DEVICE_TYPE_MACSEC: + return 125; case NM_DEVICE_TYPE_INFINIBAND: return 150; case NM_DEVICE_TYPE_ADSL: @@ -1293,7 +1595,7 @@ nm_device_get_physical_port_id (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->physical_port_id; } -/***********************************************************/ +/*****************************************************************************/ static gboolean nm_device_uses_generated_assumed_connection (NMDevice *self) @@ -1337,38 +1639,6 @@ find_slave_info (NMDevice *self, NMDevice *slave) return NULL; } -static void -apply_mtu_from_config (NMDevice *self) -{ - const char *method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - NMSettingIPConfig *s_ip4; - NMSettingWired *s_wired; - guint32 mtu; - - /* Devices having an IPv4 configuration will set MTU during the commit - * stage, so it is an error to call this function if the IPv4 method is not - * 'disabled'. - */ - s_ip4 = (NMSettingIPConfig *) - nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP4_CONFIG); - if (s_ip4) - method = nm_setting_ip_config_get_method (s_ip4); - g_return_if_fail (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)); - - s_wired = (NMSettingWired *) - nm_device_get_applied_setting (self, NM_TYPE_SETTING_WIRED); - - if (s_wired) { - mtu = nm_setting_wired_get_mtu (s_wired); - if (mtu) { - _LOGD (LOGD_DEVICE | LOGD_IP, - "setting MTU of device without IP4 config to %u", - mtu); - nm_device_set_mtu (self, mtu); - } - } -} - /** * nm_device_master_enslave_slave: * @self: the master device @@ -1429,7 +1699,7 @@ nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *c /* Since slave devices don't have their own IP configuration, * set the MTU here. */ - apply_mtu_from_config (slave); + _commit_mtu (slave, NM_DEVICE_GET_PRIVATE (slave)->ip4_config); return success; } @@ -1585,7 +1855,7 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) return; } } - if (priv->rdisc) { + if (priv->ndisc) { /* FIXME: todo */ } if (priv->dnsmasq_manager) { @@ -1770,6 +2040,75 @@ device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink) } } +static void +ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gint32 now; + GArray *addresses, *dns_servers, *dns_domains; + guint len, i; + + if (nm_ndisc_get_node_type (ndisc) != NM_NDISC_NODE_TYPE_ROUTER) + return; + + now = nm_utils_get_monotonic_timestamp_s (); + + len = nm_ip6_config_get_num_addresses (priv->ip6_config); + addresses = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscAddress), len); + for (i = 0; i < len; i++) { + const NMPlatformIP6Address *addr = nm_ip6_config_get_address (priv->ip6_config, i); + NMNDiscAddress *ndisc_addr; + + if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) + continue; + + if ( addr->n_ifa_flags & IFA_F_TENTATIVE + || addr->n_ifa_flags & IFA_F_DADFAILED) + continue; + + if (addr->plen != 64) + continue; + + g_array_set_size (addresses, addresses->len+1); + ndisc_addr = &g_array_index (addresses, NMNDiscAddress, addresses->len-1); + ndisc_addr->address = addr->address; + ndisc_addr->timestamp = addr->timestamp; + ndisc_addr->lifetime = addr->lifetime; + ndisc_addr->preferred = addr->preferred; + } + + len = nm_ip6_config_get_num_nameservers (priv->ip6_config); + dns_servers = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscDNSServer), len); + g_array_set_size (dns_servers, len); + for (i = 0; i < len; i++) { + const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (priv->ip6_config, i); + NMNDiscDNSServer *ndisc_nameserver; + + ndisc_nameserver = &g_array_index (dns_servers, NMNDiscDNSServer, i); + ndisc_nameserver->address = *nameserver; + ndisc_nameserver->timestamp = now; + ndisc_nameserver->lifetime = NM_NDISC_ROUTER_LIFETIME; + } + + len = nm_ip6_config_get_num_searches (priv->ip6_config); + dns_domains = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscDNSDomain), len); + g_array_set_size (dns_domains, len); + for (i = 0; i < len; i++) { + const char *search = nm_ip6_config_get_search (priv->ip6_config, i); + NMNDiscDNSDomain *ndisc_search; + + ndisc_search = &g_array_index (dns_domains, NMNDiscDNSDomain, i); + ndisc_search->domain = (char *) search; + ndisc_search->timestamp = now; + ndisc_search->lifetime = NM_NDISC_ROUTER_LIFETIME; + } + + nm_ndisc_set_config (ndisc, addresses, dns_servers, dns_domains); + g_array_unref (addresses); + g_array_unref (dns_servers); + g_array_unref (dns_domains); +} + static gboolean device_link_changed (NMDevice *self) { @@ -1808,7 +2147,6 @@ device_link_changed (NMDevice *self) _notify (self, PROP_DRIVER); } - /* Update MTU if it has changed. */ if (priv->mtu != info.mtu) { priv->mtu = info.mtu; _notify (self, PROP_MTU); @@ -1855,15 +2193,17 @@ device_link_changed (NMDevice *self) nm_device_emit_recheck_auto_activate (self); } - if (priv->rdisc && info.inet6_token.id) { - if (nm_rdisc_set_iid (priv->rdisc, info.inet6_token)) { + if (priv->ndisc && info.inet6_token.id) { + if (nm_ndisc_set_iid (priv->ndisc, info.inet6_token)) _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); - nm_rdisc_start (priv->rdisc); - } } - if (klass->link_changed) - klass->link_changed (self, &info); + /* Update carrier from link event if applicable. */ + if ( nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT) + && !nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) + nm_device_set_carrier (self, pllink->connected); + + klass->link_changed (self, &info); /* Update DHCP, etc, if needed */ if (ip_ifname_changed) @@ -1953,28 +2293,21 @@ device_ip_link_changed (NMDevice *self) _stats_update_counters_from_pllink (self, pllink); - if (pllink->name[0] && g_strcmp0 (priv->ip_iface, pllink->name)) { - _LOGI (LOGD_DEVICE, "interface index %d renamed ip_iface (%d) from '%s' to '%s'", - priv->ifindex, nm_device_get_ip_ifindex (self), - priv->ip_iface, pllink->name); - g_free (priv->ip_iface); - priv->ip_iface = g_strdup (pllink->name); - - _notify (self, PROP_IP_IFACE); + if (_ip_iface_update (self, pllink->name)) nm_device_update_dynamic_ip_setup (self); - } return G_SOURCE_REMOVE; } static void link_changed_cb (NMPlatform *platform, - NMPObjectType obj_type, + int obj_type_i, int ifindex, NMPlatformLink *info, - NMPlatformSignalChangeType change_type, + int change_type_i, NMDevice *self) { + const NMPlatformSignalChangeType change_type = change_type_i; NMDevicePrivate *priv; if (change_type != NM_PLATFORM_SIGNAL_CHANGED) @@ -1996,12 +2329,9 @@ link_changed_cb (NMPlatform *platform, } static void -link_changed (NMDevice *self, NMPlatformLink *info) +link_changed (NMDevice *self, const NMPlatformLink *pllink) { - /* Update carrier from link event if applicable. */ - if ( nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT) - && !nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) - nm_device_set_carrier (self, info->connected); + /* stub implementation of virtual function to allow subclasses to chain up. */ } static gboolean @@ -2161,8 +2491,10 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink) _notify (self, PROP_IFACE); } - priv->ifindex = plink->ifindex; - _notify (self, PROP_IFINDEX); + if (priv->ifindex != plink->ifindex) { + priv->ifindex = plink->ifindex; + _notify (self, PROP_IFINDEX); + } priv->up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP); if (plink->driver && g_strcmp0 (plink->driver, priv->driver) != 0) { @@ -2196,11 +2528,12 @@ check_carrier (NMDevice *self) } static void -realize_start_notify (NMDevice *self, const NMPlatformLink *plink) +realize_start_notify (NMDevice *self, + const NMPlatformLink *pllink) { - /* Stub implementation for realize_start_notify(). It does nothing, - * but allows derived classes to uniformly invoke the parent - * implementation. */ + /* the default implementation of realize_start_notify() just calls + * link_changed() -- which by default does nothing. */ + NM_DEVICE_GET_CLASS (self)->link_changed (self, pllink); } /** @@ -2223,6 +2556,7 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) NMDeviceCapabilities capabilities = 0; NMConfig *config; guint real_rate; + guint32 mtu; g_return_if_fail (NM_IS_DEVICE (self)); @@ -2243,6 +2577,15 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) /* Balanced by a thaw in nm_device_realize_finish() */ g_object_freeze_notify (G_OBJECT (self)); + priv->mtu_initialized = FALSE; + priv->mtu_initial = 0; + priv->ip6_mtu_initial = 0; + priv->ip6_mtu = 0; + if (priv->mtu) { + priv->mtu = 0; + _notify (self, PROP_MTU); + } + if (plink) { g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL)); update_device_from_platform_link (self, plink); @@ -2258,8 +2601,11 @@ realize_start_setup (NMDevice *self, const NMPlatformLink *plink) if (nm_platform_link_is_software (NM_PLATFORM_GET, priv->ifindex)) capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; - priv->mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ifindex); - _notify (self, PROP_MTU); + mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ifindex); + if (priv->mtu != mtu) { + priv->mtu = mtu; + _notify (self, PROP_MTU); + } nm_platform_link_get_driver_info (NM_PLATFORM_GET, priv->ifindex, @@ -2460,15 +2806,21 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) NM_DEVICE_GET_CLASS (self)->unrealize_notify (self); + _parent_set_ifindex (self, 0, FALSE); + if (priv->ifindex > 0) { priv->ifindex = 0; _notify (self, PROP_IFINDEX); } priv->ip_ifindex = 0; - if (priv->ip_iface) { - g_clear_pointer (&priv->ip_iface, g_free); + if (nm_clear_g_free (&priv->ip_iface)) _notify (self, PROP_IP_IFACE); + + if (priv->mtu != 0) { + priv->mtu = 0; + _notify (self, PROP_MTU); } + if (priv->driver_version) { g_clear_pointer (&priv->driver_version, g_free); _notify (self, PROP_DRIVER_VERSION); @@ -2536,27 +2888,6 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) } /** - * nm_device_notify_new_device_added(): - * @self: the #NMDevice - * @device: the newly added device - * - * Called by the manager to notify the device that a new device has - * been found and added. - */ -void -nm_device_notify_new_device_added (NMDevice *self, NMDevice *device) -{ - NMDeviceClass *klass; - - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_DEVICE (device)); - - klass = NM_DEVICE_GET_CLASS (self); - if (klass->notify_new_device_added) - klass->notify_new_device_added (self, device); -} - -/** * nm_device_notify_component_added(): * @self: the #NMDevice * @component: the component being added by a plugin @@ -2896,8 +3227,8 @@ nm_device_slave_notify_enslave (NMDevice *self, gboolean success) } if (activating) { - priv->ip4_state = IP_DONE; - priv->ip6_state = IP_DONE; + _set_ip_state (self, AF_INET, IP_DONE); + _set_ip_state (self, AF_INET6, IP_DONE); if (success) nm_device_queue_state (self, NM_DEVICE_STATE_SECONDARIES, NM_DEVICE_STATE_REASON_NONE); else @@ -3161,6 +3492,8 @@ can_auto_connect (NMDevice *self, { NMSettingConnection *s_con; + nm_assert (!specific_object || !*specific_object); + s_con = nm_connection_get_setting_connection (connection); if (!nm_setting_connection_get_autoconnect (s_con)) return FALSE; @@ -3585,9 +3918,9 @@ recheck_available (gpointer user_data) if (new_state > NM_DEVICE_STATE_UNKNOWN) { _LOGD (LOGD_DEVICE, "is %savailable, %s %s", - now_available ? "" : "not ", - new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" : "will transition to", - state_to_string (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state)); + now_available ? "" : "not ", + new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" : "will transition to", + state_to_string (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state)); priv->recheck_available.available_reason = NM_DEVICE_STATE_REASON_NONE; priv->recheck_available.unavailable_reason = NM_DEVICE_STATE_REASON_NONE; @@ -3877,7 +4210,8 @@ activate_stage1_device_prepare (NMDevice *self) NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); - priv->ip4_state = priv->ip6_state = IP_NONE; + _set_ip_state (self, AF_INET, IP_NONE); + _set_ip_state (self, AF_INET6, IP_NONE); /* Notify the new ActiveConnection along with the state change */ _notify (self, PROP_ACTIVE_CONNECTION); @@ -3977,7 +4311,7 @@ activate_stage2_device_config (NMDevice *self) nm_device_queue_recheck_assume (info->slave); } - if (lldp_rx_enabled (self)) { + if (lldp_rx_enabled (self) && priv->ifindex > 0) { gs_free_error GError *error = NULL; gconstpointer addr; size_t addr_length; @@ -4057,39 +4391,81 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self) } /* - * check_ip_failed + * check_ip_state * - * Progress the device to appropriate state if both IPv4 and IPv6 failed + * Transition the device from IP_CONFIG to the next state according to the + * outcome of IPv4 and IPv6 configuration. @may_fail indicates that we are + * called just after the initial configuration and thus IPv4/IPv6 are allowed to + * fail if the ipvx.may-fail properties say so, because the IP methods couldn't + * even be started. */ static void -check_ip_failed (NMDevice *self, gboolean may_fail) +check_ip_state (NMDevice *self, gboolean may_fail) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean ip4_disabled = FALSE, ip6_ignore = FALSE; + NMSettingIPConfig *s_ip4, *s_ip6; NMDeviceState state; - if ( priv->ip4_state != IP_FAIL - || priv->ip6_state != IP_FAIL) + if (nm_device_get_state (self) != NM_DEVICE_STATE_IP_CONFIG) return; - if (nm_device_uses_assumed_connection (self)) { - /* We have assumed configuration, but couldn't - * redo it. No problem, move to check state. */ - priv->ip4_state = priv->ip6_state = IP_DONE; - state = NM_DEVICE_STATE_IP_CHECK; - } else if ( may_fail - && get_ip_config_may_fail (self, AF_INET) - && get_ip_config_may_fail (self, AF_INET6)) { - /* Couldn't start either IPv6 and IPv4 autoconfiguration, - * but both are allowed to fail. */ - state = NM_DEVICE_STATE_SECONDARIES; - } else { - /* Autoconfiguration attempted without success. */ - state = NM_DEVICE_STATE_FAILED; + s_ip4 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP4_CONFIG); + if (s_ip4 && nm_streq0 (nm_setting_ip_config_get_method (s_ip4), + NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + ip4_disabled = TRUE; + + s_ip6 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6 && nm_streq0 (nm_setting_ip_config_get_method (s_ip6), + NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) + ip6_ignore = TRUE; + + if ( priv->ip4_state == IP_DONE + && priv->ip6_state == IP_DONE) { + /* Both method completed (or disabled), proceed with activation */ + nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); + return; } - nm_device_state_changed (self, - state, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + if ( (priv->ip4_state == IP_FAIL || (ip4_disabled && priv->ip4_state == IP_DONE)) + && (priv->ip6_state == IP_FAIL || (ip6_ignore && priv->ip6_state == IP_DONE))) { + /* Either both methods failed, or only one failed and the other is + * disabled */ + if (nm_device_uses_assumed_connection (self)) { + /* We have assumed configuration, but couldn't redo it. No problem, + * move to check state. */ + _set_ip_state (self, AF_INET, IP_DONE); + _set_ip_state (self, AF_INET6, IP_DONE); + state = NM_DEVICE_STATE_IP_CHECK; + } else if ( may_fail + && get_ip_config_may_fail (self, AF_INET) + && get_ip_config_may_fail (self, AF_INET6)) { + /* Couldn't start either IPv6 and IPv4 autoconfiguration, + * but both are allowed to fail. */ + state = NM_DEVICE_STATE_SECONDARIES; + } else { + /* Autoconfiguration attempted without success. */ + state = NM_DEVICE_STATE_FAILED; + } + + nm_device_state_changed (self, + state, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return; + } + + /* If a method is still pending but required, wait */ + if (priv->ip4_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET)) + return; + if (priv->ip6_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET6)) + return; + + /* If at least a method has completed, proceed with activation */ + if ( (priv->ip4_state == IP_DONE && !ip4_disabled) + || (priv->ip6_state == IP_DONE && !ip6_ignore)) { + nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); + return; + } } void @@ -4099,42 +4475,18 @@ nm_device_ip_method_failed (NMDevice *self, int family, NMDeviceStateReason reas g_return_if_fail (NM_IS_DEVICE (self)); g_return_if_fail (family == AF_INET || family == AF_INET6); + priv = NM_DEVICE_GET_PRIVATE (self); - if (family == AF_INET) - priv->ip4_state = IP_FAIL; - else - priv->ip6_state = IP_FAIL; + _set_ip_state (self, family, IP_FAIL); if (get_ip_config_may_fail (self, family)) - check_ip_failed (self, FALSE); + check_ip_state (self, FALSE); else nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); } -/* - * check_ip_done - * - * Progress the device to ip connectivity check state if IPv4 or IPv6 succeeded - */ -static void -check_ip_done (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if (nm_device_get_state (self) != NM_DEVICE_STATE_IP_CONFIG) - return; - - if (priv->ip4_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET)) - return; - - if (priv->ip6_state != IP_DONE && !get_ip_config_may_fail (self, AF_INET6)) - return; - - nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); -} - -/*********************************************/ +/*****************************************************************************/ /* IPv4 DAD stuff */ static guint @@ -4318,7 +4670,7 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb) } } -/*********************************************/ +/*****************************************************************************/ /* IPv4LL stuff */ static void @@ -4509,7 +4861,7 @@ fail: return NM_ACT_STAGE_RETURN_FAILURE; } -/*********************************************/ +/*****************************************************************************/ static gboolean _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route) @@ -4555,7 +4907,7 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat return success; } -/*********************************************/ +/*****************************************************************************/ static void ensure_con_ip4_config (NMDevice *self) @@ -4609,7 +4961,7 @@ ensure_con_ip6_config (NMDevice *self) } } -/*********************************************/ +/*****************************************************************************/ /* DHCPv4 stuff */ static void @@ -4813,7 +5165,6 @@ END_ADD_DEFAULT_ROUTE: priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4); } - /* Allow setting MTU etc */ if (commit) { if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); @@ -4959,6 +5310,8 @@ dhcp4_state_changed (NMDhcpClient *client, break; } + nm_device_set_proxy_config (self, options); + nm_dhcp4_config_set_options (priv->dhcp4.config, options); _notify (self, PROP_DHCP4_CONFIG); priv->dhcp4.num_tries_left = DHCP_NUM_TRIES_MAX; @@ -5105,7 +5458,7 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release) return (ret != NM_ACT_STAGE_RETURN_FAILURE); } -/*********************************************/ +/*****************************************************************************/ static GHashTable *shared_ips = NULL; @@ -5175,7 +5528,7 @@ shared4_new_config (NMDevice *self, NMConnection *connection, NMDeviceStateReaso return config; } -/*********************************************/ +/*****************************************************************************/ static gboolean connection_ip4_method_requires_carrier (NMConnection *connection, @@ -5201,6 +5554,7 @@ connection_ip6_method_requires_carrier (NMConnection *connection, static const char *ip6_carrier_methods[] = { NM_SETTING_IP6_CONFIG_METHOD_AUTO, NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_SHARED, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, NULL }; @@ -5296,7 +5650,7 @@ act_stage3_ip4_config_start (NMDevice *self, && !priv->carrier) { _LOGI (LOGD_IP4 | LOGD_DEVICE, "IPv4 config waiting until carrier is on"); - return NM_ACT_STAGE_RETURN_WAIT; + return NM_ACT_STAGE_RETURN_IP_WAIT; } if (priv->is_master && ip4_requires_slaves (connection)) { @@ -5310,7 +5664,7 @@ act_stage3_ip4_config_start (NMDevice *self, if (ready_slaves == FALSE) { _LOGI (LOGD_DEVICE | LOGD_IP4, "IPv4 config waiting until slaves are ready"); - return NM_ACT_STAGE_RETURN_WAIT; + return NM_ACT_STAGE_RETURN_IP_WAIT; } } @@ -5335,23 +5689,25 @@ act_stage3_ip4_config_start (NMDevice *self, ipv4_dad_start (self, configs, ipv4_manual_method_apply); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { - *out_config = shared4_new_config (self, connection, reason); - if (*out_config) { - priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self)); - ret = NM_ACT_STAGE_RETURN_SUCCESS; + if (out_config) { + *out_config = shared4_new_config (self, connection, reason); + if (*out_config) { + priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self)); + ret = NM_ACT_STAGE_RETURN_SUCCESS; + } else + ret = NM_ACT_STAGE_RETURN_FAILURE; } else - ret = NM_ACT_STAGE_RETURN_FAILURE; + g_return_val_if_reached (NM_ACT_STAGE_RETURN_FAILURE); } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) { - apply_mtu_from_config (self); - /* Nothing else to do... */ - ret = NM_ACT_STAGE_RETURN_STOP; + _commit_mtu (self, priv->ip4_config); + ret = NM_ACT_STAGE_RETURN_SUCCESS; } else _LOGW (LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method); return ret; } -/*********************************************/ +/*****************************************************************************/ /* DHCPv6 stuff */ static void @@ -5359,13 +5715,14 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - priv->dhcp6.mode = NM_RDISC_DHCP_LEVEL_NONE; + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; g_clear_object (&priv->dhcp6.ip6_config); g_clear_pointer (&priv->dhcp6.event_id, g_free); nm_clear_g_source (&priv->dhcp6.restart_id); if (priv->dhcp6.client) { nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.state_sigid); + nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.prefix_sigid); if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) @@ -5433,8 +5790,8 @@ ip6_config_merge_and_apply (NMDevice *self, /* If no config was passed in, create a new one */ composite = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); nm_ip6_config_set_privacy (composite, - priv->rdisc ? - priv->rdisc_use_tempaddr : + priv->ndisc ? + priv->ndisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); init_ip6_config_dns_priority (self, composite); @@ -5576,9 +5933,6 @@ END_ADD_DEFAULT_ROUTE: nm_device_get_ip_ifindex (self), iid); } - - if (NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit) - NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit (self, composite); } routes_full_sync = commit @@ -5685,7 +6039,7 @@ dhcp6_fail (NMDevice *self, gboolean timeout) dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_MANAGED) { + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { /* Don't fail if there are static addresses configured on * the device, instead retry after some time. */ @@ -5731,7 +6085,7 @@ dhcp6_timeout (NMDevice *self, NMDhcpClient *client) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_MANAGED) + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) dhcp6_fail (self, TRUE); else { /* not a hard failure; just live with the RA info */ @@ -5808,7 +6162,7 @@ dhcp6_state_changed (NMDhcpClient *client, * may exit right after getting a response from the server. That's * normal. In that case we just ignore the exit. */ - if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_OTHERCONF) + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) break; /* Otherwise, fall through */ case NM_DHCP_STATE_FAIL: @@ -5819,6 +6173,19 @@ dhcp6_state_changed (NMDhcpClient *client, } } +static void +dhcp6_prefix_delegated (NMDhcpClient *client, + NMPlatformIP6Address *prefix, + gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + + /* Just re-emit. The device just contributes the prefix to the + * pool in NMPolicy, which decides about subnet allocation + * on the shared devices. */ + g_signal_emit (self, signals[IP6_PREFIX_DELEGATED], 0, prefix); +} + static gboolean dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) { @@ -5855,8 +6222,9 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) nm_setting_ip_config_get_dhcp_hostname (s_ip6), priv->dhcp_timeout, priv->dhcp_anycast_address, - (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, - nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6))); + (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, + nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)), + priv->dhcp6.needed_prefixes); if (tmp) g_byte_array_free (tmp, TRUE); @@ -5865,6 +6233,10 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (dhcp6_state_changed), self); + priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp6.client, + NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, + G_CALLBACK (dhcp6_prefix_delegated), + self); } return !!priv->dhcp6.client; @@ -5902,7 +6274,7 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason) } /* success; already have the LL address; kick off DHCP */ - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS || ret == NM_ACT_STAGE_RETURN_FINISH); + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); } if (!dhcp6_start_with_link_ready (self, connection)) { @@ -5929,7 +6301,96 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release) return dhcp6_start (self, FALSE, NULL); } -/******************************************/ +/*****************************************************************************/ + +/* + * Called on the requesting interface when a subnet can't be obtained + * from known prefixes for a newly active shared connection. + */ +void +nm_device_request_ip6_prefixes (NMDevice *self, int needed_prefixes) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + priv->dhcp6.needed_prefixes = needed_prefixes; + + if (priv->dhcp6.client) { + _LOGD (LOGD_IP6, "ipv6-pd: asking DHCPv6 for %d prefixes", needed_prefixes); + nm_device_dhcp6_renew (self, FALSE); + } else { + _LOGI (LOGD_IP6, "ipv6-pd: device doesn't use DHCPv6, can't request prefixes"); + } +} + +gboolean +nm_device_needs_ip6_subnet (NMDevice *self) +{ + return NM_DEVICE_GET_PRIVATE (self)->needs_ip6_subnet; +} + +/* + * Called on the ipv6.method=shared interface when a new subnet is allocated + * or the prefix from which it is allocated is renewed. + */ +void +nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMPlatformIP6Address address = *subnet; + + if (!priv->ac_ip6_config) + priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); + + /* Assign a ::1 address in the subnet for us. */ + address.address.s6_addr32[3] |= htonl (1); + nm_ip6_config_add_address (priv->ac_ip6_config, &address); + + _LOGD (LOGD_IP6, "ipv6-pd: using %s address (preferred for %u seconds)", + nm_utils_inet6_ntop (&address.address, NULL), + subnet->preferred); + + /* This also updates the ndisc if there are actual changes. */ + if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + _LOGW (LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing"); +} + +/* + * Called whenever the policy picks a default IPv6 device. + * The ipv6.method=shared devices just reuse its DNS configuration. + */ +void +nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMIP6Config *from_config = NULL; + int i; + + if (priv->ac_ip6_config) { + nm_ip6_config_reset_nameservers (priv->ac_ip6_config); + nm_ip6_config_reset_searches (priv->ac_ip6_config); + } else + priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); + + if (from_device) + from_config = nm_device_get_ip6_config (from_device); + if (!from_config) + return; + + for (i = 0; i < nm_ip6_config_get_num_nameservers (from_config); i++) { + nm_ip6_config_add_nameserver (priv->ac_ip6_config, + nm_ip6_config_get_nameserver (from_config, i)); + } + + for (i = 0; i < nm_ip6_config_get_num_searches (from_config); i++) { + nm_ip6_config_add_search (priv->ac_ip6_config, + nm_ip6_config_get_search (from_config, i)); + } + + if (!ip6_config_merge_and_apply (self, TRUE, NULL)) + _LOGW (LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing"); +} + +/*****************************************************************************/ static void linklocal6_cleanup (NMDevice *self) @@ -5975,7 +6436,8 @@ linklocal6_complete (NMDevice *self) _LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses successful, continue with method %s", method); - if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { + if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 + || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { if (!addrconf6_start_with_link_ready (self)) { /* Time out IPv6 instead of failing the entire activation */ nm_device_activate_schedule_ip6_config_timeout (self); @@ -6030,7 +6492,7 @@ check_and_add_ipv6ll_addr (NMDevice *self) NMUtilsStableType stable_type; const char *stable_id; - stable_id = _get_stable_id (connection, &stable_type); + stable_id = _get_stable_id (self, connection, &stable_type); if ( !stable_id || !nm_utils_ipv6_addr_set_stable_privacy (stable_type, &lladdr, @@ -6089,7 +6551,7 @@ linklocal6_start (NMDevice *self) if ( priv->ip6_config && nm_ip6_config_get_address_first_nontentative (priv->ip6_config, TRUE)) - return NM_ACT_STAGE_RETURN_FINISH; + return NM_ACT_STAGE_RETURN_SUCCESS; connection = nm_device_get_applied_connection (self); g_assert (connection); @@ -6109,64 +6571,198 @@ linklocal6_start (NMDevice *self) return NM_ACT_STAGE_RETURN_POSTPONE; } -/******************************************/ +/*****************************************************************************/ -static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu); +gint64 +nm_device_get_configured_mtu_from_connection_default (NMDevice *self, + const char *property_name) +{ + gs_free char *str = NULL; -static void -nm_device_set_mtu (NMDevice *self, guint32 mtu) + str = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, property_name, self); + return _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1); +} + +guint32 +nm_device_get_configured_mtu_for_wired (NMDevice *self, gboolean *out_is_user_config) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - int ifindex = nm_device_get_ip_ifindex (self); + NMConnection *connection; + NMSettingWired *setting; + gint64 mtu_default; + guint32 mtu; + + nm_assert (NM_IS_DEVICE (self)); + nm_assert (out_is_user_config); - if (mtu) - priv->mtu = mtu; + connection = nm_device_get_applied_connection (self); + if (!connection) + g_return_val_if_reached (0); - /* Ensure the IPv6 MTU is still alright. */ - if (priv->ip6_mtu) - nm_device_ipv6_set_mtu (self, priv->ip6_mtu); + setting = nm_connection_get_setting_wired (connection); - if (priv->mtu && priv->mtu != nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex)) - nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, priv->mtu); + if (setting) { + mtu = nm_setting_wired_get_mtu (setting); + if (mtu) { + *out_is_user_config = TRUE; + return mtu; + } + } + + mtu_default = nm_device_get_configured_mtu_from_connection_default (self, "ethernet.mtu"); + if (mtu_default >= 0) { + *out_is_user_config = TRUE; + return (guint32) mtu_default; + } + + *out_is_user_config = FALSE; + return NM_DEVICE_DEFAULT_MTU_WIRED; } +/*****************************************************************************/ + static void -nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu) +_commit_mtu (NMDevice *self, const NMIP4Config *config) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint32 plat_mtu = nm_device_ipv6_sysctl_get_int32 (self, "mtu", priv->mtu); - char val[16]; + guint32 ip6_mtu, ip6_mtu_orig; + guint32 mtu_desired, mtu_desired_orig; + guint32 mtu_plat; + struct { + gboolean initialized; + guint32 value; + } ip6_mtu_sysctl; + int ifindex; + char sbuf[64], sbuf1[64], sbuf2[64]; - priv->ip6_mtu = mtu ?: plat_mtu; + ifindex = nm_device_get_ip_ifindex (self); + if (ifindex <= 0) + return; - if (priv->ip6_mtu && priv->mtu && priv->mtu < priv->ip6_mtu) { - _LOGI (LOGD_DEVICE | LOGD_IP6, "Lowering IPv6 MTU (%d) to match device MTU (%d)", - priv->ip6_mtu, priv->mtu); - priv->ip6_mtu = priv->mtu; + if (nm_device_uses_assumed_connection (self)) { + /* for assumed connections we don't tamper with the MTU. This is + * a bug and supposed to be fixed by the unmanaged/assumed rework. */ + return; } - if (priv->ip6_mtu && priv->ip6_mtu < 1280) { - _LOGI (LOGD_DEVICE | LOGD_IP6, "IPv6 MTU (%d) smaller than 1280, adjusting", - priv->ip6_mtu); - priv->ip6_mtu = 1280; + { + gboolean mtu_is_user_config = FALSE; + guint32 mtu = 0; + + /* preferably, get the MTU from explict user-configuration. + * Only if that fails, look at the current @config (which contains + * MTUs from DHCP/PPP) or maybe fallback to a device-specific MTU. */ + + if (NM_DEVICE_GET_CLASS (self)->get_configured_mtu) + mtu = NM_DEVICE_GET_CLASS (self)->get_configured_mtu (self, &mtu_is_user_config); + + if (mtu_is_user_config) + mtu_desired = mtu; + else { + if (config) + mtu_desired = nm_ip4_config_get_mtu (config); + else + mtu_desired = 0; + if (!mtu_desired && !priv->mtu_initialized) { + /* there is no MTU specified, and this is the first commit of the MTU. + * Reset a per-device MTU default, as returned from get_configured_mtu(). + * + * The device might choose not to return a default MTU via get_configured_mtu() + * to suppress this behavior. */ + mtu_desired = mtu; + } + } } - if (priv->ip6_mtu && priv->mtu && priv->mtu < priv->ip6_mtu) { - _LOGI (LOGD_DEVICE | LOGD_IP6, "Raising device MTU (%d) to match IPv6 MTU (%d)", - priv->mtu, priv->ip6_mtu); - nm_device_set_mtu (self, priv->ip6_mtu); + if (mtu_desired && mtu_desired < 1280) { + NMSettingIPConfig *s_ip6; + + s_ip6 = (NMSettingIPConfig *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6 && nm_streq0 (nm_setting_ip_config_get_method (s_ip6), + NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + /* the interface has IPv6 enabled. The MTU with IPv6 cannot be smaller + * then 1280. + * + * For slave-devices (that don't have @s_ip6 we) don't do this fixup because + * it's anyway an unsolved problem when the slave configures a conflicting + * MTU. */ + mtu_desired = 1280; + } } - if (priv->ip6_mtu != plat_mtu) { - g_snprintf (val, sizeof (val), "%d", mtu); - nm_device_ipv6_sysctl_set (self, "mtu", val); + ip6_mtu = priv->ip6_mtu; + if (!ip6_mtu && !priv->mtu_initialized) { + /* initially, if the IPv6 MTU is not specified, grow it as large as the + * link MTU @mtu_desired. Only exception is, if @mtu_desired is so small + * to disable IPv6. */ + if (mtu_desired >= 1280) + ip6_mtu = mtu_desired; } + + priv->mtu_initialized = TRUE; + + if (!ip6_mtu && !mtu_desired) + return; + + mtu_desired_orig = mtu_desired; + ip6_mtu_orig = ip6_mtu; + + mtu_plat = nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex); + + if (ip6_mtu) { + ip6_mtu = NM_MAX (1280, ip6_mtu); + + if (!mtu_desired) + mtu_desired = mtu_plat; + + if (mtu_desired) { + mtu_desired = NM_MAX (1280, mtu_desired); + + if (mtu_desired < ip6_mtu) + ip6_mtu = mtu_desired; + } + } + + _LOGT (LOGD_DEVICE, "mtu: device-mtu: %u%s, ipv6-mtu: %u%s, ifindex: %d", + (guint) mtu_desired, + mtu_desired == mtu_desired_orig ? "" : nm_sprintf_buf (sbuf1, " (was %u)", (guint) mtu_desired_orig), + (guint) ip6_mtu, + ip6_mtu == ip6_mtu_orig ? "" : nm_sprintf_buf (sbuf2, " (was %u)", (guint) ip6_mtu_orig), + ifindex); + + ip6_mtu_sysctl.initialized = FALSE; +#define _IP6_MTU_SYS() \ + ({ \ + if (!ip6_mtu_sysctl.initialized) { \ + ip6_mtu_sysctl.value = nm_device_ipv6_sysctl_get_uint32 (self, "mtu", 0); \ + ip6_mtu_sysctl.initialized = TRUE; \ + } \ + ip6_mtu_sysctl.value; \ + }) + if ( (mtu_desired && mtu_desired != mtu_plat) + || (ip6_mtu && ip6_mtu != _IP6_MTU_SYS ())) { + + if (!priv->mtu_initial && !priv->ip6_mtu_initial) { + /* before touching any of the MTU paramters, record the + * original setting to restore on deactivation. */ + priv->mtu_initial = mtu_plat; + priv->ip6_mtu_initial = _IP6_MTU_SYS (); + } + + if (mtu_desired && mtu_desired != mtu_plat) + nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, mtu_desired); + + if (ip6_mtu && ip6_mtu != _IP6_MTU_SYS ()) { + nm_device_ipv6_sysctl_set (self, "mtu", + nm_sprintf_buf (sbuf, "%u", (unsigned) ip6_mtu)); + } + } +#undef _IP6_MTU_SYS } static void -rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_int, NMDevice *self) +ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, NMDevice *self) { - NMRDiscConfigMap changed = changed_int; + NMNDiscConfigMap changed = changed_int; NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int i; int system_support; @@ -6182,8 +6778,8 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in if (system_support) ifa_flags = IFA_F_NOPREFIXROUTE; - if ( priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR - || priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) + if ( priv->ndisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR + || priv->ndisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) { /* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */ ifa_flags |= IFA_F_MANAGETEMPADDR; @@ -6194,25 +6790,25 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in if (!priv->ac_ip6_config) priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); - if (changed & NM_RDISC_CONFIG_GATEWAYS) { - /* Use the first gateway as ordered in router discovery cache. */ + if (changed & NM_NDISC_CONFIG_GATEWAYS) { + /* Use the first gateway as ordered in neighbor discovery cache. */ if (rdata->gateways_n) nm_ip6_config_set_gateway (priv->ac_ip6_config, &rdata->gateways[0].address); else nm_ip6_config_set_gateway (priv->ac_ip6_config, NULL); } - if (changed & NM_RDISC_CONFIG_ADDRESSES) { - /* Rebuild address list from router discovery cache. */ + if (changed & NM_NDISC_CONFIG_ADDRESSES) { + /* Rebuild address list from neighbor discovery cache. */ nm_ip6_config_reset_addresses (priv->ac_ip6_config); - /* rdisc->addresses contains at most max_addresses entries. + /* ndisc->addresses contains at most max_addresses entries. * This is different from what the kernel does, which * also counts static and temporary addresses when checking * max_addresses. **/ for (i = 0; i < rdata->addresses_n; i++) { - const NMRDiscAddress *discovered_address = &rdata->addresses[i]; + const NMNDiscAddress *discovered_address = &rdata->addresses[i]; NMPlatformIP6Address address; memset (&address, 0, sizeof (address)); @@ -6223,24 +6819,24 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in address.preferred = discovered_address->preferred; if (address.preferred > address.lifetime) address.preferred = address.lifetime; - address.addr_source = NM_IP_CONFIG_SOURCE_RDISC; + address.addr_source = NM_IP_CONFIG_SOURCE_NDISC; address.n_ifa_flags = ifa_flags; nm_ip6_config_add_address (priv->ac_ip6_config, &address); } } - if (changed & NM_RDISC_CONFIG_ROUTES) { - /* Rebuild route list from router discovery cache. */ + if (changed & NM_NDISC_CONFIG_ROUTES) { + /* Rebuild route list from neighbor discovery cache. */ nm_ip6_config_reset_routes (priv->ac_ip6_config); for (i = 0; i < rdata->routes_n; i++) { - const NMRDiscRoute *discovered_route = &rdata->routes[i]; + const NMNDiscRoute *discovered_route = &rdata->routes[i]; const NMPlatformIP6Route route = { .network = discovered_route->network, .plen = discovered_route->plen, .gateway = discovered_route->gateway, - .rt_source = NM_IP_CONFIG_SOURCE_RDISC, + .rt_source = NM_IP_CONFIG_SOURCE_NDISC, .metric = nm_device_get_ip6_route_metric (self), }; @@ -6248,34 +6844,34 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in } } - if (changed & NM_RDISC_CONFIG_DNS_SERVERS) { - /* Rebuild DNS server list from router discovery cache. */ + if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { + /* Rebuild DNS server list from neighbor discovery cache. */ nm_ip6_config_reset_nameservers (priv->ac_ip6_config); for (i = 0; i < rdata->dns_servers_n; i++) nm_ip6_config_add_nameserver (priv->ac_ip6_config, &rdata->dns_servers[i].address); } - if (changed & NM_RDISC_CONFIG_DNS_DOMAINS) { - /* Rebuild domain list from router discovery cache. */ - nm_ip6_config_reset_domains (priv->ac_ip6_config); + if (changed & NM_NDISC_CONFIG_DNS_DOMAINS) { + /* Rebuild domain list from neighbor discovery cache. */ + nm_ip6_config_reset_searches (priv->ac_ip6_config); for (i = 0; i < rdata->dns_domains_n; i++) - nm_ip6_config_add_domain (priv->ac_ip6_config, rdata->dns_domains[i].domain); + nm_ip6_config_add_search (priv->ac_ip6_config, rdata->dns_domains[i].domain); } - if (changed & NM_RDISC_CONFIG_DHCP_LEVEL) { + if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, TRUE); priv->dhcp6.mode = rdata->dhcp_level; - if (priv->dhcp6.mode != NM_RDISC_DHCP_LEVEL_NONE) { + if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE) { NMDeviceStateReason reason; _LOGD (LOGD_DEVICE | LOGD_DHCP6, "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" " as requested by IPv6 router..."); if (!dhcp6_start (self, FALSE, &reason)) { - if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_MANAGED) { + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); return; } @@ -6283,17 +6879,21 @@ rdisc_config_changed (NMRDisc *rdisc, const NMRDiscData *rdata, guint changed_in } } - if (changed & NM_RDISC_CONFIG_HOP_LIMIT) + if (changed & NM_NDISC_CONFIG_HOP_LIMIT) nm_platform_sysctl_set_ip6_hop_limit_safe (NM_PLATFORM_GET, nm_device_get_ip_iface (self), rdata->hop_limit); - if (changed & NM_RDISC_CONFIG_MTU) - priv->ip6_mtu = rdata->mtu; + if (changed & NM_NDISC_CONFIG_MTU) { + if (priv->ip6_mtu != rdata->mtu) { + _LOGD (LOGD_DEVICE, "mtu: set IPv6 MTU to %u", (guint) rdata->mtu); + priv->ip6_mtu = rdata->mtu; + } + } nm_device_activate_schedule_ip6_config_result (self); } static void -rdisc_ra_timeout (NMRDisc *rdisc, NMDevice *self) +ndisc_ra_timeout (NMNDisc *ndisc, NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -6323,13 +6923,13 @@ addrconf6_start_with_link_ready (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMUtilsIPv6IfaceId iid; - g_assert (priv->rdisc); + g_assert (priv->ndisc); if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) { _LOGD (LOGD_IP6, "addrconf6: using the device EUI-64 identifier"); - nm_rdisc_set_iid (priv->rdisc, iid); + nm_ndisc_set_iid (priv->ndisc, iid); } else { - /* Don't abort the addrconf at this point -- if rdisc needs the iid + /* Don't abort the addrconf at this point -- if ndisc needs the iid * it will notice this itself. */ _LOGI (LOGD_IP6, "addrconf6: no interface identifier; IPv6 adddress creation may fail"); } @@ -6338,24 +6938,55 @@ addrconf6_start_with_link_ready (NMDevice *self) if (!ip6_config_merge_and_apply (self, TRUE, NULL)) _LOGW (LOGD_IP6, "failed to apply manual IPv6 configuration"); - nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); - nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); - nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); - nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); + /* XXX: These sysctls would probably be better set by the lndp ndisc itself. */ + switch (nm_ndisc_get_node_type (priv->ndisc)) { + case NM_NDISC_NODE_TYPE_HOST: + /* Accepting prefixes from discovered routers. */ + nm_device_ipv6_sysctl_set (self, "accept_ra", "1"); + nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); + nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); + nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); + break; + case NM_NDISC_NODE_TYPE_ROUTER: + /* We're the router. */ + nm_device_ipv6_sysctl_set (self, "forwarding", "1"); + nm_device_activate_schedule_ip6_config_result (self); + priv->needs_ip6_subnet = TRUE; + g_signal_emit (self, signals[IP6_SUBNET_NEEDED], 0); + break; + default: + g_assert_not_reached (); + } - priv->rdisc_changed_id = g_signal_connect (priv->rdisc, - NM_RDISC_CONFIG_CHANGED, - G_CALLBACK (rdisc_config_changed), + priv->ndisc_changed_id = g_signal_connect (priv->ndisc, + NM_NDISC_CONFIG_RECEIVED, + G_CALLBACK (ndisc_config_changed), self); - priv->rdisc_timeout_id = g_signal_connect (priv->rdisc, - NM_RDISC_RA_TIMEOUT, - G_CALLBACK (rdisc_ra_timeout), + priv->ndisc_timeout_id = g_signal_connect (priv->ndisc, + NM_NDISC_RA_TIMEOUT, + G_CALLBACK (ndisc_ra_timeout), self); - nm_rdisc_start (priv->rdisc); + ndisc_set_router_config (priv->ndisc, self); + nm_ndisc_start (priv->ndisc); return TRUE; } +static NMNDiscNodeType +ndisc_node_type (NMDevice *self) +{ + NMConnection *connection; + + connection = nm_device_get_applied_connection (self); + g_assert (connection); + + if (strcmp (nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG), + NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) + return NM_NDISC_NODE_TYPE_ROUTER; + else + return NM_NDISC_NODE_TYPE_HOST; +} + static gboolean addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) { @@ -6379,23 +7010,24 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection)); g_assert (s_ip6); - stable_id = _get_stable_id (connection, &stable_type); + stable_id = _get_stable_id (self, connection, &stable_type); if (stable_id) { - priv->rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, + priv->ndisc = nm_lndp_ndisc_new (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), nm_device_get_ip_iface (self), stable_type, stable_id, nm_setting_ip6_config_get_addr_gen_mode (s_ip6), + ndisc_node_type (self), &error); } - if (!priv->rdisc) { - _LOGE (LOGD_IP6, "addrconf6: failed to start router discovery: %s", error->message); + if (!priv->ndisc) { + _LOGE (LOGD_IP6, "addrconf6: failed to start neighbor discovery: %s", error->message); g_error_free (error); return FALSE; } - priv->rdisc_use_tempaddr = use_tempaddr; + priv->ndisc_use_tempaddr = use_tempaddr; if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) && !nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET)) { @@ -6413,8 +7045,8 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) return TRUE; } - /* success; already have the LL address; kick off router discovery */ - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS || ret == NM_ACT_STAGE_RETURN_FINISH); + /* success; already have the LL address; kick off neighbor discovery */ + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); return addrconf6_start_with_link_ready (self); } @@ -6423,22 +7055,23 @@ addrconf6_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - nm_clear_g_signal_handler (priv->rdisc, &priv->rdisc_changed_id); - nm_clear_g_signal_handler (priv->rdisc, &priv->rdisc_timeout_id); + nm_clear_g_signal_handler (priv->ndisc, &priv->ndisc_changed_id); + nm_clear_g_signal_handler (priv->ndisc, &priv->ndisc_timeout_id); nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE); g_clear_object (&priv->ac_ip6_config); - g_clear_object (&priv->rdisc); + g_clear_object (&priv->ndisc); } -/******************************************/ +/*****************************************************************************/ static const char *ip6_properties_to_save[] = { "accept_ra", "accept_ra_defrtr", "accept_ra_pinfo", "accept_ra_rtr_pref", + "forwarding", "disable_ipv6", "hop_limit", "use_tempaddr", @@ -6455,7 +7088,7 @@ save_ip6_properties (NMDevice *self) g_hash_table_remove_all (priv->ip6_saved_properties); for (i = 0; i < G_N_ELEMENTS (ip6_properties_to_save); i++) { - value = nm_platform_sysctl_get (NM_PLATFORM_GET, nm_utils_ip6_property_path (ifname, ip6_properties_to_save[i])); + value = nm_platform_sysctl_get (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (ifname, ip6_properties_to_save[i]))); if (value) { g_hash_table_insert (priv->ip6_saved_properties, (char *) ip6_properties_to_save[i], @@ -6516,7 +7149,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) if (enable) { /* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */ value = nm_platform_sysctl_get (NM_PLATFORM_GET, - nm_utils_ip6_property_path (nm_device_get_ip_iface (self), "disable_ipv6")); + NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip6_property_path (nm_device_get_ip_iface (self), "disable_ipv6"))); if (g_strcmp0 (value, "0") == 0) nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); g_free (value); @@ -6528,7 +7161,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) } } -/************************************************************************/ +/*****************************************************************************/ static NMSettingIP6ConfigPrivacy _ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) @@ -6582,11 +7215,11 @@ _ip6_privacy_get (NMDevice *self) * Instead of reading static config files in /etc, just read the current sysctl value. * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves * the "default" entry untouched. */ - ip6_privacy = nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, "/proc/sys/net/ipv6/conf/default/use_tempaddr", NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + ip6_privacy = nm_platform_sysctl_get_int32 (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/default/use_tempaddr"), NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); return _ip6_privacy_clamp (ip6_privacy); } -/****************************************************************/ +/*****************************************************************************/ static gboolean ip6_requires_slaves (NMConnection *connection) @@ -6596,12 +7229,10 @@ ip6_requires_slaves (NMConnection *connection) method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) - * to complete addressing. SLAAC and DHCP obviously need a peer to - * provide a prefix, while Link-Local must perform DAD on the local link. + * to complete addressing. SLAAC and DHCP need a peer to provide a prefix. */ return strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 - || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0 - || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0; + || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0; } static NMActStageReturn @@ -6614,7 +7245,7 @@ act_stage3_ip6_config_start (NMDevice *self, NMConnection *connection; const char *method; NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - const char *ip6_privacy_str = "0\n"; + const char *ip6_privacy_str = "0"; GSList *slaves; gboolean ready_slaves; @@ -6628,7 +7259,7 @@ act_stage3_ip6_config_start (NMDevice *self, && !priv->carrier) { _LOGI (LOGD_IP6 | LOGD_DEVICE, "IPv6 config waiting until carrier is on"); - return NM_ACT_STAGE_RETURN_WAIT; + return NM_ACT_STAGE_RETURN_IP_WAIT; } if (priv->is_master && ip6_requires_slaves (connection)) { @@ -6642,11 +7273,11 @@ act_stage3_ip6_config_start (NMDevice *self, if (ready_slaves == FALSE) { _LOGI (LOGD_DEVICE | LOGD_IP6, "IPv6 config waiting until slaves are ready"); - return NM_ACT_STAGE_RETURN_WAIT; + return NM_ACT_STAGE_RETURN_IP_WAIT; } } - priv->dhcp6.mode = NM_RDISC_DHCP_LEVEL_NONE; + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; priv->dhcp6.num_tries_left = DHCP_NUM_TRIES_MAX; method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); @@ -6664,15 +7295,14 @@ act_stage3_ip6_config_start (NMDevice *self, nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); restore_ip6_properties (self); } - return NM_ACT_STAGE_RETURN_STOP; + return NM_ACT_STAGE_RETURN_IP_DONE; } /* Ensure the MTU makes sense. If it was below 1280 the kernel would not * expose any ipv6 sysctls or allow presence of any addresses on the interface, * including LL, which * would make it impossible to autoconfigure MTU to a * correct value. */ - if (!nm_device_uses_assumed_connection (self)) - nm_device_ipv6_set_mtu (self, priv->ip6_mtu); + _commit_mtu (self, priv->ip4_config); /* Any method past this point requires an IPv6LL address. Use NM-controlled * IPv6LL if this is not an assumed connection, since assumed connections @@ -6686,45 +7316,43 @@ act_stage3_ip6_config_start (NMDevice *self, ip6_privacy = _ip6_privacy_get (self); - if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0) { + if ( strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 + || strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { if (!addrconf6_start (self, ip6_privacy)) { /* IPv6 might be disabled; allow IPv4 to proceed */ - ret = NM_ACT_STAGE_RETURN_STOP; + ret = NM_ACT_STAGE_RETURN_IP_FAIL; } else ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) { ret = linklocal6_start (self); } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { - priv->dhcp6.mode = NM_RDISC_DHCP_LEVEL_MANAGED; + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; if (!dhcp6_start (self, TRUE, reason)) { /* IPv6 might be disabled; allow IPv4 to proceed */ - ret = NM_ACT_STAGE_RETURN_STOP; + ret = NM_ACT_STAGE_RETURN_IP_FAIL; } else ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) == 0) { - /* New blank config */ - *out_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); - g_assert (*out_config); - ret = NM_ACT_STAGE_RETURN_SUCCESS; } else _LOGW (LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); - /* Other methods (shared) aren't implemented yet */ - - switch (ip6_privacy) { - case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: - case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - ip6_privacy_str = "0"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - ip6_privacy_str = "1"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - ip6_privacy_str = "2"; - break; + if ( ret != NM_ACT_STAGE_RETURN_FAILURE + && !nm_device_uses_assumed_connection (self)) { + switch (ip6_privacy) { + case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: + case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: + ip6_privacy_str = "0"; + break; + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: + ip6_privacy_str = "1"; + break; + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: + ip6_privacy_str = "2"; + break; + } + nm_device_ipv6_sysctl_set (self, "use_tempaddr", ip6_privacy_str); } - nm_device_ipv6_sysctl_set (self, "use_tempaddr", ip6_privacy_str); return ret; } @@ -6745,21 +7373,25 @@ nm_device_activate_stage3_ip4_start (NMDevice *self) g_assert (priv->ip4_state == IP_WAIT); - priv->ip4_state = IP_CONF; + _set_ip_state (self, AF_INET, IP_CONF); ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - g_assert (ip4_config); + if (!ip4_config) + ip4_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); nm_device_activate_schedule_ip4_config_result (self, ip4_config); g_object_unref (ip4_config); + } else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { + _set_ip_state (self, AF_INET, IP_DONE); + check_ip_state (self, FALSE); } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); return FALSE; - } else if (ret == NM_ACT_STAGE_RETURN_STOP) { - /* Early finish */ - priv->ip4_state = IP_FAIL; - } else if (ret == NM_ACT_STAGE_RETURN_WAIT) { + } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { + /* Activation not wanted */ + _set_ip_state (self, AF_INET, IP_FAIL); + } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { /* Wait for something to try IP config again */ - priv->ip4_state = IP_WAIT; + _set_ip_state (self, AF_INET, IP_WAIT); } else g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); @@ -6782,29 +7414,29 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) g_assert (priv->ip6_state == IP_WAIT); - priv->ip6_state = IP_CONF; + _set_ip_state (self, AF_INET6, IP_CONF); ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - g_assert (ip6_config); + if (!ip6_config) + ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); /* Here we get a static IPv6 config, like for Shared where it's * autogenerated or from modems where it comes from ModemManager. */ g_warn_if_fail (priv->ac_ip6_config == NULL); priv->ac_ip6_config = ip6_config; nm_device_activate_schedule_ip6_config_result (self); + } else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { + _set_ip_state (self, AF_INET6, IP_DONE); + check_ip_state (self, FALSE); } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); return FALSE; - } else if (ret == NM_ACT_STAGE_RETURN_STOP) { + } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { /* Activation not wanted */ - priv->ip6_state = IP_FAIL; - } else if (ret == NM_ACT_STAGE_RETURN_FINISH) { - /* Early finish, nothing more to do */ - priv->ip6_state = IP_DONE; - check_ip_done (self); - } else if (ret == NM_ACT_STAGE_RETURN_WAIT) { + _set_ip_state (self, AF_INET6, IP_FAIL); + } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { /* Wait for something to try IP config again */ - priv->ip6_state = IP_WAIT; + _set_ip_state (self, AF_INET6, IP_WAIT); } else g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); @@ -6824,7 +7456,8 @@ activate_stage3_ip_config_start (NMDevice *self) NMActiveConnection *master; NMDevice *master_device; - priv->ip4_state = priv->ip6_state = IP_WAIT; + _set_ip_state (self, AF_INET, IP_WAIT); + _set_ip_state (self, AF_INET6, IP_WAIT); nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); @@ -6862,7 +7495,10 @@ activate_stage3_ip_config_start (NMDevice *self) && !nm_device_activate_stage3_ip6_start (self)) return; - check_ip_failed (self, TRUE); + /* Proxy */ + nm_device_set_proxy_config (self, NULL); + + check_ip_state (self, TRUE); } static gboolean @@ -6909,12 +7545,16 @@ fw_change_zone_cb_ip_check (NMFirewallManager *firewall_manager, gpointer user_data) { NMDevice *self = user_data; + NMDevicePrivate *priv; if (!fw_change_zone_handle (self, call_id, error)) return; /* FIXME: fail the device on error? */ - nm_device_start_ip_check (self); + + priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE) + nm_device_start_ip_check (self); } /* @@ -6981,7 +7621,6 @@ act_stage4_ip4_config_timeout (NMDevice *self, NMDeviceStateReason *reason) static void activate_stage4_ip4_config_timeout (NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; @@ -6994,9 +7633,9 @@ activate_stage4_ip4_config_timeout (NMDevice *self) } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - priv->ip4_state = IP_FAIL; + _set_ip_state (self, AF_INET, IP_FAIL); - check_ip_failed (self, FALSE); + check_ip_state (self, FALSE); } /* @@ -7038,7 +7677,6 @@ act_stage4_ip6_config_timeout (NMDevice *self, NMDeviceStateReason *reason) static void activate_stage4_ip6_config_timeout (NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; @@ -7051,9 +7689,9 @@ activate_stage4_ip6_config_timeout (NMDevice *self) } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - priv->ip6_state = IP_FAIL; + _set_ip_state (self, AF_INET6, IP_FAIL); - check_ip_failed (self, FALSE); + check_ip_state (self, FALSE); } /* @@ -7084,16 +7722,16 @@ share_init (void) char **iter; int errsv; - if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv4/ip_forward", "1")) { + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), "1")) { errsv = errno; - nm_log_err (LOGD_SHARING, "share: error starting IP forwarding: (%d) %s", + nm_log_err (LOGD_SHARING, "share: error enabling IPv4 forwarding: (%d) %s", errsv, strerror (errsv)); return FALSE; } - if (!nm_platform_sysctl_set (NM_PLATFORM_GET, "/proc/sys/net/ipv4/ip_dynaddr", "1")) { + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), "1")) { errsv = errno; - nm_log_err (LOGD_SHARING, "share: error starting IP forwarding: (%d) %s", + nm_log_err (LOGD_SHARING, "share: error enabling dynamic addresses: (%d) %s", errsv, strerror (errsv)); } @@ -7265,7 +7903,7 @@ activate_stage5_ip4_config_commit (NMDevice *self) if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { if (!start_sharing (self, priv->ip4_config)) { _LOGW (LOGD_SHARING, "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed."); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); + nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); return; } } @@ -7291,8 +7929,8 @@ activate_stage5_ip4_config_commit (NMDevice *self) nm_device_remove_pending_action (self, PENDING_ACTION_DHCP4, FALSE); /* Enter the IP_CHECK state if this is the first method to complete */ - priv->ip4_state = IP_DONE; - check_ip_done (self); + _set_ip_state (self, AF_INET, IP_DONE); + check_ip_state (self, FALSE); } void @@ -7387,9 +8025,11 @@ activate_stage5_ip6_config_commit (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; + const char *method; NMConnection *connection; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; int ip_ifindex; + int errsv; req = nm_device_get_act_request (self); g_assert (req); @@ -7405,7 +8045,7 @@ activate_stage5_ip6_config_commit (NMDevice *self) } if (ip6_config_merge_and_apply (self, TRUE, &reason)) { - if ( priv->dhcp6.mode != NM_RDISC_DHCP_LEVEL_NONE + if ( priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE && priv->ip6_state == IP_CONF) { if (priv->dhcp6.ip6_config) { /* If IPv6 wasn't the first IP to complete, and DHCP was used, @@ -7426,6 +8066,17 @@ activate_stage5_ip6_config_commit (NMDevice *self) nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE); nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE); + /* Start IPv6 forwarding if we need it */ + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); + + if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED) == 0) { + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/all/forwarding"), "1")) { + errsv = errno; + _LOGE (LOGD_SHARING, "share: error enabling IPv6 forwarding: (%d) %s", errsv, strerror (errsv)); + nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); + } + } + /* Check if we have to wait for DAD */ if (priv->ip6_state == IP_CONF && !priv->dad6_ip6_config) { priv->dad6_ip6_config = dad6_get_pending_addresses (self); @@ -7433,8 +8084,8 @@ activate_stage5_ip6_config_commit (NMDevice *self) _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: waiting termination"); } else { /* No tentative addresses, proceed right away */ - priv->ip6_state = IP_DONE; - check_ip_done (self); + _set_ip_state (self, AF_INET6, IP_DONE); + check_ip_state (self, FALSE); } } } else { @@ -7454,7 +8105,7 @@ nm_device_activate_schedule_ip6_config_result (NMDevice *self) * clearly now have configuration. */ if (priv->ip6_state == IP_FAIL) - priv->ip6_state = IP_CONF; + _set_ip_state (self, AF_INET6, IP_CONF); activation_source_schedule (self, activate_stage5_ip6_config_commit, AF_INET6); } @@ -7623,7 +8274,7 @@ _cleanup_ip4_pre (NMDevice *self, CleanupType cleanup_type) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - priv->ip4_state = IP_NONE; + _set_ip_state (self, AF_INET, IP_NONE); if (nm_clear_g_source (&priv->queued_ip4_config_id)) _LOGD (LOGD_DEVICE, "clearing queued IP4 config change"); @@ -7640,7 +8291,7 @@ _cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - priv->ip6_state = IP_NONE; + _set_ip_state (self, AF_INET6, IP_NONE); if (nm_clear_g_source (&priv->queued_ip6_config_id)) _LOGD (LOGD_DEVICE, "clearing queued IP6 config change"); @@ -7746,7 +8397,7 @@ nm_device_reactivate_ip4_config (NMDevice *self, if (!nm_streq0 (method_old, method_new)) { _cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE); - priv->ip4_state = IP_WAIT; + _set_ip_state (self, AF_INET, IP_WAIT); if (!nm_device_activate_stage3_ip4_start (self)) _LOGW (LOGD_IP4, "Failed to apply IPv4 configuration"); } else { @@ -7784,7 +8435,7 @@ nm_device_reactivate_ip6_config (NMDevice *self, if (!nm_streq0 (method_old, method_new)) { _cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE); - priv->ip6_state = IP_WAIT; + _set_ip_state (self, AF_INET6, IP_WAIT); if (!nm_device_activate_stage3_ip6_start (self)) _LOGW (LOGD_IP6, "Failed to apply IPv6 configuration"); } else { @@ -7854,6 +8505,7 @@ reapply_connection (NMDevice *self, error, NM_SETTING_CONNECTION_ID, NM_SETTING_CONNECTION_UUID, + NM_SETTING_CONNECTION_STABLE_ID, NM_SETTING_CONNECTION_AUTOCONNECT, NM_SETTING_CONNECTION_ZONE, NM_SETTING_CONNECTION_METERED)) @@ -7880,9 +8532,37 @@ reapply_connection (NMDevice *self, diffs ? "" : " (unmodified)"); if (diffs) { + NMConnection *connection_clean = connection; + gs_free NMConnection *connection_clean_free = NULL; + + { + NMSettingConnection *s_con_a, *s_con_n; + + /* we allow re-applying a connection with differing ID, UUID, STABLE_ID and AUTOCONNECT. + * This is for convenience but these values are not actually changable. So, check + * if they changed, and if the did revert to the original values. */ + s_con_a = nm_connection_get_setting_connection (applied); + s_con_n = nm_connection_get_setting_connection (connection); + + if ( !nm_streq (nm_setting_connection_get_id (s_con_a), nm_setting_connection_get_id (s_con_n)) + || !nm_streq (nm_setting_connection_get_uuid (s_con_a), nm_setting_connection_get_uuid (s_con_n)) + || nm_setting_connection_get_autoconnect (s_con_a) != nm_setting_connection_get_autoconnect (s_con_n) + || !nm_streq0 (nm_setting_connection_get_stable_id (s_con_a), nm_setting_connection_get_stable_id (s_con_n))) { + connection_clean_free = nm_simple_connection_new_clone (connection); + connection_clean = connection_clean_free; + s_con_n = nm_connection_get_setting_connection (connection); + g_object_set (s_con_n, + NM_SETTING_CONNECTION_ID, nm_setting_connection_get_id (s_con_a), + NM_SETTING_CONNECTION_UUID, nm_setting_connection_get_uuid (s_con_a), + NM_SETTING_CONNECTION_AUTOCONNECT, nm_setting_connection_get_autoconnect (s_con_a), + NM_SETTING_CONNECTION_STABLE_ID, nm_setting_connection_get_stable_id (s_con_a), + NULL); + } + } + con_old = applied_clone = nm_simple_connection_new_clone (applied); con_new = applied; - nm_connection_replace_settings_from_connection (applied, connection); + nm_connection_replace_settings_from_connection (applied, connection_clean); nm_connection_clear_secrets (applied); } else con_old = con_new = applied; @@ -8402,8 +9082,50 @@ nm_device_is_activating (NMDevice *self) return priv->act_handle4.id ? TRUE : FALSE; } -/* IP Configuration stuff */ +NMProxyConfig * +nm_device_get_proxy_config (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + + return NM_DEVICE_GET_PRIVATE (self)->proxy_config; +} +static void +nm_device_set_proxy_config (NMDevice *self, GHashTable *options) +{ + NMDevicePrivate *priv; + NMConnection *connection; + NMSettingProxy *s_proxy = NULL; + char *pac = NULL; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + + g_clear_object (&priv->proxy_config); + priv->proxy_config = nm_proxy_config_new (); + + if (options) { + pac = g_hash_table_lookup (options, "wpad"); + if (pac) { + nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); + nm_proxy_config_set_pac_url (priv->proxy_config, pac); + _LOGD (LOGD_PROXY, "proxy: PAC url \"%s\"", pac); + } else { + nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); + _LOGD (LOGD_PROXY, "proxy: PAC url not obtained from DHCP server"); + } + } + + connection = nm_device_get_applied_connection (self); + if (connection) + s_proxy = nm_connection_get_setting_proxy (connection); + + if (s_proxy) + nm_proxy_config_merge_setting (priv->proxy_config, s_proxy); +} + +/* IP Configuration stuff */ NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *self) { @@ -8456,8 +9178,7 @@ nm_device_set_ip4_config (NMDevice *self, if (commit && new_config) { gboolean assumed = nm_device_uses_assumed_connection (self); - nm_device_set_mtu (self, nm_ip4_config_get_mtu (new_config)); - + _commit_mtu (self, new_config); /* For assumed devices we must not touch the kernel-routes, such as the device-route. * FIXME: this is wrong in case where "assumed" means "take-over-seamlessly". In this * case, we should manage the device route, for example on new DHCP lease. */ @@ -8625,7 +9346,7 @@ nm_device_set_ip6_config (NMDevice *self, /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { - nm_device_ipv6_set_mtu (self, priv->ip6_mtu); + _commit_mtu (self, priv->ip4_config); success = nm_ip6_config_commit (new_config, ip_ifindex, routes_full_sync); @@ -8683,6 +9404,9 @@ nm_device_set_ip6_config (NMDevice *self, } nm_device_queue_recheck_assume (self); + + if (priv->ndisc) + ndisc_set_router_config (priv->ndisc, self); } if (reason) @@ -8737,7 +9461,7 @@ nm_device_get_ip6_config (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->ip6_config; } -/****************************************************************/ +/*****************************************************************************/ static void dispatcher_cleanup (NMDevice *self) @@ -8767,7 +9491,7 @@ dispatcher_complete_proceed_state (guint call_id, gpointer user_data) priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; } -/****************************************************************/ +/*****************************************************************************/ static void ip_check_pre_up (NMDevice *self) @@ -8953,10 +9677,10 @@ nm_device_start_ip_check (NMDevice *self) * first IP method completes. Any subsequently completing IP method doesn't * get checked. */ - g_assert (!priv->gw_ping.watch); - g_assert (!priv->gw_ping.timeout); - g_assert (!priv->gw_ping.pid); - g_assert (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE); + g_return_if_fail (!priv->gw_ping.watch); + g_return_if_fail (!priv->gw_ping.timeout); + g_return_if_fail (!priv->gw_ping.pid); + g_return_if_fail (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE); connection = nm_device_get_applied_connection (self); g_assert (connection); @@ -8995,7 +9719,7 @@ nm_device_start_ip_check (NMDevice *self) ip_check_pre_up (self); } -/****************************************************************/ +/*****************************************************************************/ static gboolean carrier_wait_timeout (gpointer user_data) @@ -9013,19 +9737,11 @@ carrier_wait_timeout (gpointer user_data) static gboolean nm_device_is_up (NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - if (NM_DEVICE_GET_CLASS (self)->is_up) - return NM_DEVICE_GET_CLASS (self)->is_up (self); - - return TRUE; -} + int ifindex; -static gboolean -is_up (NMDevice *self) -{ - int ifindex = nm_device_get_ip_ifindex (self); + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + ifindex = nm_device_get_ip_ifindex (self); return ifindex > 0 ? nm_platform_link_is_up (NM_PLATFORM_GET, ifindex) : TRUE; } @@ -9035,13 +9751,23 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gboolean device_is_up = FALSE; NMDeviceCapabilities capabilities; + int ifindex; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - _LOGD (LOGD_PLATFORM, "bringing up device"); + NM_SET_OUT (no_firmware, FALSE); + + if (!nm_device_get_enabled (self)) { + _LOGD (LOGD_PLATFORM, "bringing up device ignored due to disabled"); + return FALSE; + } - if (NM_DEVICE_GET_CLASS (self)->bring_up) { - if (!NM_DEVICE_GET_CLASS (self)->bring_up (self, no_firmware)) + ifindex = nm_device_get_ip_ifindex (self); + _LOGD (LOGD_PLATFORM, "bringing up device %d", ifindex); + if (ifindex <= 0) { + /* assume success. */ + } else { + if (!nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, no_firmware)) return FALSE; } @@ -9051,7 +9777,6 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) device_is_up = nm_device_is_up (self); if (block && !device_is_up) { - int ifindex = nm_device_get_ip_ifindex (self); gint64 wait_until = nm_utils_get_monotonic_timestamp_us () + 10000 /* microseconds */; do { @@ -9106,40 +9831,26 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) return TRUE; } -static gboolean -bring_up (NMDevice *self, gboolean *no_firmware) -{ - int ifindex = nm_device_get_ip_ifindex (self); - gboolean result; - - if (ifindex <= 0) { - if (no_firmware) - *no_firmware = FALSE; - return TRUE; - } - - result = nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, no_firmware); - - return result; -} - void nm_device_take_down (NMDevice *self, gboolean block) { + int ifindex; gboolean device_is_up; g_return_if_fail (NM_IS_DEVICE (self)); - _LOGD (LOGD_PLATFORM, "taking down device"); - - if (NM_DEVICE_GET_CLASS (self)->take_down) { - if (!NM_DEVICE_GET_CLASS (self)->take_down (self)) - return; + ifindex = nm_device_get_ip_ifindex (self); + _LOGD (LOGD_PLATFORM, "taking down device %d", ifindex); + if (ifindex <= 0) { + /* devices without ifindex are always up. */ + return; } + if (!nm_platform_link_set_down (NM_PLATFORM_GET, ifindex)) + return; + device_is_up = nm_device_is_up (self); if (block && device_is_up) { - int ifindex = nm_device_get_ip_ifindex (self); gint64 wait_until = nm_utils_get_monotonic_timestamp_us () + 10000 /* microseconds */; do { @@ -9158,19 +9869,6 @@ nm_device_take_down (NMDevice *self, gboolean block) } } -static gboolean -take_down (NMDevice *self) -{ - int ifindex = nm_device_get_ip_ifindex (self); - - if (ifindex > 0) - return nm_platform_link_set_down (NM_PLATFORM_GET, ifindex); - - /* devices without ifindex are always up. */ - _LOGD (LOGD_PLATFORM, "cannot take down device without ifindex"); - return FALSE; -} - void nm_device_set_firmware_missing (NMDevice *self, gboolean new_missing) { @@ -9191,26 +9889,6 @@ nm_device_get_firmware_missing (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->firmware_missing; } -void -nm_device_set_nm_plugin_missing (NMDevice *self, gboolean new_missing) -{ - NMDevicePrivate *priv; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->nm_plugin_missing != new_missing) { - priv->nm_plugin_missing = new_missing; - _notify (self, PROP_NM_PLUGIN_MISSING); - } -} - -gboolean -nm_device_get_nm_plugin_missing (NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE (self)->nm_plugin_missing; -} - static NMIP4Config * find_ip4_lease_config (NMDevice *self, NMConnection *connection, @@ -9563,8 +10241,8 @@ queued_ip6_config_change (gpointer user_data) if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) need_ipv6ll = TRUE; - else if (priv->rdisc) - nm_rdisc_dad_failed (priv->rdisc, &addr->address); + else if (priv->ndisc) + nm_ndisc_dad_failed (priv->ndisc, &addr->address); } /* If no IPv6 link-local address exists but other addresses do then we @@ -9590,8 +10268,8 @@ queued_ip6_config_change (gpointer user_data) priv->dad6_ip6_config)) { _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); g_clear_object (&priv->dad6_ip6_config); - priv->ip6_state = IP_DONE; - check_ip_done (self); + _set_ip_state (self, AF_INET6, IP_DONE); + check_ip_state (self, FALSE); } } @@ -9602,12 +10280,14 @@ queued_ip6_config_change (gpointer user_data) static void device_ipx_changed (NMPlatform *platform, - NMPObjectType obj_type, + int obj_type_i, int ifindex, gpointer platform_object, - NMPlatformSignalChangeType change_type, + int change_type_i, NMDevice *self) { + const NMPObjectType obj_type = obj_type_i; + const NMPlatformSignalChangeType change_type = change_type_i; NMDevicePrivate *priv; NMPlatformIP6Address *addr; @@ -10645,7 +11325,7 @@ nm_device_has_pending_action (NMDevice *self) return !!priv->pending_actions; } -/***********************************************************/ +/*****************************************************************************/ static void _cancel_activation (NMDevice *self) @@ -10717,6 +11397,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) */ nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE, NULL); nm_device_set_ip6_config (self, NULL, TRUE, TRUE, NULL); + g_clear_object (&priv->proxy_config); g_clear_object (&priv->con_ip4_config); g_clear_object (&priv->dev_ip4_config); g_clear_object (&priv->ext_ip4_config); @@ -10735,6 +11416,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) g_slist_free_full (priv->vpn6_configs, g_object_unref); priv->vpn6_configs = NULL; + priv->needs_ip6_subnet = FALSE; + clear_act_request (self); /* Clear legacy IPv4 address property */ @@ -10827,6 +11510,27 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self); } + priv->mtu_initialized = FALSE; + if (priv->mtu_initial || priv->ip6_mtu_initial) { + ifindex = nm_device_get_ip_ifindex (self); + + if ( ifindex > 0 + && cleanup_type == CLEANUP_TYPE_DECONFIGURE) { + _LOGT (LOGD_DEVICE, "mtu: reset device-mtu: %u, ipv6-mtu: %u, ifindex: %d", + (guint) priv->mtu_initial, (guint) priv->ip6_mtu_initial, ifindex); + if (priv->mtu_initial) + nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, priv->mtu_initial); + if (priv->ip6_mtu_initial) { + char sbuf[64]; + + nm_device_ipv6_sysctl_set (self, "mtu", + nm_sprintf_buf (sbuf, "%u", (unsigned) priv->ip6_mtu_initial)); + } + } + priv->mtu_initial = 0; + priv->ip6_mtu_initial = 0; + } + _cleanup_generic_post (self, cleanup_type); } @@ -10886,7 +11590,7 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, g_strdup ("--uuid")); g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection))); - stable_id = _get_stable_id (connection, &stable_type); + stable_id = _get_stable_id (self, connection, &stable_type); if (stable_id && stable_type != NM_UTILS_STABLE_TYPE_UUID) { g_ptr_array_add (argv, g_strdup ("--stable-id")); g_ptr_array_add (argv, g_strdup_printf ("%d %s", (int) stable_type, stable_id)); @@ -10903,6 +11607,12 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, logging_backend); } + g_ptr_array_add (argv, g_strdup ("--log-level")); + g_ptr_array_add (argv, g_strdup (nm_logging_level_to_string ())); + + g_ptr_array_add (argv, g_strdup ("--log-domains")); + g_ptr_array_add (argv, g_strdup (nm_logging_domains_to_string ())); + dhcp4_address = find_dhcp4_address (self); method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); @@ -10966,7 +11676,7 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, g_strdup ("--slaac-required")); g_ptr_array_add (argv, g_strdup ("--slaac-tempaddr")); - g_ptr_array_add (argv, g_strdup_printf ("%d", priv->rdisc_use_tempaddr)); + g_ptr_array_add (argv, g_strdup_printf ("%d", priv->ndisc_use_tempaddr)); if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) { g_ptr_array_add (argv, g_strdup ("--iid")); @@ -11007,7 +11717,7 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_unref (argv); } -/***********************************************************/ +/*****************************************************************************/ static gboolean ip_config_valid (NMDeviceState state) @@ -11036,6 +11746,7 @@ ip6_managed_setup (NMDevice *self) nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0"); + nm_device_ipv6_sysctl_set (self, "forwarding", "0"); } static void @@ -11174,6 +11885,11 @@ _set_state_full (NMDevice *self, if (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED) nm_device_recheck_available_connections (self); + if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_DEACTIVATING) { + if (nm_clear_g_free (&priv->current_stable_id)) + _LOGT (LOGD_DEVICE, "stable-id: clear"); + } + /* Handle the new state here; but anything that could trigger * another state change should be done below. */ @@ -11307,6 +12023,9 @@ _set_state_full (NMDevice *self, deactivate_dispatcher_complete (0, self); } } + + /* Remove config from PacRunner */ + nm_pacrunner_manager_remove (priv->pacrunner_manager, nm_device_get_ip_iface (self)); break; case NM_DEVICE_STATE_DISCONNECTED: if ( priv->queued_act_request @@ -11330,6 +12049,14 @@ _set_state_full (NMDevice *self, nm_act_request_get_settings_connection (req), nm_act_request_get_applied_connection (req), self, NULL, NULL, NULL); + + if (priv->proxy_config) { + nm_pacrunner_manager_send (priv->pacrunner_manager, + nm_device_get_ip_iface (self), + priv->proxy_config, + priv->ip4_config, + priv->ip6_config); + } break; case NM_DEVICE_STATE_FAILED: /* Usually upon failure the activation chain is interrupted in @@ -11548,7 +12275,7 @@ nm_device_get_state (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->state; } -/***********************************************************/ +/*****************************************************************************/ /* NMConfigDevice interface related stuff */ const char * @@ -11715,6 +12442,28 @@ nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze) * (until we unrealize the device). */ priv->hw_addr_perm_fake = TRUE; + /* We also persist our choice of the fake address to the device state + * file to use the same address on restart of NetworkManager. + * First, try to reload the address from the state file. */ + { + gs_free NMConfigDeviceStateData *dev_state = NULL; + + dev_state = nm_config_device_state_load (nm_config_get (), ifindex); + if ( dev_state + && dev_state->perm_hw_addr_fake + && nm_utils_hwaddr_aton (dev_state->perm_hw_addr_fake, buf, priv->hw_addr_len) + && !nm_utils_hwaddr_matches (buf, priv->hw_addr_len, priv->hw_addr, -1)) { + _LOGD (LOGD_PLATFORM | LOGD_ETHER, "hw-addr: %s (use from statefile: %s, current: %s)", + success_read + ? "read HW addr length of permanent MAC address differs" + : "unable to read permanent MAC address", + dev_state->perm_hw_addr_fake, + priv->hw_addr); + priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len); + goto notify_and_out; + } + } + _LOGD (LOGD_PLATFORM | LOGD_ETHER, "hw-addr: %s (use current: %s)", success_read ? "read HW addr length of permanent MAC address differs" @@ -11748,8 +12497,8 @@ _get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gbool a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, is_wifi ? "wifi.cloned-mac-address" : "ethernet.cloned-mac-address", self); - /* default is permanent. */ - addr = NM_CLONED_MAC_PERMANENT; + + addr = NM_CLONED_MAC_PRESERVE; if (!a) { if (is_wifi) { @@ -11937,7 +12686,10 @@ handle_fail: } gboolean -nm_device_hw_addr_set (NMDevice *self, const char *addr, const char *detail) +nm_device_hw_addr_set (NMDevice *self, + const char *addr, + const char *detail, + gboolean set_permanent) { NMDevicePrivate *priv; @@ -11948,10 +12700,13 @@ nm_device_hw_addr_set (NMDevice *self, const char *addr, const char *detail) if (!addr) g_return_val_if_reached (FALSE); - /* this is called by NMDeviceVlan to take the MAC address from the parent - * and by NMDeviceWifi to set a random MAC address during scanning. - * In this case, it's like setting it to PERMANENT. */ - priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT; + if (set_permanent) { + /* The type is set to PERMANENT by NMDeviceVlan when taking the MAC + * address from the parent and by NMDeviceWifi when setting a random MAC + * address during scanning. + */ + priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT; + } return _hw_addr_set (self, addr, "set", detail); } @@ -12009,7 +12764,7 @@ nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean return TRUE; } - stable_id = _get_stable_id (connection, &stable_type); + stable_id = _get_stable_id (self, connection, &stable_type); if (stable_id) { hw_addr_generated = nm_utils_hw_addr_gen_stable_eth (stable_type, stable_id, nm_device_get_ip_iface (self), @@ -12153,7 +12908,7 @@ spec_match_list (NMDevice *self, const GSList *specs) return matched; } -/***********************************************************/ +/*****************************************************************************/ static const char * _activation_func_to_string (ActivationHandleFunc func) @@ -12173,7 +12928,7 @@ _activation_func_to_string (ActivationHandleFunc func) g_return_val_if_reached ("unknown"); } -/***********************************************************/ +/*****************************************************************************/ static void nm_device_init (NMDevice *self) @@ -12196,6 +12951,8 @@ nm_device_init (NMDevice *self) priv->available_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); + priv->pacrunner_manager = g_object_ref (nm_pacrunner_manager_get ()); + priv->default_route.v4_is_assumed = TRUE; priv->default_route.v6_is_assumed = TRUE; @@ -12297,6 +13054,8 @@ dispose (GObject *object) _LOGD (LOGD_DEVICE, "disposing"); + _parent_set_ifindex (self, 0, FALSE); + platform = NM_PLATFORM_GET; g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self); g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self); @@ -12310,6 +13069,8 @@ dispose (GObject *object) dispatcher_cleanup (self); + g_clear_object (&priv->pacrunner_manager); + _cleanup_generic_pre (self, CLEANUP_TYPE_KEEP); g_warn_if_fail (priv->slaves == NULL); @@ -12331,6 +13092,11 @@ dispose (GObject *object) link_disconnect_action_cancel (self); + if (priv->ifindex > 0) { + priv->ifindex = 0; + _notify (self, PROP_IFINDEX); + } + if (priv->settings) { g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_added, self); g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_updated, self); @@ -12387,6 +13153,7 @@ finalize (GObject *object) g_free (priv->type_desc); g_free (priv->type_description); g_free (priv->dhcp_anycast_address); + g_free (priv->current_stable_id); g_hash_table_unref (priv->ip6_saved_properties); g_hash_table_unref (priv->available_connections); @@ -12414,7 +13181,7 @@ set_property (GObject *object, guint prop_id, } break; case PROP_IFACE: - /* construct only */ + /* construct-only */ g_return_if_fail (!priv->iface); priv->iface = g_value_dup_string (value); break; @@ -12432,9 +13199,6 @@ set_property (GObject *object, guint prop_id, g_free (priv->firmware_version); priv->firmware_version = g_value_dup_string (value); break; - case PROP_MTU: - priv->mtu = g_value_get_uint (value); - break; case PROP_IP4_ADDRESS: priv->ip4_address = g_value_get_uint (value); break; @@ -12458,10 +13222,11 @@ set_property (GObject *object, guint prop_id, nm_device_set_autoconnect (self, g_value_get_boolean (value)); break; case PROP_FIRMWARE_MISSING: - /* construct only */ + /* construct-only */ priv->firmware_missing = g_value_get_boolean (value); break; case PROP_NM_PLUGIN_MISSING: + /* construct-only */ priv->nm_plugin_missing = g_value_get_boolean (value); break; case PROP_DEVICE_TYPE: @@ -12469,7 +13234,7 @@ set_property (GObject *object, guint prop_id, priv->type = g_value_get_uint (value); break; case PROP_LINK_TYPE: - /* construct only */ + /* construct-only */ g_return_if_fail (priv->link_type == NM_LINK_TYPE_NONE); priv->link_type = g_value_get_uint (value); break; @@ -12484,7 +13249,7 @@ set_property (GObject *object, guint prop_id, priv->is_master = g_value_get_boolean (value); break; case PROP_PERM_HW_ADDRESS: - /* construct only */ + /* construct-only */ priv->hw_addr_perm = g_value_dup_string (value); break; case PROP_REFRESH_RATE_MS: @@ -12608,6 +13373,9 @@ get_property (GObject *object, guint prop_id, case PROP_MASTER: g_value_set_object (value, nm_device_get_master (self)); break; + case PROP_PARENT: + nm_utils_g_value_set_object_path (value, priv->parent_device); + break; case PROP_HW_ADDRESS: g_value_set_string (value, priv->hw_addr); break; @@ -12680,9 +13448,8 @@ nm_device_class_init (NMDeviceClass *klass) g_type_class_add_private (object_class, sizeof (NMDevicePrivate)); - exported_object_class->export_path = NM_DBUS_PATH "/Devices/%u"; + exported_object_class->export_path = NM_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/Devices"); - /* Virtual methods */ object_class->dispose = dispose; object_class->finalize = finalize; object_class->set_property = set_property; @@ -12709,15 +13476,12 @@ nm_device_class_init (NMDeviceClass *klass) klass->can_unmanaged_external_down = can_unmanaged_external_down; klass->realize_start_notify = realize_start_notify; klass->unrealize_notify = unrealize_notify; - klass->is_up = is_up; - klass->bring_up = bring_up; - klass->take_down = take_down; klass->carrier_changed = carrier_changed; klass->get_ip_iface_identifier = get_ip_iface_identifier; klass->unmanaged_on_quit = unmanaged_on_quit; klass->deactivate_reset_hw_addr = deactivate_reset_hw_addr; + klass->parent_changed_notify = parent_changed_notify; - /* Properties */ obj_properties[PROP_UDI] = g_param_spec_string (NM_DEVICE_UDI, "", "", NULL, @@ -12871,6 +13635,11 @@ nm_device_class_init (NMDeviceClass *klass) NM_TYPE_DEVICE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PARENT] = + g_param_spec_string (NM_DEVICE_PARENT, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_HW_ADDRESS] = g_param_spec_string (NM_DEVICE_HW_ADDRESS, "", "", NULL, @@ -12935,7 +13704,6 @@ nm_device_class_init (NMDeviceClass *klass) g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - /* Signals */ signals[STATE_CHANGED] = g_signal_new (NM_DEVICE_STATE_CHANGED, G_OBJECT_CLASS_TYPE (object_class), @@ -12946,7 +13714,7 @@ nm_device_class_init (NMDeviceClass *klass) G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); signals[AUTOCONNECT_ALLOWED] = - g_signal_new ("autoconnect-allowed", + g_signal_new (NM_DEVICE_AUTOCONNECT_ALLOWED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, @@ -12975,6 +13743,20 @@ nm_device_class_init (NMDeviceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT); + signals[IP6_PREFIX_DELEGATED] = + g_signal_new (NM_DEVICE_IP6_PREFIX_DELEGATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[IP6_SUBNET_NEEDED] = + g_signal_new (NM_DEVICE_IP6_SUBNET_NEEDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); + signals[REMOVED] = g_signal_new (NM_DEVICE_REMOVED, G_OBJECT_CLASS_TYPE (object_class), |