diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index caf49b7748..b3810797d5 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -72,9 +72,6 @@ static void impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *con #include "nm-device-glue.h" -#define PENDING_IP4_CONFIG "pending-ip4-config" -#define PENDING_IP6_CONFIG "pending-ip6-config" - #define DBUS_G_TYPE_UINT_STRUCT (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID)) /* default to installed helper, but can be modified for testing */ @@ -228,8 +225,11 @@ typedef struct { GByteArray * dhcp_anycast_address; /* IP4 configuration info */ - NMIP4Config * ip4_config; /* Config from DHCP, PPP, or system config files */ + NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */ IpState ip4_state; + NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ + + /* DHCPv4 tracking */ NMDHCPClient * dhcp4_client; gulong dhcp4_state_sigid; gulong dhcp4_timeout_sigid; @@ -299,6 +299,10 @@ static gboolean nm_device_set_ip4_config (NMDevice *dev, NMIP4Config *config, gboolean commit, NMDeviceStateReason *reason); +static gboolean ip4_config_merge_and_apply (NMDevice *self, + NMIP4Config *config, + NMDeviceStateReason *out_reason); + static gboolean nm_device_set_ip6_config (NMDevice *dev, NMIP6Config *config, gboolean commit, @@ -2035,21 +2039,6 @@ aipd_get_ip4_config (NMDevice *self, struct in_addr lla) return config; } -static void -autoip_changed (NMDevice *self, - NMIP4Config *config, - NMSettingIP4Config *s_ip4) -{ - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - - nm_ip4_config_merge_setting (config, s_ip4); - if (!nm_device_set_ip4_config (self, config, TRUE, &reason)) { - nm_log_err (LOGD_AUTOIP4, "(%s): failed to update IP4 config in response to autoip event.", - nm_device_get_iface (self)); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); - } -} - #define IPV4LL_NETWORK (htonl (0xA9FE0000L)) #define IPV4LL_NETMASK (htonl (0xFFFF0000L)) @@ -2062,6 +2051,7 @@ nm_device_handle_autoip4_event (NMDevice *self, NMConnection *connection = NULL; NMSettingIP4Config *s_ip4 = NULL; const char *iface, *method = NULL; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; g_return_if_fail (event != NULL); @@ -2110,7 +2100,11 @@ nm_device_handle_autoip4_event (NMDevice *self, aipd_timeout_remove (self); nm_device_activate_schedule_ip4_config_result (self, config); } else if (priv->ip4_state == IP_DONE) { - autoip_changed (self, config, s_ip4); + if (!ip4_config_merge_and_apply (self, config, &reason)) { + nm_log_err (LOGD_AUTOIP4, "(%s): failed to update IP4 config for autoip change.", + nm_device_get_iface (self)); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + } } else g_assert_not_reached (); @@ -2275,34 +2269,61 @@ dhcp4_add_option_cb (gpointer key, gpointer value, gpointer user_data) (const char *) value); } -static void -dhcp4_lease_change (NMDevice *device, NMIP4Config *config) +static gboolean +ip4_config_merge_and_apply (NMDevice *self, + NMIP4Config *config, + NMDeviceStateReason *out_reason) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + gboolean success; + NMIP4Config *composite; - if (config == NULL) { - nm_log_warn (LOGD_DHCP4, "(%s): failed to get DHCPv4 config for rebind", - nm_device_get_ip_iface (device)); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - return; - } - - connection = nm_device_get_connection (device); + connection = nm_device_get_connection (self); g_assert (connection); - /* Merge with user overrides */ - nm_ip4_config_merge_setting (config, nm_connection_get_setting_ip4_config (connection)); - - if (!nm_device_set_ip4_config (device, config, TRUE, &reason)) { - nm_log_warn (LOGD_DHCP4, "(%s): failed to update IPv4 config in response to DHCP event.", - nm_device_get_ip_iface (device)); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); - return; + /* Merge all the configs into the composite config */ + if (config) { + g_clear_object (&priv->dev_ip4_config); + priv->dev_ip4_config = g_object_ref (config); } - /* Notify dispatcher scripts of new DHCP4 config */ - nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE, connection, device, NULL, NULL); + g_assert (priv->dev_ip4_config); + + composite = nm_ip4_config_new (); + nm_ip4_config_merge (composite, priv->dev_ip4_config); + + /* Merge user overrides into the composite config */ + nm_ip4_config_merge_setting (composite, nm_connection_get_setting_ip4_config (connection)); + + /* Allow setting MTU etc */ + if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) + NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); + + success = nm_device_set_ip4_config (self, composite, TRUE, out_reason); + g_object_unref (composite); + return success; +} + +static void +dhcp4_lease_change (NMDevice *self, NMIP4Config *config) +{ + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + + g_return_if_fail (config != NULL); + + if (!ip4_config_merge_and_apply (self, config, &reason)) { + nm_log_warn (LOGD_DHCP4, "(%s): failed to update IPv4 config for DHCP change.", + nm_device_get_ip_iface (self)); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + } else { + /* Notify dispatcher scripts of new DHCP4 config */ + nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE, + nm_device_get_connection (self), + self, + NULL, + NULL); + } } static void @@ -2341,21 +2362,27 @@ dhcp4_state_changed (NMDHCPClient *client, case DHC_REBOOT: /* have valid lease, but now obtained a different one */ case DHC_REBIND4: /* new, different lease */ config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE); + if (!config) { + nm_log_warn (LOGD_DHCP4, "(%s): failed to get IPv4 config in response to DHCP event.", + nm_device_get_ip_iface (device)); + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + break; + } + if (priv->ip4_state == IP_CONF) nm_device_activate_schedule_ip4_config_result (device, config); else if (priv->ip4_state == IP_DONE) dhcp4_lease_change (device, config); + g_object_unref (config); - if (config) { - /* Update the DHCP4 config object with new DHCP options */ - nm_dhcp4_config_reset (priv->dhcp4_config); - nm_dhcp_client_foreach_option (priv->dhcp4_client, - dhcp4_add_option_cb, - priv->dhcp4_config); - g_object_notify (G_OBJECT (device), NM_DEVICE_DHCP4_CONFIG); - - g_object_unref (config); - } + /* Update the DHCP4 config object with new DHCP options */ + nm_dhcp4_config_reset (priv->dhcp4_config); + nm_dhcp_client_foreach_option (priv->dhcp4_client, + dhcp4_add_option_cb, + priv->dhcp4_config); + g_object_notify (G_OBJECT (device), NM_DEVICE_DHCP4_CONFIG); break; case DHC_TIMEOUT: /* timed out contacting DHCP server */ dhcp4_fail (device, TRUE); @@ -3723,7 +3750,6 @@ nm_device_activate_ip4_config_commit (gpointer user_data) NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; - NMIP4Config *config = NULL; const char *iface, *method = NULL; NMConnection *connection; NMSettingIP4Config *s_ip4; @@ -3742,22 +3768,13 @@ nm_device_activate_ip4_config_commit (gpointer user_data) connection = nm_act_request_get_connection (req); g_assert (connection); - config = g_object_get_data (G_OBJECT (req), PENDING_IP4_CONFIG); - g_assert (config); - /* Make sure the interface is up again just because */ ifindex = nm_device_get_ip_ifindex (self); if (ifindex && !nm_platform_link_is_up (ifindex)) nm_platform_link_set_up (ifindex); - /* Allow setting MTU etc */ - if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) - NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, config); - - /* Merge with user overrides */ - nm_ip4_config_merge_setting (config, nm_connection_get_setting_ip4_config (connection)); - - if (!nm_device_set_ip4_config (self, config, TRUE, &reason)) { + /* NULL to use the existing priv->dev_ip4_config */ + if (!ip4_config_merge_and_apply (self, NULL, &reason)) { nm_log_info (LOGD_DEVICE | LOGD_IP4, "Activation (%s) Stage 5 of 5 (IPv4 Commit) failed", iface); @@ -3771,7 +3788,7 @@ nm_device_activate_ip4_config_commit (gpointer user_data) method = nm_setting_ip4_config_get_method (s_ip4); if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { - if (!start_sharing (self, config)) { + if (!start_sharing (self, priv->ip4_config)) { nm_log_warn (LOGD_SHARING, "Activation (%s) Stage 5 of 5 (IPv4 Commit) start sharing failed.", iface); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); goto out; @@ -3787,9 +3804,6 @@ out: nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IPv4 Commit) complete.", iface); - /* Balance IP config creation; nm_device_set_ip4_config() takes a reference */ - g_object_set_data (G_OBJECT (req), PENDING_IP4_CONFIG, NULL); - return FALSE; } @@ -3799,19 +3813,11 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf NMDevicePrivate *priv; g_return_if_fail (NM_IS_DEVICE (self)); - + g_return_if_fail (NM_IS_IP4_CONFIG (config)); priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request); - if (config == NULL) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - g_object_set_data_full (G_OBJECT (priv->act_request), - PENDING_IP4_CONFIG, - g_object_ref (config), - g_object_unref); + g_clear_object (&priv->dev_ip4_config); + priv->dev_ip4_config = g_object_ref (config); activation_source_schedule (self, nm_device_activate_ip4_config_commit, AF_INET); @@ -4354,7 +4360,6 @@ nm_device_set_ip4_config (NMDevice *self, int ip_ifindex; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (reason != NULL, FALSE); priv = NM_DEVICE_GET_PRIVATE (self); ip_iface = nm_device_get_ip_iface (self); @@ -4383,6 +4388,9 @@ nm_device_set_ip4_config (NMDevice *self, if (!success && reason) *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; + } else { + /* Device config is invalid if combined config is invalid */ + g_clear_object (&priv->dev_ip4_config); } g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG); @@ -4407,7 +4415,6 @@ nm_device_set_ip6_config (NMDevice *self, int ip_ifindex; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (reason != NULL, FALSE); priv = NM_DEVICE_GET_PRIVATE (self); ip_iface = nm_device_get_ip_iface (self); @@ -4792,6 +4799,8 @@ dispose (GObject *object) nm_device_take_down (self, FALSE); } + g_clear_object (&priv->dev_ip4_config); + g_clear_object (&priv->ip4_config); /* reset the saved RA value */ if (priv->ip6_accept_ra_path) { diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index eda52c1460..bc621dd68a 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -330,6 +330,57 @@ nm_ip4_config_update_setting (NMIP4Config *config, NMSettingIP4Config *setting) /******************************************************************/ +void +nm_ip4_config_merge (NMIP4Config *dst, NMIP4Config *src) +{ + guint32 i; + + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); + + /* addresses */ + for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++) + nm_ip4_config_add_address (dst, nm_ip4_config_get_address (src, i)); + + /* ptp address; only replace if src doesn't have one */ + if (!nm_ip4_config_get_ptp_address (dst)) + nm_ip4_config_set_ptp_address (dst, nm_ip4_config_get_ptp_address (src)); + + /* nameservers */ + for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) + nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i)); + + /* default gateway */ + if (!nm_ip4_config_get_gateway (dst)) + nm_ip4_config_set_gateway (dst, nm_ip4_config_get_gateway (src)); + + /* routes */ + for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) + nm_ip4_config_add_route (dst, nm_ip4_config_get_route (src, i)); + + /* domains */ + for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) + nm_ip4_config_add_domain (dst, nm_ip4_config_get_domain (src, i)); + + /* dns searches */ + for (i = 0; i < nm_ip4_config_get_num_searches (src); i++) + nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i)); + + if (!nm_ip4_config_get_mss (dst)) + nm_ip4_config_set_mss (dst, nm_ip4_config_get_mss (src)); + + /* NIS */ + for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++) + nm_ip4_config_add_nis_server (dst, nm_ip4_config_get_nis_server (src, i)); + + if (nm_ip4_config_get_nis_domain (src)) + nm_ip4_config_set_nis_domain (dst, nm_ip4_config_get_nis_domain (src)); + + /* WINS */ + for (i = 0; i < nm_ip4_config_get_num_wins (src); i++) + nm_ip4_config_add_wins (dst, nm_ip4_config_get_wins (src, i)); +} + gboolean nm_ip4_config_destination_is_direct (NMIP4Config *config, guint32 network, int plen) { diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 79e833877c..f441be86c4 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -64,6 +64,7 @@ void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIP4Config *setti void nm_ip4_config_update_setting (NMIP4Config *config, NMSettingIP4Config *setting); /* Utility functions */ +void nm_ip4_config_merge (NMIP4Config *dst, NMIP4Config *src); gboolean nm_ip4_config_destination_is_direct (NMIP4Config *config, guint32 dest, int plen); /* Gateways */