diff options
Diffstat (limited to 'src/devices/nm-device.c')
| -rw-r--r-- | src/devices/nm-device.c | 470 |
1 files changed, 318 insertions, 152 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index da581a0d..fbf315ed 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -262,7 +262,10 @@ typedef struct _NMDevicePrivate { NMUtilsStableType current_stable_id_type:3; - bool is_nm_owned:1; /* whether the device is a device owned and created by NM */ + bool nm_owned:1; /* whether the device is a device owned and created by NM */ + + bool assume_state_guess_assume:1; + char * assume_state_connection_uuid; GHashTable * available_connections; char * hw_addr; @@ -527,6 +530,9 @@ static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll); static void nm_device_start_ip_check (NMDevice *self); static void realize_start_setup (NMDevice *self, const NMPlatformLink *plink, + gboolean assume_state_guess_assume, + const char *assume_state_connection_uuid, + gboolean set_nm_owned, NMUnmanFlagOp unmanaged_user_explicit); static void _commit_mtu (NMDevice *self, const NMIP4Config *config); static void dhcp_schedule_restart (NMDevice *self, int family, const char *reason); @@ -551,8 +557,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (queued_state_to_string, NMDeviceState, NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_FAILED, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "failed"), ); -static const char * -state_to_string (NMDeviceState state) +const char * +nm_device_state_to_str (NMDeviceState state) { return queued_state_to_string (state) + NM_STRLEN (NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE); } @@ -710,6 +716,52 @@ nm_device_sys_iface_state_set (NMDevice *self, /*****************************************************************************/ +void +nm_device_assume_state_get (NMDevice *self, + gboolean *out_assume_state_guess_assume, + const char **out_assume_state_connection_uuid) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + NM_SET_OUT (out_assume_state_guess_assume, priv->assume_state_guess_assume); + NM_SET_OUT (out_assume_state_connection_uuid, priv->assume_state_connection_uuid); +} + +static void +_assume_state_set (NMDevice *self, + gboolean assume_state_guess_assume, + const char *assume_state_connection_uuid) +{ + NMDevicePrivate *priv; + + nm_assert (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + if ( priv->assume_state_guess_assume == !!assume_state_guess_assume + && nm_streq0 (priv->assume_state_connection_uuid, assume_state_connection_uuid)) + return; + + _LOGD (LOGD_DEVICE, "assume-state: set guess-assume=%c, connection=%s%s%s", + assume_state_guess_assume ? '1' : '0', + NM_PRINT_FMT_QUOTE_STRING (assume_state_connection_uuid)); + priv->assume_state_guess_assume = assume_state_guess_assume; + g_free (priv->assume_state_connection_uuid); + priv->assume_state_connection_uuid = g_strdup (assume_state_connection_uuid); +} + +void +nm_device_assume_state_reset (NMDevice *self) +{ + g_return_if_fail (NM_IS_DEVICE (self)); + + _assume_state_set (self, FALSE, NULL); +} + +/*****************************************************************************/ + static void init_ip4_config_dns_priority (NMDevice *self, NMIP4Config *config) { @@ -1775,10 +1827,13 @@ update_connectivity_state (NMDevice *self, NMConnectivityState state) priv->connectivity_state = state; _notify (self, PROP_CONNECTIVITY); - if (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED) { - if (!ip4_config_merge_and_apply (self, NULL, TRUE)) + if ( priv->state == NM_DEVICE_STATE_ACTIVATED + && !nm_device_sys_iface_state_is_external (self)) { + if ( priv->default_route.v4_has + && !ip4_config_merge_and_apply (self, NULL, TRUE)) _LOGW (LOGD_IP4, "Failed to update IPv4 default route metric"); - if (!ip6_config_merge_and_apply (self, TRUE)) + if ( priv->default_route.v6_has + && !ip6_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP6, "Failed to update IPv6 default route metric"); } } @@ -1858,7 +1913,7 @@ nm_device_check_connectivity (NMDevice *self, /* Kick off a real connectivity check. */ nm_connectivity_check_async (nm_connectivity_get (), - nm_device_get_iface (self), + nm_device_get_ip_iface (self), concheck_cb, data); return; @@ -2069,7 +2124,7 @@ nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean co static gboolean can_unmanaged_external_down (NMDevice *self) { - return !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned + return !NM_DEVICE_GET_PRIVATE (self)->nm_owned && nm_device_is_software (self); } @@ -2167,11 +2222,21 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) } } +/*****************************************************************************/ + +static void +carrier_changed_notify (NMDevice *self, gboolean carrier) +{ + /* stub */ +} + static void carrier_changed (NMDevice *self, gboolean carrier) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NM_DEVICE_GET_CLASS (self)->carrier_changed_notify (self, carrier); + if (priv->state <= NM_DEVICE_STATE_UNMANAGED) return; @@ -2236,7 +2301,7 @@ carrier_changed (NMDevice *self, gboolean carrier) #define LINK_DISCONNECT_DELAY 4 static gboolean -link_disconnect_action_cb (gpointer user_data) +carrier_disconnected_action_cb (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -2244,21 +2309,19 @@ link_disconnect_action_cb (gpointer user_data) _LOGD (LOGD_DEVICE, "link disconnected (calling deferred action) (id=%u)", priv->carrier_defer_id); priv->carrier_defer_id = 0; - - NM_DEVICE_GET_CLASS (self)->carrier_changed (self, FALSE); - + carrier_changed (self, FALSE); return FALSE; } static void -link_disconnect_action_cancel (NMDevice *self) +carrier_disconnected_action_cancel (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + guint id = priv->carrier_defer_id; - if (priv->carrier_defer_id) { - g_source_remove (priv->carrier_defer_id); - _LOGD (LOGD_DEVICE, "link disconnected (canceling deferred action) (id=%u)", priv->carrier_defer_id); - priv->carrier_defer_id = 0; + if (nm_clear_g_source (&priv->carrier_defer_id)) { + _LOGD (LOGD_DEVICE, "link disconnected (canceling deferred action) (id=%u)", + id); } } @@ -2266,7 +2329,6 @@ void nm_device_set_carrier (NMDevice *self, gboolean carrier) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); NMDeviceState state = nm_device_get_state (self); if (priv->carrier == carrier) @@ -2277,25 +2339,51 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) if (priv->carrier) { _LOGI (LOGD_DEVICE, "link connected"); - link_disconnect_action_cancel (self); - klass->carrier_changed (self, TRUE); + carrier_disconnected_action_cancel (self); + carrier_changed (self, TRUE); - if (nm_clear_g_source (&priv->carrier_wait_id)) { - nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE); + if (priv->carrier_wait_id) { + nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); _carrier_wait_check_queued_act_request (self); } - } else if ( state <= NM_DEVICE_STATE_DISCONNECTED - && !priv->queued_act_request) { - _LOGD (LOGD_DEVICE, "link disconnected"); - klass->carrier_changed (self, FALSE); } else { - priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY, - link_disconnect_action_cb, self); - _LOGD (LOGD_DEVICE, "link disconnected (deferring action for %d seconds) (id=%u)", - LINK_DISCONNECT_DELAY, priv->carrier_defer_id); + if (priv->carrier_wait_id) + nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); + if ( state <= NM_DEVICE_STATE_DISCONNECTED + && !priv->queued_act_request) { + _LOGD (LOGD_DEVICE, "link disconnected"); + carrier_changed (self, FALSE); + } else { + priv->carrier_defer_id = g_timeout_add_seconds (LINK_DISCONNECT_DELAY, + carrier_disconnected_action_cb, self); + _LOGD (LOGD_DEVICE, "link disconnected (deferring action for %d seconds) (id=%u)", + LINK_DISCONNECT_DELAY, priv->carrier_defer_id); + } + } +} + +static void +nm_device_set_carrier_from_platform (NMDevice *self) +{ + if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { + if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { + nm_device_set_carrier (self, + nm_platform_link_is_connected (nm_device_get_platform (self), + nm_device_get_ip_ifindex (self))); + } + } else { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + /* Fake online link when carrier detection is not available. */ + if (!priv->carrier) { + priv->carrier = TRUE; + _notify (self, PROP_CARRIER); + } } } +/*****************************************************************************/ + static void device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink) { @@ -2427,7 +2515,7 @@ device_link_changed (NMDevice *self) info = *pllink; udi = nm_platform_link_get_udi (nm_device_get_platform (self), info.ifindex); - if (udi && g_strcmp0 (udi, priv->udi)) { + if (udi && !nm_streq0 (udi, priv->udi)) { /* Update UDI to what udev gives us */ g_free (priv->udi); priv->udi = g_strdup (udi); @@ -2707,6 +2795,9 @@ link_type_compatible (NMDevice *self, * nm_device_realize_start(): * @self: the #NMDevice * @plink: an existing platform link or %NULL + * @assume_state_guess_assume: set the guess_assume state. + * @assume_state_connection_uuid: set the connection uuid to assume. + * @set_nm_owned: for software device, if TRUE set nm-owned. * @unmanaged_user_explicit: the user-explicit unmanaged flag to apply * on the device initially. * @out_compatible: %TRUE on return if @self is compatible with @plink @@ -2724,6 +2815,9 @@ link_type_compatible (NMDevice *self, gboolean nm_device_realize_start (NMDevice *self, const NMPlatformLink *plink, + gboolean assume_state_guess_assume, + const char *assume_state_connection_uuid, + gboolean set_nm_owned, NMUnmanFlagOp unmanaged_user_explicit, gboolean *out_compatible, GError **error) @@ -2748,8 +2842,11 @@ nm_device_realize_start (NMDevice *self, plink_copy = *plink; plink = &plink_copy; } - realize_start_setup (self, plink, unmanaged_user_explicit); - + realize_start_setup (self, plink, + assume_state_guess_assume, + assume_state_connection_uuid, + set_nm_owned, + unmanaged_user_explicit); return TRUE; } @@ -2776,9 +2873,9 @@ nm_device_create_and_realize (NMDevice *self, const NMPlatformLink *plink = NULL; /* Must be set before device is realized */ - priv->is_nm_owned = !nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface); + priv->nm_owned = !nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface); - _LOGD (LOGD_DEVICE, "create (is %snm-owned)", priv->is_nm_owned ? "" : "not "); + _LOGD (LOGD_DEVICE, "create (is %snm-owned)", priv->nm_owned ? "" : "not "); /* Create any resources the device needs */ if (NM_DEVICE_GET_CLASS (self)->create_and_realize) { @@ -2788,7 +2885,10 @@ nm_device_create_and_realize (NMDevice *self, plink = &plink_copy; } - realize_start_setup (self, plink, NM_UNMAN_FLAG_OP_FORGET); + realize_start_setup (self, plink, + FALSE, /* assume_state_guess_assume */ + NULL, /* assume_state_connection_uuid */ + FALSE, NM_UNMAN_FLAG_OP_FORGET); nm_device_realize_finish (self, plink); if (nm_device_get_managed (self, FALSE)) { @@ -2808,7 +2908,7 @@ update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink) g_return_if_fail (plink != NULL); udi = nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex); - if (udi && !g_strcmp0 (udi, priv->udi)) { + if (udi && !nm_streq0 (udi, priv->udi)) { g_free (priv->udi); priv->udi = g_strdup (udi); _notify (self, PROP_UDI); @@ -2872,15 +2972,6 @@ config_changed (NMConfig *config, } static void -check_carrier (NMDevice *self) -{ - int ifindex = nm_device_get_ip_ifindex (self); - - if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) - nm_device_set_carrier (self, nm_platform_link_is_connected (nm_device_get_platform (self), ifindex)); -} - -static void realize_start_notify (NMDevice *self, const NMPlatformLink *pllink) { @@ -2893,6 +2984,10 @@ realize_start_notify (NMDevice *self, * realize_start_setup(): * @self: the #NMDevice * @plink: the #NMPlatformLink if backed by a kernel netdevice + * @assume_state_guess_assume: set the guess_assume state. + * @assume_state_connection_uuid: set the connection uuid to assume. + * @set_nm_owned: if TRUE and device is a software-device, set nm-owned. + * TRUE. * @unmanaged_user_explicit: the user-explict unmanaged flag to set. * * Update the device from backing resource properties (like hardware @@ -2904,6 +2999,9 @@ realize_start_notify (NMDevice *self, static void realize_start_setup (NMDevice *self, const NMPlatformLink *plink, + gboolean assume_state_guess_assume, + const char *assume_state_connection_uuid, + gboolean set_nm_owned, NMUnmanFlagOp unmanaged_user_explicit) { NMDevicePrivate *priv; @@ -2942,6 +3040,8 @@ realize_start_setup (NMDevice *self, _notify (self, PROP_MTU); } + _assume_state_set (self, assume_state_guess_assume, assume_state_connection_uuid); + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); if (plink) { @@ -2987,6 +3087,13 @@ realize_start_setup (NMDevice *self, _add_capabilities (self, capabilities); + if ( !priv->nm_owned + && set_nm_owned + && nm_device_is_software (self)) { + priv->nm_owned = TRUE; + _LOGD (LOGD_DEVICE, "set nm-owned from state file"); + } + if (!priv->udi) { /* Use a placeholder UDI until we get a real one */ priv->udi = g_strdup_printf ("/virtual/device/placeholder/%d", id++); @@ -3010,16 +3117,7 @@ realize_start_setup (NMDevice *self, self); } - if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { - check_carrier (self); - _LOGD (LOGD_PLATFORM, - "carrier is %s%s", - priv->carrier ? "ON" : "OFF", - priv->ignore_carrier ? " (but ignored)" : ""); - } else { - /* Fake online link when carrier detection is not available. */ - priv->carrier = TRUE; - } + nm_device_set_carrier_from_platform (self); device_init_sriov_num_vfs (self); @@ -3165,6 +3263,8 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) _LOGD (LOGD_DEVICE, "unrealize (ifindex %d)", ifindex > 0 ? ifindex : 0); + nm_device_assume_state_reset (self); + if (remove_resources) { if (NM_DEVICE_GET_CLASS (self)->unrealize) { if (!NM_DEVICE_GET_CLASS (self)->unrealize (self, error)) @@ -3326,9 +3426,9 @@ slave_state_changed (NMDevice *slave, _LOGD (LOGD_DEVICE, "slave %s state change %d (%s) -> %d (%s)", nm_device_get_iface (slave), slave_old_state, - state_to_string (slave_old_state), + nm_device_state_to_str (slave_old_state), slave_new_state, - state_to_string (slave_new_state)); + nm_device_state_to_str (slave_new_state)); /* Don't try to enslave slaves until the master is ready */ if (priv->state < NM_DEVICE_STATE_CONFIG) @@ -4014,27 +4114,37 @@ nm_device_master_update_slave_connection (NMDevice *self, } NMConnection * -nm_device_generate_connection (NMDevice *self, NMDevice *master) +nm_device_generate_connection (NMDevice *self, + NMDevice *master, + gboolean *out_maybe_later, + GError **error) { NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const char *ifname = nm_device_get_iface (self); - NMConnection *connection; + gs_unref_object NMConnection *connection = NULL; NMSetting *s_con; NMSetting *s_ip4; NMSetting *s_ip6; char uuid[37]; const char *ip4_method, *ip6_method; - GError *error = NULL; + GError *local = NULL; const NMPlatformLink *pllink; + NM_SET_OUT (out_maybe_later, FALSE); + /* If update_connection() is not implemented, just fail. */ - if (!klass->update_connection) + if (!klass->update_connection) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "device class %s does not support generating a connection", + G_OBJECT_TYPE_NAME (self)); return NULL; + } /* Return NULL if device is unconfigured. */ if (!device_has_config (self)) { - _LOGD (LOGD_DEVICE, "device has no existing configuration"); + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "device has no existing configuration"); return NULL; } @@ -4057,12 +4167,11 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) if (!nm_device_master_update_slave_connection (master, self, connection, - &error)) - { - _LOGE (LOGD_DEVICE, "master device '%s' failed to update slave connection: %s", - nm_device_get_iface (master), error->message); - g_error_free (error); - g_object_unref (connection); + &local)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "master device '%s' failed to update slave connection: %s", + nm_device_get_iface (master), local->message); + g_error_free (local); return NULL; } } else { @@ -4075,7 +4184,6 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) pllink = nm_platform_link_get (nm_device_get_platform (self), priv->ifindex); if (pllink && pllink->inet6_token.id) { - _LOGD (LOGD_IP6, "IPv6 tokenized identifier present"); g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, NM_IN6_ADDR_GEN_MODE_EUI64, NM_SETTING_IP6_CONFIG_TOKEN, nm_utils_inet6_interface_identifier_to_token (pllink->inet6_token, NULL), @@ -4085,11 +4193,11 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) klass->update_connection (self, connection); - /* Check the connection in case of update_connection() bug. */ - if (!nm_connection_verify (connection, &error)) { - _LOGE (LOGD_DEVICE, "Generated connection does not verify: %s", error->message); - g_clear_error (&error); - g_object_unref (connection); + if (!nm_connection_verify (connection, &local)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "generated connection does not verify: %s", + local->message); + g_error_free (local); return NULL; } @@ -4102,26 +4210,28 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master) && g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0 && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con)) && !priv->slaves) { - _LOGD (LOGD_DEVICE, "ignoring generated connection (no IP and not in master-slave relationship)"); - g_object_unref (connection); - connection = NULL; + NM_SET_OUT (out_maybe_later, TRUE); + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "ignoring generated connection (no IP and not in master-slave relationship)"); + return NULL; } /* Ignore any IPv6LL-only, not master connections without slaves, * unless they are in the assume-ipv6ll-only list. */ - if ( connection - && g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0 + if ( g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0 && g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0 && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con)) && !priv->slaves && !nm_config_data_get_assume_ipv6ll_only (NM_CONFIG_GET_DATA, self)) { _LOGD (LOGD_DEVICE, "ignoring generated connection (IPv6LL-only and not in master-slave relationship)"); - g_object_unref (connection); - connection = NULL; + NM_SET_OUT (out_maybe_later, TRUE); + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "ignoring generated connection (IPv6LL-only and not in master-slave relationship)"); + return NULL; } - return connection; + return g_steal_pointer (&connection); } gboolean @@ -4291,10 +4401,9 @@ nm_device_emit_recheck_assume (gpointer user_data) priv = NM_DEVICE_GET_PRIVATE (self); priv->recheck_assume_id = 0; - if (!nm_device_get_act_request (self)) { - _LOGD (LOGD_DEVICE, "emit RECHECK_ASSUME signal"); + if (!nm_device_get_act_request (self)) g_signal_emit (self, signals[RECHECK_ASSUME], 0); - } + return G_SOURCE_REMOVE; } @@ -4333,7 +4442,7 @@ recheck_available (gpointer user_data) _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)); + nm_device_state_to_str (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; @@ -5472,8 +5581,15 @@ ip4_config_merge_and_apply (NMDevice *self, composite = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); init_ip4_config_dns_priority (self, composite); - if (commit) + if (commit) { ensure_con_ip4_config (self); + if (priv->queued_ip4_config_id) { + g_clear_object (&priv->ext_ip4_config); + priv->ext_ip4_config = nm_ip4_config_capture (nm_device_get_platform (self), + nm_device_get_ip_ifindex (self), + FALSE); + } + } if (priv->dev_ip4_config) { nm_ip4_config_merge (composite, priv->dev_ip4_config, @@ -6200,7 +6316,6 @@ 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->ndisc ? @@ -6208,8 +6323,19 @@ ip6_config_merge_and_apply (NMDevice *self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); init_ip6_config_dns_priority (self, composite); - if (commit) + if (commit) { ensure_con_ip6_config (self); + if (priv->queued_ip6_config_id) { + g_clear_object (&priv->ext_ip6_config); + g_clear_object (&priv->ext_ip6_config_captured); + priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self), + nm_device_get_ip_ifindex (self), + FALSE, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + if (priv->ext_ip6_config_captured) + priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); + } + } /* Merge all the IP configs into the composite config */ if (priv->ac_ip6_config) { @@ -7023,7 +7149,7 @@ nm_device_get_configured_mtu_for_wired (NMDevice *self, gboolean *out_is_user_co } *out_is_user_config = FALSE; - return NM_DEVICE_DEFAULT_MTU_WIRED; + return 0; } /*****************************************************************************/ @@ -7725,7 +7851,7 @@ act_stage3_ip6_config_start (NMDevice *self, nm_platform_process_events (nm_device_get_platform (self)); g_clear_object (&priv->ext_ip6_config_captured); priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self), - nm_device_get_ifindex (self), + nm_device_get_ip_ifindex (self), FALSE, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); @@ -8649,9 +8775,9 @@ _update_ip4_address (NMDevice *self) } gboolean -nm_device_get_is_nm_owned (NMDevice *self) +nm_device_is_nm_owned (NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->is_nm_owned; + return NM_DEVICE_GET_PRIVATE (self)->nm_owned; } /* @@ -8712,7 +8838,7 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex) if (ifindex <= 0) return; - if (!priv->is_nm_owned) + if (!priv->nm_owned) return; if (priv->queued_act_request) return; @@ -9035,10 +9161,12 @@ check_and_reapply_connection (NMDevice *self, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, &diffs); - if (diffs && nm_audit_manager_audit_enabled (nm_audit_manager_get ())) - *audit_args = nm_utils_format_con_diff_for_audit (diffs); - else - *audit_args = NULL; + if (audit_args) { + if (diffs && nm_audit_manager_audit_enabled (nm_audit_manager_get ())) + *audit_args = nm_utils_format_con_diff_for_audit (diffs); + else + *audit_args = NULL; + } /************************************************************************** * check for unsupported changes and reject to reapply @@ -9140,6 +9268,20 @@ check_and_reapply_connection (NMDevice *self, return TRUE; } +gboolean +nm_device_reapply (NMDevice *self, + NMConnection *connection, + GError **error) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + return check_and_reapply_connection (self, + connection, + 0, + NULL, + error); +} + typedef struct { NMConnection *connection; guint64 version_id; @@ -10286,12 +10428,12 @@ static gboolean carrier_wait_timeout (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NM_DEVICE_GET_PRIVATE (self)->carrier_wait_id = 0; - nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE); - - _carrier_wait_check_queued_act_request (self); - + priv->carrier_wait_id = 0; + nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); + if (!priv->carrier) + _carrier_wait_check_queued_act_request (self); return G_SOURCE_REMOVE; } @@ -10333,8 +10475,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) } /* Store carrier immediately. */ - if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) - check_carrier (self); + nm_device_set_carrier_from_platform (self); device_is_up = nm_device_is_up (self); if (block && !device_is_up) { @@ -10369,8 +10510,14 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) * a timeout is reached. */ if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { - if (!nm_clear_g_source (&priv->carrier_wait_id)) - nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, TRUE); + /* we start a grace period of 5 seconds during which we will schedule + * a pending action whenever we have no carrier. + * + * If during that time carrier goes away, we declare the interface + * as not ready. */ + nm_clear_g_source (&priv->carrier_wait_id); + if (!priv->carrier) + nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); priv->carrier_wait_id = g_timeout_add_seconds (5, carrier_wait_timeout, self); } @@ -11812,7 +11959,7 @@ nm_device_add_pending_action (NMDevice *self, const char *action, gboolean asser count + g_slist_length (iter), action); g_return_val_if_reached (FALSE); } else { - _LOGD (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending (expected)", + _LOGT (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending (expected)", count + g_slist_length (iter), action); } return FALSE; @@ -11873,7 +12020,7 @@ nm_device_remove_pending_action (NMDevice *self, const char *action, gboolean as _LOGW (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending", count, action); g_return_val_if_reached (FALSE); } else - _LOGD (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending (expected)", count, action); + _LOGT (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending (expected)", count, action); return FALSE; } @@ -12058,11 +12205,6 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean /* master: release slaves */ nm_device_master_release_slaves (self); - /* slave: mark no longer enslaved */ - if ( priv->master - && nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) <= 0) - nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - /* Take out any entries in the routing table and any IP address the device had. */ ifindex = nm_device_get_ip_ifindex (self); if (ifindex > 0) { @@ -12071,6 +12213,11 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean } } + /* slave: mark no longer enslaved */ + if ( priv->master + && nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) <= 0) + nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + if (priv->lldp_listener) nm_lldp_listener_stop (priv->lldp_listener); @@ -12411,24 +12558,20 @@ _set_state_full (NMDevice *self, if ( (priv->state == state) && ( state != NM_DEVICE_STATE_UNAVAILABLE || !priv->firmware_missing)) { - _LOGD (LOGD_DEVICE, "state change: %s -> %s (reason '%s') [%d %d %d]%s", - state_to_string (old_state), - state_to_string (state), + _LOGD (LOGD_DEVICE, "state change: %s -> %s (reason '%s', internal state '%s'%s)", + nm_device_state_to_str (old_state), + nm_device_state_to_str (state), reason_to_string (reason), - old_state, - state, - reason, - priv->firmware_missing ? " (missing firmware)" : ""); + _sys_iface_state_to_str (priv->sys_iface_state), + priv->firmware_missing ? ", missing firmware" : ""); return; } - _LOGI (LOGD_DEVICE, "state change: %s -> %s (reason '%s') [%d %d %d]", - state_to_string (old_state), - state_to_string (state), + _LOGI (LOGD_DEVICE, "state change: %s -> %s (reason '%s', internal state '%s')", + nm_device_state_to_str (old_state), + nm_device_state_to_str (state), reason_to_string (reason), - old_state, - state, - reason); + _sys_iface_state_to_str (priv->sys_iface_state)); priv->in_state_changed = TRUE; @@ -12453,6 +12596,9 @@ _set_state_full (NMDevice *self, NM_DEVICE_SYS_IFACE_STATE_ASSUME)) nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); + if (state > NM_DEVICE_STATE_DISCONNECTED) + nm_device_assume_state_reset (self); + if (state <= NM_DEVICE_STATE_UNAVAILABLE) { if (available_connections_del_all (self)) _notify (self, PROP_AVAILABLE_CONNECTIONS); @@ -12745,7 +12891,7 @@ queued_state_set (gpointer user_data) nm_assert (priv->queued_state.id); _LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", - state_to_string (priv->queued_state.state), + nm_device_state_to_str (priv->queued_state.state), reason_to_string (priv->queued_state.reason), priv->queued_state.id, "change state"); @@ -12776,7 +12922,7 @@ nm_device_queue_state (NMDevice *self, if (priv->queued_state.id && priv->queued_state.state == state) { _LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s%s%s%s", - state_to_string (priv->queued_state.state), + nm_device_state_to_str (priv->queued_state.state), reason_to_string (priv->queued_state.reason), priv->queued_state.id, "ignore queuing same state change", @@ -12792,7 +12938,7 @@ nm_device_queue_state (NMDevice *self, /* We should only ever have one delayed state transition at a time */ if (priv->queued_state.id) { _LOGW (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", - state_to_string (priv->queued_state.state), + nm_device_state_to_str (priv->queued_state.state), reason_to_string (priv->queued_state.reason), priv->queued_state.id, "replace previously queued state change"); @@ -12805,7 +12951,7 @@ nm_device_queue_state (NMDevice *self, priv->queued_state.id = g_idle_add (queued_state_set, self); _LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", - state_to_string (state), + nm_device_state_to_str (state), reason_to_string (reason), priv->queued_state.id, "queue state change"); @@ -12820,7 +12966,7 @@ queued_state_clear (NMDevice *self) return; _LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", - state_to_string (priv->queued_state.state), + nm_device_state_to_str (priv->queued_state.state), reason_to_string (priv->queued_state.reason), priv->queued_state.id, "clear queued state change"); @@ -13726,6 +13872,8 @@ dispose (GObject *object) nm_clear_g_cancellable (&priv->deactivating_cancellable); + nm_device_assume_state_reset (self); + _parent_set_ifindex (self, 0, FALSE); platform = nm_device_get_platform (self); @@ -13767,7 +13915,7 @@ dispose (GObject *object) nm_clear_g_source (&priv->stats.timeout_id); - link_disconnect_action_cancel (self); + carrier_disconnected_action_cancel (self); if (priv->ifindex > 0) { priv->ifindex = 0; @@ -13782,7 +13930,8 @@ dispose (GObject *object) available_connections_del_all (self); - nm_clear_g_source (&priv->carrier_wait_id); + if (nm_clear_g_source (&priv->carrier_wait_id)) + nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); _clear_queued_act_request (priv); @@ -13854,14 +14003,11 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_UDI: - if (g_value_get_string (value)) { - g_free (priv->udi); - priv->udi = g_value_dup_string (value); - } + /* construct-only */ + priv->udi = g_value_dup_string (value); break; case PROP_IFACE: /* construct-only */ - g_return_if_fail (!priv->iface); priv->iface = g_value_dup_string (value); break; case PROP_DRIVER: @@ -13885,9 +14031,14 @@ set_property (GObject *object, guint prop_id, NMDeviceStateReason reason; managed = g_value_get_boolean (value); - if (managed) + if (managed) { reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; - else { + if (NM_IN_SET_TYPED (NMDeviceSysIfaceState, + priv->sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_REMOVED)) + nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_ASSUME); + } else { reason = NM_DEVICE_STATE_REASON_REMOVED; nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_REMOVED); } @@ -13956,28 +14107,43 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_UDI: - g_value_set_string (value, priv->udi); + /* UDI is (depending on the device type) a path to sysfs and can contain + * non-UTF-8. + * ip link add name $'d\xccf\\c' type dummy */ + g_value_take_string (value, + nm_utils_str_utf8safe_escape_cp (priv->udi, + NM_UTILS_STR_UTF8_SAFE_FLAG_NONE)); break; case PROP_IFACE: - g_value_set_string (value, priv->iface); + g_value_take_string (value, + nm_utils_str_utf8safe_escape_cp (priv->iface, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); break; case PROP_IP_IFACE: - if (ip_config_valid (priv->state)) - g_value_set_string (value, nm_device_get_ip_iface (self)); - else + if (ip_config_valid (priv->state)) { + g_value_take_string (value, + nm_utils_str_utf8safe_escape_cp (nm_device_get_ip_iface (self), + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); + } else g_value_set_string (value, NULL); break; case PROP_IFINDEX: g_value_set_int (value, priv->ifindex); break; case PROP_DRIVER: - g_value_set_string (value, priv->driver); + g_value_take_string (value, + nm_utils_str_utf8safe_escape_cp (priv->driver, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); break; case PROP_DRIVER_VERSION: - g_value_set_string (value, priv->driver_version); + g_value_take_string (value, + nm_utils_str_utf8safe_escape_cp (priv->driver_version, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); break; case PROP_FIRMWARE_VERSION: - g_value_set_string (value, priv->firmware_version); + g_value_take_string (value, + nm_utils_str_utf8safe_escape_cp (priv->firmware_version, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); break; case PROP_CAPABILITIES: g_value_set_uint (value, (priv->capabilities & ~NM_DEVICE_CAP_INTERNAL_MASK)); @@ -14161,7 +14327,7 @@ 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->carrier_changed = carrier_changed; + klass->carrier_changed_notify = carrier_changed_notify; 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; @@ -14172,7 +14338,7 @@ nm_device_class_init (NMDeviceClass *klass) obj_properties[PROP_UDI] = g_param_spec_string (NM_DEVICE_UDI, "", "", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_IFACE] = g_param_spec_string (NM_DEVICE_IFACE, "", "", |