diff options
| author | Michael Biebl <biebl@debian.org> | 2018-05-11 22:09:26 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-05-11 22:09:26 +0200 |
| commit | 341d403947279cd347ebd975cae8977703c0b1f3 (patch) | |
| tree | 34fa6425901e37182b353e7c95dd1d1ec8bc41ec /src | |
| parent | 962a081193fcc84bbcead3dac6ebe36ccf4415ed (diff) | |
| parent | ee9c73a923909e23a649407be77e25235d769e25 (diff) | |
Update upstream source from tag 'upstream/1.10.8'
Update to upstream version '1.10.8' with Debian dir 3c3431643bdd2871afa3e1131ed2320f988f564d
Diffstat (limited to 'src')
| -rw-r--r-- | src/devices/nm-device.c | 270 | ||||
| -rw-r--r-- | src/devices/tests/test-arping.c | 40 | ||||
| -rw-r--r-- | src/nm-act-request.c | 5 | ||||
| -rw-r--r-- | src/nm-act-request.h | 1 | ||||
| -rw-r--r-- | src/nm-active-connection.c | 25 | ||||
| -rw-r--r-- | src/nm-active-connection.h | 13 | ||||
| -rw-r--r-- | src/nm-checkpoint.c | 4 | ||||
| -rw-r--r-- | src/nm-connectivity.c | 15 | ||||
| -rw-r--r-- | src/nm-manager.c | 91 | ||||
| -rw-r--r-- | src/nm-manager.h | 1 | ||||
| -rw-r--r-- | src/nm-policy.c | 3 | ||||
| -rw-r--r-- | src/nm-session-monitor.c | 5 | ||||
| -rw-r--r-- | src/nm-types.h | 7 | ||||
| -rw-r--r-- | src/platform/nmp-object.h | 3 | ||||
| -rw-r--r-- | src/vpn/nm-vpn-connection.c | 2 | ||||
| -rw-r--r-- | src/vpn/nm-vpn-connection.h | 1 |
16 files changed, 294 insertions, 192 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index b8828d14..e79bc541 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -83,9 +83,8 @@ _LOG_DECLARE_SELF (NMDevice); /*****************************************************************************/ -#define DHCP_RESTART_TIMEOUT 120 -#define DHCP_NUM_TRIES_MAX 3 #define DEFAULT_AUTOCONNECT TRUE +#define DHCP_GRACE_PERIOD_SEC 480 #define CARRIER_WAIT_TIME_MS 6000 #define CARRIER_WAIT_TIME_AFTER_MTU_MS 10000 @@ -387,10 +386,9 @@ typedef struct _NMDevicePrivate { NMDhcpClient * client; gulong state_sigid; NMDhcp4Config * config; - guint restart_id; - guint num_tries_left; char * pac_url; bool was_active; + guint grace_id; } dhcp4; struct { @@ -461,10 +459,9 @@ typedef struct _NMDevicePrivate { NMIP6Config * ip6_config; /* Event ID of the current IP6 config from DHCP */ char * event_id; - guint restart_id; - guint num_tries_left; guint needed_prefixes; bool was_active; + guint grace_id; } dhcp6; gboolean needs_ip6_subnet; @@ -486,7 +483,7 @@ typedef struct _NMDevicePrivate { NMLldpListener *lldp_listener; NMConnectivityState connectivity_state; - guint concheck_periodic_id; + gulong concheck_periodic_id; guint64 concheck_seq; guint check_delete_unrealized_id; @@ -556,7 +553,6 @@ static void realize_start_setup (NMDevice *self, NMUnmanFlagOp unmanaged_user_explicit); static void _set_mtu (NMDevice *self, guint32 mtu); static void _commit_mtu (NMDevice *self, const NMIP4Config *config); -static void dhcp_schedule_restart (NMDevice *self, int addr_family, const char *reason); static void _cancel_activation (NMDevice *self); /*****************************************************************************/ @@ -879,19 +875,36 @@ nm_device_ipv4_sysctl_set (NMDevice *self, const char *property, const char *val } static guint32 -nm_device_ipv4_sysctl_get_uint32 (NMDevice *self, const char *property, guint32 fallback) +nm_device_ipv4_sysctl_get_effective_uint32 (NMDevice *self, const char *property, guint32 fallback) { char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; + gint64 v, v_all; if (!nm_device_get_ip_ifindex (self)) return fallback; - return nm_platform_sysctl_get_int_checked (nm_device_get_platform (self), - NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, buf, nm_device_get_ip_iface (self), property)), - 10, - 0, - G_MAXUINT32, - fallback); + v = nm_platform_sysctl_get_int_checked (nm_device_get_platform (self), + NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, + buf, + nm_device_get_ip_iface (self), + property)), + 10, + 0, + G_MAXUINT32, + -1); + + v_all = nm_platform_sysctl_get_int_checked (nm_device_get_platform (self), + NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_sysctl_ip_conf_path (AF_INET, + buf, + "all", + property)), + 10, + 0, + G_MAXUINT32, + -1); + + v = NM_MAX (v, v_all); + return v > -1 ? (guint32) v : fallback; } gboolean @@ -2126,8 +2139,7 @@ concheck_periodic_update (NMDevice *self) nm_device_check_connectivity (self, NULL, NULL); } else if (!check_enable && priv->concheck_periodic_id) { /* The default route has gone off, and so has connectivity. */ - g_signal_handler_disconnect (nm_connectivity_get (), priv->concheck_periodic_id); - priv->concheck_periodic_id = 0; + nm_clear_g_signal_handler (nm_connectivity_get (), &priv->concheck_periodic_id); update_connectivity_state (self, NM_CONNECTIVITY_NONE); } #else @@ -2424,12 +2436,12 @@ carrier_changed (NMDevice *self, gboolean carrier) * is restored. */ if (priv->state == NM_DEVICE_STATE_ACTIVATED) nm_device_update_dynamic_ip_setup (self); - else { - if (nm_device_activate_ip4_state_in_wait (self)) - nm_device_activate_stage3_ip4_start (self); - if (nm_device_activate_ip6_state_in_wait (self)) - nm_device_activate_stage3_ip6_start (self); - } + /* If needed, also resume IP configuration that is + * waiting for carrier. */ + if (nm_device_activate_ip4_state_in_wait (self)) + nm_device_activate_stage3_ip4_start (self); + if (nm_device_activate_ip6_state_in_wait (self)) + nm_device_activate_stage3_ip6_start (self); return; } /* fall-through and change state of device */ @@ -2981,7 +2993,7 @@ ip4_rp_filter_update (NMDevice *self) if ( priv->v4_has_shadowed_routes || nm_device_get_best_default_route (self, AF_INET)) { - if (nm_device_ipv4_sysctl_get_uint32 (self, "rp_filter", 0) != 1) { + if (nm_device_ipv4_sysctl_get_effective_uint32 (self, "rp_filter", 0) != 1) { /* Don't touch the rp_filter if it's not strict. */ return; } @@ -5881,7 +5893,7 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - nm_clear_g_source (&priv->dhcp4.restart_id); + nm_clear_g_source (&priv->dhcp4.grace_id); g_clear_pointer (&priv->dhcp4.pac_url, g_free); if (priv->dhcp4.client) { @@ -6026,20 +6038,17 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config) } static gboolean -dhcp4_restart_cb (gpointer user_data) +dhcp4_grace_period_expired (gpointer user_data) { NMDevice *self = user_data; - NMDevicePrivate *priv; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - priv = NM_DEVICE_GET_PRIVATE (self); - priv->dhcp4.restart_id = 0; + _LOGI (LOGD_DHCP4, "DHCPv4: grace period expired"); - if (dhcp4_start (self) == NM_ACT_STAGE_RETURN_FAILURE) - dhcp_schedule_restart (self, AF_INET, NULL); + nm_device_ip_method_failed (self, AF_INET, + NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); + /* If the device didn't fail, the DHCP client will continue */ - return FALSE; + return G_SOURCE_REMOVE; } static void @@ -6047,44 +6056,48 @@ dhcp4_fail (NMDevice *self, gboolean timeout) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - _LOGD (LOGD_DHCP4, "DHCPv4 failed: timeout %d, num tries left %u", - timeout, priv->dhcp4.num_tries_left); - - dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); + _LOGD (LOGD_DHCP4, "DHCPv4 failed%s", timeout ? " (timeout)" : ""); - /* Don't fail if there are static addresses configured on - * the device, instead retry after some time. + /* Keep client running if there are static addresses configured + * on the interface. */ if ( priv->ip4_state == IP_DONE && priv->con_ip4_config - && nm_ip4_config_get_num_addresses (priv->con_ip4_config) > 0) { - dhcp_schedule_restart (self, AF_INET, "device has IP addresses"); + && nm_ip4_config_get_num_addresses (priv->con_ip4_config) > 0) + goto clear_config; + + /* Fail the method in case of timeout or failure during initial + * configuration. + */ + if ( !priv->dhcp4.was_active + && (timeout || priv->ip4_state == IP_CONF)) { + dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); + nm_device_activate_schedule_ip4_config_timeout (self); return; } - if ( priv->dhcp4.num_tries_left == DHCP_NUM_TRIES_MAX - && (timeout || (priv->ip4_state == IP_CONF)) - && !priv->dhcp4.was_active) - nm_device_activate_schedule_ip4_config_timeout (self); - else if ( priv->dhcp4.num_tries_left < DHCP_NUM_TRIES_MAX - || priv->ip4_state == IP_DONE - || priv->dhcp4.was_active) { - /* Don't fail immediately when the lease expires but try to - * restart DHCP for a predefined number of times. - */ - if (priv->dhcp4.num_tries_left) { - priv->dhcp4.num_tries_left--; - dhcp_schedule_restart (self, AF_INET, "lease expired"); - } else { - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - /* We failed the ipv4 method but schedule again the retries if the ipv6 method is - * configured, keeping the connection up. - */ - if (nm_device_get_state (self) != NM_DEVICE_STATE_FAILED) - dhcp_schedule_restart (self, AF_INET, "renewal failed"); - } - } else - g_warn_if_reached (); + /* In any other case (expired lease, assumed connection, etc.), + * start a grace period in which we keep the client running, + * hoping that it will regain a lease. + */ + if (!priv->dhcp4.grace_id) { + priv->dhcp4.grace_id = g_timeout_add_seconds (DHCP_GRACE_PERIOD_SEC, + dhcp4_grace_period_expired, + self); + _LOGI (LOGD_DHCP4, + "DHCPv4: %u seconds grace period started", + DHCP_GRACE_PERIOD_SEC); + goto clear_config; + } + return; + +clear_config: + /* The previous configuration is no longer valid */ + if (priv->dhcp4.config) { + nm_exported_object_clear_and_unexport (&priv->dhcp4.config); + priv->dhcp4.config = nm_dhcp4_config_new (); + _notify (self, PROP_DHCP4_CONFIG); + } } static void @@ -6124,6 +6137,8 @@ dhcp4_state_changed (NMDhcpClient *client, break; } + nm_clear_g_source (&priv->dhcp4.grace_id); + /* After some failures, we have been able to renew the lease: * update the ip state */ @@ -6136,7 +6151,6 @@ dhcp4_state_changed (NMDhcpClient *client, nm_dhcp4_config_set_options (priv->dhcp4.config, options); _notify (self, PROP_DHCP4_CONFIG); - priv->dhcp4.num_tries_left = DHCP_NUM_TRIES_MAX; if (priv->ip4_state == IP_CONF) { connection = nm_device_get_applied_connection (self); @@ -6507,7 +6521,6 @@ act_stage3_ip4_config_start (NMDevice *self, } method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); - priv->dhcp4.num_tries_left = DHCP_NUM_TRIES_MAX; /* Start IPv4 addressing based on the method requested */ if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) { @@ -6562,7 +6575,7 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) 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); + nm_clear_g_source (&priv->dhcp6.grace_id); if (priv->dhcp6.client) { nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.state_sigid); @@ -6746,53 +6759,17 @@ dhcp6_lease_change (NMDevice *self) } static gboolean -dhcp6_restart_cb (gpointer user_data) +dhcp6_grace_period_expired (gpointer user_data) { NMDevice *self = user_data; - NMDevicePrivate *priv; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE (self); - priv->dhcp6.restart_id = 0; - if (!dhcp6_start (self, FALSE)) - dhcp_schedule_restart (self, AF_INET6, NULL); + _LOGI (LOGD_DHCP6, "DHCPv6: grace period expired"); - return FALSE; -} - -static void -dhcp_schedule_restart (NMDevice *self, - int addr_family, - const char *reason) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint tries_left; - char tries_str[255]; - - nm_assert_addr_family (addr_family); - - tries_left = (addr_family == AF_INET) - ? priv->dhcp4.num_tries_left - : priv->dhcp6.num_tries_left; + nm_device_ip_method_failed (self, AF_INET6, + NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); + /* If the device didn't fail, the DHCP client will continue */ - _LOGI ((addr_family == AF_INET) ? LOGD_DHCP4 : LOGD_DHCP6, - "scheduling DHCPv%c restart in %u seconds%s%s%s%s", - nm_utils_addr_family_to_char (addr_family), - DHCP_RESTART_TIMEOUT, - (tries_left != DHCP_NUM_TRIES_MAX) - ? nm_sprintf_buf (tries_str, ", %u tries left", tries_left + 1) - : "", - NM_PRINT_FMT_QUOTED (reason, " (reason: ", reason, ")", "")); - - if (addr_family == AF_INET) { - priv->dhcp4.restart_id = g_timeout_add_seconds (DHCP_RESTART_TIMEOUT, - dhcp4_restart_cb, self); - } else { - priv->dhcp6.restart_id = g_timeout_add_seconds (DHCP_RESTART_TIMEOUT, - dhcp6_restart_cb, self); - } + return G_SOURCE_REMOVE; } static void @@ -6801,51 +6778,57 @@ dhcp6_fail (NMDevice *self, gboolean timeout) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gboolean is_dhcp_managed; - _LOGD (LOGD_DHCP6, "DHCPv6 failed: timeout %d, num tries left %u", - timeout, priv->dhcp6.num_tries_left); + _LOGD (LOGD_DHCP6, "DHCPv6 failed%s", timeout ? " (timeout)" : ""); is_dhcp_managed = (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED); - dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (is_dhcp_managed || priv->dhcp6.num_tries_left < DHCP_NUM_TRIES_MAX) { - /* Don't fail if there are static addresses configured on - * the device, instead retry after some time. + if (is_dhcp_managed) { + /* Keep client running if there are static addresses configured + * on the interface. */ if ( priv->ip6_state == IP_DONE && priv->con_ip6_config - && nm_ip6_config_get_num_addresses (priv->con_ip6_config)) { - dhcp_schedule_restart (self, AF_INET6, "device has IP addresses"); + && nm_ip6_config_get_num_addresses (priv->con_ip6_config)) + goto clear_config; + + /* Fail the method in case of timeout or failure during initial + * configuration. + */ + if ( !priv->dhcp6.was_active + && (timeout || priv->ip6_state == IP_CONF)) { + dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); + nm_device_activate_schedule_ip6_config_timeout (self); return; } - if ( priv->dhcp6.num_tries_left == DHCP_NUM_TRIES_MAX - && (timeout || (priv->ip6_state == IP_CONF)) - && !priv->dhcp6.was_active) - nm_device_activate_schedule_ip6_config_timeout (self); - else if ( priv->dhcp6.num_tries_left < DHCP_NUM_TRIES_MAX - || priv->ip6_state == IP_DONE - || priv->dhcp6.was_active) { - /* Don't fail immediately when the lease expires but try to - * restart DHCP for a predefined number of times. - */ - if (priv->dhcp6.num_tries_left) { - priv->dhcp6.num_tries_left--; - dhcp_schedule_restart (self, AF_INET6, "lease expired"); - } else { - nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - /* We failed the ipv6 method but schedule again the retries if the ipv4 method is - * configured, keeping the connection up. - */ - if (nm_device_get_state (self) != NM_DEVICE_STATE_FAILED) - dhcp_schedule_restart (self, AF_INET6, "renewal failed"); - } - } else - g_warn_if_reached (); + /* In any other case (expired lease, assumed connection, etc.), + * start a grace period in which we keep the client running, + * hoping that it will regain a lease. + */ + if (!priv->dhcp6.grace_id) { + priv->dhcp6.grace_id = g_timeout_add_seconds (DHCP_GRACE_PERIOD_SEC, + dhcp6_grace_period_expired, + self); + _LOGI (LOGD_DHCP6, + "DHCPv6: %u seconds grace period started", + DHCP_GRACE_PERIOD_SEC); + goto clear_config; + } } else { /* not a hard failure; just live with the RA info */ + dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); if (priv->ip6_state == IP_CONF) nm_device_activate_schedule_ip6_config_result (self); } + return; + +clear_config: + /* The previous configuration is no longer valid */ + if (priv->dhcp6.config) { + nm_exported_object_clear_and_unexport (&priv->dhcp6.config); + priv->dhcp6.config = nm_dhcp6_config_new (); + _notify (self, PROP_DHCP6_CONFIG); + } } static void @@ -6881,6 +6864,7 @@ dhcp6_state_changed (NMDhcpClient *client, switch (state) { case NM_DHCP_STATE_BOUND: + nm_clear_g_source (&priv->dhcp6.grace_id); /* If the server sends multiple IPv6 addresses, we receive a state * changed event for each of them. Use the event ID to merge IPv6 * addresses from the same transaction into a single configuration. @@ -6911,8 +6895,6 @@ dhcp6_state_changed (NMDhcpClient *client, if (priv->ip6_state == IP_FAIL) _set_ip_state (self, AF_INET6, IP_CONF); - priv->dhcp6.num_tries_left = DHCP_NUM_TRIES_MAX; - if (priv->ip6_state == IP_CONF) { if (priv->dhcp6.ip6_config == NULL) { nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED); @@ -8090,8 +8072,6 @@ act_stage3_ip6_config_start (NMDevice *self, } 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); if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) { diff --git a/src/devices/tests/test-arping.c b/src/devices/tests/test-arping.c index bcbc1140..f0537545 100644 --- a/src/devices/tests/test-arping.c +++ b/src/devices/tests/test-arping.c @@ -65,12 +65,22 @@ test_arping_common (test_fixture *fixture, TestInfo *info) gs_unref_object NMArpingManager *manager = NULL; GMainLoop *loop; int i; + const guint WAIT_TIME_OPTIMISTIC = 50; + guint wait_time; + gulong signal_id; if (!nm_utils_find_helper ("arping", NULL, NULL)) { g_test_skip ("arping binary is missing"); return; } + /* first, try with a short waittime. We hope that this is long enough + * to successfully complete the test. Only if that's not the case, we + * assume the computer is currently busy (high load) and we retry with + * a longer timeout. */ + wait_time = WAIT_TIME_OPTIMISTIC; +again: + manager = nm_arping_manager_new (fixture->ifindex0); g_assert (manager != NULL); @@ -83,18 +93,32 @@ test_arping_common (test_fixture *fixture, TestInfo *info) } loop = g_main_loop_new (NULL, FALSE); - g_signal_connect (manager, NM_ARPING_MANAGER_PROBE_TERMINATED, - G_CALLBACK (arping_manager_probe_terminated), loop); - g_assert (nm_arping_manager_start_probe (manager, 250, NULL)); + signal_id = g_signal_connect (manager, NM_ARPING_MANAGER_PROBE_TERMINATED, + G_CALLBACK (arping_manager_probe_terminated), loop); + g_assert (nm_arping_manager_start_probe (manager, wait_time, NULL)); g_assert (nmtst_main_loop_run (loop, 2000)); + g_signal_handler_disconnect (manager, signal_id); + g_main_loop_unref (loop); for (i = 0; info->addresses[i]; i++) { - g_assert_cmpint (nm_arping_manager_check_address (manager, info->addresses[i]), - ==, - info->expected_result[i]); + gboolean val; + + val = nm_arping_manager_check_address (manager, info->addresses[i]); + if (val == info->expected_result[i]) + continue; + + if (wait_time == WAIT_TIME_OPTIMISTIC) { + /* probably we just had a glitch and the system took longer than + * expected. Re-verify with a large timeout this time. */ + wait_time = 1000; + g_clear_object (&manager); + goto again; + } + + g_error ("expected check for address #%d (%s) to %s, but it didn't", + i, nm_utils_inet4_ntop (info->addresses[i], NULL), + info->expected_result[i] ? "detect no duplicated" : "detect a duplicate"); } - - g_main_loop_unref (loop); } static void diff --git a/src/nm-act-request.c b/src/nm-act-request.c index 87070794..dd73947d 100644 --- a/src/nm-act-request.c +++ b/src/nm-act-request.c @@ -541,7 +541,8 @@ nm_act_request_init (NMActRequest *req) * @specific_object: the object path of the specific object (ie, WiFi access point, * etc) that will be used to activate @connection and @device * @subject: the #NMAuthSubject representing the requestor of the activation - * @activation_type: the #NMActivationType. + * @activation_type: the #NMActivationType + * @activation_reason: the reason for activation * @device: the device/interface to configure according to @connection * * Creates a new device-based activation request. If an applied connection is @@ -555,6 +556,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection, const char *specific_object, NMAuthSubject *subject, NMActivationType activation_type, + NMActivationReason activation_reason, NMDevice *device) { g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); @@ -568,6 +570,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, (int) activation_type, + NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, (int) activation_reason, NULL); } diff --git a/src/nm-act-request.h b/src/nm-act-request.h index 5d1c9dfd..a8f09271 100644 --- a/src/nm-act-request.h +++ b/src/nm-act-request.h @@ -41,6 +41,7 @@ NMActRequest *nm_act_request_new (NMSettingsConnection *settings_connec const char *specific_object, NMAuthSubject *subject, NMActivationType activation_type, + NMActivationReason activation_reason, NMDevice *device); NMSettingsConnection *nm_act_request_get_settings_connection (NMActRequest *req); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 65f57565..c3f92464 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -54,6 +54,7 @@ typedef struct _NMActiveConnectionPrivate { bool master_ready:1; NMActivationType activation_type:3; + NMActivationReason activation_reason:3; NMAuthSubject *subject; NMActiveConnection *master; @@ -92,6 +93,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMActiveConnection, PROP_INT_MASTER, PROP_INT_MASTER_READY, PROP_INT_ACTIVATION_TYPE, + PROP_INT_ACTIVATION_REASON, ); enum { @@ -882,6 +884,14 @@ _set_activation_type_managed (NMActiveConnection *self) nm_device_sys_iface_state_set (priv->device, NM_DEVICE_SYS_IFACE_STATE_MANAGED); } +NMActivationReason +nm_active_connection_get_activation_reason (NMActiveConnection *self) +{ + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NM_ACTIVATION_REASON_UNSET); + + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->activation_reason; +} + /*****************************************************************************/ static void @@ -1281,6 +1291,12 @@ set_property (GObject *object, guint prop_id, g_return_if_reached (); _set_activation_type (self, (NMActivationType) i); break; + case PROP_INT_ACTIVATION_REASON: + /* construct-only */ + i = g_value_get_int (value); + priv->activation_reason = i; + nm_assert (priv->activation_reason == ((NMActivationReason) i)); + break; case PROP_SPECIFIC_OBJECT: /* construct-only */ tmp = g_value_get_string (value); @@ -1551,6 +1567,15 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_INT_ACTIVATION_REASON] = + g_param_spec_int (NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, "", "", + NM_ACTIVATION_REASON_UNSET, + NM_ACTIVATION_REASON_USER_REQUEST, + NM_ACTIVATION_REASON_UNSET, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[DEVICE_CHANGED] = diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 3015b5c5..9b6a49ef 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -54,11 +54,12 @@ /* Internal non-exported properties */ #define NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION "int-settings-connection" #define NM_ACTIVE_CONNECTION_INT_APPLIED_CONNECTION "int-applied-connection" -#define NM_ACTIVE_CONNECTION_INT_DEVICE "int-device" -#define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" -#define NM_ACTIVE_CONNECTION_INT_MASTER "int-master" -#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready" -#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE "int-activation-type" +#define NM_ACTIVE_CONNECTION_INT_DEVICE "int-device" +#define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" +#define NM_ACTIVE_CONNECTION_INT_MASTER "int-master" +#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready" +#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE "int-activation-type" +#define NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON "int-activation-reason" /* Signals */ #define NM_ACTIVE_CONNECTION_STATE_CHANGED "state-changed" @@ -185,6 +186,8 @@ void nm_active_connection_set_parent (NMActiveConnection *self, NMActivationType nm_active_connection_get_activation_type (NMActiveConnection *self); +NMActivationReason nm_active_connection_get_activation_reason (NMActiveConnection *self); + void nm_active_connection_clear_secrets (NMActiveConnection *self); #endif /* __NETWORKMANAGER_ACTIVE_CONNECTION_H__ */ diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index d606dee3..bc57d449 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -47,6 +47,7 @@ typedef struct { NMDeviceState state; bool realized:1; NMUnmanFlagOp unmanaged_explicit; + NMActivationReason activation_reason; } DeviceCheckpoint; NM_GOBJECT_PROPERTIES_DEFINE_BASE ( @@ -301,6 +302,7 @@ activate: device, subject, NM_ACTIVATION_TYPE_MANAGED, + dev_checkpoint->activation_reason, &local_error)) { _LOGW ("rollback: reactivation of connection %s/%s failed: %s", nm_connection_get_id ((NMConnection *) connection), @@ -410,6 +412,8 @@ device_checkpoint_create (NMDevice *device, g_return_val_if_fail (act_request, NULL); dev_checkpoint->ac_version_id = nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request)); + dev_checkpoint->activation_reason = + nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (act_request)); } return dev_checkpoint; diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index 4ccc5719..8861f261 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -199,7 +199,7 @@ multi_timer_cb (CURLM *multi, long timeout_ms, void *userdata) nm_clear_g_source (&priv->curl_timer); if (timeout_ms != -1) - priv->curl_timer = g_timeout_add (timeout_ms * 1000, curl_timeout_cb, self); + priv->curl_timer = g_timeout_add (timeout_ms, curl_timeout_cb, self); return 0; } @@ -257,12 +257,15 @@ multi_socket_cb (CURL *e_handle, curl_socket_t s, int what, void *userdata, void } else nm_clear_g_source (&fdp->ev); - if (what & CURL_POLL_IN) - condition |= G_IO_IN; - if (what & CURL_POLL_OUT) - condition |= G_IO_OUT; + if (what == CURL_POLL_IN) + condition = G_IO_IN; + else if (what == CURL_POLL_OUT) + condition = G_IO_OUT; + else if (condition == CURL_POLL_INOUT) + condition = G_IO_IN | G_IO_OUT; - fdp->ev = g_io_add_watch (fdp->ch, condition, curl_socketevent_cb, self); + if (condition) + fdp->ev = g_io_add_watch (fdp->ch, condition, curl_socketevent_cb, self); curl_multi_assign (priv->curl_mhandle, s, fdp); } diff --git a/src/nm-manager.c b/src/nm-manager.c index 8391dbf2..f3bbebd0 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -278,6 +278,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self, NMDevice *device, NMAuthSubject *subject, NMActivationType activation_type, + NMActivationReason activation_reason, GError **error); static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); @@ -1180,6 +1181,10 @@ manager_device_state_changed (NMDevice *device, NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + if ( old_state == NM_DEVICE_STATE_UNMANAGED + && new_state > NM_DEVICE_STATE_UNMANAGED) + retry_connections_for_parent_device (self, device); + switch (new_state) { case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: @@ -2112,13 +2117,14 @@ get_existing_connection (NMManager *self, gs_unref_object NMConnection *connection = NULL; NMSettingsConnection *added = NULL; GError *error = NULL; + gs_free_error GError *gen_error = NULL; NMDevice *master = NULL; int ifindex = nm_device_get_ifindex (device); NMSettingsConnection *matched; NMSettingsConnection *connection_checked = NULL; gboolean assume_state_guess_assume = FALSE; const char *assume_state_connection_uuid = NULL; - gboolean maybe_later; + gboolean maybe_later, only_by_uuid = FALSE; if (out_generated) *out_generated = FALSE; @@ -2151,14 +2157,18 @@ get_existing_connection (NMManager *self, * update_connection() implemented, otherwise nm_device_generate_connection() * returns NULL. */ - connection = nm_device_generate_connection (device, master, &maybe_later, &error); + connection = nm_device_generate_connection (device, master, &maybe_later, &gen_error); if (!connection) { - if (!maybe_later) + if (maybe_later) { + /* The device can generate a connection, but it failed for now. + * Give it a chance to match a connection from the state file. */ + only_by_uuid = TRUE; + } else { nm_device_assume_state_reset (device); - _LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s", - error->message); - g_error_free (error); - return NULL; + _LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s", + gen_error->message); + return NULL; + } } nm_device_assume_state_get (device, @@ -2179,21 +2189,31 @@ get_existing_connection (NMManager *self, && !active_connection_find_first (self, connection_checked, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) && nm_device_check_connection_compatible (device, NM_CONNECTION (connection_checked))) { - NMConnection *const connections[] = { - NM_CONNECTION (connection_checked), - NULL, - }; - - matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, - connection, - TRUE, - nm_device_has_carrier (device), - nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_metric (device, AF_INET6), - NULL, NULL)); + + if (connection) { + NMConnection *const connections[] = { + NM_CONNECTION (connection_checked), + NULL, + }; + + matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, + connection, + TRUE, + nm_device_has_carrier (device), + nm_device_get_route_metric (device, AF_INET), + nm_device_get_route_metric (device, AF_INET6), + NULL, NULL)); + } else + matched = connection_checked; } else matched = NULL; + if (!matched && only_by_uuid) { + _LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s", + gen_error->message); + return NULL; + } + if (!matched && assume_state_guess_assume) { gs_free NMSettingsConnection **connections = NULL; guint len, i, j; @@ -2318,6 +2338,7 @@ recheck_assume_connection (NMManager *self, active = _new_active_connection (self, NM_CONNECTION (connection), NULL, NULL, device, subject, generated ? NM_ACTIVATION_TYPE_EXTERNAL : NM_ACTIVATION_TYPE_ASSUME, + NM_ACTIVATION_REASON_AUTOCONNECT, &error); if (!active) { @@ -3154,6 +3175,7 @@ find_master (NMManager *self, * @device: the #NMDevice, if any, which will activate @connection * @master_connection: the master connection, or %NULL * @master_device: the master device, or %NULL + * @activation_reason: the reason for activation * @error: the error, if an error occurred * * Determines whether a given #NMConnection depends on another connection to @@ -3181,6 +3203,7 @@ ensure_master_active_connection (NMManager *self, NMDevice *device, NMSettingsConnection *master_connection, NMDevice *master_device, + NMActivationReason activation_reason, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); @@ -3244,6 +3267,7 @@ ensure_master_active_connection (NMManager *self, master_device, subject, NM_ACTIVATION_TYPE_MANAGED, + activation_reason, error); return master_ac; } @@ -3290,6 +3314,7 @@ ensure_master_active_connection (NMManager *self, candidate, subject, NM_ACTIVATION_TYPE_MANAGED, + activation_reason, error); return master_ac; } @@ -3512,6 +3537,7 @@ autoconnect_slaves (NMManager *self, slave->device, subject, NM_ACTIVATION_TYPE_MANAGED, + NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES, &local_err); if (local_err) { _LOGW (LOGD_CORE, "Slave connection activation failed: %s", local_err->message); @@ -3686,7 +3712,10 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } parent_ac = nm_manager_activate_connection (self, parent_con, NULL, NULL, parent, - subject, NM_ACTIVATION_TYPE_MANAGED, error); + subject, + NM_ACTIVATION_TYPE_MANAGED, + nm_active_connection_get_activation_reason (active), + error); if (!parent_ac) { g_prefix_error (error, "%s failed to activate parent: ", nm_device_get_iface (device)); return FALSE; @@ -3747,6 +3776,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * device, master_connection, master_device, + nm_active_connection_get_activation_reason (active), error); if (!master_ac) { if (master_device) { @@ -3849,6 +3879,7 @@ _new_vpn_active_connection (NMManager *self, NMSettingsConnection *settings_connection, const char *specific_object, NMAuthSubject *subject, + NMActivationReason activation_reason, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); @@ -3884,6 +3915,7 @@ _new_vpn_active_connection (NMManager *self, return (NMActiveConnection *) nm_vpn_connection_new (settings_connection, device, nm_exported_object_get_path (NM_EXPORTED_OBJECT (parent)), + activation_reason, subject); } @@ -3895,6 +3927,7 @@ _new_active_connection (NMManager *self, NMDevice *device, NMAuthSubject *subject, NMActivationType activation_type, + NMActivationReason activation_reason, GError **error) { NMSettingsConnection *settings_connection = NULL; @@ -3929,6 +3962,7 @@ _new_active_connection (NMManager *self, settings_connection, specific_object, subject, + activation_reason, error); } @@ -3940,6 +3974,7 @@ _new_active_connection (NMManager *self, specific_object, subject, activation_type, + activation_reason, device); } @@ -3958,13 +3993,15 @@ _internal_activation_auth_done (NMActiveConnection *active, priv->authorizing_connections = g_slist_remove (priv->authorizing_connections, active); - /* Don't continue with the activation if an equivalent active connection - * already exists. We also check this earlier, but there we may fail to + /* Don't continue with an internal activation if an equivalent active + * connection already exists. Note that slave autoconnections always force a + * reconnection. We also check this earlier, but there we may fail to * detect a duplicate if the existing active connection is undergoing * authorization in impl_manager_activate_connection(). */ if ( success - && nm_auth_subject_is_internal (nm_active_connection_get_subject (active))) { + && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) + && nm_active_connection_get_activation_reason (active) != NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES) { c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { if ( nm_active_connection_get_device (ac) == nm_active_connection_get_device (active) && nm_active_connection_get_settings_connection (ac) == nm_active_connection_get_settings_connection (active) @@ -4003,6 +4040,7 @@ _internal_activation_auth_done (NMActiveConnection *active, * @subject: the subject which requested activation * @activation_type: whether to assume the connection. That is, take over gracefully, * non-destructible. + * @activation_reason: the reason for activation * @error: return location for an error * * Begins a new internally-initiated activation of @connection on @device. @@ -4023,6 +4061,7 @@ nm_manager_activate_connection (NMManager *self, NMDevice *device, NMAuthSubject *subject, NMActivationType activation_type, + NMActivationReason activation_reason, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); @@ -4059,7 +4098,8 @@ nm_manager_activate_connection (NMManager *self, && g_strcmp0 (nm_active_connection_get_specific_object (active), specific_object) == 0 && nm_active_connection_get_device (active) == device && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) - && nm_auth_subject_is_internal (subject)) + && nm_auth_subject_is_internal (subject) + && nm_active_connection_get_activation_reason (active) == activation_reason) return active; } @@ -4070,6 +4110,7 @@ nm_manager_activate_connection (NMManager *self, device, subject, activation_type, + activation_reason, error); if (active) { priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active); @@ -4313,6 +4354,7 @@ impl_manager_activate_connection (NMManager *self, device, subject, NM_ACTIVATION_TYPE_MANAGED, + NM_ACTIVATION_REASON_USER_REQUEST, &error); if (!active) goto error; @@ -4542,6 +4584,7 @@ impl_manager_add_and_activate_connection (NMManager *self, device, subject, NM_ACTIVATION_TYPE_MANAGED, + NM_ACTIVATION_REASON_USER_REQUEST, &error); if (!active) goto error; diff --git a/src/nm-manager.h b/src/nm-manager.h index b4587e08..da838532 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -136,6 +136,7 @@ NMActiveConnection *nm_manager_activate_connection (NMManager *manager, NMDevice *device, NMAuthSubject *subject, NMActivationType activation_type, + NMActivationReason activation_reason, GError **error); gboolean nm_manager_deactivate_connection (NMManager *manager, diff --git a/src/nm-policy.c b/src/nm-policy.c index b73e04cb..2bf25d50 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -1255,6 +1255,7 @@ auto_activate_device (NMPolicy *self, device, subject, NM_ACTIVATION_TYPE_MANAGED, + NM_ACTIVATION_REASON_AUTOCONNECT, &error); if (!ac) { _LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: %s", @@ -1677,6 +1678,7 @@ activate_secondary_connections (NMPolicy *self, device, nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)), NM_ACTIVATION_TYPE_MANAGED, + nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (req)), &error); if (ac) secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac)); @@ -2148,6 +2150,7 @@ vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *self) NULL, nm_active_connection_get_subject (ac), NM_ACTIVATION_TYPE_MANAGED, + nm_active_connection_get_activation_reason (ac), &error)) { _LOGW (LOGD_DEVICE, "VPN '%s' reconnect failed: %s", nm_settings_connection_get_id (connection), diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c index 20781bd4..e7d1d742 100644 --- a/src/nm-session-monitor.c +++ b/src/nm-session-monitor.c @@ -137,7 +137,10 @@ st_sd_init (NMSessionMonitor *monitor) static void st_sd_finalize (NMSessionMonitor *monitor) { - g_clear_pointer (&monitor->sd.monitor, sd_login_monitor_unref); + if (monitor->sd.monitor) { + sd_login_monitor_unref (monitor->sd.monitor); + monitor->sd.monitor = NULL; + } g_source_remove (monitor->sd.watch); } #endif /* SESSION_TRACKING_SYSTEMD */ diff --git a/src/nm-types.h b/src/nm-types.h index 02163f87..794b0a1c 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -76,6 +76,13 @@ typedef enum { } NMActivationType; typedef enum { + NM_ACTIVATION_REASON_UNSET = 0, + NM_ACTIVATION_REASON_AUTOCONNECT = 1, + NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES = 2, + NM_ACTIVATION_REASON_USER_REQUEST = 3, +} NMActivationReason; + +typedef enum { /* In priority order; higher number == higher priority */ NM_IP_CONFIG_SOURCE_UNKNOWN = 0, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index e3862f2d..e17b17b0 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -457,11 +457,10 @@ nmp_object_ref (const NMPObject *obj) return (const NMPObject *) nm_dedup_multi_obj_ref ((const NMDedupMultiObj *) obj); } -static inline const NMPObject * +static inline void nmp_object_unref (const NMPObject *obj) { nm_dedup_multi_obj_unref ((const NMDedupMultiObj *) obj); - return NULL; } #define nm_clear_nmp_object(ptr) \ diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 6c600c46..12ee0059 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -858,6 +858,7 @@ NMVpnConnection * nm_vpn_connection_new (NMSettingsConnection *settings_connection, NMDevice *parent_device, const char *specific_object, + NMActivationReason activation_reason, NMAuthSubject *subject) { g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); @@ -868,6 +869,7 @@ nm_vpn_connection_new (NMSettingsConnection *settings_connection, NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, + NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, activation_reason, NM_ACTIVE_CONNECTION_VPN, TRUE, NULL); } diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h index 038d0efd..b287c334 100644 --- a/src/vpn/nm-vpn-connection.h +++ b/src/vpn/nm-vpn-connection.h @@ -53,6 +53,7 @@ GType nm_vpn_connection_get_type (void); NMVpnConnection * nm_vpn_connection_new (NMSettingsConnection *settings_connection, NMDevice *parent_device, const char *specific_object, + NMActivationReason activation_reason, NMAuthSubject *subject); void nm_vpn_connection_activate (NMVpnConnection *self, |