diff options
Diffstat (limited to 'src/devices/nm-device-ethernet.c')
-rw-r--r-- | src/devices/nm-device-ethernet.c | 323 |
1 files changed, 190 insertions, 133 deletions
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 3c478fa3ed..dc44c084bd 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -43,6 +43,8 @@ _LOG_DECLARE_SELF(NMDeviceEthernet); #define PPPOE_RECONNECT_DELAY 7 #define PPPOE_ENCAP_OVERHEAD 8 /* 2 bytes for PPP, 6 for PPPoE */ +#define SUPPLICANT_LNK_TIMEOUT_SEC 15 + /*****************************************************************************/ typedef enum { @@ -74,16 +76,17 @@ typedef struct _NMDeviceEthernetPrivate { struct { NMSupplicantManager *mgr; + NMSupplMgrCreateIfaceHandle *create_handle; NMSupplicantInterface *iface; - /* signal handler ids */ gulong iface_state_id; gulong auth_state_id; - /* Timeouts and idles */ guint con_timeout_id; - guint timeout_id; + guint lnk_timeout_id; + + bool is_associated:1; } supplicant; NMActRequestGetSecretsCallId *wired_secrets_id; @@ -399,7 +402,9 @@ supplicant_interface_release (NMDeviceEthernet *self) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - nm_clear_g_source (&priv->supplicant.timeout_id); + nm_clear_pointer (&priv->supplicant.create_handle, nm_supplicant_manager_create_interface_cancel); + + nm_clear_g_source (&priv->supplicant.lnk_timeout_id); nm_clear_g_source (&priv->supplicant.con_timeout_id); nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id); nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.auth_state_id); @@ -500,7 +505,7 @@ wired_secrets_cb (NMActRequest *req, } supplicant_interface_release (self); - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -537,7 +542,7 @@ wired_secrets_get_secrets (NMDeviceEthernet *self, } static gboolean -link_timeout_cb (gpointer user_data) +supplicant_lnk_timeout_cb (gpointer user_data) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); @@ -546,13 +551,13 @@ link_timeout_cb (gpointer user_data) NMConnection *applied_connection; const char *setting_name; - priv->supplicant.timeout_id = 0; + priv->supplicant.lnk_timeout_id = 0; req = nm_device_get_act_request (device); if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); - return FALSE; + return G_SOURCE_REMOVE; } /* Disconnect event during initial authentication and credentials @@ -577,13 +582,13 @@ link_timeout_cb (gpointer user_data) nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); wired_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); - return FALSE; + return G_SOURCE_REMOVE; time_out: _LOGW (LOGD_DEVICE | LOGD_ETHER, "link timed out."); wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - return FALSE; + return G_SOURCE_REMOVE; } static NMSupplicantConfig * @@ -616,18 +621,86 @@ build_supplicant_config (NMDeviceEthernet *self, } static void +supplicant_iface_state_is_completed (NMDeviceEthernet *self, + NMSupplicantInterfaceState state) +{ + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + + if (state == NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) { + nm_clear_g_source (&priv->supplicant.lnk_timeout_id); + nm_clear_g_source (&priv->supplicant.con_timeout_id); + + /* If this is the initial association during device activation, + * schedule the next activation stage. + */ + if (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_CONFIG) { + _LOGI (LOGD_DEVICE | LOGD_ETHER, + "Activation: (ethernet) Stage 2 of 5 (Device Configure) successful."); + nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self)); + } + return; + } + + if ( !priv->supplicant.lnk_timeout_id + && !priv->supplicant.con_timeout_id) + priv->supplicant.lnk_timeout_id = g_timeout_add_seconds (SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self); +} + +static void supplicant_iface_assoc_cb (NMSupplicantInterface *iface, GError *error, gpointer user_data) { - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); + NMDeviceEthernet *self; + NMDeviceEthernetPrivate *priv; - if (error && !nm_utils_error_is_cancelled_or_disposing (error)) { + if (nm_utils_error_is_cancelled_or_disposing (error)) + return; + + self = NM_DEVICE_ETHERNET (user_data); + priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + + if (error) { supplicant_interface_release (self); nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); + return; + } + + nm_assert (!priv->supplicant.lnk_timeout_id); + nm_assert (!priv->supplicant.is_associated); + + priv->supplicant.is_associated = TRUE; + supplicant_iface_state_is_completed (self, + nm_supplicant_interface_get_state (priv->supplicant.iface)); +} + +static gboolean +supplicant_iface_start (NMDeviceEthernet *self) +{ + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + gs_unref_object NMSupplicantConfig *config = NULL; + gs_free_error GError *error = NULL; + + config = build_supplicant_config (self, &error); + if (!config) { + _LOGE (LOGD_DEVICE | LOGD_ETHER, + "Activation: (ethernet) couldn't build security configuration: %s", + error->message); + supplicant_interface_release (self); + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); + return FALSE; } + + nm_supplicant_interface_disconnect (priv->supplicant.iface); + nm_supplicant_interface_assoc (priv->supplicant.iface, + config, + supplicant_iface_assoc_cb, + self); + return TRUE; } static void @@ -639,72 +712,29 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); - NMSupplicantConfig *config; - NMDeviceState devstate; - GError *error = NULL; NMSupplicantInterfaceState new_state = new_state_i; NMSupplicantInterfaceState old_state = old_state_i; - if (new_state == old_state) - return; - _LOGI (LOGD_DEVICE | LOGD_ETHER, "supplicant interface state: %s -> %s", nm_supplicant_interface_state_to_string (old_state), nm_supplicant_interface_state_to_string (new_state)); - devstate = nm_device_get_state (device); - - switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - config = build_supplicant_config (self, &error); - if (config) { - nm_supplicant_interface_assoc (priv->supplicant.iface, config, - supplicant_iface_assoc_cb, self); - g_object_unref (config); - } else { - _LOGE (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) couldn't build security configuration: %s", - error->message); - g_clear_error (&error); - - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: - nm_clear_g_source (&priv->supplicant.timeout_id); - nm_clear_g_source (&priv->supplicant.con_timeout_id); - - /* If this is the initial association during device activation, - * schedule the next activation stage. - */ - if (devstate == NM_DEVICE_STATE_CONFIG) { - _LOGI (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) Stage 2 of 5 (Device Configure) successful."); - nm_device_activate_schedule_stage3_ip_config_start (device); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: - if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) { - /* Start the link timeout so we allow some time for reauthentication */ - if (!priv->supplicant.timeout_id) - priv->supplicant.timeout_id = g_timeout_add_seconds (15, link_timeout_cb, device); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { supplicant_interface_release (self); + wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + return; + } - if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) - wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - break; - default: - break; + if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { + if (!supplicant_iface_start (self)) + return; } + + if (priv->supplicant.is_associated) + supplicant_iface_state_is_completed (self, new_state); } -static NMActStageReturn +static gboolean handle_auth_or_fail (NMDeviceEthernet *self, NMActRequest *req, gboolean new_secrets) @@ -713,7 +743,7 @@ handle_auth_or_fail (NMDeviceEthernet *self, NMConnection *applied_connection; if (!nm_device_auth_retries_try_next (NM_DEVICE (self))) - return NM_ACT_STAGE_RETURN_FAILURE; + return FALSE; nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); @@ -723,7 +753,7 @@ handle_auth_or_fail (NMDeviceEthernet *self, setting_name = nm_connection_need_secrets (applied_connection, NULL); if (!setting_name) { _LOGI (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return NM_ACT_STAGE_RETURN_FAILURE; + return FALSE; } _LOGI (LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) asking for new secrets"); @@ -738,7 +768,7 @@ handle_auth_or_fail (NMDeviceEthernet *self, wired_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0)); - return NM_ACT_STAGE_RETURN_POSTPONE; + return TRUE; } static gboolean @@ -770,43 +800,70 @@ supplicant_connection_timeout_cb (gpointer user_data) if (nm_settings_connection_get_timestamp (connection, ×tamp)) new_secrets = !timestamp; - if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_FAILURE) + if (!handle_auth_or_fail (self, req, new_secrets)) { wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_NO_SECRETS); + return G_SOURCE_REMOVE; + } + + if ( !priv->supplicant.lnk_timeout_id + && priv->supplicant.iface) { + NMSupplicantInterfaceState state; - return FALSE; + state = nm_supplicant_interface_get_state (priv->supplicant.iface); + if (state != NM_SUPPLICANT_INTERFACE_STATE_COMPLETED + && NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (state)) + priv->supplicant.lnk_timeout_id = g_timeout_add_seconds (SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self); + } + + return G_SOURCE_REMOVE; } -static gboolean -supplicant_interface_init (NMDeviceEthernet *self) +static void +supplicant_interface_create_cb (NMSupplicantManager *supplicant_manager, + NMSupplMgrCreateIfaceHandle *handle, + NMSupplicantInterface *iface, + GError *error, + gpointer user_data) { - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + NMDeviceEthernet *self; + NMDeviceEthernetPrivate *priv; guint timeout; - supplicant_interface_release (self); + if (nm_utils_error_is_cancelled (error)) + return; + + self = user_data; + priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr, - nm_device_get_iface (NM_DEVICE (self)), - NM_SUPPLICANT_DRIVER_WIRED); + nm_assert (priv->supplicant.create_handle == handle); + priv->supplicant.create_handle = NULL; - if (!priv->supplicant.iface) { + if (error) { _LOGE (LOGD_DEVICE | LOGD_ETHER, - "Couldn't initialize supplicant interface"); - return FALSE; + "Couldn't initialize supplicant interface: %s", + error->message); + supplicant_interface_release (self); + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + return; } - /* Listen for its state signals */ + priv->supplicant.iface = g_object_ref (iface); + priv->supplicant.is_associated = FALSE; + priv->supplicant.iface_state_id = g_signal_connect (priv->supplicant.iface, NM_SUPPLICANT_INTERFACE_STATE, G_CALLBACK (supplicant_iface_state_cb), self); - /* Set up a timeout on the connection attempt */ timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self)); priv->supplicant.con_timeout_id = g_timeout_add_seconds (timeout, supplicant_connection_timeout_cb, self); - return TRUE; + if (NM_SUPPLICANT_INTERFACE_STATE_IS_OPERATIONAL (nm_supplicant_interface_get_state (iface))) + supplicant_iface_start (self); } static NMPlatformLinkDuplexType @@ -897,7 +954,7 @@ pppoe_reconnect_delay (gpointer user_data) priv->pppoe_wait_id = 0; priv->last_pppoe_time = 0; _LOGI (LOGD_DEVICE, "PPPoE reconnect delay complete, resuming connection..."); - nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); return G_SOURCE_REMOVE; } @@ -946,7 +1003,6 @@ supplicant_check_secrets_needed (NMDeviceEthernet *self, NMDeviceStateReason *ou NMConnection *connection; NMSetting8021x *security; const char *setting_name; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); @@ -955,7 +1011,7 @@ supplicant_check_secrets_needed (NMDeviceEthernet *self, NMDeviceStateReason *ou if (!security) { _LOGE (LOGD_DEVICE, "Invalid or missing 802.1X security"); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return ret; + return NM_ACT_STAGE_RETURN_FAILURE; } if (!priv->supplicant.mgr) @@ -970,21 +1026,25 @@ supplicant_check_secrets_needed (NMDeviceEthernet *self, NMDeviceStateReason *ou "Activation: (ethernet) connection '%s' has security, but secrets are required.", nm_connection_get_id (connection)); - ret = handle_auth_or_fail (self, req, FALSE); - if (ret != NM_ACT_STAGE_RETURN_POSTPONE) + if (!handle_auth_or_fail (self, req, FALSE)) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - } else { - _LOGI (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) connection '%s' requires no security. No secrets needed.", - nm_connection_get_id (connection)); - - if (supplicant_interface_init (self)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + return NM_ACT_STAGE_RETURN_POSTPONE; } - return ret; + _LOGI (LOGD_DEVICE | LOGD_ETHER, + "Activation: (ethernet) connection '%s' requires no security. No secrets needed.", + nm_connection_get_id (connection)); + + supplicant_interface_release (self); + + priv->supplicant.create_handle = nm_supplicant_manager_create_interface (priv->supplicant.mgr, + nm_device_get_ifindex (NM_DEVICE (self)), + NM_SUPPLICANT_DRIVER_WIRED, + supplicant_interface_create_cb, + self); + return NM_ACT_STAGE_RETURN_POSTPONE; } static void @@ -996,33 +1056,17 @@ carrier_changed (NMSupplicantInterface *iface, NMDeviceStateReason reason; NMActStageReturn ret; - if (nm_device_has_carrier (NM_DEVICE (self))) { - _LOGD (LOGD_DEVICE | LOGD_ETHER, "got carrier, initializing supplicant"); - nm_clear_g_signal_handler (self, &priv->carrier_id); - ret = supplicant_check_secrets_needed (self, &reason); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - reason); - } - } -} - -static NMActStageReturn -nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + if (!nm_device_has_carrier (NM_DEVICE (self))) + return; - if (!nm_device_has_carrier (NM_DEVICE (self))) { - _LOGD (LOGD_DEVICE | LOGD_ETHER, "delay supplicant initialization until carrier goes up"); - priv->carrier_id = g_signal_connect (self, - "notify::" NM_DEVICE_CARRIER, - G_CALLBACK (carrier_changed), - self); - return NM_ACT_STAGE_RETURN_POSTPONE; + _LOGD (LOGD_DEVICE | LOGD_ETHER, "got carrier, initializing supplicant"); + nm_clear_g_signal_handler (self, &priv->carrier_id); + ret = supplicant_check_secrets_needed (self, &reason); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + reason); } - - return supplicant_check_secrets_needed (self, out_failure_reason); } /*****************************************************************************/ @@ -1241,7 +1285,7 @@ dcb_state (NMDevice *device, gboolean timeout) break; } _LOGD (LOGD_DCB, "dcb_state() preconfig down falling through"); - /* fall through */ + /* fall-through */ case DCB_WAIT_CARRIER_PRECONFIG_UP: if (timeout || carrier) { _LOGD (LOGD_DCB, "dcb_state() preconfig up configuring DCB"); @@ -1265,7 +1309,7 @@ dcb_state (NMDevice *device, gboolean timeout) break; } _LOGD (LOGD_DCB, "dcb_state() postconfig down falling through"); - /* fall through */ + /* fall-through */ case DCB_WAIT_CARRIER_POSTCONFIG_UP: if (timeout || carrier) { _LOGD (LOGD_DCB, "dcb_state() postconfig up starting IP"); @@ -1328,7 +1372,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMSettingConnection *s_con; const char *connection_type; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + gboolean do_postpone = FALSE; NMSettingDcb *s_dcb; s_con = nm_device_get_applied_setting (device, NM_TYPE_SETTING_CONNECTION); @@ -1342,14 +1386,23 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) * process opens the port up for normal traffic. */ connection_type = nm_setting_connection_get_connection_type (s_con); - if (!strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)) { + if (nm_streq (connection_type, NM_SETTING_WIRED_SETTING_NAME)) { NMSetting8021x *security; security = nm_device_get_applied_setting (device, NM_TYPE_SETTING_802_1X); if (security) { /* FIXME: for now 802.1x is mutually exclusive with DCB */ - return nm_8021x_stage2_config (self, out_failure_reason); + if (!nm_device_has_carrier (NM_DEVICE (self))) { + _LOGD (LOGD_DEVICE | LOGD_ETHER, "delay supplicant initialization until carrier goes up"); + priv->carrier_id = g_signal_connect (self, + "notify::" NM_DEVICE_CARRIER, + G_CALLBACK (carrier_changed), + self); + return NM_ACT_STAGE_RETURN_POSTPONE; + } + + return supplicant_check_secrets_needed (self, out_failure_reason); } } @@ -1371,7 +1424,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } priv->dcb_handle_carrier_changes = TRUE; - ret = NM_ACT_STAGE_RETURN_POSTPONE; + do_postpone = TRUE; } /* PPPoE setup */ @@ -1381,11 +1434,13 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) s_ppp = nm_device_get_applied_setting (device, NM_TYPE_SETTING_PPP); if (s_ppp) { - guint32 mtu = 0, mru = 0, mxu; + guint32 mtu; + guint32 mru; + guint32 mxu; mtu = nm_setting_ppp_get_mtu (s_ppp); mru = nm_setting_ppp_get_mru (s_ppp); - mxu = mru > mtu ? mru : mtu; + mxu = MAX (mru, mtu); if (mxu) { _LOGD (LOGD_PPP, "set MTU to %u (PPP interface MRU %u, MTU %u)", mxu + PPPOE_ENCAP_OVERHEAD, mru, mtu); @@ -1396,7 +1451,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } } - return ret; + return do_postpone + ? NM_ACT_STAGE_RETURN_POSTPONE + : NM_ACT_STAGE_RETURN_SUCCESS; } static NMActStageReturn |