diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c index 8cf179e1e..ef2c98db0 100644 --- a/src/nm-device-bt.c +++ b/src/nm-device-bt.c @@ -275,10 +275,16 @@ ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) case NM_DEVICE_STATE_PREPARE: case NM_DEVICE_STATE_CONFIG: case NM_DEVICE_STATE_NEED_AUTH: - case NM_DEVICE_STATE_IP_CONFIG: case NM_DEVICE_STATE_ACTIVATED: nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); break; + case NM_DEVICE_STATE_IP_CONFIG: + if (nm_device_ip_config_should_fail (device, FALSE)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } + break; default: break; } diff --git a/src/nm-device-modem.c b/src/nm-device-modem.c index b13ce6c3b..3ba26ddcd 100644 --- a/src/nm-device-modem.c +++ b/src/nm-device-modem.c @@ -72,10 +72,16 @@ ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) case NM_DEVICE_STATE_PREPARE: case NM_DEVICE_STATE_CONFIG: case NM_DEVICE_STATE_NEED_AUTH: - case NM_DEVICE_STATE_IP_CONFIG: case NM_DEVICE_STATE_ACTIVATED: nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); break; + case NM_DEVICE_STATE_IP_CONFIG: + if (nm_device_ip_config_should_fail (device, FALSE)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } + break; default: break; } diff --git a/src/nm-device-private.h b/src/nm-device-private.h index 5c71aa1a7..371f17f10 100644 --- a/src/nm-device-private.h +++ b/src/nm-device-private.h @@ -40,4 +40,6 @@ void nm_device_handle_autoip4_event (NMDevice *self, const char *event, const char *address); +gboolean nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6); + #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index b598f2b67..1fa293725 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -2676,7 +2676,11 @@ handle_auth_or_fail (NMDeviceWifi *self, NMConnection *connection; g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); + + if (!req) { + req = nm_device_get_act_request (NM_DEVICE (self)); + g_assert (req); + } connection = nm_act_request_get_connection (req); g_assert (connection); @@ -3187,21 +3191,19 @@ real_act_stage4_get_ip4_config (NMDevice *dev, static NMActStageReturn -real_act_stage4_ip4_config_timeout (NMDevice *dev, - NMIP4Config **config, - NMDeviceStateReason *reason) +handle_ip_config_timeout (NMDeviceWifi *self, + NMConnection *connection, + gboolean may_fail, + gboolean *chain_up, + NMDeviceStateReason *reason) { - NMDeviceWifi *self = NM_DEVICE_WIFI (dev); - NMAccessPoint *ap = nm_device_wifi_get_activation_ap (self); + NMAccessPoint *ap; NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMIP4Config *real_config = NULL; - NMActRequest *req = nm_device_get_act_request (dev); - NMConnection *connection; gboolean auth_enforced = FALSE, encrypted = FALSE; - g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); + ap = nm_device_wifi_get_activation_ap (self); g_assert (ap); /* If nothing checks the security authentication information (as in @@ -3209,9 +3211,8 @@ real_act_stage4_ip4_config_timeout (NMDevice *dev, * the encryption key is likely wrong. Ask the user for a new one. * Otherwise the failure likely happened after a successful authentication. */ - connection = nm_act_request_get_connection (req); auth_enforced = ap_auth_enforced (connection, ap, &encrypted); - if (encrypted && !auth_enforced) { + if (encrypted && !auth_enforced && !may_fail) { NMSettingConnection *s_con; s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); @@ -3220,39 +3221,83 @@ real_act_stage4_ip4_config_timeout (NMDevice *dev, nm_log_warn (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): could not get IP configuration for " "connection '%s'.", - nm_device_get_iface (dev), nm_setting_connection_get_id (s_con)); + nm_device_get_iface (NM_DEVICE (self)), + nm_setting_connection_get_id (s_con)); - ret = handle_auth_or_fail (self, req, TRUE); + ret = handle_auth_or_fail (self, NULL, TRUE); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { nm_log_info (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): asking for new secrets", - nm_device_get_iface (dev)); + nm_device_get_iface (NM_DEVICE (self))); } else { *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; } - } else if (nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) { - NMDeviceWifiClass *klass; - NMDeviceClass * parent_class; - - /* For Ad-Hoc networks, chain up to parent to get a Zeroconf IP */ - klass = NM_DEVICE_WIFI_GET_CLASS (self); - parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); - ret = parent_class->act_stage4_ip4_config_timeout (dev, &real_config, reason); } else { /* Non-encrypted network or authentication is enforced by some - * entity (AP, RADIUS server, etc), but IP configure failed. Alert - * the user. + * entity (AP, RADIUS server, etc), but IP configure failed. Let the + * superclass handle it. */ - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; - ret = NM_ACT_STAGE_RETURN_FAILURE; + *chain_up = TRUE; } - *config = real_config; - return ret; } +static NMActStageReturn +real_act_stage4_ip4_config_timeout (NMDevice *dev, + NMIP4Config **config, + NMDeviceStateReason *reason) +{ + NMActRequest *req; + NMConnection *connection; + NMSettingIP4Config *s_ip4; + gboolean may_fail = FALSE, chain_up = FALSE; + NMActStageReturn ret; + + req = nm_device_get_act_request (dev); + g_assert (req); + connection = nm_act_request_get_connection (req); + g_assert (connection); + + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (s_ip4) + may_fail = nm_setting_ip4_config_get_may_fail (s_ip4); + + ret = handle_ip_config_timeout (NM_DEVICE_WIFI (dev), connection, may_fail, &chain_up, reason); + if (chain_up) + ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip4_config_timeout (dev, config, reason); + + return ret; +} + +static NMActStageReturn +real_act_stage4_ip6_config_timeout (NMDevice *dev, + NMIP6Config **config, + NMDeviceStateReason *reason) +{ + NMActRequest *req; + NMConnection *connection; + NMSettingIP6Config *s_ip6; + gboolean may_fail = FALSE, chain_up = FALSE; + NMActStageReturn ret; + + req = nm_device_get_act_request (dev); + g_assert (req); + connection = nm_act_request_get_connection (req); + g_assert (connection); + + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6) + may_fail = nm_setting_ip6_config_get_may_fail (s_ip6); + + ret = handle_ip_config_timeout (NM_DEVICE_WIFI (dev), connection, may_fail, &chain_up, reason); + if (chain_up) + ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip6_config_timeout (dev, config, reason); + + return ret; +} + static void activation_success_handler (NMDevice *dev) { @@ -3725,6 +3770,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->act_stage2_config = real_act_stage2_config; parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; parent_class->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout; + parent_class->act_stage4_ip6_config_timeout = real_act_stage4_ip6_config_timeout; parent_class->deactivate = real_deactivate; parent_class->deactivate_quickly = real_deactivate_quickly; parent_class->can_interrupt_activation = real_can_interrupt_activation; diff --git a/src/nm-device.c b/src/nm-device.c index 9fa2523b9..a09a69218 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -177,6 +177,11 @@ static NMActStageReturn dhcp6_start (NMDevice *self, guint32 dhcp_opt, NMDeviceStateReason *reason); +static void addrconf6_cleanup (NMDevice *self); +static void dhcp6_cleanup (NMDevice *self, gboolean stop); +static void dhcp4_cleanup (NMDevice *self, gboolean stop); + + static void device_interface_init (NMDeviceInterface *device_interface_class) { @@ -574,6 +579,35 @@ activation_source_schedule (NMDevice *self, GSourceFunc func, int family) } } +gboolean +nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6) +{ + NMActRequest *req; + NMConnection *connection; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + + g_return_val_if_fail (self != NULL, TRUE); + + req = nm_device_get_act_request (self); + g_assert (req); + connection = nm_act_request_get_connection (req); + g_assert (connection); + + /* Fail the connection if the failed IP method is required to complete */ + if (ip6) { + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6 && !nm_setting_ip6_config_get_may_fail (s_ip6)) + return TRUE; + } else { + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (s_ip4 && !nm_setting_ip4_config_get_may_fail (s_ip4)) + return TRUE; + } + + return FALSE; +} + static void ip6_addrconf_complete (NMIP6Manager *ip6_manager, int ifindex, @@ -1318,9 +1352,12 @@ dhcp_state_changed (NMDHCPClient *client, nm_dhcp4_config_reset (priv->dhcp4_config); /* dhclient quit and can't get/renew a lease; so kill the connection */ - if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DHCP_FAILED); - else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) + if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) { + if (ipv6) + nm_device_activate_schedule_stage4_ip6_config_timeout (device); + else + nm_device_activate_schedule_stage4_ip4_config_timeout (device); + } else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); break; case DHC_STOP: @@ -1797,8 +1834,7 @@ nm_device_activate_stage4_ip4_config_get (gpointer user_data) ret = NM_DEVICE_GET_CLASS (self)->act_stage4_get_ip4_config (self, &ip4_config, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) goto out; - else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) - { + else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } @@ -1852,9 +1888,12 @@ real_act_stage4_ip4_config_timeout (NMDevice *self, /* Notify of invalid DHCP4 config object */ g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP4_CONFIG); - /* DHCP failed; connection must fail */ - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; - return NM_ACT_STAGE_RETURN_FAILURE; + if (nm_device_ip_config_should_fail (self, FALSE)) { + *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + return NM_ACT_STAGE_RETURN_FAILURE; + } + + return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -1882,17 +1921,18 @@ nm_device_activate_stage4_ip4_config_timeout (gpointer user_data) iface); ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &ip4_config, &reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) goto out; - } else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) { + else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - g_assert (ip4_config); - g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), - NM_ACT_REQUEST_IP4_CONFIG, ip4_config); + if (ip4_config) { + g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), + NM_ACT_REQUEST_IP4_CONFIG, ip4_config); + } nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET); @@ -2125,11 +2165,15 @@ real_act_stage4_ip6_config_timeout (NMDevice *self, g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE); - /* Notify of invalid DHCP6 config object */ + /* Notify of invalid DHCP4 config object */ g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG); - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; - return NM_ACT_STAGE_RETURN_FAILURE; + if (nm_device_ip_config_should_fail (self, TRUE)) { + *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + return NM_ACT_STAGE_RETURN_FAILURE; + } + + return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -2157,17 +2201,18 @@ nm_device_activate_stage4_ip6_config_timeout (gpointer user_data) iface); ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &ip6_config, &reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) goto out; - } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - g_assert (ip6_config); - g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), - NM_ACT_REQUEST_IP6_CONFIG, ip6_config); + if (ip6_config) { + g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), + NM_ACT_REQUEST_IP6_CONFIG, ip6_config); + } nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET6);