diff options
Diffstat (limited to 'src/devices/nm-device.c')
| -rw-r--r-- | src/devices/nm-device.c | 30347 |
1 files changed, 15331 insertions, 15016 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index eb0d4d52..2dab5075 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2005 - 2018 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. @@ -28,6 +28,8 @@ #include "nm-libnm-core-intern/nm-ethtool-utils.h" #include "nm-libnm-core-intern/nm-common-macros.h" #include "nm-device-private.h" +#include "nm-l3cfg.h" +#include "nm-l3-config-data.h" #include "NetworkManagerUtils.h" #include "nm-manager.h" #include "platform/nm-platform.h" @@ -72,27 +74,27 @@ #include "nm-device-wireguard.h" #include "nm-device-logging.h" -_LOG_DECLARE_SELF (NMDevice); +_LOG_DECLARE_SELF(NMDevice); /*****************************************************************************/ -#define DEFAULT_AUTOCONNECT TRUE +#define DEFAULT_AUTOCONNECT TRUE static guint32 -dhcp_grace_period_from_timeout (guint32 timeout) +dhcp_grace_period_from_timeout(guint32 timeout) { #define DHCP_GRACE_PERIOD_MULTIPLIER 2U - nm_assert (timeout > 0); - nm_assert (timeout < G_MAXINT32); + nm_assert(timeout > 0); + nm_assert(timeout < G_MAXINT32); - if (timeout < G_MAXUINT32 / DHCP_GRACE_PERIOD_MULTIPLIER) - return timeout * DHCP_GRACE_PERIOD_MULTIPLIER; + if (timeout < G_MAXUINT32 / DHCP_GRACE_PERIOD_MULTIPLIER) + return timeout * DHCP_GRACE_PERIOD_MULTIPLIER; - return G_MAXUINT32; + return G_MAXUINT32; } -#define CARRIER_WAIT_TIME_MS 6000 +#define CARRIER_WAIT_TIME_MS 6000 #define CARRIER_WAIT_TIME_AFTER_MTU_MS 10000 #define NM_DEVICE_AUTH_RETRIES_UNSET -1 @@ -101,1651 +103,2722 @@ dhcp_grace_period_from_timeout (guint32 timeout) /*****************************************************************************/ -typedef void (*ActivationHandleFunc) (NMDevice *self); +typedef void (*ActivationHandleFunc)(NMDevice *self); typedef enum { - CLEANUP_TYPE_KEEP, - CLEANUP_TYPE_REMOVED, - CLEANUP_TYPE_DECONFIGURE, + CLEANUP_TYPE_KEEP, + CLEANUP_TYPE_REMOVED, + CLEANUP_TYPE_DECONFIGURE, } CleanupType; typedef struct { - CList lst_slave; - NMDevice *slave; - gulong watch_id; - bool slave_is_enslaved; - bool configure; + CList lst_slave; + NMDevice *slave; + gulong watch_id; + bool slave_is_enslaved; + bool configure; } SlaveInfo; typedef struct { - NMDevice *device; - guint idle_add_id; - int ifindex; + NMDevice *device; + guint idle_add_id; + int ifindex; } DeleteOnDeactivateData; typedef struct { - NMDevice *device; - GCancellable *cancellable; - NMPlatformAsyncCallback callback; - gpointer callback_data; - guint num_vfs; - NMTernary autoprobe; + NMDevice * device; + GCancellable * cancellable; + NMPlatformAsyncCallback callback; + gpointer callback_data; + guint num_vfs; + NMTernary autoprobe; } SriovOp; -typedef void (*AcdCallback) (NMDevice *, NMIP4Config **, gboolean); +typedef void (*AcdCallback)(NMDevice *, NMIP4Config **, gboolean); + +typedef enum { + /* The various NML3ConfigData types that we track explicitly. Note that + * their relative order matters: higher numbers in this enum means more + * important (and during merge overwrites other settings). */ + L3_CONFIG_DATA_TYPE_LL_4, + L3_CONFIG_DATA_TYPE_AC_6, + L3_CONFIG_DATA_TYPE_DHCP_4, + L3_CONFIG_DATA_TYPE_DHCP_6, + L3_CONFIG_DATA_TYPE_DEV_4, + L3_CONFIG_DATA_TYPE_DEV_6, + L3_CONFIG_DATA_TYPE_SETTING, + _L3_CONFIG_DATA_TYPE_NUM, + _L3_CONFIG_DATA_TYPE_NONE, +} L3ConfigDataType; typedef struct { - AcdCallback callback; - NMDevice *device; - NMIP4Config **configs; + AcdCallback callback; + NMDevice * device; + NMIP4Config **configs; } AcdData; typedef enum { - HW_ADDR_TYPE_UNSET = 0, - HW_ADDR_TYPE_PERMANENT, - HW_ADDR_TYPE_EXPLICIT, - HW_ADDR_TYPE_GENERATED, + HW_ADDR_TYPE_UNSET = 0, + HW_ADDR_TYPE_PERMANENT, + HW_ADDR_TYPE_EXPLICIT, + HW_ADDR_TYPE_GENERATED, } HwAddrType; typedef enum { - FIREWALL_STATE_UNMANAGED = 0, - FIREWALL_STATE_INITIALIZED, - FIREWALL_STATE_WAIT_STAGE_3, - FIREWALL_STATE_WAIT_IP_CONFIG, + FIREWALL_STATE_UNMANAGED = 0, + FIREWALL_STATE_INITIALIZED, + FIREWALL_STATE_WAIT_STAGE_3, + FIREWALL_STATE_WAIT_IP_CONFIG, } FirewallState; typedef struct { - NMIPConfig *orig; /* the original configuration applied to the device */ - NMIPConfig *current; /* configuration after external changes. NULL means - that the original configuration didn't change. */ + NMIPConfig *orig; /* the original configuration applied to the device */ + NMIPConfig *current; /* configuration after external changes. NULL means + * that the original configuration didn't change. */ } AppliedConfig; typedef struct { - NMDhcpClient *client; - NMDhcpConfig *config; - gulong state_sigid; - guint grace_id; - bool grace_pending:1; - bool was_active:1; + NMDhcpClient *client; + NMDhcpConfig *config; + gulong state_sigid; + guint grace_id; + bool grace_pending : 1; + bool was_active : 1; } DhcpData; struct _NMDeviceConnectivityHandle { - CList concheck_lst; - NMDevice *self; - NMDeviceConnectivityCallback callback; - gpointer user_data; - NMConnectivityCheckHandle *c_handle; - guint64 seq; - bool is_periodic:1; - bool is_periodic_bump:1; - bool is_periodic_bump_on_complete:1; - int addr_family; + CList concheck_lst; + NMDevice * self; + NMDeviceConnectivityCallback callback; + gpointer user_data; + NMConnectivityCheckHandle * c_handle; + guint64 seq; + bool is_periodic : 1; + bool is_periodic_bump : 1; + bool is_periodic_bump_on_complete : 1; + int addr_family; }; typedef struct { - int ifindex; - NMEthtoolFeatureStates *features; - NMTernary requested[_NM_ETHTOOL_ID_FEATURE_NUM]; - NMEthtoolCoalesceState *coalesce; - NMEthtoolRingState *ring; + int ifindex; + NMEthtoolFeatureStates *features; + NMTernary requested[_NM_ETHTOOL_ID_FEATURE_NUM]; + NMEthtoolCoalesceState *coalesce; + NMEthtoolRingState * ring; } EthtoolState; /*****************************************************************************/ enum { - STATE_CHANGED, - AUTOCONNECT_ALLOWED, - IP4_CONFIG_CHANGED, - IP6_CONFIG_CHANGED, - IP6_PREFIX_DELEGATED, - IP6_SUBNET_NEEDED, - REMOVED, - RECHECK_AUTO_ACTIVATE, - RECHECK_ASSUME, - LAST_SIGNAL, + STATE_CHANGED, + AUTOCONNECT_ALLOWED, + IP4_CONFIG_CHANGED, + IP6_CONFIG_CHANGED, + IP6_PREFIX_DELEGATED, + IP6_SUBNET_NEEDED, + REMOVED, + RECHECK_AUTO_ACTIVATE, + RECHECK_ASSUME, + LAST_SIGNAL, }; -static guint signals[LAST_SIGNAL] = { 0 }; - -NM_GOBJECT_PROPERTIES_DEFINE (NMDevice, - PROP_UDI, - PROP_PATH, - PROP_IFACE, - PROP_IP_IFACE, - PROP_DRIVER, - PROP_DRIVER_VERSION, - PROP_FIRMWARE_VERSION, - PROP_CAPABILITIES, - PROP_CARRIER, - PROP_MTU, - PROP_IP4_ADDRESS, - PROP_IP4_CONFIG, - PROP_DHCP4_CONFIG, - PROP_IP6_CONFIG, - PROP_DHCP6_CONFIG, - PROP_STATE, - PROP_STATE_REASON, - PROP_ACTIVE_CONNECTION, - PROP_DEVICE_TYPE, - PROP_LINK_TYPE, - PROP_MANAGED, - PROP_AUTOCONNECT, - PROP_FIRMWARE_MISSING, - PROP_NM_PLUGIN_MISSING, - PROP_TYPE_DESC, - PROP_RFKILL_TYPE, - PROP_IFINDEX, - PROP_AVAILABLE_CONNECTIONS, - PROP_PHYSICAL_PORT_ID, - PROP_MASTER, - PROP_PARENT, - PROP_HW_ADDRESS, - PROP_PERM_HW_ADDRESS, - PROP_HAS_PENDING_ACTION, - PROP_METERED, - PROP_LLDP_NEIGHBORS, - PROP_REAL, - PROP_SLAVES, - PROP_STATISTICS_REFRESH_RATE_MS, - PROP_STATISTICS_TX_BYTES, - PROP_STATISTICS_RX_BYTES, - PROP_IP4_CONNECTIVITY, - PROP_IP6_CONNECTIVITY, - PROP_INTERFACE_FLAGS, -); +static guint signals[LAST_SIGNAL] = {0}; + +NM_GOBJECT_PROPERTIES_DEFINE(NMDevice, + PROP_UDI, + PROP_PATH, + PROP_IFACE, + PROP_IP_IFACE, + PROP_DRIVER, + PROP_DRIVER_VERSION, + PROP_FIRMWARE_VERSION, + PROP_CAPABILITIES, + PROP_CARRIER, + PROP_MTU, + PROP_IP4_ADDRESS, + PROP_IP4_CONFIG, + PROP_DHCP4_CONFIG, + PROP_IP6_CONFIG, + PROP_DHCP6_CONFIG, + PROP_STATE, + PROP_STATE_REASON, + PROP_ACTIVE_CONNECTION, + PROP_DEVICE_TYPE, + PROP_LINK_TYPE, + PROP_MANAGED, + PROP_AUTOCONNECT, + PROP_FIRMWARE_MISSING, + PROP_NM_PLUGIN_MISSING, + PROP_TYPE_DESC, + PROP_RFKILL_TYPE, + PROP_IFINDEX, + PROP_AVAILABLE_CONNECTIONS, + PROP_PHYSICAL_PORT_ID, + PROP_MASTER, + PROP_PARENT, + PROP_HW_ADDRESS, + PROP_PERM_HW_ADDRESS, + PROP_HAS_PENDING_ACTION, + PROP_METERED, + PROP_LLDP_NEIGHBORS, + PROP_REAL, + PROP_SLAVES, + PROP_STATISTICS_REFRESH_RATE_MS, + PROP_STATISTICS_TX_BYTES, + PROP_STATISTICS_RX_BYTES, + PROP_IP4_CONNECTIVITY, + PROP_IP6_CONNECTIVITY, + PROP_INTERFACE_FLAGS, ); typedef struct _NMDevicePrivate { - bool in_state_changed; - - guint device_link_changed_id; - guint device_ip_link_changed_id; - - NMDeviceState state; - NMDeviceStateReason state_reason; - struct { - guint id; - - /* The @state/@reason is only valid, when @id is set. */ - NMDeviceState state; - NMDeviceStateReason reason; - } queued_state; - - union { - struct { - guint queued_ip_config_id_6; - guint queued_ip_config_id_4; - }; - guint queued_ip_config_id_x[2]; - }; - - GSList *pending_actions; - GSList *dad6_failed_addrs; - - NMDBusTrackObjPath parent_device; - - char * udi; - char * path; - char * iface; /* may change, could be renamed by user */ - int ifindex; - - int parent_ifindex; - - int auth_retries; - - union { - const guint8 hw_addr_len; /* read-only */ - guint8 hw_addr_len_; - }; - - HwAddrType hw_addr_type:5; - - bool real:1; - - bool update_ip_config_completed_v4:1; - bool update_ip_config_completed_v6:1; - - char * ip_iface; - int ip_ifindex; - NMDeviceType type; - char * type_desc; - NMLinkType link_type; - NMDeviceCapabilities capabilities; - char * driver; - char * driver_version; - char * firmware_version; - RfKillType rfkill_type; - bool firmware_missing:1; - bool nm_plugin_missing:1; - bool hw_addr_perm_fake:1; /* whether the permanent HW address could not be read and is a fake */ - - NMUtilsStableType current_stable_id_type:3; - - 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; - char * hw_addr_perm; - char * hw_addr_initial; - char * physical_port_id; - guint dev_id; - - NMUnmanagedFlags unmanaged_mask; - NMUnmanagedFlags unmanaged_flags; - DeleteOnDeactivateData *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */ - - GCancellable *deactivating_cancellable; - - guint32 ip4_address; + bool in_state_changed; + + guint device_link_changed_id; + guint device_ip_link_changed_id; + + NMDeviceState state; + NMDeviceStateReason state_reason; + struct { + guint id; + + /* The @state/@reason is only valid, when @id is set. */ + NMDeviceState state; + NMDeviceStateReason reason; + } queued_state; + + union { + struct { + guint queued_ip_config_id_6; + guint queued_ip_config_id_4; + }; + guint queued_ip_config_id_x[2]; + }; + + GSList *pending_actions; + GSList *dad6_failed_addrs; + + NMDBusTrackObjPath parent_device; + + char *udi; + char *path; + + union { + const char *const iface; + char * iface_; + }; + union { + const char *const ip_iface; + char * ip_iface_; + }; + + union { + const int ifindex; + int ifindex_; + }; + union { + const int ip_ifindex; + int ip_ifindex_; + }; + + NMNetnsSharedIPHandle *shared_ip_handle; + + int parent_ifindex; + + int auth_retries; + + union { + const guint8 hw_addr_len; /* read-only */ + guint8 hw_addr_len_; + }; + + HwAddrType hw_addr_type : 5; + + bool real : 1; + + bool update_ip_config_completed_v4 : 1; + bool update_ip_config_completed_v6 : 1; + + NMDeviceType type; + char * type_desc; + NMLinkType link_type; + NMDeviceCapabilities capabilities; + char * driver; + char * driver_version; + char * firmware_version; + RfKillType rfkill_type; + bool firmware_missing : 1; + bool nm_plugin_missing : 1; + bool + hw_addr_perm_fake : 1; /* whether the permanent HW address could not be read and is a fake */ + + NMUtilsStableType current_stable_id_type : 3; + + 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; + char * hw_addr_perm; + char * hw_addr_initial; + char * physical_port_id; + guint dev_id; + + NMUnmanagedFlags unmanaged_mask; + NMUnmanagedFlags unmanaged_flags; + DeleteOnDeactivateData + *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */ + + GCancellable *deactivating_cancellable; + + NMActRequest * queued_act_request; + bool queued_act_request_is_waiting_for_carrier : 1; + NMDBusTrackObjPath act_request; + + union { + struct { + guint activation_source_id_6; + guint activation_source_id_4; /* for layer2 and IPv4. */ + }; + guint activation_source_id_x[2]; + }; + + union { + struct { + ActivationHandleFunc activation_source_func_6; + ActivationHandleFunc activation_source_func_4; /* for layer2 and IPv4. */ + }; + ActivationHandleFunc activation_source_func_x[2]; + }; + + guint recheck_assume_id; + + struct { + guint call_id; + NMDeviceStateReason available_reason; + NMDeviceStateReason unavailable_reason; + } recheck_available; + + struct { + NMDispatcherCallId *call_id; + NMDeviceState post_state; + NMDeviceStateReason post_state_reason; + } dispatcher; + + /* Link stuff */ + guint link_connected_id; + guint link_disconnected_id; + guint carrier_defer_id; + guint carrier_wait_id; + gulong config_changed_id; + guint32 mtu; + guint32 ip6_mtu; + guint32 mtu_initial; + guint32 ip6_mtu_initial; + NMDeviceMtuSource mtu_source; + + guint32 v4_route_table; + guint32 v6_route_table; + + /* when carrier goes away, we give a grace period of _get_carrier_wait_ms() + * until taking action. + * + * When changing MTU, the device might take longer then that. So, whenever + * NM changes the MTU it sets @carrier_wait_until_ms to CARRIER_WAIT_TIME_AFTER_MTU_MS + * in the future. This is used to extend the grace period in this particular case. */ + gint64 carrier_wait_until_ms; + + union { + const NMDeviceSysIfaceState sys_iface_state; + NMDeviceSysIfaceState sys_iface_state_; + }; + + bool carrier : 1; + bool ignore_carrier : 1; + + bool up : 1; /* IFF_UP */ + + bool v4_commit_first_time : 1; + bool v6_commit_first_time : 1; + + bool default_route_metric_penalty_ip4_has : 1; + bool default_route_metric_penalty_ip6_has : 1; + + bool v4_route_table_initialized : 1; + bool v6_route_table_initialized : 1; + + bool l3config_merge_flags_has : 1; + + bool v4_route_table_all_sync_before : 1; + bool v6_route_table_all_sync_before : 1; + + NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags : 5; + + bool is_enslaved : 1; + + bool ipv6ll_handle : 1; /* TRUE if NM handles the device's IPv6LL address */ + bool ipv6ll_has : 1; + bool ndisc_started : 1; + bool device_link_changed_down : 1; + + bool concheck_rp_filter_checked : 1; + + NMDeviceStageState stage1_sriov_state : 3; + + /* Generic DHCP stuff */ + char *dhcp_anycast_address; + + char *current_stable_id; + + /* Proxy Configuration */ + NMProxyConfig * proxy_config; + NMPacrunnerConfId *pacrunner_conf_id; + + /* IP configuration info. Combined config from VPN, settings, and device */ + union { + struct { + NMIP6Config *ip_config_6; + NMIP4Config *ip_config_4; + }; + NMIPConfig *ip_config_x[2]; + }; + + /* Config from DHCP, PPP, LLv4, etc */ + AppliedConfig dev_ip_config_4; + + /* config from the setting */ + union { + struct { + NMIP6Config *con_ip_config_6; + NMIP4Config *con_ip_config_4; + }; + NMIPConfig *con_ip_config_x[2]; + }; + + /* Stuff added outside NM */ + union { + struct { + NMIP6Config *ext_ip_config_6; + NMIP4Config *ext_ip_config_4; + }; + NMIPConfig *ext_ip_config_x[2]; + }; + + /* VPNs which use this device */ + union { + struct { + GSList *vpn_configs_6; + GSList *vpn_configs_4; + }; + GSList *vpn_configs_x[2]; + }; + + /* Extra device configuration, injected by the subclass of NMDevice. + * This is used for example by NMDeviceModem for WWAN configuration. */ + union { + struct { + AppliedConfig dev2_ip_config_6; + AppliedConfig dev2_ip_config_4; + }; + AppliedConfig dev2_ip_config_x[2]; + }; + + /* DHCPv4 tracking */ + struct { + char *pac_url; + } dhcp4; + + struct { + /* IP6 config from DHCP */ + AppliedConfig ip6_config; + /* Event ID of the current IP6 config from DHCP */ + char * event_id; + gulong prefix_sigid; + NMNDiscDHCPLevel mode; + guint needed_prefixes; + } dhcp6; + + union { + struct { + DhcpData dhcp_data_6; + DhcpData dhcp_data_4; + }; + DhcpData dhcp_data_x[2]; + }; + + struct { + NMLogDomain log_domain; + guint timeout; + guint watch; + GPid pid; + char * binary; + char * address; + guint deadline; + } gw_ping; + + /* dnsmasq stuff for shared connections */ + NMDnsMasqManager *dnsmasq_manager; + gulong dnsmasq_state_id; + + /* Firewall */ + FirewallState fw_state : 4; + NMFirewallManager * fw_mgr; + NMFirewallManagerCallId *fw_call; + + /* IPv4LL stuff */ + sd_ipv4ll *ipv4ll; + guint ipv4ll_timeout; + guint rt6_temporary_not_available_id; + + /* IPv4 DAD stuff */ + struct { + GSList * dad_list; + NMAcdManager *announcing; + } acd; + + union { + struct { + const NMDeviceIPState ip_state_6; + const NMDeviceIPState ip_state_4; + }; + union { + const NMDeviceIPState ip_state_x[2]; + NMDeviceIPState ip_state_x_[2]; + }; + }; + + AppliedConfig ac_ip6_config; /* config from IPv6 autoconfiguration */ + NMIP6Config * ext_ip6_config_captured; /* Configuration captured from platform. */ + NMIP6Config * dad6_ip6_config; + struct in6_addr ipv6ll_addr; + + GHashTable *rt6_temporary_not_available; + + NMNDisc * ndisc; + gulong ndisc_changed_id; + gulong ndisc_timeout_id; + NMSettingIP6ConfigPrivacy ndisc_use_tempaddr; + + guint linklocal6_timeout_id; + guint8 linklocal6_dad_counter; + + GHashTable *ip6_saved_properties; + + EthtoolState *ethtool_state; + + gboolean needs_ip6_subnet; + + /* master interface for bridge/bond/team slave */ + NMDevice *master; + gulong master_ready_id; + + /* slave management */ + CList slaves; /* list of SlaveInfo */ + + NMMetered metered; + + NMSettings *settings; + NMManager * manager; + + NMNetns *netns; + + NMLldpListener *lldp_listener; + + NMConnectivity *concheck_mgr; + CList concheck_lst_head; + struct { + /* if periodic checks are enabled, this is the source id for the next check. */ + guint p_cur_id; + + /* the currently configured max periodic interval. */ + guint p_max_interval; + + /* the current interval. If we are probing, the interval might be lower + * then the configured max interval. */ + guint p_cur_interval; + + /* the timestamp, when we last scheduled the timer p_cur_id with current interval + * p_cur_interval. */ + gint64 p_cur_basetime_ns; + + NMConnectivityState state; + } concheck_x[2]; + + guint check_delete_unrealized_id; + guint32 interface_flags; + + struct { + SriovOp *pending; /* SR-IOV operation currently running */ + SriovOp *next; /* next SR-IOV operation scheduled */ + } sriov; + guint sriov_reset_pending; - NMActRequest * queued_act_request; - bool queued_act_request_is_waiting_for_carrier:1; - NMDBusTrackObjPath act_request; - - union { - struct { - guint activation_source_id_6; - guint activation_source_id_4; /* for layer2 and IPv4. */ - }; - guint activation_source_id_x[2]; - }; - - union { - struct { - ActivationHandleFunc activation_source_func_6; - ActivationHandleFunc activation_source_func_4; /* for layer2 and IPv4. */ - }; - ActivationHandleFunc activation_source_func_x[2]; - }; - - guint recheck_assume_id; - - struct { - guint call_id; - NMDeviceStateReason available_reason; - NMDeviceStateReason unavailable_reason; - } recheck_available; - - struct { - NMDispatcherCallId *call_id; - NMDeviceState post_state; - NMDeviceStateReason post_state_reason; - } dispatcher; - - /* Link stuff */ - guint link_connected_id; - guint link_disconnected_id; - guint carrier_defer_id; - guint carrier_wait_id; - gulong config_changed_id; - guint32 mtu; - guint32 ip6_mtu; - guint32 mtu_initial; - guint32 ip6_mtu_initial; - NMDeviceMtuSource mtu_source; - - guint32 v4_route_table; - guint32 v6_route_table; - - /* when carrier goes away, we give a grace period of _get_carrier_wait_ms() - * until taking action. - * - * When changing MTU, the device might take longer then that. So, whenever - * NM changes the MTU it sets @carrier_wait_until_ms to CARRIER_WAIT_TIME_AFTER_MTU_MS - * in the future. This is used to extend the grace period in this particular case. */ - gint64 carrier_wait_until_ms; - - bool carrier:1; - bool ignore_carrier:1; - - bool up:1; /* IFF_UP */ - - bool v4_commit_first_time:1; - bool v6_commit_first_time:1; - - bool default_route_metric_penalty_ip4_has:1; - bool default_route_metric_penalty_ip6_has:1; - - NMDeviceSysIfaceState sys_iface_state:2; - - bool v4_route_table_initialized:1; - bool v6_route_table_initialized:1; - - bool v4_route_table_all_sync_before:1; - bool v6_route_table_all_sync_before:1; - - NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags:5; - - bool is_enslaved:1; - - bool ipv6ll_handle:1; /* TRUE if NM handles the device's IPv6LL address */ - bool ipv6ll_has:1; - bool ndisc_started:1; - bool device_link_changed_down:1; - - bool concheck_rp_filter_checked:1; - - NMDeviceStageState stage1_sriov_state:3; - - /* Generic DHCP stuff */ - char * dhcp_anycast_address; - - char * current_stable_id; - - /* Proxy Configuration */ - NMProxyConfig *proxy_config; - NMPacrunnerConfId *pacrunner_conf_id; - - /* IP configuration info. Combined config from VPN, settings, and device */ - union { - struct { - NMIP6Config *ip_config_6; - NMIP4Config *ip_config_4; - }; - NMIPConfig *ip_config_x[2]; - }; - - /* Config from DHCP, PPP, LLv4, etc */ - AppliedConfig dev_ip_config_4; - - /* config from the setting */ - union { - struct { - NMIP6Config *con_ip_config_6; - NMIP4Config *con_ip_config_4; - }; - NMIPConfig *con_ip_config_x[2]; - }; - - /* Stuff added outside NM */ - union { - struct { - NMIP6Config *ext_ip_config_6; - NMIP4Config *ext_ip_config_4; - }; - NMIPConfig *ext_ip_config_x[2]; - }; - - /* VPNs which use this device */ - union { - struct { - GSList *vpn_configs_6; - GSList *vpn_configs_4; - }; - GSList *vpn_configs_x[2]; - }; - - /* Extra device configuration, injected by the subclass of NMDevice. - * This is used for example by NMDeviceModem for WWAN configuration. */ - union { - struct { - AppliedConfig dev2_ip_config_6; - AppliedConfig dev2_ip_config_4; - }; - AppliedConfig dev2_ip_config_x[2]; - }; - - /* DHCPv4 tracking */ - struct { - char * pac_url; - char * root_path; - } dhcp4; - - struct { - /* IP6 config from DHCP */ - AppliedConfig ip6_config; - /* Event ID of the current IP6 config from DHCP */ - char * event_id; - gulong prefix_sigid; - NMNDiscDHCPLevel mode; - guint needed_prefixes; - } dhcp6; - - union { - struct { - DhcpData dhcp_data_6; - DhcpData dhcp_data_4; - }; - DhcpData dhcp_data_x[2]; - }; - - struct { - NMLogDomain log_domain; - guint timeout; - guint watch; - GPid pid; - char *binary; - char *address; - guint deadline; - } gw_ping; - - /* dnsmasq stuff for shared connections */ - NMDnsMasqManager *dnsmasq_manager; - gulong dnsmasq_state_id; - - /* Firewall */ - FirewallState fw_state:4; - NMFirewallManager *fw_mgr; - NMFirewallManagerCallId *fw_call; - - /* IPv4LL stuff */ - sd_ipv4ll * ipv4ll; - guint ipv4ll_timeout; - guint rt6_temporary_not_available_id; - - /* IPv4 DAD stuff */ - struct { - GSList * dad_list; - NMAcdManager * announcing; - } acd; - - union { - struct { - const NMDeviceIPState ip_state_6; - const NMDeviceIPState ip_state_4; - }; - union { - const NMDeviceIPState ip_state_x[2]; - NMDeviceIPState ip_state_x_[2]; - }; - }; - - AppliedConfig ac_ip6_config; /* config from IPv6 autoconfiguration */ - NMIP6Config * ext_ip6_config_captured; /* Configuration captured from platform. */ - NMIP6Config * dad6_ip6_config; - struct in6_addr ipv6ll_addr; - - GHashTable * rt6_temporary_not_available; - - NMNDisc * ndisc; - gulong ndisc_changed_id; - gulong ndisc_timeout_id; - NMSettingIP6ConfigPrivacy ndisc_use_tempaddr; - - guint linklocal6_timeout_id; - guint8 linklocal6_dad_counter; - - GHashTable * ip6_saved_properties; - - EthtoolState *ethtool_state; - - gboolean needs_ip6_subnet; - - /* master interface for bridge/bond/team slave */ - NMDevice * master; - gulong master_ready_id; - - /* slave management */ - CList slaves; /* list of SlaveInfo */ - - NMMetered metered; - - NMSettings *settings; - NMManager *manager; - - NMNetns *netns; - - NMLldpListener *lldp_listener; - - NMConnectivity *concheck_mgr; - CList concheck_lst_head; - struct { - /* if periodic checks are enabled, this is the source id for the next check. */ - guint p_cur_id; - - /* the currently configured max periodic interval. */ - guint p_max_interval; - - /* the current interval. If we are probing, the interval might be lower - * then the configured max interval. */ - guint p_cur_interval; - - /* the timestamp, when we last scheduled the timer p_cur_id with current interval - * p_cur_interval. */ - gint64 p_cur_basetime_ns; - - NMConnectivityState state; - } concheck_x[2]; - - guint check_delete_unrealized_id; - guint32 interface_flags; - - struct { - SriovOp *pending; /* SR-IOV operation currently running */ - SriovOp *next; /* next SR-IOV operation scheduled */ - } sriov; - guint sriov_reset_pending; - - struct { - guint timeout_id; - guint refresh_rate_ms; - guint64 tx_bytes; - guint64 rx_bytes; - } stats; + struct { + guint timeout_id; + guint refresh_rate_ms; + guint64 tx_bytes; + guint64 rx_bytes; + } stats; } NMDevicePrivate; -G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) +G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) #define NM_DEVICE_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMDevice, NM_IS_DEVICE) /*****************************************************************************/ static const NMDBusInterfaceInfoExtended interface_info_device; -static const GDBusSignalInfo signal_info_state_changed; - -static void nm_device_set_proxy_config (NMDevice *self, const char *pac_url); - -static gboolean update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_configs); - -static gboolean nm_device_set_ip_config (NMDevice *self, - int addr_family, - NMIPConfig *config, - gboolean commit, - GPtrArray *ip4_dev_route_blacklist); - -static gboolean ip_config_merge_and_apply (NMDevice *self, - int addr_family, - gboolean commit); - -static gboolean nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure); -static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success); -static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason); - -static void addrconf6_start_with_link_ready (NMDevice *self); -static gboolean linklocal6_start (NMDevice *self); - -static void _carrier_wait_check_queued_act_request (NMDevice *self); -static gint64 _get_carrier_wait_ms (NMDevice *self); - -static const char *_activation_func_to_string (ActivationHandleFunc func); - -static void _set_state_full (NMDevice *self, - NMDeviceState state, - NMDeviceStateReason reason, - gboolean quitting); -static void queued_state_clear (NMDevice *device); -static gboolean queued_ip4_config_change (gpointer user_data); -static gboolean queued_ip6_config_change (gpointer user_data); -static void ip_check_ping_watch_cb (GPid pid, int status, gpointer user_data); -static gboolean ip_config_valid (NMDeviceState state); -static NMActStageReturn dhcp4_start (NMDevice *self); -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, - gboolean force_platform_init); -static void _set_mtu (NMDevice *self, guint32 mtu); -static void _commit_mtu (NMDevice *self, const NMIP4Config *config); -static void _cancel_activation (NMDevice *self); - -static void concheck_update_state (NMDevice *self, - int addr_family, - NMConnectivityState state, - gboolean is_periodic); - -static void activate_stage4_ip_config_timeout_4 (NMDevice *self); -static void activate_stage4_ip_config_timeout_6 (NMDevice *self); - -static void (*const activate_stage4_ip_config_timeout_x[2]) (NMDevice *self) = { - activate_stage4_ip_config_timeout_6, - activate_stage4_ip_config_timeout_4, +static const GDBusSignalInfo signal_info_state_changed; + +static void nm_device_set_proxy_config(NMDevice *self, const char *pac_url); + +static gboolean update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs); + +static gboolean nm_device_set_ip_config(NMDevice * self, + int addr_family, + NMIPConfig *config, + gboolean commit, + GPtrArray * ip4_dev_route_blacklist); + +static gboolean ip_config_merge_and_apply(NMDevice *self, int addr_family, gboolean commit); + +static gboolean nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure); +static void nm_device_slave_notify_enslave(NMDevice *self, gboolean success); +static void nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason); + +static void addrconf6_start_with_link_ready(NMDevice *self); +static gboolean linklocal6_start(NMDevice *self); + +static guint32 default_route_metric_penalty_get(NMDevice *self, int addr_family); + +static guint _prop_get_ipv4_dad_timeout(NMDevice *self); + +static void _carrier_wait_check_queued_act_request(NMDevice *self); +static gint64 _get_carrier_wait_ms(NMDevice *self); + +static const char *_activation_func_to_string(ActivationHandleFunc func); + +static void +_set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting); +static void queued_state_clear(NMDevice *device); +static gboolean queued_ip4_config_change(gpointer user_data); +static gboolean queued_ip6_config_change(gpointer user_data); +static void ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data); +static gboolean ip_config_valid(NMDeviceState state); +static NMActStageReturn dhcp4_start(NMDevice *self); +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, + gboolean force_platform_init); +static void _set_mtu(NMDevice *self, guint32 mtu); +static void _commit_mtu(NMDevice *self, const NMIP4Config *config); +static void _cancel_activation(NMDevice *self); + +static void concheck_update_state(NMDevice * self, + int addr_family, + NMConnectivityState state, + gboolean is_periodic); + +static void activate_stage4_ip_config_timeout_4(NMDevice *self); +static void activate_stage4_ip_config_timeout_6(NMDevice *self); + +static void (*const activate_stage4_ip_config_timeout_x[2])(NMDevice *self) = { + activate_stage4_ip_config_timeout_6, + activate_stage4_ip_config_timeout_4, }; -static void sriov_op_cb (GError *error, gpointer user_data); +static void sriov_op_cb(GError *error, gpointer user_data); -static void activate_stage5_ip_config_result_4 (NMDevice *self); -static void activate_stage5_ip_config_result_6 (NMDevice *self); +static void activate_stage5_ip_config_result_4(NMDevice *self); +static void activate_stage5_ip_config_result_6(NMDevice *self); -static void (*const activate_stage5_ip_config_result_x[2]) (NMDevice *self) = { - activate_stage5_ip_config_result_6, - activate_stage5_ip_config_result_4, +static void (*const activate_stage5_ip_config_result_x[2])(NMDevice *self) = { + activate_stage5_ip_config_result_6, + activate_stage5_ip_config_result_4, }; /*****************************************************************************/ -static -NM_UTILS_LOOKUP_STR_DEFINE (queued_state_to_string, NMDeviceState, - NM_UTILS_LOOKUP_DEFAULT ( NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "???"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_UNKNOWN, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_UNMANAGED, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unmanaged"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_UNAVAILABLE, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unavailable"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_DISCONNECTED, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "disconnected"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_PREPARE, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "prepare"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_CONFIG, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "config"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_NEED_AUTH, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "need-auth"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_IP_CONFIG, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-config"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_IP_CHECK, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-check"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_SECONDARIES, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "secondaries"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_ACTIVATED, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "activated"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_DEACTIVATING, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "deactivating"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_FAILED, NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "failed"), -); +static NM_UTILS_LOOKUP_STR_DEFINE( + queued_state_to_string, + NMDeviceState, + NM_UTILS_LOOKUP_DEFAULT(NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "???"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNKNOWN, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNMANAGED, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unmanaged"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNAVAILABLE, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unavailable"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_DISCONNECTED, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "disconnected"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_PREPARE, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "prepare"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_CONFIG, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "config"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_NEED_AUTH, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "need-auth"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_IP_CONFIG, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-config"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_IP_CHECK, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-check"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_SECONDARIES, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "secondaries"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_ACTIVATED, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "activated"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_DEACTIVATING, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "deactivating"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_FAILED, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "failed"), ); const char * -nm_device_state_to_str (NMDeviceState state) -{ - return queued_state_to_string (state) + NM_STRLEN (NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE); -} - -NM_UTILS_LOOKUP_STR_DEFINE (nm_device_state_reason_to_str, NMDeviceStateReason, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_UNKNOWN, "unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NOW_MANAGED, "managed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NOW_UNMANAGED, "unmanaged"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_CONFIG_FAILED, "config-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE, "ip-config-unavailable"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED, "ip-config-expired"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NO_SECRETS, "no-secrets"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT, "supplicant-disconnect"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED, "supplicant-config-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED, "supplicant-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT, "supplicant-timeout"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PPP_START_FAILED, "ppp-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PPP_DISCONNECT, "ppp-disconnect"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PPP_FAILED, "ppp-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DHCP_START_FAILED, "dhcp-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DHCP_ERROR, "dhcp-error"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DHCP_FAILED, "dhcp-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SHARED_START_FAILED, "sharing-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SHARED_FAILED, "sharing-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED, "autoip-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_AUTOIP_ERROR, "autoip-error"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_AUTOIP_FAILED, "autoip-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_BUSY, "modem-busy"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE, "modem-no-dialtone"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER, "modem-no-carrier"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT, "modem-dial-timeout"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED, "modem-dial-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED, "modem-init-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_APN_FAILED, "gsm-apn-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING, "gsm-registration-idle"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED, "gsm-registration-denied"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT, "gsm-registration-timeout"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED, "gsm-registration-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED, "gsm-pin-check-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_FIRMWARE_MISSING, "firmware-missing"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_REMOVED, "removed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SLEEPING, "sleeping"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, "connection-removed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_USER_REQUESTED, "user-requested"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_CARRIER, "carrier-changed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED, "connection-assumed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, "supplicant-available"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND, "modem-not-found"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_BT_FAILED, "bluetooth-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED, "gsm-sim-not-inserted"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED, "gsm-sim-pin-required"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED, "gsm-sim-puk-required"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_GSM_SIM_WRONG, "gsm-sim-wrong"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_INFINIBAND_MODE, "infiniband-mode"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED, "dependency-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_BR2684_FAILED, "br2684-bridge-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE, "modem-manager-unavailable"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SSID_NOT_FOUND, "ssid-not-found"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED, "secondary-connection-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED, "dcb-fcoe-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED, "teamd-control-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_FAILED, "modem-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, "modem-available"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT, "sim-pin-incorrect"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_NEW_ACTIVATION, "new-activation"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PARENT_CHANGED, "parent-changed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED, "parent-managed-changed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_OVSDB_FAILED, "ovsdb-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, "sriov-configuration-failed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, "peer-not-found"), -); - -#define reason_to_string_a(reason) NM_UTILS_LOOKUP_STR_A (nm_device_state_reason_to_str, reason) - -static -NM_UTILS_LOOKUP_STR_DEFINE (mtu_source_to_str, NMDeviceMtuSource, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_MTU_SOURCE_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_MTU_SOURCE_PARENT, "parent"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_MTU_SOURCE_IP_CONFIG, "ip-config"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_MTU_SOURCE_CONNECTION, "connection"), -); +nm_device_state_to_str(NMDeviceState state) +{ + return queued_state_to_string(state) + NM_STRLEN(NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE); +} + +NM_UTILS_LOOKUP_STR_DEFINE( + nm_device_state_reason_to_str, + NMDeviceStateReason, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNKNOWN, "unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NOW_MANAGED, "managed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NOW_UNMANAGED, "unmanaged"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONFIG_FAILED, "config-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE, "ip-config-unavailable"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED, "ip-config-expired"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NO_SECRETS, "no-secrets"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT, "supplicant-disconnect"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED, + "supplicant-config-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED, "supplicant-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT, "supplicant-timeout"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_START_FAILED, "ppp-start-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_DISCONNECT, "ppp-disconnect"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_FAILED, "ppp-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_START_FAILED, "dhcp-start-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_ERROR, "dhcp-error"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_FAILED, "dhcp-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SHARED_START_FAILED, "sharing-start-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SHARED_FAILED, "sharing-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED, "autoip-start-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_ERROR, "autoip-error"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_FAILED, "autoip-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_BUSY, "modem-busy"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE, "modem-no-dialtone"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER, "modem-no-carrier"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT, "modem-dial-timeout"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED, "modem-dial-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED, "modem-init-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_APN_FAILED, "gsm-apn-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING, + "gsm-registration-idle"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED, + "gsm-registration-denied"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT, + "gsm-registration-timeout"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED, + "gsm-registration-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED, "gsm-pin-check-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_FIRMWARE_MISSING, "firmware-missing"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_REMOVED, "removed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SLEEPING, "sleeping"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, "connection-removed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_USER_REQUESTED, "user-requested"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CARRIER, "carrier-changed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED, "connection-assumed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, "supplicant-available"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND, "modem-not-found"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_BT_FAILED, "bluetooth-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED, "gsm-sim-not-inserted"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED, "gsm-sim-pin-required"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED, "gsm-sim-puk-required"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_WRONG, "gsm-sim-wrong"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_INFINIBAND_MODE, "infiniband-mode"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED, "dependency-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_BR2684_FAILED, "br2684-bridge-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE, + "modem-manager-unavailable"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SSID_NOT_FOUND, "ssid-not-found"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED, + "secondary-connection-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED, "dcb-fcoe-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED, "teamd-control-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_FAILED, "modem-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, "modem-available"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT, "sim-pin-incorrect"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NEW_ACTIVATION, "new-activation"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PARENT_CHANGED, "parent-changed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED, + "parent-managed-changed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_OVSDB_FAILED, "ovsdb-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, + "sriov-configuration-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, "peer-not-found"), ); + +#define reason_to_string_a(reason) NM_UTILS_LOOKUP_STR_A(nm_device_state_reason_to_str, reason) + +static NM_UTILS_LOOKUP_STR_DEFINE(mtu_source_to_str, + NMDeviceMtuSource, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_PARENT, "parent"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_IP_CONFIG, + "ip-config"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_CONNECTION, + "connection"), ); + +/*****************************************************************************/ + +static NMSettingIP6ConfigPrivacy +_ip6_privacy_clamp(NMSettingIP6ConfigPrivacy use_tempaddr) +{ + switch (use_tempaddr) { + case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: + return use_tempaddr; + default: + return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + } +} + +/*****************************************************************************/ + +static const char * +_prop_get_connection_stable_id(NMDevice * self, + NMConnection * connection, + NMUtilsStableType *out_stable_type) +{ + NMDevicePrivate *priv; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_CONNECTION(connection)); + nm_assert(out_stable_type); + + priv = NM_DEVICE_GET_PRIVATE(self); + + /* we cache the generated stable ID for the time of an activation. + * + * The reason is, that we don't want the stable-id to change as long + * as the device is active. + * + * Especially with ${RANDOM} stable-id we want to generate *one* configuration + * for each activation. */ + if (G_UNLIKELY(!priv->current_stable_id)) { + gs_free char * default_id = NULL; + gs_free char * generated = NULL; + NMUtilsStableType stable_type; + NMSettingConnection *s_con; + gboolean hwaddr_is_fake; + const char * hwaddr; + const char * stable_id; + const char * uuid; + + s_con = nm_connection_get_setting_connection(connection); + + stable_id = nm_setting_connection_get_stable_id(s_con); + + if (!stable_id) { + default_id = + nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.stable-id"), + self); + stable_id = default_id; + } + + uuid = nm_connection_get_uuid(connection); + + /* the cloned-mac-address may be generated based on the stable-id. + * Thus, at this point, we can only use the permanent MAC address + * as seed. */ + hwaddr = nm_device_get_permanent_hw_address_full(self, TRUE, &hwaddr_is_fake); + + stable_type = nm_utils_stable_id_parse(stable_id, + nm_device_get_ip_iface(self), + !hwaddr_is_fake ? hwaddr : NULL, + nm_utils_boot_id_str(), + uuid, + &generated); + + /* current_stable_id_type is a bitfield! */ + priv->current_stable_id_type = stable_type; + nm_assert(stable_type <= (NMUtilsStableType) 0x3); + nm_assert(stable_type + (NMUtilsStableType) 1 > (NMUtilsStableType) 0); + nm_assert(priv->current_stable_id_type == stable_type); + + if (stable_type == NM_UTILS_STABLE_TYPE_UUID) + priv->current_stable_id = g_strdup(uuid); + else if (stable_type == NM_UTILS_STABLE_TYPE_STABLE_ID) + priv->current_stable_id = g_strdup(stable_id); + else if (stable_type == NM_UTILS_STABLE_TYPE_GENERATED) + priv->current_stable_id = + nm_str_realloc(nm_utils_stable_id_generated_complete(generated)); + else { + nm_assert(stable_type == NM_UTILS_STABLE_TYPE_RANDOM); + priv->current_stable_id = nm_str_realloc(nm_utils_stable_id_random()); + } + _LOGT(LOGD_DEVICE, + "stable-id: type=%d, \"%s\"" + "%s%s%s", + (int) priv->current_stable_id_type, + priv->current_stable_id, + NM_PRINT_FMT_QUOTED(stable_type == NM_UTILS_STABLE_TYPE_GENERATED, + " from \"", + generated, + "\"", + "")); + } + + nm_assert(priv->current_stable_id); + *out_stable_type = priv->current_stable_id_type; + return priv->current_stable_id; +} + +static GBytes * +_prop_get_ipv6_dhcp_duid(NMDevice * self, + NMConnection *connection, + GBytes * hwaddr, + gboolean * out_enforce) +{ + NMSettingIPConfig *s_ip6; + const char * duid; + gs_free char * duid_default = NULL; + const char * duid_error; + GBytes * duid_out; + gboolean duid_enforce = TRUE; + gs_free char * logstr1 = NULL; + const guint8 * hwaddr_bin; + gsize hwaddr_len; + int arp_type; + + s_ip6 = nm_connection_get_setting_ip6_config(connection); + duid = nm_setting_ip6_config_get_dhcp_duid(NM_SETTING_IP6_CONFIG(s_ip6)); + + if (!duid) { + duid_default = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv6.dhcp-duid"), + self); + duid = duid_default; + if (!duid) + duid = "lease"; + } + + if (nm_streq(duid, "lease")) { + duid_enforce = FALSE; + duid_out = nm_utils_generate_duid_from_machine_id(); + goto out_good; + } + + if (!_nm_utils_dhcp_duid_valid(duid, &duid_out)) { + duid_error = "invalid duid"; + goto out_fail; + } + + if (duid_out) + goto out_good; + + if (NM_IN_STRSET(duid, "ll", "llt")) { + if (!hwaddr) { + duid_error = "missing link-layer address"; + goto out_fail; + } + + hwaddr_bin = g_bytes_get_data(hwaddr, &hwaddr_len); + arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len); + if (arp_type < 0) { + duid_error = "unsupported link-layer address"; + goto out_fail; + } + + if (nm_streq(duid, "ll")) + duid_out = nm_utils_generate_duid_ll(arp_type, hwaddr_bin, hwaddr_len); + else { + duid_out = nm_utils_generate_duid_llt(arp_type, + hwaddr_bin, + hwaddr_len, + nm_utils_host_id_get_timestamp_ns() + / NM_UTILS_NSEC_PER_SEC); + } + + goto out_good; + } + + if (NM_IN_STRSET(duid, "stable-ll", "stable-llt", "stable-uuid")) { + /* preferably, we would salt the checksum differently for each @duid type. We missed + * to do that initially, so most types use the DEFAULT_SALT. + * + * Implementations that are added later, should use a distinct salt instead, + * like "stable-ll"/"stable-llt" with ARPHRD_INFINIBAND below. */ + const guint32 DEFAULT_SALT = 670531087u; + nm_auto_free_checksum GChecksum *sum = NULL; + NMUtilsStableType stable_type; + const char * stable_id = NULL; + guint32 salted_header; + const guint8 * host_id; + gsize host_id_len; + union { + guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256]; + guint8 hwaddr_eth[ETH_ALEN]; + guint8 hwaddr_infiniband[INFINIBAND_ALEN]; + NMUuid uuid; + struct _nm_packed { + guint8 hwaddr[ETH_ALEN]; + guint32 timestamp; + } llt_eth; + struct _nm_packed { + guint8 hwaddr[INFINIBAND_ALEN]; + guint32 timestamp; + } llt_infiniband; + } digest; + + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + + if (NM_IN_STRSET(duid, "stable-ll", "stable-llt")) { + /* for stable LL/LLT DUIDs, we still need a hardware address to detect + * the arp-type. Alternatively, we would be able to detect it based on + * other means (e.g. NMDevice type), but instead require the hardware + * address to be present. This is at least consistent with the "ll"/"llt" + * modes above. */ + if (!hwaddr) { + duid_error = "missing link-layer address"; + goto out_fail; + } + if ((arp_type = nm_utils_arp_type_detect_from_hwaddrlen(g_bytes_get_size(hwaddr))) + < 0) { + duid_error = "unsupported link-layer address"; + goto out_fail; + } + + if (arp_type == ARPHRD_ETHER) + salted_header = DEFAULT_SALT; + else { + nm_assert(arp_type == ARPHRD_INFINIBAND); + salted_header = 0x42492CEFu + ((guint32) arp_type); + } + } else { + salted_header = DEFAULT_SALT; + arp_type = -1; + } + + salted_header = htonl(salted_header + ((guint32) stable_type)); + + nm_utils_host_id_get(&host_id, &host_id_len); + + sum = g_checksum_new(G_CHECKSUM_SHA256); + g_checksum_update(sum, (const guchar *) &salted_header, sizeof(salted_header)); + g_checksum_update(sum, (const guchar *) stable_id, -1); + g_checksum_update(sum, (const guchar *) host_id, host_id_len); + nm_utils_checksum_get_digest(sum, digest.sha256); + + G_STATIC_ASSERT_EXPR(sizeof(digest) == sizeof(digest.sha256)); + + if (nm_streq(duid, "stable-ll")) { + switch (arp_type) { + case ARPHRD_ETHER: + duid_out = nm_utils_generate_duid_ll(arp_type, + digest.hwaddr_eth, + sizeof(digest.hwaddr_eth)); + break; + case ARPHRD_INFINIBAND: + duid_out = nm_utils_generate_duid_ll(arp_type, + digest.hwaddr_infiniband, + sizeof(digest.hwaddr_infiniband)); + break; + default: + g_return_val_if_reached(NULL); + } + } else if (nm_streq(duid, "stable-llt")) { + gint64 time; + guint32 timestamp; + +#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3) + + /* We want a variable time between the host_id timestamp and three years + * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll + * subtract it from the host_id timestamp. + */ + time = nm_utils_host_id_get_timestamp_ns() / NM_UTILS_NSEC_PER_SEC; + + /* don't use too old timestamps. They cannot be expressed in DUID-LLT and + * would all be truncated to zero. */ + time = NM_MAX(time, NM_UTILS_EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS); + + switch (arp_type) { + case ARPHRD_ETHER: + timestamp = unaligned_read_be32(&digest.llt_eth.timestamp); + time -= timestamp % EPOCH_DATETIME_THREE_YEARS; + duid_out = nm_utils_generate_duid_llt(arp_type, + digest.llt_eth.hwaddr, + sizeof(digest.llt_eth.hwaddr), + time); + break; + case ARPHRD_INFINIBAND: + timestamp = unaligned_read_be32(&digest.llt_infiniband.timestamp); + time -= timestamp % EPOCH_DATETIME_THREE_YEARS; + duid_out = nm_utils_generate_duid_llt(arp_type, + digest.llt_infiniband.hwaddr, + sizeof(digest.llt_infiniband.hwaddr), + time); + break; + default: + g_return_val_if_reached(NULL); + } + } else { + nm_assert(nm_streq(duid, "stable-uuid")); + duid_out = nm_utils_generate_duid_uuid(&digest.uuid); + } + + goto out_good; + } + + g_return_val_if_reached(NULL); + +out_fail: + nm_assert(!duid_out && duid_error); + { + NMUuid uuid; + + _LOGW(LOGD_IP6 | LOGD_DHCP6, + "ipv6.dhcp-duid: failure to generate %s DUID: %s. Fallback to random DUID-UUID.", + duid, + duid_error); + + nm_utils_random_bytes(&uuid, sizeof(uuid)); + duid_out = nm_utils_generate_duid_uuid(&uuid); + } + +out_good: + nm_assert(duid_out); + _LOGD(LOGD_IP6 | LOGD_DHCP6, + "ipv6.dhcp-duid: generate %s DUID '%s' (%s)", + duid, + (logstr1 = nm_dhcp_utils_duid_to_string(duid_out)), + duid_enforce ? "enforcing" : "prefer lease"); + + NM_SET_OUT(out_enforce, duid_enforce); + return duid_out; +} + +static guint32 +_prop_get_ipv6_ra_timeout(NMDevice *self) +{ + NMConnection *connection; + gint32 timeout; + + G_STATIC_ASSERT_EXPR(NM_RA_TIMEOUT_DEFAULT == 0); + G_STATIC_ASSERT_EXPR(NM_RA_TIMEOUT_INFINITY == G_MAXINT32); + + connection = nm_device_get_applied_connection(self); + + timeout = nm_setting_ip6_config_get_ra_timeout( + NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection))); + if (timeout > 0) + return timeout; + nm_assert(timeout == 0); + + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv6.ra-timeout"), + self, + 0, + G_MAXINT32, + 0); +} + +static NMSettingConnectionMdns +_prop_get_connection_mdns(NMDevice *self) +{ + NMConnection * connection; + NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + + g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_MDNS_DEFAULT); + + connection = nm_device_get_applied_connection(self); + if (connection) + mdns = nm_setting_connection_get_mdns(nm_connection_get_setting_connection(connection)); + if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) + return mdns; + + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.mdns"), + self, + NM_SETTING_CONNECTION_MDNS_NO, + NM_SETTING_CONNECTION_MDNS_YES, + NM_SETTING_CONNECTION_MDNS_DEFAULT); +} + +static NMSettingConnectionLlmnr +_prop_get_connection_llmnr(NMDevice *self) +{ + NMConnection * connection; + NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; + + g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_LLMNR_DEFAULT); + + connection = nm_device_get_applied_connection(self); + if (connection) + llmnr = nm_setting_connection_get_llmnr(nm_connection_get_setting_connection(connection)); + if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) + return llmnr; + + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.llmnr"), + self, + NM_SETTING_CONNECTION_LLMNR_NO, + NM_SETTING_CONNECTION_LLMNR_YES, + NM_SETTING_CONNECTION_LLMNR_DEFAULT); +} + +static guint32 +_prop_get_ipvx_route_table(NMDevice *self, int addr_family) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceClass * klass; + NMConnection * connection; + NMSettingIPConfig * s_ip; + guint32 route_table = 0; + gboolean is_user_config = TRUE; + NMSettingConnection *s_con; + NMSettingVrf * s_vrf; + + nm_assert_addr_family(addr_family); + + /* the route table setting affects how we sync routes. We shall + * not change it while the device is active, hence, cache it. */ + if (addr_family == AF_INET) { + if (priv->v4_route_table_initialized) + return priv->v4_route_table; + } else { + if (priv->v6_route_table_initialized) + return priv->v6_route_table; + } + + connection = nm_device_get_applied_connection(self); + if (connection) { + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); + if (s_ip) + route_table = nm_setting_ip_config_get_route_table(s_ip); + } + if (route_table == 0u) { + gint64 v; + + v = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? NM_CON_DEFAULT("ipv4.route-table") + : NM_CON_DEFAULT("ipv6.route-table"), + self, + 0, + G_MAXUINT32, + -1); + if (v != -1) { + route_table = v; + is_user_config = FALSE; + } + } + + if (route_table == 0u && connection + && (s_con = nm_connection_get_setting_connection(connection)) + && (nm_streq0(nm_setting_connection_get_slave_type(s_con), NM_SETTING_VRF_SETTING_NAME) + && priv->master && nm_device_get_device_type(priv->master) == NM_DEVICE_TYPE_VRF)) { + const NMPlatformLnkVrf *lnk; + + lnk = nm_platform_link_get_lnk_vrf(nm_device_get_platform(self), + nm_device_get_ifindex(priv->master), + NULL); + + if (lnk) + route_table = lnk->table; + } + + if (route_table == 0u && connection + && (s_vrf = (NMSettingVrf *) nm_connection_get_setting(connection, NM_TYPE_SETTING_VRF))) { + route_table = nm_setting_vrf_get_table(s_vrf); + } + + klass = NM_DEVICE_GET_CLASS(self); + if (klass->coerce_route_table) + route_table = klass->coerce_route_table(self, addr_family, route_table, is_user_config); + + if (addr_family == AF_INET) { + priv->v4_route_table_initialized = TRUE; + priv->v4_route_table = route_table; + } else { + priv->v6_route_table_initialized = TRUE; + priv->v6_route_table = route_table; + } + + _LOGT(LOGD_DEVICE, + "ipv%c.route-table = %u%s", + addr_family == AF_INET ? '4' : '6', + (guint)(route_table ?: RT_TABLE_MAIN), + route_table != 0u ? "" : " (policy routing not enabled)"); + + return route_table; +} + +static gboolean +_prop_get_connection_lldp(NMDevice *self) +{ + NMConnection * connection; + NMSettingConnection * s_con; + NMSettingConnectionLldp lldp = NM_SETTING_CONNECTION_LLDP_DEFAULT; + + connection = nm_device_get_applied_connection(self); + g_return_val_if_fail(connection, FALSE); + + s_con = nm_connection_get_setting_connection(connection); + g_return_val_if_fail(s_con, FALSE); + + lldp = nm_setting_connection_get_lldp(s_con); + if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) { + lldp = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.lldp"), + self, + NM_SETTING_CONNECTION_LLDP_DEFAULT, + NM_SETTING_CONNECTION_LLDP_ENABLE_RX, + NM_SETTING_CONNECTION_LLDP_DEFAULT); + if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) + lldp = NM_SETTING_CONNECTION_LLDP_DISABLE; + } + return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX; +} + +static guint +_prop_get_ipv4_dad_timeout(NMDevice *self) +{ + NMConnection * connection; + NMSettingIPConfig *s_ip4 = NULL; + int timeout = -1; + + connection = nm_device_get_applied_connection(self); + if (connection) + s_ip4 = nm_connection_get_setting_ip4_config(connection); + if (s_ip4) + timeout = nm_setting_ip_config_get_dad_timeout(s_ip4); + if (timeout >= 0) + return timeout; + + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv4.dad-timeout"), + self, + 0, + NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, + 0); +} + +static guint32 +_prop_get_ipvx_dhcp_timeout(NMDevice *self, int addr_family) +{ + NMDeviceClass *klass; + NMConnection * connection; + int timeout_i; + guint32 timeout; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert_addr_family(addr_family); + + connection = nm_device_get_applied_connection(self); + + timeout_i = nm_setting_ip_config_get_dhcp_timeout( + nm_connection_get_setting_ip_config(connection, addr_family)); + nm_assert(timeout_i >= 0 && timeout_i <= G_MAXINT32); + + timeout = (guint32) timeout_i; + if (timeout) + goto out; + + timeout = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? NM_CON_DEFAULT("ipv4.dhcp-timeout") + : NM_CON_DEFAULT("ipv6.dhcp-timeout"), + self, + 0, + G_MAXINT32, + 0); + if (timeout) + goto out; + + klass = NM_DEVICE_GET_CLASS(self); + if (klass->get_dhcp_timeout_for_device) { + timeout = klass->get_dhcp_timeout_for_device(self, addr_family); + if (timeout) + goto out; + } + + timeout = NM_DHCP_TIMEOUT_DEFAULT; + +out: + G_STATIC_ASSERT_EXPR(G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); + nm_assert(timeout > 0); + nm_assert(timeout <= G_MAXINT32); + return timeout; +} + +/** + * _prop_get_ipvx_dhcp_iaid: + * @self: the #NMDevice + * @addr_family: the address family + * @connection: the connection + * @out_is_explicit: on return, %TRUE if the user set a valid IAID in + * the connection or in global configuration; %FALSE if the connection + * property was empty and no valid global configuration was provided. + * + * Returns: a IAID value for this device and the given connection. + */ +static guint32 +_prop_get_ipvx_dhcp_iaid(NMDevice * self, + int addr_family, + NMConnection *connection, + gboolean * out_is_explicit) +{ + NMSettingIPConfig *s_ip; + const char * iaid_str; + gs_free char * iaid_str_free = NULL; + guint32 iaid; + const char * iface; + const char * fail_reason; + gboolean is_explicit = TRUE; + + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); + iaid_str = nm_setting_ip_config_get_dhcp_iaid(s_ip); + if (!iaid_str) { + iaid_str_free = nm_config_data_get_connection_default( + NM_CONFIG_GET_DATA, + addr_family == AF_INET ? NM_CON_DEFAULT("ipv4.dhcp-iaid") + : NM_CON_DEFAULT("ipv6.dhcp-iaid"), + self); + iaid_str = iaid_str_free; + if (!iaid_str) { + iaid_str = NM_IAID_IFNAME; + is_explicit = FALSE; + } else if (!_nm_utils_iaid_verify(iaid_str, NULL)) { + _LOGW(LOGD_DEVICE, + "invalid global default '%s' for ipv%c.dhcp-iaid", + iaid_str, + nm_utils_addr_family_to_char(addr_family)); + iaid_str = NM_IAID_IFNAME; + is_explicit = FALSE; + } + } + + if (nm_streq0(iaid_str, NM_IAID_MAC)) { + const NMPlatformLink *pllink; + + pllink = nm_platform_link_get(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); + if (!pllink || pllink->l_address.len < 4) { + fail_reason = "invalid link-layer address"; + goto out_fail; + } + + /* @iaid is in native endianness. Use unaligned_read_be32() + * so that the IAID for a given MAC address is the same on + * BE and LE machines. */ + iaid = unaligned_read_be32(&pllink->l_address.data[pllink->l_address.len - 4]); + goto out_good; + } else if (nm_streq0(iaid_str, NM_IAID_PERM_MAC)) { + guint8 hwaddr_buf[NM_UTILS_HWADDR_LEN_MAX]; + const char *hwaddr_str; + gsize hwaddr_len; + + hwaddr_str = nm_device_get_permanent_hw_address(self); + if (!hwaddr_str) { + fail_reason = "no permanent link-layer address"; + goto out_fail; + } + + if (!_nm_utils_hwaddr_aton(hwaddr_str, hwaddr_buf, sizeof(hwaddr_buf), &hwaddr_len)) + g_return_val_if_reached(0); + + if (hwaddr_len < 4) { + fail_reason = "invalid link-layer address"; + goto out_fail; + } + + iaid = unaligned_read_be32(&hwaddr_buf[hwaddr_len - 4]); + goto out_good; + } else if (nm_streq(iaid_str, "stable")) { + nm_auto_free_checksum GChecksum *sum = NULL; + guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; + NMUtilsStableType stable_type; + const char * stable_id; + guint32 salted_header; + const guint8 * host_id; + gsize host_id_len; + + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + salted_header = htonl(53390459 + stable_type); + nm_utils_host_id_get(&host_id, &host_id_len); + iface = nm_device_get_ip_iface(self); + + sum = g_checksum_new(G_CHECKSUM_SHA1); + g_checksum_update(sum, (const guchar *) &salted_header, sizeof(salted_header)); + g_checksum_update(sum, (const guchar *) stable_id, strlen(stable_id) + 1); + g_checksum_update(sum, (const guchar *) iface, strlen(iface) + 1); + g_checksum_update(sum, (const guchar *) host_id, host_id_len); + nm_utils_checksum_get_digest(sum, digest); + + iaid = unaligned_read_be32(digest); + goto out_good; + } else if ((iaid = _nm_utils_ascii_str_to_int64(iaid_str, 10, 0, G_MAXUINT32, -1)) != -1) { + goto out_good; + } else { + iface = nm_device_get_ip_iface(self); + iaid = nm_utils_create_dhcp_iaid(TRUE, (const guint8 *) iface, strlen(iface)); + goto out_good; + } + +out_fail: + nm_assert(fail_reason); + _LOGW(addr_family == AF_INET ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) + : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), + "ipv%c.dhcp-iaid: failure to generate IAID: %s. Using interface-name based IAID", + nm_utils_addr_family_to_char(addr_family), + fail_reason); + is_explicit = FALSE; + iface = nm_device_get_ip_iface(self); + iaid = nm_utils_create_dhcp_iaid(TRUE, (const guint8 *) iface, strlen(iface)); +out_good: + _LOGD(addr_family == AF_INET ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) + : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), + "ipv%c.dhcp-iaid: using %u (0x%08x) IAID (str: '%s', explicit %d)", + nm_utils_addr_family_to_char(addr_family), + iaid, + iaid, + iaid_str, + is_explicit); + NM_SET_OUT(out_is_explicit, is_explicit); + return iaid; +} + +static NMDhcpHostnameFlags +_prop_get_ipvx_dhcp_hostname_flags(NMDevice *self, int addr_family) +{ + NMConnection * connection; + NMSettingIPConfig * s_ip; + NMDhcpHostnameFlags flags; + gs_free_error GError *error = NULL; + + g_return_val_if_fail(NM_IS_DEVICE(self), NM_DHCP_HOSTNAME_FLAG_NONE); + + connection = nm_device_get_applied_connection(self); + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); + g_return_val_if_fail(s_ip, NM_DHCP_HOSTNAME_FLAG_NONE); + + if (!nm_setting_ip_config_get_dhcp_send_hostname(s_ip)) + return NM_DHCP_HOSTNAME_FLAG_NONE; + + flags = nm_setting_ip_config_get_dhcp_hostname_flags(s_ip); + if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) + return flags; + + flags = nm_config_data_get_connection_default_int64( + NM_CONFIG_GET_DATA, + addr_family == AF_INET ? NM_CON_DEFAULT("ipv4.dhcp-hostname-flags") + : NM_CON_DEFAULT("ipv6.dhcp-hostname-flags"), + self, + 0, + NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS, + 0); + + if (!_nm_utils_validate_dhcp_hostname_flags(flags, addr_family, &error)) { + _LOGW(LOGD_DEVICE, + "invalid global default value 0x%x for ipv%d.%s: %s", + (guint) flags, + addr_family == AF_INET ? 4 : 6, + NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS, + error->message); + flags = NM_DHCP_HOSTNAME_FLAG_NONE; + } + + if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) + return flags; + + if (addr_family == AF_INET) + return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP4; + else + return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP6; +} + +static const char * +_prop_get_connection_mud_url(NMDevice *self, NMSettingConnection *s_con, char **out_mud_url) +{ + const char * mud_url; + gs_free char *s = NULL; + + nm_assert(out_mud_url && !*out_mud_url); + + mud_url = nm_setting_connection_get_mud_url(s_con); + + if (mud_url) { + if (nm_streq(mud_url, NM_CONNECTION_MUD_URL_NONE)) + return NULL; + return mud_url; + } + + s = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.mud-url"), + self); + if (s) { + if (nm_streq(s, NM_CONNECTION_MUD_URL_NONE)) + return NULL; + if (nm_sd_http_url_is_valid_https(s)) + return (*out_mud_url = g_steal_pointer(&s)); + } + + return NULL; +} + +static GBytes * +_prop_get_ipv4_dhcp_client_id(NMDevice *self, NMConnection *connection, GBytes *hwaddr) +{ + NMSettingIPConfig *s_ip4; + const char * client_id; + gs_free char * client_id_default = NULL; + guint8 * client_id_buf; + const char * fail_reason; + guint8 hwaddr_bin_buf[NM_UTILS_HWADDR_LEN_MAX]; + const guint8 * hwaddr_bin; + int arp_type; + gsize hwaddr_len; + GBytes * result; + gs_free char * logstr1 = NULL; + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + client_id = nm_setting_ip4_config_get_dhcp_client_id(NM_SETTING_IP4_CONFIG(s_ip4)); + + if (!client_id) { + client_id_default = + nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv4.dhcp-client-id"), + self); + if (client_id_default && client_id_default[0]) { + /* a non-empty client-id is always valid, see nm_dhcp_utils_client_id_string_to_bytes(). */ + client_id = client_id_default; + } + } + + if (!client_id) { + _LOGD(LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: no explicit client-id configured"); + return NULL; + } + + if (nm_streq(client_id, "mac")) { + if (!hwaddr) { + fail_reason = "missing link-layer address"; + goto out_fail; + } + + hwaddr_bin = g_bytes_get_data(hwaddr, &hwaddr_len); + arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len); + if (arp_type < 0) { + fail_reason = "unsupported link-layer address"; + goto out_fail; + } + + result = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_bin, hwaddr_len); + goto out_good; + } + + if (nm_streq(client_id, "perm-mac")) { + const char *hwaddr_str; + + hwaddr_str = nm_device_get_permanent_hw_address(self); + if (!hwaddr_str) { + fail_reason = "missing permanent link-layer address"; + goto out_fail; + } + + if (!_nm_utils_hwaddr_aton(hwaddr_str, hwaddr_bin_buf, sizeof(hwaddr_bin_buf), &hwaddr_len)) + g_return_val_if_reached(NULL); + + arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len); + if (arp_type < 0) { + fail_reason = "unsupported permanent link-layer address"; + goto out_fail; + } + + result = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_bin_buf, hwaddr_len); + goto out_good; + } + + if (nm_streq(client_id, "duid")) { + guint32 iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET, connection, NULL); + + result = nm_utils_dhcp_client_id_systemd_node_specific(iaid); + goto out_good; + } + + if (nm_streq(client_id, "stable")) { + nm_auto_free_checksum GChecksum *sum = NULL; + guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; + NMUtilsStableType stable_type; + const char * stable_id; + guint32 salted_header; + const guint8 * host_id; + gsize host_id_len; + + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + salted_header = htonl(2011610591 + stable_type); + nm_utils_host_id_get(&host_id, &host_id_len); + + sum = g_checksum_new(G_CHECKSUM_SHA1); + g_checksum_update(sum, (const guchar *) &salted_header, sizeof(salted_header)); + g_checksum_update(sum, (const guchar *) stable_id, strlen(stable_id) + 1); + g_checksum_update(sum, (const guchar *) host_id, host_id_len); + nm_utils_checksum_get_digest(sum, digest); + + client_id_buf = g_malloc(1 + 15); + client_id_buf[0] = 0; + memcpy(&client_id_buf[1], digest, 15); + result = g_bytes_new_take(client_id_buf, 1 + 15); + goto out_good; + } + + result = nm_dhcp_utils_client_id_string_to_bytes(client_id); + goto out_good; + +out_fail: + nm_assert(fail_reason); + _LOGW(LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: failure to generate client id (%s). Use random client id", + fail_reason); + client_id_buf = g_malloc(1 + 15); + client_id_buf[0] = 0; + nm_utils_random_bytes(&client_id_buf[1], 15); + result = g_bytes_new_take(client_id_buf, 1 + 15); + +out_good: + nm_assert(result); + _LOGD(LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, + "ipv4.dhcp-client-id: use \"%s\" client ID: %s", + client_id, + (logstr1 = nm_dhcp_utils_duid_to_string(result))); + return result; +} + +static GBytes * +_prop_get_ipv4_dhcp_vendor_class_identifier(NMDevice *self, NMSettingIP4Config *s_ip4) +{ + gs_free char *config_data_prop = NULL; + gs_free char *to_free = NULL; + const char * conn_prop; + GBytes * bytes = NULL; + const char * bin; + gsize len; + + conn_prop = nm_setting_ip4_config_get_dhcp_vendor_class_identifier(s_ip4); + + if (!conn_prop) { + /* set in NetworkManager.conf ? */ + config_data_prop = nm_config_data_get_connection_default( + NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv4.dhcp-vendor-class-identifier"), + self); + + if (config_data_prop && nm_utils_validate_dhcp4_vendor_class_id(config_data_prop, NULL)) + conn_prop = config_data_prop; + } + + if (conn_prop) { + bin = nm_utils_buf_utf8safe_unescape(conn_prop, + NM_UTILS_STR_UTF8_SAFE_FLAG_NONE, + &len, + (gpointer *) &to_free); + if (to_free) + bytes = g_bytes_new_take(g_steal_pointer(&to_free), len); + else + bytes = g_bytes_new(bin, len); + } + + return bytes; +} + +static NMSettingIP6ConfigPrivacy +_prop_get_ipv6_ip6_privacy(NMDevice *self) +{ + NMSettingIP6ConfigPrivacy ip6_privacy; + NMConnection * connection; + + g_return_val_if_fail(self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + + /* 1.) First look at the per-connection setting. If it is not -1 (unknown), + * use it. */ + connection = nm_device_get_applied_connection(self); + if (connection) { + NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config(connection); + + if (s_ip6) { + ip6_privacy = nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip6)); + ip6_privacy = _ip6_privacy_clamp(ip6_privacy); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; + } + } + + /* 2.) use the default value from the configuration. */ + ip6_privacy = + nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv6.ip6-privacy"), + self, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) + return ip6_privacy; + + if (!nm_device_get_ip_ifindex(self)) + return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + + /* 3.) No valid default-value configured. Fallback to reading sysctl. + * + * Instead of reading static config files in /etc, just read the current sysctl value. + * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves + * the "default" entry untouched. */ + ip6_privacy = nm_platform_sysctl_get_int32( + nm_device_get_platform(self), + NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv6/conf/default/use_tempaddr"), + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + return _ip6_privacy_clamp(ip6_privacy); +} + +static const char * +_prop_get_x_cloned_mac_address(NMDevice * self, + NMConnection *connection, + gboolean is_wifi, + char ** out_addr) +{ + NMSetting * setting; + const char *addr = NULL; + + nm_assert(out_addr && !*out_addr); + + setting = nm_connection_get_setting(connection, + is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); + if (setting) { + addr = is_wifi ? nm_setting_wireless_get_cloned_mac_address((NMSettingWireless *) setting) + : nm_setting_wired_get_cloned_mac_address((NMSettingWired *) setting); + } + + if (!addr) { + gs_free char *a = NULL; + + a = nm_config_data_get_connection_default( + NM_CONFIG_GET_DATA, + is_wifi ? NM_CON_DEFAULT("wifi.cloned-mac-address") + : NM_CON_DEFAULT("ethernet.cloned-mac-address"), + self); + + addr = NM_CLONED_MAC_PRESERVE; + + if (!a) { + if (is_wifi) { + NMSettingMacRandomization v; + + /* for backward compatibility, read the deprecated wifi.mac-address-randomization setting. */ + a = nm_config_data_get_connection_default( + NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("wifi.mac-address-randomization"), + self); + v = _nm_utils_ascii_str_to_int64(a, + 10, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT, + NM_SETTING_MAC_RANDOMIZATION_ALWAYS, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT); + if (v == NM_SETTING_MAC_RANDOMIZATION_ALWAYS) + addr = NM_CLONED_MAC_RANDOM; + } + } else if (NM_CLONED_MAC_IS_SPECIAL(a) || nm_utils_hwaddr_valid(a, ETH_ALEN)) + addr = *out_addr = g_steal_pointer(&a); + } + + return addr; +} + +static const char * +_prop_get_x_generate_mac_address_mask(NMDevice * self, + NMConnection *connection, + gboolean is_wifi, + char ** out_value) +{ + NMSetting * setting; + const char *value = NULL; + char * a; + + nm_assert(out_value && !*out_value); + + setting = nm_connection_get_setting(connection, + is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); + if (setting) { + value = + is_wifi + ? nm_setting_wireless_get_generate_mac_address_mask((NMSettingWireless *) setting) + : nm_setting_wired_get_generate_mac_address_mask((NMSettingWired *) setting); + if (value) + return value; + } + + a = nm_config_data_get_connection_default( + NM_CONFIG_GET_DATA, + is_wifi ? NM_CON_DEFAULT("wifi.generate-mac-address-mask") + : NM_CON_DEFAULT("ethernet.generate-mac-address-mask"), + self); + if (!a) + return NULL; + *out_value = a; + return a; +} /*****************************************************************************/ static void -_ethtool_features_reset (NMDevice *self, - NMPlatform *platform, - EthtoolState *ethtool_state) +_ethtool_features_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) { - gs_free NMEthtoolFeatureStates *features; + gs_free NMEthtoolFeatureStates *features; - features = g_steal_pointer (ðtool_state->features); + features = g_steal_pointer(ðtool_state->features); - if (!nm_platform_ethtool_set_features (platform, - ethtool_state->ifindex, - features, - ethtool_state->requested, - FALSE)) - _LOGW (LOGD_DEVICE, "ethtool: failure resetting one or more offload features"); - else - _LOGD (LOGD_DEVICE, "ethtool: offload features successfully reset"); + if (!nm_platform_ethtool_set_features(platform, + ethtool_state->ifindex, + features, + ethtool_state->requested, + FALSE)) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting one or more offload features"); + else + _LOGD(LOGD_DEVICE, "ethtool: offload features successfully reset"); } static void -_ethtool_features_set (NMDevice *self, - NMPlatform *platform, - EthtoolState *ethtool_state, - NMSettingEthtool *s_ethtool) +_ethtool_features_set(NMDevice * self, + NMPlatform * platform, + EthtoolState * ethtool_state, + NMSettingEthtool *s_ethtool) { - gs_free NMEthtoolFeatureStates *features = NULL; + gs_free NMEthtoolFeatureStates *features = NULL; - if (ethtool_state->features) - _ethtool_features_reset (self, platform, ethtool_state); + if (ethtool_state->features) + _ethtool_features_reset(self, platform, ethtool_state); - if (nm_setting_ethtool_init_features (s_ethtool, ethtool_state->requested) == 0) - return; + if (nm_setting_ethtool_init_features(s_ethtool, ethtool_state->requested) == 0) + return; - features = nm_platform_ethtool_get_link_features (platform, - ethtool_state->ifindex); - if (!features) { - _LOGW (LOGD_DEVICE, "ethtool: failure setting offload features (cannot read features)"); - return; - } + features = nm_platform_ethtool_get_link_features(platform, ethtool_state->ifindex); + if (!features) { + _LOGW(LOGD_DEVICE, "ethtool: failure setting offload features (cannot read features)"); + return; + } - if (!nm_platform_ethtool_set_features (platform, - ethtool_state->ifindex, - features, - ethtool_state->requested, - TRUE)) - _LOGW (LOGD_DEVICE, "ethtool: failure setting one or more offload features"); - else - _LOGD (LOGD_DEVICE, "ethtool: offload features successfully set"); + if (!nm_platform_ethtool_set_features(platform, + ethtool_state->ifindex, + features, + ethtool_state->requested, + TRUE)) + _LOGW(LOGD_DEVICE, "ethtool: failure setting one or more offload features"); + else + _LOGD(LOGD_DEVICE, "ethtool: offload features successfully set"); - ethtool_state->features = g_steal_pointer (&features); + ethtool_state->features = g_steal_pointer(&features); } static void -_ethtool_coalesce_reset (NMDevice *self, - NMPlatform *platform, - EthtoolState *ethtool_state) +_ethtool_coalesce_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) { - gs_free NMEthtoolCoalesceState *coalesce = NULL; + gs_free NMEthtoolCoalesceState *coalesce = NULL; - nm_assert (NM_IS_DEVICE (self)); - nm_assert (NM_IS_PLATFORM (platform)); - nm_assert (ethtool_state); + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(ethtool_state); - coalesce = g_steal_pointer (ðtool_state->coalesce); - if (!coalesce) - return; + coalesce = g_steal_pointer(ðtool_state->coalesce); + if (!coalesce) + return; - if (!nm_platform_ethtool_set_coalesce (platform, - ethtool_state->ifindex, - coalesce)) - _LOGW (LOGD_DEVICE, "ethtool: failure resetting one or more coalesce settings"); - else - _LOGD (LOGD_DEVICE, "ethtool: coalesce settings successfully reset"); + if (!nm_platform_ethtool_set_coalesce(platform, ethtool_state->ifindex, coalesce)) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting one or more coalesce settings"); + else + _LOGD(LOGD_DEVICE, "ethtool: coalesce settings successfully reset"); } static void -_ethtool_coalesce_set (NMDevice *self, - NMPlatform *platform, - EthtoolState *ethtool_state, - NMSettingEthtool *s_ethtool) -{ - NMEthtoolCoalesceState coalesce_old; - NMEthtoolCoalesceState coalesce_new; - gboolean has_old = FALSE; - GHashTable *hash; - GHashTableIter iter; - const char *name; - GVariant *variant; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert (NM_IS_PLATFORM (platform)); - nm_assert (NM_IS_SETTING_ETHTOOL (s_ethtool)); - nm_assert (ethtool_state); - nm_assert (!ethtool_state->coalesce); - - hash = _nm_setting_option_hash (NM_SETTING (s_ethtool), FALSE); - if (!hash) - return; - - g_hash_table_iter_init (&iter, hash); - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant)) { - NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name (name); - - if (!nm_ethtool_id_is_coalesce (ethtool_id)) - continue; - - if (!has_old) { - if (!nm_platform_ethtool_get_link_coalesce (platform, - ethtool_state->ifindex, - &coalesce_old)) { - _LOGW (LOGD_DEVICE, "ethtool: failure getting coalesce settings (cannot read)"); - return; - } - has_old = TRUE; - coalesce_new = coalesce_old; - } - - nm_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); - coalesce_new.s[_NM_ETHTOOL_ID_COALESCE_AS_IDX (ethtool_id)] = g_variant_get_uint32 (variant); - } - - if (!has_old) - return; - - ethtool_state->coalesce = nm_memdup (&coalesce_old, sizeof (coalesce_old)); - - if (!nm_platform_ethtool_set_coalesce (platform, - ethtool_state->ifindex, - &coalesce_new)) { - _LOGW (LOGD_DEVICE, "ethtool: failure setting coalesce settings"); - return; - } - - _LOGD (LOGD_DEVICE, "ethtool: coalesce settings successfully set"); +_ethtool_coalesce_set(NMDevice * self, + NMPlatform * platform, + EthtoolState * ethtool_state, + NMSettingEthtool *s_ethtool) +{ + NMEthtoolCoalesceState coalesce_old; + NMEthtoolCoalesceState coalesce_new; + gboolean has_old = FALSE; + GHashTable * hash; + GHashTableIter iter; + const char * name; + GVariant * variant; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool)); + nm_assert(ethtool_state); + nm_assert(!ethtool_state->coalesce); + + hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE); + if (!hash) + return; + + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { + NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); + + if (!nm_ethtool_id_is_coalesce(ethtool_id)) + continue; + + if (!has_old) { + if (!nm_platform_ethtool_get_link_coalesce(platform, + ethtool_state->ifindex, + &coalesce_old)) { + _LOGW(LOGD_DEVICE, "ethtool: failure getting coalesce settings (cannot read)"); + return; + } + has_old = TRUE; + coalesce_new = coalesce_old; + } + + nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); + coalesce_new.s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(ethtool_id)] = g_variant_get_uint32(variant); + } + + if (!has_old) + return; + + ethtool_state->coalesce = nm_memdup(&coalesce_old, sizeof(coalesce_old)); + + if (!nm_platform_ethtool_set_coalesce(platform, ethtool_state->ifindex, &coalesce_new)) { + _LOGW(LOGD_DEVICE, "ethtool: failure setting coalesce settings"); + return; + } + + _LOGD(LOGD_DEVICE, "ethtool: coalesce settings successfully set"); } static void -_ethtool_ring_reset (NMDevice *self, - NMPlatform *platform, - EthtoolState *ethtool_state) +_ethtool_ring_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) { - gs_free NMEthtoolRingState *ring = NULL; + gs_free NMEthtoolRingState *ring = NULL; - nm_assert (NM_IS_DEVICE (self)); - nm_assert (NM_IS_PLATFORM (platform)); - nm_assert (ethtool_state); + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(ethtool_state); - ring = g_steal_pointer (ðtool_state->ring); - if (!ring) - return; + ring = g_steal_pointer(ðtool_state->ring); + if (!ring) + return; - if (!nm_platform_ethtool_set_ring (platform, - ethtool_state->ifindex, - ring)) - _LOGW (LOGD_DEVICE, "ethtool: failure resetting one or more ring settings"); - else - _LOGD (LOGD_DEVICE, "ethtool: ring settings successfully reset"); + if (!nm_platform_ethtool_set_ring(platform, ethtool_state->ifindex, ring)) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting one or more ring settings"); + else + _LOGD(LOGD_DEVICE, "ethtool: ring settings successfully reset"); } static void -_ethtool_ring_set (NMDevice *self, - NMPlatform *platform, - EthtoolState *ethtool_state, - NMSettingEthtool *s_ethtool) -{ - NMEthtoolRingState ring_old; - NMEthtoolRingState ring_new; - GHashTable *hash; - GHashTableIter iter; - const char *name; - GVariant *variant; - gboolean has_old = FALSE; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert (NM_IS_PLATFORM (platform)); - nm_assert (NM_IS_SETTING_ETHTOOL (s_ethtool)); - nm_assert (ethtool_state); - nm_assert (!ethtool_state->ring); - - hash = _nm_setting_option_hash (NM_SETTING (s_ethtool), FALSE); - if (!hash) - return; - - g_hash_table_iter_init (&iter, hash); - while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant)) { - NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name (name); - guint32 u32; - - if (!nm_ethtool_id_is_ring (ethtool_id)) - continue; - - nm_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); - - if (!has_old) { - if (!nm_platform_ethtool_get_link_ring (platform, - ethtool_state->ifindex, - &ring_old)) { - _LOGW (LOGD_DEVICE, "ethtool: failure setting ring options (cannot read existing setting)"); - return; - } - has_old = TRUE; - ring_new = ring_old; - } - - u32 = g_variant_get_uint32 (variant); - - switch (ethtool_id) { - case NM_ETHTOOL_ID_RING_RX: - ring_new.rx_pending = u32; - break; - case NM_ETHTOOL_ID_RING_RX_JUMBO: - ring_new.rx_jumbo_pending = u32; - break; - case NM_ETHTOOL_ID_RING_RX_MINI: - ring_new.rx_mini_pending = u32; - break; - case NM_ETHTOOL_ID_RING_TX: - ring_new.tx_pending = u32; - break; - default: - nm_assert_not_reached (); - } - } - - if (!has_old) - return; - - ethtool_state->ring = nm_memdup (&ring_old, sizeof (ring_old)); - - if (!nm_platform_ethtool_set_ring (platform, - ethtool_state->ifindex, - &ring_new)) { - _LOGW (LOGD_DEVICE, "ethtool: failure setting ring settings"); - return; - } - - _LOGD (LOGD_DEVICE, "ethtool: ring settings successfully set"); +_ethtool_ring_set(NMDevice * self, + NMPlatform * platform, + EthtoolState * ethtool_state, + NMSettingEthtool *s_ethtool) +{ + NMEthtoolRingState ring_old; + NMEthtoolRingState ring_new; + GHashTable * hash; + GHashTableIter iter; + const char * name; + GVariant * variant; + gboolean has_old = FALSE; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool)); + nm_assert(ethtool_state); + nm_assert(!ethtool_state->ring); + + hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE); + if (!hash) + return; + + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { + NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); + guint32 u32; + + if (!nm_ethtool_id_is_ring(ethtool_id)) + continue; + + nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); + + if (!has_old) { + if (!nm_platform_ethtool_get_link_ring(platform, ethtool_state->ifindex, &ring_old)) { + _LOGW(LOGD_DEVICE, + "ethtool: failure setting ring options (cannot read existing setting)"); + return; + } + has_old = TRUE; + ring_new = ring_old; + } + + u32 = g_variant_get_uint32(variant); + + switch (ethtool_id) { + case NM_ETHTOOL_ID_RING_RX: + ring_new.rx_pending = u32; + break; + case NM_ETHTOOL_ID_RING_RX_JUMBO: + ring_new.rx_jumbo_pending = u32; + break; + case NM_ETHTOOL_ID_RING_RX_MINI: + ring_new.rx_mini_pending = u32; + break; + case NM_ETHTOOL_ID_RING_TX: + ring_new.tx_pending = u32; + break; + default: + nm_assert_not_reached(); + } + } + + if (!has_old) + return; + + ethtool_state->ring = nm_memdup(&ring_old, sizeof(ring_old)); + + if (!nm_platform_ethtool_set_ring(platform, ethtool_state->ifindex, &ring_new)) { + _LOGW(LOGD_DEVICE, "ethtool: failure setting ring settings"); + return; + } + + _LOGD(LOGD_DEVICE, "ethtool: ring settings successfully set"); } static void -_ethtool_state_reset (NMDevice *self) +_ethtool_state_reset(NMDevice *self) { - NMPlatform *platform = nm_device_get_platform (self); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gs_free EthtoolState *ethtool_state = g_steal_pointer (&priv->ethtool_state); + NMPlatform * platform = nm_device_get_platform(self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gs_free EthtoolState *ethtool_state = g_steal_pointer(&priv->ethtool_state); - if (!ethtool_state) - return; + if (!ethtool_state) + return; - if (ethtool_state->features) - _ethtool_features_reset (self, platform, ethtool_state); - if (ethtool_state->coalesce) - _ethtool_coalesce_reset (self, platform, ethtool_state); - if (ethtool_state->ring) - _ethtool_ring_reset (self, platform, ethtool_state); + if (ethtool_state->features) + _ethtool_features_reset(self, platform, ethtool_state); + if (ethtool_state->coalesce) + _ethtool_coalesce_reset(self, platform, ethtool_state); + if (ethtool_state->ring) + _ethtool_ring_reset(self, platform, ethtool_state); } static void -_ethtool_state_set (NMDevice *self) -{ - int ifindex; - NMPlatform *platform; - NMConnection *connection; - NMSettingEthtool *s_ethtool; - gs_free EthtoolState *ethtool_state = NULL; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - ifindex = nm_device_get_ip_ifindex (self); - if (ifindex <= 0) - return; - - platform = nm_device_get_platform (self); - nm_assert (platform); - - connection = nm_device_get_applied_connection (self); - if (!connection) - return; - - s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL)); - if (!s_ethtool) - return; - - ethtool_state = g_new0 (EthtoolState, 1); - ethtool_state->ifindex = ifindex; - - _ethtool_features_set (self, - platform, - ethtool_state, - s_ethtool); - _ethtool_coalesce_set (self, - platform, - ethtool_state, - s_ethtool); - _ethtool_ring_set (self, - platform, - ethtool_state, - s_ethtool); - - if ( ethtool_state->features - || ethtool_state->coalesce - || ethtool_state->ring) - priv->ethtool_state = g_steal_pointer (ðtool_state); +_ethtool_state_set(NMDevice *self) +{ + int ifindex; + NMPlatform * platform; + NMConnection * connection; + NMSettingEthtool *s_ethtool; + gs_free EthtoolState *ethtool_state = NULL; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex <= 0) + return; + + platform = nm_device_get_platform(self); + nm_assert(platform); + + connection = nm_device_get_applied_connection(self); + if (!connection) + return; + + s_ethtool = NM_SETTING_ETHTOOL(nm_connection_get_setting(connection, NM_TYPE_SETTING_ETHTOOL)); + if (!s_ethtool) + return; + + ethtool_state = g_new0(EthtoolState, 1); + ethtool_state->ifindex = ifindex; + + _ethtool_features_set(self, platform, ethtool_state, s_ethtool); + _ethtool_coalesce_set(self, platform, ethtool_state, s_ethtool); + _ethtool_ring_set(self, platform, ethtool_state, s_ethtool); + + if (ethtool_state->features || ethtool_state->coalesce || ethtool_state->ring) + priv->ethtool_state = g_steal_pointer(ðtool_state); } /*****************************************************************************/ static gboolean -is_loopback (NMDevice *self) +is_loopback(NMDevice *self) { - return NM_IS_DEVICE_GENERIC (self) - && NM_DEVICE_GET_PRIVATE (self)->ifindex == 1; + return NM_IS_DEVICE_GENERIC(self) && NM_DEVICE_GET_PRIVATE(self)->ifindex == 1; } gboolean -nm_device_is_vpn (NMDevice *self) +nm_device_is_vpn(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - /* NetworkManager currently treats VPN connections (loaded from NetworkManager VPN plugins) - * differently. Those are considered VPNs. - * However, some native device types may also be considered VPNs... - * - * We should avoid distinguishing between is-vpn and "regular" devices. Is an (unencrypted) - * IP tunnel a VPN? Is MACSec on top of an IP tunnel a VPN? - * Sometimes we differentiate, but avoid unless reasonable. */ + /* NetworkManager currently treats VPN connections (loaded from NetworkManager VPN plugins) + * differently. Those are considered VPNs. + * However, some native device types may also be considered VPNs... + * + * We should avoid distinguishing between is-vpn and "regular" devices. Is an (unencrypted) + * IP tunnel a VPN? Is MACSec on top of an IP tunnel a VPN? + * Sometimes we differentiate, but avoid unless reasonable. */ - return NM_IS_DEVICE_WIREGUARD (self); + return NM_IS_DEVICE_WIREGUARD(self); } NMSettings * -nm_device_get_settings (NMDevice *self) +nm_device_get_settings(NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->settings; + return NM_DEVICE_GET_PRIVATE(self)->settings; } NMManager * -nm_device_get_manager (NMDevice *self) +nm_device_get_manager(NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->manager; + return NM_DEVICE_GET_PRIVATE(self)->manager; } NMNetns * -nm_device_get_netns (NMDevice *self) +nm_device_get_netns(NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->netns; + return NM_DEVICE_GET_PRIVATE(self)->netns; } NMDedupMultiIndex * -nm_device_get_multi_index (NMDevice *self) +nm_device_get_multi_index(NMDevice *self) { - return nm_netns_get_multi_idx (nm_device_get_netns (self)); + return nm_netns_get_multi_idx(nm_device_get_netns(self)); } NMPlatform * -nm_device_get_platform (NMDevice *self) +nm_device_get_platform(NMDevice *self) { - return nm_netns_get_platform (nm_device_get_netns (self)); + return nm_netns_get_platform(nm_device_get_netns(self)); } static NMConnectivity * -concheck_get_mgr (NMDevice *self) +concheck_get_mgr(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (G_UNLIKELY (!priv->concheck_mgr)) - priv->concheck_mgr = g_object_ref (nm_connectivity_get ()); - return priv->concheck_mgr; + if (G_UNLIKELY(!priv->concheck_mgr)) + priv->concheck_mgr = g_object_ref(nm_connectivity_get()); + return priv->concheck_mgr; } NMIP4Config * -nm_device_ip4_config_new (NMDevice *self) +nm_device_ip4_config_new(NMDevice *self) { - return nm_ip4_config_new (nm_device_get_multi_index (self), - nm_device_get_ip_ifindex (self)); + return nm_ip4_config_new(nm_device_get_multi_index(self), nm_device_get_ip_ifindex(self)); } NMIP6Config * -nm_device_ip6_config_new (NMDevice *self) +nm_device_ip6_config_new(NMDevice *self) { - return nm_ip6_config_new (nm_device_get_multi_index (self), - nm_device_get_ip_ifindex (self)); + return nm_ip6_config_new(nm_device_get_multi_index(self), nm_device_get_ip_ifindex(self)); } NMIPConfig * -nm_device_ip_config_new (NMDevice *self, int addr_family) +nm_device_ip_config_new(NMDevice *self, int addr_family) { - nm_assert_addr_family (addr_family); + nm_assert_addr_family(addr_family); - return addr_family == AF_INET - ? (gpointer) nm_device_ip4_config_new (self) - : (gpointer) nm_device_ip6_config_new (self); + return addr_family == AF_INET ? (gpointer) nm_device_ip4_config_new(self) + : (gpointer) nm_device_ip6_config_new(self); +} + +NML3ConfigData * +nm_device_create_l3_config_data(NMDevice *self) +{ + int ifindex; + + nm_assert(NM_IS_DEVICE(self)); + + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex <= 0) + g_return_val_if_reached(NULL); + + return nm_l3_config_data_new(nm_device_get_multi_index(self), ifindex); } static void -applied_config_clear (AppliedConfig *config) +applied_config_clear(AppliedConfig *config) { - g_clear_object (&config->current); - g_clear_object (&config->orig); + g_clear_object(&config->current); + g_clear_object(&config->orig); } static void -applied_config_init (AppliedConfig *config, gpointer ip_config) +applied_config_init(AppliedConfig *config, gpointer ip_config) { - nm_assert ( !ip_config - || (!config->orig && !config->current) - || nm_ip_config_get_addr_family (ip_config) == nm_ip_config_get_addr_family (config->orig ?: config->current)); - nm_assert ( !ip_config - || NM_IS_IP_CONFIG (ip_config, AF_UNSPEC)); + nm_assert(!ip_config || (!config->orig && !config->current) + || nm_ip_config_get_addr_family(ip_config) + == nm_ip_config_get_addr_family(config->orig ?: config->current)); + nm_assert(!ip_config || NM_IS_IP_CONFIG(ip_config)); - nm_g_object_ref (ip_config); - applied_config_clear (config); - config->orig = ip_config; + nm_g_object_ref(ip_config); + applied_config_clear(config); + config->orig = ip_config; } static void -applied_config_init_new (AppliedConfig *config, NMDevice *self, int addr_family) +applied_config_init_new(AppliedConfig *config, NMDevice *self, int addr_family) { - gs_unref_object NMIPConfig *c = nm_device_ip_config_new (self, addr_family); + gs_unref_object NMIPConfig *c = nm_device_ip_config_new(self, addr_family); - applied_config_init (config, c); + applied_config_init(config, c); } static NMIPConfig * -applied_config_get_current (AppliedConfig *config) +applied_config_get_current(AppliedConfig *config) { - return config->current ?: config->orig; + return config->current ?: config->orig; } static void -applied_config_add_address (AppliedConfig *config, const NMPlatformIPAddress *address) +applied_config_add_address(AppliedConfig *config, const NMPlatformIPAddress *address) { - if (config->orig) - nm_ip_config_add_address (config->orig, address); - else - nm_assert (!config->current); + if (config->orig) + nm_ip_config_add_address(config->orig, address); + else + nm_assert(!config->current); - if (config->current) - nm_ip_config_add_address (config->current, address); + if (config->current) + nm_ip_config_add_address(config->current, address); } static void -applied_config_add_nameserver (AppliedConfig *config, const NMIPAddr *ns) +applied_config_add_nameserver(AppliedConfig *config, const NMIPAddr *ns) { - if (config->orig) - nm_ip_config_add_nameserver (config->orig, ns); - else - nm_assert (!config->current); + if (config->orig) + nm_ip_config_add_nameserver(config->orig, ns); + else + nm_assert(!config->current); - if (config->current) - nm_ip_config_add_nameserver (config->current, ns); + if (config->current) + nm_ip_config_add_nameserver(config->current, ns); } static void -applied_config_add_search (AppliedConfig *config, const char *new) +applied_config_add_search(AppliedConfig *config, const char *new) { - if (config->orig) - nm_ip_config_add_search (config->orig, new); - else - nm_assert (!config->current); + if (config->orig) + nm_ip_config_add_search(config->orig, new); + else + nm_assert(!config->current); - if (config->current) - nm_ip_config_add_search (config->current, new); + if (config->current) + nm_ip_config_add_search(config->current, new); } static void -applied_config_reset_searches (AppliedConfig *config) +applied_config_reset_searches(AppliedConfig *config) { - if (config->orig) - nm_ip_config_reset_searches (config->orig); - else - nm_assert (!config->current); + if (config->orig) + nm_ip_config_reset_searches(config->orig); + else + nm_assert(!config->current); - if (config->current) - nm_ip_config_reset_searches (config->current); + if (config->current) + nm_ip_config_reset_searches(config->current); } static void -applied_config_reset_nameservers (AppliedConfig *config) +applied_config_reset_nameservers(AppliedConfig *config) { - if (config->orig) - nm_ip_config_reset_nameservers (config->orig); - else - nm_assert (!config->current); + if (config->orig) + nm_ip_config_reset_nameservers(config->orig); + else + nm_assert(!config->current); - if (config->current) - nm_ip_config_reset_nameservers (config->current); + if (config->current) + nm_ip_config_reset_nameservers(config->current); } /*****************************************************************************/ -static -NM_UTILS_LOOKUP_STR_DEFINE (_sys_iface_state_to_str, NMDeviceSysIfaceState, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, "external"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_SYS_IFACE_STATE_ASSUME, "assume"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_SYS_IFACE_STATE_MANAGED, "managed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_SYS_IFACE_STATE_REMOVED, "removed"), -); +static NM_UTILS_LOOKUP_STR_DEFINE( + _sys_iface_state_to_str, + NMDeviceSysIfaceState, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, "external"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_ASSUME, "assume"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_MANAGED, "managed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_REMOVED, "removed"), ); NMDeviceSysIfaceState -nm_device_sys_iface_state_get (NMDevice *self) +nm_device_sys_iface_state_get(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); - return NM_DEVICE_GET_PRIVATE (self)->sys_iface_state; + return NM_DEVICE_GET_PRIVATE(self)->sys_iface_state; } gboolean -nm_device_sys_iface_state_is_external (NMDevice *self) +nm_device_sys_iface_state_is_external(NMDevice *self) { - return NM_IN_SET (nm_device_sys_iface_state_get (self), - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); + return NM_IN_SET(nm_device_sys_iface_state_get(self), NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); } gboolean -nm_device_sys_iface_state_is_external_or_assume (NMDevice *self) +nm_device_sys_iface_state_is_external_or_assume(NMDevice *self) { - return NM_IN_SET (nm_device_sys_iface_state_get (self), - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME); + return NM_IN_SET(nm_device_sys_iface_state_get(self), + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME); } void -nm_device_sys_iface_state_set (NMDevice *self, - NMDeviceSysIfaceState sys_iface_state) +nm_device_sys_iface_state_set(NMDevice *self, NMDeviceSysIfaceState sys_iface_state) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IN_SET (sys_iface_state, - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME, - NM_DEVICE_SYS_IFACE_STATE_MANAGED, - NM_DEVICE_SYS_IFACE_STATE_REMOVED)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_IN_SET(sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME, + NM_DEVICE_SYS_IFACE_STATE_MANAGED, + NM_DEVICE_SYS_IFACE_STATE_REMOVED)); - priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->sys_iface_state != sys_iface_state) { - _LOGT (LOGD_DEVICE, "sys-iface-state: %s -> %s", - _sys_iface_state_to_str (priv->sys_iface_state), - _sys_iface_state_to_str (sys_iface_state)); - priv->sys_iface_state = sys_iface_state; - } + priv = NM_DEVICE_GET_PRIVATE(self); + if (priv->sys_iface_state != sys_iface_state) { + _LOGT(LOGD_DEVICE, + "sys-iface-state: %s -> %s", + _sys_iface_state_to_str(priv->sys_iface_state), + _sys_iface_state_to_str(sys_iface_state)); + priv->sys_iface_state_ = sys_iface_state; + } - /* this function only sets a flag, no immediate actions are initiated. - * - * If you change this, make sure that all callers are fine with such actions. */ + /* this function only sets a flag, no immediate actions are initiated. + * + * If you change this, make sure that all callers are fine with such actions. */ - nm_assert (priv->sys_iface_state == sys_iface_state); + nm_assert(priv->sys_iface_state == sys_iface_state); } static void -_active_connection_set_state_flags_full (NMDevice *self, - NMActivationStateFlags flags, - NMActivationStateFlags mask) +_active_connection_set_state_flags_full(NMDevice * self, + NMActivationStateFlags flags, + NMActivationStateFlags mask) { - NMActiveConnection *ac; + NMActiveConnection *ac; - ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (self)); - if (ac) - nm_active_connection_set_state_flags_full (ac, flags, mask); + ac = NM_ACTIVE_CONNECTION(nm_device_get_act_request(self)); + if (ac) + nm_active_connection_set_state_flags_full(ac, flags, mask); } static void -_active_connection_set_state_flags (NMDevice *self, - NMActivationStateFlags flags) +_active_connection_set_state_flags(NMDevice *self, NMActivationStateFlags flags) { - _active_connection_set_state_flags_full (self, flags, flags); + _active_connection_set_state_flags_full(self, flags, flags); } /*****************************************************************************/ void -nm_device_assume_state_get (NMDevice *self, - gboolean *out_assume_state_guess_assume, - const char **out_assume_state_connection_uuid) +nm_device_assume_state_get(NMDevice * self, + gboolean * out_assume_state_guess_assume, + const char **out_assume_state_connection_uuid) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); + 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); + 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) +_assume_state_set(NMDevice * self, + gboolean assume_state_guess_assume, + const char *assume_state_connection_uuid) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - nm_assert (NM_IS_DEVICE (self)); + 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; + 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); + _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) +nm_device_assume_state_reset(NMDevice *self) { - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - _assume_state_set (self, FALSE, NULL); + _assume_state_set(self, FALSE, NULL); } /*****************************************************************************/ static void -init_ip_config_dns_priority (NMDevice *self, NMIPConfig *config) +init_ip_config_dns_priority(NMDevice *self, NMIPConfig *config) { - const char *property; - int priority; + const char *property; + int priority; - property = (nm_ip_config_get_addr_family (config) == AF_INET) - ? NM_CON_DEFAULT ("ipv4.dns-priority") - : NM_CON_DEFAULT ("ipv6.dns-priority"); + property = (nm_ip_config_get_addr_family(config) == AF_INET) + ? NM_CON_DEFAULT("ipv4.dns-priority") + : NM_CON_DEFAULT("ipv6.dns-priority"); - priority = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - property, - self, - G_MININT, - G_MAXINT, - 0); + priority = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + property, + self, + G_MININT, + G_MAXINT, + 0); - if (priority == 0) { - priority = nm_device_is_vpn (self) - ? NM_DNS_PRIORITY_DEFAULT_VPN - : NM_DNS_PRIORITY_DEFAULT_NORMAL; - } + if (priority == 0) { + priority = + nm_device_is_vpn(self) ? NM_DNS_PRIORITY_DEFAULT_VPN : NM_DNS_PRIORITY_DEFAULT_NORMAL; + } - nm_ip_config_set_dns_priority (config, priority); + nm_ip_config_set_dns_priority(config, priority); } /*****************************************************************************/ static char * -nm_device_sysctl_ip_conf_get (NMDevice *self, - int addr_family, - const char *property) +nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property) { - const char *ifname; + const char *ifname; - nm_assert_addr_family (addr_family); + nm_assert_addr_family(addr_family); - ifname = nm_device_get_ip_iface_from_platform (self); - if (!ifname) - return NULL; - return nm_platform_sysctl_ip_conf_get (nm_device_get_platform (self), addr_family, ifname, property); + ifname = nm_device_get_ip_iface_from_platform(self); + if (!ifname) + return NULL; + return nm_platform_sysctl_ip_conf_get(nm_device_get_platform(self), + addr_family, + ifname, + property); } static gint64 -nm_device_sysctl_ip_conf_get_int_checked (NMDevice *self, - int addr_family, - const char *property, - guint base, - gint64 min, - gint64 max, - gint64 fallback) -{ - const char *ifname; - - nm_assert_addr_family (addr_family); - - ifname = nm_device_get_ip_iface_from_platform (self); - if (!ifname) { - errno = EINVAL; - return fallback; - } - return nm_platform_sysctl_ip_conf_get_int_checked (nm_device_get_platform (self), - addr_family, - ifname, - property, - base, - min, - max, - fallback); +nm_device_sysctl_ip_conf_get_int_checked(NMDevice * self, + int addr_family, + const char *property, + guint base, + gint64 min, + gint64 max, + gint64 fallback) +{ + const char *ifname; + + nm_assert_addr_family(addr_family); + + ifname = nm_device_get_ip_iface_from_platform(self); + if (!ifname) { + errno = EINVAL; + return fallback; + } + return nm_platform_sysctl_ip_conf_get_int_checked(nm_device_get_platform(self), + addr_family, + ifname, + property, + base, + min, + max, + fallback); } static void -set_ipv6_token (NMDevice *self, NMUtilsIPv6IfaceId iid, const char *token_str) -{ - NMPlatform *platform; - int ifindex; - const NMPlatformLink *link; - char buf[32]; - gint64 val; - - /* Setting the kernel token is not strictly necessary as the - * IPv6 address is generated in userspace. However it is - * convenient so that users can see the token with iproute - * ('ip token'). */ - platform = nm_device_get_platform (self); - ifindex = nm_device_get_ip_ifindex (self); - link = nm_platform_link_get (platform, ifindex); - - if (link && link->inet6_token.id == iid.id) { - _LOGT (LOGD_DEVICE | LOGD_IP6, "token %s already set", token_str); - return; - } - - /* The kernel allows setting a token only when 'accept_ra' - * is 1: temporarily flip it if necessary; unfortunately - * this will also generate an additional Router Solicitation - * from kernel. */ - val = nm_device_sysctl_ip_conf_get_int_checked (self, - AF_INET6, - "accept_ra", - 10, - G_MININT32, - G_MAXINT32, - 1); - if (val != 1) - nm_device_sysctl_ip_conf_set (self, AF_INET6, "accept_ra", "1"); - - nm_platform_link_set_ipv6_token (platform, ifindex, iid); - - if (val != 1) { - nm_sprintf_buf (buf, "%d", (int) val); - nm_device_sysctl_ip_conf_set (self, AF_INET6, "accept_ra", buf); - } +set_ipv6_token(NMDevice *self, NMUtilsIPv6IfaceId iid, const char *token_str) +{ + NMPlatform * platform; + int ifindex; + const NMPlatformLink *link; + char buf[32]; + gint64 val; + + /* Setting the kernel token is not strictly necessary as the + * IPv6 address is generated in userspace. However it is + * convenient so that users can see the token with iproute + * ('ip token'). */ + platform = nm_device_get_platform(self); + ifindex = nm_device_get_ip_ifindex(self); + link = nm_platform_link_get(platform, ifindex); + + if (link && link->inet6_token.id == iid.id) { + _LOGT(LOGD_DEVICE | LOGD_IP6, "token %s already set", token_str); + return; + } + + /* The kernel allows setting a token only when 'accept_ra' + * is 1: temporarily flip it if necessary; unfortunately + * this will also generate an additional Router Solicitation + * from kernel. */ + val = nm_device_sysctl_ip_conf_get_int_checked(self, + AF_INET6, + "accept_ra", + 10, + G_MININT32, + G_MAXINT32, + 1); + if (val != 1) + nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", "1"); + + nm_platform_link_set_ipv6_token(platform, ifindex, iid); + + if (val != 1) { + nm_sprintf_buf(buf, "%d", (int) val); + nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", buf); + } } gboolean -nm_device_sysctl_ip_conf_set (NMDevice *self, - int addr_family, - const char *property, - const char *value) -{ - NMPlatform *platform = nm_device_get_platform (self); - gs_free char *value_to_free = NULL; - const char *ifname; - - nm_assert_addr_family (addr_family); - - ifname = nm_device_get_ip_iface_from_platform (self); - if (!ifname) - return FALSE; - - if (!value) { - /* Set to a default value when we've got a NULL @value. */ - value_to_free = nm_platform_sysctl_ip_conf_get (platform, - addr_family, - "default", - property); - value = value_to_free; - if (!value) - return FALSE; - } - - return nm_platform_sysctl_ip_conf_set (platform, - addr_family, - ifname, - property, - value); +nm_device_sysctl_ip_conf_set(NMDevice * self, + int addr_family, + const char *property, + const char *value) +{ + NMPlatform * platform = nm_device_get_platform(self); + gs_free char *value_to_free = NULL; + const char * ifname; + + nm_assert_addr_family(addr_family); + + ifname = nm_device_get_ip_iface_from_platform(self); + if (!ifname) + return FALSE; + + if (!value) { + /* Set to a default value when we've got a NULL @value. */ + value_to_free = nm_platform_sysctl_ip_conf_get(platform, addr_family, "default", property); + value = value_to_free; + if (!value) + return FALSE; + } + + return nm_platform_sysctl_ip_conf_set(platform, addr_family, ifname, property, value); } /*****************************************************************************/ gboolean -nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps) +nm_device_has_capability(NMDevice *self, NMDeviceCapabilities caps) { - return NM_FLAGS_ANY (NM_DEVICE_GET_PRIVATE (self)->capabilities, caps); + return NM_FLAGS_ANY(NM_DEVICE_GET_PRIVATE(self)->capabilities, caps); } static void -_add_capabilities (NMDevice *self, NMDeviceCapabilities capabilities) +_add_capabilities(NMDevice *self, NMDeviceCapabilities capabilities) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!NM_FLAGS_ALL (priv->capabilities, capabilities)) { - priv->capabilities |= capabilities; - _notify (self, PROP_CAPABILITIES); - } -} - -/*****************************************************************************/ - -static const char * -_get_stable_id (NMDevice *self, - NMConnection *connection, - NMUtilsStableType *out_stable_type) -{ - NMDevicePrivate *priv; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert (NM_IS_CONNECTION (connection)); - nm_assert (out_stable_type); - - priv = NM_DEVICE_GET_PRIVATE (self); - - /* we cache the generated stable ID for the time of an activation. - * - * The reason is, that we don't want the stable-id to change as long - * as the device is active. - * - * Especially with ${RANDOM} stable-id we want to generate *one* configuration - * for each activation. */ - if (G_UNLIKELY (!priv->current_stable_id)) { - gs_free char *default_id = NULL; - gs_free char *generated = NULL; - NMUtilsStableType stable_type; - NMSettingConnection *s_con; - gboolean hwaddr_is_fake; - const char *hwaddr; - const char *stable_id; - const char *uuid; - - s_con = nm_connection_get_setting_connection (connection); - - stable_id = nm_setting_connection_get_stable_id (s_con); - - if (!stable_id) { - default_id = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.stable-id"), - self); - stable_id = default_id; - } - - uuid = nm_connection_get_uuid (connection); - - /* the cloned-mac-address may be generated based on the stable-id. - * Thus, at this point, we can only use the permanent MAC address - * as seed. */ - hwaddr = nm_device_get_permanent_hw_address_full (self, TRUE, &hwaddr_is_fake); - - stable_type = nm_utils_stable_id_parse (stable_id, - nm_device_get_ip_iface (self), - !hwaddr_is_fake ? hwaddr : NULL, - nm_utils_boot_id_str (), - uuid, - &generated); - - /* current_stable_id_type is a bitfield! */ - priv->current_stable_id_type = stable_type; - nm_assert (stable_type <= (NMUtilsStableType) 0x3); - nm_assert (stable_type + (NMUtilsStableType) 1 > (NMUtilsStableType) 0); - nm_assert (priv->current_stable_id_type == stable_type); - - if (stable_type == NM_UTILS_STABLE_TYPE_UUID) - priv->current_stable_id = g_strdup (uuid); - else if (stable_type == NM_UTILS_STABLE_TYPE_STABLE_ID) - priv->current_stable_id = g_strdup (stable_id); - else if (stable_type == NM_UTILS_STABLE_TYPE_GENERATED) - priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_generated_complete (generated)); - else { - nm_assert (stable_type == NM_UTILS_STABLE_TYPE_RANDOM); - priv->current_stable_id = nm_str_realloc (nm_utils_stable_id_random ()); - } - _LOGT (LOGD_DEVICE, - "stable-id: type=%d, \"%s\"" - "%s%s%s", - (int) priv->current_stable_id_type, - priv->current_stable_id, - NM_PRINT_FMT_QUOTED (stable_type == NM_UTILS_STABLE_TYPE_GENERATED, " from \"", generated, "\"", "")); - } - - nm_assert (priv->current_stable_id); - *out_stable_type = priv->current_stable_id_type; - return priv->current_stable_id; + if (!NM_FLAGS_ALL(priv->capabilities, capabilities)) { + priv->capabilities |= capabilities; + _notify(self, PROP_CAPABILITIES); + } } /*****************************************************************************/ -static -NM_UTILS_LOOKUP_STR_DEFINE (_ip_state_to_string, NMDeviceIPState, - NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_WAIT, "wait"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_CONF, "conf"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_DONE, "done"), - NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_IP_STATE_FAIL, "fail"), -); +static NM_UTILS_LOOKUP_STR_DEFINE(_ip_state_to_string, + NMDeviceIPState, + NM_UTILS_LOOKUP_DEFAULT_WARN("unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_WAIT, "wait"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_CONF, "conf"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_DONE, "done"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_FAIL, "fail"), ); static void -_set_ip_state (NMDevice *self, int addr_family, NMDeviceIPState new_state) +_set_ip_state(NMDevice *self, int addr_family, NMDeviceIPState new_state) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); - nm_assert_addr_family (addr_family); + nm_assert_addr_family(addr_family); - if (priv->ip_state_x[IS_IPv4] == new_state) - return; + if (priv->ip_state_x[IS_IPv4] == new_state) + return; - _LOGT (LOGD_DEVICE, "ip%c-state: set to %d (%s)", - nm_utils_addr_family_to_char (addr_family), - (int) new_state, - _ip_state_to_string (new_state)); + _LOGT(LOGD_DEVICE, + "ip%c-state: set to %d (%s)", + nm_utils_addr_family_to_char(addr_family), + (int) new_state, + _ip_state_to_string(new_state)); - priv->ip_state_x_[IS_IPv4] = new_state; + priv->ip_state_x_[IS_IPv4] = new_state; - if (new_state == NM_DEVICE_IP_STATE_DONE) { - /* we only set the IPx_READY flag once we reach NM_DEVICE_IP_STATE_DONE state. We don't - * ever clear it, even if we later enter NM_DEVICE_IP_STATE_FAIL state. - * - * This is not documented/guaranteed behavior, but seems to make sense for now. */ - _active_connection_set_state_flags (self, - addr_family == AF_INET - ? NM_ACTIVATION_STATE_FLAG_IP4_READY - : NM_ACTIVATION_STATE_FLAG_IP6_READY); - } + if (new_state == NM_DEVICE_IP_STATE_DONE) { + /* we only set the IPx_READY flag once we reach NM_DEVICE_IP_STATE_DONE state. We don't + * ever clear it, even if we later enter NM_DEVICE_IP_STATE_FAIL state. + * + * This is not documented/guaranteed behavior, but seems to make sense for now. */ + _active_connection_set_state_flags(self, + addr_family == AF_INET + ? NM_ACTIVATION_STATE_FLAG_IP4_READY + : NM_ACTIVATION_STATE_FLAG_IP6_READY); + } } /*****************************************************************************/ const char * -nm_device_get_udi (NMDevice *self) +nm_device_get_udi(NMDevice *self) { - g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail(self != NULL, NULL); - return NM_DEVICE_GET_PRIVATE (self)->udi; + return NM_DEVICE_GET_PRIVATE(self)->udi; } const char * -nm_device_get_iface (NMDevice *self) +nm_device_get_iface(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->iface; + return NM_DEVICE_GET_PRIVATE(self)->iface; +} + +static gboolean +_set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + int * p_ifindex; + + if (ifindex < 0) + ifindex = 0; + + p_ifindex = is_ip_ifindex ? &priv->ip_ifindex_ : &priv->ifindex_; + + if (*p_ifindex == ifindex) + return FALSE; + + *p_ifindex = ifindex; + + _LOGD(LOGD_DEVICE, "ifindex: set %sifindex %d", is_ip_ifindex ? "ip-" : "", ifindex); + + if (!is_ip_ifindex) + _notify(self, PROP_IFINDEX); + + return TRUE; } /** @@ -1763,69 +2836,64 @@ nm_device_get_iface (NMDevice *self) * Returns: %TRUE if the device took control of the link, %FALSE otherwise */ gboolean -nm_device_take_over_link (NMDevice *self, int ifindex, char **old_name, GError **error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const NMPlatformLink *plink; - NMPlatform *platform; - - nm_assert (ifindex > 0); - NM_SET_OUT (old_name, NULL); - - if ( priv->ifindex > 0 - && priv->ifindex != ifindex) { - nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, - "the device already has ifindex %d", - priv->ifindex); - return FALSE; - } - - platform = nm_device_get_platform (self); - plink = nm_platform_link_get (platform, ifindex); - if (!plink) { - nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, - "link %d not found", ifindex); - return FALSE; - } - - if (!nm_streq (plink->name, nm_device_get_iface (self))) { - gboolean up; - gboolean success; - gs_free char *name = NULL; - - up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP); - name = g_strdup (plink->name); - - /* Rename the link to the device ifname */ - if (up) - nm_platform_link_set_down (platform, ifindex); - success = nm_platform_link_set_name (platform, ifindex, nm_device_get_iface (self)); - if (up) - nm_platform_link_set_up (platform, ifindex, NULL); - - if (!success) { - nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, - "failure renaming link %d", ifindex); - return FALSE; - } - - NM_SET_OUT (old_name, g_steal_pointer (&name)); - } - - if (priv->ifindex != ifindex) { - priv->ifindex = ifindex; - _notify (self, PROP_IFINDEX); - } - - return TRUE; +nm_device_take_over_link(NMDevice *self, int ifindex, char **old_name, GError **error) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const NMPlatformLink *plink; + NMPlatform * platform; + + nm_assert(ifindex > 0); + NM_SET_OUT(old_name, NULL); + + if (priv->ifindex > 0 && priv->ifindex != ifindex) { + nm_utils_error_set(error, + NM_UTILS_ERROR_UNKNOWN, + "the device already has ifindex %d", + priv->ifindex); + return FALSE; + } + + platform = nm_device_get_platform(self); + plink = nm_platform_link_get(platform, ifindex); + if (!plink) { + nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "link %d not found", ifindex); + return FALSE; + } + + if (!nm_streq(plink->name, nm_device_get_iface(self))) { + gboolean up; + gboolean success; + gs_free char *name = NULL; + + up = NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP); + name = g_strdup(plink->name); + + /* Rename the link to the device ifname */ + if (up) + nm_platform_link_set_down(platform, ifindex); + success = nm_platform_link_set_name(platform, ifindex, nm_device_get_iface(self)); + if (up) + nm_platform_link_set_up(platform, ifindex, NULL); + + if (!success) { + nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "failure renaming link %d", ifindex); + return FALSE; + } + + NM_SET_OUT(old_name, g_steal_pointer(&name)); + } + + _set_ifindex(self, ifindex, FALSE); + + return TRUE; } int -nm_device_get_ifindex (NMDevice *self) +nm_device_get_ifindex(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), 0); + g_return_val_if_fail(NM_IS_DEVICE(self), 0); - return NM_DEVICE_GET_PRIVATE (self)->ifindex; + return NM_DEVICE_GET_PRIVATE(self)->ifindex; } /** @@ -1838,9 +2906,9 @@ nm_device_get_ifindex (NMDevice *self) * Returns: %TRUE if the device is a software-based device */ gboolean -nm_device_is_software (NMDevice *self) +nm_device_is_software(NMDevice *self) { - return NM_FLAGS_HAS (NM_DEVICE_GET_PRIVATE (self)->capabilities, NM_DEVICE_CAP_IS_SOFTWARE); + return NM_FLAGS_HAS(NM_DEVICE_GET_PRIVATE(self)->capabilities, NM_DEVICE_CAP_IS_SOFTWARE); } /** @@ -1850,116 +2918,113 @@ nm_device_is_software (NMDevice *self) * Returns: %TRUE if the device exists, %FALSE if the device is a placeholder */ gboolean -nm_device_is_real (NMDevice *self) +nm_device_is_real(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - return NM_DEVICE_GET_PRIVATE (self)->real; + return NM_DEVICE_GET_PRIVATE(self)->real; } const char * -nm_device_get_ip_iface (NMDevice *self) +nm_device_get_ip_iface(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail(self != NULL, NULL); - priv = NM_DEVICE_GET_PRIVATE (self); - /* If it's not set, default to iface */ - return priv->ip_iface ?: priv->iface; + priv = NM_DEVICE_GET_PRIVATE(self); + /* If it's not set, default to iface */ + return priv->ip_iface ?: priv->iface; } const char * -nm_device_get_ip_iface_from_platform (NMDevice *self) +nm_device_get_ip_iface_from_platform(NMDevice *self) { - int ifindex; + int ifindex; - ifindex = nm_device_get_ip_ifindex (self); - if (ifindex <= 0) - return NULL; + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex <= 0) + return NULL; - return nm_platform_link_get_name (nm_device_get_platform (self), ifindex); + return nm_platform_link_get_name(nm_device_get_platform(self), ifindex); } int -nm_device_get_ip_ifindex (const NMDevice *self) +nm_device_get_ip_ifindex(const NMDevice *self) { - const NMDevicePrivate *priv; + const NMDevicePrivate *priv; - g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail(self != NULL, 0); - priv = NM_DEVICE_GET_PRIVATE (self); - /* If it's not set, default to ifindex */ - return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; + priv = NM_DEVICE_GET_PRIVATE(self); + /* If it's not set, default to ifindex */ + return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; } static void -_set_ip_ifindex (NMDevice *self, - int ifindex, - const char *ifname) +_set_ip_ifindex(NMDevice *self, int ifindex, const char *ifname) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPlatform *platform; - gboolean eq_name; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMPlatform * platform; + gboolean eq_name; - /* normalize arguments */ - if (ifindex <= 0) { - ifindex = 0; - ifname = NULL; - } + /* normalize arguments */ + if (ifindex <= 0) { + ifindex = 0; + ifname = NULL; + } - eq_name = nm_streq0 (priv->ip_iface, ifname); + eq_name = nm_streq0(priv->ip_iface, ifname); - if ( eq_name - && priv->ip_ifindex == ifindex) - return; + if (eq_name && priv->ip_ifindex == ifindex) + return; - _LOGD (LOGD_DEVICE, "ip-ifindex: update ip-interface to %s%s%s, ifindex %d", - NM_PRINT_FMT_QUOTE_STRING (ifname), - ifindex); + _LOGD(LOGD_DEVICE, + "ip-ifindex: update ip-interface to %s%s%s, ifindex %d", + NM_PRINT_FMT_QUOTE_STRING(ifname), + ifindex); - priv->ip_ifindex = ifindex; - if (!eq_name) { - g_free (priv->ip_iface); - priv->ip_iface = g_strdup (ifname); - _notify (self, PROP_IP_IFACE); - } + _set_ifindex(self, ifindex, TRUE); - if (priv->ip_ifindex > 0) { - platform = nm_device_get_platform (self); + if (!eq_name) { + g_free(priv->ip_iface_); + priv->ip_iface_ = g_strdup(ifname); + _notify(self, PROP_IP_IFACE); + } - nm_platform_process_events_ensure_link (platform, - priv->ip_ifindex, - priv->ip_iface); + if (priv->ip_ifindex > 0) { + platform = nm_device_get_platform(self); - if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) - nm_platform_link_set_user_ipv6ll_enabled (platform, priv->ip_ifindex, TRUE); + nm_platform_process_events_ensure_link(platform, priv->ip_ifindex, priv->ip_iface); - if (!nm_platform_link_is_up (platform, priv->ip_ifindex)) - nm_platform_link_set_up (platform, priv->ip_ifindex, NULL); - } + if (nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) + nm_platform_link_set_user_ipv6ll_enabled(platform, priv->ip_ifindex, TRUE); - /* We don't care about any saved values from the old iface */ - g_hash_table_remove_all (priv->ip6_saved_properties); + if (!nm_platform_link_is_up(platform, priv->ip_ifindex)) + nm_platform_link_set_up(platform, priv->ip_ifindex, NULL); + } + + /* We don't care about any saved values from the old iface */ + g_hash_table_remove_all(priv->ip6_saved_properties); } gboolean -nm_device_set_ip_ifindex (NMDevice *self, int ifindex) +nm_device_set_ip_ifindex(NMDevice *self, int ifindex) { - char ifname_buf[IFNAMSIZ]; - const char *ifname = NULL; + char ifname_buf[IFNAMSIZ]; + const char *ifname = NULL; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (nm_device_is_activating (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(nm_device_is_activating(self), FALSE); - if (ifindex > 0) { - ifname = nm_platform_if_indextoname (nm_device_get_platform (self), ifindex, ifname_buf); - if (!ifname) - _LOGW (LOGD_DEVICE, "ip-ifindex: ifindex %d not found", ifindex); - } + if (ifindex > 0) { + ifname = nm_platform_if_indextoname(nm_device_get_platform(self), ifindex, ifname_buf); + if (!ifname) + _LOGW(LOGD_DEVICE, "ip-ifindex: ifindex %d not found", ifindex); + } - _set_ip_ifindex (self, ifindex, ifname); - return ifindex > 0; + _set_ip_ifindex(self, ifindex, ifname); + return ifindex > 0; } /** @@ -1973,367 +3038,345 @@ nm_device_set_ip_ifindex (NMDevice *self, int ifindex) * and %FALSE, if @ifname is %NULL or no such interface exists. */ gboolean -nm_device_set_ip_iface (NMDevice *self, const char *ifname) +nm_device_set_ip_iface(NMDevice *self, const char *ifname) { - int ifindex = 0; + int ifindex = 0; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (nm_device_is_activating (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(nm_device_is_activating(self), FALSE); - if (ifname) { - ifindex = nm_platform_if_nametoindex (nm_device_get_platform (self), ifname); - if (ifindex <= 0) - _LOGW (LOGD_DEVICE, "ip-ifindex: ifname %s not found", ifname); - } + if (ifname) { + ifindex = nm_platform_if_nametoindex(nm_device_get_platform(self), ifname); + if (ifindex <= 0) + _LOGW(LOGD_DEVICE, "ip-ifindex: ifname %s not found", ifname); + } - _set_ip_ifindex (self, ifindex, ifname); - return ifindex > 0; -} - -static gboolean -_ip_iface_update (NMDevice *self, const char *ip_iface) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE (self); - - g_return_val_if_fail (priv->ip_iface, FALSE); - g_return_val_if_fail (priv->ip_ifindex > 0, FALSE); - g_return_val_if_fail (ip_iface, FALSE); - - if (!ip_iface[0]) - return FALSE; - - if (nm_streq (priv->ip_iface, ip_iface)) - return FALSE; - - _LOGI (LOGD_DEVICE, "ip-ifname: interface index %d renamed ip_iface (%d) from '%s' to '%s'", - priv->ifindex, priv->ip_ifindex, - priv->ip_iface, ip_iface); - g_free (priv->ip_iface); - priv->ip_iface = g_strdup (ip_iface); - _notify (self, PROP_IP_IFACE); - return TRUE; + _set_ip_ifindex(self, ifindex, ifname); + return ifindex > 0; } /*****************************************************************************/ int -nm_device_parent_get_ifindex (NMDevice *self) +nm_device_parent_get_ifindex(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), 0); + g_return_val_if_fail(NM_IS_DEVICE(self), 0); - priv = NM_DEVICE_GET_PRIVATE (self); - return priv->parent_ifindex; + priv = NM_DEVICE_GET_PRIVATE(self); + return priv->parent_ifindex; } NMDevice * -nm_device_parent_get_device (NMDevice *self) +nm_device_parent_get_device(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->parent_device.obj; + return NM_DEVICE_GET_PRIVATE(self)->parent_device.obj; } static void -parent_changed_notify (NMDevice *self, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent) +parent_changed_notify(NMDevice *self, + int old_ifindex, + NMDevice *old_parent, + int new_ifindex, + NMDevice *new_parent) { - /* empty handler to allow subclasses to always chain up the virtual function. */ + /* empty handler to allow subclasses to always chain up the virtual function. */ } static gboolean -_parent_set_ifindex (NMDevice *self, - int parent_ifindex, - gboolean force_check) -{ - NMDevicePrivate *priv; - NMDevice *parent_device; - gboolean changed = FALSE; - int old_ifindex; - gs_unref_object NMDevice *old_device = NULL; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE (self); - - if (parent_ifindex <= 0) - parent_ifindex = 0; - - old_ifindex = priv->parent_ifindex; - - if (priv->parent_ifindex == parent_ifindex) { - if (parent_ifindex > 0) { - if ( !force_check - && priv->parent_device.obj - && nm_device_get_ifindex (priv->parent_device.obj) == parent_ifindex) - return FALSE; - } else { - if (!priv->parent_device.obj) - return FALSE; - } - } else { - priv->parent_ifindex = parent_ifindex; - changed = TRUE; - } - - if (parent_ifindex > 0) { - parent_device = nm_manager_get_device_by_ifindex (NM_MANAGER_GET, parent_ifindex); - if (parent_device == self) - parent_device = NULL; - } else - parent_device = NULL; - - if (parent_device != priv->parent_device.obj) { - old_device = nm_g_object_ref (priv->parent_device.obj); - nm_dbus_track_obj_path_set (&priv->parent_device, parent_device, TRUE); - changed = TRUE; - } - - if (changed) { - if (priv->parent_ifindex <= 0) - _LOGD (LOGD_DEVICE, "parent: clear"); - else if (!priv->parent_device.obj) - _LOGD (LOGD_DEVICE, "parent: ifindex %d, no device", priv->parent_ifindex); - else { - _LOGD (LOGD_DEVICE, "parent: ifindex %d, device %p, %s", priv->parent_ifindex, - priv->parent_device.obj, nm_device_get_iface (priv->parent_device.obj)); - } - - NM_DEVICE_GET_CLASS (self)->parent_changed_notify (self, old_ifindex, old_device, priv->parent_ifindex, priv->parent_device.obj); - } - return changed; +_parent_set_ifindex(NMDevice *self, int parent_ifindex, gboolean force_check) +{ + NMDevicePrivate *priv; + NMDevice * parent_device; + gboolean changed = FALSE; + int old_ifindex; + gs_unref_object NMDevice *old_device = NULL; + + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (parent_ifindex <= 0) + parent_ifindex = 0; + + old_ifindex = priv->parent_ifindex; + + if (priv->parent_ifindex == parent_ifindex) { + if (parent_ifindex > 0) { + if (!force_check && priv->parent_device.obj + && nm_device_get_ifindex(priv->parent_device.obj) == parent_ifindex) + return FALSE; + } else { + if (!priv->parent_device.obj) + return FALSE; + } + } else { + priv->parent_ifindex = parent_ifindex; + changed = TRUE; + } + + if (parent_ifindex > 0) { + parent_device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, parent_ifindex); + if (parent_device == self) + parent_device = NULL; + } else + parent_device = NULL; + + if (parent_device != priv->parent_device.obj) { + old_device = nm_g_object_ref(priv->parent_device.obj); + nm_dbus_track_obj_path_set(&priv->parent_device, parent_device, TRUE); + changed = TRUE; + } + + if (changed) { + if (priv->parent_ifindex <= 0) + _LOGD(LOGD_DEVICE, "parent: clear"); + else if (!priv->parent_device.obj) + _LOGD(LOGD_DEVICE, "parent: ifindex %d, no device", priv->parent_ifindex); + else { + _LOGD(LOGD_DEVICE, + "parent: ifindex %d, device %p, %s", + priv->parent_ifindex, + priv->parent_device.obj, + nm_device_get_iface(priv->parent_device.obj)); + } + + NM_DEVICE_GET_CLASS(self)->parent_changed_notify(self, + old_ifindex, + old_device, + priv->parent_ifindex, + priv->parent_device.obj); + } + return changed; } void -nm_device_parent_set_ifindex (NMDevice *self, - int parent_ifindex) +nm_device_parent_set_ifindex(NMDevice *self, int parent_ifindex) { - _parent_set_ifindex (self, parent_ifindex, FALSE); + _parent_set_ifindex(self, parent_ifindex, FALSE); } gboolean -nm_device_parent_notify_changed (NMDevice *self, - NMDevice *change_candidate, - gboolean device_removed) +nm_device_parent_notify_changed(NMDevice *self, NMDevice *change_candidate, gboolean device_removed) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - nm_assert (NM_IS_DEVICE (self)); - nm_assert (NM_IS_DEVICE (change_candidate)); + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_DEVICE(change_candidate)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->parent_ifindex > 0) { - if ( priv->parent_device.obj == change_candidate - || priv->parent_ifindex == nm_device_get_ifindex (change_candidate)) - return _parent_set_ifindex (self, priv->parent_ifindex, device_removed); - } - return FALSE; + if (priv->parent_ifindex > 0) { + if (priv->parent_device.obj == change_candidate + || priv->parent_ifindex == nm_device_get_ifindex(change_candidate)) + return _parent_set_ifindex(self, priv->parent_ifindex, device_removed); + } + return FALSE; } /*****************************************************************************/ const char * -nm_device_parent_find_for_connection (NMDevice *self, - const char *current_setting_parent) +nm_device_parent_find_for_connection(NMDevice *self, const char *current_setting_parent) { - const char *new_parent; - NMDevice *parent_device; + const char *new_parent; + NMDevice * parent_device; - parent_device = nm_device_parent_get_device (self); - if (!parent_device) - return NULL; + parent_device = nm_device_parent_get_device(self); + if (!parent_device) + return NULL; - new_parent = nm_device_get_iface (parent_device); - if (!new_parent) - return NULL; + new_parent = nm_device_get_iface(parent_device); + if (!new_parent) + return NULL; - if ( current_setting_parent - && !nm_streq (current_setting_parent, new_parent) - && nm_utils_is_uuid (current_setting_parent)) { - NMSettingsConnection *parent_connection; + if (current_setting_parent && !nm_streq(current_setting_parent, new_parent) + && nm_utils_is_uuid(current_setting_parent)) { + NMSettingsConnection *parent_connection; - /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = nm_settings_get_connection_by_uuid (nm_device_get_settings (self), - current_setting_parent); - if ( parent_connection - && nm_device_check_connection_compatible (parent_device, - nm_settings_connection_get_connection (parent_connection), - NULL)) - return current_setting_parent; - } + /* Don't change a parent specified by UUID if it's still valid */ + parent_connection = nm_settings_get_connection_by_uuid(nm_device_get_settings(self), + current_setting_parent); + if (parent_connection + && nm_device_check_connection_compatible( + parent_device, + nm_settings_connection_get_connection(parent_connection), + NULL)) + return current_setting_parent; + } - return new_parent; + return new_parent; } /*****************************************************************************/ static void -_stats_update_counters (NMDevice *self, - guint64 tx_bytes, - guint64 rx_bytes) +_stats_update_counters(NMDevice *self, guint64 tx_bytes, guint64 rx_bytes) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; + gboolean tx_changed = FALSE; + gboolean rx_changed = FALSE; + + priv = NM_DEVICE_GET_PRIVATE(self); - priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->stats.tx_bytes != tx_bytes) { + priv->stats.tx_bytes = tx_bytes; + tx_changed = TRUE; + } + if (priv->stats.rx_bytes != rx_bytes) { + priv->stats.rx_bytes = rx_bytes; + rx_changed = TRUE; + } - if (priv->stats.tx_bytes != tx_bytes) { - priv->stats.tx_bytes = tx_bytes; - _notify (self, PROP_STATISTICS_TX_BYTES); - } - if (priv->stats.rx_bytes != rx_bytes) { - priv->stats.rx_bytes = rx_bytes; - _notify (self, PROP_STATISTICS_RX_BYTES); - } + nm_gobject_notify_together(self, + tx_changed ? PROP_STATISTICS_TX_BYTES : PROP_0, + rx_changed ? PROP_STATISTICS_RX_BYTES : PROP_0); } static void -_stats_update_counters_from_pllink (NMDevice *self, const NMPlatformLink *pllink) +_stats_update_counters_from_pllink(NMDevice *self, const NMPlatformLink *pllink) { - _stats_update_counters (self, pllink->tx_bytes, pllink->rx_bytes); + _stats_update_counters(self, pllink->tx_bytes, pllink->rx_bytes); } static gboolean -_stats_timeout_cb (gpointer user_data) +_stats_timeout_cb(gpointer user_data) { - NMDevice *self = user_data; - int ifindex; + NMDevice *self = user_data; + int ifindex; - ifindex = nm_device_get_ip_ifindex (self); + ifindex = nm_device_get_ip_ifindex(self); - _LOGT (LOGD_DEVICE, "stats: refresh %d", ifindex); + _LOGT(LOGD_DEVICE, "stats: refresh %d", ifindex); - if (ifindex > 0) - nm_platform_link_refresh (nm_device_get_platform (self), ifindex); + if (ifindex > 0) + nm_platform_link_refresh(nm_device_get_platform(self), ifindex); - return G_SOURCE_CONTINUE; + return G_SOURCE_CONTINUE; } static guint -_stats_refresh_rate_real (guint refresh_rate_ms) +_stats_refresh_rate_real(guint refresh_rate_ms) { - const guint STATS_REFRESH_RATE_MS_MIN = 200; + const guint STATS_REFRESH_RATE_MS_MIN = 200; - if (refresh_rate_ms == 0) - return 0; + if (refresh_rate_ms == 0) + return 0; - if (refresh_rate_ms < STATS_REFRESH_RATE_MS_MIN) { - /* you cannot set the refresh-rate arbitrarly small. E.g. - * setting to 1ms is just killing. Have a lowest number. */ - return STATS_REFRESH_RATE_MS_MIN; - } + if (refresh_rate_ms < STATS_REFRESH_RATE_MS_MIN) { + /* you cannot set the refresh-rate arbitrarily small. E.g. + * setting to 1ms is just killing. Have a lowest number. */ + return STATS_REFRESH_RATE_MS_MIN; + } - return refresh_rate_ms; + return refresh_rate_ms; } static void -_stats_set_refresh_rate (NMDevice *self, guint refresh_rate_ms) +_stats_set_refresh_rate(NMDevice *self, guint refresh_rate_ms) { - NMDevicePrivate *priv; - int ifindex; - guint old_rate; + NMDevicePrivate *priv; + int ifindex; + guint old_rate; - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->stats.refresh_rate_ms == refresh_rate_ms) - return; + if (priv->stats.refresh_rate_ms == refresh_rate_ms) + return; - old_rate = priv->stats.refresh_rate_ms; - priv->stats.refresh_rate_ms = refresh_rate_ms; - _notify (self, PROP_STATISTICS_REFRESH_RATE_MS); + old_rate = priv->stats.refresh_rate_ms; + priv->stats.refresh_rate_ms = refresh_rate_ms; + _notify(self, PROP_STATISTICS_REFRESH_RATE_MS); - _LOGD (LOGD_DEVICE, "stats: set refresh to %u ms", priv->stats.refresh_rate_ms); + _LOGD(LOGD_DEVICE, "stats: set refresh to %u ms", priv->stats.refresh_rate_ms); - if (!nm_device_is_real (self)) - return; + if (!nm_device_is_real(self)) + return; - refresh_rate_ms = _stats_refresh_rate_real (refresh_rate_ms); - if (_stats_refresh_rate_real (old_rate) == refresh_rate_ms) - return; + refresh_rate_ms = _stats_refresh_rate_real(refresh_rate_ms); + if (_stats_refresh_rate_real(old_rate) == refresh_rate_ms) + return; - nm_clear_g_source (&priv->stats.timeout_id); + nm_clear_g_source(&priv->stats.timeout_id); - if (!refresh_rate_ms) - return; + if (!refresh_rate_ms) + return; - /* trigger an initial refresh of the data whenever the refresh-rate changes. - * As we process the result in an idle handler with device_link_changed(), - * we don't get the result right away. */ - ifindex = nm_device_get_ip_ifindex (self); - if (ifindex > 0) - nm_platform_link_refresh (nm_device_get_platform (self), ifindex); + /* trigger an initial refresh of the data whenever the refresh-rate changes. + * As we process the result in an idle handler with device_link_changed(), + * we don't get the result right away. */ + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex > 0) + nm_platform_link_refresh(nm_device_get_platform(self), ifindex); - priv->stats.timeout_id = g_timeout_add (refresh_rate_ms, _stats_timeout_cb, self); + priv->stats.timeout_id = g_timeout_add(refresh_rate_ms, _stats_timeout_cb, self); } /*****************************************************************************/ static gboolean -get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPlatform *platform = nm_device_get_platform (self); - const NMPlatformLink *pllink; - const guint8 *hwaddr; - guint8 pseudo_hwaddr[ETH_ALEN]; - gsize hwaddr_len; - int ifindex; - gboolean success; - - /* If we get here, we *must* have a kernel netdev, which implies an ifindex */ - ifindex = nm_device_get_ip_ifindex (self); - g_return_val_if_fail (ifindex > 0, FALSE); - - pllink = nm_platform_link_get (platform, ifindex); - if ( !pllink - || NM_IN_SET (pllink->type, NM_LINK_TYPE_NONE, NM_LINK_TYPE_UNKNOWN)) - return FALSE; - - hwaddr = nmp_link_address_get (&pllink->l_address, &hwaddr_len); - if (hwaddr_len <= 0) - return FALSE; - - if (pllink->type == NM_LINK_TYPE_6LOWPAN) { - /* If the underlying IEEE 802.15.4 device has a short address we generate - * a "pseudo 48-bit address" that's to be used in the same fashion as a - * wired Ethernet address. The mechanism is specified in Section 6. of - * RFC 4944 */ - guint16 pan_id; - guint16 short_addr; - - short_addr = nm_platform_wpan_get_short_addr (platform, pllink->parent); - if (short_addr != G_MAXUINT16) { - pan_id = nm_platform_wpan_get_pan_id (platform, pllink->parent); - pseudo_hwaddr[0] = short_addr & 0xff; - pseudo_hwaddr[1] = (short_addr >> 8) & 0xff; - pseudo_hwaddr[2] = 0; - pseudo_hwaddr[3] = 0; - pseudo_hwaddr[4] = pan_id & 0xff; - pseudo_hwaddr[5] = (pan_id >> 8) & 0xff; - - hwaddr = pseudo_hwaddr; - hwaddr_len = G_N_ELEMENTS (pseudo_hwaddr); - } - } - - success = nm_utils_get_ipv6_interface_identifier (pllink->type, - hwaddr, - hwaddr_len, - priv->dev_id, - out_iid); - if (!success) { - _LOGW (LOGD_PLATFORM, "failed to generate interface identifier " - "for link type %u hwaddr_len %zu", pllink->type, hwaddr_len); - } - return success; +get_ip_iface_identifier(NMDevice *self, NMUtilsIPv6IfaceId *out_iid) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMPlatform * platform = nm_device_get_platform(self); + const NMPlatformLink *pllink; + const guint8 * hwaddr; + guint8 pseudo_hwaddr[ETH_ALEN]; + gsize hwaddr_len; + int ifindex; + gboolean success; + + /* If we get here, we *must* have a kernel netdev, which implies an ifindex */ + ifindex = nm_device_get_ip_ifindex(self); + g_return_val_if_fail(ifindex > 0, FALSE); + + pllink = nm_platform_link_get(platform, ifindex); + if (!pllink || NM_IN_SET(pllink->type, NM_LINK_TYPE_NONE, NM_LINK_TYPE_UNKNOWN)) + return FALSE; + + hwaddr = nmp_link_address_get(&pllink->l_address, &hwaddr_len); + if (hwaddr_len <= 0) + return FALSE; + + if (pllink->type == NM_LINK_TYPE_6LOWPAN) { + /* If the underlying IEEE 802.15.4 device has a short address we generate + * a "pseudo 48-bit address" that's to be used in the same fashion as a + * wired Ethernet address. The mechanism is specified in Section 6. of + * RFC 4944 */ + guint16 pan_id; + guint16 short_addr; + + short_addr = nm_platform_wpan_get_short_addr(platform, pllink->parent); + if (short_addr != G_MAXUINT16) { + pan_id = nm_platform_wpan_get_pan_id(platform, pllink->parent); + pseudo_hwaddr[0] = short_addr & 0xff; + pseudo_hwaddr[1] = (short_addr >> 8) & 0xff; + pseudo_hwaddr[2] = 0; + pseudo_hwaddr[3] = 0; + pseudo_hwaddr[4] = pan_id & 0xff; + pseudo_hwaddr[5] = (pan_id >> 8) & 0xff; + + hwaddr = pseudo_hwaddr; + hwaddr_len = G_N_ELEMENTS(pseudo_hwaddr); + } + } + + success = nm_utils_get_ipv6_interface_identifier(pllink->type, + hwaddr, + hwaddr_len, + priv->dev_id, + out_iid); + if (!success) { + _LOGW(LOGD_PLATFORM, + "failed to generate interface identifier " + "for link type %u hwaddr_len %zu", + pllink->type, + hwaddr_len); + } + return success; } /** @@ -2352,56 +3395,56 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) * Returns: #TRUE if the @iid could be set */ static gboolean -nm_device_get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *iid, gboolean ignore_token) +nm_device_get_ip_iface_identifier(NMDevice *self, NMUtilsIPv6IfaceId *iid, gboolean ignore_token) { - NMSettingIP6Config *s_ip6; - const char *token = NULL; + NMSettingIP6Config *s_ip6; + const char * token = NULL; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - if (!ignore_token) { - s_ip6 = nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); + if (!ignore_token) { + s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); - g_return_val_if_fail (s_ip6, FALSE); + g_return_val_if_fail(s_ip6, FALSE); - token = nm_setting_ip6_config_get_token (s_ip6); - } - if (token) - return nm_utils_ipv6_interface_identifier_get_from_token (iid, token); - else - return NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, iid); + token = nm_setting_ip6_config_get_token(s_ip6); + } + if (token) + return nm_utils_ipv6_interface_identifier_get_from_token(iid, token); + else + return NM_DEVICE_GET_CLASS(self)->get_ip_iface_identifier(self, iid); } const char * -nm_device_get_driver (NMDevice *self) +nm_device_get_driver(NMDevice *self) { - g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail(self != NULL, NULL); - return NM_DEVICE_GET_PRIVATE (self)->driver; + return NM_DEVICE_GET_PRIVATE(self)->driver; } const char * -nm_device_get_driver_version (NMDevice *self) +nm_device_get_driver_version(NMDevice *self) { - g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail(self != NULL, NULL); - return NM_DEVICE_GET_PRIVATE (self)->driver_version; + return NM_DEVICE_GET_PRIVATE(self)->driver_version; } NMDeviceType -nm_device_get_device_type (NMDevice *self) +nm_device_get_device_type(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_TYPE_UNKNOWN); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_TYPE_UNKNOWN); - return NM_DEVICE_GET_PRIVATE (self)->type; + return NM_DEVICE_GET_PRIVATE(self)->type; } NMLinkType -nm_device_get_link_type (NMDevice *self) +nm_device_get_link_type(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NM_LINK_TYPE_UNKNOWN); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_LINK_TYPE_UNKNOWN); - return NM_DEVICE_GET_PRIVATE (self)->link_type; + return NM_DEVICE_GET_PRIVATE(self)->link_type; } /** @@ -2413,1261 +3456,1142 @@ nm_device_get_link_type (NMDevice *self) * Since: 1.2 **/ NMMetered -nm_device_get_metered (NMDevice *self) +nm_device_get_metered(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NM_METERED_UNKNOWN); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_METERED_UNKNOWN); - return NM_DEVICE_GET_PRIVATE (self)->metered; + return NM_DEVICE_GET_PRIVATE(self)->metered; } guint32 -nm_device_get_route_metric_default (NMDeviceType device_type) -{ - /* Device 'priority' is used for the default route-metric and is based on - * the device type. The settings ipv4.route-metric and ipv6.route-metric - * can overwrite this default. - * - * For both IPv4 and IPv6 we use the same default values. - * - * The route-metric is used for the metric of the routes of device. - * This also applies to the default route. Therefore it affects also - * which device is the "best". - * - * For comparison, note that iproute2 by default adds IPv4 routes with - * metric 0, and IPv6 routes with metric 1024. The latter is the IPv6 - * "user default" in the kernel (NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6). - * In kernel, the full uint32_t range is available for route - * metrics (except for IPv6, where 0 means 1024). - */ - - switch (device_type) { - - /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT). - * - * Note that returning 50 from this function means that this device-type is - * in some aspects a VPN. */ - case NM_DEVICE_TYPE_WIREGUARD: - return NM_VPN_ROUTE_METRIC_DEFAULT; - - case NM_DEVICE_TYPE_ETHERNET: - case NM_DEVICE_TYPE_VETH: - return 100; - case NM_DEVICE_TYPE_MACSEC: - return 125; - case NM_DEVICE_TYPE_INFINIBAND: - return 150; - case NM_DEVICE_TYPE_ADSL: - return 200; - case NM_DEVICE_TYPE_WIMAX: - return 250; - case NM_DEVICE_TYPE_BOND: - return 300; - case NM_DEVICE_TYPE_TEAM: - return 350; - case NM_DEVICE_TYPE_VLAN: - return 400; - case NM_DEVICE_TYPE_MACVLAN: - return 410; - case NM_DEVICE_TYPE_BRIDGE: - return 425; - case NM_DEVICE_TYPE_TUN: - return 450; - case NM_DEVICE_TYPE_PPP: - return 460; - case NM_DEVICE_TYPE_VRF: - return 470; - case NM_DEVICE_TYPE_VXLAN: - return 500; - case NM_DEVICE_TYPE_DUMMY: - return 550; - case NM_DEVICE_TYPE_WIFI: - return 600; - case NM_DEVICE_TYPE_OLPC_MESH: - return 650; - case NM_DEVICE_TYPE_IP_TUNNEL: - return 675; - case NM_DEVICE_TYPE_MODEM: - return 700; - case NM_DEVICE_TYPE_BT: - return 750; - case NM_DEVICE_TYPE_6LOWPAN: - return 775; - case NM_DEVICE_TYPE_OVS_BRIDGE: - case NM_DEVICE_TYPE_OVS_INTERFACE: - case NM_DEVICE_TYPE_OVS_PORT: - return 800; - case NM_DEVICE_TYPE_WPAN: - return 850; - case NM_DEVICE_TYPE_WIFI_P2P: - case NM_DEVICE_TYPE_GENERIC: - return 950; - case NM_DEVICE_TYPE_UNKNOWN: - return 10000; - case NM_DEVICE_TYPE_UNUSED1: - case NM_DEVICE_TYPE_UNUSED2: - /* omit default: to get compiler warning about missing switch cases */ - break; - } - return 11000; +nm_device_get_route_metric_default(NMDeviceType device_type) +{ + /* Device 'priority' is used for the default route-metric and is based on + * the device type. The settings ipv4.route-metric and ipv6.route-metric + * can overwrite this default. + * + * For both IPv4 and IPv6 we use the same default values. + * + * The route-metric is used for the metric of the routes of device. + * This also applies to the default route. Therefore it affects also + * which device is the "best". + * + * For comparison, note that iproute2 by default adds IPv4 routes with + * metric 0, and IPv6 routes with metric 1024. The latter is the IPv6 + * "user default" in the kernel (NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6). + * In kernel, the full uint32_t range is available for route + * metrics (except for IPv6, where 0 means 1024). + */ + + switch (device_type) { + /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT). + * + * Note that returning 50 from this function means that this device-type is + * in some aspects a VPN. */ + case NM_DEVICE_TYPE_WIREGUARD: + return NM_VPN_ROUTE_METRIC_DEFAULT; + + case NM_DEVICE_TYPE_ETHERNET: + case NM_DEVICE_TYPE_VETH: + return 100; + case NM_DEVICE_TYPE_MACSEC: + return 125; + case NM_DEVICE_TYPE_INFINIBAND: + return 150; + case NM_DEVICE_TYPE_ADSL: + return 200; + case NM_DEVICE_TYPE_WIMAX: + return 250; + case NM_DEVICE_TYPE_BOND: + return 300; + case NM_DEVICE_TYPE_TEAM: + return 350; + case NM_DEVICE_TYPE_VLAN: + return 400; + case NM_DEVICE_TYPE_MACVLAN: + return 410; + case NM_DEVICE_TYPE_BRIDGE: + return 425; + case NM_DEVICE_TYPE_TUN: + return 450; + case NM_DEVICE_TYPE_PPP: + return 460; + case NM_DEVICE_TYPE_VRF: + return 470; + case NM_DEVICE_TYPE_VXLAN: + return 500; + case NM_DEVICE_TYPE_DUMMY: + return 550; + case NM_DEVICE_TYPE_WIFI: + return 600; + case NM_DEVICE_TYPE_OLPC_MESH: + return 650; + case NM_DEVICE_TYPE_IP_TUNNEL: + return 675; + case NM_DEVICE_TYPE_MODEM: + return 700; + case NM_DEVICE_TYPE_BT: + return 750; + case NM_DEVICE_TYPE_6LOWPAN: + return 775; + case NM_DEVICE_TYPE_OVS_BRIDGE: + case NM_DEVICE_TYPE_OVS_INTERFACE: + case NM_DEVICE_TYPE_OVS_PORT: + return 800; + case NM_DEVICE_TYPE_WPAN: + return 850; + case NM_DEVICE_TYPE_WIFI_P2P: + case NM_DEVICE_TYPE_GENERIC: + return 950; + case NM_DEVICE_TYPE_UNKNOWN: + return 10000; + case NM_DEVICE_TYPE_UNUSED1: + case NM_DEVICE_TYPE_UNUSED2: + /* omit default: to get compiler warning about missing switch cases */ + break; + } + return 11000; } static gboolean -default_route_metric_penalty_detect (NMDevice *self, int addr_family) +default_route_metric_penalty_detect(NMDevice *self, int addr_family) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); - /* currently we don't differentiate between IPv4 and IPv6 when detecting - * connectivity. */ - if ( priv->concheck_x[IS_IPv4].state != NM_CONNECTIVITY_FULL - && nm_connectivity_check_enabled (concheck_get_mgr (self))) - return TRUE; + /* currently we don't differentiate between IPv4 and IPv6 when detecting + * connectivity. */ + if (priv->concheck_x[IS_IPv4].state != NM_CONNECTIVITY_FULL + && nm_connectivity_check_enabled(concheck_get_mgr(self))) + return TRUE; - return FALSE; + return FALSE; } static guint32 -default_route_metric_penalty_get (NMDevice *self, int addr_family) +default_route_metric_penalty_get(NMDevice *self, int addr_family) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert_addr_family (addr_family); + nm_assert_addr_family(addr_family); - if ( addr_family == AF_INET - ? priv->default_route_metric_penalty_ip4_has - : priv->default_route_metric_penalty_ip6_has) - return 20000; - return 0; + if (addr_family == AF_INET ? priv->default_route_metric_penalty_ip4_has + : priv->default_route_metric_penalty_ip6_has) + return 20000; + return 0; } guint32 -nm_device_get_route_metric (NMDevice *self, - int addr_family) -{ - gint64 route_metric; - NMSettingIPConfig *s_ip; - NMConnection *connection; - const char *property; - - g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); - g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), G_MAXUINT32); - - connection = nm_device_get_applied_connection (self); - if (connection) { - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - - /* Slave interfaces don't have IP settings, but we may get here when - * external changes are made or when noticing IP changes when starting - * the slave connection. - */ - if (s_ip) { - route_metric = nm_setting_ip_config_get_route_metric (s_ip); - if (route_metric >= 0) - goto out; - } - } - - /* use the current NMConfigData, which makes this configuration reloadable. - * Note that that means that the route-metric might change between SIGHUP. - * You must cache the returned value if that is a problem. */ - property = addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.route-metric") - : NM_CON_DEFAULT ("ipv6.route-metric"); - route_metric = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - property, - self, - 0, G_MAXUINT32, -1); - if (route_metric >= 0) - goto out; - - route_metric = nm_manager_device_route_metric_reserve (NM_MANAGER_GET, - nm_device_get_ip_ifindex (self), - nm_device_get_device_type (self)); +nm_device_get_route_metric(NMDevice *self, int addr_family) +{ + gint64 route_metric; + NMSettingIPConfig *s_ip; + NMConnection * connection; + const char * property; + + g_return_val_if_fail(NM_IS_DEVICE(self), G_MAXUINT32); + g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), G_MAXUINT32); + + connection = nm_device_get_applied_connection(self); + if (connection) { + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); + + /* Slave interfaces don't have IP settings, but we may get here when + * external changes are made or when noticing IP changes when starting + * the slave connection. + */ + if (s_ip) { + route_metric = nm_setting_ip_config_get_route_metric(s_ip); + if (route_metric >= 0) + goto out; + } + } + + /* use the current NMConfigData, which makes this configuration reloadable. + * Note that that means that the route-metric might change between SIGHUP. + * You must cache the returned value if that is a problem. */ + property = addr_family == AF_INET ? NM_CON_DEFAULT("ipv4.route-metric") + : NM_CON_DEFAULT("ipv6.route-metric"); + route_metric = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + property, + self, + 0, + G_MAXUINT32, + -1); + if (route_metric >= 0) + goto out; + + route_metric = nm_manager_device_route_metric_reserve(NM_MANAGER_GET, + nm_device_get_ip_ifindex(self), + nm_device_get_device_type(self)); out: - return nm_utils_ip_route_metric_normalize (addr_family, route_metric); -} - -static NMSettingConnectionMdns -_get_mdns (NMDevice *self) -{ - NMConnection *connection; - NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; - - g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_MDNS_DEFAULT); - - connection = nm_device_get_applied_connection (self); - if (connection) - mdns = nm_setting_connection_get_mdns (nm_connection_get_setting_connection (connection)); - if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) - return mdns; - - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.mdns"), - self, - NM_SETTING_CONNECTION_MDNS_NO, - NM_SETTING_CONNECTION_MDNS_YES, - NM_SETTING_CONNECTION_MDNS_DEFAULT); -} - -static NMSettingConnectionLlmnr -_get_llmnr (NMDevice *self) -{ - NMConnection *connection; - NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; - - g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_LLMNR_DEFAULT); - - connection = nm_device_get_applied_connection (self); - if (connection) - llmnr = nm_setting_connection_get_llmnr (nm_connection_get_setting_connection (connection)); - if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) - return llmnr; - - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.llmnr"), - self, - NM_SETTING_CONNECTION_LLMNR_NO, - NM_SETTING_CONNECTION_LLMNR_YES, - NM_SETTING_CONNECTION_LLMNR_DEFAULT); -} - -static guint32 -_get_route_table (NMDevice *self, - int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceClass *klass; - NMConnection *connection; - NMSettingIPConfig *s_ip; - guint32 route_table = 0; - gboolean is_user_config = TRUE; - NMSettingConnection *s_con; - NMSettingVrf *s_vrf; - - nm_assert_addr_family (addr_family); - - /* the route table setting affects how we sync routes. We shall - * not change it while the device is active, hence, cache it. */ - if (addr_family == AF_INET) { - if (priv->v4_route_table_initialized) - return priv->v4_route_table; - } else { - if (priv->v6_route_table_initialized) - return priv->v6_route_table; - } - - connection = nm_device_get_applied_connection (self); - if (connection) { - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - if (s_ip) - route_table = nm_setting_ip_config_get_route_table (s_ip); - } - if (route_table == 0u) { - gint64 v; - - v = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.route-table") - : NM_CON_DEFAULT ("ipv6.route-table"), - self, - 0, - G_MAXUINT32, - -1); - if (v != -1) { - route_table = v; - is_user_config = FALSE; - } - } - - if ( route_table == 0u - && connection - && (s_con = nm_connection_get_setting_connection (connection)) - && (nm_streq0 (nm_setting_connection_get_slave_type (s_con), NM_SETTING_VRF_SETTING_NAME) - && priv->master - && nm_device_get_device_type (priv->master) == NM_DEVICE_TYPE_VRF)) { - const NMPlatformLnkVrf *lnk; - - lnk = nm_platform_link_get_lnk_vrf (nm_device_get_platform (self), - nm_device_get_ifindex (priv->master), - NULL); - - if (lnk) - route_table = lnk->table; - } - - if ( route_table == 0u - && connection - && (s_vrf = (NMSettingVrf *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VRF))) { - route_table = nm_setting_vrf_get_table (s_vrf); - } - - klass = NM_DEVICE_GET_CLASS (self); - if (klass->coerce_route_table) - route_table = klass->coerce_route_table (self, addr_family, route_table, is_user_config); - - if (addr_family == AF_INET) { - priv->v4_route_table_initialized = TRUE; - priv->v4_route_table = route_table; - } else { - priv->v6_route_table_initialized = TRUE; - priv->v6_route_table = route_table; - } - - _LOGT (LOGD_DEVICE, - "ipv%c.route-table = %u%s", - addr_family == AF_INET ? '4' : '6', - (guint) (route_table ?: RT_TABLE_MAIN), - route_table != 0u ? "" : " (policy routing not enabled)"); - - return route_table; + return nm_utils_ip_route_metric_normalize(addr_family, route_metric); } guint32 -nm_device_get_route_table (NMDevice *self, - int addr_family) +nm_device_get_route_table(NMDevice *self, int addr_family) { - guint32 route_table; + guint32 route_table; - g_return_val_if_fail (NM_IS_DEVICE (self), RT_TABLE_MAIN); + g_return_val_if_fail(NM_IS_DEVICE(self), RT_TABLE_MAIN); - route_table = _get_route_table (self, addr_family); - return route_table ?: (guint32) RT_TABLE_MAIN; + route_table = _prop_get_ipvx_route_table(self, addr_family); + return route_table ?: (guint32) RT_TABLE_MAIN; } static NMIPRouteTableSyncMode -_get_route_table_sync_mode_stateful (NMDevice *self, - int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDedupMultiIter ipconf_iter; - gboolean all_sync_now; - gboolean all_sync_eff; - - all_sync_now = _get_route_table (self, addr_family) != 0u; - - if (!all_sync_now) { - /* If there's a local route switch to all-sync in order - * to properly manage the local table */ - if (addr_family == AF_INET) { - const NMPlatformIP4Route *route; - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->con_ip_config_4, &route) { - if (nm_platform_route_type_uncoerce (route->type_coerced) == RTN_LOCAL) { - all_sync_now = TRUE; - break; - } - } - } else { - const NMPlatformIP6Route *route; - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->con_ip_config_6, &route) { - if (nm_platform_route_type_uncoerce (route->type_coerced) == RTN_LOCAL) { - all_sync_now = TRUE; - break; - } - } - } - } - - if (all_sync_now) - all_sync_eff = TRUE; - else { - /* When we change from all-sync to no all-sync, we do a last all-sync one - * more time. For that, we determine the effective all-state based on the - * cached/previous all-sync flag. - * - * The purpose of this is to support reapply of route-table (and thus the - * all-sync mode). If reapply toggles from all-sync to no-all-sync, we must - * sync one last time. */ - if (addr_family == AF_INET) - all_sync_eff = priv->v4_route_table_all_sync_before; - else - all_sync_eff = priv->v6_route_table_all_sync_before; - } - - if (addr_family == AF_INET) - priv->v4_route_table_all_sync_before = all_sync_now; - else - priv->v6_route_table_all_sync_before = all_sync_now; - - return all_sync_eff - ? NM_IP_ROUTE_TABLE_SYNC_MODE_ALL - : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; +_get_route_table_sync_mode_stateful(NMDevice *self, int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDedupMultiIter ipconf_iter; + gboolean all_sync_now; + gboolean all_sync_eff; + + all_sync_now = _prop_get_ipvx_route_table(self, addr_family) != 0u; + + if (!all_sync_now) { + /* If there's a local route switch to all-sync in order + * to properly manage the local table */ + if (addr_family == AF_INET) { + const NMPlatformIP4Route *route; + + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->con_ip_config_4, &route) { + if (nm_platform_route_type_uncoerce(route->type_coerced) == RTN_LOCAL) { + all_sync_now = TRUE; + break; + } + } + } else { + const NMPlatformIP6Route *route; + + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->con_ip_config_6, &route) { + if (nm_platform_route_type_uncoerce(route->type_coerced) == RTN_LOCAL) { + all_sync_now = TRUE; + break; + } + } + } + } + + if (all_sync_now) + all_sync_eff = TRUE; + else { + /* When we change from all-sync to no all-sync, we do a last all-sync one + * more time. For that, we determine the effective all-state based on the + * cached/previous all-sync flag. + * + * The purpose of this is to support reapply of route-table (and thus the + * all-sync mode). If reapply toggles from all-sync to no-all-sync, we must + * sync one last time. */ + if (addr_family == AF_INET) + all_sync_eff = priv->v4_route_table_all_sync_before; + else + all_sync_eff = priv->v6_route_table_all_sync_before; + } + + if (addr_family == AF_INET) + priv->v4_route_table_all_sync_before = all_sync_now; + else + priv->v6_route_table_all_sync_before = all_sync_now; + + return all_sync_eff ? NM_IP_ROUTE_TABLE_SYNC_MODE_ALL : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; } const NMPObject * -nm_device_get_best_default_route (NMDevice *self, - int addr_family) +nm_device_get_best_default_route(NMDevice *self, int addr_family) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - switch (addr_family) { - case AF_INET: - return priv->ip_config_4 ? nm_ip4_config_best_default_route_get (priv->ip_config_4) : NULL; - case AF_INET6: - return priv->ip_config_6 ? nm_ip6_config_best_default_route_get (priv->ip_config_6) : NULL; - case AF_UNSPEC: - return (priv->ip_config_4 ? nm_ip4_config_best_default_route_get (priv->ip_config_4) : NULL) - ?: (priv->ip_config_6 ? nm_ip6_config_best_default_route_get (priv->ip_config_6) : NULL); - default: - g_return_val_if_reached (NULL); - } + switch (addr_family) { + case AF_INET: + return priv->ip_config_4 ? nm_ip4_config_best_default_route_get(priv->ip_config_4) : NULL; + case AF_INET6: + return priv->ip_config_6 ? nm_ip6_config_best_default_route_get(priv->ip_config_6) : NULL; + case AF_UNSPEC: + return (priv->ip_config_4 ? nm_ip4_config_best_default_route_get(priv->ip_config_4) : NULL) + ?: (priv->ip_config_6 ? nm_ip6_config_best_default_route_get(priv->ip_config_6) + : NULL); + default: + g_return_val_if_reached(NULL); + } } const char * -nm_device_get_type_desc (NMDevice *self) +nm_device_get_type_desc(NMDevice *self) { - g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail(self != NULL, NULL); - return NM_DEVICE_GET_PRIVATE (self)->type_desc; + return NM_DEVICE_GET_PRIVATE(self)->type_desc; } const char * -nm_device_get_type_description (NMDevice *self) +nm_device_get_type_description(NMDevice *self) { - g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail(self != NULL, NULL); - /* Beware: this function should return the same - * value as nm_device_get_type_description() in libnm. */ + /* Beware: this function should return the same + * value as nm_device_get_type_description() in libnm. */ - return NM_DEVICE_GET_CLASS (self)->get_type_description (self); + return NM_DEVICE_GET_CLASS(self)->get_type_description(self); } static const char * -get_type_description (NMDevice *self) -{ - NMDeviceClass *klass; - - nm_assert (NM_IS_DEVICE (self)); - - /* the default implementation for the description just returns the (modified) - * class name and depends entirely on the type of self. Note that we cache the - * description in the klass itself. - * - * Also note, that as the GObject class gets inited, it inherrits the fields - * of the parent class. That means, if NMDeviceVethClass was initialized after - * NMDeviceEthernetClass already has the description cached in the class - * (because we already fetched the description for an ethernet device), - * then default_type_description will wrongly contain "ethernet". - * To avoid that, and catch the situation, also cache the klass for - * which the description was cached. If that doesn't match, it was - * inherited and we need to reset it. */ - klass = NM_DEVICE_GET_CLASS (self); - if (G_UNLIKELY (klass->default_type_description_klass != klass)) { - const char *typename; - gs_free char *s = NULL; - - typename = G_OBJECT_TYPE_NAME (self); - if (g_str_has_prefix (typename, "NMDevice")) - typename += 8; - s = g_ascii_strdown (typename, -1); - klass->default_type_description = g_intern_string (s); - klass->default_type_description_klass = klass; - } - - nm_assert (klass->default_type_description); - return klass->default_type_description; +get_type_description(NMDevice *self) +{ + NMDeviceClass *klass; + + nm_assert(NM_IS_DEVICE(self)); + + /* the default implementation for the description just returns the (modified) + * class name and depends entirely on the type of self. Note that we cache the + * description in the klass itself. + * + * Also note, that as the GObject class gets inited, it inherrits the fields + * of the parent class. That means, if NMDeviceVethClass was initialized after + * NMDeviceEthernetClass already has the description cached in the class + * (because we already fetched the description for an ethernet device), + * then default_type_description will wrongly contain "ethernet". + * To avoid that, and catch the situation, also cache the klass for + * which the description was cached. If that doesn't match, it was + * inherited and we need to reset it. */ + klass = NM_DEVICE_GET_CLASS(self); + if (G_UNLIKELY(klass->default_type_description_klass != klass)) { + const char *typename; + gs_free char *s = NULL; + + typename = G_OBJECT_TYPE_NAME(self); + if (g_str_has_prefix(typename, "NMDevice")) + typename += 8; + s = g_ascii_strdown(typename, -1); + klass->default_type_description = g_intern_string(s); + klass->default_type_description_klass = klass; + } + + nm_assert(klass->default_type_description); + return klass->default_type_description; } gboolean -nm_device_has_carrier (NMDevice *self) +nm_device_has_carrier(NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->carrier; + return NM_DEVICE_GET_PRIVATE(self)->carrier; } NMActRequest * -nm_device_get_act_request (NMDevice *self) +nm_device_get_act_request(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->act_request.obj; + return NM_DEVICE_GET_PRIVATE(self)->act_request.obj; } NMActivationStateFlags -nm_device_get_activation_state_flags (NMDevice *self) +nm_device_get_activation_state_flags(NMDevice *self) { - NMActRequest *ac; + NMActRequest *ac; - g_return_val_if_fail (NM_IS_DEVICE (self), NM_ACTIVATION_STATE_FLAG_NONE); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_ACTIVATION_STATE_FLAG_NONE); - ac = NM_DEVICE_GET_PRIVATE (self)->act_request.obj; - if (!ac) - return NM_ACTIVATION_STATE_FLAG_NONE; - return nm_active_connection_get_state_flags (NM_ACTIVE_CONNECTION (ac)); + ac = NM_DEVICE_GET_PRIVATE(self)->act_request.obj; + if (!ac) + return NM_ACTIVATION_STATE_FLAG_NONE; + return nm_active_connection_get_state_flags(NM_ACTIVE_CONNECTION(ac)); } NMSettingsConnection * -nm_device_get_settings_connection (NMDevice *self) +nm_device_get_settings_connection(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - return priv->act_request.obj ? nm_act_request_get_settings_connection (priv->act_request.obj) : NULL; + return priv->act_request.obj ? nm_act_request_get_settings_connection(priv->act_request.obj) + : NULL; } NMConnection * -nm_device_get_settings_connection_get_connection (NMDevice *self) +nm_device_get_settings_connection_get_connection(NMDevice *self) { - NMSettingsConnection *sett_con; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMSettingsConnection *sett_con; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - if (!priv->act_request.obj) - return NULL; + if (!priv->act_request.obj) + return NULL; - sett_con = nm_act_request_get_settings_connection (priv->act_request.obj); - if (!sett_con) - return NULL; + sett_con = nm_act_request_get_settings_connection(priv->act_request.obj); + if (!sett_con) + return NULL; - return nm_settings_connection_get_connection (sett_con); + return nm_settings_connection_get_connection(sett_con); } NMConnection * -nm_device_get_applied_connection (NMDevice *self) +nm_device_get_applied_connection(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - return priv->act_request.obj ? nm_act_request_get_applied_connection (priv->act_request.obj) : NULL; + return priv->act_request.obj ? nm_act_request_get_applied_connection(priv->act_request.obj) + : NULL; } gboolean -nm_device_has_unmodified_applied_connection (NMDevice *self, NMSettingCompareFlags compare_flags) +nm_device_has_unmodified_applied_connection(NMDevice *self, NMSettingCompareFlags compare_flags) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!priv->act_request.obj) - return FALSE; + if (!priv->act_request.obj) + return FALSE; - return nm_active_connection_has_unmodified_applied_connection ((NMActiveConnection *) priv->act_request.obj, compare_flags); + return nm_active_connection_has_unmodified_applied_connection( + (NMActiveConnection *) priv->act_request.obj, + compare_flags); } gpointer -nm_device_get_applied_setting (NMDevice *self, GType setting_type) +nm_device_get_applied_setting(NMDevice *self, GType setting_type) { - NMConnection *connection; + NMConnection *connection; - connection = nm_device_get_applied_connection (self); - return connection ? nm_connection_get_setting (connection, setting_type) : NULL; + connection = nm_device_get_applied_connection(self); + return connection ? nm_connection_get_setting(connection, setting_type) : NULL; } RfKillType -nm_device_get_rfkill_type (NMDevice *self) +nm_device_get_rfkill_type(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - return NM_DEVICE_GET_PRIVATE (self)->rfkill_type; + return NM_DEVICE_GET_PRIVATE(self)->rfkill_type; } static const char * -nm_device_get_physical_port_id (NMDevice *self) +nm_device_get_physical_port_id(NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->physical_port_id; + return NM_DEVICE_GET_PRIVATE(self)->physical_port_id; } /*****************************************************************************/ typedef enum { - CONCHECK_SCHEDULE_UPDATE_INTERVAL, - CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART, - CONCHECK_SCHEDULE_CHECK_EXTERNAL, - CONCHECK_SCHEDULE_CHECK_PERIODIC, - CONCHECK_SCHEDULE_RETURNED_MIN, - CONCHECK_SCHEDULE_RETURNED_BUMP, - CONCHECK_SCHEDULE_RETURNED_MAX, + CONCHECK_SCHEDULE_UPDATE_INTERVAL, + CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART, + CONCHECK_SCHEDULE_CHECK_EXTERNAL, + CONCHECK_SCHEDULE_CHECK_PERIODIC, + CONCHECK_SCHEDULE_RETURNED_MIN, + CONCHECK_SCHEDULE_RETURNED_BUMP, + CONCHECK_SCHEDULE_RETURNED_MAX, } ConcheckScheduleMode; -static NMDeviceConnectivityHandle *concheck_start (NMDevice *self, - int addr_family, - NMDeviceConnectivityCallback callback, - gpointer user_data, - gboolean is_periodic); +static NMDeviceConnectivityHandle *concheck_start(NMDevice * self, + int addr_family, + NMDeviceConnectivityCallback callback, + gpointer user_data, + gboolean is_periodic); -static void concheck_periodic_schedule_set (NMDevice *self, - int addr_family, - ConcheckScheduleMode mode); +static void +concheck_periodic_schedule_set(NMDevice *self, int addr_family, ConcheckScheduleMode mode); static gboolean -_concheck_periodic_timeout_cb (NMDevice *self, int addr_family) +_concheck_periodic_timeout_cb(NMDevice *self, int addr_family) { - _LOGt (LOGD_CONCHECK, "connectivity: [IPv%c] periodic timeout", - nm_utils_addr_family_to_char (addr_family)); - concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_CHECK_PERIODIC); - return G_SOURCE_REMOVE; + _LOGt(LOGD_CONCHECK, + "connectivity: [IPv%c] periodic timeout", + nm_utils_addr_family_to_char(addr_family)); + concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_CHECK_PERIODIC); + return G_SOURCE_REMOVE; } static gboolean -concheck_ip4_periodic_timeout_cb (gpointer user_data) +concheck_ip4_periodic_timeout_cb(gpointer user_data) { - return _concheck_periodic_timeout_cb (user_data, AF_INET); + return _concheck_periodic_timeout_cb(user_data, AF_INET); } static gboolean -concheck_ip6_periodic_timeout_cb (gpointer user_data) +concheck_ip6_periodic_timeout_cb(gpointer user_data) { - return _concheck_periodic_timeout_cb (user_data, AF_INET6); + return _concheck_periodic_timeout_cb(user_data, AF_INET6); } static gboolean -concheck_is_possible (NMDevice *self) +concheck_is_possible(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if ( !nm_device_is_real (self) - || is_loopback (self)) - return FALSE; + if (!nm_device_is_real(self) || is_loopback(self)) + return FALSE; - /* we enable periodic checks for every device state (except UNKNOWN). Especially with - * unmanaged devices, it is interesting to know whether we have connectivity on that device. */ - if (priv->state == NM_DEVICE_STATE_UNKNOWN) - return FALSE; + /* we enable periodic checks for every device state (except UNKNOWN). Especially with + * unmanaged devices, it is interesting to know whether we have connectivity on that device. */ + if (priv->state == NM_DEVICE_STATE_UNKNOWN) + return FALSE; - return TRUE; + return TRUE; } static gboolean -concheck_periodic_schedule_do (NMDevice *self, int addr_family, gint64 now_ns) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean periodic_check_disabled = FALSE; - gint64 expiry, tdiff; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - /* we always cancel whatever was pending. */ - if (nm_clear_g_source (&priv->concheck_x[IS_IPv4].p_cur_id)) - periodic_check_disabled = TRUE; - - if (priv->concheck_x[IS_IPv4].p_max_interval == 0) { - /* periodic checks are disabled */ - goto out; - } - - if (!concheck_is_possible (self)) - goto out; - - nm_assert (now_ns > 0); - nm_assert (priv->concheck_x[IS_IPv4].p_cur_interval > 0); - - /* we schedule the timeout based on our current settings cur-interval and cur-basetime. - * Before calling concheck_periodic_schedule_do(), make sure that these properties are - * correct. */ - - expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - tdiff = expiry - now_ns; - - _LOGT (LOGD_CONCHECK, "connectivity: [IPv%c] periodic-check: %sscheduled in %lld milliseconds (%u seconds interval)", - nm_utils_addr_family_to_char (addr_family), - periodic_check_disabled ? "re-" : "", - (long long) (tdiff / NM_UTILS_NSEC_PER_MSEC), - priv->concheck_x[IS_IPv4].p_cur_interval); - - priv->concheck_x[IS_IPv4].p_cur_id = - g_timeout_add (NM_MAX ((gint64) 0, tdiff) / NM_UTILS_NSEC_PER_MSEC, - IS_IPv4 ? concheck_ip4_periodic_timeout_cb : concheck_ip6_periodic_timeout_cb, - self); - return TRUE; +concheck_periodic_schedule_do(NMDevice *self, int addr_family, gint64 now_ns) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean periodic_check_disabled = FALSE; + gint64 expiry, tdiff; + const gboolean IS_IPv4 = (addr_family == AF_INET); + + /* we always cancel whatever was pending. */ + if (nm_clear_g_source(&priv->concheck_x[IS_IPv4].p_cur_id)) + periodic_check_disabled = TRUE; + + if (priv->concheck_x[IS_IPv4].p_max_interval == 0) { + /* periodic checks are disabled */ + goto out; + } + + if (!concheck_is_possible(self)) + goto out; + + nm_assert(now_ns > 0); + nm_assert(priv->concheck_x[IS_IPv4].p_cur_interval > 0); + + /* we schedule the timeout based on our current settings cur-interval and cur-basetime. + * Before calling concheck_periodic_schedule_do(), make sure that these properties are + * correct. */ + + expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); + tdiff = expiry - now_ns; + + _LOGT(LOGD_CONCHECK, + "connectivity: [IPv%c] periodic-check: %sscheduled in %lld milliseconds (%u seconds " + "interval)", + nm_utils_addr_family_to_char(addr_family), + periodic_check_disabled ? "re-" : "", + (long long) (tdiff / NM_UTILS_NSEC_PER_MSEC), + priv->concheck_x[IS_IPv4].p_cur_interval); + + priv->concheck_x[IS_IPv4].p_cur_id = + g_timeout_add(NM_MAX((gint64) 0, tdiff) / NM_UTILS_NSEC_PER_MSEC, + IS_IPv4 ? concheck_ip4_periodic_timeout_cb : concheck_ip6_periodic_timeout_cb, + self); + return TRUE; out: - if (periodic_check_disabled) { - _LOGT (LOGD_CONCHECK, "connectivity: [IPv%c] periodic-check: unscheduled", - nm_utils_addr_family_to_char (addr_family)); - } - return FALSE; + if (periodic_check_disabled) { + _LOGT(LOGD_CONCHECK, + "connectivity: [IPv%c] periodic-check: unscheduled", + nm_utils_addr_family_to_char(addr_family)); + } + return FALSE; } #define CONCHECK_P_PROBE_INTERVAL 1 static void -concheck_periodic_schedule_set (NMDevice *self, int addr_family, ConcheckScheduleMode mode) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gint64 new_expiry, exp_expiry, cur_expiry, tdiff; - gint64 now_ns = 0; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - if (priv->concheck_x[IS_IPv4].p_max_interval == 0) { - /* periodic check is disabled. Nothing to do. */ - return; - } - - if (!priv->concheck_x[IS_IPv4].p_cur_id) { - /* we currently don't have a timeout scheduled. No need to reschedule - * another one... */ - if (NM_IN_SET (mode, CONCHECK_SCHEDULE_UPDATE_INTERVAL, - CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART)) { - /* ... unless, we are about to start periodic checks after update-interval. - * In this case, fall through and restart the periodic checks below. */ - mode = CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART; - } else - return; - } - - switch (mode) { - case CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART: - priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL); - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_nsec_cached (&now_ns); - if (concheck_periodic_schedule_do (self, addr_family, now_ns)) - concheck_start (self, addr_family, NULL, NULL, TRUE); - return; - - case CONCHECK_SCHEDULE_UPDATE_INTERVAL: - /* called with "UPDATE_INTERVAL" and already have a p_cur_id scheduled. */ - - nm_assert (priv->concheck_x[IS_IPv4].p_max_interval > 0); - nm_assert (priv->concheck_x[IS_IPv4].p_cur_interval > 0); - - if (priv->concheck_x[IS_IPv4].p_cur_interval <= priv->concheck_x[IS_IPv4].p_max_interval) { - /* we currently have a shorter interval set, than what we now have. Either, - * because we are probing, or because the previous max interval was shorter. - * - * Either way, the current timer is set just fine. Nothing to do, we will - * probe our way up. */ - return; - } - - cur_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (priv->concheck_x[IS_IPv4].p_max_interval * NM_UTILS_NSEC_PER_SEC); - nm_utils_get_monotonic_timestamp_nsec_cached (&now_ns); - - priv->concheck_x[IS_IPv4].p_cur_interval = priv->concheck_x[IS_IPv4].p_max_interval; - if (cur_expiry <= now_ns) { - /* Since the last time we scheduled a periodic check, already more than the - * new max_interval passed. We need to start a check right away (and - * schedule a timeout in cur-interval in the future). */ - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = now_ns; - if (concheck_periodic_schedule_do (self, addr_family, now_ns)) - concheck_start (self, addr_family, NULL, NULL, TRUE); - } else { - /* we are reducing the max-interval to a shorter interval that we have currently - * scheduled (with cur_interval). - * - * However, since the last time we scheduled the check, not even the new max-interval - * expired. All we need to do, is reschedule the timer to expire sooner. The cur_basetime - * is unchanged. */ - concheck_periodic_schedule_do (self, addr_family, now_ns); - } - return; - - case CONCHECK_SCHEDULE_CHECK_EXTERNAL: - /* a external connectivity check delays our periodic check. We reset the counter. */ - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_nsec_cached (&now_ns); - concheck_periodic_schedule_do (self, addr_family, now_ns); - return; - - case CONCHECK_SCHEDULE_CHECK_PERIODIC: - { - gboolean any_periodic_pending; - NMDeviceConnectivityHandle *handle; - guint old_interval = priv->concheck_x[IS_IPv4].p_cur_interval; - - any_periodic_pending = FALSE; - c_list_for_each_entry (handle, &priv->concheck_lst_head, concheck_lst) { - if (handle->addr_family != addr_family) - continue; - if (handle->is_periodic_bump) { - handle->is_periodic_bump = FALSE; - handle->is_periodic_bump_on_complete = FALSE; - any_periodic_pending = TRUE; - } - } - if (any_periodic_pending) { - /* we reached a timeout to schedule a new periodic request, however we still - * have period requests pending that didn't complete yet. We need to bump the - * interval already. */ - priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (old_interval * 2, priv->concheck_x[IS_IPv4].p_max_interval); - } - - /* we just reached a timeout. The expected expiry (exp_expiry) should be - * pretty close to now_ns. - * - * We want to reschedule the timeout at exp_expiry (aka now) + cur_interval. */ - nm_utils_get_monotonic_timestamp_nsec_cached (&now_ns); - exp_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (old_interval * NM_UTILS_NSEC_PER_SEC); - new_expiry = exp_expiry + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - tdiff = NM_MAX (new_expiry - now_ns, 0); - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = (now_ns + tdiff) - (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - if (concheck_periodic_schedule_do (self, addr_family, now_ns)) { - handle = concheck_start (self, addr_family, NULL, NULL, TRUE); - if (old_interval != priv->concheck_x[IS_IPv4].p_cur_interval) { - /* we just bumped the interval already when scheduling this check. - * When the handle returns, don't bump a second time. - * - * But if we reach the timeout again before the handle returns (this - * code here) we will still bump the interval. */ - handle->is_periodic_bump_on_complete = FALSE; - } - } - return; - } - - /* we just got an event that we lost connectivity (that is, concheck returned). We reset - * the interval to min/max or increase the probe interval (bump). */ - case CONCHECK_SCHEDULE_RETURNED_MIN: - priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL); - break; - case CONCHECK_SCHEDULE_RETURNED_MAX: - priv->concheck_x[IS_IPv4].p_cur_interval = priv->concheck_x[IS_IPv4].p_max_interval; - break; - case CONCHECK_SCHEDULE_RETURNED_BUMP: - priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (priv->concheck_x[IS_IPv4].p_cur_interval * 2, priv->concheck_x[IS_IPv4].p_max_interval); - break; - } - - /* we are here, because we returned from a connectivity check and adjust the current interval. - * - * But note that we calculate the new timeout based on the time when we scheduled the - * last check, instead of counting from now. The reason is that we want that the times - * when we schedule checks be at precise intervals, without including the time it took for - * the connectivity check. */ - new_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - tdiff = NM_MAX (new_expiry - nm_utils_get_monotonic_timestamp_nsec_cached (&now_ns), 0); - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = now_ns + tdiff - (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - concheck_periodic_schedule_do (self, addr_family, now_ns); +concheck_periodic_schedule_set(NMDevice *self, int addr_family, ConcheckScheduleMode mode) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gint64 new_expiry, exp_expiry, cur_expiry, tdiff; + gint64 now_ns = 0; + const gboolean IS_IPv4 = (addr_family == AF_INET); + + if (priv->concheck_x[IS_IPv4].p_max_interval == 0) { + /* periodic check is disabled. Nothing to do. */ + return; + } + + if (!priv->concheck_x[IS_IPv4].p_cur_id) { + /* we currently don't have a timeout scheduled. No need to reschedule + * another one... */ + if (NM_IN_SET(mode, + CONCHECK_SCHEDULE_UPDATE_INTERVAL, + CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART)) { + /* ... unless, we are about to start periodic checks after update-interval. + * In this case, fall through and restart the periodic checks below. */ + mode = CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART; + } else + return; + } + + switch (mode) { + case CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART: + priv->concheck_x[IS_IPv4].p_cur_interval = + NM_MIN(priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL); + priv->concheck_x[IS_IPv4].p_cur_basetime_ns = + nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns); + if (concheck_periodic_schedule_do(self, addr_family, now_ns)) + concheck_start(self, addr_family, NULL, NULL, TRUE); + return; + + case CONCHECK_SCHEDULE_UPDATE_INTERVAL: + /* called with "UPDATE_INTERVAL" and already have a p_cur_id scheduled. */ + + nm_assert(priv->concheck_x[IS_IPv4].p_max_interval > 0); + nm_assert(priv->concheck_x[IS_IPv4].p_cur_interval > 0); + + if (priv->concheck_x[IS_IPv4].p_cur_interval <= priv->concheck_x[IS_IPv4].p_max_interval) { + /* we currently have a shorter interval set, than what we now have. Either, + * because we are probing, or because the previous max interval was shorter. + * + * Either way, the current timer is set just fine. Nothing to do, we will + * probe our way up. */ + return; + } + + cur_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + + (priv->concheck_x[IS_IPv4].p_max_interval * NM_UTILS_NSEC_PER_SEC); + nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns); + + priv->concheck_x[IS_IPv4].p_cur_interval = priv->concheck_x[IS_IPv4].p_max_interval; + if (cur_expiry <= now_ns) { + /* Since the last time we scheduled a periodic check, already more than the + * new max_interval passed. We need to start a check right away (and + * schedule a timeout in cur-interval in the future). */ + priv->concheck_x[IS_IPv4].p_cur_basetime_ns = now_ns; + if (concheck_periodic_schedule_do(self, addr_family, now_ns)) + concheck_start(self, addr_family, NULL, NULL, TRUE); + } else { + /* we are reducing the max-interval to a shorter interval that we have currently + * scheduled (with cur_interval). + * + * However, since the last time we scheduled the check, not even the new max-interval + * expired. All we need to do, is reschedule the timer to expire sooner. The cur_basetime + * is unchanged. */ + concheck_periodic_schedule_do(self, addr_family, now_ns); + } + return; + + case CONCHECK_SCHEDULE_CHECK_EXTERNAL: + /* a external connectivity check delays our periodic check. We reset the counter. */ + priv->concheck_x[IS_IPv4].p_cur_basetime_ns = + nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns); + concheck_periodic_schedule_do(self, addr_family, now_ns); + return; + + case CONCHECK_SCHEDULE_CHECK_PERIODIC: + { + gboolean any_periodic_pending; + NMDeviceConnectivityHandle *handle; + guint old_interval = priv->concheck_x[IS_IPv4].p_cur_interval; + + any_periodic_pending = FALSE; + c_list_for_each_entry (handle, &priv->concheck_lst_head, concheck_lst) { + if (handle->addr_family != addr_family) + continue; + if (handle->is_periodic_bump) { + handle->is_periodic_bump = FALSE; + handle->is_periodic_bump_on_complete = FALSE; + any_periodic_pending = TRUE; + } + } + if (any_periodic_pending) { + /* we reached a timeout to schedule a new periodic request, however we still + * have period requests pending that didn't complete yet. We need to bump the + * interval already. */ + priv->concheck_x[IS_IPv4].p_cur_interval = + NM_MIN(old_interval * 2, priv->concheck_x[IS_IPv4].p_max_interval); + } + + /* we just reached a timeout. The expected expiry (exp_expiry) should be + * pretty close to now_ns. + * + * We want to reschedule the timeout at exp_expiry (aka now) + cur_interval. */ + nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns); + exp_expiry = + priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (old_interval * NM_UTILS_NSEC_PER_SEC); + new_expiry = + exp_expiry + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); + tdiff = NM_MAX(new_expiry - now_ns, 0); + priv->concheck_x[IS_IPv4].p_cur_basetime_ns = + (now_ns + tdiff) - (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); + if (concheck_periodic_schedule_do(self, addr_family, now_ns)) { + handle = concheck_start(self, addr_family, NULL, NULL, TRUE); + if (old_interval != priv->concheck_x[IS_IPv4].p_cur_interval) { + /* we just bumped the interval already when scheduling this check. + * When the handle returns, don't bump a second time. + * + * But if we reach the timeout again before the handle returns (this + * code here) we will still bump the interval. */ + handle->is_periodic_bump_on_complete = FALSE; + } + } + return; + } + + /* we just got an event that we lost connectivity (that is, concheck returned). We reset + * the interval to min/max or increase the probe interval (bump). */ + case CONCHECK_SCHEDULE_RETURNED_MIN: + priv->concheck_x[IS_IPv4].p_cur_interval = + NM_MIN(priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL); + break; + case CONCHECK_SCHEDULE_RETURNED_MAX: + priv->concheck_x[IS_IPv4].p_cur_interval = priv->concheck_x[IS_IPv4].p_max_interval; + break; + case CONCHECK_SCHEDULE_RETURNED_BUMP: + priv->concheck_x[IS_IPv4].p_cur_interval = + NM_MIN(priv->concheck_x[IS_IPv4].p_cur_interval * 2, + priv->concheck_x[IS_IPv4].p_max_interval); + break; + } + + /* we are here, because we returned from a connectivity check and adjust the current interval. + * + * But note that we calculate the new timeout based on the time when we scheduled the + * last check, instead of counting from now. The reason is that we want that the times + * when we schedule checks be at precise intervals, without including the time it took for + * the connectivity check. */ + new_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); + tdiff = NM_MAX(new_expiry - nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns), 0); + priv->concheck_x[IS_IPv4].p_cur_basetime_ns = + now_ns + tdiff - (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); + concheck_periodic_schedule_do(self, addr_family, now_ns); } static void -concheck_update_interval (NMDevice *self, int addr_family, gboolean check_now) +concheck_update_interval(NMDevice *self, int addr_family, gboolean check_now) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint new_interval; - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + guint new_interval; + const gboolean IS_IPv4 = (addr_family == AF_INET); - new_interval = nm_connectivity_get_interval (concheck_get_mgr (self)); + new_interval = nm_connectivity_get_interval(concheck_get_mgr(self)); - new_interval = NM_MIN (new_interval, 7 *24 * 3600); + new_interval = NM_MIN(new_interval, 7 * 24 * 3600); - if (new_interval != priv->concheck_x[IS_IPv4].p_max_interval) { - _LOGT (LOGD_CONCHECK, "connectivity: [IPv%c] periodic-check: set interval to %u seconds", - nm_utils_addr_family_to_char (addr_family), new_interval); - priv->concheck_x[IS_IPv4].p_max_interval = new_interval; - } + if (new_interval != priv->concheck_x[IS_IPv4].p_max_interval) { + _LOGT(LOGD_CONCHECK, + "connectivity: [IPv%c] periodic-check: set interval to %u seconds", + nm_utils_addr_family_to_char(addr_family), + new_interval); + priv->concheck_x[IS_IPv4].p_max_interval = new_interval; + } - if (!new_interval) { - /* this will cancel any potentially pending timeout because max-interval is zero. - * But it logs a nice message... */ - concheck_periodic_schedule_do (self, addr_family, 0); + if (!new_interval) { + /* this will cancel any potentially pending timeout because max-interval is zero. + * But it logs a nice message... */ + concheck_periodic_schedule_do(self, addr_family, 0); - /* also update the fake connectivity state. */ - concheck_update_state (self, addr_family, NM_CONNECTIVITY_FAKE, TRUE); - return; - } + /* also update the fake connectivity state. */ + concheck_update_state(self, addr_family, NM_CONNECTIVITY_FAKE, TRUE); + return; + } - concheck_periodic_schedule_set (self, - addr_family, - check_now - ? CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART - : CONCHECK_SCHEDULE_UPDATE_INTERVAL); + concheck_periodic_schedule_set(self, + addr_family, + check_now ? CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART + : CONCHECK_SCHEDULE_UPDATE_INTERVAL); } void -nm_device_check_connectivity_update_interval (NMDevice *self) +nm_device_check_connectivity_update_interval(NMDevice *self) { - concheck_update_interval (self, AF_INET, TRUE); - concheck_update_interval (self, AF_INET6, TRUE); + concheck_update_interval(self, AF_INET, TRUE); + concheck_update_interval(self, AF_INET6, TRUE); } static void -concheck_update_state (NMDevice *self, - int addr_family, - NMConnectivityState state, - gboolean allow_periodic_bump) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - /* @state is a result of the connectivity check. We only expect a precise - * number of possible values. */ - nm_assert (NM_IN_SET (state, NM_CONNECTIVITY_LIMITED, - NM_CONNECTIVITY_PORTAL, - NM_CONNECTIVITY_FULL, - NM_CONNECTIVITY_FAKE, - NM_CONNECTIVITY_NONE, - NM_CONNECTIVITY_ERROR)); - - if (state == NM_CONNECTIVITY_ERROR) { - /* on error, we don't change the current connectivity state, - * except making UNKNOWN to NONE. */ - state = priv->concheck_x[IS_IPv4].state; - if (state == NM_CONNECTIVITY_UNKNOWN) - state = NM_CONNECTIVITY_NONE; - } else if (state == NM_CONNECTIVITY_FAKE) { - /* If the connectivity check is disabled and we obtain a fake - * result, make an optimistic guess. */ - if (priv->state == NM_DEVICE_STATE_ACTIVATED) { - /* FIXME: the fake connectivity state depends on the availablility of - * a default route. However, we have no mechanism that rechecks the - * value if a device route appears/disappears after the device - * was activated. */ - if (nm_device_get_best_default_route (self, AF_UNSPEC)) - state = NM_CONNECTIVITY_FULL; - else - state = NM_CONNECTIVITY_LIMITED; - } else - state = NM_CONNECTIVITY_NONE; - } - - if (priv->concheck_x[IS_IPv4].state == state) { - /* we got a connectivty update, but the state didn't change. If we were probing, - * we bump the probe frequency. */ - if (allow_periodic_bump) - concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_BUMP); - return; - } - /* we need to update the probe interval before emitting signals. Emitting - * a signal might call back into NMDevice and change the probe settings. - * So, do that first. */ - if (state == NM_CONNECTIVITY_FULL) { - /* we reached full connectivity state. Stop probing by setting the - * interval to the max. */ - concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_MAX); - } else if (priv->concheck_x[IS_IPv4].state == NM_CONNECTIVITY_FULL) { - /* we are about to loose connectivity. (re)start probing by setting - * the timeout interval to the min. */ - concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_MIN); - } else { - if (allow_periodic_bump) - concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_BUMP); - } - - _LOGD (LOGD_CONCHECK, "connectivity state changed from %s to %s", - nm_connectivity_state_to_string (priv->concheck_x[IS_IPv4].state), - nm_connectivity_state_to_string (state)); - priv->concheck_x[IS_IPv4].state = state; - - _notify (self, IS_IPv4 ? PROP_IP4_CONNECTIVITY : PROP_IP6_CONNECTIVITY); - - if ( priv->state == NM_DEVICE_STATE_ACTIVATED - && !nm_device_sys_iface_state_is_external (self)) { - if ( nm_device_get_best_default_route (self, AF_INET) - && !ip_config_merge_and_apply (self, AF_INET, TRUE)) - _LOGW (LOGD_IP4, "Failed to update IPv4 route metric"); - if ( nm_device_get_best_default_route (self, AF_INET6) - && !ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "Failed to update IPv6 route metric"); - } +concheck_update_state(NMDevice * self, + int addr_family, + NMConnectivityState state, + gboolean allow_periodic_bump) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); + + /* @state is a result of the connectivity check. We only expect a precise + * number of possible values. */ + nm_assert(NM_IN_SET(state, + NM_CONNECTIVITY_LIMITED, + NM_CONNECTIVITY_PORTAL, + NM_CONNECTIVITY_FULL, + NM_CONNECTIVITY_FAKE, + NM_CONNECTIVITY_NONE, + NM_CONNECTIVITY_ERROR)); + + if (state == NM_CONNECTIVITY_ERROR) { + /* on error, we don't change the current connectivity state, + * except making UNKNOWN to NONE. */ + state = priv->concheck_x[IS_IPv4].state; + if (state == NM_CONNECTIVITY_UNKNOWN) + state = NM_CONNECTIVITY_NONE; + } else if (state == NM_CONNECTIVITY_FAKE) { + /* If the connectivity check is disabled and we obtain a fake + * result, make an optimistic guess. */ + if (priv->state == NM_DEVICE_STATE_ACTIVATED) { + /* FIXME: the fake connectivity state depends on the availability of + * a default route. However, we have no mechanism that rechecks the + * value if a device route appears/disappears after the device + * was activated. */ + if (nm_device_get_best_default_route(self, AF_UNSPEC)) + state = NM_CONNECTIVITY_FULL; + else + state = NM_CONNECTIVITY_LIMITED; + } else + state = NM_CONNECTIVITY_NONE; + } + + if (priv->concheck_x[IS_IPv4].state == state) { + /* we got a connectivity update, but the state didn't change. If we were probing, + * we bump the probe frequency. */ + if (allow_periodic_bump) + concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_RETURNED_BUMP); + return; + } + /* we need to update the probe interval before emitting signals. Emitting + * a signal might call back into NMDevice and change the probe settings. + * So, do that first. */ + if (state == NM_CONNECTIVITY_FULL) { + /* we reached full connectivity state. Stop probing by setting the + * interval to the max. */ + concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_RETURNED_MAX); + } else if (priv->concheck_x[IS_IPv4].state == NM_CONNECTIVITY_FULL) { + /* we are about to loose connectivity. (re)start probing by setting + * the timeout interval to the min. */ + concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_RETURNED_MIN); + } else { + if (allow_periodic_bump) + concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_RETURNED_BUMP); + } + + _LOGD(LOGD_CONCHECK, + "connectivity state changed from %s to %s", + nm_connectivity_state_to_string(priv->concheck_x[IS_IPv4].state), + nm_connectivity_state_to_string(state)); + priv->concheck_x[IS_IPv4].state = state; + + _notify(self, IS_IPv4 ? PROP_IP4_CONNECTIVITY : PROP_IP6_CONNECTIVITY); + + if (priv->state == NM_DEVICE_STATE_ACTIVATED && !nm_device_sys_iface_state_is_external(self)) { + if (nm_device_get_best_default_route(self, AF_INET) + && !ip_config_merge_and_apply(self, AF_INET, TRUE)) + _LOGW(LOGD_IP4, "Failed to update IPv4 route metric"); + if (nm_device_get_best_default_route(self, AF_INET6) + && !ip_config_merge_and_apply(self, AF_INET6, TRUE)) + _LOGW(LOGD_IP6, "Failed to update IPv6 route metric"); + } } static const char * -nm_device_get_effective_ip_config_method (NMDevice *self, - int addr_family) +nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family) { - NMDeviceClass *klass; - NMConnection *connection = nm_device_get_applied_connection (self); - const char *method; + NMDeviceClass *klass; + NMConnection * connection = nm_device_get_applied_connection(self); + const char * method; - g_return_val_if_fail (NM_IS_CONNECTION (connection), "" /* bogus */); - nm_assert_addr_family (addr_family); + g_return_val_if_fail(NM_IS_CONNECTION(connection), "" /* bogus */); + nm_assert_addr_family(addr_family); - method = nm_utils_get_ip_config_method (connection, addr_family); + method = nm_utils_get_ip_config_method(connection, addr_family); - if ( (addr_family == AF_INET && nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) - || (addr_family == AF_INET6 && nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO))) { - klass = NM_DEVICE_GET_CLASS (self); - if (klass->get_auto_ip_config_method) { - const char *auto_method; + if ((addr_family == AF_INET && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) + || (addr_family == AF_INET6 && nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO))) { + klass = NM_DEVICE_GET_CLASS(self); + if (klass->get_auto_ip_config_method) { + const char *auto_method; - auto_method = klass->get_auto_ip_config_method (self, addr_family); - if (auto_method) - return auto_method; - } - } + auto_method = klass->get_auto_ip_config_method(self, addr_family); + if (auto_method) + return auto_method; + } + } - return method; + return method; } static void -concheck_handle_complete (NMDeviceConnectivityHandle *handle, GError *error) +concheck_handle_complete(NMDeviceConnectivityHandle *handle, GError *error) { - const gboolean IS_IPv4 = (handle->addr_family == AF_INET); + const gboolean IS_IPv4 = (handle->addr_family == AF_INET); - /* The moment we invoke the callback, we unlink it. It signals - * that @handle is handled -- as far as the callee of callback - * is concerned. */ - c_list_unlink (&handle->concheck_lst); + /* The moment we invoke the callback, we unlink it. It signals + * that @handle is handled -- as far as the callee of callback + * is concerned. */ + c_list_unlink(&handle->concheck_lst); - if (handle->c_handle) - nm_connectivity_check_cancel (handle->c_handle); + if (handle->c_handle) + nm_connectivity_check_cancel(handle->c_handle); - if (handle->callback) { - handle->callback (handle->self, - handle, - NM_DEVICE_GET_PRIVATE (handle->self)->concheck_x[IS_IPv4].state, - error, - handle->user_data); - } + if (handle->callback) { + handle->callback(handle->self, + handle, + NM_DEVICE_GET_PRIVATE(handle->self)->concheck_x[IS_IPv4].state, + error, + handle->user_data); + } - g_slice_free (NMDeviceConnectivityHandle, handle); + g_slice_free(NMDeviceConnectivityHandle, handle); } static void -concheck_cb (NMConnectivity *connectivity, - NMConnectivityCheckHandle *c_handle, - NMConnectivityState state, - gpointer user_data) -{ - _nm_unused gs_unref_object NMDevice *self_keep_alive = NULL; - NMDevice *self; - NMDevicePrivate *priv; - NMDeviceConnectivityHandle *handle; - NMDeviceConnectivityHandle *other_handle; - gboolean handle_is_alive; - gboolean allow_periodic_bump; - gboolean any_periodic_before; - gboolean any_periodic_after; - guint64 seq; - - handle = user_data; - nm_assert (handle->c_handle == c_handle); - nm_assert (NM_IS_DEVICE (handle->self)); - - handle->c_handle = NULL; - self = handle->self; - - if (state == NM_CONNECTIVITY_CANCELLED) { - /* the only place where we nm_connectivity_check_cancel(@c_handle), is - * from inside concheck_handle_complete(). This is a recursive call, - * nothing to do. */ - _LOGT (LOGD_CONCHECK, "connectivity: [IPv%c] complete check (seq:%llu, cancelled)", - nm_utils_addr_family_to_char (handle->addr_family), - (long long unsigned) handle->seq); - return; - } - - /* we keep NMConnectivity instance alive. It cannot be disposing. */ - nm_assert (state != NM_CONNECTIVITY_DISPOSING); - - self_keep_alive = g_object_ref (self); - - /* keep @self alive, while we invoke callbacks. */ - priv = NM_DEVICE_GET_PRIVATE (self); - - nm_assert (handle && c_list_contains (&priv->concheck_lst_head, &handle->concheck_lst)); - - seq = handle->seq; - - _LOGT (LOGD_CONCHECK, "connectivity: [Ipv%c] complete check (seq:%llu, state:%s)", - nm_utils_addr_family_to_char (handle->addr_family), - (long long unsigned) handle->seq, - nm_connectivity_state_to_string (state)); - - /* find out, if there are any periodic checks pending (either whether they - * were scheduled before or after @handle. */ - any_periodic_before = FALSE; - any_periodic_after = FALSE; - c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { - if (other_handle->addr_family != handle->addr_family) - continue; - if (other_handle->is_periodic_bump_on_complete) { - if (other_handle->seq < seq) - any_periodic_before = TRUE; - else if (other_handle->seq > seq) - any_periodic_after = TRUE; - } - } - if (NM_IN_SET (state, NM_CONNECTIVITY_ERROR)) { - /* the request failed. We consider this periodic check only as completed if - * this was a periodic check, and there are not checks pending (either - * before or after this one). - * - * We allow_periodic_bump, if the request failed and there are - * still other requests periodic pending. */ - allow_periodic_bump = handle->is_periodic_bump_on_complete - && !any_periodic_before - && !any_periodic_after; - } else { - /* the request succeeded. This marks the completion of a periodic check, - * if this handle was periodic, or any previously scheduled one (that - * we are going to complete below). */ - allow_periodic_bump = handle->is_periodic_bump_on_complete - || any_periodic_before; - } - - /* first update the new state, and emit signals. */ - concheck_update_state (self, handle->addr_family, state, allow_periodic_bump); - - handle_is_alive = FALSE; - - /* we might have invoked callbacks during concheck_update_state(). The caller might have - * cancelled and thus destroyed @handle. We have to check whether handle is still alive, - * by searching it in the list of alive handles. - * - * Also, we might want to complete all pending callbacks that were started before - * @handle, as they are automatically obsoleted. */ +concheck_cb(NMConnectivity * connectivity, + NMConnectivityCheckHandle *c_handle, + NMConnectivityState state, + gpointer user_data) +{ + _nm_unused gs_unref_object NMDevice *self_keep_alive = NULL; + NMDevice * self; + NMDevicePrivate * priv; + NMDeviceConnectivityHandle * handle; + NMDeviceConnectivityHandle * other_handle; + gboolean handle_is_alive; + gboolean allow_periodic_bump; + gboolean any_periodic_before; + gboolean any_periodic_after; + guint64 seq; + + handle = user_data; + nm_assert(handle->c_handle == c_handle); + nm_assert(NM_IS_DEVICE(handle->self)); + + handle->c_handle = NULL; + self = handle->self; + + if (state == NM_CONNECTIVITY_CANCELLED) { + /* the only place where we nm_connectivity_check_cancel(@c_handle), is + * from inside concheck_handle_complete(). This is a recursive call, + * nothing to do. */ + _LOGT(LOGD_CONCHECK, + "connectivity: [IPv%c] complete check (seq:%llu, cancelled)", + nm_utils_addr_family_to_char(handle->addr_family), + (long long unsigned) handle->seq); + return; + } + + /* we keep NMConnectivity instance alive. It cannot be disposing. */ + nm_assert(state != NM_CONNECTIVITY_DISPOSING); + + self_keep_alive = g_object_ref(self); + + /* keep @self alive, while we invoke callbacks. */ + priv = NM_DEVICE_GET_PRIVATE(self); + + nm_assert(handle && c_list_contains(&priv->concheck_lst_head, &handle->concheck_lst)); + + seq = handle->seq; + + _LOGT(LOGD_CONCHECK, + "connectivity: [Ipv%c] complete check (seq:%llu, state:%s)", + nm_utils_addr_family_to_char(handle->addr_family), + (long long unsigned) handle->seq, + nm_connectivity_state_to_string(state)); + + /* find out, if there are any periodic checks pending (either whether they + * were scheduled before or after @handle. */ + any_periodic_before = FALSE; + any_periodic_after = FALSE; + c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { + if (other_handle->addr_family != handle->addr_family) + continue; + if (other_handle->is_periodic_bump_on_complete) { + if (other_handle->seq < seq) + any_periodic_before = TRUE; + else if (other_handle->seq > seq) + any_periodic_after = TRUE; + } + } + if (NM_IN_SET(state, NM_CONNECTIVITY_ERROR)) { + /* the request failed. We consider this periodic check only as completed if + * this was a periodic check, and there are not checks pending (either + * before or after this one). + * + * We allow_periodic_bump, if the request failed and there are + * still other requests periodic pending. */ + allow_periodic_bump = + handle->is_periodic_bump_on_complete && !any_periodic_before && !any_periodic_after; + } else { + /* the request succeeded. This marks the completion of a periodic check, + * if this handle was periodic, or any previously scheduled one (that + * we are going to complete below). */ + allow_periodic_bump = handle->is_periodic_bump_on_complete || any_periodic_before; + } + + /* first update the new state, and emit signals. */ + concheck_update_state(self, handle->addr_family, state, allow_periodic_bump); + + handle_is_alive = FALSE; + + /* we might have invoked callbacks during concheck_update_state(). The caller might have + * cancelled and thus destroyed @handle. We have to check whether handle is still alive, + * by searching it in the list of alive handles. + * + * Also, we might want to complete all pending callbacks that were started before + * @handle, as they are automatically obsoleted. */ check_handles: - c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { - if (other_handle->addr_family != handle->addr_family) - continue; - if (other_handle->seq >= seq) { - /* it's not guaranteed that @handle is still in the list. It might already - * be canceled while invoking callbacks for a previous other_handle. - * If it is already cancelled, @handle is a dangling pointer. - * - * Since @seq is assigned uniquely and increasing, either @other_handle is - * @handle (and thus, handle is alive), or it isn't. */ - if (other_handle == handle) - handle_is_alive = TRUE; - break; - } - - nm_assert (other_handle != handle); - - if (!NM_IN_SET (state, NM_CONNECTIVITY_ERROR)) { - /* we also want to complete handles that were started before the current - * @handle. Their response is out-dated. */ - concheck_handle_complete (other_handle, NULL); - - /* we invoked callbacks, other handles might be cancelled and removed from the list. - * Need to iterate the list from the start. */ - goto check_handles; - } - } - - if (!handle_is_alive) { - /* We didn't find @handle in the list of alive handles. Thus, the handles - * was cancelled while we were invoking events. Nothing to do, and don't - * touch the dangling pointer. */ - return; - } - - concheck_handle_complete (handle, NULL); + c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { + if (other_handle->addr_family != handle->addr_family) + continue; + if (other_handle->seq >= seq) { + /* it's not guaranteed that @handle is still in the list. It might already + * be canceled while invoking callbacks for a previous other_handle. + * If it is already cancelled, @handle is a dangling pointer. + * + * Since @seq is assigned uniquely and increasing, either @other_handle is + * @handle (and thus, handle is alive), or it isn't. */ + if (other_handle == handle) + handle_is_alive = TRUE; + break; + } + + nm_assert(other_handle != handle); + + if (!NM_IN_SET(state, NM_CONNECTIVITY_ERROR)) { + /* we also want to complete handles that were started before the current + * @handle. Their response is out-dated. */ + concheck_handle_complete(other_handle, NULL); + + /* we invoked callbacks, other handles might be cancelled and removed from the list. + * Need to iterate the list from the start. */ + goto check_handles; + } + } + + if (!handle_is_alive) { + /* We didn't find @handle in the list of alive handles. Thus, the handles + * was cancelled while we were invoking events. Nothing to do, and don't + * touch the dangling pointer. */ + return; + } + + concheck_handle_complete(handle, NULL); } static NMDeviceConnectivityHandle * -concheck_start (NMDevice *self, - int addr_family, - NMDeviceConnectivityCallback callback, - gpointer user_data, - gboolean is_periodic) -{ - static guint64 seq_counter = 0; - NMDevicePrivate *priv; - NMDeviceConnectivityHandle *handle; - const char *ifname; - - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - - priv = NM_DEVICE_GET_PRIVATE (self); - - handle = g_slice_new0 (NMDeviceConnectivityHandle); - handle->seq = ++seq_counter; - handle->self = self; - handle->callback = callback; - handle->user_data = user_data; - handle->is_periodic = is_periodic; - handle->is_periodic_bump = is_periodic; - handle->is_periodic_bump_on_complete = is_periodic; - handle->addr_family = addr_family; - - c_list_link_tail (&priv->concheck_lst_head, &handle->concheck_lst); - - _LOGT (LOGD_CONCHECK, "connectivity: [IPv%c] start check (seq:%llu%s)", - nm_utils_addr_family_to_char (addr_family), - (long long unsigned) handle->seq, - is_periodic ? ", periodic-check" : ""); - - if ( addr_family == AF_INET - && !priv->concheck_rp_filter_checked) { - - if ((ifname = nm_device_get_ip_iface_from_platform (self))) { - gboolean due_to_all; - int val; - - val = nm_platform_sysctl_ip_conf_get_rp_filter_ipv4 (nm_device_get_platform (self), - ifname, - TRUE, - &due_to_all); - if (val == 1) { - _LOGW (LOGD_CONCHECK, "connectivity: \"/proc/sys/net/ipv4/conf/%s/rp_filter\" is set to \"1\". " - "This might break connectivity checking for IPv4 on this device", - due_to_all ? "all" : ifname); - } - } - - /* we only check once per device. It's a warning after all. */ - priv->concheck_rp_filter_checked = TRUE; - } - - handle->c_handle = nm_connectivity_check_start (concheck_get_mgr (self), - handle->addr_family, - nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - nm_device_get_ip_iface (self), - concheck_cb, - handle); - return handle; +concheck_start(NMDevice * self, + int addr_family, + NMDeviceConnectivityCallback callback, + gpointer user_data, + gboolean is_periodic) +{ + static guint64 seq_counter = 0; + NMDevicePrivate * priv; + NMDeviceConnectivityHandle *handle; + const char * ifname; + + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); + + priv = NM_DEVICE_GET_PRIVATE(self); + + handle = g_slice_new0(NMDeviceConnectivityHandle); + handle->seq = ++seq_counter; + handle->self = self; + handle->callback = callback; + handle->user_data = user_data; + handle->is_periodic = is_periodic; + handle->is_periodic_bump = is_periodic; + handle->is_periodic_bump_on_complete = is_periodic; + handle->addr_family = addr_family; + + c_list_link_tail(&priv->concheck_lst_head, &handle->concheck_lst); + + _LOGT(LOGD_CONCHECK, + "connectivity: [IPv%c] start check (seq:%llu%s)", + nm_utils_addr_family_to_char(addr_family), + (long long unsigned) handle->seq, + is_periodic ? ", periodic-check" : ""); + + if (addr_family == AF_INET && !priv->concheck_rp_filter_checked) { + if ((ifname = nm_device_get_ip_iface_from_platform(self))) { + gboolean due_to_all; + int val; + + val = nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(nm_device_get_platform(self), + ifname, + TRUE, + &due_to_all); + if (val == 1) { + _LOGW(LOGD_CONCHECK, + "connectivity: \"/proc/sys/net/ipv4/conf/%s/rp_filter\" is set to \"1\". " + "This might break connectivity checking for IPv4 on this device", + due_to_all ? "all" : ifname); + } + } + + /* we only check once per device. It's a warning after all. */ + priv->concheck_rp_filter_checked = TRUE; + } + + handle->c_handle = nm_connectivity_check_start(concheck_get_mgr(self), + handle->addr_family, + nm_device_get_platform(self), + nm_device_get_ip_ifindex(self), + nm_device_get_ip_iface(self), + concheck_cb, + handle); + return handle; } NMDeviceConnectivityHandle * -nm_device_check_connectivity (NMDevice *self, - int addr_family, - NMDeviceConnectivityCallback callback, - gpointer user_data) +nm_device_check_connectivity(NMDevice * self, + int addr_family, + NMDeviceConnectivityCallback callback, + gpointer user_data) { - if (!concheck_is_possible (self)) - return NULL; + if (!concheck_is_possible(self)) + return NULL; - concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_CHECK_EXTERNAL); - return concheck_start (self, addr_family, callback, user_data, FALSE); + concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_CHECK_EXTERNAL); + return concheck_start(self, addr_family, callback, user_data, FALSE); } void -nm_device_check_connectivity_cancel (NMDeviceConnectivityHandle *handle) +nm_device_check_connectivity_cancel(NMDeviceConnectivityHandle *handle) { - gs_free_error GError *cancelled_error = NULL; + gs_free_error GError *cancelled_error = NULL; - g_return_if_fail (handle); - g_return_if_fail (NM_IS_DEVICE (handle->self)); - g_return_if_fail (!c_list_is_empty (&handle->concheck_lst)); + g_return_if_fail(handle); + g_return_if_fail(NM_IS_DEVICE(handle->self)); + g_return_if_fail(!c_list_is_empty(&handle->concheck_lst)); - /* nobody has access to periodic handles, and cannot cancel - * them externally. */ - nm_assert (!handle->is_periodic); + /* nobody has access to periodic handles, and cannot cancel + * them externally. */ + nm_assert(!handle->is_periodic); - nm_utils_error_set_cancelled (&cancelled_error, FALSE, "NMDevice"); - concheck_handle_complete (handle, cancelled_error); + nm_utils_error_set_cancelled(&cancelled_error, FALSE, "NMDevice"); + concheck_handle_complete(handle, cancelled_error); } NMConnectivityState -nm_device_get_connectivity_state (NMDevice *self, int addr_family) +nm_device_get_connectivity_state(NMDevice *self, int addr_family) { - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); - g_return_val_if_fail (NM_IS_DEVICE (self), NM_CONNECTIVITY_UNKNOWN); - nm_assert_addr_family (addr_family); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_CONNECTIVITY_UNKNOWN); + nm_assert_addr_family(addr_family); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - switch (addr_family) { - case AF_INET: - case AF_INET6: - return priv->concheck_x[IS_IPv4].state; - default: - nm_assert (addr_family == AF_UNSPEC); - return NM_MAX_WITH_CMP (nm_connectivity_state_cmp, - priv->concheck_x[0].state, - priv->concheck_x[1].state); - } + switch (addr_family) { + case AF_INET: + case AF_INET6: + return priv->concheck_x[IS_IPv4].state; + default: + nm_assert(addr_family == AF_UNSPEC); + return NM_MAX_WITH_CMP(nm_connectivity_state_cmp, + priv->concheck_x[0].state, + priv->concheck_x[1].state); + } } /*****************************************************************************/ static SlaveInfo * -find_slave_info (NMDevice *self, NMDevice *slave) +find_slave_info(NMDevice *self, NMDevice *slave) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - CList *iter; - SlaveInfo *info; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + CList * iter; + SlaveInfo * info; - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry (iter, SlaveInfo, lst_slave); - if (info->slave == slave) - return info; - } - return NULL; + c_list_for_each (iter, &priv->slaves) { + info = c_list_entry(iter, SlaveInfo, lst_slave); + if (info->slave == slave) + return info; + } + return NULL; } /** @@ -3683,63 +4607,62 @@ find_slave_info (NMDevice *self, NMDevice *slave) * other devices. */ static gboolean -nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connection) +nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection) { - NMDevicePrivate *priv; - SlaveInfo *info; - gboolean success = FALSE; - gboolean configure; + NMDevicePrivate *priv; + SlaveInfo * info; + gboolean success = FALSE; + gboolean configure; - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (slave != NULL, FALSE); - g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL, FALSE); + g_return_val_if_fail(self != NULL, FALSE); + g_return_val_if_fail(slave != NULL, FALSE); + g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE); - priv = NM_DEVICE_GET_PRIVATE (self); - info = find_slave_info (self, slave); - if (!info) - return FALSE; + priv = NM_DEVICE_GET_PRIVATE(self); + info = find_slave_info(self, slave); + if (!info) + return FALSE; - if (info->slave_is_enslaved) - success = TRUE; - else { - configure = (info->configure && connection != NULL); - if (configure) - g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + if (info->slave_is_enslaved) + success = TRUE; + else { + configure = (info->configure && connection != NULL); + if (configure) + g_return_val_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); - success = NM_DEVICE_GET_CLASS (self)->enslave_slave (self, slave, connection, configure); - info->slave_is_enslaved = success; - } + success = NM_DEVICE_GET_CLASS(self)->enslave_slave(self, slave, connection, configure); + info->slave_is_enslaved = success; + } - nm_device_slave_notify_enslave (info->slave, success); + nm_device_slave_notify_enslave(info->slave, success); - /* Ensure the device's hardware address is up-to-date; it often changes - * when slaves change. - */ - nm_device_update_hw_address (self); + /* Ensure the device's hardware address is up-to-date; it often changes + * when slaves change. + */ + nm_device_update_hw_address(self); - /* Send ARP announcements if did not yet and have addresses. */ - if ( priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - && !priv->acd.announcing) - nm_device_arp_announce (self); + /* Send ARP announcements if did not yet and have addresses. */ + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !priv->acd.announcing) + nm_device_arp_announce(self); - /* Restart IP configuration if we're waiting for slaves. Do this - * after updating the hardware address as IP config may need the - * new address. - */ - if (success) { - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_WAIT) - nm_device_activate_stage3_ip4_start (self); + /* Restart IP configuration if we're waiting for slaves. Do this + * after updating the hardware address as IP config may need the + * new address. + */ + if (success) { + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_WAIT) + nm_device_activate_stage3_ip4_start(self); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT) - nm_device_activate_stage3_ip6_start (self); - } + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT) + nm_device_activate_stage3_ip6_start(self); + } - /* Since slave devices don't have their own IP configuration, - * set the MTU here. - */ - _commit_mtu (slave, NM_DEVICE_GET_PRIVATE (slave)->ip_config_4); + /* Since slave devices don't have their own IP configuration, + * set the MTU here. + */ + _commit_mtu(slave, NM_DEVICE_GET_PRIVATE(slave)->ip_config_4); - return success; + return success; } /** @@ -3747,6 +4670,8 @@ nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *c * @self: the master device * @slave: the slave device to release * @configure: whether @self needs to actually release @slave + * @force: force the release of @slave even if it wasn't added + * to @master by NetworkManager * @reason: the state change reason for the @slave * * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, @@ -3754,60 +4679,72 @@ nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *c * updates the state of @self and @slave to reflect its release. */ static void -nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure, NMDeviceStateReason reason) -{ - NMDevicePrivate *priv; - NMDevicePrivate *slave_priv; - SlaveInfo *info; - gs_unref_object NMDevice *self_free = NULL; - - g_return_if_fail (NM_DEVICE (self)); - g_return_if_fail (NM_DEVICE (slave)); - g_return_if_fail (NM_DEVICE_GET_CLASS (self)->release_slave != NULL); - - info = find_slave_info (self, slave); - - _LOGT (LOGD_CORE, "master: release one slave %p/%s%s", slave, nm_device_get_iface (slave), - !info ? " (not registered)" : ""); - - if (!info) - g_return_if_reached (); - - priv = NM_DEVICE_GET_PRIVATE (self); - slave_priv = NM_DEVICE_GET_PRIVATE (slave); - - g_return_if_fail (self == slave_priv->master); - nm_assert (slave == info->slave); - - /* first, let subclasses handle the release ... */ - if (info->slave_is_enslaved) - NM_DEVICE_GET_CLASS (self)->release_slave (self, slave, configure); - - /* raise notifications about the release, including clearing is_enslaved. */ - nm_device_slave_notify_release (slave, reason); - - /* keep both alive until the end of the function. - * Transfers ownership from slave_priv->master. */ - self_free = self; - - c_list_unlink (&info->lst_slave); - slave_priv->master = NULL; - - g_signal_handler_disconnect (slave, info->watch_id); - g_object_unref (slave); - g_slice_free (SlaveInfo, info); - - if (c_list_is_empty (&priv->slaves)) { - _active_connection_set_state_flags_full (self, - 0, - NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES); - } - - /* Ensure the device's hardware address is up-to-date; it often changes - * when slaves change. - */ - nm_device_update_hw_address (self); - nm_device_set_unmanaged_by_flags (slave, NM_UNMANAGED_IS_SLAVE, NM_UNMAN_FLAG_OP_FORGET, NM_DEVICE_STATE_REASON_REMOVED); +nm_device_master_release_one_slave(NMDevice * self, + NMDevice * slave, + gboolean configure, + gboolean force, + NMDeviceStateReason reason) +{ + NMDevicePrivate *priv; + NMDevicePrivate *slave_priv; + SlaveInfo * info; + gs_unref_object NMDevice *self_free = NULL; + + g_return_if_fail(NM_DEVICE(self)); + g_return_if_fail(NM_DEVICE(slave)); + g_return_if_fail(!force || configure); + g_return_if_fail(NM_DEVICE_GET_CLASS(self)->release_slave != NULL); + + info = find_slave_info(self, slave); + + _LOGT(LOGD_CORE, + "master: release one slave %p/%s %s%s", + slave, + nm_device_get_iface(slave), + !info ? "(not registered)" : (info->slave_is_enslaved ? "(enslaved)" : "(not enslaved)"), + force ? " (force-configure)" : (configure ? " (configure)" : "")); + + if (!info) + g_return_if_reached(); + + priv = NM_DEVICE_GET_PRIVATE(self); + slave_priv = NM_DEVICE_GET_PRIVATE(slave); + + g_return_if_fail(self == slave_priv->master); + nm_assert(slave == info->slave); + + /* first, let subclasses handle the release ... */ + if (info->slave_is_enslaved || force) + NM_DEVICE_GET_CLASS(self)->release_slave(self, slave, configure); + + /* raise notifications about the release, including clearing is_enslaved. */ + nm_device_slave_notify_release(slave, reason); + + /* keep both alive until the end of the function. + * Transfers ownership from slave_priv->master. */ + self_free = self; + + c_list_unlink(&info->lst_slave); + slave_priv->master = NULL; + + g_signal_handler_disconnect(slave, info->watch_id); + g_object_unref(slave); + g_slice_free(SlaveInfo, info); + + if (c_list_is_empty(&priv->slaves)) { + _active_connection_set_state_flags_full(self, + 0, + NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES); + } + + /* Ensure the device's hardware address is up-to-date; it often changes + * when slaves change. + */ + nm_device_update_hw_address(self); + nm_device_set_unmanaged_by_flags(slave, + NM_UNMANAGED_IS_SLAVE, + NM_UNMAN_FLAG_OP_FORGET, + NM_DEVICE_STATE_REASON_REMOVED); } /** @@ -3818,736 +4755,761 @@ nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean co * IFF_UP-ed externally. */ static gboolean -can_unmanaged_external_down (NMDevice *self) +can_unmanaged_external_down(NMDevice *self) { - return !NM_DEVICE_GET_PRIVATE (self)->nm_owned - && nm_device_is_software (self); + return !NM_DEVICE_GET_PRIVATE(self)->nm_owned && nm_device_is_software(self); } static NMUnmanFlagOp -is_unmanaged_external_down (NMDevice *self, gboolean consider_can) +is_unmanaged_external_down(NMDevice *self, gboolean consider_can) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if ( consider_can - && !NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) - return NM_UNMAN_FLAG_OP_FORGET; + if (consider_can && !NM_DEVICE_GET_CLASS(self)->can_unmanaged_external_down(self)) + return NM_UNMAN_FLAG_OP_FORGET; - /* Manage externally-created software interfaces only when they are IFF_UP */ - if ( priv->ifindex <= 0 - || !priv->up - || !( !c_list_is_empty (&priv->slaves) - || nm_platform_link_can_assume (nm_device_get_platform (self), priv->ifindex))) - return NM_UNMAN_FLAG_OP_SET_UNMANAGED; + /* Manage externally-created software interfaces only when they are IFF_UP */ + if (priv->ifindex <= 0 || !priv->up + || !(!c_list_is_empty(&priv->slaves) + || nm_platform_link_can_assume(nm_device_get_platform(self), priv->ifindex))) + return NM_UNMAN_FLAG_OP_SET_UNMANAGED; - return NM_UNMAN_FLAG_OP_SET_MANAGED; + return NM_UNMAN_FLAG_OP_SET_MANAGED; } static void -set_unmanaged_external_down (NMDevice *self, gboolean only_if_unmanaged) +set_unmanaged_external_down(NMDevice *self, gboolean only_if_unmanaged) { - NMUnmanFlagOp ext_flags; + NMUnmanFlagOp ext_flags; - if (!nm_device_get_unmanaged_mask (self, NM_UNMANAGED_EXTERNAL_DOWN)) - return; + if (!nm_device_get_unmanaged_mask(self, NM_UNMANAGED_EXTERNAL_DOWN)) + return; - if (only_if_unmanaged) { - if (!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN)) - return; - } + if (only_if_unmanaged) { + if (!nm_device_get_unmanaged_flags(self, NM_UNMANAGED_EXTERNAL_DOWN)) + return; + } - ext_flags = is_unmanaged_external_down (self, FALSE); - if (ext_flags != NM_UNMAN_FLAG_OP_SET_UNMANAGED) { - /* Ensure the assume check is queued before any queued state changes - * from the transition to UNAVAILABLE. - */ - nm_device_queue_recheck_assume (self); - } + ext_flags = is_unmanaged_external_down(self, FALSE); + if (ext_flags != NM_UNMAN_FLAG_OP_SET_UNMANAGED) { + /* Ensure the assume check is queued before any queued state changes + * from the transition to UNAVAILABLE. + */ + nm_device_queue_recheck_assume(self); + } - nm_device_set_unmanaged_by_flags (self, - NM_UNMANAGED_EXTERNAL_DOWN, - ext_flags, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + nm_device_set_unmanaged_by_flags(self, + NM_UNMANAGED_EXTERNAL_DOWN, + ext_flags, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } void -nm_device_update_dynamic_ip_setup (NMDevice *self) -{ - NMDevicePrivate *priv; - GError *error = NULL; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE (self); - - if ( priv->state < NM_DEVICE_STATE_IP_CONFIG - || priv->state > NM_DEVICE_STATE_ACTIVATED) - return; - - g_hash_table_remove_all (priv->ip6_saved_properties); - - if (priv->dhcp_data_4.client) { - if (!nm_device_dhcp4_renew (self, FALSE)) { - nm_device_state_changed (self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DHCP_FAILED); - return; - } - } - if (priv->dhcp_data_6.client) { - if (!nm_device_dhcp6_renew (self, FALSE)) { - nm_device_state_changed (self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DHCP_FAILED); - return; - } - } - if (priv->ndisc) { - /* FIXME: todo */ - } - if (priv->dnsmasq_manager) { - /* FIXME: todo */ - } - - if ( priv->lldp_listener - && nm_lldp_listener_is_running (priv->lldp_listener)) { - nm_lldp_listener_stop (priv->lldp_listener); - if (!nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error)) { - _LOGD (LOGD_DEVICE, "LLDP listener %p could not be restarted: %s", - priv->lldp_listener, error->message); - g_clear_error (&error); - } - } +nm_device_update_dynamic_ip_setup(NMDevice *self) +{ + NMDevicePrivate *priv; + GError * error = NULL; + + g_return_if_fail(NM_IS_DEVICE(self)); + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->state < NM_DEVICE_STATE_IP_CONFIG || priv->state > NM_DEVICE_STATE_ACTIVATED) + return; + + g_hash_table_remove_all(priv->ip6_saved_properties); + + if (priv->dhcp_data_4.client) { + if (!nm_device_dhcp4_renew(self, FALSE)) { + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_DHCP_FAILED); + return; + } + } + if (priv->dhcp_data_6.client) { + if (!nm_device_dhcp6_renew(self, FALSE)) { + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_DHCP_FAILED); + return; + } + } + if (priv->ndisc) { + /* FIXME: todo */ + } + if (priv->dnsmasq_manager) { + /* FIXME: todo */ + } + + if (priv->lldp_listener && nm_lldp_listener_is_running(priv->lldp_listener)) { + nm_lldp_listener_stop(priv->lldp_listener); + if (!nm_lldp_listener_start(priv->lldp_listener, nm_device_get_ifindex(self), &error)) { + _LOGD(LOGD_DEVICE, + "LLDP listener %p could not be restarted: %s", + priv->lldp_listener, + error->message); + g_clear_error(&error); + } + } } /*****************************************************************************/ static void -carrier_changed_notify (NMDevice *self, gboolean carrier) +carrier_changed_notify(NMDevice *self, gboolean carrier) { - /* stub */ + /* stub */ } static void -carrier_changed (NMDevice *self, gboolean carrier) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if (priv->state <= NM_DEVICE_STATE_UNMANAGED) - return; - - nm_device_recheck_available_connections (self); - - /* ignore-carrier devices ignore all carrier-down events */ - if (priv->ignore_carrier && !carrier) - return; - - if (nm_device_is_master (self)) { - if (carrier) { - /* Force master to retry getting ip addresses when carrier - * is restored. */ - if (priv->state == NM_DEVICE_STATE_ACTIVATED) - nm_device_update_dynamic_ip_setup (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 */ - } else if (priv->is_enslaved && !carrier) { - /* Slaves don't deactivate when they lose carrier; for - * bonds/teams in particular that would be actively - * counterproductive. - */ - return; - } - - if (carrier) { - if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_CARRIER); - } else if (priv->state == NM_DEVICE_STATE_DISCONNECTED) { - /* If the device is already in DISCONNECTED state without a carrier - * (probably because it is tagged for carrier ignore) ensure that - * when the carrier appears, auto connections are rechecked for - * the device. - */ - nm_device_emit_recheck_auto_activate (self); - } else if (priv->state == NM_DEVICE_STATE_ACTIVATED) { - /* If the device is active without a carrier (probably because it is - * tagged for carrier ignore) ensure that when the carrier appears we - * renew DHCP leases and such. - */ - nm_device_update_dynamic_ip_setup (self); - } - } else { - if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { - if ( priv->queued_state.id - && priv->queued_state.state >= NM_DEVICE_STATE_DISCONNECTED) - queued_state_clear (self); - } else { - nm_device_queue_state (self, NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_CARRIER); - } - } +carrier_changed(NMDevice *self, gboolean carrier) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->state <= NM_DEVICE_STATE_UNMANAGED) + return; + + nm_device_recheck_available_connections(self); + + /* ignore-carrier devices ignore all carrier-down events */ + if (priv->ignore_carrier && !carrier) + return; + + if (nm_device_is_master(self)) { + if (carrier) { + /* Force master to retry getting ip addresses when carrier + * is restored. */ + if (priv->state == NM_DEVICE_STATE_ACTIVATED) + nm_device_update_dynamic_ip_setup(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 */ + } else if (priv->is_enslaved && !carrier) { + /* Slaves don't deactivate when they lose carrier; for + * bonds/teams in particular that would be actively + * counterproductive. + */ + return; + } + + if (carrier) { + if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { + nm_device_queue_state(self, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_CARRIER); + } else if (priv->state == NM_DEVICE_STATE_DISCONNECTED) { + /* If the device is already in DISCONNECTED state without a carrier + * (probably because it is tagged for carrier ignore) ensure that + * when the carrier appears, auto connections are rechecked for + * the device. + */ + nm_device_emit_recheck_auto_activate(self); + } else if (priv->state == NM_DEVICE_STATE_ACTIVATED) { + /* If the device is active without a carrier (probably because it is + * tagged for carrier ignore) ensure that when the carrier appears we + * renew DHCP leases and such. + */ + nm_device_update_dynamic_ip_setup(self); + } + } else { + if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { + if (priv->queued_state.id && priv->queued_state.state >= NM_DEVICE_STATE_DISCONNECTED) + queued_state_clear(self); + } else { + nm_device_queue_state(self, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_CARRIER); + } + } } static gboolean -carrier_disconnected_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); + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - _LOGD (LOGD_DEVICE, "carrier: link disconnected (calling deferred action) (id=%u)", priv->carrier_defer_id); + _LOGD(LOGD_DEVICE, + "carrier: link disconnected (calling deferred action) (id=%u)", + priv->carrier_defer_id); - priv->carrier_defer_id = 0; - carrier_changed (self, FALSE); - return FALSE; + priv->carrier_defer_id = 0; + carrier_changed(self, FALSE); + return FALSE; } static void -carrier_disconnected_action_cancel (NMDevice *self) +carrier_disconnected_action_cancel(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint id = priv->carrier_defer_id; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + guint id = priv->carrier_defer_id; - if (nm_clear_g_source (&priv->carrier_defer_id)) { - _LOGD (LOGD_DEVICE, "carrier: link disconnected (canceling deferred action) (id=%u)", - id); - } + if (nm_clear_g_source(&priv->carrier_defer_id)) { + _LOGD(LOGD_DEVICE, "carrier: link disconnected (canceling deferred action) (id=%u)", id); + } } void -nm_device_set_carrier (NMDevice *self, gboolean carrier) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceState state = nm_device_get_state (self); - gboolean notify_flags = FALSE; - - if (priv->carrier == carrier) - return; - - if (NM_FLAGS_ALL (priv->capabilities, - NM_DEVICE_CAP_CARRIER_DETECT - | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { - if (carrier) - priv->interface_flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; - else - priv->interface_flags &= ~NM_DEVICE_INTERFACE_FLAG_CARRIER; - notify_flags = TRUE; - } - - priv->carrier = carrier; - if (notify_flags) - nm_gobject_notify_together (self, PROP_CARRIER, PROP_INTERFACE_FLAGS); - else - _notify (self, PROP_CARRIER); - - if (priv->carrier) { - _LOGI (LOGD_DEVICE, "carrier: link connected"); - carrier_disconnected_action_cancel (self); - NM_DEVICE_GET_CLASS (self)->carrier_changed_notify (self, carrier); - carrier_changed (self, 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 (priv->carrier_wait_id) - nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); - NM_DEVICE_GET_CLASS (self)->carrier_changed_notify (self, carrier); - if ( state <= NM_DEVICE_STATE_DISCONNECTED - && !priv->queued_act_request) { - _LOGD (LOGD_DEVICE, "carrier: link disconnected"); - carrier_changed (self, FALSE); - } else { - gint64 now_ms, until_ms; - - now_ms = nm_utils_get_monotonic_timestamp_msec (); - until_ms = NM_MAX (now_ms + _get_carrier_wait_ms (self), priv->carrier_wait_until_ms); - priv->carrier_defer_id = g_timeout_add (until_ms - now_ms, carrier_disconnected_action_cb, self); - _LOGD (LOGD_DEVICE, "carrier: link disconnected (deferring action for %ld milliseconds) (id=%u)", - (long) (until_ms - now_ms), priv->carrier_defer_id); - } - } +nm_device_set_carrier(NMDevice *self, gboolean carrier) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceState state = nm_device_get_state(self); + gboolean notify_flags = FALSE; + + if (priv->carrier == carrier) + return; + + if (NM_FLAGS_ALL(priv->capabilities, + NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { + if (carrier) + priv->interface_flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; + else + priv->interface_flags &= ~NM_DEVICE_INTERFACE_FLAG_CARRIER; + notify_flags = TRUE; + } + + priv->carrier = carrier; + if (notify_flags) + nm_gobject_notify_together(self, PROP_CARRIER, PROP_INTERFACE_FLAGS); + else + _notify(self, PROP_CARRIER); + + if (priv->carrier) { + _LOGI(LOGD_DEVICE, "carrier: link connected"); + carrier_disconnected_action_cancel(self); + NM_DEVICE_GET_CLASS(self)->carrier_changed_notify(self, carrier); + carrier_changed(self, 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 (priv->carrier_wait_id) + nm_device_add_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); + NM_DEVICE_GET_CLASS(self)->carrier_changed_notify(self, carrier); + if (state <= NM_DEVICE_STATE_DISCONNECTED && !priv->queued_act_request) { + _LOGD(LOGD_DEVICE, "carrier: link disconnected"); + carrier_changed(self, FALSE); + } else { + gint64 now_ms, until_ms; + + now_ms = nm_utils_get_monotonic_timestamp_msec(); + until_ms = NM_MAX(now_ms + _get_carrier_wait_ms(self), priv->carrier_wait_until_ms); + priv->carrier_defer_id = + g_timeout_add(until_ms - now_ms, carrier_disconnected_action_cb, self); + _LOGD(LOGD_DEVICE, + "carrier: link disconnected (deferring action for %ld milliseconds) (id=%u)", + (long) (until_ms - now_ms), + priv->carrier_defer_id); + } + } } static void -nm_device_set_carrier_from_platform (NMDevice *self) +nm_device_set_carrier_from_platform(NMDevice *self) { - int ifindex; + int ifindex; - if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { - if ( !nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER) - && (ifindex = nm_device_get_ip_ifindex (self)) > 0) { - nm_device_set_carrier (self, - nm_platform_link_is_connected (nm_device_get_platform (self), - ifindex)); - } - } else { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + if (nm_device_has_capability(self, NM_DEVICE_CAP_CARRIER_DETECT)) { + if (!nm_device_has_capability(self, NM_DEVICE_CAP_NONSTANDARD_CARRIER) + && (ifindex = nm_device_get_ip_ifindex(self)) > 0) { + nm_device_set_carrier( + self, + nm_platform_link_is_connected(nm_device_get_platform(self), ifindex)); + } + } 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); - } - } + /* 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) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDevice *master; - nm_auto_nmpobj const NMPObject *plink_master_keep_alive = NULL; - const NMPlatformLink *plink_master; - - g_return_if_fail (plink); - - if (plink->master <= 0) - return; - - master = nm_manager_get_device_by_ifindex (NM_MANAGER_GET, plink->master); - plink_master = nm_platform_link_get (nm_device_get_platform (self), plink->master); - plink_master_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink_master)); - - if ( master == NULL - && plink_master - && g_strcmp0 (plink_master->name, "ovs-system") == 0 - && plink_master->type == NM_LINK_TYPE_OPENVSWITCH) { - _LOGD (LOGD_DEVICE, "the device claimed by openvswitch"); - return; - } - - if (priv->master) { - if ( plink->master > 0 - && plink->master == nm_device_get_ifindex (priv->master)) { - /* call add-slave again. We expect @self already to be added to - * the master, but this also triggers a recheck-assume. */ - nm_device_master_add_slave (priv->master, self, FALSE); - return; - } - - nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - } - - if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) - nm_device_master_add_slave (master, self, FALSE); - else if (master) { - _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface (master)); - } else { - _LOGW (LOGD_DEVICE, "enslaved to unknown device %d (%s%s%s)", - plink->master, - NM_PRINT_FMT_QUOTED (plink_master, "\"", plink_master->name, "\"", "??")); - } +device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDevice * master; + nm_auto_nmpobj const NMPObject *plink_master_keep_alive = NULL; + const NMPlatformLink * plink_master; + + g_return_if_fail(plink); + + if (plink->master <= 0) + return; + + master = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, plink->master); + plink_master = nm_platform_link_get(nm_device_get_platform(self), plink->master); + plink_master_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(plink_master)); + + if (master == NULL && plink_master && nm_streq0(plink_master->name, "ovs-system") + && plink_master->type == NM_LINK_TYPE_OPENVSWITCH) { + _LOGD(LOGD_DEVICE, "the device claimed by openvswitch"); + return; + } + + if (priv->master) { + if (plink->master > 0 && plink->master == nm_device_get_ifindex(priv->master)) { + /* call add-slave again. We expect @self already to be added to + * the master, but this also triggers a recheck-assume. */ + nm_device_master_add_slave(priv->master, self, FALSE); + return; + } + + nm_device_master_release_one_slave(priv->master, + self, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + + if (master && NM_DEVICE_GET_CLASS(master)->enslave_slave) + nm_device_master_add_slave(master, self, FALSE); + else if (master) { + _LOGI(LOGD_DEVICE, + "enslaved to non-master-type device %s; ignoring", + nm_device_get_iface(master)); + } else { + _LOGW(LOGD_DEVICE, + "enslaved to unknown device %d (%s%s%s)", + plink->master, + NM_PRINT_FMT_QUOTED(plink_master, "\"", plink_master->name, "\"", "??")); + } } static void -ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gint32 now; - GArray *addresses, *dns_servers, *dns_domains; - guint len, i; - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter ipconf_iter; - - if (nm_ndisc_get_node_type (ndisc) != NM_NDISC_NODE_TYPE_ROUTER) - return; - - now = nm_utils_get_monotonic_timestamp_sec (); - - head_entry = nm_ip6_config_lookup_addresses (priv->ip_config_6); - addresses = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscAddress), - head_entry ? head_entry->len : 0); - nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) { - const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (ipconf_iter.current->obj); - NMNDiscAddress *ndisc_addr; - guint32 lifetime, preferred; - gint32 base; - - if ( IN6_IS_ADDR_UNSPECIFIED (&addr->address) - || IN6_IS_ADDR_LINKLOCAL (&addr->address)) - continue; - - if ( addr->n_ifa_flags & IFA_F_TENTATIVE - || addr->n_ifa_flags & IFA_F_DADFAILED) - continue; - - if (addr->plen != 64) - continue; - - /* resolve the timestamps relative to a new base. - * - * Note that for convenience, platform @addr might have timestamp and/or - * lifetime unset. We don't allow that flexibility for ndisc and require - * well defined timestamps. */ - if (addr->timestamp) { - nm_assert (addr->timestamp < G_MAXINT32); - base = addr->timestamp; - } else - base = now; - - lifetime = nm_utils_lifetime_get (addr->timestamp, addr->lifetime, addr->preferred, - base, &preferred); - if (!lifetime) - continue; - - g_array_set_size (addresses, addresses->len+1); - ndisc_addr = &g_array_index (addresses, NMNDiscAddress, addresses->len-1); - ndisc_addr->address = addr->address; - ndisc_addr->timestamp = base; - ndisc_addr->lifetime = lifetime; - ndisc_addr->preferred = preferred; - } - - len = nm_ip6_config_get_num_nameservers (priv->ip_config_6); - dns_servers = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscDNSServer), len); - g_array_set_size (dns_servers, len); - for (i = 0; i < len; i++) { - const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (priv->ip_config_6, i); - NMNDiscDNSServer *ndisc_nameserver; - - ndisc_nameserver = &g_array_index (dns_servers, NMNDiscDNSServer, i); - ndisc_nameserver->address = *nameserver; - ndisc_nameserver->timestamp = now; - ndisc_nameserver->lifetime = NM_NDISC_ROUTER_LIFETIME; - } - - len = nm_ip6_config_get_num_searches (priv->ip_config_6); - dns_domains = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscDNSDomain), len); - g_array_set_size (dns_domains, len); - for (i = 0; i < len; i++) { - const char *search = nm_ip6_config_get_search (priv->ip_config_6, i); - NMNDiscDNSDomain *ndisc_search; - - ndisc_search = &g_array_index (dns_domains, NMNDiscDNSDomain, i); - ndisc_search->domain = (char *) search; - ndisc_search->timestamp = now; - ndisc_search->lifetime = NM_NDISC_ROUTER_LIFETIME; - } - - nm_ndisc_set_config (ndisc, addresses, dns_servers, dns_domains); - g_array_unref (addresses); - g_array_unref (dns_servers); - g_array_unref (dns_domains); +ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + gint32 now; + GArray * addresses, *dns_servers, *dns_domains; + guint len, i; + const NMDedupMultiHeadEntry *head_entry; + NMDedupMultiIter ipconf_iter; + + if (nm_ndisc_get_node_type(ndisc) != NM_NDISC_NODE_TYPE_ROUTER) + return; + + now = nm_utils_get_monotonic_timestamp_sec(); + + head_entry = nm_ip6_config_lookup_addresses(priv->ip_config_6); + addresses = + g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscAddress), head_entry ? head_entry->len : 0); + nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) { + const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(ipconf_iter.current->obj); + NMNDiscAddress * ndisc_addr; + guint32 lifetime, preferred; + gint32 base; + + if (IN6_IS_ADDR_UNSPECIFIED(&addr->address) || IN6_IS_ADDR_LINKLOCAL(&addr->address)) + continue; + + if (addr->n_ifa_flags & IFA_F_TENTATIVE || addr->n_ifa_flags & IFA_F_DADFAILED) + continue; + + if (addr->plen != 64) + continue; + + /* resolve the timestamps relative to a new base. + * + * Note that for convenience, platform @addr might have timestamp and/or + * lifetime unset. We don't allow that flexibility for ndisc and require + * well defined timestamps. */ + if (addr->timestamp) { + nm_assert(addr->timestamp < G_MAXINT32); + base = addr->timestamp; + } else + base = now; + + lifetime = nm_utils_lifetime_get(addr->timestamp, + addr->lifetime, + addr->preferred, + base, + &preferred); + if (!lifetime) + continue; + + g_array_set_size(addresses, addresses->len + 1); + ndisc_addr = &g_array_index(addresses, NMNDiscAddress, addresses->len - 1); + ndisc_addr->address = addr->address; + ndisc_addr->timestamp = base; + ndisc_addr->lifetime = lifetime; + ndisc_addr->preferred = preferred; + } + + len = nm_ip6_config_get_num_nameservers(priv->ip_config_6); + dns_servers = g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscDNSServer), len); + g_array_set_size(dns_servers, len); + for (i = 0; i < len; i++) { + const struct in6_addr *nameserver = nm_ip6_config_get_nameserver(priv->ip_config_6, i); + NMNDiscDNSServer * ndisc_nameserver; + + ndisc_nameserver = &g_array_index(dns_servers, NMNDiscDNSServer, i); + ndisc_nameserver->address = *nameserver; + ndisc_nameserver->timestamp = now; + ndisc_nameserver->lifetime = NM_NDISC_ROUTER_LIFETIME; + } + + len = nm_ip6_config_get_num_searches(priv->ip_config_6); + dns_domains = g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscDNSDomain), len); + g_array_set_size(dns_domains, len); + for (i = 0; i < len; i++) { + const char * search = nm_ip6_config_get_search(priv->ip_config_6, i); + NMNDiscDNSDomain *ndisc_search; + + ndisc_search = &g_array_index(dns_domains, NMNDiscDNSDomain, i); + ndisc_search->domain = (char *) search; + ndisc_search->timestamp = now; + ndisc_search->lifetime = NM_NDISC_ROUTER_LIFETIME; + } + + nm_ndisc_set_config(ndisc, addresses, dns_servers, dns_domains); + g_array_unref(addresses); + g_array_unref(dns_servers); + g_array_unref(dns_domains); } static void -device_update_interface_flags (NMDevice *self, const NMPlatformLink *plink) +device_update_interface_flags(NMDevice *self, const NMPlatformLink *plink) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceInterfaceFlags flags = NM_DEVICE_INTERFACE_FLAG_NONE; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceInterfaceFlags flags = NM_DEVICE_INTERFACE_FLAG_NONE; - if (plink && NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP)) - flags |= NM_DEVICE_INTERFACE_FLAG_UP; - if (plink && NM_FLAGS_HAS (plink->n_ifi_flags, IFF_LOWER_UP)) - flags |= NM_DEVICE_INTERFACE_FLAG_LOWER_UP; + if (plink && NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP)) + flags |= NM_DEVICE_INTERFACE_FLAG_UP; + if (plink && NM_FLAGS_HAS(plink->n_ifi_flags, IFF_LOWER_UP)) + flags |= NM_DEVICE_INTERFACE_FLAG_LOWER_UP; - if (NM_FLAGS_ALL (priv->capabilities, - NM_DEVICE_CAP_CARRIER_DETECT - | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { - if (priv->carrier) - flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; - } else { - if (plink && NM_FLAGS_HAS (plink->n_ifi_flags, IFF_LOWER_UP)) - flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; - } + if (NM_FLAGS_ALL(priv->capabilities, + NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { + if (priv->carrier) + flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; + } else { + if (plink && NM_FLAGS_HAS(plink->n_ifi_flags, IFF_LOWER_UP)) + flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; + } - if (flags != priv->interface_flags) { - priv->interface_flags = flags; - _notify (self, PROP_INTERFACE_FLAGS); - } + if (flags != priv->interface_flags) { + priv->interface_flags = flags; + _notify(self, PROP_INTERFACE_FLAGS); + } } static gboolean -device_link_changed (NMDevice *self) -{ - NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean ip_ifname_changed = FALSE; - nm_auto_nmpobj const NMPObject *pllink_keep_alive = NULL; - const NMPlatformLink *pllink; - const char *str; - int ifindex; - gboolean was_up; - gboolean update_unmanaged_specs = FALSE; - gboolean got_hw_addr = FALSE, had_hw_addr; - gboolean seen_down = priv->device_link_changed_down; - - priv->device_link_changed_id = 0; - priv->device_link_changed_down = FALSE; - - ifindex = nm_device_get_ifindex (self); - if (ifindex <= 0) - return G_SOURCE_REMOVE; - pllink = nm_platform_link_get (nm_device_get_platform (self), ifindex); - if (!pllink) - return G_SOURCE_REMOVE; - - pllink_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (pllink)); - - str = nm_platform_link_get_udi (nm_device_get_platform (self), pllink->ifindex); - if (!nm_streq0 (str, priv->udi)) { - g_free (priv->udi); - priv->udi = g_strdup (str); - _notify (self, PROP_UDI); - } - - str = nm_platform_link_get_path (nm_device_get_platform (self), pllink->ifindex); - if (!nm_streq0 (str, priv->path)) { - g_free (priv->path); - priv->path = g_strdup (str); - _notify (self, PROP_PATH); - } - - if (!nm_streq0 (pllink->driver, priv->driver)) { - g_free (priv->driver); - priv->driver = g_strdup (pllink->driver); - _notify (self, PROP_DRIVER); - } - - _set_mtu (self, pllink->mtu); - - if (ifindex == nm_device_get_ip_ifindex (self)) - _stats_update_counters_from_pllink (self, pllink); - - had_hw_addr = (priv->hw_addr != NULL); - nm_device_update_hw_address (self); - got_hw_addr = (!had_hw_addr && priv->hw_addr); - nm_device_update_permanent_hw_address (self, FALSE); - - if (pllink->name[0] && strcmp (priv->iface, pllink->name) != 0) { - _LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'", - priv->ifindex, priv->iface, pllink->name); - g_free (priv->iface); - priv->iface = g_strdup (pllink->name); - - /* If the device has no explicit ip_iface, then changing iface changes ip_iface too. */ - ip_ifname_changed = !priv->ip_iface; - - if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) - nm_device_set_unmanaged_by_user_settings (self); - else - update_unmanaged_specs = TRUE; - - _notify (self, PROP_IFACE); - if (ip_ifname_changed) - _notify (self, PROP_IP_IFACE); - - /* Re-match available connections against the new interface name */ - nm_device_recheck_available_connections (self); - - /* Let any connections that use the new interface name have a chance - * to auto-activate on the device. - */ - nm_device_emit_recheck_auto_activate (self); - } - - if (priv->ndisc && pllink->inet6_token.id) { - if (nm_ndisc_set_iid (priv->ndisc, pllink->inet6_token)) - _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); - } - - /* Update carrier from link event if applicable. */ - if ( nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT) - && !nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) - nm_device_set_carrier (self, pllink->connected); - - device_update_interface_flags (self, pllink); - - klass->link_changed (self, pllink); - - /* Update DHCP, etc, if needed */ - if (ip_ifname_changed) - nm_device_update_dynamic_ip_setup (self); - - was_up = priv->up; - priv->up = NM_FLAGS_HAS (pllink->n_ifi_flags, IFF_UP); - - if ( pllink->initialized - && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) { - NMDeviceStateReason reason; - - nm_device_set_unmanaged_by_user_udev (self); - nm_device_set_unmanaged_by_user_conf (self); - - reason = NM_DEVICE_STATE_REASON_NOW_MANAGED; - - /* If the device is a external-down candidated but no longer has external - * down set, we must clear the platform-unmanaged flag with reason - * "assumed". */ - if ( nm_device_get_unmanaged_mask (self, NM_UNMANAGED_EXTERNAL_DOWN) - && !nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN)) { - /* actually, user-udev overwrites external-down. So we only assume the device, - * when it is a external-down candidate, which is not managed via udev. */ - if (!nm_device_get_unmanaged_mask (self, NM_UNMANAGED_USER_UDEV)) { - /* Ensure the assume check is queued before any queued state changes - * from the transition to UNAVAILABLE. - */ - nm_device_queue_recheck_assume (self); - reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; - } - } - - nm_device_set_unmanaged_by_flags (self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason); - } - - set_unmanaged_external_down (self, FALSE); - - device_recheck_slave_status (self, pllink); - - if (priv->up && (!was_up || seen_down)) { - /* the link was down and just came up. That happens for example, while changing MTU. - * We must restore IP configuration. */ - if (NM_IN_SET (priv->ip_state_4, NM_DEVICE_IP_STATE_CONF, - NM_DEVICE_IP_STATE_DONE)) { - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) - _LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again"); - } - - priv->linklocal6_dad_counter = 0; - if (NM_IN_SET (priv->ip_state_6, NM_DEVICE_IP_STATE_CONF, - NM_DEVICE_IP_STATE_DONE)) { - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again"); - } - } - - if (update_unmanaged_specs) - nm_device_set_unmanaged_by_user_settings (self); - - if ( got_hw_addr - && !priv->up - && nm_device_get_state (self) == NM_DEVICE_STATE_UNAVAILABLE) { - /* - * If the device is UNAVAILABLE, any previous try to - * bring it up probably has failed because of the - * invalid hardware address; try again. - */ - nm_device_bring_up (self, TRUE, NULL); - nm_device_queue_recheck_available (self, - NM_DEVICE_STATE_REASON_NONE, - NM_DEVICE_STATE_REASON_NONE); - } - - return G_SOURCE_REMOVE; +device_link_changed(NMDevice *self) +{ + NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + gboolean ip_ifname_changed = FALSE; + nm_auto_nmpobj const NMPObject *pllink_keep_alive = NULL; + const NMPlatformLink * pllink; + const char * str; + int ifindex; + gboolean was_up; + gboolean update_unmanaged_specs = FALSE; + gboolean got_hw_addr = FALSE, had_hw_addr; + gboolean seen_down = priv->device_link_changed_down; + + priv->device_link_changed_id = 0; + priv->device_link_changed_down = FALSE; + + ifindex = nm_device_get_ifindex(self); + if (ifindex <= 0) + return G_SOURCE_REMOVE; + pllink = nm_platform_link_get(nm_device_get_platform(self), ifindex); + if (!pllink) + return G_SOURCE_REMOVE; + + pllink_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(pllink)); + + str = nm_platform_link_get_udi(nm_device_get_platform(self), pllink->ifindex); + if (!nm_streq0(str, priv->udi)) { + g_free(priv->udi); + priv->udi = g_strdup(str); + _notify(self, PROP_UDI); + } + + str = nm_platform_link_get_path(nm_device_get_platform(self), pllink->ifindex); + if (!nm_streq0(str, priv->path)) { + g_free(priv->path); + priv->path = g_strdup(str); + _notify(self, PROP_PATH); + } + + if (!nm_streq0(pllink->driver, priv->driver)) { + g_free(priv->driver); + priv->driver = g_strdup(pllink->driver); + _notify(self, PROP_DRIVER); + } + + _set_mtu(self, pllink->mtu); + + if (ifindex == nm_device_get_ip_ifindex(self)) + _stats_update_counters_from_pllink(self, pllink); + + had_hw_addr = (priv->hw_addr != NULL); + nm_device_update_hw_address(self); + got_hw_addr = (!had_hw_addr && priv->hw_addr); + nm_device_update_permanent_hw_address(self, FALSE); + + if (pllink->name[0] && !nm_streq(priv->iface, pllink->name)) { + _LOGI(LOGD_DEVICE, + "interface index %d renamed iface from '%s' to '%s'", + priv->ifindex, + priv->iface, + pllink->name); + g_free(priv->iface_); + priv->iface_ = g_strdup(pllink->name); + + /* If the device has no explicit ip_iface, then changing iface changes ip_iface too. */ + ip_ifname_changed = !priv->ip_iface; + + if (nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) + nm_device_set_unmanaged_by_user_settings(self); + else + update_unmanaged_specs = TRUE; + + _notify(self, PROP_IFACE); + if (ip_ifname_changed) + _notify(self, PROP_IP_IFACE); + + /* Re-match available connections against the new interface name */ + nm_device_recheck_available_connections(self); + + /* Let any connections that use the new interface name have a chance + * to auto-activate on the device. + */ + nm_device_emit_recheck_auto_activate(self); + } + + if (priv->ndisc && pllink->inet6_token.id) { + if (nm_ndisc_set_iid(priv->ndisc, pllink->inet6_token)) + _LOGD(LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); + } + + /* Update carrier from link event if applicable. */ + if (nm_device_has_capability(self, NM_DEVICE_CAP_CARRIER_DETECT) + && !nm_device_has_capability(self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) + nm_device_set_carrier(self, pllink->connected); + + device_update_interface_flags(self, pllink); + + klass->link_changed(self, pllink); + + /* Update DHCP, etc, if needed */ + if (ip_ifname_changed) + nm_device_update_dynamic_ip_setup(self); + + was_up = priv->up; + priv->up = NM_FLAGS_HAS(pllink->n_ifi_flags, IFF_UP); + + if (pllink->initialized && nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { + NMDeviceStateReason reason; + + nm_device_set_unmanaged_by_user_udev(self); + nm_device_set_unmanaged_by_user_conf(self); + + reason = NM_DEVICE_STATE_REASON_NOW_MANAGED; + + /* If the device is a external-down candidated but no longer has external + * down set, we must clear the platform-unmanaged flag with reason + * "assumed". */ + if (nm_device_get_unmanaged_mask(self, NM_UNMANAGED_EXTERNAL_DOWN) + && !nm_device_get_unmanaged_flags(self, NM_UNMANAGED_EXTERNAL_DOWN)) { + /* actually, user-udev overwrites external-down. So we only assume the device, + * when it is a external-down candidate, which is not managed via udev. */ + if (!nm_device_get_unmanaged_mask(self, NM_UNMANAGED_USER_UDEV)) { + /* Ensure the assume check is queued before any queued state changes + * from the transition to UNAVAILABLE. + */ + nm_device_queue_recheck_assume(self); + reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; + } + } + + nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason); + } + + set_unmanaged_external_down(self, FALSE); + + device_recheck_slave_status(self, pllink); + + if (priv->up && (!was_up || seen_down)) { + /* the link was down and just came up. That happens for example, while changing MTU. + * We must restore IP configuration. */ + if (NM_IN_SET(priv->ip_state_4, NM_DEVICE_IP_STATE_CONF, NM_DEVICE_IP_STATE_DONE)) { + if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) + _LOGW(LOGD_IP4, "failed applying IP4 config after link comes up again"); + } + + priv->linklocal6_dad_counter = 0; + if (NM_IN_SET(priv->ip_state_6, NM_DEVICE_IP_STATE_CONF, NM_DEVICE_IP_STATE_DONE)) { + if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) + _LOGW(LOGD_IP6, "failed applying IP6 config after link comes up again"); + } + } + + if (update_unmanaged_specs) + nm_device_set_unmanaged_by_user_settings(self); + + if (got_hw_addr && !priv->up && nm_device_get_state(self) == NM_DEVICE_STATE_UNAVAILABLE) { + /* + * If the device is UNAVAILABLE, any previous try to + * bring it up probably has failed because of the + * invalid hardware address; try again. + */ + nm_device_bring_up(self, TRUE, NULL); + nm_device_queue_recheck_available(self, + NM_DEVICE_STATE_REASON_NONE, + NM_DEVICE_STATE_REASON_NONE); + } + + return G_SOURCE_REMOVE; } static gboolean -device_ip_link_changed (NMDevice *self) +device_ip_link_changed(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const NMPlatformLink *pllink; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const NMPlatformLink *pllink; + const char * ip_iface; + + priv->device_ip_link_changed_id = 0; + + if (priv->ip_ifindex <= 0) + return G_SOURCE_REMOVE; - priv->device_ip_link_changed_id = 0; + nm_assert(priv->ip_iface); - if (!priv->ip_ifindex) - return G_SOURCE_REMOVE; + pllink = nm_platform_link_get(nm_device_get_platform(self), priv->ip_ifindex); + if (!pllink) + return G_SOURCE_REMOVE; - pllink = nm_platform_link_get (nm_device_get_platform (self), priv->ip_ifindex); - if (!pllink) - return G_SOURCE_REMOVE; + if (priv->ifindex <= 0 && pllink->mtu) + _set_mtu(self, pllink->mtu); - if (priv->ifindex <= 0 && pllink->mtu) - _set_mtu (self, pllink->mtu); + _stats_update_counters_from_pllink(self, pllink); - _stats_update_counters_from_pllink (self, pllink); + ip_iface = pllink->name; - if (_ip_iface_update (self, pllink->name)) - nm_device_update_dynamic_ip_setup (self); + if (!ip_iface[0]) + return FALSE; - return G_SOURCE_REMOVE; + if (!nm_streq(priv->ip_iface, ip_iface)) { + _LOGI(LOGD_DEVICE, + "ip-ifname: interface index %d renamed ip_iface (%d) from '%s' to '%s'", + priv->ifindex, + priv->ip_ifindex, + priv->ip_iface, + ip_iface); + g_free(priv->ip_iface_); + priv->ip_iface_ = g_strdup(ip_iface); + _notify(self, PROP_IP_IFACE); + + nm_device_update_dynamic_ip_setup(self); + } + + return G_SOURCE_REMOVE; } static void -link_changed_cb (NMPlatform *platform, - int obj_type_i, - int ifindex, - NMPlatformLink *info, - int change_type_i, - NMDevice *self) -{ - const NMPlatformSignalChangeType change_type = change_type_i; - NMDevicePrivate *priv; - - if (change_type != NM_PLATFORM_SIGNAL_CHANGED) - return; - - priv = NM_DEVICE_GET_PRIVATE (self); - - if (ifindex == nm_device_get_ifindex (self)) { - if (!(info->n_ifi_flags & IFF_UP)) - priv->device_link_changed_down = TRUE; - if (!priv->device_link_changed_id) { - priv->device_link_changed_id = g_idle_add ((GSourceFunc) device_link_changed, self); - _LOGD (LOGD_DEVICE, "queued link change for ifindex %d", ifindex); - } - } else if (ifindex == nm_device_get_ip_ifindex (self)) { - if (!priv->device_ip_link_changed_id) { - priv->device_ip_link_changed_id = g_idle_add ((GSourceFunc) device_ip_link_changed, self); - _LOGD (LOGD_DEVICE, "queued link change for ip-ifindex %d", ifindex); - } - } +link_changed_cb(NMPlatform * platform, + int obj_type_i, + int ifindex, + NMPlatformLink *info, + int change_type_i, + NMDevice * self) +{ + const NMPlatformSignalChangeType change_type = change_type_i; + NMDevicePrivate * priv; + + if (change_type != NM_PLATFORM_SIGNAL_CHANGED) + return; + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (ifindex == nm_device_get_ifindex(self)) { + if (!(info->n_ifi_flags & IFF_UP)) + priv->device_link_changed_down = TRUE; + if (!priv->device_link_changed_id) { + priv->device_link_changed_id = g_idle_add((GSourceFunc) device_link_changed, self); + _LOGD(LOGD_DEVICE, "queued link change for ifindex %d", ifindex); + } + } else if (ifindex == nm_device_get_ip_ifindex(self)) { + if (!priv->device_ip_link_changed_id) { + priv->device_ip_link_changed_id = + g_idle_add((GSourceFunc) device_ip_link_changed, self); + _LOGD(LOGD_DEVICE, "queued link change for ip-ifindex %d", ifindex); + } + } } /*****************************************************************************/ static void -link_changed (NMDevice *self, const NMPlatformLink *pllink) +link_changed(NMDevice *self, const NMPlatformLink *pllink) { - /* stub implementation of virtual function to allow subclasses to chain up. */ + /* stub implementation of virtual function to allow subclasses to chain up. */ } static gboolean -link_type_compatible (NMDevice *self, - NMLinkType link_type, - gboolean *out_compatible, - GError **error) -{ - NMDeviceClass *klass; - NMLinkType device_type; - guint i = 0; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - klass = NM_DEVICE_GET_CLASS (self); - - if (!klass->link_types) { - NM_SET_OUT (out_compatible, FALSE); - g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, - "Device does not support platform links"); - return FALSE; - } - - device_type = self->_priv->link_type; - if (device_type > NM_LINK_TYPE_UNKNOWN && device_type != link_type) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, - "Needed link type 0x%x does not match the platform link type 0x%X", - device_type, link_type); - return FALSE; - } - - for (i = 0; klass->link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { - if (klass->link_types[i] == link_type) - return TRUE; - if (klass->link_types[i] == NM_LINK_TYPE_ANY) - return TRUE; - } - - NM_SET_OUT (out_compatible, FALSE); - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, - "Device does not support platform link type 0x%X", - link_type); - return FALSE; +link_type_compatible(NMDevice *self, NMLinkType link_type, gboolean *out_compatible, GError **error) +{ + NMDeviceClass *klass; + NMLinkType device_type; + guint i = 0; + + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + + klass = NM_DEVICE_GET_CLASS(self); + + if (!klass->link_types) { + NM_SET_OUT(out_compatible, FALSE); + g_set_error_literal(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "Device does not support platform links"); + return FALSE; + } + + device_type = self->_priv->link_type; + if (device_type > NM_LINK_TYPE_UNKNOWN && device_type != link_type) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "Needed link type 0x%x does not match the platform link type 0x%X", + device_type, + link_type); + return FALSE; + } + + for (i = 0; klass->link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + if (klass->link_types[i] == link_type) + return TRUE; + if (klass->link_types[i] == NM_LINK_TYPE_ANY) + return TRUE; + } + + NM_SET_OUT(out_compatible, FALSE); + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "Device does not support platform link type 0x%X", + link_type); + return FALSE; } /** @@ -4572,43 +5534,45 @@ link_type_compatible (NMDevice *self, * Returns: %TRUE on success, %FALSE on error */ 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) -{ - nm_auto_nmpobj const NMPObject *plink_keep_alive = NULL; - - nm_assert (!plink || NMP_OBJECT_GET_TYPE (NMP_OBJECT_UP_CAST (plink)) == NMP_OBJECT_TYPE_LINK); - - NM_SET_OUT (out_compatible, TRUE); - - if (plink) { - if (g_strcmp0 (nm_device_get_iface (self), plink->name) != 0) { - NM_SET_OUT (out_compatible, FALSE); - g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, - "Device interface name does not match platform link"); - return FALSE; - } - - if (!link_type_compatible (self, plink->type, out_compatible, error)) - return FALSE; - - plink_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink)); - } - - realize_start_setup (self, - plink, - assume_state_guess_assume, - assume_state_connection_uuid, - set_nm_owned, - unmanaged_user_explicit, - FALSE); - return TRUE; +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) +{ + nm_auto_nmpobj const NMPObject *plink_keep_alive = NULL; + + nm_assert(!plink || NMP_OBJECT_GET_TYPE(NMP_OBJECT_UP_CAST(plink)) == NMP_OBJECT_TYPE_LINK); + + NM_SET_OUT(out_compatible, TRUE); + + if (plink) { + if (!nm_streq0(nm_device_get_iface(self), plink->name)) { + NM_SET_OUT(out_compatible, FALSE); + g_set_error_literal(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "Device interface name does not match platform link"); + return FALSE; + } + + if (!link_type_compatible(self, plink->type, out_compatible, error)) + return FALSE; + + plink_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(plink)); + } + + realize_start_setup(self, + plink, + assume_state_guess_assume, + assume_state_connection_uuid, + set_nm_owned, + unmanaged_user_explicit, + FALSE); + return TRUE; } /** @@ -4624,277 +5588,267 @@ nm_device_realize_start (NMDevice *self, * Returns: %TRUE on success, %FALSE on error */ gboolean -nm_device_create_and_realize (NMDevice *self, - NMConnection *connection, - NMDevice *parent, - GError **error) -{ - nm_auto_nmpobj const NMPObject *plink_keep_alive = NULL; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const NMPlatformLink *plink; - gboolean nm_owned; - - /* Must be set before device is realized */ - plink = nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface); - nm_owned = !plink || !link_type_compatible (self, plink->type, NULL, NULL); - _LOGD (LOGD_DEVICE, "create (is %snm-owned)", nm_owned ? "" : "not "); - - plink = NULL; - /* Create any resources the device needs */ - if (NM_DEVICE_GET_CLASS (self)->create_and_realize) { - if (!NM_DEVICE_GET_CLASS (self)->create_and_realize (self, connection, parent, &plink, error)) - return FALSE; - if (plink) { - nm_assert (NMP_OBJECT_GET_TYPE (NMP_OBJECT_UP_CAST (plink)) == NMP_OBJECT_TYPE_LINK); - plink_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink)); - } - } - - priv->nm_owned = nm_owned; - - realize_start_setup (self, - plink, - FALSE, /* assume_state_guess_assume */ - NULL, /* assume_state_connection_uuid */ - FALSE, NM_UNMAN_FLAG_OP_FORGET, - TRUE); - nm_device_realize_finish (self, plink); - - if (nm_device_get_managed (self, FALSE)) { - nm_device_state_changed (self, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_NOW_MANAGED); - } - return TRUE; +nm_device_create_and_realize(NMDevice * self, + NMConnection *connection, + NMDevice * parent, + GError ** error) +{ + nm_auto_nmpobj const NMPObject *plink_keep_alive = NULL; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const NMPlatformLink * plink; + gboolean nm_owned; + + /* Must be set before device is realized */ + plink = nm_platform_link_get_by_ifname(nm_device_get_platform(self), priv->iface); + nm_owned = !plink || !link_type_compatible(self, plink->type, NULL, NULL); + _LOGD(LOGD_DEVICE, "create (is %snm-owned)", nm_owned ? "" : "not "); + + plink = NULL; + /* Create any resources the device needs */ + if (NM_DEVICE_GET_CLASS(self)->create_and_realize) { + if (!NM_DEVICE_GET_CLASS(self)->create_and_realize(self, connection, parent, &plink, error)) + return FALSE; + if (plink) { + nm_assert(NMP_OBJECT_GET_TYPE(NMP_OBJECT_UP_CAST(plink)) == NMP_OBJECT_TYPE_LINK); + plink_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(plink)); + } + } + + priv->nm_owned = nm_owned; + + realize_start_setup(self, + plink, + FALSE, /* assume_state_guess_assume */ + NULL, /* assume_state_connection_uuid */ + FALSE, + NM_UNMAN_FLAG_OP_FORGET, + TRUE); + nm_device_realize_finish(self, plink); + + if (nm_device_get_managed(self, FALSE)) { + nm_device_state_changed(self, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_NOW_MANAGED); + } + return TRUE; } static gboolean -can_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink) +can_update_from_platform_link(NMDevice *self, const NMPlatformLink *plink) { - return TRUE; + return TRUE; } void -nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const char *str; - int ifindex; - guint32 mtu; - - if (!NM_DEVICE_GET_CLASS (self)->can_update_from_platform_link (self, plink)) - return; - - g_return_if_fail (plink == NULL || link_type_compatible (self, plink->type, NULL, NULL)); - - str = plink ? nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex) : NULL; - if (g_strcmp0 (str, priv->udi)) { - g_free (priv->udi); - priv->udi = g_strdup (str); - _notify (self, PROP_UDI); - } - - str = plink ? nm_platform_link_get_path (nm_device_get_platform (self), plink->ifindex) : NULL; - if (g_strcmp0 (str, priv->path)) { - g_free (priv->path); - priv->path = g_strdup (str); - _notify (self, PROP_PATH); - } - - str = plink ? plink->name : NULL; - if (str && g_strcmp0 (str, priv->iface)) { - g_free (priv->iface); - priv->iface = g_strdup (str); - _notify (self, PROP_IFACE); - } - - str = plink ? plink->driver : NULL; - if (g_strcmp0 (str, priv->driver) != 0) { - g_free (priv->driver); - priv->driver = g_strdup (str); - _notify (self, PROP_DRIVER); - } - - if (plink) { - priv->up = NM_FLAGS_HAS (plink->n_ifi_flags, IFF_UP); - if (plink->ifindex == nm_device_get_ip_ifindex (self)) - _stats_update_counters_from_pllink (self, plink); - } else { - priv->up = FALSE; - } - - mtu = plink ? plink->mtu : 0; - _set_mtu (self, mtu); - - ifindex = plink ? plink->ifindex : 0; - if (priv->ifindex != ifindex) { - priv->ifindex = ifindex; - _notify (self, PROP_IFINDEX); - NM_DEVICE_GET_CLASS (self)->link_changed (self, plink); - } - - device_update_interface_flags (self, plink); +nm_device_update_from_platform_link(NMDevice *self, const NMPlatformLink *plink) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const char * str; + gboolean ifindex_changed; + guint32 mtu; + + if (!NM_DEVICE_GET_CLASS(self)->can_update_from_platform_link(self, plink)) + return; + + g_return_if_fail(plink == NULL || link_type_compatible(self, plink->type, NULL, NULL)); + + str = plink ? nm_platform_link_get_udi(nm_device_get_platform(self), plink->ifindex) : NULL; + if (!nm_streq0(str, priv->udi)) { + g_free(priv->udi); + priv->udi = g_strdup(str); + _notify(self, PROP_UDI); + } + + str = plink ? nm_platform_link_get_path(nm_device_get_platform(self), plink->ifindex) : NULL; + if (!nm_streq0(str, priv->path)) { + g_free(priv->path); + priv->path = g_strdup(str); + _notify(self, PROP_PATH); + } + + if (plink && !nm_str_is_empty(plink->name) && nm_utils_strdup_reset(&priv->iface_, plink->name)) + _notify(self, PROP_IFACE); + + str = plink ? plink->driver : NULL; + if (!nm_streq0(str, priv->driver)) { + g_free(priv->driver); + priv->driver = g_strdup(str); + _notify(self, PROP_DRIVER); + } + + if (plink) { + priv->up = NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP); + if (plink->ifindex == nm_device_get_ip_ifindex(self)) + _stats_update_counters_from_pllink(self, plink); + } else { + priv->up = FALSE; + } + + mtu = plink ? plink->mtu : 0; + _set_mtu(self, mtu); + + ifindex_changed = _set_ifindex(self, plink ? plink->ifindex : 0, FALSE); + + if (ifindex_changed) + NM_DEVICE_GET_CLASS(self)->link_changed(self, plink); + + device_update_interface_flags(self, plink); } /*****************************************************************************/ static void -sriov_op_start (NMDevice *self, SriovOp *op) +sriov_op_start(NMDevice *self, SriovOp *op) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert (!priv->sriov.pending); + nm_assert(!priv->sriov.pending); - op->cancellable = g_cancellable_new (); - op->device = g_object_ref (self); - priv->sriov.pending = op; + op->cancellable = g_cancellable_new(); + op->device = g_object_ref(self); + priv->sriov.pending = op; - nm_platform_link_set_sriov_params_async (nm_device_get_platform (self), - priv->ifindex, - op->num_vfs, - op->autoprobe, - sriov_op_cb, - op, - op->cancellable); + nm_platform_link_set_sriov_params_async(nm_device_get_platform(self), + priv->ifindex, + op->num_vfs, + op->autoprobe, + sriov_op_cb, + op, + op->cancellable); } static void -sriov_op_cb (GError *error, gpointer user_data) +sriov_op_cb(GError *error, gpointer user_data) { - SriovOp *op = user_data; - gs_unref_object NMDevice *self = op->device; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + SriovOp * op = user_data; + gs_unref_object NMDevice *self = op->device; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert (op == priv->sriov.pending); + nm_assert(op == priv->sriov.pending); - g_clear_object (&op->cancellable); + g_clear_object(&op->cancellable); - if (op->callback) - op->callback (error, op->callback_data); + if (op->callback) + op->callback(error, op->callback_data); - priv->sriov.pending = NULL; - nm_g_slice_free (op); + priv->sriov.pending = NULL; + nm_g_slice_free(op); - if (priv->sriov.next) { - sriov_op_start (self, - g_steal_pointer (&priv->sriov.next)); - } + if (priv->sriov.next) { + sriov_op_start(self, g_steal_pointer(&priv->sriov.next)); + } } static void -sriov_op_queue_op (NMDevice *self, - SriovOp *op) +sriov_op_queue_op(NMDevice *self, SriovOp *op) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->sriov.next) { - SriovOp *op_next = g_steal_pointer (&priv->sriov.next); + if (priv->sriov.next) { + SriovOp *op_next = g_steal_pointer(&priv->sriov.next); - priv->sriov.next = op; + priv->sriov.next = op; - /* Cancel the next operation immediately */ - if (op_next->callback) { - gs_free_error GError *error = NULL; + /* Cancel the next operation immediately */ + if (op_next->callback) { + gs_free_error GError *error = NULL; - nm_utils_error_set_cancelled (&error, FALSE, NULL); - op_next->callback (error, op_next->callback_data); - } + nm_utils_error_set_cancelled(&error, FALSE, NULL); + op_next->callback(error, op_next->callback_data); + } - nm_g_slice_free (op_next); - return; - } + nm_g_slice_free(op_next); + return; + } - if (priv->sriov.pending) { - priv->sriov.next = op; - g_cancellable_cancel (priv->sriov.pending->cancellable); - return; - } + if (priv->sriov.pending) { + priv->sriov.next = op; + g_cancellable_cancel(priv->sriov.pending->cancellable); + return; + } - if (op) - sriov_op_start (self, op); + if (op) + sriov_op_start(self, op); } static void -sriov_op_queue (NMDevice *self, - guint num_vfs, - NMTernary autoprobe, - NMPlatformAsyncCallback callback, - gpointer callback_data) -{ - SriovOp *op; - - /* We usually never want to cancel an async write operation, unless it's superseded - * by a newer operation (that resets the state). That is, because we need to ensure - * that we never end up doing two concurrent writes (since we write on a background - * thread, that would be unordered/racy). - * Of course, since we queue requests only per-device, when devices get renamed we - * might end up writing the same sysctl concurrently still. But that's really - * unlikely, and don't rename after udev completes! - * - * The "next" operation is not yet even started. It can be replaced/canceled right away - * when a newer request comes. - * The "pending" operation is currently ongoing, and we may cancel it if - * we have a follow-up operation (queued in "next"). Unless we have a such - * a newer request, we cannot cancel it! - * - * FIXME(shutdown): However, during shutdown we don't have a follow-up write request to cancel - * this operation and we have to give it at least some time to complete. The solution is that - * we register a way to abort the last call during shutdown, and after NM_SHUTDOWN_TIMEOUT_MS - * grace period we pull the plug and cancel it. */ - - op = g_slice_new (SriovOp); - *op = (SriovOp) { - .num_vfs = num_vfs, - .autoprobe = autoprobe, - .callback = callback, - .callback_data = callback_data, - }; - sriov_op_queue_op (self, op); +sriov_op_queue(NMDevice * self, + guint num_vfs, + NMTernary autoprobe, + NMPlatformAsyncCallback callback, + gpointer callback_data) +{ + SriovOp *op; + + /* We usually never want to cancel an async write operation, unless it's superseded + * by a newer operation (that resets the state). That is, because we need to ensure + * that we never end up doing two concurrent writes (since we write on a background + * thread, that would be unordered/racy). + * Of course, since we queue requests only per-device, when devices get renamed we + * might end up writing the same sysctl concurrently still. But that's really + * unlikely, and don't rename after udev completes! + * + * The "next" operation is not yet even started. It can be replaced/canceled right away + * when a newer request comes. + * The "pending" operation is currently ongoing, and we may cancel it if + * we have a follow-up operation (queued in "next"). Unless we have a such + * a newer request, we cannot cancel it! + * + * FIXME(shutdown): However, during shutdown we don't have a follow-up write request to cancel + * this operation and we have to give it at least some time to complete. The solution is that + * we register a way to abort the last call during shutdown, and after NM_SHUTDOWN_TIMEOUT_MS + * grace period we pull the plug and cancel it. */ + + op = g_slice_new(SriovOp); + *op = (SriovOp){ + .num_vfs = num_vfs, + .autoprobe = autoprobe, + .callback = callback, + .callback_data = callback_data, + }; + sriov_op_queue_op(self, op); } static void -device_init_static_sriov_num_vfs (NMDevice *self) +device_init_static_sriov_num_vfs(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gs_free char *value = NULL; - int num_vfs; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gs_free char * value = NULL; + int num_vfs; - if ( priv->ifindex > 0 - && nm_device_has_capability (self, NM_DEVICE_CAP_SRIOV)) { - value = nm_config_data_get_device_config (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS, - self, - NULL); - num_vfs = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, -1); - if (num_vfs >= 0) - sriov_op_queue (self, num_vfs, NM_TERNARY_DEFAULT, NULL, NULL); - } + if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV)) { + value = nm_config_data_get_device_config(NM_CONFIG_GET_DATA, + NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS, + self, + NULL); + num_vfs = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXINT32, -1); + if (num_vfs >= 0) + sriov_op_queue(self, num_vfs, NM_TERNARY_DEFAULT, NULL, NULL); + } } static void -config_changed (NMConfig *config, - NMConfigData *config_data, - NMConfigChangeFlags changes, - NMConfigData *old_data, - NMDevice *self) +config_changed(NMConfig * config, + NMConfigData * config_data, + NMConfigChangeFlags changes, + NMConfigData * old_data, + NMDevice * self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if ( priv->state <= NM_DEVICE_STATE_DISCONNECTED - || priv->state > NM_DEVICE_STATE_ACTIVATED) { - priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self); - if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) - device_init_static_sriov_num_vfs (self); - } + if (priv->state <= NM_DEVICE_STATE_DISCONNECTED || priv->state > NM_DEVICE_STATE_ACTIVATED) { + priv->ignore_carrier = nm_config_data_get_ignore_carrier(config_data, self); + if (NM_FLAGS_HAS(changes, NM_CONFIG_CHANGE_VALUES)) + device_init_static_sriov_num_vfs(self); + } } static void -realize_start_notify (NMDevice *self, - const NMPlatformLink *pllink) +realize_start_notify(NMDevice *self, const NMPlatformLink *pllink) { - /* the default implementation of realize_start_notify() just calls - * link_changed() -- which by default does nothing. */ - NM_DEVICE_GET_CLASS (self)->link_changed (self, pllink); + /* the default implementation of realize_start_notify() just calls + * link_changed() -- which by default does nothing. */ + NM_DEVICE_GET_CLASS(self)->link_changed(self, pllink); } /** @@ -4916,158 +5870,150 @@ realize_start_notify (NMDevice *self, * stuff). */ 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, - gboolean force_platform_init) -{ - NMDevicePrivate *priv; - NMDeviceClass *klass; - NMPlatform *platform; - static guint32 id = 0; - NMDeviceCapabilities capabilities = 0; - NMConfig *config; - guint real_rate; - gboolean unmanaged; - - /* plink is a NMPlatformLink type, however, we require it to come from the platform - * cache (where else would it come from?). */ - nm_assert (!plink || NMP_OBJECT_GET_TYPE (NMP_OBJECT_UP_CAST (plink)) == NMP_OBJECT_TYPE_LINK); - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE (self); - - /* The device should not be realized */ - g_return_if_fail (!priv->real); - g_return_if_fail (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)); - g_return_if_fail (priv->ip_ifindex <= 0); - g_return_if_fail (priv->ip_iface == NULL); - g_return_if_fail (!priv->queued_ip_config_id_4); - g_return_if_fail (!priv->queued_ip_config_id_6); - - _LOGD (LOGD_DEVICE, "start setup of %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), plink ? plink->ifindex : 0); - - klass = NM_DEVICE_GET_CLASS (self); - platform = nm_device_get_platform (self); - - /* Balanced by a thaw in nm_device_realize_finish() */ - g_object_freeze_notify (G_OBJECT (self)); - - priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; - priv->mtu_initial = 0; - priv->ip6_mtu_initial = 0; - priv->ip6_mtu = 0; - _set_mtu (self, 0); - - _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) - nm_device_update_from_platform_link (self, plink); - - if (priv->ifindex > 0) { - priv->physical_port_id = nm_platform_link_get_physical_port_id (platform, priv->ifindex); - _notify (self, PROP_PHYSICAL_PORT_ID); - - priv->dev_id = nm_platform_link_get_dev_id (platform, priv->ifindex); - - if (nm_platform_link_is_software (platform, priv->ifindex)) - capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; - - _set_mtu (self, - nm_platform_link_get_mtu (platform, - priv->ifindex)); - - nm_platform_link_get_driver_info (platform, - priv->ifindex, - NULL, - &priv->driver_version, - &priv->firmware_version); - if (priv->driver_version) - _notify (self, PROP_DRIVER_VERSION); - if (priv->firmware_version) - _notify (self, PROP_FIRMWARE_VERSION); - - if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) - priv->ipv6ll_handle = nm_platform_link_get_user_ipv6ll_enabled (platform, priv->ifindex); - - if (nm_platform_link_supports_sriov (platform, priv->ifindex)) - capabilities |= NM_DEVICE_CAP_SRIOV; - } - - if (klass->get_generic_capabilities) - capabilities |= klass->get_generic_capabilities (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++); - _notify (self, PROP_UDI); - } - - nm_device_update_hw_address (self); - nm_device_update_initial_hw_address (self); - nm_device_update_permanent_hw_address (self, FALSE); - - /* Note: initial hardware address must be read before calling get_ignore_carrier() */ - config = nm_config_get (); - priv->ignore_carrier = nm_config_data_get_ignore_carrier (nm_config_get_data (config), self); - if (!priv->config_changed_id) { - priv->config_changed_id = g_signal_connect (config, - NM_CONFIG_SIGNAL_CONFIG_CHANGED, - G_CALLBACK (config_changed), - self); - } +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, + gboolean force_platform_init) +{ + NMDevicePrivate * priv; + NMDeviceClass * klass; + NMPlatform * platform; + static guint32 id = 0; + NMDeviceCapabilities capabilities = 0; + NMConfig * config; + guint real_rate; + gboolean unmanaged; + + /* plink is a NMPlatformLink type, however, we require it to come from the platform + * cache (where else would it come from?). */ + nm_assert(!plink || NMP_OBJECT_GET_TYPE(NMP_OBJECT_UP_CAST(plink)) == NMP_OBJECT_TYPE_LINK); + + g_return_if_fail(NM_IS_DEVICE(self)); + + priv = NM_DEVICE_GET_PRIVATE(self); + + /* The device should not be realized */ + g_return_if_fail(!priv->real); + g_return_if_fail(nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)); + g_return_if_fail(priv->ip_ifindex <= 0); + g_return_if_fail(priv->ip_iface == NULL); + g_return_if_fail(!priv->queued_ip_config_id_4); + g_return_if_fail(!priv->queued_ip_config_id_6); + + _LOGD(LOGD_DEVICE, + "start setup of %s, kernel ifindex %d", + G_OBJECT_TYPE_NAME(self), + plink ? plink->ifindex : 0); + + klass = NM_DEVICE_GET_CLASS(self); + platform = nm_device_get_platform(self); + + /* Balanced by a thaw in nm_device_realize_finish() */ + g_object_freeze_notify(G_OBJECT(self)); + + priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; + priv->mtu_initial = 0; + priv->ip6_mtu_initial = 0; + priv->ip6_mtu = 0; + _set_mtu(self, 0); + + _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) + nm_device_update_from_platform_link(self, plink); + + if (priv->ifindex > 0) { + priv->physical_port_id = nm_platform_link_get_physical_port_id(platform, priv->ifindex); + _notify(self, PROP_PHYSICAL_PORT_ID); + + priv->dev_id = nm_platform_link_get_dev_id(platform, priv->ifindex); + + if (nm_platform_link_is_software(platform, priv->ifindex)) + capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; + + _set_mtu(self, nm_platform_link_get_mtu(platform, priv->ifindex)); + + nm_platform_link_get_driver_info(platform, + priv->ifindex, + NULL, + &priv->driver_version, + &priv->firmware_version); + if (priv->driver_version) + _notify(self, PROP_DRIVER_VERSION); + if (priv->firmware_version) + _notify(self, PROP_FIRMWARE_VERSION); + + if (nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) + priv->ipv6ll_handle = nm_platform_link_get_user_ipv6ll_enabled(platform, priv->ifindex); + + if (nm_platform_link_supports_sriov(platform, priv->ifindex)) + capabilities |= NM_DEVICE_CAP_SRIOV; + } + + if (klass->get_generic_capabilities) + capabilities |= klass->get_generic_capabilities(self); + + _add_capabilities(self, capabilities); - nm_device_set_carrier_from_platform (self); + 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"); + } - nm_assert (!priv->stats.timeout_id); - real_rate = _stats_refresh_rate_real (priv->stats.refresh_rate_ms); - if (real_rate) - priv->stats.timeout_id = g_timeout_add (real_rate, _stats_timeout_cb, self); + if (!priv->udi) { + /* Use a placeholder UDI until we get a real one */ + priv->udi = g_strdup_printf("/virtual/device/placeholder/%d", id++); + _notify(self, PROP_UDI); + } - klass->realize_start_notify (self, plink); + nm_device_update_hw_address(self); + nm_device_update_initial_hw_address(self); + nm_device_update_permanent_hw_address(self, FALSE); - nm_assert (!nm_device_get_unmanaged_mask (self, NM_UNMANAGED_USER_EXPLICIT)); - nm_device_set_unmanaged_flags (self, - NM_UNMANAGED_USER_EXPLICIT, - unmanaged_user_explicit); + /* Note: initial hardware address must be read before calling get_ignore_carrier() */ + config = nm_config_get(); + priv->ignore_carrier = nm_config_data_get_ignore_carrier(nm_config_get_data(config), self); + if (!priv->config_changed_id) { + priv->config_changed_id = g_signal_connect(config, + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK(config_changed), + self); + } - /* Do not manage externally created software devices until they are IFF_UP - * or have IP addressing */ - nm_device_set_unmanaged_flags (self, - NM_UNMANAGED_EXTERNAL_DOWN, - is_unmanaged_external_down (self, TRUE)); + nm_device_set_carrier_from_platform(self); - /* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag. - * Later we might want to manage 'lo' too. Currently that doesn't work because - * NetworkManager might down the interface or remove the 127.0.0.1 address. */ - nm_device_set_unmanaged_flags (self, - NM_UNMANAGED_BY_TYPE, - is_loopback (self)); - - nm_device_set_unmanaged_by_user_udev (self); - nm_device_set_unmanaged_by_user_conf (self); + nm_assert(!priv->stats.timeout_id); + real_rate = _stats_refresh_rate_real(priv->stats.refresh_rate_ms); + if (real_rate) + priv->stats.timeout_id = g_timeout_add(real_rate, _stats_timeout_cb, self); - unmanaged = plink - && !plink->initialized - && !force_platform_init; - - nm_device_set_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT, - unmanaged); + klass->realize_start_notify(self, plink); + + nm_assert(!nm_device_get_unmanaged_mask(self, NM_UNMANAGED_USER_EXPLICIT)); + nm_device_set_unmanaged_flags(self, NM_UNMANAGED_USER_EXPLICIT, unmanaged_user_explicit); + + /* Do not manage externally created software devices until they are IFF_UP + * or have IP addressing */ + nm_device_set_unmanaged_flags(self, + NM_UNMANAGED_EXTERNAL_DOWN, + is_unmanaged_external_down(self, TRUE)); + + /* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag. + * Later we might want to manage 'lo' too. Currently, that doesn't work because + * NetworkManager might down the interface or remove the 127.0.0.1 address. */ + nm_device_set_unmanaged_flags(self, NM_UNMANAGED_BY_TYPE, is_loopback(self)); + + nm_device_set_unmanaged_by_user_udev(self); + nm_device_set_unmanaged_by_user_conf(self); + + unmanaged = plink && !plink->initialized && !force_platform_init; + + nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, unmanaged); } /** @@ -5080,70 +6026,69 @@ realize_start_setup (NMDevice *self, * is ready for network connectivity. */ void -nm_device_realize_finish (NMDevice *self, const NMPlatformLink *plink) +nm_device_realize_finish(NMDevice *self, const NMPlatformLink *plink) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (!plink || link_type_compatible (self, plink->type, NULL, NULL)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(!plink || link_type_compatible(self, plink->type, NULL, NULL)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - g_return_if_fail (!priv->real); + g_return_if_fail(!priv->real); - if (plink) - device_recheck_slave_status (self, plink); + if (plink) + device_recheck_slave_status(self, plink); - priv->update_ip_config_completed_v4 = FALSE; - priv->update_ip_config_completed_v6 = FALSE; + priv->update_ip_config_completed_v4 = FALSE; + priv->update_ip_config_completed_v6 = FALSE; - priv->real = TRUE; - _notify (self, PROP_REAL); + priv->real = TRUE; + _notify(self, PROP_REAL); - nm_device_recheck_available_connections (self); + nm_device_recheck_available_connections(self); - /* Balanced by a freeze in realize_start_setup(). */ - g_object_thaw_notify (G_OBJECT (self)); + /* Balanced by a freeze in realize_start_setup(). */ + g_object_thaw_notify(G_OBJECT(self)); } static void -unrealize_notify (NMDevice *self) +unrealize_notify(NMDevice *self) { - /* Stub implementation for unrealize_notify(). It does nothing, - * but allows derived classes to uniformly invoke the parent - * implementation. */ + /* Stub implementation for unrealize_notify(). It does nothing, + * but allows derived classes to uniformly invoke the parent + * implementation. */ } static gboolean -available_connections_check_delete_unrealized_on_idle (gpointer user_data) +available_connections_check_delete_unrealized_on_idle(gpointer user_data) { - NMDevice *self = user_data; - NMDevicePrivate *priv; + NMDevice * self = user_data; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); + g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - priv->check_delete_unrealized_id = 0; + priv->check_delete_unrealized_id = 0; - if ( g_hash_table_size (priv->available_connections) == 0 - && !nm_device_is_real (self)) - g_signal_emit (self, signals[REMOVED], 0); + if (g_hash_table_size(priv->available_connections) == 0 && !nm_device_is_real(self)) + g_signal_emit(self, signals[REMOVED], 0); - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; } static void -available_connections_check_delete_unrealized (NMDevice *self) +available_connections_check_delete_unrealized(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - /* always rescheadule the remove signal. */ - nm_clear_g_source (&priv->check_delete_unrealized_id); + /* always rescheadule the remove signal. */ + nm_clear_g_source(&priv->check_delete_unrealized_id); - if ( g_hash_table_size (priv->available_connections) == 0 - && !nm_device_is_real (self)) - priv->check_delete_unrealized_id = g_idle_add (available_connections_check_delete_unrealized_on_idle, self); + if (g_hash_table_size(priv->available_connections) == 0 && !nm_device_is_real(self)) + priv->check_delete_unrealized_id = + g_idle_add(available_connections_check_delete_unrealized_on_idle, self); } /** @@ -5158,145 +6103,137 @@ available_connections_check_delete_unrealized (NMDevice *self) * Returns: %TRUE on success, %FALSE on error */ gboolean -nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) -{ - NMDevicePrivate *priv; - int ifindex; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - if (!nm_device_is_software (self) || !nm_device_is_real (self)) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_SOFTWARE, - "This device is not a software device or is not realized"); - return FALSE; - } - - priv = NM_DEVICE_GET_PRIVATE (self); - - g_return_val_if_fail (priv->iface != NULL, FALSE); - g_return_val_if_fail (priv->real, FALSE); - - ifindex = nm_device_get_ifindex (self); - - _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)) - return FALSE; - } else if (ifindex > 0) { - nm_platform_link_delete (nm_device_get_platform (self), ifindex); - } - } - - nm_clear_g_source (&priv->queued_ip_config_id_4); - nm_clear_g_source (&priv->queued_ip_config_id_6); - - g_object_freeze_notify (G_OBJECT (self)); - NM_DEVICE_GET_CLASS (self)->unrealize_notify (self); - - _parent_set_ifindex (self, 0, FALSE); - - if (priv->ifindex > 0) { - priv->ifindex = 0; - _notify (self, PROP_IFINDEX); - } - priv->ip_ifindex = 0; - if (nm_clear_g_free (&priv->ip_iface)) - _notify (self, PROP_IP_IFACE); - - _set_mtu (self, 0); - - if (priv->driver_version) { - nm_clear_g_free (&priv->driver_version); - _notify (self, PROP_DRIVER_VERSION); - } - if (priv->firmware_version) { - nm_clear_g_free (&priv->firmware_version); - _notify (self, PROP_FIRMWARE_VERSION); - } - if (priv->udi) { - nm_clear_g_free (&priv->udi); - _notify (self, PROP_UDI); - } - if (priv->path) { - nm_clear_g_free (&priv->path); - _notify (self, PROP_PATH); - } - if (priv->physical_port_id) { - nm_clear_g_free (&priv->physical_port_id); - _notify (self, PROP_PHYSICAL_PORT_ID); - } - - nm_clear_g_source (&priv->stats.timeout_id); - _stats_update_counters (self, 0, 0); - - priv->hw_addr_len_ = 0; - if (nm_clear_g_free (&priv->hw_addr)) - _notify (self, PROP_HW_ADDRESS); - priv->hw_addr_type = HW_ADDR_TYPE_UNSET; - if (nm_clear_g_free (&priv->hw_addr_perm)) - _notify (self, PROP_PERM_HW_ADDRESS); - nm_clear_g_free (&priv->hw_addr_initial); - - priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; - if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) - priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); - _notify (self, PROP_CAPABILITIES); - - nm_clear_g_signal_handler (nm_config_get (), &priv->config_changed_id); - - priv->real = FALSE; - _notify (self, PROP_REAL); - - g_object_thaw_notify (G_OBJECT (self)); - - nm_device_set_unmanaged_flags (self, - NM_UNMANAGED_PLATFORM_INIT, - TRUE); - - nm_device_set_unmanaged_flags (self, - NM_UNMANAGED_PARENT | - NM_UNMANAGED_BY_TYPE | - NM_UNMANAGED_USER_UDEV | - NM_UNMANAGED_USER_EXPLICIT | - NM_UNMANAGED_EXTERNAL_DOWN | - NM_UNMANAGED_IS_SLAVE, - NM_UNMAN_FLAG_OP_FORGET); - - nm_device_state_changed (self, - NM_DEVICE_STATE_UNMANAGED, - remove_resources ? - NM_DEVICE_STATE_REASON_USER_REQUESTED : NM_DEVICE_STATE_REASON_NOW_UNMANAGED); - - /* Garbage-collect unneeded unrealized devices. */ - nm_device_recheck_available_connections (self); - - return TRUE; +nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error) +{ + NMDevicePrivate *priv; + int ifindex; + + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + + if (!nm_device_is_software(self) || !nm_device_is_real(self)) { + g_set_error_literal(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_SOFTWARE, + "This device is not a software device or is not realized"); + return FALSE; + } + + priv = NM_DEVICE_GET_PRIVATE(self); + + g_return_val_if_fail(priv->iface != NULL, FALSE); + g_return_val_if_fail(priv->real, FALSE); + + ifindex = nm_device_get_ifindex(self); + + _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)) + return FALSE; + } else if (ifindex > 0) { + nm_platform_link_delete(nm_device_get_platform(self), ifindex); + } + } + + nm_clear_g_source(&priv->queued_ip_config_id_4); + nm_clear_g_source(&priv->queued_ip_config_id_6); + + g_object_freeze_notify(G_OBJECT(self)); + NM_DEVICE_GET_CLASS(self)->unrealize_notify(self); + + _parent_set_ifindex(self, 0, FALSE); + + _set_ifindex(self, 0, FALSE); + _set_ifindex(self, 0, TRUE); + if (nm_clear_g_free(&priv->ip_iface_)) + _notify(self, PROP_IP_IFACE); + + _set_mtu(self, 0); + + if (priv->driver_version) { + nm_clear_g_free(&priv->driver_version); + _notify(self, PROP_DRIVER_VERSION); + } + if (priv->firmware_version) { + nm_clear_g_free(&priv->firmware_version); + _notify(self, PROP_FIRMWARE_VERSION); + } + if (priv->udi) { + nm_clear_g_free(&priv->udi); + _notify(self, PROP_UDI); + } + if (priv->path) { + nm_clear_g_free(&priv->path); + _notify(self, PROP_PATH); + } + if (priv->physical_port_id) { + nm_clear_g_free(&priv->physical_port_id); + _notify(self, PROP_PHYSICAL_PORT_ID); + } + + nm_clear_g_source(&priv->stats.timeout_id); + _stats_update_counters(self, 0, 0); + + priv->hw_addr_len_ = 0; + if (nm_clear_g_free(&priv->hw_addr)) + _notify(self, PROP_HW_ADDRESS); + priv->hw_addr_type = HW_ADDR_TYPE_UNSET; + if (nm_clear_g_free(&priv->hw_addr_perm)) + _notify(self, PROP_PERM_HW_ADDRESS); + nm_clear_g_free(&priv->hw_addr_initial); + + priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; + if (NM_DEVICE_GET_CLASS(self)->get_generic_capabilities) + priv->capabilities |= NM_DEVICE_GET_CLASS(self)->get_generic_capabilities(self); + _notify(self, PROP_CAPABILITIES); + + nm_clear_g_signal_handler(nm_config_get(), &priv->config_changed_id); + + priv->real = FALSE; + _notify(self, PROP_REAL); + + g_object_thaw_notify(G_OBJECT(self)); + + nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE); + + nm_device_set_unmanaged_flags(self, + NM_UNMANAGED_PARENT | NM_UNMANAGED_BY_TYPE + | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT + | NM_UNMANAGED_EXTERNAL_DOWN | NM_UNMANAGED_IS_SLAVE, + NM_UNMAN_FLAG_OP_FORGET); + + nm_device_state_changed(self, + NM_DEVICE_STATE_UNMANAGED, + remove_resources ? NM_DEVICE_STATE_REASON_USER_REQUESTED + : NM_DEVICE_STATE_REASON_NOW_UNMANAGED); + + /* Garbage-collect unneeded unrealized devices. */ + nm_device_recheck_available_connections(self); + + return TRUE; } void -nm_device_notify_availability_maybe_changed (NMDevice *self) +nm_device_notify_availability_maybe_changed(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->state != NM_DEVICE_STATE_DISCONNECTED) - return; + if (priv->state != NM_DEVICE_STATE_DISCONNECTED) + return; - /* A device could have stayed disconnected because it would - * want to register with a network server that now become - * available. */ - nm_device_recheck_available_connections (self); - if (g_hash_table_size (priv->available_connections) > 0) - nm_device_emit_recheck_auto_activate (self); + /* A device could have stayed disconnected because it would + * want to register with a network server that now become + * available. */ + nm_device_recheck_available_connections(self); + if (g_hash_table_size(priv->available_connections) > 0) + nm_device_emit_recheck_auto_activate(self); } /** @@ -5314,79 +6251,77 @@ nm_device_notify_availability_maybe_changed (NMDevice *self) * %FALSE if not */ gboolean -nm_device_owns_iface (NMDevice *self, const char *iface) +nm_device_owns_iface(NMDevice *self, const char *iface) { - if (NM_DEVICE_GET_CLASS (self)->owns_iface) - return NM_DEVICE_GET_CLASS (self)->owns_iface (self, iface); - return FALSE; + if (NM_DEVICE_GET_CLASS(self)->owns_iface) + return NM_DEVICE_GET_CLASS(self)->owns_iface(self, iface); + return FALSE; } NMConnection * -nm_device_new_default_connection (NMDevice *self) +nm_device_new_default_connection(NMDevice *self) { - NMConnection *connection; - GError *error = NULL; + NMConnection *connection; + GError * error = NULL; - if (!NM_DEVICE_GET_CLASS (self)->new_default_connection) - return NULL; + if (!NM_DEVICE_GET_CLASS(self)->new_default_connection) + return NULL; - connection = NM_DEVICE_GET_CLASS (self)->new_default_connection (self); - if (!connection) - return NULL; + connection = NM_DEVICE_GET_CLASS(self)->new_default_connection(self); + if (!connection) + return NULL; - if (!nm_connection_normalize (connection, NULL, NULL, &error)) { - _LOGD (LOGD_DEVICE, "device generated an invalid default connection: %s", error->message); - g_error_free (error); - g_return_val_if_reached (NULL); - } + if (!nm_connection_normalize(connection, NULL, NULL, &error)) { + _LOGD(LOGD_DEVICE, "device generated an invalid default connection: %s", error->message); + g_error_free(error); + g_return_val_if_reached(NULL); + } - return connection; + return connection; } static void -slave_state_changed (NMDevice *slave, - NMDeviceState slave_new_state, - NMDeviceState slave_old_state, - NMDeviceStateReason reason, - NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean release = FALSE; - gboolean configure; - - _LOGD (LOGD_DEVICE, "slave %s state change %d (%s) -> %d (%s)", - nm_device_get_iface (slave), - slave_old_state, - nm_device_state_to_str (slave_old_state), - 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) - return; - - if (slave_new_state == NM_DEVICE_STATE_IP_CONFIG) - nm_device_master_enslave_slave (self, slave, nm_device_get_applied_connection (slave)); - else if (slave_new_state > NM_DEVICE_STATE_ACTIVATED) - release = TRUE; - else if ( slave_new_state <= NM_DEVICE_STATE_DISCONNECTED - && slave_old_state > NM_DEVICE_STATE_DISCONNECTED) { - /* Catch failures due to unavailable or unmanaged */ - release = TRUE; - } - - if (release) { - configure = priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED - && nm_device_sys_iface_state_get (slave) != NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; - - nm_device_master_release_one_slave (self, slave, - configure, - reason); - /* Bridge/bond/team interfaces are left up until manually deactivated */ - if ( c_list_is_empty (&priv->slaves) - && priv->state == NM_DEVICE_STATE_ACTIVATED) - _LOGD (LOGD_DEVICE, "last slave removed; remaining activated"); - } +slave_state_changed(NMDevice * slave, + NMDeviceState slave_new_state, + NMDeviceState slave_old_state, + NMDeviceStateReason reason, + NMDevice * self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean release = FALSE; + gboolean configure; + + _LOGD(LOGD_DEVICE, + "slave %s state change %d (%s) -> %d (%s)", + nm_device_get_iface(slave), + slave_old_state, + nm_device_state_to_str(slave_old_state), + 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) + return; + + if (slave_new_state == NM_DEVICE_STATE_IP_CONFIG) + nm_device_master_enslave_slave(self, slave, nm_device_get_applied_connection(slave)); + else if (slave_new_state > NM_DEVICE_STATE_ACTIVATED) + release = TRUE; + else if (slave_new_state <= NM_DEVICE_STATE_DISCONNECTED + && slave_old_state > NM_DEVICE_STATE_DISCONNECTED) { + /* Catch failures due to unavailable or unmanaged */ + release = TRUE; + } + + if (release) { + configure = priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED + && nm_device_sys_iface_state_get(slave) != NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; + + nm_device_master_release_one_slave(self, slave, configure, FALSE, reason); + /* Bridge/bond/team interfaces are left up until manually deactivated */ + if (c_list_is_empty(&priv->slaves) && priv->state == NM_DEVICE_STATE_ACTIVATED) + _LOGD(LOGD_DEVICE, "last slave removed; remaining activated"); + } } /** @@ -5403,61 +6338,65 @@ slave_state_changed (NMDevice *slave, * enslaved and nothing was done. */ static gboolean -nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure) +nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure) { - NMDevicePrivate *priv; - NMDevicePrivate *slave_priv; - SlaveInfo *info; - gboolean changed = FALSE; + NMDevicePrivate *priv; + NMDevicePrivate *slave_priv; + SlaveInfo * info; + gboolean changed = FALSE; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (NM_IS_DEVICE (slave), FALSE); - g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL, FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(slave), FALSE); + g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE); - priv = NM_DEVICE_GET_PRIVATE (self); - slave_priv = NM_DEVICE_GET_PRIVATE (slave); + priv = NM_DEVICE_GET_PRIVATE(self); + slave_priv = NM_DEVICE_GET_PRIVATE(slave); - info = find_slave_info (self, slave); + info = find_slave_info(self, slave); - _LOGT (LOGD_CORE, "master: add one slave %p/%s%s", slave, nm_device_get_iface (slave), - info ? " (already registered)" : ""); + _LOGT(LOGD_CORE, + "master: add one slave %p/%s%s", + slave, + nm_device_get_iface(slave), + info ? " (already registered)" : ""); - if (configure) - g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + if (configure) + g_return_val_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); - if (!info) { - g_return_val_if_fail (!slave_priv->master, FALSE); - g_return_val_if_fail (!slave_priv->is_enslaved, FALSE); + if (!info) { + g_return_val_if_fail(!slave_priv->master, FALSE); + g_return_val_if_fail(!slave_priv->is_enslaved, FALSE); - info = g_slice_new0 (SlaveInfo); - info->slave = g_object_ref (slave); - info->configure = configure; - info->watch_id = g_signal_connect (slave, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK (slave_state_changed), self); - c_list_link_tail (&priv->slaves, &info->lst_slave); - slave_priv->master = g_object_ref (self); + info = g_slice_new0(SlaveInfo); + info->slave = g_object_ref(slave); + info->configure = configure; + info->watch_id = + g_signal_connect(slave, NM_DEVICE_STATE_CHANGED, G_CALLBACK(slave_state_changed), self); + c_list_link_tail(&priv->slaves, &info->lst_slave); + slave_priv->master = g_object_ref(self); - _active_connection_set_state_flags (self, - NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES); + _active_connection_set_state_flags(self, NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES); - /* no need to emit - * - * _notify (slave, PROP_MASTER); - * - * because slave_priv->is_enslaved is not true, thus the value - * didn't change yet. */ + /* no need to emit + * + * _notify (slave, PROP_MASTER); + * + * because slave_priv->is_enslaved is not true, thus the value + * didn't change yet. */ - g_warn_if_fail (!NM_FLAGS_HAS (slave_priv->unmanaged_mask, NM_UNMANAGED_IS_SLAVE)); - nm_device_set_unmanaged_by_flags (slave, NM_UNMANAGED_IS_SLAVE, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - changed = TRUE; - } else - g_return_val_if_fail (slave_priv->master == self, FALSE); + g_warn_if_fail(!NM_FLAGS_HAS(slave_priv->unmanaged_mask, NM_UNMANAGED_IS_SLAVE)); + nm_device_set_unmanaged_by_flags(slave, + NM_UNMANAGED_IS_SLAVE, + FALSE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + changed = TRUE; + } else + g_return_val_if_fail(slave_priv->master == self, FALSE); - nm_device_queue_recheck_assume (self); - nm_device_queue_recheck_assume (slave); + nm_device_queue_recheck_assume(self); + nm_device_queue_recheck_assume(slave); - return changed; + return changed; } /** @@ -5470,59 +6409,59 @@ nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure) * as @slave, and logs a warning if so. */ void -nm_device_master_check_slave_physical_port (NMDevice *self, NMDevice *slave, - NMLogDomain log_domain) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const char *slave_physical_port_id, *existing_physical_port_id; - SlaveInfo *info; - CList *iter; - - slave_physical_port_id = nm_device_get_physical_port_id (slave); - if (!slave_physical_port_id) - return; - - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry (iter, SlaveInfo, lst_slave); - if (info->slave == slave) - continue; - - existing_physical_port_id = nm_device_get_physical_port_id (info->slave); - if (!g_strcmp0 (slave_physical_port_id, existing_physical_port_id)) { - _LOGW (log_domain, "slave %s shares a physical port with existing slave %s", - nm_device_get_ip_iface (slave), - nm_device_get_ip_iface (info->slave)); - /* Since this function will get called for every slave, we only have - * to warn about the first match we find; if there are other matches - * later in the list, we will have already warned about them matching - * @existing earlier. - */ - return; - } - } +nm_device_master_check_slave_physical_port(NMDevice *self, NMDevice *slave, NMLogDomain log_domain) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const char * slave_physical_port_id, *existing_physical_port_id; + SlaveInfo * info; + CList * iter; + + slave_physical_port_id = nm_device_get_physical_port_id(slave); + if (!slave_physical_port_id) + return; + + c_list_for_each (iter, &priv->slaves) { + info = c_list_entry(iter, SlaveInfo, lst_slave); + if (info->slave == slave) + continue; + + existing_physical_port_id = nm_device_get_physical_port_id(info->slave); + if (nm_streq0(slave_physical_port_id, existing_physical_port_id)) { + _LOGW(log_domain, + "slave %s shares a physical port with existing slave %s", + nm_device_get_ip_iface(slave), + nm_device_get_ip_iface(info->slave)); + /* Since this function will get called for every slave, we only have + * to warn about the first match we find; if there are other matches + * later in the list, we will have already warned about them matching + * @existing earlier. + */ + return; + } + } } /* release all slaves */ static void -nm_device_master_release_slaves (NMDevice *self) +nm_device_master_release_slaves(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceStateReason reason; - CList *iter, *safe; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceStateReason reason; + CList * iter, *safe; - /* Don't release the slaves if this connection doesn't belong to NM. */ - if (nm_device_sys_iface_state_is_external (self)) - return; + /* Don't release the slaves if this connection doesn't belong to NM. */ + if (nm_device_sys_iface_state_is_external(self)) + return; - reason = priv->state_reason; - if (priv->state == NM_DEVICE_STATE_FAILED) - reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; + reason = priv->state_reason; + if (priv->state == NM_DEVICE_STATE_FAILED) + reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; - c_list_for_each_safe (iter, safe, &priv->slaves) { - SlaveInfo *info = c_list_entry (iter, SlaveInfo, lst_slave); + c_list_for_each_safe (iter, safe, &priv->slaves) { + SlaveInfo *info = c_list_entry(iter, SlaveInfo, lst_slave); - nm_device_master_release_one_slave (self, info->slave, TRUE, reason); - } + nm_device_master_release_one_slave(self, info->slave, TRUE, FALSE, reason); + } } /** @@ -5532,11 +6471,11 @@ nm_device_master_release_slaves (NMDevice *self) * Returns: %TRUE if the device can have slaves */ gboolean -nm_device_is_master (NMDevice *self) +nm_device_is_master(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - return NM_DEVICE_GET_CLASS (self)->is_master; + return NM_DEVICE_GET_CLASS(self)->is_master; } /** @@ -5544,35 +6483,35 @@ nm_device_is_master (NMDevice *self) * @self: the device * * If @self has been enslaved by another device, this returns that - * device. Otherwise it returns %NULL. (In particular, note that if + * device. Otherwise, it returns %NULL. (In particular, note that if * @self is in the process of activating as a slave, but has not yet * been enslaved by its master, this will return %NULL.) * * Returns: (transfer none): @self's master, or %NULL */ NMDevice * -nm_device_get_master (NMDevice *self) +nm_device_get_master(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->is_enslaved) { - g_return_val_if_fail (priv->master, NULL); - return priv->master; - } - return NULL; + if (priv->is_enslaved) { + g_return_val_if_fail(priv->master, NULL); + return priv->master; + } + return NULL; } static gboolean -get_ip_config_may_fail (NMDevice *self, int addr_family) +get_ip_config_may_fail(NMDevice *self, int addr_family) { - NMConnection *connection; - NMSettingIPConfig *s_ip; + NMConnection * connection; + NMSettingIPConfig *s_ip; - connection = nm_device_get_applied_connection (self); + connection = nm_device_get_applied_connection(self); - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - return !s_ip || nm_setting_ip_config_get_may_fail (s_ip); + return !s_ip || nm_setting_ip_config_get_may_fail(s_ip); } /* @@ -5587,84 +6526,82 @@ get_ip_config_may_fail (NMDevice *self, int addr_family) * due to the state of both ip families and the ipvx.may-fail settings. */ static void -check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean ip4_disabled = FALSE, ip6_disabled = FALSE; - NMSettingIPConfig *s_ip4, *s_ip6; - NMDeviceState state; - - if ( full_state_update - && nm_device_get_state (self) != NM_DEVICE_STATE_IP_CONFIG) - return; - - /* Don't progress into IP_CHECK or SECONDARIES if we're waiting for the - * master to enslave us. */ - if ( nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request.obj)) - && !priv->is_enslaved) - return; - - s_ip4 = nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP4_CONFIG); - if (s_ip4 && nm_streq0 (nm_setting_ip_config_get_method (s_ip4), - NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - ip4_disabled = TRUE; - - s_ip6 = nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); - if (s_ip6 && NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6), - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) - ip6_disabled = TRUE; - - if ( priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { - /* Both method completed (or disabled), proceed with activation */ - nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); - return; - } - - if ( (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL || (ip4_disabled && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE)) - && (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL || (ip6_disabled && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE))) { - /* Either both methods failed, or only one failed and the other is - * disabled */ - if (nm_device_sys_iface_state_is_external_or_assume (self)) { - /* We have assumed configuration, but couldn't redo it. No problem, - * move to check state. */ - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_DONE); - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_DONE); - state = NM_DEVICE_STATE_IP_CHECK; - } else if ( may_fail - && get_ip_config_may_fail (self, AF_INET) - && get_ip_config_may_fail (self, AF_INET6)) { - /* Couldn't start either IPv6 and IPv4 autoconfiguration, - * but both are allowed to fail. */ - state = NM_DEVICE_STATE_SECONDARIES; - } else { - /* Autoconfiguration attempted without success. */ - state = NM_DEVICE_STATE_FAILED; - } - - if ( full_state_update - || state == NM_DEVICE_STATE_FAILED) { - nm_device_state_changed (self, - state, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } - return; - } - - /* If a method is still pending but required, wait */ - if (priv->ip_state_4 != NM_DEVICE_IP_STATE_DONE && !get_ip_config_may_fail (self, AF_INET)) - return; - if (priv->ip_state_6 != NM_DEVICE_IP_STATE_DONE && !get_ip_config_may_fail (self, AF_INET6)) - return; - - /* If at least a method has completed, proceed with activation */ - if ( (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !ip4_disabled) - || (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && !ip6_disabled)) { - if (full_state_update) - nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); - return; - } +check_ip_state(NMDevice *self, gboolean may_fail, gboolean full_state_update) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + gboolean ip4_disabled = FALSE, ip6_disabled = FALSE; + NMSettingIPConfig *s_ip4, *s_ip6; + NMDeviceState state; + + if (full_state_update && nm_device_get_state(self) != NM_DEVICE_STATE_IP_CONFIG) + return; + + /* Don't progress into IP_CHECK or SECONDARIES if we're waiting for the + * master to enslave us. */ + if (nm_active_connection_get_master(NM_ACTIVE_CONNECTION(priv->act_request.obj)) + && !priv->is_enslaved) + return; + + s_ip4 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG); + if (s_ip4 + && nm_streq0(nm_setting_ip_config_get_method(s_ip4), NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + ip4_disabled = TRUE; + + s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6 + && NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip6), + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) + ip6_disabled = TRUE; + + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE + && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { + /* Both method completed (or disabled), proceed with activation */ + nm_device_state_changed(self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); + return; + } + + if ((priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL + || (ip4_disabled && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE)) + && (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL + || (ip6_disabled && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE))) { + /* Either both methods failed, or only one failed and the other is + * disabled */ + if (nm_device_sys_iface_state_is_external_or_assume(self)) { + /* We have assumed configuration, but couldn't redo it. No problem, + * move to check state. */ + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_DONE); + state = NM_DEVICE_STATE_IP_CHECK; + } else if (may_fail && get_ip_config_may_fail(self, AF_INET) + && get_ip_config_may_fail(self, AF_INET6)) { + /* Couldn't start either IPv6 and IPv4 autoconfiguration, + * but both are allowed to fail. */ + state = NM_DEVICE_STATE_SECONDARIES; + } else { + /* Autoconfiguration attempted without success. */ + state = NM_DEVICE_STATE_FAILED; + } + + if (full_state_update || state == NM_DEVICE_STATE_FAILED) { + nm_device_state_changed(self, state, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } + return; + } + + /* If a method is still pending but required, wait */ + if (priv->ip_state_4 != NM_DEVICE_IP_STATE_DONE && !get_ip_config_may_fail(self, AF_INET)) + return; + if (priv->ip_state_6 != NM_DEVICE_IP_STATE_DONE && !get_ip_config_may_fail(self, AF_INET6)) + return; + + /* If at least a method has completed, proceed with activation */ + if ((priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !ip4_disabled) + || (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && !ip6_disabled)) { + if (full_state_update) + nm_device_state_changed(self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); + return; + } } /** @@ -5676,39 +6613,41 @@ check_ip_state (NMDevice *self, gboolean may_fail, gboolean full_state_update) * to enslave it and failed. */ static void -nm_device_slave_notify_enslave (NMDevice *self, gboolean success) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection = nm_device_get_applied_connection (self); - gboolean activating = (priv->state == NM_DEVICE_STATE_IP_CONFIG); - - g_return_if_fail (priv->master); - - if (!priv->is_enslaved) { - if (success) { - if (activating) { - _LOGI (LOGD_DEVICE, "Activation: connection '%s' enslaved, continuing activation", - nm_connection_get_id (connection)); - } else - _LOGI (LOGD_DEVICE, "enslaved to %s", nm_device_get_iface (priv->master)); - - priv->is_enslaved = TRUE; - - _notify (self, PROP_MASTER); - _notify (priv->master, PROP_SLAVES); - } else if (activating) { - _LOGW (LOGD_DEVICE, "Activation: connection '%s' could not be enslaved", - nm_connection_get_id (connection)); - } - } - - if (activating) { - if (success) - check_ip_state (self, FALSE, TRUE); - else - nm_device_queue_state (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN); - } else - nm_device_queue_recheck_assume (self); +nm_device_slave_notify_enslave(NMDevice *self, gboolean success) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection = nm_device_get_applied_connection(self); + gboolean activating = (priv->state == NM_DEVICE_STATE_IP_CONFIG); + + g_return_if_fail(priv->master); + + if (!priv->is_enslaved) { + if (success) { + if (activating) { + _LOGI(LOGD_DEVICE, + "Activation: connection '%s' enslaved, continuing activation", + nm_connection_get_id(connection)); + } else + _LOGI(LOGD_DEVICE, "enslaved to %s", nm_device_get_iface(priv->master)); + + priv->is_enslaved = TRUE; + + _notify(self, PROP_MASTER); + _notify(priv->master, PROP_SLAVES); + } else if (activating) { + _LOGW(LOGD_DEVICE, + "Activation: connection '%s' could not be enslaved", + nm_connection_get_id(connection)); + } + } + + if (activating) { + if (success) + check_ip_state(self, FALSE, TRUE); + else + nm_device_queue_state(self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN); + } else + nm_device_queue_recheck_assume(self); } /** @@ -5719,48 +6658,48 @@ nm_device_slave_notify_enslave (NMDevice *self, gboolean success) * Notifies a slave that it has been released, and why. */ static void -nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection = nm_device_get_applied_connection (self); - const char *master_status; - - g_return_if_fail (priv->master); - - if ( priv->state > NM_DEVICE_STATE_DISCONNECTED - && priv->state <= NM_DEVICE_STATE_ACTIVATED) { - switch (nm_device_state_reason_check (reason)) { - case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: - master_status = "failed"; - break; - case NM_DEVICE_STATE_REASON_USER_REQUESTED: - reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; - master_status = "deactivated by user request"; - break; - case NM_DEVICE_STATE_REASON_CONNECTION_REMOVED: - reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; - master_status = "deactivated because master was removed"; - break; - default: - master_status = "deactivated"; - break; - } - - _LOGD (LOGD_DEVICE, "Activation: connection '%s' master %s", - nm_connection_get_id (connection), - master_status); - - /* Cancel any pending activation sources */ - _cancel_activation (self); - nm_device_queue_state (self, NM_DEVICE_STATE_DEACTIVATING, reason); - } else - _LOGI (LOGD_DEVICE, "released from master device %s", nm_device_get_iface (priv->master)); - - if (priv->is_enslaved) { - priv->is_enslaved = FALSE; - _notify (self, PROP_MASTER); - _notify (priv->master, PROP_SLAVES); - } +nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection = nm_device_get_applied_connection(self); + const char * master_status; + + g_return_if_fail(priv->master); + + if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state <= NM_DEVICE_STATE_ACTIVATED) { + switch (nm_device_state_reason_check(reason)) { + case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: + master_status = "failed"; + break; + case NM_DEVICE_STATE_REASON_USER_REQUESTED: + reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; + master_status = "deactivated by user request"; + break; + case NM_DEVICE_STATE_REASON_CONNECTION_REMOVED: + reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; + master_status = "deactivated because master was removed"; + break; + default: + master_status = "deactivated"; + break; + } + + _LOGD(LOGD_DEVICE, + "Activation: connection '%s' master %s", + nm_connection_get_id(connection), + master_status); + + /* Cancel any pending activation sources */ + _cancel_activation(self); + nm_device_queue_state(self, NM_DEVICE_STATE_DEACTIVATING, reason); + } else + _LOGI(LOGD_DEVICE, "released from master device %s", nm_device_get_iface(priv->master)); + + if (priv->is_enslaved) { + priv->is_enslaved = FALSE; + _notify(self, PROP_MASTER); + _notify(priv->master, PROP_SLAVES); + } } /** @@ -5773,47 +6712,50 @@ nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason) * the master in case it's enslaved. */ void -nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config) -{ - NMDevicePrivate *priv; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->master) { - /* this is called when something externally messes with the slave or during shut-down. - * Release the slave from master, but don't touch the device. */ - nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - } - - if (unconfigure_ip_config) { - nm_device_set_ip_config (self, AF_INET, NULL, FALSE, NULL); - nm_device_set_ip_config (self, AF_INET6, NULL, FALSE, NULL); - } else { - if (priv->dhcp_data_4.client) - nm_dhcp_client_stop (priv->dhcp_data_4.client, FALSE); - if (priv->dhcp_data_6.client) - nm_dhcp_client_stop (priv->dhcp_data_6.client, FALSE); - } +nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config) +{ + NMDevicePrivate *priv; + + g_return_if_fail(NM_IS_DEVICE(self)); + + priv = NM_DEVICE_GET_PRIVATE(self); + if (priv->master) { + /* this is called when something externally messes with the slave or during shut-down. + * Release the slave from master, but don't touch the device. */ + nm_device_master_release_one_slave(priv->master, + self, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + + if (unconfigure_ip_config) { + nm_device_set_ip_config(self, AF_INET, NULL, FALSE, NULL); + nm_device_set_ip_config(self, AF_INET6, NULL, FALSE, NULL); + } else { + if (priv->dhcp_data_4.client) + nm_dhcp_client_stop(priv->dhcp_data_4.client, FALSE); + if (priv->dhcp_data_6.client) + nm_dhcp_client_stop(priv->dhcp_data_6.client, FALSE); + } } static gboolean -is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags) +is_available(NMDevice *self, NMDeviceCheckDevAvailableFlags flags) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if ( priv->carrier - || priv->ignore_carrier) - return TRUE; + if (priv->carrier || priv->ignore_carrier) + return TRUE; - if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER)) - return TRUE; + if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER)) + return TRUE; - /* master types are always available even without carrier. */ - if (nm_device_is_master (self)) - return TRUE; + /* master types are always available even without carrier. */ + if (nm_device_is_master(self)) + return TRUE; - return FALSE; + return FALSE; } /** @@ -5836,102 +6778,108 @@ is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags) * Returns: %TRUE or %FALSE */ gboolean -nm_device_is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags) +nm_device_is_available(NMDevice *self, NMDeviceCheckDevAvailableFlags flags) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->firmware_missing) - return FALSE; + if (priv->firmware_missing) + return FALSE; - return NM_DEVICE_GET_CLASS (self)->is_available (self, flags); + return NM_DEVICE_GET_CLASS(self)->is_available(self, flags); } gboolean -nm_device_ignore_carrier_by_default (NMDevice *self) +nm_device_ignore_carrier_by_default(NMDevice *self) { - /* master types ignore-carrier by default. */ - return nm_device_is_master (self); + /* master types ignore-carrier by default. */ + return nm_device_is_master(self); } gboolean -nm_device_get_enabled (NMDevice *self) +nm_device_get_enabled(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - if (NM_DEVICE_GET_CLASS (self)->get_enabled) - return NM_DEVICE_GET_CLASS (self)->get_enabled (self); - return TRUE; + if (NM_DEVICE_GET_CLASS(self)->get_enabled) + return NM_DEVICE_GET_CLASS(self)->get_enabled(self); + return TRUE; } void -nm_device_set_enabled (NMDevice *self, gboolean enabled) +nm_device_set_enabled(NMDevice *self, gboolean enabled) { - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - if (NM_DEVICE_GET_CLASS (self)->set_enabled) - NM_DEVICE_GET_CLASS (self)->set_enabled (self, enabled); + if (NM_DEVICE_GET_CLASS(self)->set_enabled) + NM_DEVICE_GET_CLASS(self)->set_enabled(self, enabled); } -static -NM_UTILS_FLAGS2STR_DEFINE (_autoconnect_blocked_flags_to_string, NMDeviceAutoconnectBlockedFlags, - NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_NONE, "none"), - NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_USER, "user"), - NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN, "wrong-pin"), - NM_UTILS_FLAGS2STR (NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT, "manual-disconnect"), -); +static NM_UTILS_FLAGS2STR_DEFINE(_autoconnect_blocked_flags_to_string, + NMDeviceAutoconnectBlockedFlags, + NM_UTILS_FLAGS2STR(NM_DEVICE_AUTOCONNECT_BLOCKED_NONE, "none"), + NM_UTILS_FLAGS2STR(NM_DEVICE_AUTOCONNECT_BLOCKED_USER, "user"), + NM_UTILS_FLAGS2STR(NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN, + "wrong-pin"), + NM_UTILS_FLAGS2STR(NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT, + "manual-disconnect"), ); NMDeviceAutoconnectBlockedFlags -nm_device_autoconnect_blocked_get (NMDevice *self, NMDeviceAutoconnectBlockedFlags mask) +nm_device_autoconnect_blocked_get(NMDevice *self, NMDeviceAutoconnectBlockedFlags mask) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - if (mask == 0) - mask = NM_DEVICE_AUTOCONNECT_BLOCKED_ALL; + if (mask == 0) + mask = NM_DEVICE_AUTOCONNECT_BLOCKED_ALL; - priv = NM_DEVICE_GET_PRIVATE (self); - return priv->autoconnect_blocked_flags & mask; + priv = NM_DEVICE_GET_PRIVATE(self); + return priv->autoconnect_blocked_flags & mask; } void -nm_device_autoconnect_blocked_set_full (NMDevice *self, NMDeviceAutoconnectBlockedFlags mask, NMDeviceAutoconnectBlockedFlags value) +nm_device_autoconnect_blocked_set_full(NMDevice * self, + NMDeviceAutoconnectBlockedFlags mask, + NMDeviceAutoconnectBlockedFlags value) { - NMDevicePrivate *priv; - gboolean changed; - char buf1[128], buf2[128]; + NMDevicePrivate *priv; + gboolean changed; + char buf1[128], buf2[128]; - g_return_if_fail (NM_IS_DEVICE (self)); - nm_assert (mask); - nm_assert (!NM_FLAGS_ANY (mask, ~NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)); - nm_assert (!NM_FLAGS_ANY (value, ~mask)); + g_return_if_fail(NM_IS_DEVICE(self)); + nm_assert(mask); + nm_assert(!NM_FLAGS_ANY(mask, ~NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)); + nm_assert(!NM_FLAGS_ANY(value, ~mask)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - value = (priv->autoconnect_blocked_flags & ~mask) | (mask & value); - if (value == priv->autoconnect_blocked_flags) - return; + value = (priv->autoconnect_blocked_flags & ~mask) | (mask & value); + if (value == priv->autoconnect_blocked_flags) + return; - changed = ((!value) != (!priv->autoconnect_blocked_flags)); + changed = ((!value) != (!priv->autoconnect_blocked_flags)); - _LOGT (LOGD_DEVICE, "autoconnect-blocked: set \"%s\" (was \"%s\")", - _autoconnect_blocked_flags_to_string (value, buf1, sizeof (buf1)), - _autoconnect_blocked_flags_to_string (priv->autoconnect_blocked_flags, buf2, sizeof (buf2))); + _LOGT( + LOGD_DEVICE, + "autoconnect-blocked: set \"%s\" (was \"%s\")", + _autoconnect_blocked_flags_to_string(value, buf1, sizeof(buf1)), + _autoconnect_blocked_flags_to_string(priv->autoconnect_blocked_flags, buf2, sizeof(buf2))); - priv->autoconnect_blocked_flags = value; - nm_assert (priv->autoconnect_blocked_flags == value); - if (changed) - _notify (self, PROP_AUTOCONNECT); + priv->autoconnect_blocked_flags = value; + nm_assert(priv->autoconnect_blocked_flags == value); + if (changed) + _notify(self, PROP_AUTOCONNECT); } static gboolean -autoconnect_allowed_accumulator (GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, gpointer data) +autoconnect_allowed_accumulator(GSignalInvocationHint *ihint, + GValue * return_accu, + const GValue * handler_return, + gpointer data) { - if (!g_value_get_boolean (handler_return)) - g_value_set_boolean (return_accu, FALSE); - return TRUE; + if (!g_value_get_boolean(handler_return)) + g_value_set_boolean(return_accu, FALSE); + return TRUE; } /** @@ -5943,59 +6891,59 @@ autoconnect_allowed_accumulator (GSignalInvocationHint *ihint, * block autoconnect for a time). */ gboolean -nm_device_autoconnect_allowed (NMDevice *self) +nm_device_autoconnect_allowed(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); - GValue instance = G_VALUE_INIT; - GValue retval = G_VALUE_INIT; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); + GValue instance = G_VALUE_INIT; + GValue retval = G_VALUE_INIT; - if (nm_device_autoconnect_blocked_get (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)) - return FALSE; + if (nm_device_autoconnect_blocked_get(self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)) + return FALSE; - if ( klass->get_autoconnect_allowed - && !klass->get_autoconnect_allowed (self)) - return FALSE; + if (klass->get_autoconnect_allowed && !klass->get_autoconnect_allowed(self)) + return FALSE; - if (!nm_device_get_enabled (self)) - return FALSE; + if (!nm_device_get_enabled(self)) + return FALSE; - if (nm_device_is_real (self)) { - if (priv->state < NM_DEVICE_STATE_DISCONNECTED) - return FALSE; - } else { - if (!nm_device_check_unrealized_device_managed (self)) - return FALSE; - } + if (nm_device_is_real(self)) { + if (priv->state < NM_DEVICE_STATE_DISCONNECTED) + return FALSE; + } else { + if (!nm_device_check_unrealized_device_managed(self)) + return FALSE; + } - /* The 'autoconnect-allowed' signal is emitted on a device to allow - * other listeners to block autoconnect on the device if they wish. - * This is mainly used by the OLPC Mesh devices to block autoconnect - * on their companion Wi-Fi device as they share radio resources and - * cannot be connected at the same time. - */ + if (priv->delete_on_deactivate_data) + return FALSE; - g_value_init (&instance, G_TYPE_OBJECT); - g_value_set_object (&instance, self); + /* The 'autoconnect-allowed' signal is emitted on a device to allow + * other listeners to block autoconnect on the device if they wish. + * This is mainly used by the OLPC Mesh devices to block autoconnect + * on their companion Wi-Fi device as they share radio resources and + * cannot be connected at the same time. + */ - g_value_init (&retval, G_TYPE_BOOLEAN); - g_value_set_boolean (&retval, TRUE); + g_value_init(&instance, G_TYPE_OBJECT); + g_value_set_object(&instance, self); - /* Use g_signal_emitv() rather than g_signal_emit() to avoid the return - * value being changed if no handlers are connected */ - g_signal_emitv (&instance, signals[AUTOCONNECT_ALLOWED], 0, &retval); - g_value_unset (&instance); + g_value_init(&retval, G_TYPE_BOOLEAN); + g_value_set_boolean(&retval, TRUE); - return g_value_get_boolean (&retval); + /* Use g_signal_emitv() rather than g_signal_emit() to avoid the return + * value being changed if no handlers are connected */ + g_signal_emitv(&instance, signals[AUTOCONNECT_ALLOWED], 0, &retval); + g_value_unset(&instance); + + return g_value_get_boolean(&retval); } static gboolean -can_auto_connect (NMDevice *self, - NMSettingsConnection *sett_conn, - char **specific_object) +can_auto_connect(NMDevice *self, NMSettingsConnection *sett_conn, char **specific_object) { - nm_assert (!specific_object || !*specific_object); - return TRUE; + nm_assert(!specific_object || !*specific_object); + return TRUE; } /** @@ -6016,57 +6964,55 @@ can_auto_connect (NMDevice *self, * Returns: %TRUE, if the @sett_conn can be auto-activated. **/ gboolean -nm_device_can_auto_connect (NMDevice *self, - NMSettingsConnection *sett_conn, - char **specific_object) +nm_device_can_auto_connect(NMDevice *self, NMSettingsConnection *sett_conn, char **specific_object) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn), FALSE); - g_return_val_if_fail (!specific_object || !*specific_object, FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(sett_conn), FALSE); + g_return_val_if_fail(!specific_object || !*specific_object, FALSE); - /* the caller must ensure that nm_device_autoconnect_allowed() returns - * TRUE as well. This is done, because nm_device_can_auto_connect() - * has only one caller, and it iterates over a list of available - * connections. - * - * Hence, we don't need to re-check nm_device_autoconnect_allowed() - * over and over again. The caller is supposed to do that. */ - nm_assert (nm_device_autoconnect_allowed (self)); + /* the caller must ensure that nm_device_autoconnect_allowed() returns + * TRUE as well. This is done, because nm_device_can_auto_connect() + * has only one caller, and it iterates over a list of available + * connections. + * + * Hence, we don't need to re-check nm_device_autoconnect_allowed() + * over and over again. The caller is supposed to do that. */ + nm_assert(nm_device_autoconnect_allowed(self)); - if (!nm_device_check_connection_available (self, - nm_settings_connection_get_connection (sett_conn), - NM_DEVICE_CHECK_CON_AVAILABLE_NONE, - NULL, - NULL)) - return FALSE; + if (!nm_device_check_connection_available(self, + nm_settings_connection_get_connection(sett_conn), + NM_DEVICE_CHECK_CON_AVAILABLE_NONE, + NULL, + NULL)) + return FALSE; - if (!NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, sett_conn, specific_object)) - return FALSE; + if (!NM_DEVICE_GET_CLASS(self)->can_auto_connect(self, sett_conn, specific_object)) + return FALSE; - return TRUE; + return TRUE; } static gboolean -device_has_config (NMDevice *self) +device_has_config(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - /* Check for IP configuration. */ - if (priv->ip_config_4 && nm_ip4_config_get_num_addresses (priv->ip_config_4)) - return TRUE; - if (priv->ip_config_6 && nm_ip6_config_get_num_addresses (priv->ip_config_6)) - return TRUE; + /* Check for IP configuration. */ + if (priv->ip_config_4 && nm_ip4_config_get_num_addresses(priv->ip_config_4)) + return TRUE; + if (priv->ip_config_6 && nm_ip6_config_get_num_addresses(priv->ip_config_6)) + return TRUE; - /* The existence of a software device is good enough. */ - if (nm_device_is_software (self) && nm_device_is_real (self)) - return TRUE; + /* The existence of a software device is good enough. */ + if (nm_device_is_software(self) && nm_device_is_real(self)) + return TRUE; - /* Master-slave relationship is also a configuration */ - if ( !c_list_is_empty (&priv->slaves) - || nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) > 0) - return TRUE; + /* Master-slave relationship is also a configuration */ + if (!c_list_is_empty(&priv->slaves) + || nm_platform_link_get_master(nm_device_get_platform(self), priv->ifindex) > 0) + return TRUE; - return FALSE; + return FALSE; } /** @@ -6083,166 +7029,208 @@ device_has_config (NMDevice *self) * %FALSE on failure. */ gboolean -nm_device_master_update_slave_connection (NMDevice *self, - NMDevice *slave, - NMConnection *connection, - GError **error) +nm_device_master_update_slave_connection(NMDevice * self, + NMDevice * slave, + NMConnection *connection, + GError ** error) { - NMDeviceClass *klass; - gboolean success; + NMDeviceClass *klass; + gboolean success; - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (slave, FALSE); - g_return_val_if_fail (connection, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - g_return_val_if_fail (nm_connection_get_setting_connection (connection), FALSE); + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(slave, FALSE); + g_return_val_if_fail(connection, FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + g_return_val_if_fail(nm_connection_get_setting_connection(connection), FALSE); - g_return_val_if_fail (nm_device_get_iface (self), FALSE); + g_return_val_if_fail(nm_device_get_iface(self), FALSE); - klass = NM_DEVICE_GET_CLASS (self); - if (klass->master_update_slave_connection) { - success = klass->master_update_slave_connection (self, slave, connection, error); + klass = NM_DEVICE_GET_CLASS(self); + if (klass->master_update_slave_connection) { + success = klass->master_update_slave_connection(self, slave, connection, error); - g_return_val_if_fail (!error || (success && !*error) || *error, success); - return success; - } + g_return_val_if_fail(!error || (success && !*error) || *error, success); + return success; + } - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "master device '%s' cannot update a slave connection for slave device '%s' (master type not supported?)", - nm_device_get_iface (self), nm_device_get_iface (slave)); - return FALSE; + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "master device '%s' cannot update a slave connection for slave device '%s' (master " + "type not supported?)", + nm_device_get_iface(self), + nm_device_get_iface(slave)); + return FALSE; +} + +static gboolean +_get_maybe_ipv6_disabled(NMDevice *self) +{ + NMPlatform *platform; + int ifindex; + const char *path; + char ifname[IFNAMSIZ]; + + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex <= 0) + return FALSE; + + platform = nm_device_get_platform(self); + if (!nm_platform_if_indextoname(platform, ifindex, ifname)) + return FALSE; + + path = nm_sprintf_bufa(128, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname); + return (nm_platform_sysctl_get_int32(platform, NMP_SYSCTL_PATHID_ABSOLUTE(path), 0) == 0); } NMConnection * -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); - 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 *local = NULL; - const NMPlatformLink *pllink; - - NM_SET_OUT (out_maybe_later, FALSE); - - /* If update_connection() is not implemented, just fail. */ - 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)) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, - "device has no existing configuration"); - return NULL; - } - - connection = nm_simple_connection_new (); - s_con = nm_setting_connection_new (); - - g_object_set (s_con, - NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), - NM_SETTING_CONNECTION_ID, ifname, - NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, - NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, - NM_SETTING_CONNECTION_TIMESTAMP, (guint64) time (NULL), - NULL); - - if (klass->connection_type_supported) - g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type_supported, NULL); - - nm_connection_add_setting (connection, s_con); - - /* If the device is a slave, update various slave settings */ - if (master) { - if (!nm_device_master_update_slave_connection (master, - self, - 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 { - /* Only regular and master devices get IP configuration; slaves do not */ - s_ip4 = nm_ip4_config_create_setting (priv->ip_config_4); - nm_connection_add_setting (connection, s_ip4); - - s_ip6 = nm_ip6_config_create_setting (priv->ip_config_6); - nm_connection_add_setting (connection, s_ip6); - - nm_connection_add_setting (connection, nm_setting_proxy_new ()); - - pllink = nm_platform_link_get (nm_device_get_platform (self), priv->ifindex); - if ( pllink - && pllink->inet6_token.id) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - 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, sbuf), - NULL); - } - } - - klass->update_connection (self, connection); - - if (!nm_connection_normalize (connection, NULL, NULL, &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; - } - - /* Ignore the connection if it has no IP configuration, - * no slave configuration, and is not a master interface. - */ - ip4_method = nm_utils_get_ip_config_method (connection, AF_INET); - ip6_method = nm_utils_get_ip_config_method (connection, AF_INET6); - if ( nm_streq0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) - && NM_IN_STRSET (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED) - && !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con)) - && c_list_is_empty (&priv->slaves)) { - 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 ( 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)) - && c_list_is_empty (&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)"); - 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 g_steal_pointer (&connection); +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); + 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 * local = NULL; + const NMPlatformLink * pllink; + + NM_SET_OUT(out_maybe_later, FALSE); + + /* If update_connection() is not implemented, just fail. */ + 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)) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "device has no existing configuration"); + return NULL; + } + + connection = nm_simple_connection_new(); + s_con = nm_setting_connection_new(); + + g_object_set(s_con, + NM_SETTING_CONNECTION_UUID, + nm_utils_uuid_generate_buf(uuid), + NM_SETTING_CONNECTION_ID, + ifname, + NM_SETTING_CONNECTION_AUTOCONNECT, + FALSE, + NM_SETTING_CONNECTION_INTERFACE_NAME, + ifname, + NM_SETTING_CONNECTION_TIMESTAMP, + (guint64) time(NULL), + NULL); + + if (klass->connection_type_supported) + g_object_set(s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type_supported, NULL); + + nm_connection_add_setting(connection, s_con); + + /* If the device is a slave, update various slave settings */ + if (master) { + if (!nm_device_master_update_slave_connection(master, self, 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 { + /* Only regular and master devices get IP configuration; slaves do not */ + s_ip4 = nm_ip4_config_create_setting(priv->ip_config_4); + nm_connection_add_setting(connection, s_ip4); + + s_ip6 = nm_ip6_config_create_setting(priv->ip_config_6, _get_maybe_ipv6_disabled(self)); + nm_connection_add_setting(connection, s_ip6); + + nm_connection_add_setting(connection, nm_setting_proxy_new()); + + pllink = nm_platform_link_get(nm_device_get_platform(self), priv->ifindex); + if (pllink && pllink->inet6_token.id) { + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + + 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, sbuf), + NULL); + } + } + + klass->update_connection(self, connection); + + if (!nm_connection_normalize(connection, NULL, NULL, &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; + } + + /* Ignore the connection if it has no IP configuration, + * no slave configuration, and is not a master interface. + */ + ip4_method = nm_utils_get_ip_config_method(connection, AF_INET); + ip6_method = nm_utils_get_ip_config_method(connection, AF_INET6); + if (nm_streq0(ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) + && NM_IN_STRSET(ip6_method, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED) + && !nm_setting_connection_get_master(NM_SETTING_CONNECTION(s_con)) + && c_list_is_empty(&priv->slaves)) { + 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 (nm_streq0(ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) + && nm_streq0(ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) + && !nm_setting_connection_get_master(NM_SETTING_CONNECTION(s_con)) + && c_list_is_empty(&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)"); + 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 g_steal_pointer(&connection); } /** @@ -6256,182 +7244,180 @@ nm_device_generate_connection (NMDevice *self, * Returns: success or failure. */ gboolean -nm_device_complete_connection (NMDevice *self, - NMConnection *connection, - const char *specific_object, - NMConnection *const*existing_connections, - GError **error) +nm_device_complete_connection(NMDevice * self, + NMConnection * connection, + const char * specific_object, + NMConnection *const *existing_connections, + GError ** error) { - NMDeviceClass *klass; + NMDeviceClass *klass; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - klass = NM_DEVICE_GET_CLASS (self); + klass = NM_DEVICE_GET_CLASS(self); - if (!klass->complete_connection) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, - "Device class %s had no complete_connection method", - G_OBJECT_TYPE_NAME (self)); - return FALSE; - } + if (!klass->complete_connection) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "Device class %s had no complete_connection method", + G_OBJECT_TYPE_NAME(self)); + return FALSE; + } - if (!klass->complete_connection (self, - connection, - specific_object, - existing_connections, - error)) - return FALSE; + if (!klass->complete_connection(self, connection, specific_object, existing_connections, error)) + return FALSE; - if (!nm_connection_normalize (connection, NULL, NULL, error)) - return FALSE; + if (!nm_connection_normalize(connection, NULL, NULL, error)) + return FALSE; - return nm_device_check_connection_compatible (self, connection, error); + return nm_device_check_connection_compatible(self, connection, error); } gboolean -nm_device_match_parent (NMDevice *self, const char *parent) +nm_device_match_parent(NMDevice *self, const char *parent) { - NMDevice *parent_device; + NMDevice *parent_device; - g_return_val_if_fail (parent, FALSE); + g_return_val_if_fail(parent, FALSE); - parent_device = nm_device_parent_get_device (self); - if (!parent_device) - return FALSE; + parent_device = nm_device_parent_get_device(self); + if (!parent_device) + return FALSE; - if (nm_utils_is_uuid (parent)) { - NMConnection *connection; + if (nm_utils_is_uuid(parent)) { + NMConnection *connection; - /* If the parent is a UUID, the connection matches when there is - * no connection active on the device or when a connection with - * that UUID is active. - */ - connection = nm_device_get_applied_connection (parent_device); - if ( connection - && !nm_streq0 (parent, nm_connection_get_uuid (connection))) - return FALSE; - } else { - /* Interface name */ - if (!nm_streq0 (parent, nm_device_get_ip_iface (parent_device))) - return FALSE; - } + /* If the parent is a UUID, the connection matches when there is + * no connection active on the device or when a connection with + * that UUID is active. + */ + connection = nm_device_get_applied_connection(parent_device); + if (connection && !nm_streq0(parent, nm_connection_get_uuid(connection))) + return FALSE; + } else { + /* Interface name */ + if (!nm_streq0(parent, nm_device_get_ip_iface(parent_device))) + return FALSE; + } - return TRUE; + return TRUE; } gboolean -nm_device_match_parent_hwaddr (NMDevice *device, - NMConnection *connection, - gboolean fail_if_no_hwaddr) +nm_device_match_parent_hwaddr(NMDevice * device, + NMConnection *connection, + gboolean fail_if_no_hwaddr) { - NMSettingWired *s_wired; - NMDevice *parent_device; - const char *setting_mac; - const char *parent_mac; + NMSettingWired *s_wired; + NMDevice * parent_device; + const char * setting_mac; + const char * parent_mac; - s_wired = nm_connection_get_setting_wired (connection); - if (!s_wired) - return !fail_if_no_hwaddr; + s_wired = nm_connection_get_setting_wired(connection); + if (!s_wired) + return !fail_if_no_hwaddr; - setting_mac = nm_setting_wired_get_mac_address (s_wired); - if (!setting_mac) - return !fail_if_no_hwaddr; + setting_mac = nm_setting_wired_get_mac_address(s_wired); + if (!setting_mac) + return !fail_if_no_hwaddr; - parent_device = nm_device_parent_get_device (device); - if (!parent_device) - return !fail_if_no_hwaddr; + parent_device = nm_device_parent_get_device(device); + if (!parent_device) + return !fail_if_no_hwaddr; - parent_mac = nm_device_get_permanent_hw_address (parent_device); - return parent_mac && nm_utils_hwaddr_matches (setting_mac, -1, parent_mac, -1); + parent_mac = nm_device_get_permanent_hw_address(parent_device); + return parent_mac && nm_utils_hwaddr_matches(setting_mac, -1, parent_mac, -1); } static gboolean -check_connection_compatible (NMDevice *self, NMConnection *connection, GError **error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const char *device_iface = nm_device_get_iface (self); - gs_free_error GError *local = NULL; - gs_free char *conn_iface = NULL; - NMDeviceClass *klass; - NMSettingMatch *s_match; - - klass = NM_DEVICE_GET_CLASS (self); - if (klass->connection_type_check_compatible) { - if (!_nm_connection_check_main_setting (connection, - klass->connection_type_check_compatible, - error)) - return FALSE; - } else if (klass->check_connection_compatible == check_connection_compatible) { - /* the device class does not implement check_connection_compatible nor set - * connection_type_check_compatible. That means, it is by default not compatible - * with any connection type. */ - nm_utils_error_set_literal (error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "device does not support any connections"); - return FALSE; - } - - conn_iface = nm_manager_get_connection_iface (NM_MANAGER_GET, - connection, - NULL, - NULL, - &local); - - /* We always need a interface name for virtual devices, but for - * physical ones a connection without interface name is fine for - * any device. */ - if (!conn_iface) { - if (nm_connection_is_virtual (connection)) { - nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "cannot get interface name due to %s", local->message); - return FALSE; - } - } else if (!nm_streq0 (conn_iface, device_iface)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "mismatching interface name"); - return FALSE; - } - - s_match = (NMSettingMatch *) nm_connection_get_setting (connection, - NM_TYPE_SETTING_MATCH); - if (s_match) { - const char *const *patterns; - const char *device_driver; - guint num_patterns = 0; - - patterns = nm_setting_match_get_interface_names (s_match, &num_patterns); - if (!nm_wildcard_match_check (device_iface, patterns, num_patterns)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not satisfy match.interface-name property"); - return FALSE; - } - - patterns = nm_setting_match_get_kernel_command_lines (s_match, &num_patterns); - if ( num_patterns > 0 - && !nm_utils_kernel_cmdline_match_check (nm_utils_proc_cmdline_split (), - patterns, - num_patterns, - error)) - return FALSE; - - device_driver = nm_device_get_driver (self); - patterns = nm_setting_match_get_drivers (s_match, &num_patterns); - if (!nm_wildcard_match_check (device_driver, patterns, num_patterns)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not satisfy match.driver property"); - return FALSE; - } - - patterns = nm_setting_match_get_paths (s_match, &num_patterns); - if (!nm_wildcard_match_check (priv->path, patterns, num_patterns)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "device does not satisfy match.path property"); - return FALSE; - } - } - - return TRUE; +check_connection_compatible(NMDevice *self, NMConnection *connection, GError **error) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const char * device_iface = nm_device_get_iface(self); + gs_free_error GError *local = NULL; + gs_free char * conn_iface = NULL; + NMDeviceClass * klass; + NMSettingMatch * s_match; + + klass = NM_DEVICE_GET_CLASS(self); + if (klass->connection_type_check_compatible) { + if (!_nm_connection_check_main_setting(connection, + klass->connection_type_check_compatible, + error)) + return FALSE; + } else if (klass->check_connection_compatible == check_connection_compatible) { + /* the device class does not implement check_connection_compatible nor set + * connection_type_check_compatible. That means, it is by default not compatible + * with any connection type. */ + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "device does not support any connections"); + return FALSE; + } + + conn_iface = nm_manager_get_connection_iface(NM_MANAGER_GET, connection, NULL, NULL, &local); + + /* We always need a interface name for virtual devices, but for + * physical ones a connection without interface name is fine for + * any device. */ + if (!conn_iface) { + if (nm_connection_is_virtual(connection)) { + nm_utils_error_set(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "cannot get interface name due to %s", + local->message); + return FALSE; + } + } else if (!nm_streq0(conn_iface, device_iface)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "mismatching interface name"); + return FALSE; + } + + s_match = (NMSettingMatch *) nm_connection_get_setting(connection, NM_TYPE_SETTING_MATCH); + if (s_match) { + const char *const *patterns; + const char * device_driver; + guint num_patterns = 0; + + patterns = nm_setting_match_get_interface_names(s_match, &num_patterns); + if (!nm_wildcard_match_check(device_iface, patterns, num_patterns)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not satisfy match.interface-name property"); + return FALSE; + } + + patterns = nm_setting_match_get_kernel_command_lines(s_match, &num_patterns); + if (num_patterns > 0 + && !nm_utils_kernel_cmdline_match_check(nm_utils_proc_cmdline_split(), + patterns, + num_patterns, + error)) + return FALSE; + + device_driver = nm_device_get_driver(self); + patterns = nm_setting_match_get_drivers(s_match, &num_patterns); + if (!nm_wildcard_match_check(device_driver, patterns, num_patterns)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not satisfy match.driver property"); + return FALSE; + } + + patterns = nm_setting_match_get_paths(s_match, &num_patterns); + if (!nm_wildcard_match_check(priv->path, patterns, num_patterns)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "device does not satisfy match.path property"); + return FALSE; + } + } + + return TRUE; } /** @@ -6455,37 +7441,37 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError ** * @self. */ gboolean -nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection, GError **error) +nm_device_check_connection_compatible(NMDevice *self, NMConnection *connection, GError **error) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - return NM_DEVICE_GET_CLASS (self)->check_connection_compatible (self, connection, error); + return NM_DEVICE_GET_CLASS(self)->check_connection_compatible(self, connection, error); } gboolean -nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave) +nm_device_check_slave_connection_compatible(NMDevice *self, NMConnection *slave) { - NMSettingConnection *s_con; - const char *connection_type, *slave_type; + NMSettingConnection *s_con; + const char * connection_type, *slave_type; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (slave), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(NM_IS_CONNECTION(slave), FALSE); - if (!nm_device_is_master (self)) - return FALSE; + if (!nm_device_is_master(self)) + return FALSE; - /* All masters should have connection type set */ - connection_type = NM_DEVICE_GET_CLASS (self)->connection_type_supported; - g_return_val_if_fail (connection_type, FALSE); + /* All masters should have connection type set */ + connection_type = NM_DEVICE_GET_CLASS(self)->connection_type_supported; + g_return_val_if_fail(connection_type, FALSE); - s_con = nm_connection_get_setting_connection (slave); - g_assert (s_con); - slave_type = nm_setting_connection_get_slave_type (s_con); - if (!slave_type) - return FALSE; + s_con = nm_connection_get_setting_connection(slave); + g_assert(s_con); + slave_type = nm_setting_connection_get_slave_type(s_con); + if (!slave_type) + return FALSE; - return strcmp (connection_type, slave_type) == 0; + return nm_streq(connection_type, slave_type); } /** @@ -6498,500 +7484,477 @@ nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave * Returns: %TRUE if the device is capable of assuming connections, %FALSE if not */ static gboolean -nm_device_can_assume_connections (NMDevice *self) +nm_device_can_assume_connections(NMDevice *self) { - return !!NM_DEVICE_GET_CLASS (self)->update_connection; + return !!NM_DEVICE_GET_CLASS(self)->update_connection; } static gboolean -unmanaged_on_quit (NMDevice *self) -{ - NMConnection *connection; - - /* NMDeviceWifi overwrites this function to always unmanage wifi devices. - * - * For all other types, if the device type can assume connections, we leave - * it up on quit. - * - * Originally, we would only keep devices up that can be assumed afterwards. - * However, that meant we unmanged layer-2 only devices. So, this was step - * by step refined to unmanage less (commit 25aaaab3, rh#1311988, rh#1333983). - * But there are more scenarios where we also want to keep the device up - * (rh#1378418, rh#1371126). */ - if (!nm_device_can_assume_connections (self)) - return TRUE; - - /* the only exception are IPv4 shared connections. We unmanage them on quit. */ - connection = nm_device_get_applied_connection (self); - if (connection) { - if (NM_IN_STRSET (nm_utils_get_ip_config_method (connection, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - /* shared connections are to be unmangaed. */ - return TRUE; - } - } - - return FALSE; +unmanaged_on_quit(NMDevice *self) +{ + NMConnection *connection; + + /* NMDeviceWifi overwrites this function to always unmanage wifi devices. + * + * For all other types, if the device type can assume connections, we leave + * it up on quit. + * + * Originally, we would only keep devices up that can be assumed afterwards. + * However, that meant we unmanged layer-2 only devices. So, this was step + * by step refined to unmanage less (commit 25aaaab3, rh#1311988, rh#1333983). + * But there are more scenarios where we also want to keep the device up + * (rh#1378418, rh#1371126). */ + if (!nm_device_can_assume_connections(self)) + return TRUE; + + /* the only exception are IPv4 shared connections. We unmanage them on quit. */ + connection = nm_device_get_applied_connection(self); + if (connection) { + if (NM_IN_STRSET(nm_utils_get_ip_config_method(connection, AF_INET), + NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { + /* shared connections are to be unmangaed. */ + return TRUE; + } + } + + return FALSE; } gboolean -nm_device_unmanage_on_quit (NMDevice *self) +nm_device_unmanage_on_quit(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - return NM_DEVICE_GET_CLASS (self)->unmanaged_on_quit (self); + return NM_DEVICE_GET_CLASS(self)->unmanaged_on_quit(self); } static gboolean -nm_device_emit_recheck_assume (gpointer user_data) +nm_device_emit_recheck_assume(gpointer user_data) { - NMDevice *self = user_data; - NMDevicePrivate *priv; + NMDevice * self = user_data; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); + g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - priv->recheck_assume_id = 0; - if (!nm_device_get_act_request (self)) - g_signal_emit (self, signals[RECHECK_ASSUME], 0); + priv->recheck_assume_id = 0; + if (!nm_device_get_act_request(self)) + g_signal_emit(self, signals[RECHECK_ASSUME], 0); - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; } void -nm_device_queue_recheck_assume (NMDevice *self) +nm_device_queue_recheck_assume(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if ( !priv->recheck_assume_id - && nm_device_can_assume_connections (self)) - priv->recheck_assume_id = g_idle_add (nm_device_emit_recheck_assume, self); + if (!priv->recheck_assume_id && nm_device_can_assume_connections(self)) + priv->recheck_assume_id = g_idle_add(nm_device_emit_recheck_assume, self); } static gboolean -recheck_available (gpointer user_data) +recheck_available(gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean now_available; - NMDeviceState state = nm_device_get_state (self); - NMDeviceState new_state = NM_DEVICE_STATE_UNKNOWN; + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean now_available; + NMDeviceState state = nm_device_get_state(self); + NMDeviceState new_state = NM_DEVICE_STATE_UNKNOWN; - priv->recheck_available.call_id = 0; + priv->recheck_available.call_id = 0; - now_available = nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); + now_available = nm_device_is_available(self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); - if (state == NM_DEVICE_STATE_UNAVAILABLE && now_available) { - new_state = NM_DEVICE_STATE_DISCONNECTED; - nm_device_queue_state (self, new_state, priv->recheck_available.available_reason); - } else if (state >= NM_DEVICE_STATE_DISCONNECTED && !now_available) { - new_state = NM_DEVICE_STATE_UNAVAILABLE; - nm_device_queue_state (self, new_state, priv->recheck_available.unavailable_reason); - } + if (state == NM_DEVICE_STATE_UNAVAILABLE && now_available) { + new_state = NM_DEVICE_STATE_DISCONNECTED; + nm_device_queue_state(self, new_state, priv->recheck_available.available_reason); + } else if (state >= NM_DEVICE_STATE_DISCONNECTED && !now_available) { + new_state = NM_DEVICE_STATE_UNAVAILABLE; + nm_device_queue_state(self, new_state, priv->recheck_available.unavailable_reason); + } - if (new_state > NM_DEVICE_STATE_UNKNOWN) { - _LOGD (LOGD_DEVICE, "is %savailable, %s %s", - now_available ? "" : "not ", - new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" : "will transition to", - nm_device_state_to_str (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state)); + if (new_state > NM_DEVICE_STATE_UNKNOWN) { + _LOGD(LOGD_DEVICE, + "is %savailable, %s %s", + now_available ? "" : "not ", + new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" + : "will transition to", + 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; - } + priv->recheck_available.available_reason = NM_DEVICE_STATE_REASON_NONE; + priv->recheck_available.unavailable_reason = NM_DEVICE_STATE_REASON_NONE; + } - if (priv->recheck_available.call_id == 0) - nm_device_remove_pending_action (self, NM_PENDING_ACTION_RECHECK_AVAILABLE, TRUE); + if (priv->recheck_available.call_id == 0) + nm_device_remove_pending_action(self, NM_PENDING_ACTION_RECHECK_AVAILABLE, TRUE); - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; } void -nm_device_queue_recheck_available (NMDevice *self, - NMDeviceStateReason available_reason, - NMDeviceStateReason unavailable_reason) +nm_device_queue_recheck_available(NMDevice * self, + NMDeviceStateReason available_reason, + NMDeviceStateReason unavailable_reason) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->recheck_available.available_reason = available_reason; - priv->recheck_available.unavailable_reason = unavailable_reason; - if (!priv->recheck_available.call_id) { - priv->recheck_available.call_id = g_idle_add (recheck_available, self); - nm_device_add_pending_action (self, NM_PENDING_ACTION_RECHECK_AVAILABLE, - FALSE /* cannot assert, because of how recheck_available() first clears - the call-id and postpones removing the pending-action. */); - } + priv->recheck_available.available_reason = available_reason; + priv->recheck_available.unavailable_reason = unavailable_reason; + if (!priv->recheck_available.call_id) { + priv->recheck_available.call_id = g_idle_add(recheck_available, self); + nm_device_add_pending_action (self, NM_PENDING_ACTION_RECHECK_AVAILABLE, + FALSE /* cannot assert, because of how recheck_available() first clears + * the call-id and postpones removing the pending-action. */); + } } void -nm_device_emit_recheck_auto_activate (NMDevice *self) +nm_device_emit_recheck_auto_activate(NMDevice *self) { - g_signal_emit (self, signals[RECHECK_AUTO_ACTIVATE], 0); + g_signal_emit(self, signals[RECHECK_AUTO_ACTIVATE], 0); } static void -dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer user_data) +dnsmasq_state_changed_cb(NMDnsMasqManager *manager, guint32 status, gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); + NMDevice *self = NM_DEVICE(user_data); - switch (status) { - case NM_DNSMASQ_STATUS_DEAD: - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); - break; - default: - break; - } + switch (status) { + case NM_DNSMASQ_STATUS_DEAD: + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); + break; + default: + break; + } } void -nm_device_auth_request (NMDevice *self, - GDBusMethodInvocation *context, - NMConnection *connection, - const char *permission, - gboolean allow_interaction, - GCancellable *cancellable, - NMManagerDeviceAuthRequestFunc callback, - gpointer user_data) -{ - nm_manager_device_auth_request (nm_device_get_manager (self), - self, - context, - connection, - permission, - allow_interaction, - cancellable, - callback, - user_data); +nm_device_auth_request(NMDevice * self, + GDBusMethodInvocation * context, + NMConnection * connection, + const char * permission, + gboolean allow_interaction, + GCancellable * cancellable, + NMManagerDeviceAuthRequestFunc callback, + gpointer user_data) +{ + nm_manager_device_auth_request(nm_device_get_manager(self), + self, + context, + connection, + permission, + allow_interaction, + cancellable, + callback, + user_data); } /*****************************************************************************/ static void -activation_source_clear (NMDevice *self, - int addr_family) +activation_source_clear(NMDevice *self, int addr_family) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); - if (priv->activation_source_id_x[IS_IPv4] != 0) { - _LOGD (LOGD_DEVICE, "activation-stage: clear %s,v%c (id %u)", - _activation_func_to_string (priv->activation_source_func_x[IS_IPv4]), - nm_utils_addr_family_to_char (addr_family), - priv->activation_source_id_x[IS_IPv4]); - nm_clear_g_source (&priv->activation_source_id_x[IS_IPv4]); - priv->activation_source_func_x[IS_IPv4] = NULL; - } + if (priv->activation_source_id_x[IS_IPv4] != 0) { + _LOGD(LOGD_DEVICE, + "activation-stage: clear %s,v%c (id %u)", + _activation_func_to_string(priv->activation_source_func_x[IS_IPv4]), + nm_utils_addr_family_to_char(addr_family), + priv->activation_source_id_x[IS_IPv4]); + nm_clear_g_source(&priv->activation_source_id_x[IS_IPv4]); + priv->activation_source_func_x[IS_IPv4] = NULL; + } } static gboolean -activation_source_handle_cb (NMDevice *self, - int addr_family) +activation_source_handle_cb(NMDevice *self, int addr_family) { - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); - ActivationHandleFunc activation_source_func; - guint activation_source_id; + NMDevicePrivate * priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); + ActivationHandleFunc activation_source_func; + guint activation_source_id; - g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); + g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - activation_source_func = priv->activation_source_func_x[IS_IPv4]; - activation_source_id = priv->activation_source_id_x[IS_IPv4]; + activation_source_func = priv->activation_source_func_x[IS_IPv4]; + activation_source_id = priv->activation_source_id_x[IS_IPv4]; - g_return_val_if_fail (activation_source_id != 0, G_SOURCE_REMOVE); - nm_assert (activation_source_func); + g_return_val_if_fail(activation_source_id != 0, G_SOURCE_REMOVE); + nm_assert(activation_source_func); - priv->activation_source_func_x[IS_IPv4] = NULL; - priv->activation_source_id_x[IS_IPv4] = 0; + priv->activation_source_func_x[IS_IPv4] = NULL; + priv->activation_source_id_x[IS_IPv4] = 0; - _LOGD (LOGD_DEVICE, "activation-stage: invoke %s,v%c (id %u)", - _activation_func_to_string (activation_source_func), - nm_utils_addr_family_to_char (addr_family), - activation_source_id); + _LOGD(LOGD_DEVICE, + "activation-stage: invoke %s,v%c (id %u)", + _activation_func_to_string(activation_source_func), + nm_utils_addr_family_to_char(addr_family), + activation_source_id); - activation_source_func (self); + activation_source_func(self); - _LOGT (LOGD_DEVICE, "activation-stage: complete %s,v%c (id %u)", - _activation_func_to_string (activation_source_func), - nm_utils_addr_family_to_char (addr_family), - activation_source_id); + _LOGT(LOGD_DEVICE, + "activation-stage: complete %s,v%c (id %u)", + _activation_func_to_string(activation_source_func), + nm_utils_addr_family_to_char(addr_family), + activation_source_id); - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; } static gboolean -activation_source_handle_cb_4 (gpointer user_data) +activation_source_handle_cb_4(gpointer user_data) { - return activation_source_handle_cb (user_data, AF_INET); + return activation_source_handle_cb(user_data, AF_INET); } static gboolean -activation_source_handle_cb_6 (gpointer user_data) +activation_source_handle_cb_6(gpointer user_data) { - return activation_source_handle_cb (user_data, AF_INET6); + return activation_source_handle_cb(user_data, AF_INET6); } static void -activation_source_schedule (NMDevice *self, ActivationHandleFunc func, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - guint new_id = 0; - - if ( priv->activation_source_id_x[IS_IPv4] != 0 - && priv->activation_source_func_x[IS_IPv4] == func) { - /* Scheduling the same stage multiple times is fine. */ - _LOGT (LOGD_DEVICE, "activation-stage: already scheduled %s,v%c (id %u)", - _activation_func_to_string (func), - nm_utils_addr_family_to_char (addr_family), - priv->activation_source_id_x[IS_IPv4]); - return; - } - - new_id = g_idle_add ( IS_IPv4 - ? activation_source_handle_cb_4 - : activation_source_handle_cb_6, - self); - - if (priv->activation_source_id_x[IS_IPv4] != 0) { - _LOGD (LOGD_DEVICE, "activation-stage: schedule %s,v%c which replaces %s,v%c (id %u -> %u)", - _activation_func_to_string (func), - nm_utils_addr_family_to_char (addr_family), - _activation_func_to_string (priv->activation_source_func_x[IS_IPv4]), - nm_utils_addr_family_to_char (addr_family), - priv->activation_source_id_x[IS_IPv4], new_id); - nm_clear_g_source (&priv->activation_source_id_x[IS_IPv4]); - } else { - _LOGD (LOGD_DEVICE, "activation-stage: schedule %s,v%c (id %u)", - _activation_func_to_string (func), - nm_utils_addr_family_to_char (addr_family), - new_id); - } - - priv->activation_source_func_x[IS_IPv4] = func; - priv->activation_source_id_x[IS_IPv4] = new_id; +activation_source_schedule(NMDevice *self, ActivationHandleFunc func, int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); + guint new_id = 0; + + if (priv->activation_source_id_x[IS_IPv4] != 0 + && priv->activation_source_func_x[IS_IPv4] == func) { + /* Scheduling the same stage multiple times is fine. */ + _LOGT(LOGD_DEVICE, + "activation-stage: already scheduled %s,v%c (id %u)", + _activation_func_to_string(func), + nm_utils_addr_family_to_char(addr_family), + priv->activation_source_id_x[IS_IPv4]); + return; + } + + new_id = + g_idle_add(IS_IPv4 ? activation_source_handle_cb_4 : activation_source_handle_cb_6, self); + + if (priv->activation_source_id_x[IS_IPv4] != 0) { + _LOGD(LOGD_DEVICE, + "activation-stage: schedule %s,v%c which replaces %s,v%c (id %u -> %u)", + _activation_func_to_string(func), + nm_utils_addr_family_to_char(addr_family), + _activation_func_to_string(priv->activation_source_func_x[IS_IPv4]), + nm_utils_addr_family_to_char(addr_family), + priv->activation_source_id_x[IS_IPv4], + new_id); + nm_clear_g_source(&priv->activation_source_id_x[IS_IPv4]); + } else { + _LOGD(LOGD_DEVICE, + "activation-stage: schedule %s,v%c (id %u)", + _activation_func_to_string(func), + nm_utils_addr_family_to_char(addr_family), + new_id); + } + + priv->activation_source_func_x[IS_IPv4] = func; + priv->activation_source_id_x[IS_IPv4] = new_id; } static void -activation_source_invoke_sync (NMDevice *self, ActivationHandleFunc func, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - if (priv->activation_source_id_x[IS_IPv4] == 0) { - _LOGD (LOGD_DEVICE, "activation-stage: synchronously invoke %s,v%c", - _activation_func_to_string (func), - nm_utils_addr_family_to_char (addr_family)); - } else if (priv->activation_source_func_x[IS_IPv4] == func) { - _LOGD (LOGD_DEVICE, "activation-stage: synchronously invoke %s,v%c which was already scheduled (id %u)", - _activation_func_to_string (func), - nm_utils_addr_family_to_char (addr_family), - priv->activation_source_id_x[IS_IPv4]); - } else { - _LOGD (LOGD_DEVICE, "activation-stage: synchronously invoke %s,v%c which replaces %s,v%c (id %u)", - _activation_func_to_string (func), - nm_utils_addr_family_to_char (addr_family), - _activation_func_to_string (priv->activation_source_func_x[IS_IPv4]), - nm_utils_addr_family_to_char (addr_family), - priv->activation_source_id_x[IS_IPv4]); - } - - nm_clear_g_source (&priv->activation_source_id_x[IS_IPv4]); - priv->activation_source_func_x[IS_IPv4] = NULL; - - func (self); +activation_source_invoke_sync(NMDevice *self, ActivationHandleFunc func, int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); + + if (priv->activation_source_id_x[IS_IPv4] == 0) { + _LOGD(LOGD_DEVICE, + "activation-stage: synchronously invoke %s,v%c", + _activation_func_to_string(func), + nm_utils_addr_family_to_char(addr_family)); + } else if (priv->activation_source_func_x[IS_IPv4] == func) { + _LOGD(LOGD_DEVICE, + "activation-stage: synchronously invoke %s,v%c which was already scheduled (id %u)", + _activation_func_to_string(func), + nm_utils_addr_family_to_char(addr_family), + priv->activation_source_id_x[IS_IPv4]); + } else { + _LOGD(LOGD_DEVICE, + "activation-stage: synchronously invoke %s,v%c which replaces %s,v%c (id %u)", + _activation_func_to_string(func), + nm_utils_addr_family_to_char(addr_family), + _activation_func_to_string(priv->activation_source_func_x[IS_IPv4]), + nm_utils_addr_family_to_char(addr_family), + priv->activation_source_id_x[IS_IPv4]); + } + + nm_clear_g_source(&priv->activation_source_id_x[IS_IPv4]); + priv->activation_source_func_x[IS_IPv4] = NULL; + + func(self); } /*****************************************************************************/ static void -master_ready (NMDevice *self, - NMActiveConnection *active) +master_ready(NMDevice *self, NMActiveConnection *active) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActiveConnection *master_connection; - NMDevice *master; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMActiveConnection *master_connection; + NMDevice * master; - /* Notify a master device that it has a new slave */ - nm_assert (nm_active_connection_get_master_ready (active)); + /* Notify a master device that it has a new slave */ + nm_assert(nm_active_connection_get_master_ready(active)); - master_connection = nm_active_connection_get_master (active); + master_connection = nm_active_connection_get_master(active); - master = nm_active_connection_get_device (master_connection); + master = nm_active_connection_get_device(master_connection); - _LOGD (LOGD_DEVICE, "master connection ready; master device %s", - nm_device_get_iface (master)); + _LOGD(LOGD_DEVICE, "master connection ready; master device %s", nm_device_get_iface(master)); - if ( priv->master - && priv->master != master) - nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + if (priv->master && priv->master != master) + nm_device_master_release_one_slave(priv->master, + self, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - /* If the master didn't change, add-slave only rechecks whether to assume a connection. */ - nm_device_master_add_slave (master, - self, - !nm_device_sys_iface_state_is_external_or_assume (self)); + /* If the master didn't change, add-slave only rechecks whether to assume a connection. */ + nm_device_master_add_slave(master, + self, + !nm_device_sys_iface_state_is_external_or_assume(self)); } static void -master_ready_cb (NMActiveConnection *active, - GParamSpec *pspec, - NMDevice *self) +master_ready_cb(NMActiveConnection *active, GParamSpec *pspec, NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert (nm_active_connection_get_master_ready (active)); + nm_assert(nm_active_connection_get_master_ready(active)); - if (priv->state == NM_DEVICE_STATE_PREPARE) - nm_device_activate_schedule_stage1_device_prepare (self, FALSE); + if (priv->state == NM_DEVICE_STATE_PREPARE) + nm_device_activate_schedule_stage1_device_prepare(self, FALSE); } static void -lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec, - gpointer user_data) +lldp_neighbors_changed(NMLldpListener *lldp_listener, GParamSpec *pspec, gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); + NMDevice *self = NM_DEVICE(user_data); - _notify (self, PROP_LLDP_NEIGHBORS); -} - -static gboolean -lldp_rx_enabled (NMDevice *self) -{ - NMConnection *connection; - NMSettingConnection *s_con; - NMSettingConnectionLldp lldp = NM_SETTING_CONNECTION_LLDP_DEFAULT; - - connection = nm_device_get_applied_connection (self); - g_return_val_if_fail (connection, FALSE); - - s_con = nm_connection_get_setting_connection (connection); - g_return_val_if_fail (s_con, FALSE); - - lldp = nm_setting_connection_get_lldp (s_con); - if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) { - lldp = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.lldp"), - self, - NM_SETTING_CONNECTION_LLDP_DEFAULT, - NM_SETTING_CONNECTION_LLDP_ENABLE_RX, - NM_SETTING_CONNECTION_LLDP_DEFAULT); - if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) - lldp = NM_SETTING_CONNECTION_LLDP_DISABLE; - } - return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX; + _notify(self, PROP_LLDP_NEIGHBORS); } static NMPlatformVF * -sriov_vf_config_to_platform (NMDevice *self, - NMSriovVF *vf, - GError **error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gs_free NMPlatformVF *plat_vf = NULL; - const guint *vlan_ids; - GVariant *variant; - guint i, num_vlans; - gsize length; - - g_return_val_if_fail (!error || !*error, FALSE); - - vlan_ids = nm_sriov_vf_get_vlan_ids (vf, &num_vlans); - plat_vf = g_malloc0 ( sizeof (NMPlatformVF) - + sizeof (NMPlatformVFVlan) * num_vlans); - - plat_vf->index = nm_sriov_vf_get_index (vf); - - variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK); - if (variant) - plat_vf->spoofchk = g_variant_get_boolean (variant); - else - plat_vf->spoofchk = -1; - - variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_TRUST); - if (variant) - plat_vf->trust = g_variant_get_boolean (variant); - else - plat_vf->trust = -1; - - variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAC); - if (variant) { - if (!_nm_utils_hwaddr_aton (g_variant_get_string (variant, NULL), - plat_vf->mac.data, - sizeof (plat_vf->mac.data), - &length)) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "invalid MAC %s", - g_variant_get_string (variant, NULL)); - return NULL; - } - if (length != priv->hw_addr_len) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "wrong MAC length %" G_GSIZE_FORMAT ", should be %u", - length, priv->hw_addr_len); - return NULL; - } - plat_vf->mac.len = length; - } - - variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE); - if (variant) - plat_vf->min_tx_rate = g_variant_get_uint32 (variant); - - variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE); - if (variant) - plat_vf->max_tx_rate = g_variant_get_uint32 (variant); - - plat_vf->num_vlans = num_vlans; - plat_vf->vlans = (NMPlatformVFVlan *) (&plat_vf[1]); - for (i = 0; i < num_vlans; i++) { - plat_vf->vlans[i].id = vlan_ids[i]; - plat_vf->vlans[i].qos = nm_sriov_vf_get_vlan_qos (vf, vlan_ids[i]); - plat_vf->vlans[i].proto_ad = nm_sriov_vf_get_vlan_protocol (vf, vlan_ids[i]) == NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD; - } - - return g_steal_pointer (&plat_vf); +sriov_vf_config_to_platform(NMDevice *self, NMSriovVF *vf, GError **error) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gs_free NMPlatformVF *plat_vf = NULL; + const guint * vlan_ids; + GVariant * variant; + guint i, num_vlans; + gsize length; + + g_return_val_if_fail(!error || !*error, FALSE); + + vlan_ids = nm_sriov_vf_get_vlan_ids(vf, &num_vlans); + plat_vf = g_malloc0(sizeof(NMPlatformVF) + sizeof(NMPlatformVFVlan) * num_vlans); + + plat_vf->index = nm_sriov_vf_get_index(vf); + + variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK); + if (variant) + plat_vf->spoofchk = g_variant_get_boolean(variant); + else + plat_vf->spoofchk = -1; + + variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_TRUST); + if (variant) + plat_vf->trust = g_variant_get_boolean(variant); + else + plat_vf->trust = -1; + + variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_MAC); + if (variant) { + if (!_nm_utils_hwaddr_aton(g_variant_get_string(variant, NULL), + plat_vf->mac.data, + sizeof(plat_vf->mac.data), + &length)) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "invalid MAC %s", + g_variant_get_string(variant, NULL)); + return NULL; + } + if (length != priv->hw_addr_len) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "wrong MAC length %" G_GSIZE_FORMAT ", should be %u", + length, + priv->hw_addr_len); + return NULL; + } + plat_vf->mac.len = length; + } + + variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE); + if (variant) + plat_vf->min_tx_rate = g_variant_get_uint32(variant); + + variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE); + if (variant) + plat_vf->max_tx_rate = g_variant_get_uint32(variant); + + plat_vf->num_vlans = num_vlans; + plat_vf->vlans = (NMPlatformVFVlan *) (&plat_vf[1]); + for (i = 0; i < num_vlans; i++) { + plat_vf->vlans[i].id = vlan_ids[i]; + plat_vf->vlans[i].qos = nm_sriov_vf_get_vlan_qos(vf, vlan_ids[i]); + plat_vf->vlans[i].proto_ad = + nm_sriov_vf_get_vlan_protocol(vf, vlan_ids[i]) == NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD; + } + + return g_steal_pointer(&plat_vf); } static void -sriov_params_cb (GError *error, gpointer data) +sriov_params_cb(GError *error, gpointer data) { - NMDevice *self; - NMDevicePrivate *priv; - nm_auto_freev NMPlatformVF **plat_vfs = NULL; + NMDevice * self; + NMDevicePrivate *priv; + nm_auto_freev NMPlatformVF **plat_vfs = NULL; - nm_utils_user_data_unpack (data, &self, &plat_vfs); + nm_utils_user_data_unpack(data, &self, &plat_vfs); - if (nm_utils_error_is_cancelled_or_disposing (error)) - return; + if (nm_utils_error_is_cancelled_or_disposing(error)) + return; - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if (error) { - _LOGE (LOGD_DEVICE, "failed to set SR-IOV parameters: %s", error->message); - nm_device_state_changed (self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return; - } + if (error) { + _LOGE(LOGD_DEVICE, "failed to set SR-IOV parameters: %s", error->message); + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return; + } - if (!nm_platform_link_set_sriov_vfs (nm_device_get_platform (self), - priv->ifindex, - (const NMPlatformVF *const *) plat_vfs)) { - _LOGE (LOGD_DEVICE, "failed to apply SR-IOV VFs"); - nm_device_state_changed (self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return; - } + if (!nm_platform_link_set_sriov_vfs(nm_device_get_platform(self), + priv->ifindex, + (const NMPlatformVF *const *) plat_vfs)) { + _LOGE(LOGD_DEVICE, "failed to apply SR-IOV VFs"); + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return; + } - priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_COMPLETED; + priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare (self, FALSE); + nm_device_activate_schedule_stage1_device_prepare(self, FALSE); } /* @@ -7001,196 +7964,206 @@ sriov_params_cb (GError *error, gpointer data) * */ static void -activate_stage1_device_prepare (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - NMActiveConnection *active; - NMActiveConnection *master; - NMDeviceClass *klass; - - priv->v4_route_table_initialized = FALSE; - priv->v6_route_table_initialized = FALSE; - - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_NONE); - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_NONE); - - /* Notify the new ActiveConnection along with the state change */ - nm_dbus_track_obj_path_set (&priv->act_request, - priv->act_request.obj, - TRUE); - - nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); - - if (priv->stage1_sriov_state != NM_DEVICE_STAGE_STATE_COMPLETED) { - NMSettingSriov *s_sriov; - - if (nm_device_sys_iface_state_is_external_or_assume (self)) { - /* pass */ - } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) - return; - else if ( priv->ifindex > 0 - && nm_device_has_capability (self, NM_DEVICE_CAP_SRIOV) - && (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) { - nm_auto_freev NMPlatformVF **plat_vfs = NULL; - gs_free_error GError *error = NULL; - NMSriovVF *vf; - NMTernary autoprobe; - guint i, num; - - autoprobe = nm_setting_sriov_get_autoprobe_drivers (s_sriov); - if (autoprobe == NM_TERNARY_DEFAULT) { - autoprobe = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("sriov.autoprobe-drivers"), - self, - NM_TERNARY_FALSE, - NM_TERNARY_TRUE, - NM_TERNARY_TRUE); - } - - num = nm_setting_sriov_get_num_vfs (s_sriov); - plat_vfs = g_new0 (NMPlatformVF *, num + 1); - for (i = 0; i < num; i++) { - vf = nm_setting_sriov_get_vf (s_sriov, i); - plat_vfs[i] = sriov_vf_config_to_platform (self, vf, &error); - if (!plat_vfs[i]) { - _LOGE (LOGD_DEVICE, - "failed to apply SR-IOV VF '%s': %s", - nm_utils_sriov_vf_to_str (vf, FALSE, NULL), - error->message); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return; - } - } - - /* When changing the number of VFs the kernel can block - * for very long time in the write to sysfs, especially - * if autoprobe-drivers is enabled. Do it asynchronously - * to avoid blocking the entire NM process. - */ - sriov_op_queue (self, - nm_setting_sriov_get_total_vfs (s_sriov), - autoprobe, - sriov_params_cb, - nm_utils_user_data_pack (self, - g_steal_pointer (&plat_vfs))); - priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_PENDING; - return; - } - priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_COMPLETED; - } - - /* Assumed connections were already set up outside NetworkManager */ - klass = NM_DEVICE_GET_CLASS (self); - - if ( klass->act_stage1_prepare_set_hwaddr_ethernet - && !nm_device_sys_iface_state_is_external_or_assume (self)) { - if (!nm_device_hw_addr_set_cloned (self, - nm_device_get_applied_connection (self), - FALSE)) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - } - - if ( klass->act_stage1_prepare_also_for_external_or_assume - || !nm_device_sys_iface_state_is_external_or_assume (self)) { - nm_assert (!klass->act_stage1_prepare_also_for_external_or_assume || klass->act_stage1_prepare); - if (klass->act_stage1_prepare) { - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - - ret = klass->act_stage1_prepare (self, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); - return; - } - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - return; - - nm_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - } - } - - active = NM_ACTIVE_CONNECTION (priv->act_request.obj); - master = nm_active_connection_get_master (active); - if (master) { - if (nm_active_connection_get_state (master) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { - _LOGD (LOGD_DEVICE, "master connection is deactivating"); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); - return; - } - /* If the master connection is ready for slaves, attach ourselves */ - if (!nm_active_connection_get_master_ready (active)) { - if (priv->master_ready_id == 0) { - _LOGD (LOGD_DEVICE, "waiting for master connection to become ready"); - priv->master_ready_id = g_signal_connect (active, - "notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY, - (GCallback) master_ready_cb, - self); - } - return; - } - } - nm_clear_g_signal_handler (priv->act_request.obj, &priv->master_ready_id); - if (master) - master_ready (self, active); - - nm_device_activate_schedule_stage2_device_config (self, TRUE); +activate_stage1_device_prepare(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMActiveConnection *active; + NMActiveConnection *master; + NMDeviceClass * klass; + + priv->v4_route_table_initialized = FALSE; + priv->v6_route_table_initialized = FALSE; + + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_NONE); + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_NONE); + + /* Notify the new ActiveConnection along with the state change */ + nm_dbus_track_obj_path_set(&priv->act_request, priv->act_request.obj, TRUE); + + nm_device_state_changed(self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); + + if (priv->stage1_sriov_state != NM_DEVICE_STAGE_STATE_COMPLETED) { + NMSettingSriov *s_sriov; + + if (nm_device_sys_iface_state_is_external_or_assume(self)) { + /* pass */ + } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) + return; + else if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV) + && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { + nm_auto_freev NMPlatformVF **plat_vfs = NULL; + gs_free_error GError *error = NULL; + NMSriovVF * vf; + NMTernary autoprobe; + guint i, num; + + autoprobe = nm_setting_sriov_get_autoprobe_drivers(s_sriov); + if (autoprobe == NM_TERNARY_DEFAULT) { + autoprobe = nm_config_data_get_connection_default_int64( + NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("sriov.autoprobe-drivers"), + self, + NM_TERNARY_FALSE, + NM_TERNARY_TRUE, + NM_TERNARY_TRUE); + } + + num = nm_setting_sriov_get_num_vfs(s_sriov); + plat_vfs = g_new0(NMPlatformVF *, num + 1); + for (i = 0; i < num; i++) { + vf = nm_setting_sriov_get_vf(s_sriov, i); + plat_vfs[i] = sriov_vf_config_to_platform(self, vf, &error); + if (!plat_vfs[i]) { + _LOGE(LOGD_DEVICE, + "failed to apply SR-IOV VF '%s': %s", + nm_utils_sriov_vf_to_str(vf, FALSE, NULL), + error->message); + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return; + } + } + + /* When changing the number of VFs the kernel can block + * for very long time in the write to sysfs, especially + * if autoprobe-drivers is enabled. Do it asynchronously + * to avoid blocking the entire NM process. + */ + sriov_op_queue(self, + nm_setting_sriov_get_total_vfs(s_sriov), + autoprobe, + sriov_params_cb, + nm_utils_user_data_pack(self, g_steal_pointer(&plat_vfs))); + priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_PENDING; + return; + } + priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_COMPLETED; + } + + /* Assumed connections were already set up outside NetworkManager */ + klass = NM_DEVICE_GET_CLASS(self); + + if (klass->act_stage1_prepare_set_hwaddr_ethernet + && !nm_device_sys_iface_state_is_external_or_assume(self)) { + if (!nm_device_hw_addr_set_cloned(self, nm_device_get_applied_connection(self), FALSE)) { + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return; + } + } + + if (klass->act_stage1_prepare_also_for_external_or_assume + || !nm_device_sys_iface_state_is_external_or_assume(self)) { + nm_assert(!klass->act_stage1_prepare_also_for_external_or_assume + || klass->act_stage1_prepare); + if (klass->act_stage1_prepare) { + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + + ret = klass->act_stage1_prepare(self, &failure_reason); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); + return; + } + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) + return; + + nm_assert(ret == NM_ACT_STAGE_RETURN_SUCCESS); + } + } + + active = NM_ACTIVE_CONNECTION(priv->act_request.obj); + master = nm_active_connection_get_master(active); + if (master) { + if (nm_active_connection_get_state(master) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { + _LOGD(LOGD_DEVICE, "master connection is deactivating"); + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); + return; + } + /* If the master connection is ready for slaves, attach ourselves */ + if (!nm_active_connection_get_master_ready(active)) { + if (priv->master_ready_id == 0) { + _LOGD(LOGD_DEVICE, "waiting for master connection to become ready"); + priv->master_ready_id = + g_signal_connect(active, + "notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY, + (GCallback) master_ready_cb, + self); + } + return; + } + } + nm_clear_g_signal_handler(priv->act_request.obj, &priv->master_ready_id); + if (master) + master_ready(self, active); + else if (priv->master) { + nm_device_master_release_one_slave(priv->master, + self, + TRUE, + TRUE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + + nm_device_activate_schedule_stage2_device_config(self, TRUE); } void -nm_device_activate_schedule_stage1_device_prepare (NMDevice *self, - gboolean do_sync) +nm_device_activate_schedule_stage1_device_prepare(NMDevice *self, gboolean do_sync) { - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_DEVICE_GET_PRIVATE (self)->act_request.obj); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_DEVICE_GET_PRIVATE(self)->act_request.obj); - if (!do_sync) { - activation_source_schedule (self, activate_stage1_device_prepare, AF_INET); - return; - } + if (!do_sync) { + activation_source_schedule(self, activate_stage1_device_prepare, AF_INET); + return; + } - activation_source_invoke_sync (self, activate_stage1_device_prepare, AF_INET); + activation_source_invoke_sync(self, activate_stage1_device_prepare, AF_INET); } static NMActStageReturn -act_stage2_config (NMDevice *self, NMDeviceStateReason *out_failure_reason) +act_stage2_config(NMDevice *self, NMDeviceStateReason *out_failure_reason) { - return NM_ACT_STAGE_RETURN_SUCCESS; + return NM_ACT_STAGE_RETURN_SUCCESS; } static void -lldp_init (NMDevice *self, gboolean restart) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if (priv->ifindex > 0 && lldp_rx_enabled (self)) { - gs_free_error GError *error = NULL; - - if (priv->lldp_listener) { - if ( restart - && nm_lldp_listener_is_running (priv->lldp_listener)) - nm_lldp_listener_stop (priv->lldp_listener); - } else { - priv->lldp_listener = nm_lldp_listener_new (); - g_signal_connect (priv->lldp_listener, - "notify::" NM_LLDP_LISTENER_NEIGHBORS, - G_CALLBACK (lldp_neighbors_changed), - self); - } - - if (!nm_lldp_listener_is_running (priv->lldp_listener)) { - if (nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), &error)) - _LOGD (LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener); - else { - _LOGD (LOGD_DEVICE, "LLDP listener %p could not be started: %s", - priv->lldp_listener, error->message); - } - } - } else { - if (priv->lldp_listener) - nm_lldp_listener_stop (priv->lldp_listener); - } +lldp_init(NMDevice *self, gboolean restart) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->ifindex > 0 && _prop_get_connection_lldp(self)) { + gs_free_error GError *error = NULL; + + if (priv->lldp_listener) { + if (restart && nm_lldp_listener_is_running(priv->lldp_listener)) + nm_lldp_listener_stop(priv->lldp_listener); + } else { + priv->lldp_listener = nm_lldp_listener_new(); + g_signal_connect(priv->lldp_listener, + "notify::" NM_LLDP_LISTENER_NEIGHBORS, + G_CALLBACK(lldp_neighbors_changed), + self); + } + + if (!nm_lldp_listener_is_running(priv->lldp_listener)) { + if (nm_lldp_listener_start(priv->lldp_listener, nm_device_get_ifindex(self), &error)) + _LOGD(LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener); + else { + _LOGD(LOGD_DEVICE, + "LLDP listener %p could not be started: %s", + priv->lldp_listener, + error->message); + } + } + } else { + if (priv->lldp_listener) + nm_lldp_listener_stop(priv->lldp_listener); + } } /* set-mode can be: @@ -7205,131 +8178,130 @@ lldp_init (NMDevice *self, gboolean restart) * you care about that. */ static void -_routing_rules_sync (NMDevice *self, - NMTernary set_mode) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPRulesManager *rules_manager = nm_netns_get_rules_manager (nm_device_get_netns (self)); - NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); - gboolean untrack_only_dirty = FALSE; - gboolean keep_deleted_rules; - gpointer user_tag_1; - gpointer user_tag_2; - - /* take two arbitrary user-tag pointers that belong to @self. */ - user_tag_1 = &priv->v4_route_table; - user_tag_2 = &priv->v6_route_table; - - if (set_mode == NM_TERNARY_TRUE) { - NMConnection *applied_connection; - NMSettingIPConfig *s_ip; - guint i, num; - int is_ipv4; - - untrack_only_dirty = TRUE; - nmp_rules_manager_set_dirty (rules_manager, user_tag_1); - if (klass->get_extra_rules) - nmp_rules_manager_set_dirty (rules_manager, user_tag_2); - - applied_connection = nm_device_get_applied_connection (self); - - for (is_ipv4 = 0; applied_connection && is_ipv4 < 2; is_ipv4++) { - int addr_family = is_ipv4 ? AF_INET : AF_INET6; - - s_ip = nm_connection_get_setting_ip_config (applied_connection, addr_family); - if (!s_ip) - continue; - - num = nm_setting_ip_config_get_num_routing_rules (s_ip); - for (i = 0; i < num; i++) { - NMPlatformRoutingRule plrule; - NMIPRoutingRule *rule; - - rule = nm_setting_ip_config_get_routing_rule (s_ip, i); - nm_ip_routing_rule_to_platform (rule, &plrule); - - /* We track this rule, but we also make it explicitly not weakly-tracked - * (meaning to untrack NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG at - * the same time). */ - nmp_rules_manager_track (rules_manager, - &plrule, - 10, - user_tag_1, - NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); - } - } - - if (klass->get_extra_rules) { - gs_unref_ptrarray GPtrArray *extra_rules = NULL; - - extra_rules = klass->get_extra_rules (self); - if (extra_rules) { - for (i = 0; i < extra_rules->len; i++) { - nmp_rules_manager_track (rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE (extra_rules->pdata[i]), - 10, - user_tag_2, - NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); - } - } - } - } - - nmp_rules_manager_untrack_all (rules_manager, user_tag_1, !untrack_only_dirty); - if (klass->get_extra_rules) - nmp_rules_manager_untrack_all (rules_manager, user_tag_2, !untrack_only_dirty); - - keep_deleted_rules = FALSE; - if (set_mode == NM_TERNARY_DEFAULT) { - /* when exiting NM, we leave the device up and the rules configured. - * We just all nmp_rules_manager_sync() to forget about the synced rules, - * but we don't actually delete them. - * - * FIXME: that is a problem after restart of NetworkManager, because these - * rules will look like externally added, and NM will no longer remove - * them. - * To fix that, we could during "assume" mark the rules of the profile - * as owned (and "added" by the device). The problem with that is that it - * wouldn't cover rules that devices add by internal decision (not because - * of a setting in the profile, e.g. WireGuard could setup policy routing). - * Maybe it would be better to remember these orphaned rules at exit in a - * file and track them after restart again. */ - keep_deleted_rules = TRUE; - } - nmp_rules_manager_sync (rules_manager, keep_deleted_rules); +_routing_rules_sync(NMDevice *self, NMTernary set_mode) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMPRulesManager *rules_manager = nm_netns_get_rules_manager(nm_device_get_netns(self)); + NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); + gboolean untrack_only_dirty = FALSE; + gboolean keep_deleted_rules; + gpointer user_tag_1; + gpointer user_tag_2; + + /* take two arbitrary user-tag pointers that belong to @self. */ + user_tag_1 = &priv->v4_route_table; + user_tag_2 = &priv->v6_route_table; + + if (set_mode == NM_TERNARY_TRUE) { + NMConnection * applied_connection; + NMSettingIPConfig *s_ip; + guint i, num; + int is_ipv4; + + untrack_only_dirty = TRUE; + nmp_rules_manager_set_dirty(rules_manager, user_tag_1); + if (klass->get_extra_rules) + nmp_rules_manager_set_dirty(rules_manager, user_tag_2); + + applied_connection = nm_device_get_applied_connection(self); + + for (is_ipv4 = 0; applied_connection && is_ipv4 < 2; is_ipv4++) { + int addr_family = is_ipv4 ? AF_INET : AF_INET6; + + s_ip = nm_connection_get_setting_ip_config(applied_connection, addr_family); + if (!s_ip) + continue; + + num = nm_setting_ip_config_get_num_routing_rules(s_ip); + for (i = 0; i < num; i++) { + NMPlatformRoutingRule plrule; + NMIPRoutingRule * rule; + + rule = nm_setting_ip_config_get_routing_rule(s_ip, i); + nm_ip_routing_rule_to_platform(rule, &plrule); + + /* We track this rule, but we also make it explicitly not weakly-tracked + * (meaning to untrack NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG at + * the same time). */ + nmp_rules_manager_track(rules_manager, + &plrule, + 10, + user_tag_1, + NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + } + } + + if (klass->get_extra_rules) { + gs_unref_ptrarray GPtrArray *extra_rules = NULL; + + extra_rules = klass->get_extra_rules(self); + if (extra_rules) { + for (i = 0; i < extra_rules->len; i++) { + nmp_rules_manager_track(rules_manager, + NMP_OBJECT_CAST_ROUTING_RULE(extra_rules->pdata[i]), + 10, + user_tag_2, + NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + } + } + } + } + + nmp_rules_manager_untrack_all(rules_manager, user_tag_1, !untrack_only_dirty); + if (klass->get_extra_rules) + nmp_rules_manager_untrack_all(rules_manager, user_tag_2, !untrack_only_dirty); + + keep_deleted_rules = FALSE; + if (set_mode == NM_TERNARY_DEFAULT) { + /* when exiting NM, we leave the device up and the rules configured. + * We just all nmp_rules_manager_sync() to forget about the synced rules, + * but we don't actually delete them. + * + * FIXME: that is a problem after restart of NetworkManager, because these + * rules will look like externally added, and NM will no longer remove + * them. + * To fix that, we could during "assume" mark the rules of the profile + * as owned (and "added" by the device). The problem with that is that it + * wouldn't cover rules that devices add by internal decision (not because + * of a setting in the profile, e.g. WireGuard could setup policy routing). + * Maybe it would be better to remember these orphaned rules at exit in a + * file and track them after restart again. */ + keep_deleted_rules = TRUE; + } + nmp_rules_manager_sync(rules_manager, keep_deleted_rules); } static gboolean -tc_commit (NMDevice *self) +tc_commit(NMDevice *self) { - NMConnection *connection = NULL; - gs_unref_ptrarray GPtrArray *qdiscs = NULL; - gs_unref_ptrarray GPtrArray *tfilters = NULL; - NMSettingTCConfig *s_tc = NULL; - NMPlatform *platform; - int ip_ifindex; + NMConnection * connection = NULL; + gs_unref_ptrarray GPtrArray *qdiscs = NULL; + gs_unref_ptrarray GPtrArray *tfilters = NULL; + NMSettingTCConfig * s_tc = NULL; + NMPlatform * platform; + int ip_ifindex; - platform = nm_device_get_platform (self); - connection = nm_device_get_applied_connection (self); - if (connection) - s_tc = nm_connection_get_setting_tc_config (connection); + platform = nm_device_get_platform(self); + connection = nm_device_get_applied_connection(self); + if (connection) + s_tc = nm_connection_get_setting_tc_config(connection); - ip_ifindex = nm_device_get_ip_ifindex (self); - if (!ip_ifindex) - return s_tc == NULL; + ip_ifindex = nm_device_get_ip_ifindex(self); + if (!ip_ifindex) + return s_tc == NULL; - if (s_tc) { - qdiscs = nm_utils_qdiscs_from_tc_setting (platform, s_tc, ip_ifindex); - tfilters = nm_utils_tfilters_from_tc_setting (platform, s_tc, ip_ifindex); - } + if (s_tc) { + qdiscs = nm_utils_qdiscs_from_tc_setting(platform, s_tc, ip_ifindex); + tfilters = nm_utils_tfilters_from_tc_setting(platform, s_tc, ip_ifindex); + } - if (!nm_platform_qdisc_sync (platform, ip_ifindex, qdiscs)) - return FALSE; + if (!nm_platform_qdisc_sync(platform, ip_ifindex, qdiscs)) + return FALSE; - if (!nm_platform_tfilter_sync (platform, ip_ifindex, tfilters)) - return FALSE; + if (!nm_platform_tfilter_sync(platform, ip_ifindex, tfilters)) + return FALSE; - return TRUE; + return TRUE; } /* @@ -7340,202 +8312,176 @@ tc_commit (NMDevice *self) * */ static void -activate_stage2_device_config (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceClass *klass; - NMActStageReturn ret; - gboolean no_firmware = FALSE; - CList *iter; - - nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); - - if (!nm_device_sys_iface_state_is_external_or_assume (self)) - _ethtool_state_set (self); - - if (!nm_device_sys_iface_state_is_external_or_assume (self)) { - if (!tc_commit (self)) { - _LOGW (LOGD_IP6, "failed applying traffic control rules"); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - } - - _routing_rules_sync (self, NM_TERNARY_TRUE); - - if (!nm_device_sys_iface_state_is_external_or_assume (self)) { - if (!nm_device_bring_up (self, FALSE, &no_firmware)) { - nm_device_state_changed (self, - NM_DEVICE_STATE_FAILED, - no_firmware - ? NM_DEVICE_STATE_REASON_FIRMWARE_MISSING - : NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - } - - klass = NM_DEVICE_GET_CLASS (self); - if ( klass->act_stage2_config_also_for_external_or_assume - || !nm_device_sys_iface_state_is_external_or_assume (self)) { - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - - ret = klass->act_stage2_config (self, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - return; - if (ret != NM_ACT_STAGE_RETURN_SUCCESS) { - nm_assert (ret == NM_ACT_STAGE_RETURN_FAILURE); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); - return; - } - } - - /* If we have slaves that aren't yet enslaved, do that now */ - c_list_for_each (iter, &priv->slaves) { - SlaveInfo *info = c_list_entry (iter, SlaveInfo, lst_slave); - NMDeviceState slave_state = nm_device_get_state (info->slave); - - if (slave_state == NM_DEVICE_STATE_IP_CONFIG) - nm_device_master_enslave_slave (self, info->slave, nm_device_get_applied_connection (info->slave)); - else if ( priv->act_request.obj - && nm_device_sys_iface_state_is_external (self) - && slave_state <= NM_DEVICE_STATE_DISCONNECTED) - nm_device_queue_recheck_assume (info->slave); - } - - lldp_init (self, TRUE); - - nm_device_activate_schedule_stage3_ip_config_start (self); +activate_stage2_device_config(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceClass * klass; + NMActStageReturn ret; + gboolean no_firmware = FALSE; + CList * iter; + + nm_device_state_changed(self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); + + if (!nm_device_sys_iface_state_is_external_or_assume(self)) + _ethtool_state_set(self); + + if (!nm_device_sys_iface_state_is_external_or_assume(self)) { + if (!tc_commit(self)) { + _LOGW(LOGD_IP6, "failed applying traffic control rules"); + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return; + } + } + + _routing_rules_sync(self, NM_TERNARY_TRUE); + + if (!nm_device_sys_iface_state_is_external_or_assume(self)) { + if (!nm_device_bring_up(self, FALSE, &no_firmware)) { + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + no_firmware ? NM_DEVICE_STATE_REASON_FIRMWARE_MISSING + : NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return; + } + } + + klass = NM_DEVICE_GET_CLASS(self); + if (klass->act_stage2_config_also_for_external_or_assume + || !nm_device_sys_iface_state_is_external_or_assume(self)) { + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + + ret = klass->act_stage2_config(self, &failure_reason); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) + return; + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) { + nm_assert(ret == NM_ACT_STAGE_RETURN_FAILURE); + nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); + return; + } + } + + /* If we have slaves that aren't yet enslaved, do that now */ + c_list_for_each (iter, &priv->slaves) { + SlaveInfo * info = c_list_entry(iter, SlaveInfo, lst_slave); + NMDeviceState slave_state = nm_device_get_state(info->slave); + + if (slave_state == NM_DEVICE_STATE_IP_CONFIG) + nm_device_master_enslave_slave(self, + info->slave, + nm_device_get_applied_connection(info->slave)); + else if (priv->act_request.obj && nm_device_sys_iface_state_is_external(self) + && slave_state <= NM_DEVICE_STATE_DISCONNECTED) + nm_device_queue_recheck_assume(info->slave); + } + + lldp_init(self, TRUE); + + nm_device_activate_schedule_stage3_ip_config_start(self); } void -nm_device_activate_schedule_stage2_device_config (NMDevice *self, - gboolean do_sync) +nm_device_activate_schedule_stage2_device_config(NMDevice *self, gboolean do_sync) { - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - if (!do_sync) { - activation_source_schedule (self, activate_stage2_device_config, AF_INET); - return; - } + if (!do_sync) { + activation_source_schedule(self, activate_stage2_device_config, AF_INET); + return; + } - activation_source_invoke_sync (self, activate_stage2_device_config, AF_INET); + activation_source_invoke_sync(self, activate_stage2_device_config, AF_INET); } void -nm_device_ip_method_failed (NMDevice *self, - int addr_family, - NMDeviceStateReason reason) +nm_device_ip_method_failed(NMDevice *self, int addr_family, NMDeviceStateReason reason) { - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - _set_ip_state (self, addr_family, NM_DEVICE_IP_STATE_FAIL); + _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_FAIL); - if (get_ip_config_may_fail (self, addr_family)) - check_ip_state (self, FALSE, (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG)); - else - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + if (get_ip_config_may_fail(self, addr_family)) + check_ip_state(self, FALSE, (nm_device_get_state(self) == NM_DEVICE_STATE_IP_CONFIG)); + else + nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, reason); } /*****************************************************************************/ -/* IPv4 DAD stuff */ - -static guint -get_ipv4_dad_timeout (NMDevice *self) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip4 = NULL; - int timeout = -1; - - connection = nm_device_get_applied_connection (self); - if (connection) - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4) - timeout = nm_setting_ip_config_get_dad_timeout (s_ip4); - if (timeout >= 0) - return timeout; - - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv4.dad-timeout"), - self, - 0, - NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, - 0); -} static void -acd_data_destroy (gpointer ptr) +acd_data_destroy(gpointer ptr) { - AcdData *data = ptr; - int i; + AcdData *data = ptr; + int i; - for (i = 0; data->configs && data->configs[i]; i++) - g_object_unref (data->configs[i]); - g_free (data->configs); - g_slice_free (AcdData, data); + for (i = 0; data->configs && data->configs[i]; i++) + g_object_unref(data->configs[i]); + g_free(data->configs); + g_slice_free(AcdData, data); } static void -ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean success) +ipv4_manual_method_apply(NMDevice *self, NMIP4Config **configs, gboolean success) { - NMConnection *connection; - const char *method; + NMConnection *connection; + const char * method; - connection = nm_device_get_applied_connection (self); - nm_assert (connection); - method = nm_utils_get_ip_config_method (connection, AF_INET); - nm_assert (NM_IN_STRSET (method, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NM_SETTING_IP4_CONFIG_METHOD_AUTO)); + connection = nm_device_get_applied_connection(self); + nm_assert(connection); + method = nm_utils_get_ip_config_method(connection, AF_INET); + nm_assert(NM_IN_STRSET(method, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP4_CONFIG_METHOD_AUTO)); - if (!success) { - nm_device_ip_method_failed (self, AF_INET, - NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); - return; - } + if (!success) { + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); + return; + } - if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) - nm_device_activate_schedule_ip_config_result (self, AF_INET, NULL); - else { - if (NM_DEVICE_GET_PRIVATE (self)->ip_state_4 != NM_DEVICE_IP_STATE_DONE) - ip_config_merge_and_apply (self, AF_INET, TRUE); - } + if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + nm_device_activate_schedule_ip_config_result(self, AF_INET, NULL); + else { + if (NM_DEVICE_GET_PRIVATE(self)->ip_state_4 != NM_DEVICE_IP_STATE_DONE) + ip_config_merge_and_apply(self, AF_INET, TRUE); + } } static void -acd_manager_probe_terminated (NMAcdManager *acd_manager, gpointer user_data) +acd_manager_probe_terminated(NMAcdManager *acd_manager, gpointer user_data) { - AcdData *data = user_data; - NMDevice *self; - NMDevicePrivate *priv; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *address; - gboolean result, success = TRUE; - int i; + AcdData * data = user_data; + NMDevice * self; + NMDevicePrivate * priv; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Address *address; + gboolean result, success = TRUE; + int i; - g_assert (data); - self = data->device; - priv = NM_DEVICE_GET_PRIVATE (self); + g_assert(data); + self = data->device; + priv = NM_DEVICE_GET_PRIVATE(self); - for (i = 0; data->configs && data->configs[i]; i++) { - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, data->configs[i], &address) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + for (i = 0; data->configs && data->configs[i]; i++) { + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, data->configs[i], &address) { + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - result = nm_acd_manager_check_address (acd_manager, address->address); - success &= result; + result = nm_acd_manager_check_address(acd_manager, address->address); + success &= result; - _NMLOG (result ? LOGL_DEBUG : LOGL_WARN, - LOGD_DEVICE, - "IPv4 DAD result: address %s is %s", - _nm_utils_inet4_ntop (address->address, sbuf), - result ? "unique" : "duplicate"); - } - } + _NMLOG(result ? LOGL_DEBUG : LOGL_WARN, + LOGD_DEVICE, + "IPv4 DAD result: address %s is %s", + _nm_utils_inet4_ntop(address->address, sbuf), + result ? "unique" : "duplicate"); + } + } - data->callback (self, data->configs, success); + data->callback(self, data->configs, success); - priv->acd.dad_list = g_slist_remove (priv->acd.dad_list, acd_manager); - nm_acd_manager_free (acd_manager); + priv->acd.dad_list = g_slist_remove(priv->acd.dad_list, acd_manager); + nm_acd_manager_free(acd_manager); } /** @@ -7549,2123 +8495,1381 @@ acd_manager_probe_terminated (NMAcdManager *acd_manager, gpointer user_data) * be started. @configs will be unreferenced after @cb has been called. */ static void -ipv4_dad_start (NMDevice *self, NMIP4Config **configs, AcdCallback cb) -{ - static const NMAcdCallbacks acd_callbacks = { - .probe_terminated_callback = acd_manager_probe_terminated, - .user_data_destroy = acd_data_destroy, - }; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMAcdManager *acd_manager; - const NMPlatformIP4Address *address; - NMDedupMultiIter ipconf_iter; - AcdData *data; - guint timeout; - gboolean addr_found; - int r; - const guint8 *hwaddr_arr; - size_t length; - guint i; - - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (configs); - g_return_if_fail (cb); - - for (i = 0, addr_found = FALSE; configs[i]; i++) { - if (nm_ip4_config_get_num_addresses (configs[i]) > 0) { - addr_found = TRUE; - break; - } - } - - timeout = get_ipv4_dad_timeout (self); - hwaddr_arr = nm_platform_link_get_address (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - &length); - - if ( !timeout - || !hwaddr_arr - || !addr_found - || length != ETH_ALEN - || nm_device_sys_iface_state_is_external_or_assume (self)) { - - /* DAD not needed, signal success */ - cb (self, configs, TRUE); - - for (i = 0; configs[i]; i++) - g_object_unref (configs[i]); - g_free (configs); - - return; - } - - data = g_slice_new0 (AcdData); - data->configs = configs; - data->callback = cb; - data->device = self; - - acd_manager = nm_acd_manager_new (nm_device_get_ip_ifindex (self), - hwaddr_arr, - length, - &acd_callbacks, - data); - priv->acd.dad_list = g_slist_append (priv->acd.dad_list, acd_manager); - - for (i = 0; configs[i]; i++) { - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, configs[i], &address) - nm_acd_manager_add_address (acd_manager, address->address); - } - - r = nm_acd_manager_start_probe (acd_manager, timeout); - if (r < 0) { - _LOGW (LOGD_DEVICE, "acd probe failed"); - - /* DAD could not be started, signal success */ - cb (self, configs, TRUE); - - priv->acd.dad_list = g_slist_remove (priv->acd.dad_list, acd_manager); - nm_acd_manager_free (acd_manager); - } +ipv4_dad_start(NMDevice *self, NMIP4Config **configs, AcdCallback cb) +{ + static const NMAcdCallbacks acd_callbacks = { + .probe_terminated_callback = acd_manager_probe_terminated, + .user_data_destroy = acd_data_destroy, + }; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMAcdManager * acd_manager; + const NMPlatformIP4Address *address; + NMDedupMultiIter ipconf_iter; + AcdData * data; + guint timeout; + gboolean addr_found; + int r; + const guint8 * hwaddr_arr; + size_t length; + guint i; + + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(configs); + g_return_if_fail(cb); + + for (i = 0, addr_found = FALSE; configs[i]; i++) { + if (nm_ip4_config_get_num_addresses(configs[i]) > 0) { + addr_found = TRUE; + break; + } + } + + timeout = _prop_get_ipv4_dad_timeout(self); + hwaddr_arr = nm_platform_link_get_address(nm_device_get_platform(self), + nm_device_get_ip_ifindex(self), + &length); + + if (!timeout || !hwaddr_arr || !addr_found || length != ETH_ALEN + || nm_device_sys_iface_state_is_external_or_assume(self)) { + /* DAD not needed, signal success */ + cb(self, configs, TRUE); + + for (i = 0; configs[i]; i++) + g_object_unref(configs[i]); + g_free(configs); + + return; + } + + data = g_slice_new0(AcdData); + data->configs = configs; + data->callback = cb; + data->device = self; + + acd_manager = nm_acd_manager_new(nm_device_get_ip_ifindex(self), + hwaddr_arr, + length, + &acd_callbacks, + data); + priv->acd.dad_list = g_slist_append(priv->acd.dad_list, acd_manager); + + for (i = 0; configs[i]; i++) { + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, configs[i], &address) + nm_acd_manager_add_address(acd_manager, address->address); + } + + r = nm_acd_manager_start_probe(acd_manager, timeout); + if (r < 0) { + _LOGW(LOGD_DEVICE, "acd probe failed"); + + /* DAD could not be started, signal success */ + cb(self, configs, TRUE); + + priv->acd.dad_list = g_slist_remove(priv->acd.dad_list, acd_manager); + nm_acd_manager_free(acd_manager); + } } /*****************************************************************************/ /* IPv4LL stuff */ static void -ipv4ll_cleanup (NMDevice *self) +ipv4ll_cleanup(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->ipv4ll) { - sd_ipv4ll_set_callback (priv->ipv4ll, NULL, NULL); - sd_ipv4ll_stop (priv->ipv4ll); - priv->ipv4ll = sd_ipv4ll_unref (priv->ipv4ll); - } + if (priv->ipv4ll) { + sd_ipv4ll_set_callback(priv->ipv4ll, NULL, NULL); + sd_ipv4ll_stop(priv->ipv4ll); + priv->ipv4ll = sd_ipv4ll_unref(priv->ipv4ll); + } - nm_clear_g_source (&priv->ipv4ll_timeout); + nm_clear_g_source(&priv->ipv4ll_timeout); } static NMIP4Config * -ipv4ll_get_ip4_config (NMDevice *self, guint32 lla) +ipv4ll_get_ip4_config(NMDevice *self, guint32 lla) { - NMIP4Config *config = NULL; - NMPlatformIP4Address address; - NMPlatformIP4Route route; + NMIP4Config * config = NULL; + NMPlatformIP4Address address; + NMPlatformIP4Route route; - config = nm_device_ip4_config_new (self); - g_assert (config); + config = nm_device_ip4_config_new(self); + g_assert(config); - memset (&address, 0, sizeof (address)); - nm_platform_ip4_address_set_addr (&address, lla, 16); - address.addr_source = NM_IP_CONFIG_SOURCE_IP4LL; - nm_ip4_config_add_address (config, &address); + memset(&address, 0, sizeof(address)); + nm_platform_ip4_address_set_addr(&address, lla, 16); + address.addr_source = NM_IP_CONFIG_SOURCE_IP4LL; + nm_ip4_config_add_address(config, &address); - /* Add a multicast route for link-local connections: destination= 224.0.0.0, netmask=240.0.0.0 */ - memset (&route, 0, sizeof (route)); - route.network = htonl (0xE0000000L); - route.plen = 4; - route.rt_source = NM_IP_CONFIG_SOURCE_IP4LL; - route.table_coerced = nm_platform_route_table_coerce (nm_device_get_route_table (self, AF_INET)); - route.metric = nm_device_get_route_metric (self, AF_INET); - nm_ip4_config_add_route (config, &route, NULL); + /* Add a multicast route for link-local connections: destination= 224.0.0.0, netmask=240.0.0.0 */ + memset(&route, 0, sizeof(route)); + route.network = htonl(0xE0000000L); + route.plen = 4; + route.rt_source = NM_IP_CONFIG_SOURCE_IP4LL; + route.table_coerced = nm_platform_route_table_coerce(nm_device_get_route_table(self, AF_INET)); + route.metric = nm_device_get_route_metric(self, AF_INET); + nm_ip4_config_add_route(config, &route, NULL); - return config; + return config; } -#define IPV4LL_NETWORK (htonl (0xA9FE0000L)) -#define IPV4LL_NETMASK (htonl (0xFFFF0000L)) - static void -nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data) -{ - NMDevice *self = data; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - struct in_addr address; - NMIP4Config *config; - int r; - - if (priv->act_request.obj == NULL) - return; - - nm_assert (nm_streq (nm_device_get_effective_ip_config_method (self, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)); - - switch (event) { - case SD_IPV4LL_EVENT_BIND: - r = sd_ipv4ll_get_address (ll, &address); - if (r < 0) { - _LOGE (LOGD_AUTOIP4, "invalid IPv4 link-local address received, error %d.", r); - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); - return; - } - - if ((address.s_addr & IPV4LL_NETMASK) != IPV4LL_NETWORK) { - _LOGE (LOGD_AUTOIP4, "invalid address %08x received (not link-local).", address.s_addr); - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_ERROR); - return; - } - - config = ipv4ll_get_ip4_config (self, address.s_addr); - if (config == NULL) { - _LOGE (LOGD_AUTOIP4, "failed to get IPv4LL config"); - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); - return; - } - - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { - nm_clear_g_source (&priv->ipv4ll_timeout); - nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (config)); - } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - applied_config_init (&priv->dev_ip_config_4, config); - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) { - _LOGE (LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); - } - } else - g_assert_not_reached (); - - g_object_unref (config); - break; - default: - _LOGW (LOGD_AUTOIP4, "IPv4LL address no longer valid after event %d.", event); - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); - } +nm_device_handle_ipv4ll_event(sd_ipv4ll *ll, int event, void *data) +{ + NMDevice * self = data; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + struct in_addr address; + NMIP4Config * config; + int r; + + if (priv->act_request.obj == NULL) + return; + + nm_assert(nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET), + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)); + + switch (event) { + case SD_IPV4LL_EVENT_BIND: + r = sd_ipv4ll_get_address(ll, &address); + if (r < 0) { + _LOGE(LOGD_AUTOIP4, "invalid IPv4 link-local address received, error %d.", r); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); + return; + } + + if (!nm_utils_ip4_address_is_link_local(address.s_addr)) { + _LOGE(LOGD_AUTOIP4, "invalid address %08x received (not link-local).", address.s_addr); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_ERROR); + return; + } + + config = ipv4ll_get_ip4_config(self, address.s_addr); + if (config == NULL) { + _LOGE(LOGD_AUTOIP4, "failed to get IPv4LL config"); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); + return; + } + + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { + nm_clear_g_source(&priv->ipv4ll_timeout); + nm_device_activate_schedule_ip_config_result(self, AF_INET, NM_IP_CONFIG_CAST(config)); + } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { + applied_config_init(&priv->dev_ip_config_4, config); + if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { + _LOGE(LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); + } + } else + g_assert_not_reached(); + + g_object_unref(config); + break; + default: + _LOGW(LOGD_AUTOIP4, "IPv4LL address no longer valid after event %d.", event); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); + } } static gboolean -ipv4ll_timeout_cb (gpointer user_data) +ipv4ll_timeout_cb(gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->ipv4ll_timeout) { - _LOGI (LOGD_AUTOIP4, "IPv4LL configuration timed out."); - priv->ipv4ll_timeout = 0; - ipv4ll_cleanup (self); + if (priv->ipv4ll_timeout) { + _LOGI(LOGD_AUTOIP4, "IPv4LL configuration timed out."); + priv->ipv4ll_timeout = 0; + ipv4ll_cleanup(self); - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_timeout (self, AF_INET); - } + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) + nm_device_activate_schedule_ip_config_timeout(self, AF_INET); + } - return FALSE; + return FALSE; } static NMActStageReturn -ipv4ll_start (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const struct ether_addr *addr; - int ifindex, r; - size_t addr_len; - - ipv4ll_cleanup (self); - - r = sd_ipv4ll_new (&priv->ipv4ll); - if (r < 0) { - _LOGE (LOGD_AUTOIP4, "IPv4LL: new() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_attach_event (priv->ipv4ll, NULL, 0); - if (r < 0) { - _LOGE (LOGD_AUTOIP4, "IPv4LL: attach_event() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - ifindex = nm_device_get_ip_ifindex (self); - addr = nm_platform_link_get_address (nm_device_get_platform (self), ifindex, &addr_len); - if (!addr || addr_len != ETH_ALEN) { - _LOGE (LOGD_AUTOIP4, "IPv4LL: can't retrieve hardware address"); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_mac (priv->ipv4ll, addr); - if (r < 0) { - _LOGE (LOGD_AUTOIP4, "IPv4LL: set_mac() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_ifindex (priv->ipv4ll, ifindex); - if (r < 0) { - _LOGE (LOGD_AUTOIP4, "IPv4LL: set_ifindex() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_callback (priv->ipv4ll, nm_device_handle_ipv4ll_event, self); - if (r < 0) { - _LOGE (LOGD_AUTOIP4, "IPv4LL: set_callback() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_start (priv->ipv4ll); - if (r < 0) { - _LOGE (LOGD_AUTOIP4, "IPv4LL: start() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - _LOGI (LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started"); - - /* Start a timeout to bound the address attempt */ - priv->ipv4ll_timeout = g_timeout_add_seconds (20, ipv4ll_timeout_cb, self); - return NM_ACT_STAGE_RETURN_POSTPONE; +ipv4ll_start(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const struct ether_addr *addr; + int ifindex, r; + size_t addr_len; + + ipv4ll_cleanup(self); + + r = sd_ipv4ll_new(&priv->ipv4ll); + if (r < 0) { + _LOGE(LOGD_AUTOIP4, "IPv4LL: new() failed with error %d", r); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + r = sd_ipv4ll_attach_event(priv->ipv4ll, NULL, 0); + if (r < 0) { + _LOGE(LOGD_AUTOIP4, "IPv4LL: attach_event() failed with error %d", r); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + ifindex = nm_device_get_ip_ifindex(self); + addr = nm_platform_link_get_address(nm_device_get_platform(self), ifindex, &addr_len); + if (!addr || addr_len != ETH_ALEN) { + _LOGE(LOGD_AUTOIP4, "IPv4LL: can't retrieve hardware address"); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + r = sd_ipv4ll_set_mac(priv->ipv4ll, addr); + if (r < 0) { + _LOGE(LOGD_AUTOIP4, "IPv4LL: set_mac() failed with error %d", r); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + r = sd_ipv4ll_set_ifindex(priv->ipv4ll, ifindex); + if (r < 0) { + _LOGE(LOGD_AUTOIP4, "IPv4LL: set_ifindex() failed with error %d", r); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + r = sd_ipv4ll_set_callback(priv->ipv4ll, nm_device_handle_ipv4ll_event, self); + if (r < 0) { + _LOGE(LOGD_AUTOIP4, "IPv4LL: set_callback() failed with error %d", r); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + r = sd_ipv4ll_start(priv->ipv4ll); + if (r < 0) { + _LOGE(LOGD_AUTOIP4, "IPv4LL: start() failed with error %d", r); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + _LOGI(LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started"); + + /* Start a timeout to bound the address attempt */ + priv->ipv4ll_timeout = g_timeout_add_seconds(20, ipv4ll_timeout_cb, self); + return NM_ACT_STAGE_RETURN_POSTPONE; } /*****************************************************************************/ static void -ensure_con_ip_config (NMDevice *self, int addr_family) +ensure_con_ip_config(NMDevice *self, int addr_family) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMIPConfig *con_ip_config; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + const gboolean IS_IPv4 = (addr_family == AF_INET); + NMIPConfig * con_ip_config; - if (priv->con_ip_config_x[IS_IPv4]) - return; + if (priv->con_ip_config_x[IS_IPv4]) + return; - connection = nm_device_get_applied_connection (self); - if (!connection) - return; + connection = nm_device_get_applied_connection(self); + if (!connection) + return; - con_ip_config = nm_device_ip_config_new (self, addr_family); + con_ip_config = nm_device_ip_config_new(self, addr_family); - if (IS_IPv4) { - nm_ip4_config_merge_setting (NM_IP4_CONFIG (con_ip_config), - nm_connection_get_setting_ip4_config (connection), - _get_mdns (self), - _get_llmnr (self), - nm_device_get_route_table (self, addr_family), - nm_device_get_route_metric (self, addr_family)); - } else { - nm_ip6_config_merge_setting (NM_IP6_CONFIG (con_ip_config), - nm_connection_get_setting_ip6_config (connection), - nm_device_get_route_table (self, addr_family), - nm_device_get_route_metric (self, addr_family)); - } + if (IS_IPv4) { + nm_ip4_config_merge_setting(NM_IP4_CONFIG(con_ip_config), + nm_connection_get_setting_ip4_config(connection), + _prop_get_connection_mdns(self), + _prop_get_connection_llmnr(self), + nm_device_get_route_table(self, addr_family), + nm_device_get_route_metric(self, addr_family)); + } else { + nm_ip6_config_merge_setting(NM_IP6_CONFIG(con_ip_config), + nm_connection_get_setting_ip6_config(connection), + nm_device_get_route_table(self, addr_family), + nm_device_get_route_metric(self, addr_family)); + } - if (nm_device_sys_iface_state_is_external_or_assume (self)) { - /* For assumed connections ignore all addresses and routes. */ - nm_ip_config_reset_addresses (con_ip_config); - nm_ip_config_reset_routes (con_ip_config); - } + if (nm_device_sys_iface_state_is_external_or_assume(self)) { + /* For assumed connections ignore all addresses and routes. */ + nm_ip_config_reset_addresses(con_ip_config); + nm_ip_config_reset_routes(con_ip_config); + } - priv->con_ip_config_x[IS_IPv4] = con_ip_config; + priv->con_ip_config_x[IS_IPv4] = con_ip_config; } /*****************************************************************************/ -/* DHCPv4 stuff */ - -static guint32 -get_dhcp_timeout (NMDevice *self, int addr_family) -{ - NMDeviceClass *klass; - NMConnection *connection; - int timeout_i; - guint32 timeout; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert_addr_family (addr_family); - - connection = nm_device_get_applied_connection (self); - - timeout_i = nm_setting_ip_config_get_dhcp_timeout (nm_connection_get_setting_ip_config (connection, addr_family)); - nm_assert (timeout_i >= 0 && timeout_i <= G_MAXINT32); - - timeout = (guint32) timeout_i; - if (timeout) - goto out; - - timeout = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.dhcp-timeout") - : NM_CON_DEFAULT ("ipv6.dhcp-timeout"), - self, - 0, G_MAXINT32, 0); - if (timeout) - goto out; - - klass = NM_DEVICE_GET_CLASS (self); - if (klass->get_dhcp_timeout_for_device) { - timeout = klass->get_dhcp_timeout_for_device (self, addr_family); - if (timeout) - goto out; - } - - timeout = NM_DHCP_TIMEOUT_DEFAULT; - -out: - G_STATIC_ASSERT_EXPR (G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); - nm_assert (timeout > 0); - nm_assert (timeout <= G_MAXINT32); - return timeout; -} static void -dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) +dhcp4_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->dhcp_data_4.was_active = FALSE; - nm_clear_g_source (&priv->dhcp_data_4.grace_id); - priv->dhcp_data_4.grace_pending = FALSE; - nm_clear_g_free (&priv->dhcp4.pac_url); - nm_clear_g_free (&priv->dhcp4.root_path); + priv->dhcp_data_4.was_active = FALSE; + nm_clear_g_source(&priv->dhcp_data_4.grace_id); + priv->dhcp_data_4.grace_pending = FALSE; + nm_clear_g_free(&priv->dhcp4.pac_url); - if (priv->dhcp_data_4.client) { - /* Stop any ongoing DHCP transaction on this device */ - nm_clear_g_signal_handler (priv->dhcp_data_4.client, &priv->dhcp_data_4.state_sigid); + if (priv->dhcp_data_4.client) { + /* Stop any ongoing DHCP transaction on this device */ + nm_clear_g_signal_handler(priv->dhcp_data_4.client, &priv->dhcp_data_4.state_sigid); - if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE - || cleanup_type == CLEANUP_TYPE_REMOVED) - nm_dhcp_client_stop (priv->dhcp_data_4.client, release); + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) + nm_dhcp_client_stop(priv->dhcp_data_4.client, release); - g_clear_object (&priv->dhcp_data_4.client); - } + g_clear_object(&priv->dhcp_data_4.client); + } - if (priv->dhcp_data_4.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp_data_4.config); - _notify (self, PROP_DHCP4_CONFIG); - } + if (priv->dhcp_data_4.config) { + nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); + _notify(self, PROP_DHCP4_CONFIG); + } } static gboolean -ip_config_merge_and_apply (NMDevice *self, - int addr_family, - gboolean commit) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean success; - gs_unref_object NMIPConfig *composite = NULL; - NMIPConfig *config; - gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; - NMConnection *connection; - gboolean ignore_auto_routes = FALSE; - gboolean ignore_auto_dns = FALSE; - gboolean ignore_default_routes = FALSE; - GSList *iter; - const char *ip6_addr_gen_token = NULL; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - if (nm_device_sys_iface_state_is_external (self)) - commit = FALSE; - - connection = nm_device_get_applied_connection (self); - - /* Apply ignore-auto-routes and ignore-auto-dns settings */ - if (connection) { - NMSettingIPConfig *s_ip; - - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - if (s_ip) { - ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip); - ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip); - - /* if the connection has an explicit gateway, we also ignore - * the default routes from other sources. */ - ignore_default_routes = nm_setting_ip_config_get_never_default (s_ip) - || nm_setting_ip_config_get_gateway (s_ip); - - if (!IS_IPv4) { - NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG (s_ip); - - if (nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) - ip6_addr_gen_token = nm_setting_ip6_config_get_token (s_ip6); - } - } - } - - composite = nm_device_ip_config_new (self, addr_family); - - if (!IS_IPv4) { - nm_ip6_config_set_privacy (NM_IP6_CONFIG (composite), - priv->ndisc - ? priv->ndisc_use_tempaddr - : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - } - - init_ip_config_dns_priority (self, composite); - - if (commit) { - if (priv->queued_ip_config_id_x[IS_IPv4]) - update_ext_ip_config (self, addr_family, FALSE); - ensure_con_ip_config (self, addr_family); - } - - if (!IS_IPv4) { - if ( commit - && priv->ipv6ll_has) { - const NMPlatformIP6Address ll_a = { - .address = priv->ipv6ll_addr, - .plen = 64, - .addr_source = NM_IP_CONFIG_SOURCE_IP6LL, - }; - const NMPlatformIP6Route ll_r = { - .network.s6_addr16[0] = htons (0xfe80u), - .plen = 64, - .metric = nm_device_get_route_metric (self, addr_family), - .rt_source = NM_IP_CONFIG_SOURCE_IP6LL, - }; - - nm_assert (IN6_IS_ADDR_LINKLOCAL (&priv->ipv6ll_addr)); - - nm_ip6_config_add_address (NM_IP6_CONFIG (composite), &ll_a); - nm_ip6_config_add_route (NM_IP6_CONFIG (composite), &ll_r, NULL); - } - } - - if (commit) { - gboolean v; - - v = default_route_metric_penalty_detect (self, addr_family); - if (IS_IPv4) - priv->default_route_metric_penalty_ip4_has = v; - else - priv->default_route_metric_penalty_ip6_has = v; - } - - /* Merge all the IP configs into the composite config */ - - if (IS_IPv4) { - config = applied_config_get_current (&priv->dev_ip_config_4); - if (config) { - nm_ip4_config_merge (NM_IP4_CONFIG (composite), NM_IP4_CONFIG (config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get (self, addr_family)); - } - } - - if (!IS_IPv4) { - config = applied_config_get_current (&priv->ac_ip6_config); - if (config) { - nm_ip6_config_merge (NM_IP6_CONFIG (composite), NM_IP6_CONFIG (config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get (self, addr_family)); - } - } - - if (!IS_IPv4) { - config = applied_config_get_current (&priv->dhcp6.ip6_config); - if (config) { - nm_ip6_config_merge (NM_IP6_CONFIG (composite), NM_IP6_CONFIG (config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get (self, addr_family)); - } - } - - for (iter = priv->vpn_configs_x[IS_IPv4]; iter; iter = iter->next) - nm_ip_config_merge (composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0); - - if (priv->ext_ip_config_x[IS_IPv4]) - nm_ip_config_merge (composite, priv->ext_ip_config_x[IS_IPv4], NM_IP_CONFIG_MERGE_EXTERNAL, 0); - - /* Merge WWAN config *last* to ensure modem-given settings overwrite - * any external stuff set by pppd or other scripts. - */ - config = applied_config_get_current (&priv->dev2_ip_config_x[IS_IPv4]); - if (config) { - nm_ip_config_merge (composite, config, - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get (self, addr_family)); - } - - if (!IS_IPv4) { - if (priv->rt6_temporary_not_available) { - const NMPObject *o; - GHashTableIter hiter; - - g_hash_table_iter_init (&hiter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next (&hiter, (gpointer *) &o, NULL)) { - nm_ip6_config_add_route (NM_IP6_CONFIG (composite), - NMP_OBJECT_CAST_IP6_ROUTE (o), - NULL); - } - } - } - - /* Merge user overrides into the composite config. For assumed connections, - * con_ip_config_x is empty. */ - if (priv->con_ip_config_x[IS_IPv4]) { - nm_ip_config_merge (composite, priv->con_ip_config_x[IS_IPv4], NM_IP_CONFIG_MERGE_DEFAULT, - default_route_metric_penalty_get (self, addr_family)); - } - - if (commit) { - gboolean is_vrf; - - is_vrf = priv->master && nm_device_get_device_type (priv->master) == NM_DEVICE_TYPE_VRF; - - if (IS_IPv4) { - nm_ip4_config_add_dependent_routes (NM_IP4_CONFIG (composite), - nm_device_get_route_table (self, addr_family), - nm_device_get_route_metric (self, addr_family), - is_vrf, - &ip4_dev_route_blacklist); - } else { - nm_ip6_config_add_dependent_routes (NM_IP6_CONFIG (composite), - nm_device_get_route_table (self, addr_family), - nm_device_get_route_metric (self, addr_family), - is_vrf); - } - } - - if (IS_IPv4) { - if (commit) { - if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) - NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, NM_IP4_CONFIG (composite)); - } - } - - if (!IS_IPv4) { - NMUtilsIPv6IfaceId iid; - - if ( commit - && priv->ndisc_started - && ip6_addr_gen_token - && nm_utils_ipv6_interface_identifier_get_from_token (&iid, ip6_addr_gen_token)) { - set_ipv6_token (self, iid, ip6_addr_gen_token); - } - } - - success = nm_device_set_ip_config (self, addr_family, composite, commit, ip4_dev_route_blacklist); - if (commit) { - if (IS_IPv4) - priv->v4_commit_first_time = FALSE; - else - priv->v6_commit_first_time = FALSE; - } - - return success; +ip_config_merge_and_apply(NMDevice *self, int addr_family, gboolean commit) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean success; + gs_unref_object NMIPConfig *composite = NULL; + NMIPConfig * config; + gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; + NMConnection * connection; + gboolean ignore_auto_routes = FALSE; + gboolean ignore_auto_dns = FALSE; + gboolean ignore_default_routes = FALSE; + GSList * iter; + const char * ip6_addr_gen_token = NULL; + const gboolean IS_IPv4 = (addr_family == AF_INET); + + if (nm_device_sys_iface_state_is_external(self)) + commit = FALSE; + + connection = nm_device_get_applied_connection(self); + + /* Apply ignore-auto-routes and ignore-auto-dns settings */ + if (connection) { + NMSettingIPConfig *s_ip; + + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); + if (s_ip) { + ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes(s_ip); + ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns(s_ip); + + /* if the connection has an explicit gateway, we also ignore + * the default routes from other sources. */ + ignore_default_routes = nm_setting_ip_config_get_never_default(s_ip) + || nm_setting_ip_config_get_gateway(s_ip); + + if (!IS_IPv4) { + NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG(s_ip); + + if (nm_setting_ip6_config_get_addr_gen_mode(s_ip6) + == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) + ip6_addr_gen_token = nm_setting_ip6_config_get_token(s_ip6); + } + } + } + + composite = nm_device_ip_config_new(self, addr_family); + + if (!IS_IPv4) { + nm_ip6_config_set_privacy(NM_IP6_CONFIG(composite), + priv->ndisc ? priv->ndisc_use_tempaddr + : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + } + + init_ip_config_dns_priority(self, composite); + + if (commit) { + if (priv->queued_ip_config_id_x[IS_IPv4]) + update_ext_ip_config(self, addr_family, FALSE); + ensure_con_ip_config(self, addr_family); + } + + if (!IS_IPv4) { + if (commit && priv->ipv6ll_has) { + const NMPlatformIP6Address ll_a = { + .address = priv->ipv6ll_addr, + .plen = 64, + .addr_source = NM_IP_CONFIG_SOURCE_IP6LL, + }; + const NMPlatformIP6Route ll_r = { + .network.s6_addr16[0] = htons(0xfe80u), + .plen = 64, + .metric = nm_device_get_route_metric(self, addr_family), + .rt_source = NM_IP_CONFIG_SOURCE_IP6LL, + }; + + nm_assert(IN6_IS_ADDR_LINKLOCAL(&priv->ipv6ll_addr)); + + nm_ip6_config_add_address(NM_IP6_CONFIG(composite), &ll_a); + nm_ip6_config_add_route(NM_IP6_CONFIG(composite), &ll_r, NULL); + } + } + + if (commit) { + gboolean v; + + v = default_route_metric_penalty_detect(self, addr_family); + if (IS_IPv4) + priv->default_route_metric_penalty_ip4_has = v; + else + priv->default_route_metric_penalty_ip6_has = v; + } + + /* Merge all the IP configs into the composite config */ + + if (IS_IPv4) { + config = applied_config_get_current(&priv->dev_ip_config_4); + if (config) { + nm_ip4_config_merge( + NM_IP4_CONFIG(composite), + NM_IP4_CONFIG(config), + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get(self, addr_family)); + } + } + + if (!IS_IPv4) { + config = applied_config_get_current(&priv->ac_ip6_config); + if (config) { + nm_ip6_config_merge( + NM_IP6_CONFIG(composite), + NM_IP6_CONFIG(config), + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get(self, addr_family)); + } + } + + if (!IS_IPv4) { + config = applied_config_get_current(&priv->dhcp6.ip6_config); + if (config) { + nm_ip6_config_merge( + NM_IP6_CONFIG(composite), + NM_IP6_CONFIG(config), + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get(self, addr_family)); + } + } + + for (iter = priv->vpn_configs_x[IS_IPv4]; iter; iter = iter->next) + nm_ip_config_merge(composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0); + + if (priv->ext_ip_config_x[IS_IPv4]) + nm_ip_config_merge(composite, + priv->ext_ip_config_x[IS_IPv4], + NM_IP_CONFIG_MERGE_EXTERNAL, + 0); + + /* Merge WWAN config *last* to ensure modem-given settings overwrite + * any external stuff set by pppd or other scripts. + */ + config = applied_config_get_current(&priv->dev2_ip_config_x[IS_IPv4]); + if (config) { + nm_ip_config_merge(composite, + config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), + default_route_metric_penalty_get(self, addr_family)); + } + + if (!IS_IPv4) { + if (priv->rt6_temporary_not_available) { + const NMPObject *o; + GHashTableIter hiter; + + g_hash_table_iter_init(&hiter, priv->rt6_temporary_not_available); + while (g_hash_table_iter_next(&hiter, (gpointer *) &o, NULL)) { + nm_ip6_config_add_route(NM_IP6_CONFIG(composite), + NMP_OBJECT_CAST_IP6_ROUTE(o), + NULL); + } + } + } + + /* Merge user overrides into the composite config. For assumed connections, + * con_ip_config_x is empty. */ + if (priv->con_ip_config_x[IS_IPv4]) { + nm_ip_config_merge(composite, + priv->con_ip_config_x[IS_IPv4], + NM_IP_CONFIG_MERGE_DEFAULT, + default_route_metric_penalty_get(self, addr_family)); + } + + if (commit) { + gboolean is_vrf; + + is_vrf = priv->master && nm_device_get_device_type(priv->master) == NM_DEVICE_TYPE_VRF; + + if (IS_IPv4) { + nm_ip4_config_add_dependent_routes(NM_IP4_CONFIG(composite), + nm_device_get_route_table(self, addr_family), + nm_device_get_route_metric(self, addr_family), + is_vrf, + &ip4_dev_route_blacklist); + } else { + nm_ip6_config_add_dependent_routes(NM_IP6_CONFIG(composite), + nm_device_get_route_table(self, addr_family), + nm_device_get_route_metric(self, addr_family), + is_vrf); + } + } + + if (IS_IPv4) { + if (commit) { + if (NM_DEVICE_GET_CLASS(self)->ip4_config_pre_commit) + NM_DEVICE_GET_CLASS(self)->ip4_config_pre_commit(self, NM_IP4_CONFIG(composite)); + } + } + + if (!IS_IPv4) { + NMUtilsIPv6IfaceId iid; + + if (commit && priv->ndisc_started && ip6_addr_gen_token + && nm_utils_ipv6_interface_identifier_get_from_token(&iid, ip6_addr_gen_token)) { + set_ipv6_token(self, iid, ip6_addr_gen_token); + } + } + + success = + nm_device_set_ip_config(self, addr_family, composite, commit, ip4_dev_route_blacklist); + if (commit) { + if (IS_IPv4) + priv->v4_commit_first_time = FALSE; + else + priv->v6_commit_first_time = FALSE; + } + + return success; } static gboolean -dhcp4_lease_change (NMDevice *self, NMIP4Config *config, gboolean bound) +dhcp4_lease_change(NMDevice *self, NMIP4Config *config, gboolean bound) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gs_free_error GError *error = NULL; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gs_free_error GError *error = NULL; - g_return_val_if_fail (config, FALSE); + g_return_val_if_fail(config, FALSE); - applied_config_init (&priv->dev_ip_config_4, config); + applied_config_init(&priv->dev_ip_config_4, config); - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) { - _LOGW (LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); - return FALSE; - } + if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { + _LOGW(LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); + return FALSE; + } - /* TODO: we should perform DAD again whenever we obtain a - * new lease after an expiry. But what should we do if - * a duplicate address is detected? Fail the connection; - * restart DHCP; continue without an address? */ - if (bound && !nm_dhcp_client_accept (priv->dhcp_data_4.client, &error)) { - _LOGW (LOGD_DHCP4, "error accepting lease: %s", error->message); - return FALSE; - } + /* TODO: we should perform DAD again whenever we obtain a + * new lease after an expiry. But what should we do if + * a duplicate address is detected? Fail the connection; + * restart DHCP; continue without an address? */ + if (bound && !nm_dhcp_client_accept(priv->dhcp_data_4.client, &error)) { + _LOGW(LOGD_DHCP4, "error accepting lease: %s", error->message); + return FALSE; + } - nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP4_CHANGE, - self, - NULL, - NULL, NULL, NULL); + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP4_CHANGE, self, NULL, NULL, NULL, NULL); - return TRUE; + return TRUE; } static gboolean -dhcp_grace_period_expired (NMDevice *self, int addr_family) +dhcp_grace_period_expired(NMDevice *self, int addr_family) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); - priv->dhcp_data_x[IS_IPv4].grace_id = 0; - priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE; + priv->dhcp_data_x[IS_IPv4].grace_id = 0; + priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE; - _LOGI (LOGD_DHCP_from_addr_family (addr_family), - "DHCPv%c: grace period expired", - nm_utils_addr_family_to_char (addr_family)); + _LOGI(LOGD_DHCP_from_addr_family(addr_family), + "DHCPv%c: grace period expired", + nm_utils_addr_family_to_char(addr_family)); - nm_device_ip_method_failed (self, - addr_family, - NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - /* If the device didn't fail, the DHCP client will continue */ + nm_device_ip_method_failed(self, addr_family, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); + /* If the device didn't fail, the DHCP client will continue */ - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; } static gboolean -dhcp_grace_period_expired_4 (gpointer user_data) +dhcp_grace_period_expired_4(gpointer user_data) { - return dhcp_grace_period_expired (user_data, AF_INET); + return dhcp_grace_period_expired(user_data, AF_INET); } static gboolean -dhcp_grace_period_expired_6 (gpointer user_data) +dhcp_grace_period_expired_6(gpointer user_data) { - return dhcp_grace_period_expired (user_data, AF_INET6); + return dhcp_grace_period_expired(user_data, AF_INET6); } static gboolean -dhcp_grace_period_start (NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - guint32 timeout; - - /* In any other case (expired lease, assumed connection, etc.), - * wait for some time before failing the IP method. - */ - if (priv->dhcp_data_x[IS_IPv4].grace_pending) { - /* already pending. */ - return FALSE; - } - - /* Start a grace period equal to the DHCP timeout multiplied - * by a constant factor. */ - timeout = get_dhcp_timeout (self, addr_family); - if (timeout == NM_DHCP_TIMEOUT_INFINITY) - _LOGI (LOGD_DHCP_from_addr_family (addr_family), - "DHCPv%c: trying to acquire a new lease", - nm_utils_addr_family_to_char (addr_family)); - else { - timeout = dhcp_grace_period_from_timeout (timeout); - _LOGI (LOGD_DHCP_from_addr_family (addr_family), - "DHCPv%c: trying to acquire a new lease within %u seconds", - nm_utils_addr_family_to_char (addr_family), - timeout); - nm_assert (!priv->dhcp_data_x[IS_IPv4].grace_id); - priv->dhcp_data_x[IS_IPv4].grace_id = g_timeout_add_seconds (timeout, - IS_IPv4 - ? dhcp_grace_period_expired_4 - : dhcp_grace_period_expired_6, - self); - } - - priv->dhcp_data_x[IS_IPv4].grace_pending = TRUE; - - return TRUE; +dhcp_grace_period_start(NMDevice *self, int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); + guint32 timeout; + + /* In any other case (expired lease, assumed connection, etc.), + * wait for some time before failing the IP method. + */ + if (priv->dhcp_data_x[IS_IPv4].grace_pending) { + /* already pending. */ + return FALSE; + } + + /* Start a grace period equal to the DHCP timeout multiplied + * by a constant factor. */ + timeout = _prop_get_ipvx_dhcp_timeout(self, addr_family); + if (timeout == NM_DHCP_TIMEOUT_INFINITY) + _LOGI(LOGD_DHCP_from_addr_family(addr_family), + "DHCPv%c: trying to acquire a new lease", + nm_utils_addr_family_to_char(addr_family)); + else { + timeout = dhcp_grace_period_from_timeout(timeout); + _LOGI(LOGD_DHCP_from_addr_family(addr_family), + "DHCPv%c: trying to acquire a new lease within %u seconds", + nm_utils_addr_family_to_char(addr_family), + timeout); + nm_assert(!priv->dhcp_data_x[IS_IPv4].grace_id); + priv->dhcp_data_x[IS_IPv4].grace_id = g_timeout_add_seconds( + timeout, + IS_IPv4 ? dhcp_grace_period_expired_4 : dhcp_grace_period_expired_6, + self); + } + + priv->dhcp_data_x[IS_IPv4].grace_pending = TRUE; + + return TRUE; } static void -dhcp4_fail (NMDevice *self, NMDhcpState dhcp_state) +dhcp4_fail(NMDevice *self, NMDhcpState dhcp_state) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - _LOGD (LOGD_DHCP4, "DHCPv4 failed (ip_state %s, was_active %d)", - _ip_state_to_string (priv->ip_state_4), - priv->dhcp_data_4.was_active); + _LOGD(LOGD_DHCP4, + "DHCPv4 failed (ip_state %s, was_active %d)", + _ip_state_to_string(priv->ip_state_4), + priv->dhcp_data_4.was_active); - /* The client is always left running after a failure. */ + /* The client is always left running after a failure. */ - /* Nothing to do if we failed before... */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) - goto clear_config; + /* Nothing to do if we failed before... */ + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) + goto clear_config; - /* ... and also if there are static addresses configured - * on the interface. - */ - if ( priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - && priv->con_ip_config_4 - && nm_ip4_config_get_num_addresses (priv->con_ip_config_4) > 0) - goto clear_config; + /* ... and also if there are static addresses configured + * on the interface. + */ + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && priv->con_ip_config_4 + && nm_ip4_config_get_num_addresses(priv->con_ip_config_4) > 0) + goto clear_config; - /* Fail the method when one of the following is true: - * 1) the DHCP client terminated: it does not make sense to start a grace - * period without a client running; - * 2) we failed to get an initial lease AND the client was - * not active before. - */ - if ( dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp_data_4.was_active && priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF)) { - nm_device_activate_schedule_ip_config_timeout (self, AF_INET); - return; - } + /* Fail the method when one of the following is true: + * 1) the DHCP client terminated: it does not make sense to start a grace + * period without a client running; + * 2) we failed to get an initial lease AND the client was + * not active before. + */ + if (dhcp_state == NM_DHCP_STATE_TERMINATED + || (!priv->dhcp_data_4.was_active && priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF)) { + nm_device_activate_schedule_ip_config_timeout(self, AF_INET); + return; + } - if (dhcp_grace_period_start (self, AF_INET)) - goto clear_config; + if (dhcp_grace_period_start(self, AF_INET)) + goto clear_config; - return; + return; clear_config: - /* The previous configuration is no longer valid */ - if (priv->dhcp_data_4.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp_data_4.config); - priv->dhcp_data_4.config = nm_dhcp_config_new (AF_INET); - _notify (self, PROP_DHCP4_CONFIG); - } + /* The previous configuration is no longer valid */ + if (priv->dhcp_data_4.config) { + nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); + priv->dhcp_data_4.config = nm_dhcp_config_new(AF_INET); + _notify(self, PROP_DHCP4_CONFIG); + } } static void -dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success) +dhcp4_dad_cb(NMDevice *self, NMIP4Config **configs, gboolean success) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (success) { - nm_device_activate_schedule_ip_config_result (self, AF_INET, - NM_IP_CONFIG_CAST (configs[1])); - } else { - nm_dhcp_client_decline (priv->dhcp_data_4.client, "Address conflict detected", NULL); - nm_device_ip_method_failed (self, AF_INET, - NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); - } + if (success) { + nm_device_activate_schedule_ip_config_result(self, AF_INET, NM_IP_CONFIG_CAST(configs[1])); + } else { + nm_dhcp_client_decline(priv->dhcp_data_4.client, "Address conflict detected", NULL); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); + } } static void -dhcp4_state_changed (NMDhcpClient *client, - NMDhcpState state, - NMIP4Config *ip4_config, - GHashTable *options, - const char *event_id, - gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMIP4Config *manual, **configs; - NMConnection *connection; - - g_return_if_fail (nm_dhcp_client_get_addr_family (client) == AF_INET); - g_return_if_fail (!ip4_config || NM_IS_IP4_CONFIG (ip4_config)); - - _LOGD (LOGD_DHCP4, "new DHCPv4 client state %d", state); - - switch (state) { - case NM_DHCP_STATE_BOUND: - case NM_DHCP_STATE_EXTENDED: - if (!ip4_config) { - _LOGW (LOGD_DHCP4, "failed to get IPv4 config in response to DHCP event."); - dhcp4_fail (self, state); - break; - } - - nm_clear_g_source (&priv->dhcp_data_4.grace_id); - priv->dhcp_data_4.grace_pending = FALSE; - - /* After some failures, we have been able to renew the lease: - * update the ip state - */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_CONF); - - g_free (priv->dhcp4.pac_url); - priv->dhcp4.pac_url = g_strdup (g_hash_table_lookup (options, "wpad")); - nm_device_set_proxy_config (self, priv->dhcp4.pac_url); - - g_free (priv->dhcp4.root_path); - priv->dhcp4.root_path = g_strdup (g_hash_table_lookup (options, "root_path")); - - nm_dhcp_config_set_options (priv->dhcp_data_4.config, options); - _notify (self, PROP_DHCP4_CONFIG); - - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { - connection = nm_device_get_applied_connection (self); - g_assert (connection); - - manual = nm_device_ip4_config_new (self); - nm_ip4_config_merge_setting (manual, - nm_connection_get_setting_ip4_config (connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, - NM_SETTING_CONNECTION_LLMNR_DEFAULT, - nm_device_get_route_table (self, AF_INET), - nm_device_get_route_metric (self, AF_INET)); - - configs = g_new0 (NMIP4Config *, 3); - configs[0] = manual; - configs[1] = g_object_ref (ip4_config); - - ipv4_dad_start (self, configs, dhcp4_dad_cb); - } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - if (dhcp4_lease_change (self, ip4_config, - state == NM_DHCP_STATE_BOUND)) - nm_device_update_metered (self); - else - dhcp4_fail (self, state); - } - break; - case NM_DHCP_STATE_TIMEOUT: - dhcp4_fail (self, state); - break; - case NM_DHCP_STATE_EXPIRE: - /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) - break; - /* fall-through */ - case NM_DHCP_STATE_DONE: - case NM_DHCP_STATE_FAIL: - case NM_DHCP_STATE_TERMINATED: - dhcp4_fail (self, state); - break; - default: - break; - } +dhcp4_state_changed(NMDhcpClient *client, + NMDhcpState state, + NMIP4Config * ip4_config, + GHashTable * options, + gpointer user_data) +{ + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMIP4Config * manual, **configs; + NMConnection * connection; + + g_return_if_fail(nm_dhcp_client_get_addr_family(client) == AF_INET); + g_return_if_fail(!ip4_config || NM_IS_IP4_CONFIG(ip4_config)); + + _LOGD(LOGD_DHCP4, "new DHCPv4 client state %d", state); + + switch (state) { + case NM_DHCP_STATE_BOUND: + case NM_DHCP_STATE_EXTENDED: + if (!ip4_config) { + _LOGW(LOGD_DHCP4, "failed to get IPv4 config in response to DHCP event."); + dhcp4_fail(self, state); + break; + } + + nm_clear_g_source(&priv->dhcp_data_4.grace_id); + priv->dhcp_data_4.grace_pending = FALSE; + + /* After some failures, we have been able to renew the lease: + * update the ip state + */ + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_CONF); + + g_free(priv->dhcp4.pac_url); + priv->dhcp4.pac_url = g_strdup(g_hash_table_lookup(options, "wpad")); + nm_device_set_proxy_config(self, priv->dhcp4.pac_url); + + nm_dhcp_config_set_options(priv->dhcp_data_4.config, options); + _notify(self, PROP_DHCP4_CONFIG); + + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { + connection = nm_device_get_applied_connection(self); + g_assert(connection); + + manual = nm_device_ip4_config_new(self); + nm_ip4_config_merge_setting(manual, + nm_connection_get_setting_ip4_config(connection), + NM_SETTING_CONNECTION_MDNS_DEFAULT, + NM_SETTING_CONNECTION_LLMNR_DEFAULT, + nm_device_get_route_table(self, AF_INET), + nm_device_get_route_metric(self, AF_INET)); + + configs = g_new0(NMIP4Config *, 3); + configs[0] = manual; + configs[1] = g_object_ref(ip4_config); + + ipv4_dad_start(self, configs, dhcp4_dad_cb); + } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { + if (dhcp4_lease_change(self, ip4_config, state == NM_DHCP_STATE_BOUND)) + nm_device_update_metered(self); + else + dhcp4_fail(self, state); + } + break; + case NM_DHCP_STATE_TIMEOUT: + dhcp4_fail(self, state); + break; + case NM_DHCP_STATE_EXPIRE: + /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) + break; + /* fall-through */ + case NM_DHCP_STATE_DONE: + case NM_DHCP_STATE_FAIL: + case NM_DHCP_STATE_TERMINATED: + dhcp4_fail(self, state); + break; + default: + break; + } } -/** - * dhcp_get_iaid: - * @self: the #NMDevice - * @addr_family: the address family - * @connection: the connection - * @out_is_explicit: on return, %TRUE if the user set a valid IAID in - * the connection or in global configuration; %FALSE if the connection - * property was empty and no valid global configuration was provided. - * - * Returns: a IAID value for this device and the given connection. - */ -static guint32 -dhcp_get_iaid (NMDevice *self, - int addr_family, - NMConnection *connection, - gboolean *out_is_explicit) -{ - NMSettingIPConfig *s_ip; - const char *iaid_str; - gs_free char *iaid_str_free = NULL; - guint32 iaid; - const char *iface; - const char *fail_reason; - gboolean is_explicit = TRUE; - - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - iaid_str = nm_setting_ip_config_get_dhcp_iaid (s_ip); - if (!iaid_str) { - iaid_str_free = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.dhcp-iaid") - : NM_CON_DEFAULT ("ipv6.dhcp-iaid"), - self); - iaid_str = iaid_str_free; - if (!iaid_str) { - iaid_str = NM_IAID_IFNAME; - is_explicit = FALSE; - } else if (!_nm_utils_iaid_verify (iaid_str, NULL)) { - _LOGW (LOGD_DEVICE, "invalid global default '%s' for ipv%c.dhcp-iaid", - iaid_str, - nm_utils_addr_family_to_char (addr_family)); - iaid_str = NM_IAID_IFNAME; - is_explicit = FALSE; - } - } - - if (nm_streq0 (iaid_str, NM_IAID_MAC)) { - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self)); - if (!pllink || pllink->l_address.len < 4) { - fail_reason = "invalid link-layer address"; - goto out_fail; - } - - /* @iaid is in native endianness. Use unaligned_read_be32() - * so that the IAID for a given MAC address is the same on - * BE and LE machines. */ - iaid = unaligned_read_be32 (&pllink->l_address.data[pllink->l_address.len - 4]); - goto out_good; - } else if (nm_streq0 (iaid_str, NM_IAID_PERM_MAC)) { - guint8 hwaddr_buf[NM_UTILS_HWADDR_LEN_MAX]; - const char *hwaddr_str; - gsize hwaddr_len; - - hwaddr_str = nm_device_get_permanent_hw_address (self); - if (!hwaddr_str) { - fail_reason = "no permanent link-layer address"; - goto out_fail; - } - - if (!_nm_utils_hwaddr_aton (hwaddr_str, hwaddr_buf, sizeof (hwaddr_buf), &hwaddr_len)) - g_return_val_if_reached (0); - - if (hwaddr_len < 4) { - fail_reason = "invalid link-layer address"; - goto out_fail; - } - - iaid = unaligned_read_be32 (&hwaddr_buf[hwaddr_len - 4]); - goto out_good; - } else if (nm_streq (iaid_str, "stable")) { - nm_auto_free_checksum GChecksum *sum = NULL; - guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - NMUtilsStableType stable_type; - const char *stable_id; - guint32 salted_header; - const guint8 *host_id; - gsize host_id_len; - - stable_id = _get_stable_id (self, connection, &stable_type); - salted_header = htonl (53390459 + stable_type); - nm_utils_host_id_get (&host_id, &host_id_len); - iface = nm_device_get_ip_iface (self); - - sum = g_checksum_new (G_CHECKSUM_SHA1); - g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); - g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1); - g_checksum_update (sum, (const guchar *) iface, strlen (iface) + 1); - g_checksum_update (sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest (sum, digest); - - iaid = unaligned_read_be32 (digest); - goto out_good; - } else if ((iaid = _nm_utils_ascii_str_to_int64 (iaid_str, 10, 0, G_MAXUINT32, -1)) != -1) { - goto out_good; - } else { - iface = nm_device_get_ip_iface (self); - iaid = nm_utils_create_dhcp_iaid (TRUE, - (const guint8 *) iface, - strlen (iface)); - goto out_good; - } - -out_fail: - nm_assert (fail_reason); - _LOGW ( addr_family == AF_INET - ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) - : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), - "ipv%c.dhcp-iaid: failure to generate IAID: %s. Using interface-name based IAID", - nm_utils_addr_family_to_char (addr_family), fail_reason); - is_explicit = FALSE; - iface = nm_device_get_ip_iface (self); - iaid = nm_utils_create_dhcp_iaid (TRUE, - (const guint8 *) iface, - strlen (iface)); -out_good: - _LOGD ( addr_family == AF_INET - ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) - : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), - "ipv%c.dhcp-iaid: using %u (0x%08x) IAID (str: '%s', explicit %d)", - nm_utils_addr_family_to_char (addr_family), iaid, iaid, - iaid_str, is_explicit); - NM_SET_OUT (out_is_explicit, is_explicit); - return iaid; -} - -static NMDhcpHostnameFlags -get_dhcp_hostname_flags (NMDevice *self, int addr_family) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip; - NMDhcpHostnameFlags flags; - gs_free_error GError *error = NULL; - - g_return_val_if_fail (NM_IS_DEVICE (self), NM_DHCP_HOSTNAME_FLAG_NONE); - - connection = nm_device_get_applied_connection (self); - s_ip = nm_connection_get_setting_ip_config (connection, addr_family); - g_return_val_if_fail (s_ip, NM_DHCP_HOSTNAME_FLAG_NONE); - - if (!nm_setting_ip_config_get_dhcp_send_hostname (s_ip)) - return NM_DHCP_HOSTNAME_FLAG_NONE; - - flags = nm_setting_ip_config_get_dhcp_hostname_flags (s_ip); - if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) - return flags; - - flags = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT ("ipv4.dhcp-hostname-flags") - : NM_CON_DEFAULT ("ipv6.dhcp-hostname-flags"), - self, - 0, NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS, - 0); - - if (!_nm_utils_validate_dhcp_hostname_flags (flags, addr_family, &error)) { - _LOGW (LOGD_DEVICE, "invalid global default value 0x%x for ipv%d.%s: %s", - (guint) flags, - addr_family == AF_INET ? 4 : 6, - NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS, - error->message); - flags = NM_DHCP_HOSTNAME_FLAG_NONE; - } - - if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) - return flags; - - if (addr_family == AF_INET) - return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP4; - else - return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP6; +static NMActStageReturn +dhcp4_start(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingIPConfig *s_ip4; + gs_unref_bytes GBytes *vendor_class_identifier = NULL; + gs_unref_bytes GBytes *hwaddr = NULL; + gs_unref_bytes GBytes *bcast_hwaddr = NULL; + gs_unref_bytes GBytes *client_id = NULL; + gs_free char * mud_url_free = NULL; + NMConnection * connection; + NMSettingConnection * s_con; + GError * error = NULL; + const NMPlatformLink * pllink; + const char *const * reject_servers; + + connection = nm_device_get_applied_connection(self); + g_return_val_if_fail(connection, FALSE); + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + + s_con = nm_connection_get_setting_connection(connection); + nm_assert(s_con); + + /* Clear old exported DHCP options */ + nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); + priv->dhcp_data_4.config = nm_dhcp_config_new(AF_INET); + + pllink = nm_platform_link_get(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); + if (pllink) { + hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); + bcast_hwaddr = nmp_link_address_get_as_bytes(&pllink->l_broadcast); + } + + client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr); + vendor_class_identifier = + _prop_get_ipv4_dhcp_vendor_class_identifier(self, NM_SETTING_IP4_CONFIG(s_ip4)); + reject_servers = nm_setting_ip_config_get_dhcp_reject_servers(s_ip4, NULL); + + g_warn_if_fail(priv->dhcp_data_4.client == NULL); + priv->dhcp_data_4.client = + nm_dhcp_manager_start_ip4(nm_dhcp_manager_get(), + nm_netns_get_multi_idx(nm_device_get_netns(self)), + nm_device_get_ip_iface(self), + nm_device_get_ip_ifindex(self), + hwaddr, + bcast_hwaddr, + nm_connection_get_uuid(connection), + nm_device_get_route_table(self, AF_INET), + nm_device_get_route_metric(self, AF_INET), + nm_setting_ip_config_get_dhcp_send_hostname(s_ip4), + nm_setting_ip_config_get_dhcp_hostname(s_ip4), + nm_setting_ip4_config_get_dhcp_fqdn(NM_SETTING_IP4_CONFIG(s_ip4)), + _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET), + _prop_get_connection_mud_url(self, s_con, &mud_url_free), + client_id, + _prop_get_ipvx_dhcp_timeout(self, AF_INET), + priv->dhcp_anycast_address, + NULL, + vendor_class_identifier, + reject_servers, + &error); + if (!priv->dhcp_data_4.client) { + _LOGW(LOGD_DHCP4, "failure to start DHCP: %s", error->message); + g_clear_error(&error); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + priv->dhcp_data_4.state_sigid = g_signal_connect(priv->dhcp_data_4.client, + NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, + G_CALLBACK(dhcp4_state_changed), + self); + + if (nm_device_sys_iface_state_is_external_or_assume(self)) + priv->dhcp_data_4.was_active = TRUE; + + /* DHCP devices will be notified by the DHCP manager when stuff happens */ + return NM_ACT_STAGE_RETURN_POSTPONE; } -static const char * -connection_get_mud_url (NMDevice *self, - NMSettingConnection *s_con, - char **out_mud_url) +gboolean +nm_device_dhcp4_renew(NMDevice *self, gboolean release) { - const char *mud_url; - gs_free char *s = NULL; - - nm_assert (out_mud_url && !*out_mud_url); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - mud_url = nm_setting_connection_get_mud_url (s_con); + g_return_val_if_fail(priv->dhcp_data_4.client != NULL, FALSE); - if (mud_url) { - if (nm_streq (mud_url, NM_CONNECTION_MUD_URL_NONE)) - return NULL; - return mud_url; - } + _LOGI(LOGD_DHCP4, "DHCPv4 lease renewal requested"); - s = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.mud-url"), - self); - if (s) { - if (nm_streq (s, NM_CONNECTION_MUD_URL_NONE)) - return NULL; - if (nm_sd_http_url_is_valid_https (s)) - return (*out_mud_url = g_steal_pointer (&s)); - } + /* Terminate old DHCP instance and release the old lease */ + dhcp4_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release); - return NULL; + /* Start DHCP again on the interface */ + return dhcp4_start(self) != NM_ACT_STAGE_RETURN_FAILURE; } -static GBytes * -dhcp4_get_client_id (NMDevice *self, - NMConnection *connection, - GBytes *hwaddr) -{ - NMSettingIPConfig *s_ip4; - const char *client_id; - gs_free char *client_id_default = NULL; - guint8 *client_id_buf; - const char *fail_reason; - guint8 hwaddr_bin_buf[NM_UTILS_HWADDR_LEN_MAX]; - const guint8 *hwaddr_bin; - int arp_type; - gsize hwaddr_len; - GBytes *result; - gs_free char *logstr1 = NULL; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - client_id = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)); - - if (!client_id) { - client_id_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv4.dhcp-client-id"), - self); - if (client_id_default && client_id_default[0]) { - /* a non-empty client-id is always valid, see nm_dhcp_utils_client_id_string_to_bytes(). */ - client_id = client_id_default; - } - } - - if (!client_id) { - _LOGD (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: no explicit client-id configured"); - return NULL; - } - - if (nm_streq (client_id, "mac")) { - if (!hwaddr) { - fail_reason = "missing link-layer address"; - goto out_fail; - } - - hwaddr_bin = g_bytes_get_data (hwaddr, &hwaddr_len); - arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); - if (arp_type < 0) { - fail_reason = "unsupported link-layer address"; - goto out_fail; - } - - result = nm_utils_dhcp_client_id_mac (arp_type, hwaddr_bin, hwaddr_len); - goto out_good; - } - - if (nm_streq (client_id, "perm-mac")) { - const char *hwaddr_str; - - hwaddr_str = nm_device_get_permanent_hw_address (self); - if (!hwaddr_str) { - fail_reason = "missing permanent link-layer address"; - goto out_fail; - } - - if (!_nm_utils_hwaddr_aton (hwaddr_str, hwaddr_bin_buf, sizeof (hwaddr_bin_buf), &hwaddr_len)) - g_return_val_if_reached (NULL); - - arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); - if (arp_type < 0) { - fail_reason = "unsupported permanent link-layer address"; - goto out_fail; - } - - result = nm_utils_dhcp_client_id_mac (arp_type, hwaddr_bin_buf, hwaddr_len); - goto out_good; - } - - if (nm_streq (client_id, "duid")) { - guint32 iaid = dhcp_get_iaid (self, AF_INET, connection, NULL); - - result = nm_utils_dhcp_client_id_systemd_node_specific (iaid); - goto out_good; - } - - if (nm_streq (client_id, "stable")) { - nm_auto_free_checksum GChecksum *sum = NULL; - guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - NMUtilsStableType stable_type; - const char *stable_id; - guint32 salted_header; - const guint8 *host_id; - gsize host_id_len; - - stable_id = _get_stable_id (self, connection, &stable_type); - salted_header = htonl (2011610591 + stable_type); - nm_utils_host_id_get (&host_id, &host_id_len); - - sum = g_checksum_new (G_CHECKSUM_SHA1); - g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); - g_checksum_update (sum, (const guchar *) stable_id, strlen (stable_id) + 1); - g_checksum_update (sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest (sum, digest); - - client_id_buf = g_malloc (1 + 15); - client_id_buf[0] = 0; - memcpy (&client_id_buf[1], digest, 15); - result = g_bytes_new_take (client_id_buf, 1 + 15); - goto out_good; - } - - result = nm_dhcp_utils_client_id_string_to_bytes (client_id); - goto out_good; - -out_fail: - nm_assert (fail_reason); - _LOGW (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: failure to generate client id (%s). Use random client id", - fail_reason); - client_id_buf = g_malloc (1 + 15); - client_id_buf[0] = 0; - nm_utils_random_bytes (&client_id_buf[1], 15); - result = g_bytes_new_take (client_id_buf, 1 + 15); - -out_good: - nm_assert (result); - _LOGD (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: use \"%s\" client ID: %s", - client_id, - (logstr1 = nm_dhcp_utils_duid_to_string (result))); - return result; -} - -static NMActStageReturn -dhcp4_start (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMSettingIPConfig *s_ip4; - gs_unref_bytes GBytes *hwaddr = NULL; - gs_unref_bytes GBytes *bcast_hwaddr = NULL; - gs_unref_bytes GBytes *client_id = NULL; - gs_free char *mud_url_free = NULL; - NMConnection *connection; - NMSettingConnection *s_con; - GError *error = NULL; - const NMPlatformLink *pllink; - - connection = nm_device_get_applied_connection (self); - g_return_val_if_fail (connection, FALSE); - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - - s_con = nm_connection_get_setting_connection (connection); - nm_assert (s_con); - - /* Clear old exported DHCP options */ - nm_dbus_object_clear_and_unexport (&priv->dhcp_data_4.config); - priv->dhcp_data_4.config = nm_dhcp_config_new (AF_INET); - - pllink = nm_platform_link_get (nm_device_get_platform (self), nm_device_get_ip_ifindex (self)); - if (pllink) { - hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address); - bcast_hwaddr = nmp_link_address_get_as_bytes (&pllink->l_broadcast); - } - - client_id = dhcp4_get_client_id (self, connection, hwaddr); - - g_warn_if_fail (priv->dhcp_data_4.client == NULL); - priv->dhcp_data_4.client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (), - nm_netns_get_multi_idx (nm_device_get_netns (self)), - nm_device_get_ip_iface (self), - nm_device_get_ip_ifindex (self), - hwaddr, - bcast_hwaddr, - nm_connection_get_uuid (connection), - nm_device_get_route_table (self, AF_INET), - nm_device_get_route_metric (self, AF_INET), - nm_setting_ip_config_get_dhcp_send_hostname (s_ip4), - nm_setting_ip_config_get_dhcp_hostname (s_ip4), - nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)), - get_dhcp_hostname_flags (self, AF_INET), - connection_get_mud_url (self, s_con, &mud_url_free), - client_id, - get_dhcp_timeout (self, AF_INET), - priv->dhcp_anycast_address, - NULL, - &error); - if (!priv->dhcp_data_4.client) { - _LOGW (LOGD_DHCP4, "failure to start DHCP: %s", error->message); - g_clear_error (&error); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - priv->dhcp_data_4.state_sigid = g_signal_connect (priv->dhcp_data_4.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK (dhcp4_state_changed), - self); - - if (nm_device_sys_iface_state_is_external_or_assume (self)) - priv->dhcp_data_4.was_active = TRUE; - - /* DHCP devices will be notified by the DHCP manager when stuff happens */ - return NM_ACT_STAGE_RETURN_POSTPONE; -} +/*****************************************************************************/ -gboolean -nm_device_dhcp4_renew (NMDevice *self, gboolean release) +static NMIP4Config * +shared4_new_config(NMDevice *self, NMConnection *connection) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - g_return_val_if_fail (priv->dhcp_data_4.client != NULL, FALSE); - - _LOGI (LOGD_DHCP4, "DHCPv4 lease renewal requested"); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMIP4Config * config; + NMSettingIPConfig * s_ip4; + NMPlatformIP4Address address = { + .addr_source = NM_IP_CONFIG_SOURCE_SHARED, + }; - /* Terminate old DHCP instance and release the old lease */ - dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release); + g_return_val_if_fail(self, NULL); + g_return_val_if_fail(connection, NULL); - /* Start DHCP again on the interface */ - return dhcp4_start (self) != NM_ACT_STAGE_RETURN_FAILURE; -} + s_ip4 = nm_connection_get_setting_ip4_config(connection); + if (s_ip4 && nm_setting_ip_config_get_num_addresses(s_ip4) > 0) { + /* Use the first user-supplied address */ + NMIPAddress *user = nm_setting_ip_config_get_address(s_ip4, 0); + in_addr_t a; -/*****************************************************************************/ + nm_ip_address_get_address_binary(user, &a); + nm_platform_ip4_address_set_addr(&address, a, nm_ip_address_get_prefix(user)); + nm_clear_pointer(&priv->shared_ip_handle, nm_netns_shared_ip_release); + } else { + if (!priv->shared_ip_handle) + priv->shared_ip_handle = nm_netns_shared_ip_reserve(nm_device_get_netns(self)); + nm_platform_ip4_address_set_addr(&address, priv->shared_ip_handle->addr, 24); + } -static GHashTable *shared_ips = NULL; + config = nm_device_ip4_config_new(self); + nm_ip4_config_add_address(config, &address); -static void -shared_ip_release (gpointer data) -{ - g_hash_table_remove (shared_ips, data); - if (!g_hash_table_size (shared_ips)) - nm_clear_pointer (&shared_ips, g_hash_table_unref); -} - -static NMIP4Config * -shared4_new_config (NMDevice *self, NMConnection *connection) -{ - NMIP4Config *config = NULL; - gboolean is_generated = FALSE; - NMSettingIPConfig *s_ip4; - NMPlatformIP4Address address = { - .addr_source = NM_IP_CONFIG_SOURCE_SHARED, - }; - - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (connection, NULL); - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4 && nm_setting_ip_config_get_num_addresses (s_ip4)) { - /* Use the first user-supplied address */ - NMIPAddress *user = nm_setting_ip_config_get_address (s_ip4, 0); - in_addr_t a; - - nm_ip_address_get_address_binary (user, &a); - nm_platform_ip4_address_set_addr (&address, a, nm_ip_address_get_prefix (user)); - } else { - /* Find an unused address in the 10.42.x.x range */ - guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */ - guint32 count = 0; - - if (G_UNLIKELY (!shared_ips)) - shared_ips = g_hash_table_new (nm_direct_hash, NULL); - else { - while (g_hash_table_lookup (shared_ips, GUINT_TO_POINTER (start + count))) { - count += ntohl (0x100); - if (count > ntohl (0xFE00)) { - _LOGE (LOGD_SHARING, "ran out of shared IP addresses!"); - return FALSE; - } - } - } - nm_platform_ip4_address_set_addr (&address, start + count, 24); - g_hash_table_add (shared_ips, GUINT_TO_POINTER (address.address)); - is_generated = TRUE; - } - - config = nm_device_ip4_config_new (self); - nm_ip4_config_add_address (config, &address); - if (is_generated) { - /* Remove the address lock when the object gets disposed */ - g_object_set_qdata_full (G_OBJECT (config), NM_CACHED_QUARK ("shared-ip"), - GUINT_TO_POINTER (address.address), - shared_ip_release); - } - return config; + return config; } /*****************************************************************************/ static gboolean -connection_ip_method_requires_carrier (NMConnection *connection, - int addr_family, - gboolean *out_ip_enabled) +connection_ip_method_requires_carrier(NMConnection *connection, + int addr_family, + gboolean * out_ip_enabled) { - const char *method; + const char *method; - method = nm_utils_get_ip_config_method (connection, addr_family); + method = nm_utils_get_ip_config_method(connection, addr_family); - if (addr_family == AF_INET) { - NM_SET_OUT (out_ip_enabled, !nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)); - return NM_IN_STRSET (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); - } + if (addr_family == AF_INET) { + NM_SET_OUT(out_ip_enabled, !nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)); + return NM_IN_STRSET(method, + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); + } - NM_SET_OUT (out_ip_enabled, - !NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)); - return NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP, - NM_SETTING_IP6_CONFIG_METHOD_SHARED, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL); + NM_SET_OUT(out_ip_enabled, + !NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)); + return NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_SHARED, + NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL); } static gboolean -connection_requires_carrier (NMConnection *connection) -{ - NMSettingIPConfig *s_ip4, *s_ip6; - NMSettingConnection *s_con; - gboolean ip4_carrier_wanted, ip6_carrier_wanted; - gboolean ip4_used = FALSE, ip6_used = FALSE; - - /* We can progress to IP_CONFIG now, so that we're enslaved. - * That may actually cause carrier to go up and thus continue acivation. */ - s_con = nm_connection_get_setting_connection (connection); - if (nm_setting_connection_get_master (s_con)) - return FALSE; - - ip4_carrier_wanted = connection_ip_method_requires_carrier (connection, AF_INET, &ip4_used); - if (ip4_carrier_wanted) { - /* If IPv4 wants a carrier and cannot fail, the whole connection - * requires a carrier regardless of the IPv6 method. - */ - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4 && !nm_setting_ip_config_get_may_fail (s_ip4)) - return TRUE; - } - - ip6_carrier_wanted = connection_ip_method_requires_carrier (connection, AF_INET6, &ip6_used); - if (ip6_carrier_wanted) { - /* If IPv6 wants a carrier and cannot fail, the whole connection - * requires a carrier regardless of the IPv4 method. - */ - s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (s_ip6 && !nm_setting_ip_config_get_may_fail (s_ip6)) - return TRUE; - } - - /* If an IP version wants a carrier and the other IP version isn't - * used, the connection requires carrier since it will just fail without one. - */ - if (ip4_carrier_wanted && !ip6_used) - return TRUE; - if (ip6_carrier_wanted && !ip4_used) - return TRUE; - - /* If both want a carrier, the whole connection wants a carrier */ - return ip4_carrier_wanted && ip6_carrier_wanted; +connection_requires_carrier(NMConnection *connection) +{ + NMSettingIPConfig * s_ip4, *s_ip6; + NMSettingConnection *s_con; + gboolean ip4_carrier_wanted, ip6_carrier_wanted; + gboolean ip4_used = FALSE, ip6_used = FALSE; + + /* We can progress to IP_CONFIG now, so that we're enslaved. + * That may actually cause carrier to go up and thus continue activation. */ + s_con = nm_connection_get_setting_connection(connection); + if (nm_setting_connection_get_master(s_con)) + return FALSE; + + ip4_carrier_wanted = connection_ip_method_requires_carrier(connection, AF_INET, &ip4_used); + if (ip4_carrier_wanted) { + /* If IPv4 wants a carrier and cannot fail, the whole connection + * requires a carrier regardless of the IPv6 method. + */ + s_ip4 = nm_connection_get_setting_ip4_config(connection); + if (s_ip4 && !nm_setting_ip_config_get_may_fail(s_ip4)) + return TRUE; + } + + ip6_carrier_wanted = connection_ip_method_requires_carrier(connection, AF_INET6, &ip6_used); + if (ip6_carrier_wanted) { + /* If IPv6 wants a carrier and cannot fail, the whole connection + * requires a carrier regardless of the IPv4 method. + */ + s_ip6 = nm_connection_get_setting_ip6_config(connection); + if (s_ip6 && !nm_setting_ip_config_get_may_fail(s_ip6)) + return TRUE; + } + + /* If an IP version wants a carrier and the other IP version isn't + * used, the connection requires carrier since it will just fail without one. + */ + if (ip4_carrier_wanted && !ip6_used) + return TRUE; + if (ip6_carrier_wanted && !ip4_used) + return TRUE; + + /* If both want a carrier, the whole connection wants a carrier */ + return ip4_carrier_wanted && ip6_carrier_wanted; } static gboolean -have_any_ready_slaves (NMDevice *self) +have_any_ready_slaves(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - SlaveInfo *info; - CList *iter; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + SlaveInfo * info; + CList * iter; - /* Any enslaved slave is "ready" in the generic case as it's - * at least >= NM_DEVCIE_STATE_IP_CONFIG and has had Layer 2 - * properties set up. - */ - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry (iter, SlaveInfo, lst_slave); - if (NM_DEVICE_GET_PRIVATE (info->slave)->is_enslaved) - return TRUE; - } - return FALSE; + /* Any enslaved slave is "ready" in the generic case as it's + * at least >= NM_DEVCIE_STATE_IP_CONFIG and has had Layer 2 + * properties set up. + */ + c_list_for_each (iter, &priv->slaves) { + info = c_list_entry(iter, SlaveInfo, lst_slave); + if (NM_DEVICE_GET_PRIVATE(info->slave)->is_enslaved) + return TRUE; + } + return FALSE; } /*****************************************************************************/ /* DHCPv6 stuff */ static void -dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) +dhcp6_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->dhcp_data_6.was_active = FALSE; - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - applied_config_clear (&priv->dhcp6.ip6_config); - nm_clear_g_free (&priv->dhcp6.event_id); - nm_clear_g_source (&priv->dhcp_data_6.grace_id); - priv->dhcp_data_6.grace_pending = FALSE; + priv->dhcp_data_6.was_active = FALSE; + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; + applied_config_clear(&priv->dhcp6.ip6_config); + nm_clear_g_free(&priv->dhcp6.event_id); + nm_clear_g_source(&priv->dhcp_data_6.grace_id); + priv->dhcp_data_6.grace_pending = FALSE; - if (priv->dhcp_data_6.client) { - nm_clear_g_signal_handler (priv->dhcp_data_6.client, &priv->dhcp_data_6.state_sigid); - nm_clear_g_signal_handler (priv->dhcp_data_6.client, &priv->dhcp6.prefix_sigid); + if (priv->dhcp_data_6.client) { + nm_clear_g_signal_handler(priv->dhcp_data_6.client, &priv->dhcp_data_6.state_sigid); + nm_clear_g_signal_handler(priv->dhcp_data_6.client, &priv->dhcp6.prefix_sigid); - if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE - || cleanup_type == CLEANUP_TYPE_REMOVED) - nm_dhcp_client_stop (priv->dhcp_data_6.client, release); + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) + nm_dhcp_client_stop(priv->dhcp_data_6.client, release); - g_clear_object (&priv->dhcp_data_6.client); - } + g_clear_object(&priv->dhcp_data_6.client); + } - if (priv->dhcp_data_6.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp_data_6.config); - _notify (self, PROP_DHCP6_CONFIG); - } + if (priv->dhcp_data_6.config) { + nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); + _notify(self, PROP_DHCP6_CONFIG); + } } static gboolean -dhcp6_lease_change (NMDevice *self) +dhcp6_lease_change(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMSettingsConnection *settings_connection; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingsConnection *settings_connection; - if (!applied_config_get_current (&priv->dhcp6.ip6_config)) { - _LOGW (LOGD_DHCP6, "failed to get DHCPv6 config for rebind"); - return FALSE; - } + if (!applied_config_get_current(&priv->dhcp6.ip6_config)) { + _LOGW(LOGD_DHCP6, "failed to get DHCPv6 config for rebind"); + return FALSE; + } - g_assert (priv->dhcp_data_6.client); /* sanity check */ + g_assert(priv->dhcp_data_6.client); /* sanity check */ - settings_connection = nm_device_get_settings_connection (self); - g_assert (settings_connection); + settings_connection = nm_device_get_settings_connection(self); + g_assert(settings_connection); - /* Apply the updated config */ - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) { - _LOGW (LOGD_DHCP6, "failed to update IPv6 config in response to DHCP event"); - return FALSE; - } + /* Apply the updated config */ + if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) { + _LOGW(LOGD_DHCP6, "failed to update IPv6 config in response to DHCP event"); + return FALSE; + } - nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP6_CHANGE, - self, - NULL, - NULL, NULL, NULL); + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP6_CHANGE, self, NULL, NULL, NULL, NULL); - return TRUE; + return TRUE; } static void -dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean is_dhcp_managed; - - _LOGD (LOGD_DHCP6, "DHCPv6 failed (ip_state %s, was_active %d)", - _ip_state_to_string (priv->ip_state_6), - priv->dhcp_data_6.was_active); - - /* The client is always left running after a failure. */ - - /* Nothing to do if we failed before... */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) - goto clear_config; - - is_dhcp_managed = (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED); - - if (is_dhcp_managed) { - /* ... and also if there are static addresses configured - * on the interface. - */ - if ( priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE - && priv->con_ip_config_6 - && nm_ip6_config_get_num_addresses (priv->con_ip_config_6)) - goto clear_config; - - /* Fail the method when one of the following is true: - * 1) the DHCP client terminated: it does not make sense to start a grace - * period without a client running; - * 2) we failed to get an initial lease AND the client was - * not active before. - */ - if ( dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp_data_6.was_active && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF)) { - nm_device_activate_schedule_ip_config_timeout (self, AF_INET6); - return; - } - - if (dhcp_grace_period_start (self, AF_INET6)) - goto clear_config; - } else { - /* not a hard failure; just live with the RA info */ - dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); - } - return; +dhcp6_fail(NMDevice *self, NMDhcpState dhcp_state) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean is_dhcp_managed; + + _LOGD(LOGD_DHCP6, + "DHCPv6 failed (ip_state %s, was_active %d)", + _ip_state_to_string(priv->ip_state_6), + priv->dhcp_data_6.was_active); + + /* The client is always left running after a failure. */ + + /* Nothing to do if we failed before... */ + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) + goto clear_config; + + is_dhcp_managed = (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED); + + if (is_dhcp_managed) { + /* ... and also if there are static addresses configured + * on the interface. + */ + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && priv->con_ip_config_6 + && nm_ip6_config_get_num_addresses(priv->con_ip_config_6)) + goto clear_config; + + /* Fail the method when one of the following is true: + * 1) the DHCP client terminated: it does not make sense to start a grace + * period without a client running; + * 2) we failed to get an initial lease AND the client was + * not active before. + */ + if (dhcp_state == NM_DHCP_STATE_TERMINATED + || (!priv->dhcp_data_6.was_active && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF)) { + nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); + return; + } + + if (dhcp_grace_period_start(self, AF_INET6)) + goto clear_config; + } else { + /* not a hard failure; just live with the RA info */ + dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, FALSE); + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + } + return; clear_config: - /* The previous configuration is no longer valid */ - if (priv->dhcp_data_6.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp_data_6.config); - priv->dhcp_data_6.config = nm_dhcp_config_new (AF_INET6); - _notify (self, PROP_DHCP6_CONFIG); - } + /* The previous configuration is no longer valid */ + if (priv->dhcp_data_6.config) { + nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); + priv->dhcp_data_6.config = nm_dhcp_config_new(AF_INET6); + _notify(self, PROP_DHCP6_CONFIG); + } } static void -dhcp6_state_changed (NMDhcpClient *client, - NMDhcpState state, - NMIP6Config *ip6_config, - GHashTable *options, - const char *event_id, - gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - g_return_if_fail (nm_dhcp_client_get_addr_family (client) == AF_INET6); - g_return_if_fail (!ip6_config || NM_IS_IP6_CONFIG (ip6_config)); - - _LOGD (LOGD_DHCP6, "new DHCPv6 client state %d", state); - - switch (state) { - case NM_DHCP_STATE_BOUND: - case NM_DHCP_STATE_EXTENDED: - nm_clear_g_source (&priv->dhcp_data_6.grace_id); - priv->dhcp_data_6.grace_pending = FALSE; - /* 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. - */ - if ( ip6_config - && event_id - && priv->dhcp6.event_id - && !strcmp (event_id, priv->dhcp6.event_id)) { - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *a; - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6_config, &a) - applied_config_add_address (&priv->dhcp6.ip6_config, NM_PLATFORM_IP_ADDRESS_CAST (a)); - } else { - nm_clear_g_free (&priv->dhcp6.event_id); - if (ip6_config) { - applied_config_init (&priv->dhcp6.ip6_config, ip6_config); - priv->dhcp6.event_id = g_strdup (event_id); - nm_dhcp_config_set_options (priv->dhcp_data_6.config, options); - _notify (self, PROP_DHCP6_CONFIG); - } else - applied_config_clear (&priv->dhcp6.ip6_config); - } - - /* After long time we have been able to renew the lease: - * update the ip state - */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_CONF); - - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { - if (!applied_config_get_current (&priv->dhcp6.ip6_config)) { - nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED); - break; - } - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); - } else if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) - if (!dhcp6_lease_change (self)) - dhcp6_fail (self, state); - break; - case NM_DHCP_STATE_TIMEOUT: - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) - dhcp6_fail (self, state); - else { - /* not a hard failure; just live with the RA info */ - dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); - } - break; - case NM_DHCP_STATE_EXPIRE: - /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ - if (priv->ip_state_6 != NM_DEVICE_IP_STATE_CONF) - dhcp6_fail (self, state); - break; - case NM_DHCP_STATE_TERMINATED: - /* In IPv6 info-only mode, the client doesn't handle leases so it - * may exit right after getting a response from the server. That's - * normal. In that case we just ignore the exit. - */ - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) - break; - /* fall-through */ - case NM_DHCP_STATE_DONE: - case NM_DHCP_STATE_FAIL: - dhcp6_fail (self, state); - break; - default: - break; - } +dhcp6_state_changed(NMDhcpClient *client, + NMDhcpState state, + NMIP6Config * ip6_config, + GHashTable * options, + gpointer user_data) +{ + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gs_free char * event_id = NULL; + + g_return_if_fail(nm_dhcp_client_get_addr_family(client) == AF_INET6); + g_return_if_fail(!ip6_config || NM_IS_IP6_CONFIG(ip6_config)); + + _LOGD(LOGD_DHCP6, "new DHCPv6 client state %d", state); + + switch (state) { + case NM_DHCP_STATE_BOUND: + case NM_DHCP_STATE_EXTENDED: + nm_clear_g_source(&priv->dhcp_data_6.grace_id); + priv->dhcp_data_6.grace_pending = FALSE; + /* 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. + */ + + event_id = nm_dhcp_utils_get_dhcp6_event_id(options); + + if (ip6_config && event_id && priv->dhcp6.event_id + && nm_streq(event_id, priv->dhcp6.event_id)) { + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *a; + + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6_config, &a) + applied_config_add_address(&priv->dhcp6.ip6_config, NM_PLATFORM_IP_ADDRESS_CAST(a)); + } else { + nm_clear_g_free(&priv->dhcp6.event_id); + if (ip6_config) { + applied_config_init(&priv->dhcp6.ip6_config, ip6_config); + priv->dhcp6.event_id = g_strdup(event_id); + nm_dhcp_config_set_options(priv->dhcp_data_6.config, options); + _notify(self, PROP_DHCP6_CONFIG); + } else + applied_config_clear(&priv->dhcp6.ip6_config); + } + + /* After long time we have been able to renew the lease: + * update the ip state + */ + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_CONF); + + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { + if (!applied_config_get_current(&priv->dhcp6.ip6_config)) { + nm_device_ip_method_failed(self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED); + break; + } + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + } else if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) + if (!dhcp6_lease_change(self)) + dhcp6_fail(self, state); + break; + case NM_DHCP_STATE_TIMEOUT: + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) + dhcp6_fail(self, state); + else { + /* not a hard failure; just live with the RA info */ + dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, FALSE); + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + } + break; + case NM_DHCP_STATE_EXPIRE: + /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ + if (priv->ip_state_6 != NM_DEVICE_IP_STATE_CONF) + dhcp6_fail(self, state); + break; + case NM_DHCP_STATE_TERMINATED: + /* In IPv6 info-only mode, the client doesn't handle leases so it + * may exit right after getting a response from the server. That's + * normal. In that case we just ignore the exit. + */ + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) + break; + /* fall-through */ + case NM_DHCP_STATE_DONE: + case NM_DHCP_STATE_FAIL: + dhcp6_fail(self, state); + break; + default: + break; + } } static void -dhcp6_prefix_delegated (NMDhcpClient *client, - NMPlatformIP6Address *prefix, - gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - - /* Just re-emit. The device just contributes the prefix to the - * pool in NMPolicy, which decides about subnet allocation - * on the shared devices. */ - g_signal_emit (self, signals[IP6_PREFIX_DELEGATED], 0, prefix); -} - -/*****************************************************************************/ - -/* RFC 3315 defines the epoch for the DUID-LLT time field on Jan 1st 2000. */ -#define EPOCH_DATETIME_200001010000 946684800 - -static GBytes * -generate_duid_llt (int arp_type, - const guint8 *hwaddr, - gsize hwaddr_len, - gint64 time) -{ - guint8 *arr; - const guint16 duid_type = htons (1); - const guint16 hw_type = htons (arp_type); - const guint32 duid_time = htonl (NM_MAX (0, time - EPOCH_DATETIME_200001010000)); - - if (!nm_utils_arp_type_get_hwaddr_relevant_part (arp_type, &hwaddr, &hwaddr_len)) - nm_assert_not_reached (); - - arr = g_new (guint8, 2 + 2 + 4 + hwaddr_len); - - memcpy (&arr[0], &duid_type, 2); - memcpy (&arr[2], &hw_type, 2); - memcpy (&arr[4], &duid_time, 4); - memcpy (&arr[8], hwaddr, hwaddr_len); - - return g_bytes_new_take (arr, 2 + 2 + 4 + hwaddr_len); -} - -static GBytes * -generate_duid_ll (int arp_type, - const guint8 *hwaddr, - gsize hwaddr_len) -{ - guint8 *arr; - const guint16 duid_type = htons (3); - const guint16 hw_type = htons (arp_type); - - if (!nm_utils_arp_type_get_hwaddr_relevant_part (arp_type, &hwaddr, &hwaddr_len)) - nm_assert_not_reached (); - - arr = g_new (guint8, 2 + 2 + hwaddr_len); - - memcpy (&arr[0], &duid_type, 2); - memcpy (&arr[2], &hw_type, 2); - memcpy (&arr[4], hwaddr, hwaddr_len); - - return g_bytes_new_take (arr, 2 + 2 + hwaddr_len); -} - -static GBytes * -generate_duid_uuid (const NMUuid *uuid) -{ - const guint16 duid_type = htons (4); - guint8 *duid_buffer; - - nm_assert (uuid); - - /* Generate a DHCP Unique Identifier for DHCPv6 using the - * DUID-UUID method (see RFC 6355 section 4). Format is: - * - * u16: type (DUID-UUID = 4) - * u8[16]: UUID bytes - */ - G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2); - G_STATIC_ASSERT_EXPR (sizeof (*uuid) == 16); - duid_buffer = g_malloc (18); - memcpy (&duid_buffer[0], &duid_type, 2); - memcpy (&duid_buffer[2], uuid, 16); - return g_bytes_new_take (duid_buffer, 18); -} - -static GBytes * -generate_duid_from_machine_id (void) +dhcp6_prefix_delegated(NMDhcpClient *client, NMPlatformIP6Address *prefix, gpointer user_data) { - static GBytes *volatile global_duid = NULL; - GBytes *p; - -again: - p = g_atomic_pointer_get (&global_duid); - if (G_UNLIKELY (!p)) { - nm_auto_free_checksum GChecksum *sum = NULL; - const NMUuid *machine_id; - union { - guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256]; - NMUuid uuid; - } digest; - - machine_id = nm_utils_machine_id_bin (); - - /* Hash the machine ID so it's not leaked to the network */ - sum = g_checksum_new (G_CHECKSUM_SHA256); - g_checksum_update (sum, (const guchar *) machine_id, sizeof (*machine_id)); - nm_utils_checksum_get_digest (sum, digest.sha256); - - G_STATIC_ASSERT_EXPR (sizeof (digest.sha256) > sizeof (digest.uuid)); - p = generate_duid_uuid (&digest.uuid); - - if (!g_atomic_pointer_compare_and_exchange (&global_duid, NULL, p)) { - g_bytes_unref (p); - goto again; - } - } + NMDevice *self = NM_DEVICE(user_data); - return g_bytes_ref (p); -} - -static GBytes * -dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboolean *out_enforce) -{ - NMSettingIPConfig *s_ip6; - const char *duid; - gs_free char *duid_default = NULL; - const char *duid_error; - GBytes *duid_out; - gboolean duid_enforce = TRUE; - gs_free char *logstr1 = NULL; - const guint8 *hwaddr_bin; - gsize hwaddr_len; - int arp_type; - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - duid = nm_setting_ip6_config_get_dhcp_duid (NM_SETTING_IP6_CONFIG (s_ip6)); - - if (!duid) { - duid_default = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv6.dhcp-duid"), - self); - duid = duid_default; - if (!duid) - duid = "lease"; - } - - if (nm_streq (duid, "lease")) { - duid_enforce = FALSE; - duid_out = generate_duid_from_machine_id (); - goto out_good; - } - - if (!_nm_utils_dhcp_duid_valid (duid, &duid_out)) { - duid_error = "invalid duid"; - goto out_fail; - } - - if (duid_out) - goto out_good; - - if (NM_IN_STRSET (duid, "ll", "llt")) { - if (!hwaddr) { - duid_error = "missing link-layer address"; - goto out_fail; - } - - hwaddr_bin = g_bytes_get_data (hwaddr, &hwaddr_len); - arp_type = nm_utils_arp_type_detect_from_hwaddrlen (hwaddr_len); - if (arp_type < 0) { - duid_error = "unsupported link-layer address"; - goto out_fail; - } - - if (nm_streq (duid, "ll")) - duid_out = generate_duid_ll (arp_type, hwaddr_bin, hwaddr_len); - else { - duid_out = generate_duid_llt (arp_type, hwaddr_bin, hwaddr_len, - nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NSEC_PER_SEC); - } - - goto out_good; - } - - if (NM_IN_STRSET (duid, "stable-ll", "stable-llt", "stable-uuid")) { - /* preferably, we would salt the checksum differently for each @duid type. We missed - * to do that initially, so most types use the DEFAULT_SALT. - * - * Implementations that are added later, should use a distinct salt instead, - * like "stable-ll"/"stable-llt" with ARPHRD_INFINIBAND below. */ - const guint32 DEFAULT_SALT = 670531087u; - nm_auto_free_checksum GChecksum *sum = NULL; - NMUtilsStableType stable_type; - const char *stable_id = NULL; - guint32 salted_header; - const guint8 *host_id; - gsize host_id_len; - union { - guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256]; - guint8 hwaddr_eth[ETH_ALEN]; - guint8 hwaddr_infiniband[INFINIBAND_ALEN]; - NMUuid uuid; - struct _nm_packed { - guint8 hwaddr[ETH_ALEN]; - guint32 timestamp; - } llt_eth; - struct _nm_packed { - guint8 hwaddr[INFINIBAND_ALEN]; - guint32 timestamp; - } llt_infiniband; - } digest; - - stable_id = _get_stable_id (self, connection, &stable_type); - - if (NM_IN_STRSET (duid, "stable-ll", "stable-llt")) { - /* for stable LL/LLT DUIDs, we still need a hardware address to detect - * the arp-type. Alternatively, we would be able to detect it based on - * other means (e.g. NMDevice type), but instead require the hardware - * address to be present. This is at least consistent with the "ll"/"llt" - * modes above. */ - if (!hwaddr) { - duid_error = "missing link-layer address"; - goto out_fail; - } - if ((arp_type = nm_utils_arp_type_detect_from_hwaddrlen (g_bytes_get_size (hwaddr))) < 0) { - duid_error = "unsupported link-layer address"; - goto out_fail; - } - - if (arp_type == ARPHRD_ETHER) - salted_header = DEFAULT_SALT; - else { - nm_assert (arp_type == ARPHRD_INFINIBAND); - salted_header = 0x42492CEFu + ((guint32) arp_type); - } - } else { - salted_header = DEFAULT_SALT; - arp_type = -1; - } - - salted_header = htonl (salted_header + ((guint32) stable_type)); - - nm_utils_host_id_get (&host_id, &host_id_len); - - sum = g_checksum_new (G_CHECKSUM_SHA256); - g_checksum_update (sum, (const guchar *) &salted_header, sizeof (salted_header)); - g_checksum_update (sum, (const guchar *) stable_id, -1); - g_checksum_update (sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest (sum, digest.sha256); - - G_STATIC_ASSERT_EXPR (sizeof (digest) == sizeof (digest.sha256)); - - if (nm_streq (duid, "stable-ll")) { - switch (arp_type) { - case ARPHRD_ETHER: - duid_out = generate_duid_ll (arp_type, digest.hwaddr_eth, sizeof (digest.hwaddr_eth)); - break; - case ARPHRD_INFINIBAND: - duid_out = generate_duid_ll (arp_type, digest.hwaddr_infiniband, sizeof (digest.hwaddr_infiniband)); - break; - default: - g_return_val_if_reached (NULL); - } - } else if (nm_streq (duid, "stable-llt")) { - gint64 time; - guint32 timestamp; - -#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3) - - /* We want a variable time between the host_id timestamp and three years - * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll - * subtract it from the host_id timestamp. - */ - time = nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NSEC_PER_SEC; - - /* don't use too old timestamps. They cannot be expressed in DUID-LLT and - * would all be truncated to zero. */ - time = NM_MAX (time, EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS); - - switch (arp_type) { - case ARPHRD_ETHER: - timestamp = unaligned_read_be32 (&digest.llt_eth.timestamp); - time -= timestamp % EPOCH_DATETIME_THREE_YEARS; - duid_out = generate_duid_llt (arp_type, digest.llt_eth.hwaddr, sizeof (digest.llt_eth.hwaddr), time); - break; - case ARPHRD_INFINIBAND: - timestamp = unaligned_read_be32 (&digest.llt_infiniband.timestamp); - time -= timestamp % EPOCH_DATETIME_THREE_YEARS; - duid_out = generate_duid_llt (arp_type, digest.llt_infiniband.hwaddr, sizeof (digest.llt_infiniband.hwaddr), time); - break; - default: - g_return_val_if_reached (NULL); - } - } else { - nm_assert (nm_streq (duid, "stable-uuid")); - duid_out = generate_duid_uuid (&digest.uuid); - } - - goto out_good; - } - - g_return_val_if_reached (NULL); - -out_fail: - nm_assert (!duid_out && duid_error); - { - NMUuid uuid; - - _LOGW (LOGD_IP6 | LOGD_DHCP6, - "ipv6.dhcp-duid: failure to generate %s DUID: %s. Fallback to random DUID-UUID.", - duid, duid_error); - - nm_utils_random_bytes (&uuid, sizeof (uuid)); - duid_out = generate_duid_uuid (&uuid); - } - -out_good: - nm_assert (duid_out); - _LOGD (LOGD_IP6 | LOGD_DHCP6, - "ipv6.dhcp-duid: generate %s DUID '%s' (%s)", - duid, - (logstr1 = nm_dhcp_utils_duid_to_string (duid_out)), - duid_enforce ? "enforcing" : "prefer lease"); - - NM_SET_OUT (out_enforce, duid_enforce); - return duid_out; + /* Just re-emit. The device just contributes the prefix to the + * pool in NMPolicy, which decides about subnet allocation + * on the shared devices. */ + g_signal_emit(self, signals[IP6_PREFIX_DELEGATED], 0, prefix); } /*****************************************************************************/ static gboolean -dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMSettingIPConfig *s_ip6; - gs_unref_bytes GBytes *hwaddr = NULL; - gs_unref_bytes GBytes *duid = NULL; - gboolean enforce_duid = FALSE; - const NMPlatformLink *pllink; - gs_free char *mud_url_free = NULL; - GError *error = NULL; - guint32 iaid; - gboolean iaid_explicit; - NMSettingConnection *s_con; - const NMPlatformIP6Address *ll_addr = NULL; - - g_return_val_if_fail (connection, FALSE); - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - nm_assert (s_ip6); - s_con = nm_connection_get_setting_connection (connection); - nm_assert (s_con); - - if (priv->ext_ip6_config_captured) { - ll_addr = nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); - } - - if (!ll_addr) { - _LOGW (LOGD_DHCP6, "can't start DHCPv6: no link-local address"); - return FALSE; - } - - pllink = nm_platform_link_get (nm_device_get_platform (self), nm_device_get_ip_ifindex (self)); - if (pllink) - hwaddr = nmp_link_address_get_as_bytes (&pllink->l_address); - - iaid = dhcp_get_iaid (self, AF_INET6, connection, &iaid_explicit); - duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid); - - priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), - nm_device_get_multi_index (self), - nm_device_get_ip_iface (self), - nm_device_get_ip_ifindex (self), - &ll_addr->address, - nm_connection_get_uuid (connection), - nm_device_get_route_table (self, AF_INET6), - nm_device_get_route_metric (self, AF_INET6), - nm_setting_ip_config_get_dhcp_send_hostname (s_ip6), - nm_setting_ip_config_get_dhcp_hostname (s_ip6), - get_dhcp_hostname_flags (self, AF_INET6), - connection_get_mud_url (self, s_con, &mud_url_free), - duid, - enforce_duid, - iaid, - iaid_explicit, - get_dhcp_timeout (self, AF_INET6), - priv->dhcp_anycast_address, - (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, - nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)), - priv->dhcp6.needed_prefixes, - &error); - if (!priv->dhcp_data_6.client) { - _LOGW (LOGD_DHCP6, "failure to start DHCPv6: %s", error->message); - g_clear_error (&error); - if (nm_device_sys_iface_state_is_external_or_assume (self)) - priv->dhcp_data_6.was_active = TRUE; - return FALSE; - } - - priv->dhcp_data_6.state_sigid = g_signal_connect (priv->dhcp_data_6.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK (dhcp6_state_changed), - self); - priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp_data_6.client, - NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, - G_CALLBACK (dhcp6_prefix_delegated), - self); - - if (nm_device_sys_iface_state_is_external_or_assume (self)) - priv->dhcp_data_6.was_active = TRUE; - - return TRUE; +dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingIPConfig *s_ip6; + gs_unref_bytes GBytes *hwaddr = NULL; + gs_unref_bytes GBytes * duid = NULL; + gboolean enforce_duid = FALSE; + const NMPlatformLink * pllink; + gs_free char * mud_url_free = NULL; + GError * error = NULL; + guint32 iaid; + gboolean iaid_explicit; + NMSettingConnection * s_con; + const NMPlatformIP6Address *ll_addr = NULL; + + g_return_val_if_fail(connection, FALSE); + + s_ip6 = nm_connection_get_setting_ip6_config(connection); + nm_assert(s_ip6); + s_con = nm_connection_get_setting_connection(connection); + nm_assert(s_con); + + if (priv->ext_ip6_config_captured) { + ll_addr = nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); + } + + if (!ll_addr) { + _LOGW(LOGD_DHCP6, "can't start DHCPv6: no link-local address"); + return FALSE; + } + + pllink = nm_platform_link_get(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); + if (pllink) + hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); + + iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, &iaid_explicit); + duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid); + + priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6( + nm_dhcp_manager_get(), + nm_device_get_multi_index(self), + nm_device_get_ip_iface(self), + nm_device_get_ip_ifindex(self), + &ll_addr->address, + nm_connection_get_uuid(connection), + nm_device_get_route_table(self, AF_INET6), + nm_device_get_route_metric(self, AF_INET6), + nm_setting_ip_config_get_dhcp_send_hostname(s_ip6), + nm_setting_ip_config_get_dhcp_hostname(s_ip6), + _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6), + _prop_get_connection_mud_url(self, s_con, &mud_url_free), + duid, + enforce_duid, + iaid, + iaid_explicit, + _prop_get_ipvx_dhcp_timeout(self, AF_INET6), + priv->dhcp_anycast_address, + (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, + nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip6)), + priv->dhcp6.needed_prefixes, + &error); + if (!priv->dhcp_data_6.client) { + _LOGW(LOGD_DHCP6, "failure to start DHCPv6: %s", error->message); + g_clear_error(&error); + if (nm_device_sys_iface_state_is_external_or_assume(self)) + priv->dhcp_data_6.was_active = TRUE; + return FALSE; + } + + priv->dhcp_data_6.state_sigid = g_signal_connect(priv->dhcp_data_6.client, + NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, + G_CALLBACK(dhcp6_state_changed), + self); + priv->dhcp6.prefix_sigid = g_signal_connect(priv->dhcp_data_6.client, + NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, + G_CALLBACK(dhcp6_prefix_delegated), + self); + + if (nm_device_sys_iface_state_is_external_or_assume(self)) + priv->dhcp_data_6.was_active = TRUE; + + return TRUE; } static gboolean -dhcp6_start (NMDevice *self, gboolean wait_for_ll) +dhcp6_start(NMDevice *self, gboolean wait_for_ll) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; - nm_dbus_object_clear_and_unexport (&priv->dhcp_data_6.config); - priv->dhcp_data_6.config = nm_dhcp_config_new (AF_INET6); + nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); + priv->dhcp_data_6.config = nm_dhcp_config_new(AF_INET6); - nm_assert (!applied_config_get_current (&priv->dhcp6.ip6_config)); - applied_config_clear (&priv->dhcp6.ip6_config); - nm_clear_g_free (&priv->dhcp6.event_id); + nm_assert(!applied_config_get_current(&priv->dhcp6.ip6_config)); + applied_config_clear(&priv->dhcp6.ip6_config); + nm_clear_g_free(&priv->dhcp6.event_id); - connection = nm_device_get_applied_connection (self); - g_return_val_if_fail (connection, FALSE); + connection = nm_device_get_applied_connection(self); + g_return_val_if_fail(connection, FALSE); - if (wait_for_ll) { - /* ensure link local is ready... */ - if (!linklocal6_start (self)) { - /* wait for the LL address to show up */ - return TRUE; - } - /* already have the LL address; kick off DHCP */ - } + if (wait_for_ll) { + /* ensure link local is ready... */ + if (!linklocal6_start(self)) { + /* wait for the LL address to show up */ + return TRUE; + } + /* already have the LL address; kick off DHCP */ + } - if (!dhcp6_start_with_link_ready (self, connection)) - return FALSE; + if (!dhcp6_start_with_link_ready(self, connection)) + return FALSE; - return TRUE; + return TRUE; } gboolean -nm_device_dhcp6_renew (NMDevice *self, gboolean release) +nm_device_dhcp6_renew(NMDevice *self, gboolean release) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - g_return_val_if_fail (priv->dhcp_data_6.client != NULL, FALSE); + g_return_val_if_fail(priv->dhcp_data_6.client != NULL, FALSE); - _LOGI (LOGD_DHCP6, "DHCPv6 lease renewal requested"); + _LOGI(LOGD_DHCP6, "DHCPv6 lease renewal requested"); - /* Terminate old DHCP instance and release the old lease */ - dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release); + /* Terminate old DHCP instance and release the old lease */ + dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release); - /* Start DHCP again on the interface */ - return dhcp6_start (self, FALSE); + /* Start DHCP again on the interface */ + return dhcp6_start(self, FALSE); } /*****************************************************************************/ @@ -9675,24 +9879,24 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release) * from known prefixes for a newly active shared connection. */ void -nm_device_request_ip6_prefixes (NMDevice *self, int needed_prefixes) +nm_device_request_ip6_prefixes(NMDevice *self, int needed_prefixes) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->dhcp6.needed_prefixes = needed_prefixes; + priv->dhcp6.needed_prefixes = needed_prefixes; - if (priv->dhcp_data_6.client) { - _LOGD (LOGD_IP6, "ipv6-pd: asking DHCPv6 for %d prefixes", needed_prefixes); - nm_device_dhcp6_renew (self, FALSE); - } else { - _LOGI (LOGD_IP6, "ipv6-pd: device doesn't use DHCPv6, can't request prefixes"); - } + if (priv->dhcp_data_6.client) { + _LOGD(LOGD_IP6, "ipv6-pd: asking DHCPv6 for %d prefixes", needed_prefixes); + nm_device_dhcp6_renew(self, FALSE); + } else { + _LOGI(LOGD_IP6, "ipv6-pd: device doesn't use DHCPv6, can't request prefixes"); + } } gboolean -nm_device_needs_ip6_subnet (NMDevice *self) +nm_device_needs_ip6_subnet(NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->needs_ip6_subnet; + return NM_DEVICE_GET_PRIVATE(self)->needs_ip6_subnet; } /* @@ -9700,26 +9904,27 @@ nm_device_needs_ip6_subnet (NMDevice *self) * or the prefix from which it is allocated is renewed. */ void -nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet) +nm_device_use_ip6_subnet(NMDevice *self, const NMPlatformIP6Address *subnet) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPlatformIP6Address address = *subnet; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMPlatformIP6Address address = *subnet; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - if (!applied_config_get_current (&priv->ac_ip6_config)) - applied_config_init_new (&priv->ac_ip6_config, self, AF_INET6); + if (!applied_config_get_current(&priv->ac_ip6_config)) + applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); - /* Assign a ::1 address in the subnet for us. */ - address.address.s6_addr32[3] |= htonl (1); - applied_config_add_address (&priv->ac_ip6_config, NM_PLATFORM_IP_ADDRESS_CAST (&address)); + /* Assign a ::1 address in the subnet for us. */ + address.address.s6_addr32[3] |= htonl(1); + applied_config_add_address(&priv->ac_ip6_config, NM_PLATFORM_IP_ADDRESS_CAST(&address)); - _LOGD (LOGD_IP6, "ipv6-pd: using %s address (preferred for %u seconds)", - _nm_utils_inet6_ntop (&address.address, sbuf), - subnet->preferred); + _LOGD(LOGD_IP6, + "ipv6-pd: using %s address (preferred for %u seconds)", + _nm_utils_inet6_ntop(&address.address, sbuf), + subnet->preferred); - /* This also updates the ndisc if there are actual changes. */ - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing"); + /* This also updates the ndisc if there are actual changes. */ + if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) + _LOGW(LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing"); } /* @@ -9727,1301 +9932,1266 @@ nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet) * The ipv6.method=shared devices just reuse its DNS configuration. */ void -nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device) +nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMIP6Config *from_config = NULL; - guint i, len; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMIP6Config * from_config = NULL; + guint i, len; - if (applied_config_get_current (&priv->ac_ip6_config)) { - applied_config_reset_nameservers (&priv->ac_ip6_config); - applied_config_reset_searches (&priv->ac_ip6_config); - } else - applied_config_init_new (&priv->ac_ip6_config, self, AF_INET6); + if (applied_config_get_current(&priv->ac_ip6_config)) { + applied_config_reset_nameservers(&priv->ac_ip6_config); + applied_config_reset_searches(&priv->ac_ip6_config); + } else + applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); - if (from_device) - from_config = nm_device_get_ip6_config (from_device); - if (!from_config) - return; + if (from_device) + from_config = nm_device_get_ip6_config(from_device); + if (!from_config) + return; - len = nm_ip6_config_get_num_nameservers (from_config); - for (i = 0; i < len; i++) { - applied_config_add_nameserver (&priv->ac_ip6_config, - (const NMIPAddr *) nm_ip6_config_get_nameserver (from_config, i)); - } + len = nm_ip6_config_get_num_nameservers(from_config); + for (i = 0; i < len; i++) { + applied_config_add_nameserver( + &priv->ac_ip6_config, + (const NMIPAddr *) nm_ip6_config_get_nameserver(from_config, i)); + } - len = nm_ip6_config_get_num_searches (from_config); - for (i = 0; i < len; i++) { - applied_config_add_search (&priv->ac_ip6_config, - nm_ip6_config_get_search (from_config, i)); - } + len = nm_ip6_config_get_num_searches(from_config); + for (i = 0; i < len; i++) { + applied_config_add_search(&priv->ac_ip6_config, nm_ip6_config_get_search(from_config, i)); + } - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing"); + if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) + _LOGW(LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing"); } /*****************************************************************************/ static void -linklocal6_failed (NMDevice *self) +linklocal6_failed(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_clear_g_source (&priv->linklocal6_timeout_id); - nm_device_activate_schedule_ip_config_timeout (self, AF_INET6); + nm_clear_g_source(&priv->linklocal6_timeout_id); + nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); } static gboolean -linklocal6_timeout_cb (gpointer user_data) +linklocal6_timeout_cb(gpointer user_data) { - NMDevice *self = user_data; + NMDevice *self = user_data; - _LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses failed due to timeout"); - linklocal6_failed (self); - return G_SOURCE_REMOVE; + _LOGD(LOGD_DEVICE, "linklocal6: waiting for link-local addresses failed due to timeout"); + linklocal6_failed(self); + return G_SOURCE_REMOVE; } static void -linklocal6_check_complete (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - const char *method; - - if (!priv->linklocal6_timeout_id) { - /* we are not waiting for linklocal to complete. Nothing to do. */ - return; - } - - if ( !priv->ext_ip6_config_captured - || !nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { - /* we don't have a non-tentative link local address yet. Wait longer. */ - return; - } - - nm_clear_g_source (&priv->linklocal6_timeout_id); - - connection = nm_device_get_applied_connection (self); - g_assert (connection); - - method = nm_device_get_effective_ip_config_method (self, AF_INET6); - - _LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses successful, continue with method %s", method); - - if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_SHARED)) - addrconf6_start_with_link_ready (self); - else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { - if (!dhcp6_start_with_link_ready (self, connection)) { - /* Time out IPv6 instead of failing the entire activation */ - nm_device_activate_schedule_ip_config_timeout (self, AF_INET6); - } - } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); - else - g_return_if_fail (FALSE); +linklocal6_check_complete(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + const char * method; + + if (!priv->linklocal6_timeout_id) { + /* we are not waiting for linklocal to complete. Nothing to do. */ + return; + } + + if (!priv->ext_ip6_config_captured + || !nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { + /* we don't have a non-tentative link local address yet. Wait longer. */ + return; + } + + nm_clear_g_source(&priv->linklocal6_timeout_id); + + connection = nm_device_get_applied_connection(self); + g_assert(connection); + + method = nm_device_get_effective_ip_config_method(self, AF_INET6); + + _LOGD(LOGD_DEVICE, + "linklocal6: waiting for link-local addresses successful, continue with method %s", + method); + + if (NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_SHARED)) + addrconf6_start_with_link_ready(self); + else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + if (!dhcp6_start_with_link_ready(self, connection)) { + /* Time out IPv6 instead of failing the entire activation */ + nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); + } + } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + else + g_return_if_fail(FALSE); } static void -check_and_add_ipv6ll_addr (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - struct in6_addr lladdr; - NMConnection *connection; - NMSettingIP6Config *s_ip6 = NULL; - GError *error = NULL; - const char *addr_type; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - if (!priv->ipv6ll_handle) - return; - - if ( priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { - /* Already have an LL address, nothing to do */ - return; - } - - priv->ipv6ll_has = FALSE; - memset (&priv->ipv6ll_addr, 0, sizeof (priv->ipv6ll_addr)); - - memset (&lladdr, 0, sizeof (lladdr)); - lladdr.s6_addr16[0] = htons (0xfe80); - - connection = nm_device_get_applied_connection (self); - if (connection) - s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection)); - - if (s_ip6 && nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { - NMUtilsStableType stable_type; - const char *stable_id; - - stable_id = _get_stable_id (self, connection, &stable_type); - if (!nm_utils_ipv6_addr_set_stable_privacy (stable_type, - &lladdr, - nm_device_get_iface (self), - stable_id, - priv->linklocal6_dad_counter++, - &error)) { - _LOGW (LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message); - g_clear_error (&error); - linklocal6_failed (self); - return; - } - addr_type = "stable-privacy"; - } else { - NMUtilsIPv6IfaceId iid; - - if (priv->linklocal6_timeout_id) { - /* We already started and attempt to add a LL address. For the EUI-64 - * mode we can't pick a new one, we'll just fail. */ - _LOGW (LOGD_IP6, "linklocal6: DAD failed for an EUI-64 address"); - linklocal6_failed (self); - return; - } - - if (!nm_device_get_ip_iface_identifier (self, &iid, TRUE)) { - _LOGW (LOGD_IP6, "linklocal6: failed to get interface identifier; IPv6 cannot continue"); - return; - } - nm_utils_ipv6_addr_set_interface_identifier (&lladdr, iid); - addr_type = "EUI-64"; - } - - _LOGD (LOGD_IP6, "linklocal6: generated %s IPv6LL address %s", - addr_type, _nm_utils_inet6_ntop (&lladdr, sbuf)); - priv->ipv6ll_has = TRUE; - priv->ipv6ll_addr = lladdr; - ip_config_merge_and_apply (self, AF_INET6, TRUE); +check_and_add_ipv6ll_addr(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + struct in6_addr lladdr; + NMConnection * connection; + NMSettingIP6Config *s_ip6 = NULL; + GError * error = NULL; + const char * addr_type; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + + if (!priv->ipv6ll_handle) + return; + + if (priv->ext_ip6_config_captured + && nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { + /* Already have an LL address, nothing to do */ + return; + } + + priv->ipv6ll_has = FALSE; + memset(&priv->ipv6ll_addr, 0, sizeof(priv->ipv6ll_addr)); + + memset(&lladdr, 0, sizeof(lladdr)); + lladdr.s6_addr16[0] = htons(0xfe80); + + connection = nm_device_get_applied_connection(self); + if (connection) + s_ip6 = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection)); + + if (s_ip6 + && nm_setting_ip6_config_get_addr_gen_mode(s_ip6) + == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { + NMUtilsStableType stable_type; + const char * stable_id; + + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + if (!nm_utils_ipv6_addr_set_stable_privacy(stable_type, + &lladdr, + nm_device_get_iface(self), + stable_id, + priv->linklocal6_dad_counter++, + &error)) { + _LOGW(LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message); + g_clear_error(&error); + linklocal6_failed(self); + return; + } + addr_type = "stable-privacy"; + } else { + NMUtilsIPv6IfaceId iid; + + if (priv->linklocal6_timeout_id) { + /* We already started and attempt to add a LL address. For the EUI-64 + * mode we can't pick a new one, we'll just fail. */ + _LOGW(LOGD_IP6, "linklocal6: DAD failed for an EUI-64 address"); + linklocal6_failed(self); + return; + } + + if (!nm_device_get_ip_iface_identifier(self, &iid, TRUE)) { + _LOGW(LOGD_IP6, "linklocal6: failed to get interface identifier; IPv6 cannot continue"); + return; + } + nm_utils_ipv6_addr_set_interface_identifier(&lladdr, iid); + addr_type = "EUI-64"; + } + + _LOGD(LOGD_IP6, + "linklocal6: generated %s IPv6LL address %s", + addr_type, + _nm_utils_inet6_ntop(&lladdr, sbuf)); + priv->ipv6ll_has = TRUE; + priv->ipv6ll_addr = lladdr; + ip_config_merge_and_apply(self, AF_INET6, TRUE); } static gboolean -linklocal6_start (NMDevice *self) +linklocal6_start(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_clear_g_source (&priv->linklocal6_timeout_id); + nm_clear_g_source(&priv->linklocal6_timeout_id); - if ( priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) - return TRUE; + if (priv->ext_ip6_config_captured + && nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) + return TRUE; - _LOGD (LOGD_DEVICE, "linklocal6: starting IPv6 with method '%s', but the device has no link-local addresses configured. Wait.", - nm_device_get_effective_ip_config_method (self, AF_INET6)); + _LOGD(LOGD_DEVICE, + "linklocal6: starting IPv6 with method '%s', but the device has no link-local addresses " + "configured. Wait.", + nm_device_get_effective_ip_config_method(self, AF_INET6)); - check_and_add_ipv6ll_addr (self); + check_and_add_ipv6ll_addr(self); - /* Depending on the network and what the 'dad_transmits' and 'retrans_time_ms' - * sysctl values are, DAD for the IPv6LL address may take quite a while. - * FIXME: use dad/retrans sysctl values if they are higher than a minimum time. - * (rh #1101809) - */ - priv->linklocal6_timeout_id = g_timeout_add_seconds (15, linklocal6_timeout_cb, self); - return FALSE; + /* Depending on the network and what the 'dad_transmits' and 'retrans_time_ms' + * sysctl values are, DAD for the IPv6LL address may take quite a while. + * FIXME: use dad/retrans sysctl values if they are higher than a minimum time. + * (rh #1101809) + */ + priv->linklocal6_timeout_id = g_timeout_add_seconds(15, linklocal6_timeout_cb, self); + return FALSE; } /*****************************************************************************/ gint64 -nm_device_get_configured_mtu_from_connection_default (NMDevice *self, - const char *property_name, - guint32 max_mtu) +nm_device_get_configured_mtu_from_connection_default(NMDevice * self, + const char *property_name, + guint32 max_mtu) { - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - property_name, - self, - 0, max_mtu, -1); + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + property_name, + self, + 0, + max_mtu, + -1); } guint32 -nm_device_get_configured_mtu_from_connection (NMDevice *self, - GType setting_type, - NMDeviceMtuSource *out_source) -{ - const char *global_property_name; - NMConnection *connection; - NMSetting *setting; - gint64 mtu_default; - guint32 mtu = 0; - guint32 max_mtu = G_MAXUINT32; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert (out_source); - - connection = nm_device_get_applied_connection (self); - if (!connection) - g_return_val_if_reached (0); - - setting = nm_connection_get_setting (connection, setting_type); - - if (setting_type == NM_TYPE_SETTING_WIRED) { - if (setting) - mtu = nm_setting_wired_get_mtu (NM_SETTING_WIRED (setting)); - global_property_name = NM_CON_DEFAULT ("ethernet.mtu"); - } else if (setting_type == NM_TYPE_SETTING_WIRELESS) { - if (setting) - mtu = nm_setting_wireless_get_mtu (NM_SETTING_WIRELESS (setting)); - global_property_name = NM_CON_DEFAULT ("wifi.mtu"); - } else if (setting_type == NM_TYPE_SETTING_INFINIBAND) { - if (setting) - mtu = nm_setting_infiniband_get_mtu (NM_SETTING_INFINIBAND (setting)); - global_property_name = NM_CON_DEFAULT ("infiniband.mtu"); - max_mtu = NM_INFINIBAND_MAX_MTU; - } else if (setting_type == NM_TYPE_SETTING_IP_TUNNEL) { - if (setting) - mtu = nm_setting_ip_tunnel_get_mtu (NM_SETTING_IP_TUNNEL (setting)); - global_property_name = NM_CON_DEFAULT ("ip-tunnel.mtu"); - } else if (setting_type == NM_TYPE_SETTING_WIREGUARD) { - if (setting) - mtu = nm_setting_wireguard_get_mtu (NM_SETTING_WIREGUARD (setting)); - global_property_name = NM_CON_DEFAULT ("wireguard.mtu"); - } else - g_return_val_if_reached (0); - - if (mtu) { - *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; - return mtu; - } - - mtu_default = nm_device_get_configured_mtu_from_connection_default (self, global_property_name, max_mtu); - if (mtu_default >= 0) { - *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; - return (guint32) mtu_default; - } - - *out_source = NM_DEVICE_MTU_SOURCE_NONE; - return 0; +nm_device_get_configured_mtu_from_connection(NMDevice * self, + GType setting_type, + NMDeviceMtuSource *out_source) +{ + const char * global_property_name; + NMConnection *connection; + NMSetting * setting; + gint64 mtu_default; + guint32 mtu = 0; + guint32 max_mtu = G_MAXUINT32; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(out_source); + + connection = nm_device_get_applied_connection(self); + if (!connection) + g_return_val_if_reached(0); + + setting = nm_connection_get_setting(connection, setting_type); + + if (setting_type == NM_TYPE_SETTING_WIRED) { + if (setting) + mtu = nm_setting_wired_get_mtu(NM_SETTING_WIRED(setting)); + global_property_name = NM_CON_DEFAULT("ethernet.mtu"); + } else if (setting_type == NM_TYPE_SETTING_WIRELESS) { + if (setting) + mtu = nm_setting_wireless_get_mtu(NM_SETTING_WIRELESS(setting)); + global_property_name = NM_CON_DEFAULT("wifi.mtu"); + } else if (setting_type == NM_TYPE_SETTING_INFINIBAND) { + if (setting) + mtu = nm_setting_infiniband_get_mtu(NM_SETTING_INFINIBAND(setting)); + global_property_name = NM_CON_DEFAULT("infiniband.mtu"); + max_mtu = NM_INFINIBAND_MAX_MTU; + } else if (setting_type == NM_TYPE_SETTING_IP_TUNNEL) { + if (setting) + mtu = nm_setting_ip_tunnel_get_mtu(NM_SETTING_IP_TUNNEL(setting)); + global_property_name = NM_CON_DEFAULT("ip-tunnel.mtu"); + } else if (setting_type == NM_TYPE_SETTING_WIREGUARD) { + if (setting) + mtu = nm_setting_wireguard_get_mtu(NM_SETTING_WIREGUARD(setting)); + global_property_name = NM_CON_DEFAULT("wireguard.mtu"); + } else + g_return_val_if_reached(0); + + if (mtu) { + *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; + return mtu; + } + + mtu_default = + nm_device_get_configured_mtu_from_connection_default(self, global_property_name, max_mtu); + if (mtu_default >= 0) { + *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; + return (guint32) mtu_default; + } + + *out_source = NM_DEVICE_MTU_SOURCE_NONE; + return 0; } guint32 -nm_device_get_configured_mtu_for_wired (NMDevice *self, - NMDeviceMtuSource *out_source, - gboolean *out_force) +nm_device_get_configured_mtu_for_wired(NMDevice * self, + NMDeviceMtuSource *out_source, + gboolean * out_force) { - return nm_device_get_configured_mtu_from_connection (self, - NM_TYPE_SETTING_WIRED, - out_source); + return nm_device_get_configured_mtu_from_connection(self, NM_TYPE_SETTING_WIRED, out_source); } guint32 -nm_device_get_configured_mtu_wired_parent (NMDevice *self, - NMDeviceMtuSource *out_source, - gboolean *out_force) -{ - guint32 mtu = 0; - guint32 parent_mtu = 0; - int ifindex; - - ifindex = nm_device_parent_get_ifindex (self); - if (ifindex > 0) { - parent_mtu = nm_platform_link_get_mtu (nm_device_get_platform (self), ifindex); - if (parent_mtu >= NM_DEVICE_GET_CLASS (self)->mtu_parent_delta) - parent_mtu -= NM_DEVICE_GET_CLASS (self)->mtu_parent_delta; - else - parent_mtu = 0; - } - - mtu = nm_device_get_configured_mtu_for_wired (self, out_source, NULL); - - if (parent_mtu && mtu > parent_mtu) { - /* Trying to set a MTU that is out of range from configuration: - * fall back to the parent MTU and set force flag so that it - * overrides an MTU with higher priority already configured. - */ - *out_source = NM_DEVICE_MTU_SOURCE_PARENT; - *out_force = TRUE; - return parent_mtu; - } - - if (*out_source != NM_DEVICE_MTU_SOURCE_NONE) { - nm_assert (mtu > 0); - return mtu; - } - - /* Inherit the MTU from parent device, if any */ - if (parent_mtu) { - mtu = parent_mtu; - *out_source = NM_DEVICE_MTU_SOURCE_PARENT; - } - - return mtu; +nm_device_get_configured_mtu_wired_parent(NMDevice * self, + NMDeviceMtuSource *out_source, + gboolean * out_force) +{ + guint32 mtu = 0; + guint32 parent_mtu = 0; + int ifindex; + + ifindex = nm_device_parent_get_ifindex(self); + if (ifindex > 0) { + parent_mtu = nm_platform_link_get_mtu(nm_device_get_platform(self), ifindex); + if (parent_mtu >= NM_DEVICE_GET_CLASS(self)->mtu_parent_delta) + parent_mtu -= NM_DEVICE_GET_CLASS(self)->mtu_parent_delta; + else + parent_mtu = 0; + } + + mtu = nm_device_get_configured_mtu_for_wired(self, out_source, NULL); + + if (parent_mtu && mtu > parent_mtu) { + /* Trying to set a MTU that is out of range from configuration: + * fall back to the parent MTU and set force flag so that it + * overrides an MTU with higher priority already configured. + */ + *out_source = NM_DEVICE_MTU_SOURCE_PARENT; + *out_force = TRUE; + return parent_mtu; + } + + if (*out_source != NM_DEVICE_MTU_SOURCE_NONE) { + nm_assert(mtu > 0); + return mtu; + } + + /* Inherit the MTU from parent device, if any */ + if (parent_mtu) { + mtu = parent_mtu; + *out_source = NM_DEVICE_MTU_SOURCE_PARENT; + } + + return mtu; } /*****************************************************************************/ static void -_set_mtu (NMDevice *self, guint32 mtu) +_set_mtu(NMDevice *self, guint32 mtu) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->mtu == mtu) - return; + if (priv->mtu == mtu) + return; - priv->mtu = mtu; - _notify (self, PROP_MTU); + priv->mtu = mtu; + _notify(self, PROP_MTU); - if (priv->master) { - /* changing the MTU of a slave, might require the master to reset - * its MTU. Note that the master usually cannot set a MTU larger - * then the slave's. Hence, when the slave increases the MTU, - * master might want to retry setting the MTU. */ - nm_device_commit_mtu (priv->master); - } + if (priv->master) { + /* changing the MTU of a slave, might require the master to reset + * its MTU. Note that the master usually cannot set a MTU larger + * then the slave's. Hence, when the slave increases the MTU, + * master might want to retry setting the MTU. */ + nm_device_commit_mtu(priv->master); + } } static gboolean -set_platform_mtu (NMDevice *self, guint32 mtu) +set_platform_mtu(NMDevice *self, guint32 mtu) { - int r; + int r; - r = nm_platform_link_set_mtu (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - mtu); - return (r != -NME_PL_CANT_SET_MTU); + r = nm_platform_link_set_mtu(nm_device_get_platform(self), nm_device_get_ip_ifindex(self), mtu); + return (r != -NME_PL_CANT_SET_MTU); } static void -_commit_mtu (NMDevice *self, const NMIP4Config *config) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceMtuSource source = NM_DEVICE_MTU_SOURCE_NONE; - guint32 ip6_mtu, ip6_mtu_orig; - guint32 mtu_desired, mtu_desired_orig; - guint32 mtu_plat; - struct { - gboolean initialized; - guint32 value; - } ip6_mtu_sysctl = { 0, }; - int ifindex; - char sbuf[64], sbuf1[64], sbuf2[64]; - gboolean success = TRUE; - - ifindex = nm_device_get_ip_ifindex (self); - if (ifindex <= 0) - return; - - if ( !nm_device_get_applied_connection (self) - || nm_device_sys_iface_state_is_external_or_assume (self)) { - /* we don't tamper with the MTU of disconnected and - * external/assumed devices. */ - return; - } - - { - guint32 mtu = 0; - gboolean force = FALSE; - - /* We take the MTU from various sources: (in order of increasing - * priority) parent link, IP configuration (which contains the - * MTU from DHCP/PPP), connection profile. - * - * We could just compare it with the platform MTU and apply it - * when different, but this would revert at random times manual - * changes done by the user with the MTU from the connection. - * - * Instead, we remember the source of the currently configured - * MTU and apply the new one only when the new source has a - * higher priority, so that we don't set a MTU from same source - * multiple times. An exception to this is for the PARENT - * source, since we need to keep tracking the parent MTU when it - * changes. - * - * The subclass can set the @force argument to TRUE to signal that the - * returned MTU should be applied even if it has a lower priority. This - * is useful when the value from a lower source should - * preempt the one from higher ones. - */ - - if (NM_DEVICE_GET_CLASS (self)->get_configured_mtu) - mtu = NM_DEVICE_GET_CLASS (self)->get_configured_mtu (self, &source, &force); - - if ( config - && !force - && source < NM_DEVICE_MTU_SOURCE_IP_CONFIG - && nm_ip4_config_get_mtu (config)) { - mtu = nm_ip4_config_get_mtu (config); - source = NM_DEVICE_MTU_SOURCE_IP_CONFIG; - } - - if (mtu != 0) { - _LOGT (LOGD_DEVICE, - "mtu: value %u from source '%s' (%u), current source '%s' (%u)%s", - (guint) mtu, - mtu_source_to_str (source), (guint) source, - mtu_source_to_str (priv->mtu_source), (guint) priv->mtu_source, - force ? " (forced)" : ""); - } - - if ( mtu != 0 - && ( force - || source > priv->mtu_source - || (priv->mtu_source == NM_DEVICE_MTU_SOURCE_PARENT && source == priv->mtu_source))) - mtu_desired = mtu; - else { - mtu_desired = 0; - source = NM_DEVICE_MTU_SOURCE_NONE; - } - } - - if (mtu_desired && mtu_desired < 1280) { - NMSettingIPConfig *s_ip6; - - s_ip6 = nm_device_get_applied_setting (self, NM_TYPE_SETTING_IP6_CONFIG); - if ( s_ip6 - && !NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6), - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { - /* the interface has IPv6 enabled. The MTU with IPv6 cannot be smaller - * then 1280. - * - * For slave-devices (that don't have @s_ip6 we) don't do this fixup because - * it's anyway an unsolved problem when the slave configures a conflicting - * MTU. */ - mtu_desired = 1280; - } - } - - ip6_mtu = priv->ip6_mtu; - if (!ip6_mtu && priv->mtu_source == NM_DEVICE_MTU_SOURCE_NONE) { - /* initially, if the IPv6 MTU is not specified, grow it as large as the - * link MTU @mtu_desired. Only exception is, if @mtu_desired is so small - * to disable IPv6. */ - if (mtu_desired >= 1280) - ip6_mtu = mtu_desired; - } - - if (!ip6_mtu && !mtu_desired) - return; - - mtu_desired_orig = mtu_desired; - ip6_mtu_orig = ip6_mtu; - - mtu_plat = nm_platform_link_get_mtu (nm_device_get_platform (self), ifindex); - - if (ip6_mtu) { - ip6_mtu = NM_MAX (1280, ip6_mtu); - - if (!mtu_desired) - mtu_desired = mtu_plat; - - if (mtu_desired) { - mtu_desired = NM_MAX (1280, mtu_desired); - - if (mtu_desired < ip6_mtu) - ip6_mtu = mtu_desired; - } - } - - _LOGT (LOGD_DEVICE, "mtu: device-mtu: %u%s, ipv6-mtu: %u%s, ifindex: %d", - (guint) mtu_desired, - mtu_desired == mtu_desired_orig ? "" : nm_sprintf_buf (sbuf1, " (was %u)", (guint) mtu_desired_orig), - (guint) ip6_mtu, - ip6_mtu == ip6_mtu_orig ? "" : nm_sprintf_buf (sbuf2, " (was %u)", (guint) ip6_mtu_orig), - ifindex); - -#define _IP6_MTU_SYS() \ - ({ \ - if (!ip6_mtu_sysctl.initialized) { \ - ip6_mtu_sysctl.value = nm_device_sysctl_ip_conf_get_int_checked (self, AF_INET6, "mtu", 10, 0, G_MAXUINT32, 0); \ - ip6_mtu_sysctl.initialized = TRUE; \ - } \ - ip6_mtu_sysctl.value; \ - }) - if ( (mtu_desired && mtu_desired != mtu_plat) - || (ip6_mtu && ip6_mtu != _IP6_MTU_SYS ())) { - gboolean anticipated_failure = FALSE; - - if (!priv->mtu_initial && !priv->ip6_mtu_initial) { - /* before touching any of the MTU parameters, record the - * original setting to restore on deactivation. */ - priv->mtu_initial = mtu_plat; - priv->ip6_mtu_initial = _IP6_MTU_SYS (); - } - - if (mtu_desired && mtu_desired != mtu_plat) { - if (!NM_DEVICE_GET_CLASS (self)->set_platform_mtu (self, mtu_desired)) { - anticipated_failure = TRUE; - success = FALSE; - _LOGW (LOGD_DEVICE, "mtu: failure to set MTU. %s", - NM_IS_DEVICE_VLAN (self) - ? "Is the parent's MTU size large enough?" - : (!c_list_is_empty (&priv->slaves) - ? "Are the MTU sizes of the slaves large enough?" - : "Did you configure the MTU correctly?")); - } - priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_msec () + CARRIER_WAIT_TIME_AFTER_MTU_MS; - } - - if (ip6_mtu && ip6_mtu != _IP6_MTU_SYS ()) { - if (!nm_device_sysctl_ip_conf_set (self, AF_INET6, "mtu", - nm_sprintf_buf (sbuf, "%u", (unsigned) ip6_mtu))) { - int errsv = errno; - NMLogLevel level = LOGL_WARN; - const char *msg = NULL; - - success = FALSE; - - if (anticipated_failure && errsv == EINVAL) { - level = LOGL_DEBUG; - msg = "Is the underlying MTU value successfully set?"; - } else if (!g_file_test ("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) { - level = LOGL_DEBUG; - msg = "IPv6 is disabled"; - success = TRUE; - } - - _NMLOG (level, - LOGD_DEVICE, - "mtu: failure to set IPv6 MTU%s%s", - msg ? ": " : "", - msg ?: ""); - } - priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_msec () + CARRIER_WAIT_TIME_AFTER_MTU_MS; - } - } - - if (success && source != NM_DEVICE_MTU_SOURCE_NONE) - priv->mtu_source = source; +_commit_mtu(NMDevice *self, const NMIP4Config *config) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceMtuSource source = NM_DEVICE_MTU_SOURCE_NONE; + guint32 ip6_mtu, ip6_mtu_orig; + guint32 mtu_desired, mtu_desired_orig; + guint32 mtu_plat; + struct { + gboolean initialized; + guint32 value; + } ip6_mtu_sysctl = { + 0, + }; + int ifindex; + char sbuf[64], sbuf1[64], sbuf2[64]; + gboolean success = TRUE; + + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex <= 0) + return; + + if (!nm_device_get_applied_connection(self) + || nm_device_sys_iface_state_is_external_or_assume(self)) { + /* we don't tamper with the MTU of disconnected and + * external/assumed devices. */ + return; + } + + { + guint32 mtu = 0; + gboolean force = FALSE; + + /* We take the MTU from various sources: (in order of increasing + * priority) parent link, IP configuration (which contains the + * MTU from DHCP/PPP), connection profile. + * + * We could just compare it with the platform MTU and apply it + * when different, but this would revert at random times manual + * changes done by the user with the MTU from the connection. + * + * Instead, we remember the source of the currently configured + * MTU and apply the new one only when the new source has a + * higher priority, so that we don't set a MTU from same source + * multiple times. An exception to this is for the PARENT + * source, since we need to keep tracking the parent MTU when it + * changes. + * + * The subclass can set the @force argument to TRUE to signal that the + * returned MTU should be applied even if it has a lower priority. This + * is useful when the value from a lower source should + * preempt the one from higher ones. + */ + + if (NM_DEVICE_GET_CLASS(self)->get_configured_mtu) + mtu = NM_DEVICE_GET_CLASS(self)->get_configured_mtu(self, &source, &force); + + if (config && !force && source < NM_DEVICE_MTU_SOURCE_IP_CONFIG + && nm_ip4_config_get_mtu(config)) { + mtu = nm_ip4_config_get_mtu(config); + source = NM_DEVICE_MTU_SOURCE_IP_CONFIG; + } + + if (mtu != 0) { + _LOGT(LOGD_DEVICE, + "mtu: value %u from source '%s' (%u), current source '%s' (%u)%s", + (guint) mtu, + mtu_source_to_str(source), + (guint) source, + mtu_source_to_str(priv->mtu_source), + (guint) priv->mtu_source, + force ? " (forced)" : ""); + } + + if (mtu != 0 + && (force || source > priv->mtu_source + || (priv->mtu_source == NM_DEVICE_MTU_SOURCE_PARENT && source == priv->mtu_source))) + mtu_desired = mtu; + else { + mtu_desired = 0; + source = NM_DEVICE_MTU_SOURCE_NONE; + } + } + + if (mtu_desired && mtu_desired < 1280) { + NMSettingIPConfig *s_ip6; + + s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6 + && !NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip6), + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { + /* the interface has IPv6 enabled. The MTU with IPv6 cannot be smaller + * then 1280. + * + * For slave-devices (that don't have @s_ip6 we) don't do this fixup because + * it's anyway an unsolved problem when the slave configures a conflicting + * MTU. */ + mtu_desired = 1280; + } + } + + ip6_mtu = priv->ip6_mtu; + if (!ip6_mtu && priv->mtu_source == NM_DEVICE_MTU_SOURCE_NONE) { + /* initially, if the IPv6 MTU is not specified, grow it as large as the + * link MTU @mtu_desired. Only exception is, if @mtu_desired is so small + * to disable IPv6. */ + if (mtu_desired >= 1280) + ip6_mtu = mtu_desired; + } + + if (!ip6_mtu && !mtu_desired) + return; + + mtu_desired_orig = mtu_desired; + ip6_mtu_orig = ip6_mtu; + + mtu_plat = nm_platform_link_get_mtu(nm_device_get_platform(self), ifindex); + + if (ip6_mtu) { + ip6_mtu = NM_MAX(1280, ip6_mtu); + + if (!mtu_desired) + mtu_desired = mtu_plat; + + if (mtu_desired) { + mtu_desired = NM_MAX(1280, mtu_desired); + + if (mtu_desired < ip6_mtu) + ip6_mtu = mtu_desired; + } + } + + _LOGT(LOGD_DEVICE, + "mtu: device-mtu: %u%s, ipv6-mtu: %u%s, ifindex: %d", + (guint) mtu_desired, + mtu_desired == mtu_desired_orig + ? "" + : nm_sprintf_buf(sbuf1, " (was %u)", (guint) mtu_desired_orig), + (guint) ip6_mtu, + ip6_mtu == ip6_mtu_orig ? "" : nm_sprintf_buf(sbuf2, " (was %u)", (guint) ip6_mtu_orig), + ifindex); + +#define _IP6_MTU_SYS() \ + ({ \ + if (!ip6_mtu_sysctl.initialized) { \ + ip6_mtu_sysctl.value = nm_device_sysctl_ip_conf_get_int_checked(self, \ + AF_INET6, \ + "mtu", \ + 10, \ + 0, \ + G_MAXUINT32, \ + 0); \ + ip6_mtu_sysctl.initialized = TRUE; \ + } \ + ip6_mtu_sysctl.value; \ + }) + if ((mtu_desired && mtu_desired != mtu_plat) || (ip6_mtu && ip6_mtu != _IP6_MTU_SYS())) { + gboolean anticipated_failure = FALSE; + + if (!priv->mtu_initial && !priv->ip6_mtu_initial) { + /* before touching any of the MTU parameters, record the + * original setting to restore on deactivation. */ + priv->mtu_initial = mtu_plat; + priv->ip6_mtu_initial = _IP6_MTU_SYS(); + } + + if (mtu_desired && mtu_desired != mtu_plat) { + if (!NM_DEVICE_GET_CLASS(self)->set_platform_mtu(self, mtu_desired)) { + anticipated_failure = TRUE; + success = FALSE; + _LOGW(LOGD_DEVICE, + "mtu: failure to set MTU. %s", + NM_IS_DEVICE_VLAN(self) + ? "Is the parent's MTU size large enough?" + : (!c_list_is_empty(&priv->slaves) + ? "Are the MTU sizes of the slaves large enough?" + : "Did you configure the MTU correctly?")); + } + priv->carrier_wait_until_ms = + nm_utils_get_monotonic_timestamp_msec() + CARRIER_WAIT_TIME_AFTER_MTU_MS; + } + + if (ip6_mtu && ip6_mtu != _IP6_MTU_SYS()) { + if (!nm_device_sysctl_ip_conf_set(self, + AF_INET6, + "mtu", + nm_sprintf_buf(sbuf, "%u", (unsigned) ip6_mtu))) { + int errsv = errno; + NMLogLevel level = LOGL_WARN; + const char *msg = NULL; + + success = FALSE; + + if (anticipated_failure && errsv == EINVAL) { + level = LOGL_DEBUG; + msg = "Is the underlying MTU value successfully set?"; + } else if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) { + level = LOGL_DEBUG; + msg = "IPv6 is disabled"; + success = TRUE; + } + + _NMLOG(level, + LOGD_DEVICE, + "mtu: failure to set IPv6 MTU%s%s", + msg ? ": " : "", + msg ?: ""); + } + priv->carrier_wait_until_ms = + nm_utils_get_monotonic_timestamp_msec() + CARRIER_WAIT_TIME_AFTER_MTU_MS; + } + } + + if (success && source != NM_DEVICE_MTU_SOURCE_NONE) + priv->mtu_source = source; #undef _IP6_MTU_SYS } void -nm_device_commit_mtu (NMDevice *self) +nm_device_commit_mtu(NMDevice *self) { - NMDeviceState state; + NMDeviceState state; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - state = nm_device_get_state (self); - if ( state >= NM_DEVICE_STATE_CONFIG - && state < NM_DEVICE_STATE_DEACTIVATING) { - _LOGT (LOGD_DEVICE, "mtu: commit-mtu..."); - _commit_mtu (self, NM_DEVICE_GET_PRIVATE (self)->ip_config_4); - } else - _LOGT (LOGD_DEVICE, "mtu: commit-mtu... skip due to state %s", nm_device_state_to_str (state)); + state = nm_device_get_state(self); + if (state >= NM_DEVICE_STATE_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) { + _LOGT(LOGD_DEVICE, "mtu: commit-mtu..."); + _commit_mtu(self, NM_DEVICE_GET_PRIVATE(self)->ip_config_4); + } else + _LOGT(LOGD_DEVICE, + "mtu: commit-mtu... skip due to state %s", + nm_device_state_to_str(state)); } static void -ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, NMDevice *self) -{ - NMNDiscConfigMap changed = changed_int; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint i; - - g_return_if_fail (priv->act_request.obj); - - if (!applied_config_get_current (&priv->ac_ip6_config)) - applied_config_init_new (&priv->ac_ip6_config, self, AF_INET6); - - if (changed & NM_NDISC_CONFIG_ADDRESSES) { - guint8 plen; - guint32 ifa_flags; - - /* Check, whether kernel is recent enough to help user space handling RA. - * If it's not supported, we have no ipv6-privacy and must add autoconf - * addresses as /128. The reason for the /128 is to prevent the kernel - * from adding a prefix route for this address. */ - ifa_flags = 0; - if (nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) { - ifa_flags |= IFA_F_NOPREFIXROUTE; - if (NM_IN_SET (priv->ndisc_use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)) - ifa_flags |= IFA_F_MANAGETEMPADDR; - plen = 64; - } else - plen = 128; - - nm_ip6_config_reset_addresses_ndisc ((NMIP6Config *) priv->ac_ip6_config.orig, - rdata->addresses, - rdata->addresses_n, - plen, - ifa_flags); - if (priv->ac_ip6_config.current) { - nm_ip6_config_reset_addresses_ndisc ((NMIP6Config *) priv->ac_ip6_config.current, - rdata->addresses, - rdata->addresses_n, - plen, - ifa_flags); - } - } - - if (NM_FLAGS_ANY (changed, NM_NDISC_CONFIG_ROUTES - | NM_NDISC_CONFIG_GATEWAYS)) { - nm_ip6_config_reset_routes_ndisc ((NMIP6Config *) priv->ac_ip6_config.orig, - rdata->gateways, - rdata->gateways_n, - rdata->routes, - rdata->routes_n, - nm_device_get_route_table (self, AF_INET6), - nm_device_get_route_metric (self, AF_INET6), - nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); - if (priv->ac_ip6_config.current) { - nm_ip6_config_reset_routes_ndisc ((NMIP6Config *) priv->ac_ip6_config.current, - rdata->gateways, - rdata->gateways_n, - rdata->routes, - rdata->routes_n, - nm_device_get_route_table (self, AF_INET6), - nm_device_get_route_metric (self, AF_INET6), - nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); - } - - } - - if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { - /* Rebuild DNS server list from neighbor discovery cache. */ - applied_config_reset_nameservers (&priv->ac_ip6_config); - - for (i = 0; i < rdata->dns_servers_n; i++) - applied_config_add_nameserver (&priv->ac_ip6_config, (const NMIPAddr *) &rdata->dns_servers[i].address); - } - - if (changed & NM_NDISC_CONFIG_DNS_DOMAINS) { - /* Rebuild domain list from neighbor discovery cache. */ - applied_config_reset_searches (&priv->ac_ip6_config); - - for (i = 0; i < rdata->dns_domains_n; i++) - applied_config_add_search (&priv->ac_ip6_config, rdata->dns_domains[i].domain); - } - - if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { - dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, TRUE); - - priv->dhcp6.mode = rdata->dhcp_level; - if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE) { - _LOGD (LOGD_DEVICE | LOGD_DHCP6, - "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" - " as requested by IPv6 router..."); - if (!dhcp6_start (self, FALSE)) { - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DHCP_START_FAILED); - return; - } - } - } - } - - if (changed & NM_NDISC_CONFIG_HOP_LIMIT) - nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe (nm_device_get_platform (self), nm_device_get_ip_iface (self), rdata->hop_limit); - - if (changed & NM_NDISC_CONFIG_REACHABLE_TIME) { - nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time (nm_device_get_platform (self), - nm_device_get_ip_iface (self), - rdata->reachable_time_ms); - } - - if (changed & NM_NDISC_CONFIG_RETRANS_TIMER) { - nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time (nm_device_get_platform (self), - nm_device_get_ip_iface (self), - rdata->retrans_timer_ms); - } - - if (changed & NM_NDISC_CONFIG_MTU) { - if (priv->ip6_mtu != rdata->mtu) { - _LOGD (LOGD_DEVICE, "mtu: set IPv6 MTU to %u", (guint) rdata->mtu); - priv->ip6_mtu = rdata->mtu; - } - } - - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); +ndisc_config_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, NMDevice *self) +{ + NMNDiscConfigMap changed = changed_int; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + guint i; + + g_return_if_fail(priv->act_request.obj); + + if (!applied_config_get_current(&priv->ac_ip6_config)) + applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); + + if (changed & NM_NDISC_CONFIG_ADDRESSES) { + guint8 plen; + guint32 ifa_flags; + + /* Check, whether kernel is recent enough to help user space handling RA. + * If it's not supported, we have no ipv6-privacy and must add autoconf + * addresses as /128. The reason for the /128 is to prevent the kernel + * from adding a prefix route for this address. */ + ifa_flags = 0; + if (nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) { + ifa_flags |= IFA_F_NOPREFIXROUTE; + if (NM_IN_SET(priv->ndisc_use_tempaddr, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)) + ifa_flags |= IFA_F_MANAGETEMPADDR; + plen = 64; + } else + plen = 128; + + nm_ip6_config_reset_addresses_ndisc((NMIP6Config *) priv->ac_ip6_config.orig, + rdata->addresses, + rdata->addresses_n, + plen, + ifa_flags); + if (priv->ac_ip6_config.current) { + nm_ip6_config_reset_addresses_ndisc((NMIP6Config *) priv->ac_ip6_config.current, + rdata->addresses, + rdata->addresses_n, + plen, + ifa_flags); + } + } + + if (NM_FLAGS_ANY(changed, NM_NDISC_CONFIG_ROUTES | NM_NDISC_CONFIG_GATEWAYS)) { + nm_ip6_config_reset_routes_ndisc( + (NMIP6Config *) priv->ac_ip6_config.orig, + rdata->gateways, + rdata->gateways_n, + rdata->routes, + rdata->routes_n, + nm_device_get_route_table(self, AF_INET6), + nm_device_get_route_metric(self, AF_INET6), + nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); + if (priv->ac_ip6_config.current) { + nm_ip6_config_reset_routes_ndisc( + (NMIP6Config *) priv->ac_ip6_config.current, + rdata->gateways, + rdata->gateways_n, + rdata->routes, + rdata->routes_n, + nm_device_get_route_table(self, AF_INET6), + nm_device_get_route_metric(self, AF_INET6), + nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); + } + } + + if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { + /* Rebuild DNS server list from neighbor discovery cache. */ + applied_config_reset_nameservers(&priv->ac_ip6_config); + + for (i = 0; i < rdata->dns_servers_n; i++) + applied_config_add_nameserver(&priv->ac_ip6_config, + (const NMIPAddr *) &rdata->dns_servers[i].address); + } + + if (changed & NM_NDISC_CONFIG_DNS_DOMAINS) { + /* Rebuild domain list from neighbor discovery cache. */ + applied_config_reset_searches(&priv->ac_ip6_config); + + for (i = 0; i < rdata->dns_domains_n; i++) + applied_config_add_search(&priv->ac_ip6_config, rdata->dns_domains[i].domain); + } + + if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { + dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, TRUE); + + priv->dhcp6.mode = rdata->dhcp_level; + if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE) { + _LOGD(LOGD_DEVICE | LOGD_DHCP6, + "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" + " as requested by IPv6 router..."); + if (!dhcp6_start(self, FALSE)) { + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { + nm_device_state_changed(self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_DHCP_START_FAILED); + return; + } + } + } + } + + if (changed & NM_NDISC_CONFIG_HOP_LIMIT) + nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(nm_device_get_platform(self), + nm_device_get_ip_iface(self), + rdata->hop_limit); + + if (changed & NM_NDISC_CONFIG_REACHABLE_TIME) { + nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(nm_device_get_platform(self), + nm_device_get_ip_iface(self), + rdata->reachable_time_ms); + } + + if (changed & NM_NDISC_CONFIG_RETRANS_TIMER) { + nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(nm_device_get_platform(self), + nm_device_get_ip_iface(self), + rdata->retrans_timer_ms); + } + + if (changed & NM_NDISC_CONFIG_MTU) { + if (priv->ip6_mtu != rdata->mtu) { + _LOGD(LOGD_DEVICE, "mtu: set IPv6 MTU to %u", (guint) rdata->mtu); + priv->ip6_mtu = rdata->mtu; + } + } + + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); } static void -ndisc_ra_timeout (NMNDisc *ndisc, NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - /* We don't want to stop listening for router advertisements completely, - * but instead let device activation continue activating. If an RA - * shows up later, we'll use it as long as the device is not disconnected. - */ - - _LOGD (LOGD_IP6, "timed out waiting for IPv6 router advertisement"); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { - /* If RA is our only source of addressing information and we don't - * ever receive one, then time out IPv6. But if there is other - * IPv6 configuration, like manual IPv6 addresses or external IPv6 - * config, consider that sufficient for IPv6 success. - * - * FIXME: it doesn't seem correct to determine this based on which - * addresses we find inside priv->ip_config_6. - */ - if ( priv->ip_config_6 - && nm_ip6_config_find_first_address (priv->ip_config_6, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); - else - nm_device_activate_schedule_ip_config_timeout (self, AF_INET6); - } +ndisc_ra_timeout(NMNDisc *ndisc, NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + /* We don't want to stop listening for router advertisements completely, + * but instead let device activation continue activating. If an RA + * shows up later, we'll use it as long as the device is not disconnected. + */ + + _LOGD(LOGD_IP6, "timed out waiting for IPv6 router advertisement"); + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { + /* If RA is our only source of addressing information and we don't + * ever receive one, then time out IPv6. But if there is other + * IPv6 configuration, like manual IPv6 addresses or external IPv6 + * config, consider that sufficient for IPv6 success. + * + * FIXME: it doesn't seem correct to determine this based on which + * addresses we find inside priv->ip_config_6. + */ + if (priv->ip_config_6 + && nm_ip6_config_find_first_address(priv->ip_config_6, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + else + nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); + } } static void -addrconf6_start_with_link_ready (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMUtilsIPv6IfaceId iid; - - g_assert (priv->ndisc); - - if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) { - _LOGD (LOGD_IP6, "addrconf6: using the device EUI-64 identifier"); - nm_ndisc_set_iid (priv->ndisc, iid); - } else { - /* Don't abort the addrconf at this point -- if ndisc needs the iid - * it will notice this itself. */ - _LOGI (LOGD_IP6, "addrconf6: no interface identifier; IPv6 address creation may fail"); - } - - /* Apply any manual configuration before starting RA */ - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "failed to apply manual IPv6 configuration"); - - if (nm_ndisc_get_node_type (priv->ndisc) == NM_NDISC_NODE_TYPE_ROUTER) { - nm_device_sysctl_ip_conf_set (self, AF_INET6, "forwarding", "1"); - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); - priv->needs_ip6_subnet = TRUE; - g_signal_emit (self, signals[IP6_SUBNET_NEEDED], 0); - } - - priv->ndisc_changed_id = g_signal_connect (priv->ndisc, - NM_NDISC_CONFIG_RECEIVED, - G_CALLBACK (ndisc_config_changed), - self); - priv->ndisc_timeout_id = g_signal_connect (priv->ndisc, - NM_NDISC_RA_TIMEOUT_SIGNAL, - G_CALLBACK (ndisc_ra_timeout), - self); - - ndisc_set_router_config (priv->ndisc, self); - nm_ndisc_start (priv->ndisc); - priv->ndisc_started = TRUE; - return; -} - -static NMNDiscNodeType -ndisc_node_type (NMDevice *self) -{ - if (nm_streq (nm_device_get_effective_ip_config_method (self, AF_INET6), - NM_SETTING_IP4_CONFIG_METHOD_SHARED)) - return NM_NDISC_NODE_TYPE_ROUTER; - return NM_NDISC_NODE_TYPE_HOST; -} - -static gint32 -get_ra_timeout (NMDevice *self) -{ - NMConnection *connection; - gint32 timeout; - - G_STATIC_ASSERT_EXPR (NM_RA_TIMEOUT_DEFAULT == 0); - G_STATIC_ASSERT_EXPR (NM_RA_TIMEOUT_INFINITY == G_MAXINT32); - - connection = nm_device_get_applied_connection (self); - - timeout = nm_setting_ip6_config_get_ra_timeout (NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection))); - nm_assert (timeout >= 0); - if (timeout) - return timeout; - - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv6.ra-timeout"), - self, - 0, G_MAXINT32, 0); +addrconf6_start_with_link_ready(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMUtilsIPv6IfaceId iid; + + g_assert(priv->ndisc); + + if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) { + _LOGD(LOGD_IP6, "addrconf6: using the device EUI-64 identifier"); + nm_ndisc_set_iid(priv->ndisc, iid); + } else { + /* Don't abort the addrconf at this point -- if ndisc needs the iid + * it will notice this itself. */ + _LOGI(LOGD_IP6, "addrconf6: no interface identifier; IPv6 address creation may fail"); + } + + /* Apply any manual configuration before starting RA */ + if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) + _LOGW(LOGD_IP6, "failed to apply manual IPv6 configuration"); + + if (nm_ndisc_get_node_type(priv->ndisc) == NM_NDISC_NODE_TYPE_ROUTER) { + nm_device_sysctl_ip_conf_set(self, AF_INET6, "forwarding", "1"); + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + priv->needs_ip6_subnet = TRUE; + g_signal_emit(self, signals[IP6_SUBNET_NEEDED], 0); + } + + priv->ndisc_changed_id = g_signal_connect(priv->ndisc, + NM_NDISC_CONFIG_RECEIVED, + G_CALLBACK(ndisc_config_changed), + self); + priv->ndisc_timeout_id = g_signal_connect(priv->ndisc, + NM_NDISC_RA_TIMEOUT_SIGNAL, + G_CALLBACK(ndisc_ra_timeout), + self); + + ndisc_set_router_config(priv->ndisc, self); + nm_ndisc_start(priv->ndisc); + priv->ndisc_started = TRUE; + return; } static gboolean -addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - NMSettingIP6Config *s_ip6 = NULL; - GError *error = NULL; - NMUtilsStableType stable_type; - const char *stable_id; - - connection = nm_device_get_applied_connection (self); - g_assert (connection); - - nm_assert (!applied_config_get_current (&priv->ac_ip6_config)); - applied_config_clear (&priv->ac_ip6_config); - - nm_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source (&priv->rt6_temporary_not_available_id); - - s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection)); - g_assert (s_ip6); - - stable_id = _get_stable_id (self, connection, &stable_type); - priv->ndisc = nm_lndp_ndisc_new (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - nm_device_get_ip_iface (self), - stable_type, - stable_id, - nm_setting_ip6_config_get_addr_gen_mode (s_ip6), - ndisc_node_type (self), - get_ra_timeout (self), - &error); - if (!priv->ndisc) { - _LOGE (LOGD_IP6, "addrconf6: failed to start neighbor discovery: %s", error->message); - g_error_free (error); - return FALSE; - } - - priv->ndisc_use_tempaddr = use_tempaddr; - - if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) - && !nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) { - _LOGW (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for " - "IPv6 private addresses. This feature is not available"); - } - - /* ensure link local is ready... */ - if (!linklocal6_start (self)) { - /* wait for the LL address to show up */ - return TRUE; - } - - /* already have the LL address; kick off neighbor discovery */ - addrconf6_start_with_link_ready (self); - return TRUE; +addrconf6_start(NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + NMSettingIP6Config *s_ip6 = NULL; + GError * error = NULL; + NMUtilsStableType stable_type; + const char * stable_id; + NMNDiscNodeType node_type; + int max_addresses; + int router_solicitations; + int router_solicitation_interval; + guint32 ra_timeout; + guint32 default_ra_timeout; + + connection = nm_device_get_applied_connection(self); + g_assert(connection); + + nm_assert(!applied_config_get_current(&priv->ac_ip6_config)); + applied_config_clear(&priv->ac_ip6_config); + + nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); + nm_clear_g_source(&priv->rt6_temporary_not_available_id); + + s_ip6 = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection)); + g_assert(s_ip6); + + if (nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET6), + NM_SETTING_IP4_CONFIG_METHOD_SHARED)) + node_type = NM_NDISC_NODE_TYPE_ROUTER; + else + node_type = NM_NDISC_NODE_TYPE_HOST; + + nm_lndp_ndisc_get_sysctl(nm_device_get_platform(self), + nm_device_get_ip_iface(self), + &max_addresses, + &router_solicitations, + &router_solicitation_interval, + &default_ra_timeout); + + if (node_type == NM_NDISC_NODE_TYPE_ROUTER) + ra_timeout = 0u; + else { + ra_timeout = _prop_get_ipv6_ra_timeout(self); + if (ra_timeout == 0u) + ra_timeout = default_ra_timeout; + } + + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + priv->ndisc = nm_lndp_ndisc_new(nm_device_get_platform(self), + nm_device_get_ip_ifindex(self), + nm_device_get_ip_iface(self), + stable_type, + stable_id, + nm_setting_ip6_config_get_addr_gen_mode(s_ip6), + node_type, + max_addresses, + router_solicitations, + router_solicitation_interval, + ra_timeout, + &error); + if (!priv->ndisc) { + _LOGE(LOGD_IP6, "addrconf6: failed to start neighbor discovery: %s", error->message); + g_error_free(error); + return FALSE; + } + + priv->ndisc_use_tempaddr = use_tempaddr; + + if (NM_IN_SET(use_tempaddr, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) + && !nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) { + _LOGW(LOGD_IP6, + "The kernel does not support extended IFA_FLAGS needed by NM for " + "IPv6 private addresses. This feature is not available"); + } + + /* ensure link local is ready... */ + if (!linklocal6_start(self)) { + /* wait for the LL address to show up */ + return TRUE; + } + + /* already have the LL address; kick off neighbor discovery */ + addrconf6_start_with_link_ready(self); + return TRUE; } static void -addrconf6_cleanup (NMDevice *self) +addrconf6_cleanup(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->ndisc_started = FALSE; - nm_clear_g_signal_handler (priv->ndisc, &priv->ndisc_changed_id); - nm_clear_g_signal_handler (priv->ndisc, &priv->ndisc_timeout_id); + priv->ndisc_started = FALSE; + nm_clear_g_signal_handler(priv->ndisc, &priv->ndisc_changed_id); + nm_clear_g_signal_handler(priv->ndisc, &priv->ndisc_timeout_id); - applied_config_clear (&priv->ac_ip6_config); - nm_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source (&priv->rt6_temporary_not_available_id); - g_clear_object (&priv->ndisc); + applied_config_clear(&priv->ac_ip6_config); + nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); + nm_clear_g_source(&priv->rt6_temporary_not_available_id); + if (priv->ndisc) { + nm_ndisc_stop(priv->ndisc); + g_clear_object(&priv->ndisc); + } } /*****************************************************************************/ static void -save_ip6_properties (NMDevice *self) -{ - static const char *const ip6_properties_to_save[] = { - "accept_ra", - "forwarding", - "disable_ipv6", - "hop_limit", - "use_tempaddr", - }; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPlatform *platform = nm_device_get_platform (self); - const char *ifname; - char *value; - int i; - - g_hash_table_remove_all (priv->ip6_saved_properties); - - ifname = nm_device_get_ip_iface_from_platform (self); - if (!ifname) - return; - - for (i = 0; i < G_N_ELEMENTS (ip6_properties_to_save); i++) { - value = nm_platform_sysctl_ip_conf_get (platform, - AF_INET6, - ifname, - ip6_properties_to_save[i]); - if (value) { - g_hash_table_insert (priv->ip6_saved_properties, - (char *) ip6_properties_to_save[i], - value); - } - } +save_ip6_properties(NMDevice *self) +{ + static const char *const ip6_properties_to_save[] = { + "accept_ra", + "forwarding", + "disable_ipv6", + "hop_limit", + "use_tempaddr", + }; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMPlatform * platform = nm_device_get_platform(self); + const char * ifname; + char * value; + int i; + + g_hash_table_remove_all(priv->ip6_saved_properties); + + ifname = nm_device_get_ip_iface_from_platform(self); + if (!ifname) + return; + + for (i = 0; i < G_N_ELEMENTS(ip6_properties_to_save); i++) { + value = + nm_platform_sysctl_ip_conf_get(platform, AF_INET6, ifname, ip6_properties_to_save[i]); + if (value) { + g_hash_table_insert(priv->ip6_saved_properties, + (char *) ip6_properties_to_save[i], + value); + } + } } static void -restore_ip6_properties (NMDevice *self) +restore_ip6_properties(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - GHashTableIter iter; - gpointer key, value; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + GHashTableIter iter; + gpointer key, value; - g_hash_table_iter_init (&iter, priv->ip6_saved_properties); - while (g_hash_table_iter_next (&iter, &key, &value)) { - /* Don't touch "disable_ipv6" if we're doing userland IPv6LL */ - if ( priv->ipv6ll_handle - && nm_streq (key, "disable_ipv6")) - continue; - nm_device_sysctl_ip_conf_set (self, AF_INET6, key, value); - } + g_hash_table_iter_init(&iter, priv->ip6_saved_properties); + while (g_hash_table_iter_next(&iter, &key, &value)) { + /* Don't touch "disable_ipv6" if we're doing userland IPv6LL */ + if (priv->ipv6ll_handle && nm_streq(key, "disable_ipv6")) + continue; + nm_device_sysctl_ip_conf_set(self, AF_INET6, key, value); + } } static void -set_disable_ipv6 (NMDevice *self, const char *value) +set_disable_ipv6(NMDevice *self, const char *value) { - /* We only touch disable_ipv6 when NM is not managing the IPv6LL address */ - if (!NM_DEVICE_GET_PRIVATE (self)->ipv6ll_handle) - nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", value); + /* We only touch disable_ipv6 when NM is not managing the IPv6LL address */ + if (!NM_DEVICE_GET_PRIVATE(self)->ipv6ll_handle) + nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", value); } static void -set_nm_ipv6ll (NMDevice *self, gboolean enable) +set_nm_ipv6ll(NMDevice *self, gboolean enable) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - int ifindex = nm_device_get_ip_ifindex (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + int ifindex = nm_device_get_ip_ifindex(self); - if (!nm_platform_kernel_support_get (NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) - return; + if (!nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) + return; - priv->ipv6ll_handle = enable; - if (ifindex > 0) { - const char *detail = enable ? "enable" : "disable"; - int r; + priv->ipv6ll_handle = enable; + if (ifindex > 0) { + const char *detail = enable ? "enable" : "disable"; + int r; - _LOGD (LOGD_IP6, "will %s userland IPv6LL", detail); - r = nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), ifindex, enable); - if (r < 0) { - _NMLOG ( NM_IN_SET (r, -NME_PL_NOT_FOUND, - -NME_PL_OPNOTSUPP) - ? LOGL_DEBUG - : LOGL_WARN, - LOGD_IP6, - "failed to %s userspace IPv6LL address handling (%s)", - detail, - nm_strerror (r)); - } + _LOGD(LOGD_IP6, "will %s userland IPv6LL", detail); + r = nm_platform_link_set_user_ipv6ll_enabled(nm_device_get_platform(self), ifindex, enable); + if (r < 0) { + _NMLOG(NM_IN_SET(r, -NME_PL_NOT_FOUND, -NME_PL_OPNOTSUPP) ? LOGL_DEBUG : LOGL_WARN, + LOGD_IP6, + "failed to %s userspace IPv6LL address handling (%s)", + detail, + nm_strerror(r)); + } - if (enable) { - gs_free char *value = NULL; + if (enable) { + gs_free char *value = NULL; - /* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */ - value = nm_device_sysctl_ip_conf_get (self, - AF_INET6, - "disable_ipv6"); - if (nm_streq0 (value, "0")) - nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", "1"); - - /* Ensure IPv6 is enabled */ - nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", "0"); - } - - } -} - -/*****************************************************************************/ - -static NMSettingIP6ConfigPrivacy -_ip6_privacy_clamp (NMSettingIP6ConfigPrivacy use_tempaddr) -{ - switch (use_tempaddr) { - case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - return use_tempaddr; - default: - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - } -} + /* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */ + value = nm_device_sysctl_ip_conf_get(self, AF_INET6, "disable_ipv6"); + if (nm_streq0(value, "0")) + nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1"); -static NMSettingIP6ConfigPrivacy -_ip6_privacy_get (NMDevice *self) -{ - NMSettingIP6ConfigPrivacy ip6_privacy; - NMConnection *connection; - - g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - - /* 1.) First look at the per-connection setting. If it is not -1 (unknown), - * use it. */ - connection = nm_device_get_applied_connection (self); - if (connection) { - NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); - - if (s_ip6) { - ip6_privacy = nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)); - ip6_privacy = _ip6_privacy_clamp (ip6_privacy); - if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) - return ip6_privacy; - } - } - - /* 2.) use the default value from the configuration. */ - ip6_privacy = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("ipv6.ip6-privacy"), - self, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) - return ip6_privacy; - - if (!nm_device_get_ip_ifindex (self)) - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - - /* 3.) No valid default-value configured. Fallback to reading sysctl. - * - * Instead of reading static config files in /etc, just read the current sysctl value. - * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves - * the "default" entry untouched. */ - ip6_privacy = nm_platform_sysctl_get_int32 (nm_device_get_platform (self), - NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/default/use_tempaddr"), - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - return _ip6_privacy_clamp (ip6_privacy); + /* Ensure IPv6 is enabled */ + nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "0"); + } + } } /*****************************************************************************/ static gboolean -ip_requires_slaves (NMDevice *self, int addr_family) +ip_requires_slaves(NMDevice *self, int addr_family) { - const char *method; + const char *method; - method = nm_device_get_effective_ip_config_method (self, addr_family); + method = nm_device_get_effective_ip_config_method(self, addr_family); - if (addr_family == AF_INET) - return nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + if (addr_family == AF_INET) + return nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) - * to complete addressing. SLAAC and DHCP need a peer to provide a prefix. - */ - return NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP); + /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) + * to complete addressing. SLAAC and DHCP need a peer to provide a prefix. + */ + return NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP); } static NMActStageReturn -act_stage3_ip_config_start (NMDevice *self, - int addr_family, - gpointer *out_config, - NMDeviceStateReason *out_failure_reason) -{ - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - const char *method; - - nm_assert_addr_family (addr_family); - - connection = nm_device_get_applied_connection (self); - - g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); - - if ( connection_ip_method_requires_carrier (connection, addr_family, NULL) - && nm_device_is_master (self) - && !priv->carrier) { - _LOGI (LOGD_IP | LOGD_DEVICE, - "IPv%c config waiting until carrier is on", - nm_utils_addr_family_to_char (addr_family)); - return NM_ACT_STAGE_RETURN_IP_WAIT; - } - - if ( nm_device_is_master (self) - && ip_requires_slaves (self, addr_family)) { - /* If the master has no ready slaves, and depends on slaves for - * a successful IP configuration attempt, then postpone IP addressing. - */ - if (!have_any_ready_slaves (self)) { - _LOGI (LOGD_DEVICE | LOGD_IP, - "IPv%c config waiting until slaves are ready", - nm_utils_addr_family_to_char (addr_family)); - return NM_ACT_STAGE_RETURN_IP_WAIT; - } - } - - if (!IS_IPv4) - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - - method = nm_device_get_effective_ip_config_method (self, addr_family); - - _LOGD (LOGD_IP | LOGD_DEVICE, "IPv%c config method is %s", - nm_utils_addr_family_to_char (addr_family), method); - - if (IS_IPv4) { - if (NM_IN_STRSET (method, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { - NMSettingIPConfig *s_ip4; - NMIP4Config **configs, *config; - guint num_addresses; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - g_return_val_if_fail (s_ip4, NM_ACT_STAGE_RETURN_FAILURE); - num_addresses = nm_setting_ip_config_get_num_addresses (s_ip4); - - if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - ret = dhcp4_start (self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); - return ret; - } - } else { - g_return_val_if_fail (num_addresses != 0, NM_ACT_STAGE_RETURN_FAILURE); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (num_addresses) { - config = nm_device_ip4_config_new (self); - nm_ip4_config_merge_setting (config, - nm_connection_get_setting_ip4_config (connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, - NM_SETTING_CONNECTION_LLMNR_DEFAULT, - nm_device_get_route_table (self, AF_INET), - nm_device_get_route_metric (self, AF_INET)); - configs = g_new0 (NMIP4Config *, 2); - configs[0] = config; - ipv4_dad_start (self, configs, ipv4_manual_method_apply); - } - } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { - ret = ipv4ll_start (self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); - } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - if (out_config) { - *out_config = shared4_new_config (self, connection); - if (*out_config) { - priv->dnsmasq_manager = nm_dnsmasq_manager_new (nm_device_get_ip_iface (self)); - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - } else - g_return_val_if_reached (NM_ACT_STAGE_RETURN_FAILURE); - } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - ret = NM_ACT_STAGE_RETURN_SUCCESS; - else - _LOGW (LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method); - - return ret; - } else { - NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - const char *ip6_privacy_str = "0"; - NMPlatform *platform; - int ifindex; - - if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { - nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", "1"); - return NM_ACT_STAGE_RETURN_IP_DONE; - } - - if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { - if (!nm_device_sys_iface_state_is_external (self)) { - if (priv->master) { - /* If a device only has an IPv6 link-local address, - * we don't generate an assumed connection. Therefore, - * when a new slave connection (without IP configuration) - * is activated on the device, the link-local address - * remains configured. The IP configuration of an activated - * slave should not depend on the previous state. Flush - * addresses and routes on activation. - */ - ifindex = nm_device_get_ip_ifindex (self); - platform = nm_device_get_platform (self); - - if (ifindex > 0) { - gs_unref_object NMIP6Config *config = nm_device_ip6_config_new (self); - - nm_platform_ip_route_flush (platform, AF_INET6, ifindex); - nm_platform_ip_address_flush (platform, AF_INET6, ifindex); - nm_device_set_ip_config (self, AF_INET6, (NMIPConfig *) config, FALSE, NULL); - } - } else { - gboolean ipv6ll_handle_old = priv->ipv6ll_handle; - - /* When activating an IPv6 'ignore' connection we need to revert back - * to kernel IPv6LL, but the kernel won't actually assign an address - * to the interface until disable_ipv6 is bounced. - */ - set_nm_ipv6ll (self, FALSE); - if (ipv6ll_handle_old) - nm_device_sysctl_ip_conf_set (self, AF_INET6, "disable_ipv6", "1"); - restore_ip6_properties (self); - } - } - return NM_ACT_STAGE_RETURN_IP_DONE; - } - - /* Ensure the MTU makes sense. If it was below 1280 the kernel would not - * expose any ipv6 sysctls or allow presence of any addresses on the interface, - * including LL, which * would make it impossible to autoconfigure MTU to a - * correct value. */ - _commit_mtu (self, priv->ip_config_4); - - /* Any method past this point requires an IPv6LL address. Use NM-controlled - * IPv6LL if this is not an assumed connection, since assumed connections - * will already have IPv6 set up. - */ - if (!nm_device_sys_iface_state_is_external_or_assume (self)) - set_nm_ipv6ll (self, TRUE); - - /* Re-enable IPv6 on the interface */ - nm_device_sysctl_ip_conf_set (self, AF_INET6, "accept_ra", "0"); - set_disable_ipv6 (self, "0"); - - /* Synchronize external IPv6 configuration with kernel, since - * linklocal6_start() uses the information there to determine if we can - * proceed with the selected method (SLAAC, DHCP, link-local). - */ - 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_multi_index (self), - nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - - ip6_privacy = _ip6_privacy_get (self); - - if (NM_IN_STRSET (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - if (!addrconf6_start (self, ip6_privacy)) { - /* IPv6 might be disabled; allow IPv4 to proceed */ - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - } else - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { - ret = linklocal6_start (self) - ? NM_ACT_STAGE_RETURN_SUCCESS - : NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; - if (!dhcp6_start (self, TRUE)) { - /* IPv6 might be disabled; allow IPv4 to proceed */ - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - } else - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) - ret = NM_ACT_STAGE_RETURN_SUCCESS; - else - _LOGW (LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); - - if ( ret != NM_ACT_STAGE_RETURN_FAILURE - && !nm_device_sys_iface_state_is_external_or_assume (self)) { - switch (ip6_privacy) { - case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: - case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - ip6_privacy_str = "0"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - ip6_privacy_str = "1"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - ip6_privacy_str = "2"; - break; - } - nm_device_sysctl_ip_conf_set (self, AF_INET6, "use_tempaddr", ip6_privacy_str); - } - - return ret; - } +act_stage3_ip_config_start(NMDevice * self, + int addr_family, + gpointer * out_config, + NMDeviceStateReason *out_failure_reason) +{ + const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + const char * method; + + nm_assert_addr_family(addr_family); + + connection = nm_device_get_applied_connection(self); + + g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); + + if (connection_ip_method_requires_carrier(connection, addr_family, NULL) + && nm_device_is_master(self) && !priv->carrier) { + _LOGI(LOGD_IP | LOGD_DEVICE, + "IPv%c config waiting until carrier is on", + nm_utils_addr_family_to_char(addr_family)); + return NM_ACT_STAGE_RETURN_IP_WAIT; + } + + if (nm_device_is_master(self) && ip_requires_slaves(self, addr_family)) { + /* If the master has no ready slaves, and depends on slaves for + * a successful IP configuration attempt, then postpone IP addressing. + */ + if (!have_any_ready_slaves(self)) { + _LOGI(LOGD_DEVICE | LOGD_IP, + "IPv%c config waiting until slaves are ready", + nm_utils_addr_family_to_char(addr_family)); + return NM_ACT_STAGE_RETURN_IP_WAIT; + } + } + + if (!IS_IPv4) + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; + + method = nm_device_get_effective_ip_config_method(self, addr_family); + + _LOGD(LOGD_IP | LOGD_DEVICE, + "IPv%c config method is %s", + nm_utils_addr_family_to_char(addr_family), + method); + + if (IS_IPv4) { + if (NM_IN_STRSET(method, + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + NMSettingIPConfig *s_ip4; + NMIP4Config ** configs, *config; + guint num_addresses; + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + g_return_val_if_fail(s_ip4, NM_ACT_STAGE_RETURN_FAILURE); + num_addresses = nm_setting_ip_config_get_num_addresses(s_ip4); + + if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + ret = dhcp4_start(self); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); + return ret; + } + } else { + g_return_val_if_fail(num_addresses != 0, NM_ACT_STAGE_RETURN_FAILURE); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } + + if (num_addresses) { + config = nm_device_ip4_config_new(self); + nm_ip4_config_merge_setting(config, + nm_connection_get_setting_ip4_config(connection), + NM_SETTING_CONNECTION_MDNS_DEFAULT, + NM_SETTING_CONNECTION_LLMNR_DEFAULT, + nm_device_get_route_table(self, AF_INET), + nm_device_get_route_metric(self, AF_INET)); + configs = g_new0(NMIP4Config *, 2); + configs[0] = config; + ipv4_dad_start(self, configs, ipv4_manual_method_apply); + } + } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + ret = ipv4ll_start(self); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) + NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); + } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { + if (out_config) { + *out_config = shared4_new_config(self, connection); + if (*out_config) { + priv->dnsmasq_manager = nm_dnsmasq_manager_new(nm_device_get_ip_iface(self)); + ret = NM_ACT_STAGE_RETURN_SUCCESS; + } else { + NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + ret = NM_ACT_STAGE_RETURN_FAILURE; + } + } else + g_return_val_if_reached(NM_ACT_STAGE_RETURN_FAILURE); + } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + ret = NM_ACT_STAGE_RETURN_SUCCESS; + else + _LOGW(LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method); + + return ret; + } else { + NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + const char * ip6_privacy_str = "0"; + NMPlatform * platform; + int ifindex; + + if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { + nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1"); + return NM_ACT_STAGE_RETURN_IP_DONE; + } + + if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + if (!nm_device_sys_iface_state_is_external(self)) { + if (priv->master) { + /* If a device only has an IPv6 link-local address, + * we don't generate an assumed connection. Therefore, + * when a new slave connection (without IP configuration) + * is activated on the device, the link-local address + * remains configured. The IP configuration of an activated + * slave should not depend on the previous state. Flush + * addresses and routes on activation. + */ + ifindex = nm_device_get_ip_ifindex(self); + platform = nm_device_get_platform(self); + + if (ifindex > 0) { + gs_unref_object NMIP6Config *config = nm_device_ip6_config_new(self); + + nm_platform_ip_route_flush(platform, AF_INET6, ifindex); + nm_platform_ip_address_flush(platform, AF_INET6, ifindex); + nm_device_set_ip_config(self, AF_INET6, (NMIPConfig *) config, FALSE, NULL); + } + } else { + gboolean ipv6ll_handle_old = priv->ipv6ll_handle; + + /* When activating an IPv6 'ignore' connection we need to revert back + * to kernel IPv6LL, but the kernel won't actually assign an address + * to the interface until disable_ipv6 is bounced. + */ + set_nm_ipv6ll(self, FALSE); + if (ipv6ll_handle_old) + nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1"); + restore_ip6_properties(self); + } + } + return NM_ACT_STAGE_RETURN_IP_DONE; + } + + /* Ensure the MTU makes sense. If it was below 1280 the kernel would not + * expose any ipv6 sysctls or allow presence of any addresses on the interface, + * including LL, which * would make it impossible to autoconfigure MTU to a + * correct value. */ + _commit_mtu(self, priv->ip_config_4); + + /* Any method past this point requires an IPv6LL address. Use NM-controlled + * IPv6LL if this is not an assumed connection, since assumed connections + * will already have IPv6 set up. + */ + if (!nm_device_sys_iface_state_is_external_or_assume(self)) + set_nm_ipv6ll(self, TRUE); + + /* Re-enable IPv6 on the interface */ + nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", "0"); + set_disable_ipv6(self, "0"); + + /* Synchronize external IPv6 configuration with kernel, since + * linklocal6_start() uses the information there to determine if we can + * proceed with the selected method (SLAAC, DHCP, link-local). + */ + 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_multi_index(self), + nm_device_get_platform(self), + nm_device_get_ip_ifindex(self), + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + + ip6_privacy = _prop_get_ipv6_ip6_privacy(self); + + if (NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { + if (!addrconf6_start(self, ip6_privacy)) { + /* IPv6 might be disabled; allow IPv4 to proceed */ + ret = NM_ACT_STAGE_RETURN_IP_FAIL; + } else + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { + ret = + linklocal6_start(self) ? NM_ACT_STAGE_RETURN_SUCCESS : NM_ACT_STAGE_RETURN_POSTPONE; + } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; + if (!dhcp6_start(self, TRUE)) { + /* IPv6 might be disabled; allow IPv4 to proceed */ + ret = NM_ACT_STAGE_RETURN_IP_FAIL; + } else + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + ret = NM_ACT_STAGE_RETURN_SUCCESS; + else + _LOGW(LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); + + if (ret != NM_ACT_STAGE_RETURN_FAILURE + && !nm_device_sys_iface_state_is_external_or_assume(self)) { + switch (ip6_privacy) { + case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: + case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: + ip6_privacy_str = "0"; + break; + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: + ip6_privacy_str = "1"; + break; + case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: + ip6_privacy_str = "2"; + break; + } + nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", ip6_privacy_str); + } + + return ret; + } } /** @@ -11031,41 +11201,44 @@ act_stage3_ip_config_start (NMDevice *self, * Try starting IPv4 configuration. */ gboolean -nm_device_activate_stage3_ip4_start (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActStageReturn ret; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - gs_unref_object NMIP4Config *ip4_config = NULL; - - g_assert (priv->ip_state_4 == NM_DEVICE_IP_STATE_WAIT); - - if (nm_device_sys_iface_state_is_external (self)) { - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_DONE); - check_ip_state (self, FALSE, TRUE); - return TRUE; - } - - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_CONF); - ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip_config_start (self, AF_INET, (gpointer *) &ip4_config, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) - nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (ip4_config)); - else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_DONE); - check_ip_state (self, FALSE, TRUE); - } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); - return FALSE; - } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { - /* Activation not wanted */ - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_FAIL); - } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { - /* Wait for something to try IP config again */ - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_WAIT); - } else - g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); - - return TRUE; +nm_device_activate_stage3_ip4_start(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMActStageReturn ret; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + gs_unref_object NMIP4Config *ip4_config = NULL; + + g_assert(priv->ip_state_4 == NM_DEVICE_IP_STATE_WAIT); + + if (nm_device_sys_iface_state_is_external(self)) { + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); + check_ip_state(self, FALSE, TRUE); + return TRUE; + } + + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_CONF); + ret = NM_DEVICE_GET_CLASS(self)->act_stage3_ip_config_start(self, + AF_INET, + (gpointer *) &ip4_config, + &failure_reason); + if (ret == NM_ACT_STAGE_RETURN_SUCCESS) + nm_device_activate_schedule_ip_config_result(self, AF_INET, NM_IP_CONFIG_CAST(ip4_config)); + else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); + check_ip_state(self, FALSE, TRUE); + } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); + return FALSE; + } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { + /* Activation not wanted */ + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_FAIL); + } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { + /* Wait for something to try IP config again */ + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_WAIT); + } else + g_assert(ret == NM_ACT_STAGE_RETURN_POSTPONE); + + return TRUE; } /** @@ -11075,48 +11248,51 @@ nm_device_activate_stage3_ip4_start (NMDevice *self) * Try starting IPv6 configuration. */ gboolean -nm_device_activate_stage3_ip6_start (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActStageReturn ret; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - gs_unref_object NMIP6Config *ip6_config = NULL; - - g_assert (priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT); - - if (nm_device_sys_iface_state_is_external (self)) { - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_DONE); - check_ip_state (self, FALSE, TRUE); - return TRUE; - } - - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_CONF); - ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip_config_start (self, AF_INET6, (gpointer *) &ip6_config, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - if (!ip6_config) - ip6_config = nm_device_ip6_config_new (self); - /* Here we get a static IPv6 config, like for Shared where it's - * autogenerated or from modems where it comes from ModemManager. - */ - nm_assert (!applied_config_get_current (&priv->ac_ip6_config)); - applied_config_init (&priv->ac_ip6_config, ip6_config); - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); - } else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_DONE); - check_ip_state (self, FALSE, TRUE); - } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); - return FALSE; - } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { - /* Activation not wanted */ - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_FAIL); - } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { - /* Wait for something to try IP config again */ - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); - } else - g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); - - return TRUE; +nm_device_activate_stage3_ip6_start(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMActStageReturn ret; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + gs_unref_object NMIP6Config *ip6_config = NULL; + + g_assert(priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT); + + if (nm_device_sys_iface_state_is_external(self)) { + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_DONE); + check_ip_state(self, FALSE, TRUE); + return TRUE; + } + + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_CONF); + ret = NM_DEVICE_GET_CLASS(self)->act_stage3_ip_config_start(self, + AF_INET6, + (gpointer *) &ip6_config, + &failure_reason); + if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { + if (!ip6_config) + ip6_config = nm_device_ip6_config_new(self); + /* Here we get a static IPv6 config, like for Shared where it's + * autogenerated or from modems where it comes from ModemManager. + */ + nm_assert(!applied_config_get_current(&priv->ac_ip6_config)); + applied_config_init(&priv->ac_ip6_config, ip6_config); + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + } else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_DONE); + check_ip_state(self, FALSE, TRUE); + } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); + return FALSE; + } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { + /* Activation not wanted */ + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_FAIL); + } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { + /* Wait for something to try IP config again */ + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); + } else + g_assert(ret == NM_ACT_STAGE_RETURN_POSTPONE); + + return TRUE; } /* @@ -11126,117 +11302,117 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) * */ static void -activate_stage3_ip_config_start (NMDevice *self) +activate_stage3_ip_config_start(NMDevice *self) { - int ifindex; + int ifindex; - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_WAIT); - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_WAIT); + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); - _active_connection_set_state_flags (self, - NM_ACTIVATION_STATE_FLAG_LAYER2_READY); + _active_connection_set_state_flags(self, NM_ACTIVATION_STATE_FLAG_LAYER2_READY); - nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); + nm_device_state_changed(self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); - /* Device should be up before we can do anything with it */ - if ( (ifindex = nm_device_get_ip_ifindex (self)) > 0 - && !nm_platform_link_is_up (nm_device_get_platform (self), ifindex)) - _LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self)); + /* Device should be up before we can do anything with it */ + if ((ifindex = nm_device_get_ip_ifindex(self)) > 0 + && !nm_platform_link_is_up(nm_device_get_platform(self), ifindex)) + _LOGW(LOGD_DEVICE, + "interface %s not up for IP configuration", + nm_device_get_ip_iface(self)); - /* IPv4 */ - if ( nm_device_activate_ip4_state_in_wait (self) - && !nm_device_activate_stage3_ip4_start (self)) - return; + /* IPv4 */ + if (nm_device_activate_ip4_state_in_wait(self) && !nm_device_activate_stage3_ip4_start(self)) + return; - /* IPv6 */ - if ( nm_device_activate_ip6_state_in_wait (self) - && !nm_device_activate_stage3_ip6_start (self)) - return; + /* IPv6 */ + if (nm_device_activate_ip6_state_in_wait(self) && !nm_device_activate_stage3_ip6_start(self)) + return; - /* Proxy */ - nm_device_set_proxy_config (self, NULL); + /* Proxy */ + nm_device_set_proxy_config(self, NULL); - check_ip_state (self, TRUE, TRUE); + check_ip_state(self, TRUE, TRUE); } static void -fw_change_zone_cb (NMFirewallManager *firewall_manager, - NMFirewallManagerCallId *call_id, - GError *error, - gpointer user_data) +fw_change_zone_cb(NMFirewallManager * firewall_manager, + NMFirewallManagerCallId *call_id, + GError * error, + gpointer user_data) { - NMDevice *self = user_data; - NMDevicePrivate *priv; + NMDevice * self = user_data; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->fw_call != call_id) - g_return_if_reached (); + if (priv->fw_call != call_id) + g_return_if_reached(); - priv->fw_call = NULL; + priv->fw_call = NULL; - if (nm_utils_error_is_cancelled (error)) - return; + if (nm_utils_error_is_cancelled(error)) + return; - switch (priv->fw_state) { - case FIREWALL_STATE_WAIT_STAGE_3: - priv->fw_state = FIREWALL_STATE_INITIALIZED; - nm_device_activate_schedule_stage3_ip_config_start (self); - break; - case FIREWALL_STATE_WAIT_IP_CONFIG: - priv->fw_state = FIREWALL_STATE_INITIALIZED; - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE || priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) - nm_device_start_ip_check (self); - break; - case FIREWALL_STATE_INITIALIZED: - break; - default: - g_return_if_reached (); - } + switch (priv->fw_state) { + case FIREWALL_STATE_WAIT_STAGE_3: + priv->fw_state = FIREWALL_STATE_INITIALIZED; + nm_device_activate_schedule_stage3_ip_config_start(self); + break; + case FIREWALL_STATE_WAIT_IP_CONFIG: + priv->fw_state = FIREWALL_STATE_INITIALIZED; + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE + || priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) + nm_device_start_ip_check(self); + break; + case FIREWALL_STATE_INITIALIZED: + break; + default: + g_return_if_reached(); + } } static void -fw_change_zone (NMDevice *self) +fw_change_zone(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *applied_connection; - NMSettingConnection *s_con; - const char *zone; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * applied_connection; + NMSettingConnection *s_con; + const char * zone; - nm_assert (priv->fw_state >= FIREWALL_STATE_INITIALIZED); + nm_assert(priv->fw_state >= FIREWALL_STATE_INITIALIZED); - applied_connection = nm_device_get_applied_connection (self); - nm_assert (applied_connection); + applied_connection = nm_device_get_applied_connection(self); + nm_assert(applied_connection); - s_con = nm_connection_get_setting_connection (applied_connection); - nm_assert (s_con); + s_con = nm_connection_get_setting_connection(applied_connection); + nm_assert(s_con); - if (priv->fw_call) { - nm_firewall_manager_cancel_call (priv->fw_call); - nm_assert (!priv->fw_call); - } + if (priv->fw_call) { + nm_firewall_manager_cancel_call(priv->fw_call); + nm_assert(!priv->fw_call); + } - if (G_UNLIKELY (!priv->fw_mgr)) - priv->fw_mgr = g_object_ref (nm_firewall_manager_get ()); + if (G_UNLIKELY(!priv->fw_mgr)) + priv->fw_mgr = g_object_ref(nm_firewall_manager_get()); - zone = nm_setting_connection_get_zone (s_con); + zone = nm_setting_connection_get_zone(s_con); #if WITH_FIREWALLD_ZONE - if (!zone || zone[0] == '\0') { - if ( nm_streq0 (nm_device_get_effective_ip_config_method (self, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_SHARED) - || nm_streq0 (nm_device_get_effective_ip_config_method (self, AF_INET6), - NM_SETTING_IP6_CONFIG_METHOD_SHARED)) - zone = "nm-shared"; - } + if (!zone || zone[0] == '\0') { + if (nm_streq0(nm_device_get_effective_ip_config_method(self, AF_INET), + NM_SETTING_IP4_CONFIG_METHOD_SHARED) + || nm_streq0(nm_device_get_effective_ip_config_method(self, AF_INET6), + NM_SETTING_IP6_CONFIG_METHOD_SHARED)) + zone = "nm-shared"; + } #endif - priv->fw_call = nm_firewall_manager_add_or_change_zone (priv->fw_mgr, - nm_device_get_ip_iface (self), - zone, - FALSE, /* change zone */ - fw_change_zone_cb, - self); + priv->fw_call = nm_firewall_manager_add_or_change_zone(priv->fw_mgr, + nm_device_get_ip_iface(self), + zone, + FALSE, /* change zone */ + fw_change_zone_cb, + self); } /* @@ -11245,51 +11421,50 @@ fw_change_zone (NMDevice *self) * Schedule IP configuration start */ void -nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) +nm_device_activate_schedule_stage3_ip_config_start(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); + priv = NM_DEVICE_GET_PRIVATE(self); + g_return_if_fail(priv->act_request.obj); - /* Add the interface to the specified firewall zone */ - if (priv->fw_state == FIREWALL_STATE_UNMANAGED) { - if (!nm_device_sys_iface_state_is_external (self)) { - priv->fw_state = FIREWALL_STATE_WAIT_STAGE_3; - fw_change_zone (self); - return; - } + /* Add the interface to the specified firewall zone */ + if (priv->fw_state == FIREWALL_STATE_UNMANAGED) { + if (!nm_device_sys_iface_state_is_external(self)) { + priv->fw_state = FIREWALL_STATE_WAIT_STAGE_3; + fw_change_zone(self); + return; + } - /* fake success. */ - priv->fw_state = FIREWALL_STATE_INITIALIZED; - } else if (priv->fw_state == FIREWALL_STATE_WAIT_STAGE_3) { - /* a firewall call for stage3 is pending. Return and wait. */ - return; - } + /* fake success. */ + priv->fw_state = FIREWALL_STATE_INITIALIZED; + } else if (priv->fw_state == FIREWALL_STATE_WAIT_STAGE_3) { + /* a firewall call for stage3 is pending. Return and wait. */ + return; + } - nm_assert (priv->fw_state == FIREWALL_STATE_INITIALIZED); + nm_assert(priv->fw_state == FIREWALL_STATE_INITIALIZED); - activation_source_schedule (self, activate_stage3_ip_config_start, AF_INET); + activation_source_schedule(self, activate_stage3_ip_config_start, AF_INET); } static NMActStageReturn -act_stage4_ip_config_timeout (NMDevice *self, - int addr_family, - NMDeviceStateReason *out_failure_reason) +act_stage4_ip_config_timeout(NMDevice * self, + int addr_family, + NMDeviceStateReason *out_failure_reason) { - nm_assert_addr_family (addr_family); + nm_assert_addr_family(addr_family); - if (!get_ip_config_may_fail (self, addr_family)) { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return NM_ACT_STAGE_RETURN_FAILURE; - } + if (!get_ip_config_may_fail(self, addr_family)) { + NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return NM_ACT_STAGE_RETURN_FAILURE; + } - return NM_ACT_STAGE_RETURN_SUCCESS; + return NM_ACT_STAGE_RETURN_SUCCESS; } - /* * nm_device_activate_stage4_ip4_config_timeout * @@ -11297,417 +11472,469 @@ act_stage4_ip_config_timeout (NMDevice *self, * */ static void -activate_stage4_ip_config_timeout_4 (NMDevice *self) +activate_stage4_ip_config_timeout_4(NMDevice *self) { - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip_config_timeout (self, AF_INET6, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - return; - else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); - return; - } - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + ret = NM_DEVICE_GET_CLASS(self)->act_stage4_ip_config_timeout(self, AF_INET, &failure_reason); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) + return; + else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); + return; + } + g_assert(ret == NM_ACT_STAGE_RETURN_SUCCESS); - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_FAIL); + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_FAIL); - check_ip_state (self, FALSE, TRUE); + check_ip_state(self, FALSE, TRUE); } void -nm_device_activate_schedule_ip_config_timeout (NMDevice *self, - int addr_family) +nm_device_activate_schedule_ip_config_timeout(NMDevice *self, int addr_family) { - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - g_return_if_fail (priv->act_request.obj); + g_return_if_fail(priv->act_request.obj); - activation_source_schedule (self, activate_stage4_ip_config_timeout_x[IS_IPv4], addr_family); + activation_source_schedule(self, activate_stage4_ip_config_timeout_x[IS_IPv4], addr_family); } static void -activate_stage4_ip_config_timeout_6 (NMDevice *self) +activate_stage4_ip_config_timeout_6(NMDevice *self) { - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip_config_timeout (self, AF_INET6, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - return; - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, failure_reason); - return; - } - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + ret = NM_DEVICE_GET_CLASS(self)->act_stage4_ip_config_timeout(self, AF_INET6, &failure_reason); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) + return; + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); + return; + } + g_assert(ret == NM_ACT_STAGE_RETURN_SUCCESS); - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_FAIL); + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_FAIL); - check_ip_state (self, FALSE, TRUE); + check_ip_state(self, FALSE, TRUE); } static gboolean -share_init (NMDevice *self, GError **error) -{ - char *modules[] = { "ip_tables", "iptable_nat", "nf_nat_ftp", "nf_nat_irc", - "nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323", - NULL }; - char **iter; - int errsv; - - if (nm_platform_sysctl_get_int32 (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), -1) == 1) { - /* nothing to do. */ - } else if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_forward"), "1")) { - errsv = errno; - _LOGD (LOGD_SHARING, "share: error enabling IPv4 forwarding: (%d) %s", - errsv, nm_strerror_native (errsv)); - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "cannot set ipv4/ip_forward: %s", nm_strerror_native (errsv)); - return FALSE; - } - - if (nm_platform_sysctl_get_int32 (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), -1) == 1) { - /* nothing to do. */ - } else if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv4/ip_dynaddr"), "1")) { - errsv = errno; - _LOGD (LOGD_SHARING, "share: error enabling dynamic addresses: (%d) %s", - errsv, nm_strerror_native (errsv)); - } - - for (iter = modules; *iter; iter++) - nm_utils_modprobe (NULL, FALSE, *iter, NULL); - - return TRUE; -} - -#define add_share_rule(req, table, ...) \ - G_STMT_START { \ - char *_cmd = g_strdup_printf (__VA_ARGS__); \ - nm_act_request_add_share_rule (req, table, _cmd); \ - g_free (_cmd); \ - } G_STMT_END +share_init(NMDevice *self, GError **error) +{ + char * modules[] = {"ip_tables", + "iptable_nat", + "nf_nat_ftp", + "nf_nat_irc", + "nf_nat_sip", + "nf_nat_tftp", + "nf_nat_pptp", + "nf_nat_h323", + NULL}; + char **iter; + int errsv; + + if (nm_platform_sysctl_get_int32(nm_device_get_platform(self), + NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"), + -1) + == 1) { + /* nothing to do. */ + } else if (!nm_platform_sysctl_set(nm_device_get_platform(self), + NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"), + "1")) { + errsv = errno; + _LOGD(LOGD_SHARING, + "share: error enabling IPv4 forwarding: (%d) %s", + errsv, + nm_strerror_native(errsv)); + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "cannot set ipv4/ip_forward: %s", + nm_strerror_native(errsv)); + return FALSE; + } + + if (nm_platform_sysctl_get_int32(nm_device_get_platform(self), + NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_dynaddr"), + -1) + == 1) { + /* nothing to do. */ + } else if (!nm_platform_sysctl_set(nm_device_get_platform(self), + NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_dynaddr"), + "1")) { + errsv = errno; + _LOGD(LOGD_SHARING, + "share: error enabling dynamic addresses: (%d) %s", + errsv, + nm_strerror_native(errsv)); + } + + for (iter = modules; *iter; iter++) + nm_utils_modprobe(NULL, FALSE, *iter, NULL); + + return TRUE; +} + +#define add_share_rule(req, table, ...) \ + G_STMT_START \ + { \ + char *_cmd = g_strdup_printf(__VA_ARGS__); \ + nm_act_request_add_share_rule(req, table, _cmd); \ + g_free(_cmd); \ + } \ + G_STMT_END static gboolean -start_sharing (NMDevice *self, NMIP4Config *config, GError **error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActRequest *req; - char str_addr[INET_ADDRSTRLEN]; - char str_mask[INET_ADDRSTRLEN]; - guint32 netmask, network; - const NMPlatformIP4Address *ip4_addr = NULL; - const char *ip_iface; - GError *local = NULL; - NMConnection *conn; - NMSettingConnection *s_con; - gboolean announce_android_metered; - - g_return_val_if_fail (config, FALSE); - - ip_iface = nm_device_get_ip_iface (self); - if (!ip_iface) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "device has no ip interface"); - return FALSE; - } - - ip4_addr = nm_ip4_config_get_first_address (config); - if (!ip4_addr || !ip4_addr->address) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "could not determine IPv4 address"); - return FALSE; - } - - if (!share_init (self, error)) - return FALSE; - - req = nm_device_get_act_request (self); - g_return_val_if_fail (req, FALSE); - - netmask = _nm_utils_ip4_prefix_to_netmask (ip4_addr->plen); - _nm_utils_inet4_ntop (netmask, str_mask); - - network = ip4_addr->address & netmask; - _nm_utils_inet4_ntop (network, str_addr); - - add_share_rule (req, "nat", "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE", str_addr, str_mask, str_addr, str_mask); - add_share_rule (req, "filter", "FORWARD --destination %s/%s --out-interface %s --match state --state ESTABLISHED,RELATED --jump ACCEPT", str_addr, str_mask, ip_iface); - add_share_rule (req, "filter", "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", str_addr, str_mask, ip_iface); - add_share_rule (req, "filter", "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", ip_iface, ip_iface); - add_share_rule (req, "filter", "FORWARD --out-interface %s --jump REJECT", ip_iface); - add_share_rule (req, "filter", "FORWARD --in-interface %s --jump REJECT", ip_iface); - add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT", ip_iface); - add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT", ip_iface); - add_share_rule (req, "filter", "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT", ip_iface); - add_share_rule (req, "filter", "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT", ip_iface); - - nm_act_request_set_shared (req, TRUE); - - conn = nm_act_request_get_applied_connection (req); - s_con = nm_connection_get_setting_connection (conn); - - switch (nm_setting_connection_get_metered (s_con)) { - case NM_METERED_YES: - /* honor the metered flag. Note that reapply on the device does not affect - * the metered setting. This is different from other profiles, where the - * metered flag of an activated profile can be changed (reapplied). */ - announce_android_metered = TRUE; - break; - case NM_METERED_UNKNOWN: - /* we pick up the current value and announce it. But again, we cannot update - * the announced setting without restarting dnsmasq. That means, if the default - * route changes w.r.t. being metered, then the shared connection does not get - * updated before reactivating. */ - announce_android_metered = NM_IN_SET (nm_manager_get_metered (NM_MANAGER_GET), - NM_METERED_YES, - NM_METERED_GUESS_YES); - break; - default: - announce_android_metered = FALSE; - break; - } - - - if (!nm_dnsmasq_manager_start (priv->dnsmasq_manager, - config, - announce_android_metered, - &local)) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "could not start dnsmasq due to %s", local->message); - g_error_free (local); - nm_act_request_set_shared (req, FALSE); - return FALSE; - } - - priv->dnsmasq_state_id = g_signal_connect (priv->dnsmasq_manager, NM_DNS_MASQ_MANAGER_STATE_CHANGED, - G_CALLBACK (dnsmasq_state_changed_cb), - self); - return TRUE; +start_sharing(NMDevice *self, NMIP4Config *config, GError **error) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMActRequest * req; + char str_addr[INET_ADDRSTRLEN]; + char str_mask[INET_ADDRSTRLEN]; + guint32 netmask, network; + const NMPlatformIP4Address *ip4_addr = NULL; + const char * ip_iface; + GError * local = NULL; + NMConnection * conn; + NMSettingConnection * s_con; + gboolean announce_android_metered; + + g_return_val_if_fail(config, FALSE); + + ip_iface = nm_device_get_ip_iface(self); + if (!ip_iface) { + g_set_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "device has no ip interface"); + return FALSE; + } + + ip4_addr = nm_ip4_config_get_first_address(config); + if (!ip4_addr || !ip4_addr->address) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "could not determine IPv4 address"); + return FALSE; + } + + if (!share_init(self, error)) + return FALSE; + + req = nm_device_get_act_request(self); + g_return_val_if_fail(req, FALSE); + + netmask = _nm_utils_ip4_prefix_to_netmask(ip4_addr->plen); + _nm_utils_inet4_ntop(netmask, str_mask); + + network = ip4_addr->address & netmask; + _nm_utils_inet4_ntop(network, str_addr); + + add_share_rule(req, + "nat", + "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE", + str_addr, + str_mask, + str_addr, + str_mask); + add_share_rule(req, + "filter", + "FORWARD --destination %s/%s --out-interface %s --match state --state " + "ESTABLISHED,RELATED --jump ACCEPT", + str_addr, + str_mask, + ip_iface); + add_share_rule(req, + "filter", + "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", + str_addr, + str_mask, + ip_iface); + add_share_rule(req, + "filter", + "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", + ip_iface, + ip_iface); + add_share_rule(req, "filter", "FORWARD --out-interface %s --jump REJECT", ip_iface); + add_share_rule(req, "filter", "FORWARD --in-interface %s --jump REJECT", ip_iface); + add_share_rule(req, + "filter", + "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT", + ip_iface); + add_share_rule(req, + "filter", + "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT", + ip_iface); + add_share_rule(req, + "filter", + "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT", + ip_iface); + add_share_rule(req, + "filter", + "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT", + ip_iface); + + nm_act_request_set_shared(req, TRUE); + + conn = nm_act_request_get_applied_connection(req); + s_con = nm_connection_get_setting_connection(conn); + + switch (nm_setting_connection_get_metered(s_con)) { + case NM_METERED_YES: + /* honor the metered flag. Note that reapply on the device does not affect + * the metered setting. This is different from other profiles, where the + * metered flag of an activated profile can be changed (reapplied). */ + announce_android_metered = TRUE; + break; + case NM_METERED_UNKNOWN: + /* we pick up the current value and announce it. But again, we cannot update + * the announced setting without restarting dnsmasq. That means, if the default + * route changes w.r.t. being metered, then the shared connection does not get + * updated before reactivating. */ + announce_android_metered = + NM_IN_SET(nm_manager_get_metered(NM_MANAGER_GET), NM_METERED_YES, NM_METERED_GUESS_YES); + break; + default: + announce_android_metered = FALSE; + break; + } + + if (!nm_dnsmasq_manager_start(priv->dnsmasq_manager, + config, + announce_android_metered, + &local)) { + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "could not start dnsmasq due to %s", + local->message); + g_error_free(local); + nm_act_request_set_shared(req, FALSE); + return FALSE; + } + + priv->dnsmasq_state_id = g_signal_connect(priv->dnsmasq_manager, + NM_DNS_MASQ_MANAGER_STATE_CHANGED, + G_CALLBACK(dnsmasq_state_changed_cb), + self); + return TRUE; } static void -arp_cleanup (NMDevice *self) +arp_cleanup(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_clear_pointer (&priv->acd.announcing, nm_acd_manager_free); + nm_clear_pointer(&priv->acd.announcing, nm_acd_manager_free); } void -nm_device_arp_announce (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - NMSettingIPConfig *s_ip4; - guint num, i; - const guint8 *hw_addr; - size_t hw_addr_len = 0; - - arp_cleanup (self); - - hw_addr = nm_platform_link_get_address (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self), - &hw_addr_len); - - if (!hw_addr || hw_addr_len != ETH_ALEN) - return; - - /* We only care about manually-configured addresses; DHCP- and autoip-configured - * ones should already have been seen on the network at this point. - */ - connection = nm_device_get_applied_connection (self); - if (!connection) - return; - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (!s_ip4) - return; - num = nm_setting_ip_config_get_num_addresses (s_ip4); - if (num == 0) - return; - - priv->acd.announcing = nm_acd_manager_new (nm_device_get_ip_ifindex (self), - hw_addr, - hw_addr_len, - NULL, - NULL); - - for (i = 0; i < num; i++) { - NMIPAddress *ip = nm_setting_ip_config_get_address (s_ip4, i); - in_addr_t addr; - - if (inet_pton (AF_INET, nm_ip_address_get_address (ip), &addr) == 1) - nm_acd_manager_add_address (priv->acd.announcing, addr); - else - g_warn_if_reached (); - } - - nm_acd_manager_announce_addresses (priv->acd.announcing); +nm_device_arp_announce(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + NMSettingIPConfig *s_ip4; + guint num, i; + const guint8 * hw_addr; + size_t hw_addr_len = 0; + + arp_cleanup(self); + + hw_addr = nm_platform_link_get_address(nm_device_get_platform(self), + nm_device_get_ip_ifindex(self), + &hw_addr_len); + + if (!hw_addr || hw_addr_len != ETH_ALEN) + return; + + /* We only care about manually-configured addresses; DHCP- and autoip-configured + * ones should already have been seen on the network at this point. + */ + connection = nm_device_get_applied_connection(self); + if (!connection) + return; + s_ip4 = nm_connection_get_setting_ip4_config(connection); + if (!s_ip4) + return; + num = nm_setting_ip_config_get_num_addresses(s_ip4); + if (num == 0) + return; + + priv->acd.announcing = + nm_acd_manager_new(nm_device_get_ip_ifindex(self), hw_addr, hw_addr_len, NULL, NULL); + + for (i = 0; i < num; i++) { + NMIPAddress *ip = nm_setting_ip_config_get_address(s_ip4, i); + in_addr_t addr; + + if (inet_pton(AF_INET, nm_ip_address_get_address(ip), &addr) == 1) + nm_acd_manager_add_address(priv->acd.announcing, addr); + else + g_warn_if_reached(); + } + + nm_acd_manager_announce_addresses(priv->acd.announcing); } static void -activate_stage5_ip_config_result_4 (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActRequest *req; - const char *method; - int ip_ifindex; - gboolean do_announce = FALSE; - - req = nm_device_get_act_request (self); - g_assert (req); - - /* Interface must be IFF_UP before IP config can be applied */ - ip_ifindex = nm_device_get_ip_ifindex (self); - if (!nm_platform_link_is_up (nm_device_get_platform (self), ip_ifindex) && !nm_device_sys_iface_state_is_external_or_assume (self)) { - nm_platform_link_set_up (nm_device_get_platform (self), ip_ifindex, NULL); - if (!nm_platform_link_is_up (nm_device_get_platform (self), ip_ifindex)) - _LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self)); - } - - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) { - _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed"); - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - - /* Start IPv4 sharing if we need it */ - method = nm_device_get_effective_ip_config_method (self, AF_INET); - if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - gs_free_error GError *error = NULL; - - if (!start_sharing (self, priv->ip_config_4, &error)) { - _LOGW (LOGD_SHARING, "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed: %s", error->message); - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); - return; - } - } - - if (priv->dhcp_data_4.client) { - gs_free_error GError *error = NULL; - - if (!nm_dhcp_client_accept (priv->dhcp_data_4.client, &error)) { - _LOGW (LOGD_DHCP4, - "Activation: Stage 5 of 5 (IPv4 Commit) error accepting lease: %s", - error->message); - nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_DHCP_ERROR); - return; - } - } - - /* If IPv4 wasn't the first to complete, and DHCP was used, then ensure - * dispatcher scripts get the DHCP lease information. - */ - if ( priv->dhcp_data_4.client - && nm_device_activate_ip4_state_in_conf (self) - && (nm_device_get_state (self) > NM_DEVICE_STATE_IP_CONFIG)) { - nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP4_CHANGE, - self, - NULL, - NULL, NULL, NULL); - } - - /* Send ARP announcements */ - - if (nm_device_is_master (self)) { - CList *iter; - SlaveInfo *info; - - /* Skip announcement if there are no device enslaved, for two reasons: - * 1) the master has a temporary MAC address until the first slave comes - * 2) announcements are going to be dropped anyway without slaves - */ - do_announce = FALSE; - - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry (iter, SlaveInfo, lst_slave); - if (info->slave_is_enslaved) { - do_announce = TRUE; - break; - } - } - } else - do_announce = TRUE; - - if (do_announce) - nm_device_arp_announce (self); - - /* Enter the IP_CHECK state if this is the first method to complete */ - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_DONE); - check_ip_state (self, FALSE, TRUE); +activate_stage5_ip_config_result_4(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMActRequest * req; + const char * method; + int ip_ifindex; + gboolean do_announce = FALSE; + + req = nm_device_get_act_request(self); + g_assert(req); + + /* Interface must be IFF_UP before IP config can be applied */ + ip_ifindex = nm_device_get_ip_ifindex(self); + if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex) + && !nm_device_sys_iface_state_is_external_or_assume(self)) { + nm_platform_link_set_up(nm_device_get_platform(self), ip_ifindex, NULL); + if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex)) + _LOGW(LOGD_DEVICE, + "interface %s not up for IP configuration", + nm_device_get_ip_iface(self)); + } + + if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { + _LOGD(LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed"); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return; + } + + /* Start IPv4 sharing if we need it */ + method = nm_device_get_effective_ip_config_method(self, AF_INET); + if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { + gs_free_error GError *error = NULL; + + if (!start_sharing(self, priv->ip_config_4, &error)) { + _LOGW(LOGD_SHARING, + "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed: %s", + error->message); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); + return; + } + } + + if (priv->dhcp_data_4.client) { + gs_free_error GError *error = NULL; + + if (!nm_dhcp_client_accept(priv->dhcp_data_4.client, &error)) { + _LOGW(LOGD_DHCP4, + "Activation: Stage 5 of 5 (IPv4 Commit) error accepting lease: %s", + error->message); + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_DHCP_ERROR); + return; + } + } + + /* If IPv4 wasn't the first to complete, and DHCP was used, then ensure + * dispatcher scripts get the DHCP lease information. + */ + if (priv->dhcp_data_4.client && nm_device_activate_ip4_state_in_conf(self) + && (nm_device_get_state(self) > NM_DEVICE_STATE_IP_CONFIG)) { + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP4_CHANGE, self, NULL, NULL, NULL, NULL); + } + + /* Send ARP announcements */ + + if (nm_device_is_master(self)) { + CList * iter; + SlaveInfo *info; + + /* Skip announcement if there are no device enslaved, for two reasons: + * 1) the master has a temporary MAC address until the first slave comes + * 2) announcements are going to be dropped anyway without slaves + */ + do_announce = FALSE; + + c_list_for_each (iter, &priv->slaves) { + info = c_list_entry(iter, SlaveInfo, lst_slave); + if (info->slave_is_enslaved) { + do_announce = TRUE; + break; + } + } + } else + do_announce = TRUE; + + if (do_announce) + nm_device_arp_announce(self); + + /* Enter the IP_CHECK state if this is the first method to complete */ + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); + check_ip_state(self, FALSE, TRUE); } void -nm_device_activate_schedule_ip_config_result (NMDevice *self, - int addr_family, - NMIPConfig *config) +nm_device_activate_schedule_ip_config_result(NMDevice *self, int addr_family, NMIPConfig *config) { - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - g_return_if_fail ( !config - || ( addr_family == AF_INET - && nm_ip_config_get_addr_family (config) == AF_INET)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); + g_return_if_fail( + !config || (addr_family == AF_INET && nm_ip_config_get_addr_family(config) == AF_INET)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if (IS_IPv4) { - applied_config_init (&priv->dev_ip_config_4, config); - } else { - /* If IP had previously failed, move it back to NM_DEVICE_IP_STATE_CONF since we - * clearly now have configuration. - */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_CONF); - } + if (IS_IPv4) { + applied_config_init(&priv->dev_ip_config_4, config); + } else { + /* If IP had previously failed, move it back to NM_DEVICE_IP_STATE_CONF since we + * clearly now have configuration. + */ + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_CONF); + } - activation_source_schedule (self, activate_stage5_ip_config_result_x[IS_IPv4], addr_family); + activation_source_schedule(self, activate_stage5_ip_config_result_x[IS_IPv4], addr_family); } NMDeviceIPState -nm_device_activate_get_ip_state (NMDevice *self, - int addr_family) +nm_device_activate_get_ip_state(NMDevice *self, int addr_family) { - const gboolean IS_IPv4 = (addr_family == AF_INET); + const gboolean IS_IPv4 = (addr_family == AF_INET); - g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_IP_STATE_NONE); - g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), NM_DEVICE_IP_STATE_NONE); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_IP_STATE_NONE); + g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), NM_DEVICE_IP_STATE_NONE); - return NM_DEVICE_GET_PRIVATE (self)->ip_state_x[IS_IPv4]; + return NM_DEVICE_GET_PRIVATE(self)->ip_state_x[IS_IPv4]; } static void -dad6_add_pending_address (NMDevice *self, - NMPlatform *platform, - int ifindex, - const struct in6_addr *address, - NMIP6Config **dad6_config) +dad6_add_pending_address(NMDevice * self, + NMPlatform * platform, + int ifindex, + const struct in6_addr *address, + NMIP6Config ** dad6_config) { - const NMPlatformIP6Address *pl_addr; + const NMPlatformIP6Address *pl_addr; - pl_addr = nm_platform_ip6_address_get (platform, - ifindex, - *address); - if ( pl_addr - && NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_DADFAILED) - && !NM_FLAGS_HAS (pl_addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - _LOGt (LOGD_DEVICE, "IPv6 DAD: pending address %s", - nm_platform_ip6_address_to_string (pl_addr, NULL, 0)); + pl_addr = nm_platform_ip6_address_get(platform, ifindex, address); + if (pl_addr && NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_TENTATIVE) + && !NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_DADFAILED) + && !NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { + _LOGt(LOGD_DEVICE, + "IPv6 DAD: pending address %s", + nm_platform_ip6_address_to_string(pl_addr, NULL, 0)); - if (!*dad6_config) - *dad6_config = nm_device_ip6_config_new (self); + if (!*dad6_config) + *dad6_config = nm_device_ip6_config_new(self); - nm_ip6_config_add_address (*dad6_config, pl_addr); - } + nm_ip6_config_add_address(*dad6_config, pl_addr); + } } /* @@ -11715,199 +11942,184 @@ dad6_add_pending_address (NMDevice *self, * have the tentative flag, or NULL if none is present. */ static NMIP6Config * -dad6_get_pending_addresses (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMIP6Config *confs[] = { (NMIP6Config *) applied_config_get_current (&priv->ac_ip6_config), - (NMIP6Config *) applied_config_get_current (&priv->dhcp6.ip6_config), - priv->con_ip_config_6, - (NMIP6Config *) applied_config_get_current (&priv->dev2_ip_config_6) }; - const NMPlatformIP6Address *addr; - NMIP6Config *dad6_config = NULL; - NMDedupMultiIter ipconf_iter; - guint i; - int ifindex; - NMPlatform *platform; - - ifindex = nm_device_get_ip_ifindex (self); - g_return_val_if_fail (ifindex > 0, NULL); - - platform = nm_device_get_platform (self); - - if (priv->ipv6ll_has) { - dad6_add_pending_address (self, - platform, - ifindex, - &priv->ipv6ll_addr, - &dad6_config); - } - - /* We are interested only in addresses that we have explicitly configured, - * not in externally added ones. - */ - for (i = 0; i < G_N_ELEMENTS (confs); i++) { - if (!confs[i]) - continue; - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, confs[i], &addr) { - dad6_add_pending_address (self, - platform, - ifindex, - &addr->address, - &dad6_config); - } - } - - return dad6_config; +dad6_get_pending_addresses(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMIP6Config * confs[] = {(NMIP6Config *) applied_config_get_current(&priv->ac_ip6_config), + (NMIP6Config *) applied_config_get_current(&priv->dhcp6.ip6_config), + priv->con_ip_config_6, + (NMIP6Config *) applied_config_get_current(&priv->dev2_ip_config_6)}; + const NMPlatformIP6Address *addr; + NMIP6Config * dad6_config = NULL; + NMDedupMultiIter ipconf_iter; + guint i; + int ifindex; + NMPlatform * platform; + + ifindex = nm_device_get_ip_ifindex(self); + g_return_val_if_fail(ifindex > 0, NULL); + + platform = nm_device_get_platform(self); + + if (priv->ipv6ll_has) { + dad6_add_pending_address(self, platform, ifindex, &priv->ipv6ll_addr, &dad6_config); + } + + /* We are interested only in addresses that we have explicitly configured, + * not in externally added ones. + */ + for (i = 0; i < G_N_ELEMENTS(confs); i++) { + if (!confs[i]) + continue; + + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, confs[i], &addr) { + dad6_add_pending_address(self, platform, ifindex, &addr->address, &dad6_config); + } + } + + return dad6_config; } static void -activate_stage5_ip_config_result_6 (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActRequest *req; - const char *method; - int ip_ifindex; - int errsv; - - req = nm_device_get_act_request (self); - g_assert (req); - - /* Interface must be IFF_UP before IP config can be applied */ - ip_ifindex = nm_device_get_ip_ifindex (self); - g_return_if_fail (ip_ifindex); - - if (!nm_platform_link_is_up (nm_device_get_platform (self), ip_ifindex) && !nm_device_sys_iface_state_is_external_or_assume (self)) { - nm_platform_link_set_up (nm_device_get_platform (self), ip_ifindex, NULL); - if (!nm_platform_link_is_up (nm_device_get_platform (self), ip_ifindex)) - _LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self)); - } - - if (ip_config_merge_and_apply (self, AF_INET6, TRUE)) { - if ( priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE - && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { - if (applied_config_get_current (&priv->dhcp6.ip6_config)) { - /* If IPv6 wasn't the first IP to complete, and DHCP was used, - * then ensure dispatcher scripts get the DHCP lease information. - */ - nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DHCP6_CHANGE, - self, - NULL, - NULL, NULL, NULL); - } else { - /* still waiting for first dhcp6 lease. */ - return; - } - } - - /* Start IPv6 forwarding if we need it */ - method = nm_device_get_effective_ip_config_method (self, AF_INET6); - if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - if (!nm_platform_sysctl_set (nm_device_get_platform (self), NMP_SYSCTL_PATHID_ABSOLUTE ("/proc/sys/net/ipv6/conf/all/forwarding"), "1")) { - errsv = errno; - _LOGE (LOGD_SHARING, "share: error enabling IPv6 forwarding: (%d) %s", errsv, nm_strerror_native (errsv)); - nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); - } - } - - /* Check if we have to wait for DAD */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF && !priv->dad6_ip6_config) { - if (!priv->carrier && priv->ignore_carrier && get_ip_config_may_fail (self, AF_INET6)) - _LOGI (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: carrier missing and ignored, not delaying activation"); - else - priv->dad6_ip6_config = dad6_get_pending_addresses (self); - - if (priv->dad6_ip6_config) { - _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: awaiting termination"); - } else { - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_DONE); - check_ip_state (self, FALSE, TRUE); - } - } - } else { - _LOGW (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) failed"); - nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - } +activate_stage5_ip_config_result_6(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMActRequest * req; + const char * method; + int ip_ifindex; + int errsv; + + req = nm_device_get_act_request(self); + g_assert(req); + + /* Interface must be IFF_UP before IP config can be applied */ + ip_ifindex = nm_device_get_ip_ifindex(self); + g_return_if_fail(ip_ifindex); + + if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex) + && !nm_device_sys_iface_state_is_external_or_assume(self)) { + nm_platform_link_set_up(nm_device_get_platform(self), ip_ifindex, NULL); + if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex)) + _LOGW(LOGD_DEVICE, + "interface %s not up for IP configuration", + nm_device_get_ip_iface(self)); + } + + if (ip_config_merge_and_apply(self, AF_INET6, TRUE)) { + if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE + && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { + if (applied_config_get_current(&priv->dhcp6.ip6_config)) { + /* If IPv6 wasn't the first IP to complete, and DHCP was used, + * then ensure dispatcher scripts get the DHCP lease information. + */ + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP6_CHANGE, + self, + NULL, + NULL, + NULL, + NULL); + } else { + /* still waiting for first dhcp6 lease. */ + return; + } + } + + /* Start IPv6 forwarding if we need it */ + method = nm_device_get_effective_ip_config_method(self, AF_INET6); + if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { + if (!nm_platform_sysctl_set( + nm_device_get_platform(self), + NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv6/conf/all/forwarding"), + "1")) { + errsv = errno; + _LOGE(LOGD_SHARING, + "share: error enabling IPv6 forwarding: (%d) %s", + errsv, + nm_strerror_native(errsv)); + nm_device_ip_method_failed(self, + AF_INET6, + NM_DEVICE_STATE_REASON_SHARED_START_FAILED); + } + } + + /* Check if we have to wait for DAD */ + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF && !priv->dad6_ip6_config) { + if (!priv->carrier && priv->ignore_carrier && get_ip_config_may_fail(self, AF_INET6)) + _LOGI(LOGD_DEVICE | LOGD_IP6, + "IPv6 DAD: carrier missing and ignored, not delaying activation"); + else + priv->dad6_ip6_config = dad6_get_pending_addresses(self); + + if (priv->dad6_ip6_config) { + _LOGD(LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: awaiting termination"); + } else { + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_DONE); + check_ip_state(self, FALSE, TRUE); + } + } + } else { + _LOGW(LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) failed"); + nm_device_ip_method_failed(self, AF_INET6, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } } /*****************************************************************************/ static void -act_request_set (NMDevice *self, NMActRequest *act_request) -{ - NMDevicePrivate *priv; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert (!act_request || NM_IS_ACT_REQUEST (act_request)); - - priv = NM_DEVICE_GET_PRIVATE (self); - - if ( !priv->act_request.visible - && priv->act_request.obj == act_request) - return; - - /* always clear the public flag. The few callers that set a new @act_request - * don't want that the property is public yet. */ - nm_dbus_track_obj_path_set (&priv->act_request, - act_request, - FALSE); - - if (act_request) { - switch (nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (act_request))) { - case NM_ACTIVATION_TYPE_EXTERNAL: - break; - case NM_ACTIVATION_TYPE_ASSUME: - if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_EXTERNAL) - nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_ASSUME); - break; - case NM_ACTIVATION_TYPE_MANAGED: - if (NM_IN_SET_TYPED (NMDeviceSysIfaceState, - priv->sys_iface_state, - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME)) - nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); - break; - } - } -} - -static void -dnsmasq_cleanup (NMDevice *self) +act_request_set(NMDevice *self, NMActRequest *act_request) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv; - if (!priv->dnsmasq_manager) - return; + nm_assert(NM_IS_DEVICE(self)); + nm_assert(!act_request || NM_IS_ACT_REQUEST(act_request)); - nm_clear_g_signal_handler (priv->dnsmasq_manager, &priv->dnsmasq_state_id); + priv = NM_DEVICE_GET_PRIVATE(self); - nm_dnsmasq_manager_stop (priv->dnsmasq_manager); - g_object_unref (priv->dnsmasq_manager); - priv->dnsmasq_manager = NULL; + if (!priv->act_request.visible && priv->act_request.obj == act_request) + return; + + /* always clear the public flag. The few callers that set a new @act_request + * don't want that the property is public yet. */ + nm_dbus_track_obj_path_set(&priv->act_request, act_request, FALSE); + + if (act_request) { + switch (nm_active_connection_get_activation_type(NM_ACTIVE_CONNECTION(act_request))) { + case NM_ACTIVATION_TYPE_EXTERNAL: + break; + case NM_ACTIVATION_TYPE_ASSUME: + if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_EXTERNAL) + nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_ASSUME); + break; + case NM_ACTIVATION_TYPE_MANAGED: + if (NM_IN_SET_TYPED(NMDeviceSysIfaceState, + priv->sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME)) + nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); + break; + } + } } static void -_update_ip4_address (NMDevice *self) +dnsmasq_cleanup(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const NMPlatformIP4Address *address; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - g_return_if_fail (NM_IS_DEVICE (self)); + if (!priv->dnsmasq_manager) + return; - if ( priv->ip_config_4 - && ip_config_valid (priv->state) - && (address = nm_ip4_config_get_first_address (priv->ip_config_4))) { - if (address->address != priv->ip4_address) { - priv->ip4_address = address->address; - _notify (self, PROP_IP4_ADDRESS); - } - } + nm_clear_g_signal_handler(priv->dnsmasq_manager, &priv->dnsmasq_state_id); + + nm_dnsmasq_manager_stop(priv->dnsmasq_manager); + g_object_unref(priv->dnsmasq_manager); + priv->dnsmasq_manager = NULL; } gboolean -nm_device_is_nm_owned (NMDevice *self) +nm_device_is_nm_owned(NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->nm_owned; + return NM_DEVICE_GET_PRIVATE(self)->nm_owned; } /* @@ -11918,402 +12130,407 @@ nm_device_is_nm_owned (NMDevice *self) * of the device. */ static gboolean -delete_on_deactivate_link_delete (gpointer user_data) +delete_on_deactivate_link_delete(gpointer user_data) { - DeleteOnDeactivateData *data = user_data; - NMDevice *self = data->device; + DeleteOnDeactivateData *data = user_data; + NMDevice * self = data->device; + + _LOGD(LOGD_DEVICE, + "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)", + data->ifindex, + data->idle_add_id); - _LOGD (LOGD_DEVICE, "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)", - data->ifindex, data->idle_add_id); + if (data->device) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(data->device); + gs_free_error GError *error = NULL; - if (data->device) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (data->device); - gs_free_error GError *error = NULL; + g_object_remove_weak_pointer(G_OBJECT(data->device), (void **) &data->device); + priv->delete_on_deactivate_data = NULL; - g_object_remove_weak_pointer (G_OBJECT (data->device), (void **) &data->device); - priv->delete_on_deactivate_data = NULL; + if (!nm_device_unrealize(data->device, TRUE, &error)) + _LOGD(LOGD_DEVICE, + "delete_on_deactivate: unrealizing %d failed (%s)", + data->ifindex, + error->message); + } else if (data->ifindex > 0) + nm_platform_link_delete(nm_device_get_platform(self), data->ifindex); - if (!nm_device_unrealize (data->device, TRUE, &error)) - _LOGD (LOGD_DEVICE, "delete_on_deactivate: unrealizing %d failed (%s)", data->ifindex, error->message); - } else if (data->ifindex > 0) - nm_platform_link_delete (nm_device_get_platform (self), data->ifindex); + nm_device_emit_recheck_auto_activate(self); - g_free (data); - return FALSE; + g_free(data); + return FALSE; } static void -delete_on_deactivate_unschedule (NMDevice *self) +delete_on_deactivate_unschedule(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->delete_on_deactivate_data) { - DeleteOnDeactivateData *data = priv->delete_on_deactivate_data; + if (priv->delete_on_deactivate_data) { + DeleteOnDeactivateData *data = priv->delete_on_deactivate_data; - priv->delete_on_deactivate_data = NULL; + priv->delete_on_deactivate_data = NULL; - g_source_remove (data->idle_add_id); - g_object_remove_weak_pointer (G_OBJECT (self), (void **) &data->device); - _LOGD (LOGD_DEVICE, "delete_on_deactivate: cancel cleanup and delete virtual link #%d (id=%u)", - data->ifindex, data->idle_add_id); - g_free (data); - } + g_source_remove(data->idle_add_id); + g_object_remove_weak_pointer(G_OBJECT(self), (void **) &data->device); + _LOGD(LOGD_DEVICE, + "delete_on_deactivate: cancel cleanup and delete virtual link #%d (id=%u)", + data->ifindex, + data->idle_add_id); + g_free(data); + } } static void -delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - DeleteOnDeactivateData *data; - - if (!priv->nm_owned) - return; - if (priv->queued_act_request) - return; - if (!nm_device_is_software (self) || !nm_device_is_real (self)) - return; - if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED) - return; - if (nm_device_get_state (self) == NM_DEVICE_STATE_UNAVAILABLE) - return; - delete_on_deactivate_unschedule (self); /* always cancel and reschedule */ - - data = g_new (DeleteOnDeactivateData, 1); - g_object_add_weak_pointer (G_OBJECT (self), (void **) &data->device); - data->device = self; - data->ifindex = ifindex; - data->idle_add_id = g_idle_add (delete_on_deactivate_link_delete, data); - priv->delete_on_deactivate_data = data; - - _LOGD (LOGD_DEVICE, "delete_on_deactivate: schedule cleanup and delete virtual link #%d (id=%u)", - ifindex, data->idle_add_id); +delete_on_deactivate_check_and_schedule(NMDevice *self, int ifindex) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + DeleteOnDeactivateData *data; + + if (!priv->nm_owned) + return; + if (priv->queued_act_request) + return; + if (!nm_device_is_software(self) || !nm_device_is_real(self)) + return; + if (nm_device_get_state(self) == NM_DEVICE_STATE_UNMANAGED) + return; + if (nm_device_get_state(self) == NM_DEVICE_STATE_UNAVAILABLE) + return; + delete_on_deactivate_unschedule(self); /* always cancel and reschedule */ + + data = g_new(DeleteOnDeactivateData, 1); + g_object_add_weak_pointer(G_OBJECT(self), (void **) &data->device); + data->device = self; + data->ifindex = ifindex; + data->idle_add_id = g_idle_add(delete_on_deactivate_link_delete, data); + priv->delete_on_deactivate_data = data; + + _LOGD(LOGD_DEVICE, + "delete_on_deactivate: schedule cleanup and delete virtual link #%d (id=%u)", + ifindex, + data->idle_add_id); } static void -_cleanup_ip_pre (NMDevice *self, int addr_family, CleanupType cleanup_type) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - _set_ip_state (self, addr_family, NM_DEVICE_IP_STATE_NONE); - - if (nm_clear_g_source (&priv->queued_ip_config_id_x[IS_IPv4])) { - _LOGD (LOGD_DEVICE, "clearing queued IP%c config change", - nm_utils_addr_family_to_char (addr_family)); - } - - if (IS_IPv4) { - dhcp4_cleanup (self, cleanup_type, FALSE); - arp_cleanup (self); - dnsmasq_cleanup (self); - ipv4ll_cleanup (self); - g_slist_free_full (priv->acd.dad_list, (GDestroyNotify) nm_acd_manager_free); - priv->acd.dad_list = NULL; - } else { - g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - priv->dad6_failed_addrs = NULL; - g_clear_object (&priv->dad6_ip6_config); - dhcp6_cleanup (self, cleanup_type, FALSE); - nm_clear_g_source (&priv->linklocal6_timeout_id); - addrconf6_cleanup (self); - } +_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); + + _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_NONE); + + if (nm_clear_g_source(&priv->queued_ip_config_id_x[IS_IPv4])) { + _LOGD(LOGD_DEVICE, + "clearing queued IP%c config change", + nm_utils_addr_family_to_char(addr_family)); + } + + if (IS_IPv4) { + dhcp4_cleanup(self, cleanup_type, FALSE); + arp_cleanup(self); + dnsmasq_cleanup(self); + ipv4ll_cleanup(self); + g_slist_free_full(priv->acd.dad_list, (GDestroyNotify) nm_acd_manager_free); + priv->acd.dad_list = NULL; + } else { + g_slist_free_full(priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); + priv->dad6_failed_addrs = NULL; + g_clear_object(&priv->dad6_ip6_config); + dhcp6_cleanup(self, cleanup_type, FALSE); + nm_clear_g_source(&priv->linklocal6_timeout_id); + addrconf6_cleanup(self); + } } gboolean -_nm_device_hash_check_invalid_keys (GHashTable *hash, - const char *setting_name, - GError **error, - const char *const*whitelist) +_nm_device_hash_check_invalid_keys(GHashTable * hash, + const char * setting_name, + GError ** error, + const char *const *whitelist) { - guint found_whitelisted_keys = 0; - guint i; + guint found_whitelisted_keys = 0; + guint i; - nm_assert (hash && g_hash_table_size (hash) > 0); - nm_assert (whitelist && whitelist[0]); + nm_assert(hash && g_hash_table_size(hash) > 0); + nm_assert(whitelist && whitelist[0]); #if NM_MORE_ASSERTS > 10 - /* Require whitelist to only contain unique keys. */ - { - gs_unref_hashtable GHashTable *check_dups = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, NULL); - - for (i = 0; whitelist[i]; i++) { - if (!g_hash_table_add (check_dups, (char *) whitelist[i])) - nm_assert (FALSE); - } - nm_assert (g_hash_table_size (check_dups) > 0); - } + /* Require whitelist to only contain unique keys. */ + { + gs_unref_hashtable GHashTable *check_dups = + g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, NULL); + + for (i = 0; whitelist[i]; i++) { + if (!g_hash_table_add(check_dups, (char *) whitelist[i])) + nm_assert(FALSE); + } + nm_assert(g_hash_table_size(check_dups) > 0); + } #endif - for (i = 0; whitelist[i]; i++) { - if (g_hash_table_contains (hash, whitelist[i])) - found_whitelisted_keys++; - } - - if (found_whitelisted_keys == g_hash_table_size (hash)) { - /* Good, there are only whitelisted keys in the hash. */ - return TRUE; - } - - if (error) { - GHashTableIter iter; - const char *k = NULL; - const char *first_invalid_key = NULL; - - g_hash_table_iter_init (&iter, hash); - while (g_hash_table_iter_next (&iter, (gpointer *) &k, NULL)) { - if (nm_utils_strv_find_first ((char **) whitelist, -1, k) < 0) { - first_invalid_key = k; - break; - } - } - if (setting_name) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply changes to '%s.%s' setting", - setting_name, - first_invalid_key); - } else { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply any changes to '%s' setting", - first_invalid_key); - } - g_return_val_if_fail (first_invalid_key, FALSE); - } - - return FALSE; + for (i = 0; whitelist[i]; i++) { + if (g_hash_table_contains(hash, whitelist[i])) + found_whitelisted_keys++; + } + + if (found_whitelisted_keys == g_hash_table_size(hash)) { + /* Good, there are only whitelisted keys in the hash. */ + return TRUE; + } + + if (error) { + GHashTableIter iter; + const char * k = NULL; + const char * first_invalid_key = NULL; + + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &k, NULL)) { + if (nm_utils_strv_find_first((char **) whitelist, -1, k) < 0) { + first_invalid_key = k; + break; + } + } + if (setting_name) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Can't reapply changes to '%s.%s' setting", + setting_name, + first_invalid_key); + } else { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Can't reapply any changes to '%s' setting", + first_invalid_key); + } + g_return_val_if_fail(first_invalid_key, FALSE); + } + + return FALSE; } void -nm_device_reactivate_ip4_config (NMDevice *self, - NMSettingIPConfig *s_ip4_old, - NMSettingIPConfig *s_ip4_new) -{ - NMDevicePrivate *priv; - const char *method_old, *method_new; - - g_return_if_fail (NM_IS_DEVICE (self)); - priv = NM_DEVICE_GET_PRIVATE (self); - - if (priv->ip_state_4 != NM_DEVICE_IP_STATE_NONE) { - g_clear_object (&priv->con_ip_config_4); - g_clear_object (&priv->ext_ip_config_4); - g_clear_object (&priv->dev_ip_config_4.current); - g_clear_object (&priv->dev2_ip_config_4.current); - priv->con_ip_config_4 = nm_device_ip4_config_new (self); - nm_ip4_config_merge_setting (priv->con_ip_config_4, - s_ip4_new, - _get_mdns (self), - _get_llmnr (self), - nm_device_get_route_table (self, AF_INET), - nm_device_get_route_metric (self, AF_INET)); - - method_old = s_ip4_old - ? nm_setting_ip_config_get_method (s_ip4_old) - : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - method_new = s_ip4_new - ? nm_setting_ip_config_get_method (s_ip4_new) - : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - - if (!nm_streq0 (method_old, method_new)) { - _cleanup_ip_pre (self, AF_INET, CLEANUP_TYPE_DECONFIGURE); - _set_ip_state (self, AF_INET, NM_DEVICE_IP_STATE_WAIT); - if (!nm_device_activate_stage3_ip4_start (self)) - _LOGW (LOGD_IP4, "Failed to apply IPv4 configuration"); - return; - } - - if (s_ip4_old && s_ip4_new) { - gint64 metric_old, metric_new; - - /* For dynamic IP methods (DHCP, IPv4LL, WWAN) the route metric is - * set at activation/renewal time using the value from static - * configuration. To support runtime change we need to update the - * dynamic configuration in place and tell the DHCP client the new - * value to use for future renewals. - */ - metric_old = nm_setting_ip_config_get_route_metric (s_ip4_old); - metric_new = nm_setting_ip_config_get_route_metric (s_ip4_new); - - if (metric_old != metric_new) { - if (priv->dev_ip_config_4.orig) { - nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->dev_ip_config_4.orig, - nm_device_get_route_metric (self, AF_INET)); - } - if (priv->dev2_ip_config_4.orig) { - nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->dev2_ip_config_4.orig, - nm_device_get_route_metric (self, AF_INET)); - } - if (priv->dhcp_data_4.client) { - nm_dhcp_client_set_route_metric (priv->dhcp_data_4.client, - nm_device_get_route_metric (self, AF_INET)); - } - } - } - - if ( nm_device_get_ip_ifindex (self) > 0 - && !ip_config_merge_and_apply (self, AF_INET, TRUE)) - _LOGW (LOGD_IP4, "Failed to reapply IPv4 configuration"); - } +nm_device_reactivate_ip4_config(NMDevice * self, + NMSettingIPConfig *s_ip4_old, + NMSettingIPConfig *s_ip4_new) +{ + NMDevicePrivate *priv; + const char * method_old, *method_new; + + g_return_if_fail(NM_IS_DEVICE(self)); + priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->ip_state_4 != NM_DEVICE_IP_STATE_NONE) { + g_clear_object(&priv->con_ip_config_4); + g_clear_object(&priv->ext_ip_config_4); + g_clear_object(&priv->dev_ip_config_4.current); + g_clear_object(&priv->dev2_ip_config_4.current); + priv->con_ip_config_4 = nm_device_ip4_config_new(self); + nm_ip4_config_merge_setting(priv->con_ip_config_4, + s_ip4_new, + _prop_get_connection_mdns(self), + _prop_get_connection_llmnr(self), + nm_device_get_route_table(self, AF_INET), + nm_device_get_route_metric(self, AF_INET)); + + method_old = s_ip4_old ? nm_setting_ip_config_get_method(s_ip4_old) + : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + method_new = s_ip4_new ? nm_setting_ip_config_get_method(s_ip4_new) + : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; + + if (!nm_streq0(method_old, method_new)) { + _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_DECONFIGURE); + _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_WAIT); + if (!nm_device_activate_stage3_ip4_start(self)) + _LOGW(LOGD_IP4, "Failed to apply IPv4 configuration"); + return; + } + + if (s_ip4_old && s_ip4_new) { + gint64 metric_old, metric_new; + + /* For dynamic IP methods (DHCP, IPv4LL, WWAN) the route metric is + * set at activation/renewal time using the value from static + * configuration. To support runtime change we need to update the + * dynamic configuration in place and tell the DHCP client the new + * value to use for future renewals. + */ + metric_old = nm_setting_ip_config_get_route_metric(s_ip4_old); + metric_new = nm_setting_ip_config_get_route_metric(s_ip4_new); + + if (metric_old != metric_new) { + if (priv->dev_ip_config_4.orig) { + nm_ip4_config_update_routes_metric((NMIP4Config *) priv->dev_ip_config_4.orig, + nm_device_get_route_metric(self, AF_INET)); + } + if (priv->dev2_ip_config_4.orig) { + nm_ip4_config_update_routes_metric((NMIP4Config *) priv->dev2_ip_config_4.orig, + nm_device_get_route_metric(self, AF_INET)); + } + if (priv->dhcp_data_4.client) { + nm_dhcp_client_set_route_metric(priv->dhcp_data_4.client, + nm_device_get_route_metric(self, AF_INET)); + } + } + } + + if (nm_device_get_ip_ifindex(self) > 0 && !ip_config_merge_and_apply(self, AF_INET, TRUE)) + _LOGW(LOGD_IP4, "Failed to reapply IPv4 configuration"); + } } void -nm_device_reactivate_ip6_config (NMDevice *self, - NMSettingIPConfig *s_ip6_old, - NMSettingIPConfig *s_ip6_new) -{ - NMDevicePrivate *priv; - const char *method_old, *method_new; - - g_return_if_fail (NM_IS_DEVICE (self)); - priv = NM_DEVICE_GET_PRIVATE (self); - - if (priv->ip_state_6 != NM_DEVICE_IP_STATE_NONE) { - g_clear_object (&priv->con_ip_config_6); - g_clear_object (&priv->ext_ip_config_6); - g_clear_object (&priv->ac_ip6_config.current); - g_clear_object (&priv->dhcp6.ip6_config.current); - g_clear_object (&priv->dev2_ip_config_6.current); - if ( priv->ipv6ll_handle - && !IN6_IS_ADDR_UNSPECIFIED (&priv->ipv6ll_addr)) - priv->ipv6ll_has = TRUE; - priv->con_ip_config_6 = nm_device_ip6_config_new (self); - nm_ip6_config_merge_setting (priv->con_ip_config_6, - s_ip6_new, - nm_device_get_route_table (self, AF_INET6), - nm_device_get_route_metric (self, AF_INET6)); - - method_old = s_ip6_old - ? nm_setting_ip_config_get_method (s_ip6_old) - : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - method_new = s_ip6_new - ? nm_setting_ip_config_get_method (s_ip6_new) - : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - - if (!nm_streq0 (method_old, method_new)) { - _cleanup_ip_pre (self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); - _set_ip_state (self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); - if (!nm_device_activate_stage3_ip6_start (self)) - _LOGW (LOGD_IP6, "Failed to apply IPv6 configuration"); - return; - } - - if (s_ip6_old && s_ip6_new) { - gint64 metric_old, metric_new; - - /* See comment in nm_device_reactivate_ip4_config() */ - metric_old = nm_setting_ip_config_get_route_metric (s_ip6_old); - metric_new = nm_setting_ip_config_get_route_metric (s_ip6_new); - - if (metric_old != metric_new) { - if (priv->ac_ip6_config.orig) { - nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->ac_ip6_config.orig, - nm_device_get_route_metric (self, AF_INET6)); - } - if (priv->dhcp6.ip6_config.orig) { - nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->dhcp6.ip6_config.orig, - nm_device_get_route_metric (self, AF_INET6)); - } - if (priv->dev2_ip_config_6.orig) { - nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->dev2_ip_config_6.orig, - nm_device_get_route_metric (self, AF_INET6)); - } - if (priv->dhcp_data_6.client) { - nm_dhcp_client_set_route_metric (priv->dhcp_data_6.client, - nm_device_get_route_metric (self, AF_INET6)); - } - } - } - - if ( nm_device_get_ip_ifindex (self) > 0 - && !ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP4, "Failed to reapply IPv6 configuration"); - } +nm_device_reactivate_ip6_config(NMDevice * self, + NMSettingIPConfig *s_ip6_old, + NMSettingIPConfig *s_ip6_new) +{ + NMDevicePrivate *priv; + const char * method_old, *method_new; + + g_return_if_fail(NM_IS_DEVICE(self)); + priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->ip_state_6 != NM_DEVICE_IP_STATE_NONE) { + g_clear_object(&priv->con_ip_config_6); + g_clear_object(&priv->ext_ip_config_6); + g_clear_object(&priv->ac_ip6_config.current); + g_clear_object(&priv->dhcp6.ip6_config.current); + g_clear_object(&priv->dev2_ip_config_6.current); + if (priv->ipv6ll_handle && !IN6_IS_ADDR_UNSPECIFIED(&priv->ipv6ll_addr)) + priv->ipv6ll_has = TRUE; + priv->con_ip_config_6 = nm_device_ip6_config_new(self); + nm_ip6_config_merge_setting(priv->con_ip_config_6, + s_ip6_new, + nm_device_get_route_table(self, AF_INET6), + nm_device_get_route_metric(self, AF_INET6)); + + method_old = s_ip6_old ? nm_setting_ip_config_get_method(s_ip6_old) + : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + method_new = s_ip6_new ? nm_setting_ip_config_get_method(s_ip6_new) + : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; + + if (!nm_streq0(method_old, method_new)) { + _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); + _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); + if (!nm_device_activate_stage3_ip6_start(self)) + _LOGW(LOGD_IP6, "Failed to apply IPv6 configuration"); + return; + } + + if (s_ip6_old && s_ip6_new) { + gint64 metric_old, metric_new; + + /* See comment in nm_device_reactivate_ip4_config() */ + metric_old = nm_setting_ip_config_get_route_metric(s_ip6_old); + metric_new = nm_setting_ip_config_get_route_metric(s_ip6_new); + + if (metric_old != metric_new) { + if (priv->ac_ip6_config.orig) { + nm_ip6_config_update_routes_metric((NMIP6Config *) priv->ac_ip6_config.orig, + nm_device_get_route_metric(self, AF_INET6)); + } + if (priv->dhcp6.ip6_config.orig) { + nm_ip6_config_update_routes_metric((NMIP6Config *) priv->dhcp6.ip6_config.orig, + nm_device_get_route_metric(self, AF_INET6)); + } + if (priv->dev2_ip_config_6.orig) { + nm_ip6_config_update_routes_metric((NMIP6Config *) priv->dev2_ip_config_6.orig, + nm_device_get_route_metric(self, AF_INET6)); + } + if (priv->dhcp_data_6.client) { + nm_dhcp_client_set_route_metric(priv->dhcp_data_6.client, + nm_device_get_route_metric(self, AF_INET6)); + } + } + } + + if (nm_device_get_ip_ifindex(self) > 0 && !ip_config_merge_and_apply(self, AF_INET6, TRUE)) + _LOGW(LOGD_IP4, "Failed to reapply IPv6 configuration"); + } } static void -_pacrunner_manager_add (NMDevice *self) +_pacrunner_manager_add(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); + nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); - priv->pacrunner_conf_id = nm_pacrunner_manager_add (nm_pacrunner_manager_get (), - priv->proxy_config, - nm_device_get_ip_iface (self), - NULL, - NULL); + priv->pacrunner_conf_id = nm_pacrunner_manager_add(nm_pacrunner_manager_get(), + priv->proxy_config, + nm_device_get_ip_iface(self), + NULL, + NULL); } static void -reactivate_proxy_config (NMDevice *self) +reactivate_proxy_config(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!priv->pacrunner_conf_id) - return; - nm_device_set_proxy_config (self, priv->dhcp4.pac_url); - _pacrunner_manager_add (self); + if (!priv->pacrunner_conf_id) + return; + nm_device_set_proxy_config(self, priv->dhcp4.pac_url); + _pacrunner_manager_add(self); } static gboolean -can_reapply_change (NMDevice *self, - const char *setting_name, - NMSetting *s_old, - NMSetting *s_new, - GHashTable *diffs, - GError **error) -{ - if (nm_streq (setting_name, NM_SETTING_CONNECTION_SETTING_NAME)) { - /* Whitelist allowed properties from "connection" setting which are - * allowed to differ. - * - * This includes UUID, there is no principal problem with reapplying a - * connection and changing its UUID. In fact, disallowing it makes it - * cumbersome for the user to reapply any connection but the original - * settings-connection. */ - return nm_device_hash_check_invalid_keys (diffs, - NM_SETTING_CONNECTION_SETTING_NAME, - error, - NM_SETTING_CONNECTION_ID, - NM_SETTING_CONNECTION_UUID, - NM_SETTING_CONNECTION_STABLE_ID, - NM_SETTING_CONNECTION_AUTOCONNECT, - NM_SETTING_CONNECTION_ZONE, - NM_SETTING_CONNECTION_METERED, - NM_SETTING_CONNECTION_LLDP, - NM_SETTING_CONNECTION_MDNS, - NM_SETTING_CONNECTION_LLMNR); - } else if (NM_IN_STRSET (setting_name, - NM_SETTING_USER_SETTING_NAME, - NM_SETTING_PROXY_SETTING_NAME, - NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP6_CONFIG_SETTING_NAME)) { - return TRUE; - } else if ( nm_streq (setting_name, NM_SETTING_WIRED_SETTING_NAME) - && NM_IN_SET (NM_DEVICE_GET_CLASS (self)->get_configured_mtu, - nm_device_get_configured_mtu_wired_parent, - nm_device_get_configured_mtu_for_wired)) { - return nm_device_hash_check_invalid_keys (diffs, - NM_SETTING_WIRED_SETTING_NAME, - error, - NM_SETTING_WIRED_MTU); - } else { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply any changes to '%s' setting", - setting_name); - return FALSE; - } +can_reapply_change(NMDevice * self, + const char *setting_name, + NMSetting * s_old, + NMSetting * s_new, + GHashTable *diffs, + GError ** error) +{ + if (nm_streq(setting_name, NM_SETTING_CONNECTION_SETTING_NAME)) { + /* Whitelist allowed properties from "connection" setting which are + * allowed to differ. + * + * This includes UUID, there is no principal problem with reapplying a + * connection and changing its UUID. In fact, disallowing it makes it + * cumbersome for the user to reapply any connection but the original + * settings-connection. */ + return nm_device_hash_check_invalid_keys(diffs, + NM_SETTING_CONNECTION_SETTING_NAME, + error, + NM_SETTING_CONNECTION_ID, + NM_SETTING_CONNECTION_UUID, + NM_SETTING_CONNECTION_STABLE_ID, + NM_SETTING_CONNECTION_AUTOCONNECT, + NM_SETTING_CONNECTION_ZONE, + NM_SETTING_CONNECTION_METERED, + NM_SETTING_CONNECTION_LLDP, + NM_SETTING_CONNECTION_MDNS, + NM_SETTING_CONNECTION_LLMNR); + } else if (NM_IN_STRSET(setting_name, + NM_SETTING_USER_SETTING_NAME, + NM_SETTING_PROXY_SETTING_NAME, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME)) { + return TRUE; + } else if (nm_streq(setting_name, NM_SETTING_WIRED_SETTING_NAME) + && NM_IN_SET(NM_DEVICE_GET_CLASS(self)->get_configured_mtu, + nm_device_get_configured_mtu_wired_parent, + nm_device_get_configured_mtu_for_wired)) { + return nm_device_hash_check_invalid_keys(diffs, + NM_SETTING_WIRED_SETTING_NAME, + error, + NM_SETTING_WIRED_MTU); + } else { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Can't reapply any changes to '%s' setting", + setting_name); + return FALSE; + } } static void -reapply_connection (NMDevice *self, NMConnection *con_old, NMConnection *con_new) -{ -} +reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new) +{} /* check_and_reapply_connection: * @connection: the new connection settings to be applied or %NULL to reapply @@ -12329,823 +12546,834 @@ reapply_connection (NMDevice *self, NMConnection *con_old, NMConnection *con_new * Return: %FALSE if the new configuration can not be reapplied. */ static gboolean -check_and_reapply_connection (NMDevice *self, - NMConnection *connection, - guint64 version_id, - char **audit_args, - GError **error) -{ - NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *applied = nm_device_get_applied_connection (self); - gs_unref_object NMConnection *applied_clone = NULL; - gs_unref_hashtable GHashTable *diffs = NULL; - NMConnection *con_old, *con_new; - NMSettingIPConfig *s_ip4_old, *s_ip4_new; - NMSettingIPConfig *s_ip6_old, *s_ip6_new; - GHashTableIter iter; - - if ( priv->state < NM_DEVICE_STATE_PREPARE - || priv->state > NM_DEVICE_STATE_ACTIVATED) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not activated"); - return FALSE; - } - - nm_connection_diff (connection, - applied, - NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP | - NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, - &diffs); - - 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 - *************************************************************************/ - if (diffs) { - char *setting_name; - GHashTable *setting_diff; - - g_hash_table_iter_init (&iter, diffs); - while (g_hash_table_iter_next (&iter, (gpointer *) &setting_name, (gpointer *) &setting_diff)) { - if (!klass->can_reapply_change (self, - setting_name, - nm_connection_get_setting_by_name (applied, setting_name), - nm_connection_get_setting_by_name (connection, setting_name), - setting_diff, - error)) - return FALSE; - } - } - - if ( version_id != 0 - && version_id != nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request.obj)) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_VERSION_ID_MISMATCH, - "Reapply failed because device changed in the meantime and the version-id mismatches"); - return FALSE; - } - - /************************************************************************** - * Update applied connection - *************************************************************************/ - - if (diffs) - nm_active_connection_version_id_bump ((NMActiveConnection *) priv->act_request.obj); - - _LOGD (LOGD_DEVICE, "reapply (version-id %llu%s)", - (unsigned long long) nm_active_connection_version_id_get (((NMActiveConnection *) priv->act_request.obj)), - diffs ? "" : " (unmodified)"); - - if (diffs) { - NMConnection *connection_clean = connection; - gs_unref_object NMConnection *connection_clean_free = NULL; - - { - NMSettingConnection *s_con_a, *s_con_n; - - /* we allow re-applying a connection with differing ID, UUID, STABLE_ID and AUTOCONNECT. - * This is for convenience but these values are not actually changeable. So, check - * if they changed, and if the did revert to the original values. */ - s_con_a = nm_connection_get_setting_connection (applied); - s_con_n = nm_connection_get_setting_connection (connection); - - if ( !nm_streq (nm_setting_connection_get_id (s_con_a), nm_setting_connection_get_id (s_con_n)) - || !nm_streq (nm_setting_connection_get_uuid (s_con_a), nm_setting_connection_get_uuid (s_con_n)) - || nm_setting_connection_get_autoconnect (s_con_a) != nm_setting_connection_get_autoconnect (s_con_n) - || !nm_streq0 (nm_setting_connection_get_stable_id (s_con_a), nm_setting_connection_get_stable_id (s_con_n))) { - connection_clean_free = nm_simple_connection_new_clone (connection); - connection_clean = connection_clean_free; - s_con_n = nm_connection_get_setting_connection (connection_clean); - g_object_set (s_con_n, - NM_SETTING_CONNECTION_ID, nm_setting_connection_get_id (s_con_a), - NM_SETTING_CONNECTION_UUID, nm_setting_connection_get_uuid (s_con_a), - NM_SETTING_CONNECTION_AUTOCONNECT, nm_setting_connection_get_autoconnect (s_con_a), - NM_SETTING_CONNECTION_STABLE_ID, nm_setting_connection_get_stable_id (s_con_a), - NULL); - } - } - - con_old = applied_clone = nm_simple_connection_new_clone (applied); - con_new = applied; - nm_connection_replace_settings_from_connection (applied, connection_clean); - nm_connection_clear_secrets (applied); - } else - con_old = con_new = applied; - - priv->v4_commit_first_time = TRUE; - priv->v6_commit_first_time = TRUE; - - priv->v4_route_table_initialized = FALSE; - priv->v6_route_table_initialized = FALSE; - - /************************************************************************** - * Reapply changes - * - * Note that reapply_connection() is called as very first. This is for example - * important for NMDeviceWireGuard, which implements coerce_route_table() - * and get_extra_rules(). - * That is because NMDeviceWireGuard caches settings, so during reapply that - * cache must be updated *first*. - *************************************************************************/ - klass->reapply_connection (self, con_old, con_new); - - if (priv->state >= NM_DEVICE_STATE_CONFIG) - lldp_init (self, FALSE); - - if (priv->state >= NM_DEVICE_STATE_IP_CONFIG) { - s_ip4_old = nm_connection_get_setting_ip4_config (con_old); - s_ip4_new = nm_connection_get_setting_ip4_config (con_new); - s_ip6_old = nm_connection_get_setting_ip6_config (con_old); - s_ip6_new = nm_connection_get_setting_ip6_config (con_new); - - /* Allow reapply of MTU */ - priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; - - nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new); - nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new); - - _routing_rules_sync (self, NM_TERNARY_TRUE); - - reactivate_proxy_config (self); - } - - if (priv->state >= NM_DEVICE_STATE_IP_CHECK) - nm_device_update_firewall_zone (self); - - if (priv->state >= NM_DEVICE_STATE_ACTIVATED) - nm_device_update_metered (self); - - return TRUE; +check_and_reapply_connection(NMDevice * self, + NMConnection *connection, + guint64 version_id, + char ** audit_args, + GError ** error) +{ + NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * applied = nm_device_get_applied_connection(self); + gs_unref_object NMConnection *applied_clone = NULL; + gs_unref_hashtable GHashTable *diffs = NULL; + NMConnection * con_old, *con_new; + NMSettingIPConfig * s_ip4_old, *s_ip4_new; + NMSettingIPConfig * s_ip6_old, *s_ip6_new; + GHashTableIter iter; + + if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) { + g_set_error_literal(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not activated"); + return FALSE; + } + + nm_connection_diff(connection, + applied, + NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP + | NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, + &diffs); + + 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 + *************************************************************************/ + if (diffs) { + char * setting_name; + GHashTable *setting_diff; + + g_hash_table_iter_init(&iter, diffs); + while ( + g_hash_table_iter_next(&iter, (gpointer *) &setting_name, (gpointer *) &setting_diff)) { + if (!klass->can_reapply_change( + self, + setting_name, + nm_connection_get_setting_by_name(applied, setting_name), + nm_connection_get_setting_by_name(connection, setting_name), + setting_diff, + error)) + return FALSE; + } + } + + if (version_id != 0 + && version_id + != nm_active_connection_version_id_get( + (NMActiveConnection *) priv->act_request.obj)) { + g_set_error_literal( + error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_VERSION_ID_MISMATCH, + "Reapply failed because device changed in the meantime and the version-id mismatches"); + return FALSE; + } + + /************************************************************************** + * Update applied connection + *************************************************************************/ + + if (diffs) + nm_active_connection_version_id_bump((NMActiveConnection *) priv->act_request.obj); + + _LOGD(LOGD_DEVICE, + "reapply (version-id %llu%s)", + (unsigned long long) nm_active_connection_version_id_get( + ((NMActiveConnection *) priv->act_request.obj)), + diffs ? "" : " (unmodified)"); + + if (diffs) { + NMConnection * connection_clean = connection; + gs_unref_object NMConnection *connection_clean_free = NULL; + + { + NMSettingConnection *s_con_a, *s_con_n; + + /* we allow re-applying a connection with differing ID, UUID, STABLE_ID and AUTOCONNECT. + * This is for convenience but these values are not actually changeable. So, check + * if they changed, and if the did revert to the original values. */ + s_con_a = nm_connection_get_setting_connection(applied); + s_con_n = nm_connection_get_setting_connection(connection); + + if (!nm_streq(nm_setting_connection_get_id(s_con_a), + nm_setting_connection_get_id(s_con_n)) + || !nm_streq(nm_setting_connection_get_uuid(s_con_a), + nm_setting_connection_get_uuid(s_con_n)) + || nm_setting_connection_get_autoconnect(s_con_a) + != nm_setting_connection_get_autoconnect(s_con_n) + || !nm_streq0(nm_setting_connection_get_stable_id(s_con_a), + nm_setting_connection_get_stable_id(s_con_n))) { + connection_clean_free = nm_simple_connection_new_clone(connection); + connection_clean = connection_clean_free; + s_con_n = nm_connection_get_setting_connection(connection_clean); + g_object_set(s_con_n, + NM_SETTING_CONNECTION_ID, + nm_setting_connection_get_id(s_con_a), + NM_SETTING_CONNECTION_UUID, + nm_setting_connection_get_uuid(s_con_a), + NM_SETTING_CONNECTION_AUTOCONNECT, + nm_setting_connection_get_autoconnect(s_con_a), + NM_SETTING_CONNECTION_STABLE_ID, + nm_setting_connection_get_stable_id(s_con_a), + NULL); + } + } + + con_old = applied_clone = nm_simple_connection_new_clone(applied); + con_new = applied; + nm_connection_replace_settings_from_connection(applied, connection_clean); + nm_connection_clear_secrets(applied); + } else + con_old = con_new = applied; + + priv->v4_commit_first_time = TRUE; + priv->v6_commit_first_time = TRUE; + + priv->v4_route_table_initialized = FALSE; + priv->v6_route_table_initialized = FALSE; + + /************************************************************************** + * Reapply changes + * + * Note that reapply_connection() is called as very first. This is for example + * important for NMDeviceWireGuard, which implements coerce_route_table() + * and get_extra_rules(). + * That is because NMDeviceWireGuard caches settings, so during reapply that + * cache must be updated *first*. + *************************************************************************/ + klass->reapply_connection(self, con_old, con_new); + + if (priv->state >= NM_DEVICE_STATE_CONFIG) + lldp_init(self, FALSE); + + if (priv->state >= NM_DEVICE_STATE_IP_CONFIG) { + s_ip4_old = nm_connection_get_setting_ip4_config(con_old); + s_ip4_new = nm_connection_get_setting_ip4_config(con_new); + s_ip6_old = nm_connection_get_setting_ip6_config(con_old); + s_ip6_new = nm_connection_get_setting_ip6_config(con_new); + + /* Allow reapply of MTU */ + priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; + + nm_device_reactivate_ip4_config(self, s_ip4_old, s_ip4_new); + nm_device_reactivate_ip6_config(self, s_ip6_old, s_ip6_new); + + _routing_rules_sync(self, NM_TERNARY_TRUE); + + reactivate_proxy_config(self); + } + + if (priv->state >= NM_DEVICE_STATE_IP_CHECK) + nm_device_update_firewall_zone(self); + + if (priv->state >= NM_DEVICE_STATE_ACTIVATED) + nm_device_update_metered(self); + + return TRUE; } gboolean -nm_device_reapply (NMDevice *self, - NMConnection *connection, - GError **error) +nm_device_reapply(NMDevice *self, NMConnection *connection, GError **error) { - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - return check_and_reapply_connection (self, - connection, - 0, - NULL, - error); + return check_and_reapply_connection(self, connection, 0, NULL, error); } typedef struct { - NMConnection *connection; - guint64 version_id; + NMConnection *connection; + guint64 version_id; } ReapplyData; static void -reapply_cb (NMDevice *self, - GDBusMethodInvocation *context, - NMAuthSubject *subject, - GError *error, - gpointer user_data) -{ - ReapplyData *reapply_data = user_data; - guint64 version_id = 0; - gs_unref_object NMConnection *connection = NULL; - GError *local = NULL; - gs_free char *audit_args = NULL; - - if (reapply_data) { - connection = reapply_data->connection; - version_id = reapply_data->version_id; - g_slice_free (ReapplyData, reapply_data); - } - - if (error) { - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, subject, error->message); - g_dbus_method_invocation_return_gerror (context, error); - return; - } - - if (nm_device_sys_iface_state_is_external (self)) - nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); - - if (!check_and_reapply_connection (self, - connection ?: nm_device_get_settings_connection_get_connection (self), - version_id, - &audit_args, - &local)) { - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, audit_args, subject, local->message); - g_dbus_method_invocation_take_error (context, local); - local = NULL; - } else { - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, TRUE, audit_args, subject, NULL); - g_dbus_method_invocation_return_value (context, NULL); - } +reapply_cb(NMDevice * self, + GDBusMethodInvocation *context, + NMAuthSubject * subject, + GError * error, + gpointer user_data) +{ + ReapplyData * reapply_data = user_data; + guint64 version_id = 0; + gs_unref_object NMConnection *connection = NULL; + GError * local = NULL; + gs_free char * audit_args = NULL; + + if (reapply_data) { + connection = reapply_data->connection; + version_id = reapply_data->version_id; + g_slice_free(ReapplyData, reapply_data); + } + + if (error) { + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, + self, + FALSE, + NULL, + subject, + error->message); + g_dbus_method_invocation_return_gerror(context, error); + return; + } + + if (nm_device_sys_iface_state_is_external(self)) + nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); + + if (!check_and_reapply_connection(self, + connection + ?: nm_device_get_settings_connection_get_connection(self), + version_id, + &audit_args, + &local)) { + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, + self, + FALSE, + audit_args, + subject, + local->message); + g_dbus_method_invocation_take_error(context, local); + local = NULL; + } else { + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, self, TRUE, audit_args, subject, NULL); + g_dbus_method_invocation_return_value(context, NULL); + } } static void -impl_device_reapply (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMDevice *self = NM_DEVICE (obj); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMSettingsConnection *settings_connection; - NMConnection *connection = NULL; - GError *error = NULL; - ReapplyData *reapply_data; - gs_unref_variant GVariant *settings = NULL; - guint64 version_id; - guint32 flags; - - g_variant_get (parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &flags); - - /* No flags supported as of now. */ - if (flags != 0) { - error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Invalid flags specified"); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, invocation, error->message); - g_dbus_method_invocation_take_error (invocation, error); - return; - } - - if ( priv->state < NM_DEVICE_STATE_PREPARE - || priv->state > NM_DEVICE_STATE_ACTIVATED) { - error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not activated"); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, invocation, error->message); - g_dbus_method_invocation_take_error (invocation, error); - return; - } - - settings_connection = nm_device_get_settings_connection (self); - g_return_if_fail (settings_connection); - - if (settings && g_variant_n_children (settings)) { - /* New settings specified inline. */ - connection = _nm_simple_connection_new_from_dbus (settings, - NM_SETTING_PARSE_FLAGS_STRICT - | NM_SETTING_PARSE_FLAGS_NORMALIZE, - &error); - if (!connection) { - g_prefix_error (&error, "The settings specified are invalid: "); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, NULL, invocation, error->message); - g_dbus_method_invocation_take_error (invocation, error); - return; - } - nm_connection_clear_secrets (connection); - } - - if (connection || version_id) { - reapply_data = g_slice_new (ReapplyData); - reapply_data->connection = connection; - reapply_data->version_id = version_id; - } else - reapply_data = NULL; - - nm_device_auth_request (self, - invocation, - nm_device_get_applied_connection (self), - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - NULL, - reapply_cb, - reapply_data); +impl_device_reapply(NMDBusObject * obj, + const NMDBusInterfaceInfoExtended *interface_info, + const NMDBusMethodInfoExtended * method_info, + GDBusConnection * dbus_connection, + const char * sender, + GDBusMethodInvocation * invocation, + GVariant * parameters) +{ + NMDevice * self = NM_DEVICE(obj); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingsConnection *settings_connection; + NMConnection * connection = NULL; + GError * error = NULL; + ReapplyData * reapply_data; + gs_unref_variant GVariant *settings = NULL; + guint64 version_id; + guint32 flags; + + g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &flags); + + /* No flags supported as of now. */ + if (flags != 0) { + error = + g_error_new_literal(NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "Invalid flags specified"); + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, + self, + FALSE, + NULL, + invocation, + error->message); + g_dbus_method_invocation_take_error(invocation, error); + return; + } + + if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) { + error = g_error_new_literal(NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not activated"); + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, + self, + FALSE, + NULL, + invocation, + error->message); + g_dbus_method_invocation_take_error(invocation, error); + return; + } + + settings_connection = nm_device_get_settings_connection(self); + g_return_if_fail(settings_connection); + + if (settings && g_variant_n_children(settings)) { + /* New settings specified inline. */ + connection = _nm_simple_connection_new_from_dbus(settings, + NM_SETTING_PARSE_FLAGS_STRICT + | NM_SETTING_PARSE_FLAGS_NORMALIZE, + &error); + if (!connection) { + g_prefix_error(&error, "The settings specified are invalid: "); + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, + self, + FALSE, + NULL, + invocation, + error->message); + g_dbus_method_invocation_take_error(invocation, error); + return; + } + nm_connection_clear_secrets(connection); + } + + if (connection || version_id) { + reapply_data = g_slice_new(ReapplyData); + reapply_data->connection = connection; + reapply_data->version_id = version_id; + } else + reapply_data = NULL; + + nm_device_auth_request(self, + invocation, + nm_device_get_applied_connection(self), + NM_AUTH_PERMISSION_NETWORK_CONTROL, + TRUE, + NULL, + reapply_cb, + reapply_data); } /*****************************************************************************/ static void -get_applied_connection_cb (NMDevice *self, - GDBusMethodInvocation *context, - NMAuthSubject *subject, - GError *error, - gpointer user_data /* possibly dangling pointer */) -{ - NMDevicePrivate *priv; - NMConnection *applied_connection; - GVariant *settings; - - g_return_if_fail (NM_IS_DEVICE (self)); - - if (error) { - g_dbus_method_invocation_return_gerror (context, error); - return; - } - - priv = NM_DEVICE_GET_PRIVATE (self); - - applied_connection = nm_device_get_applied_connection (self); - - if (!applied_connection) { - error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not activated"); - g_dbus_method_invocation_take_error (context, error); - return; - } - - if (applied_connection != user_data) { - /* The applied connection changed due to a race. Reauthenticate. */ - nm_device_auth_request (self, - context, - applied_connection, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - NULL, - get_applied_connection_cb, - applied_connection /* no need take a ref. We will not dereference this pointer. */); - return; - } - - settings = nm_connection_to_dbus (applied_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); - if (!settings) - settings = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0); - - g_dbus_method_invocation_return_value (context, - g_variant_new ("(@a{sa{sv}}t)", - settings, - nm_active_connection_version_id_get ((NMActiveConnection *) priv->act_request.obj))); -} - -static void -impl_device_get_applied_connection (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMDevice *self = NM_DEVICE (obj); - NMConnection *applied_connection; - guint32 flags; - - g_variant_get (parameters, "(u)", &flags); - - /* No flags supported as of now. */ - if (flags != 0) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Invalid flags specified"); - return; - } - - applied_connection = nm_device_get_applied_connection (self); - if (!applied_connection) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not activated"); - return; - } - - nm_device_auth_request (self, - invocation, - applied_connection, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - NULL, - get_applied_connection_cb, - applied_connection /* no need take a ref. We will not dereference this pointer. */); +impl_device_get_applied_connection(NMDBusObject * obj, + const NMDBusInterfaceInfoExtended *interface_info, + const NMDBusMethodInfoExtended * method_info, + GDBusConnection * connection, + const char * sender, + GDBusMethodInvocation * invocation, + GVariant * parameters) +{ + NMDevice * self = NM_DEVICE(obj); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gs_free_error GError *error = NULL; + NMConnection * applied_connection; + guint32 flags; + GVariant * var_settings; + + g_variant_get(parameters, "(u)", &flags); + + /* No flags supported as of now. */ + if (flags != 0) { + g_dbus_method_invocation_return_error_literal(invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "Invalid flags specified"); + return; + } + + applied_connection = nm_device_get_applied_connection(self); + if (!applied_connection) { + g_dbus_method_invocation_return_error_literal(invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not activated"); + return; + } + + if (!nm_auth_is_invocation_in_acl_set_error(applied_connection, + invocation, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + NULL, + &error)) { + g_dbus_method_invocation_take_error(invocation, g_steal_pointer(&error)); + return; + } + + var_settings = nm_connection_to_dbus(applied_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); + if (!var_settings) + var_settings = g_variant_new_array(G_VARIANT_TYPE("{sa{sv}}"), NULL, 0); + + g_dbus_method_invocation_return_value( + invocation, + g_variant_new( + "(@a{sa{sv}}t)", + var_settings, + nm_active_connection_version_id_get((NMActiveConnection *) priv->act_request.obj))); } /*****************************************************************************/ typedef struct { - gint64 timestamp_ms; - bool dirty; + gint64 timestamp_ms; + bool dirty; } IP6RoutesTemporaryNotAvailableData; static gboolean -_rt6_temporary_not_available_timeout (gpointer user_data) +_rt6_temporary_not_available_timeout(gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->rt6_temporary_not_available_id = 0; - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); + priv->rt6_temporary_not_available_id = 0; + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; } static gboolean -_rt6_temporary_not_available_set (NMDevice *self, - GPtrArray *temporary_not_available) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - IP6RoutesTemporaryNotAvailableData *data; - GHashTableIter iter; - gint64 now_ms, oldest_ms; - const gint64 MAX_AGE_MS = 20000; - guint i; - gboolean success = TRUE; - - if ( !temporary_not_available - || !temporary_not_available->len) { - /* nothing outstanding. Clear tracking the routes. */ - nm_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source (&priv->rt6_temporary_not_available_id); - return success; - } - - if (priv->rt6_temporary_not_available) { - g_hash_table_iter_init (&iter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data)) - data->dirty = TRUE; - } else { - priv->rt6_temporary_not_available = g_hash_table_new_full ((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal, - (GDestroyNotify) nmp_object_unref, - nm_g_slice_free_fcn (IP6RoutesTemporaryNotAvailableData)); - } - - now_ms = nm_utils_get_monotonic_timestamp_msec (); - oldest_ms = now_ms; - - for (i = 0; i < temporary_not_available->len; i++) { - const NMPObject *o = temporary_not_available->pdata[i]; - - data = g_hash_table_lookup (priv->rt6_temporary_not_available, o); - if (data) { - if (!data->dirty) - continue; - data->dirty = FALSE; - nm_assert (data->timestamp_ms > 0 && data->timestamp_ms <= now_ms); - if (now_ms > data->timestamp_ms + MAX_AGE_MS) { - /* timeout. Could not add this address. */ - _LOGW (LOGD_DEVICE, "failure to add IPv6 route: %s", - nmp_object_to_string (o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - success = FALSE; - } else - oldest_ms = MIN (data->timestamp_ms, oldest_ms); - continue; - } - - data = g_slice_new0 (IP6RoutesTemporaryNotAvailableData); - data->timestamp_ms = now_ms; - g_hash_table_insert (priv->rt6_temporary_not_available, (gpointer) nmp_object_ref (o), data); - } - - g_hash_table_iter_init (&iter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data)) { - if (data->dirty) - g_hash_table_iter_remove (&iter); - } - - nm_clear_g_source (&priv->rt6_temporary_not_available_id); - priv->rt6_temporary_not_available_id = g_timeout_add (oldest_ms + MAX_AGE_MS - now_ms, - _rt6_temporary_not_available_timeout, - self); - - return success; +_rt6_temporary_not_available_set(NMDevice *self, GPtrArray *temporary_not_available) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + IP6RoutesTemporaryNotAvailableData *data; + GHashTableIter iter; + gint64 now_ms, oldest_ms; + const gint64 MAX_AGE_MS = 20000; + guint i; + gboolean success = TRUE; + + if (!temporary_not_available || !temporary_not_available->len) { + /* nothing outstanding. Clear tracking the routes. */ + nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); + nm_clear_g_source(&priv->rt6_temporary_not_available_id); + return success; + } + + if (priv->rt6_temporary_not_available) { + g_hash_table_iter_init(&iter, priv->rt6_temporary_not_available); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data)) + data->dirty = TRUE; + } else { + priv->rt6_temporary_not_available = + g_hash_table_new_full((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal, + (GDestroyNotify) nmp_object_unref, + nm_g_slice_free_fcn(IP6RoutesTemporaryNotAvailableData)); + } + + now_ms = nm_utils_get_monotonic_timestamp_msec(); + oldest_ms = now_ms; + + for (i = 0; i < temporary_not_available->len; i++) { + const NMPObject *o = temporary_not_available->pdata[i]; + + data = g_hash_table_lookup(priv->rt6_temporary_not_available, o); + if (data) { + if (!data->dirty) + continue; + data->dirty = FALSE; + nm_assert(data->timestamp_ms > 0 && data->timestamp_ms <= now_ms); + if (now_ms > data->timestamp_ms + MAX_AGE_MS) { + /* timeout. Could not add this address. */ + _LOGW(LOGD_DEVICE, + "failure to add IPv6 route: %s", + nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + success = FALSE; + } else + oldest_ms = MIN(data->timestamp_ms, oldest_ms); + continue; + } + + data = g_slice_new0(IP6RoutesTemporaryNotAvailableData); + data->timestamp_ms = now_ms; + g_hash_table_insert(priv->rt6_temporary_not_available, (gpointer) nmp_object_ref(o), data); + } + + g_hash_table_iter_init(&iter, priv->rt6_temporary_not_available); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data)) { + if (data->dirty) + g_hash_table_iter_remove(&iter); + } + + nm_clear_g_source(&priv->rt6_temporary_not_available_id); + priv->rt6_temporary_not_available_id = + g_timeout_add(oldest_ms + MAX_AGE_MS - now_ms, _rt6_temporary_not_available_timeout, self); + + return success; } /*****************************************************************************/ static void -disconnect_cb (NMDevice *self, - GDBusMethodInvocation *context, - NMAuthSubject *subject, - GError *error, - gpointer user_data) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - GError *local = NULL; - - if (error) { - g_dbus_method_invocation_return_gerror (context, error); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, NULL, subject, error->message); - return; - } - - /* Authorized */ - if (priv->state <= NM_DEVICE_STATE_DISCONNECTED) { - local = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not active"); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, NULL, subject, local->message); - g_dbus_method_invocation_take_error (context, local); - } else { - nm_device_autoconnect_blocked_set (self, NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT); - - nm_device_state_changed (self, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - g_dbus_method_invocation_return_value (context, NULL); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, TRUE, NULL, subject, NULL); - } +disconnect_cb(NMDevice * self, + GDBusMethodInvocation *context, + NMAuthSubject * subject, + GError * error, + gpointer user_data) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + GError * local = NULL; + + if (error) { + g_dbus_method_invocation_return_gerror(context, error); + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DISCONNECT, + self, + FALSE, + NULL, + subject, + error->message); + return; + } + + /* Authorized */ + if (priv->state <= NM_DEVICE_STATE_DISCONNECTED) { + local = g_error_new_literal(NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not active"); + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DISCONNECT, + self, + FALSE, + NULL, + subject, + local->message); + g_dbus_method_invocation_take_error(context, local); + } else { + nm_device_autoconnect_blocked_set(self, NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT); + + nm_device_state_changed(self, + NM_DEVICE_STATE_DEACTIVATING, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + g_dbus_method_invocation_return_value(context, NULL); + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DISCONNECT, self, TRUE, NULL, subject, NULL); + } } static void -_clear_queued_act_request (NMDevicePrivate *priv, - NMActiveConnectionStateReason active_reason) +_clear_queued_act_request(NMDevicePrivate *priv, NMActiveConnectionStateReason active_reason) { - if (priv->queued_act_request) { - gs_unref_object NMActRequest *ac = NULL; + if (priv->queued_act_request) { + gs_unref_object NMActRequest *ac = NULL; - ac = g_steal_pointer (&priv->queued_act_request); - nm_active_connection_set_state_fail ((NMActiveConnection *) ac, - active_reason, - NULL); - } + ac = g_steal_pointer(&priv->queued_act_request); + nm_active_connection_set_state_fail((NMActiveConnection *) ac, active_reason, NULL); + } } static void -impl_device_disconnect (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *dbus_connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMDevice *self = NM_DEVICE (obj); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - - if (!priv->act_request.obj) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "This device is not active"); - return; - } - - connection = nm_device_get_applied_connection (self); - nm_assert (connection); - - nm_device_auth_request (self, - invocation, - connection, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - NULL, - disconnect_cb, - NULL); +impl_device_disconnect(NMDBusObject * obj, + const NMDBusInterfaceInfoExtended *interface_info, + const NMDBusMethodInfoExtended * method_info, + GDBusConnection * dbus_connection, + const char * sender, + GDBusMethodInvocation * invocation, + GVariant * parameters) +{ + NMDevice * self = NM_DEVICE(obj); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + + if (!priv->act_request.obj) { + g_dbus_method_invocation_return_error_literal(invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "This device is not active"); + return; + } + + connection = nm_device_get_applied_connection(self); + nm_assert(connection); + + nm_device_auth_request(self, + invocation, + connection, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + TRUE, + NULL, + disconnect_cb, + NULL); } static void -delete_cb (NMDevice *self, - GDBusMethodInvocation *context, - NMAuthSubject *subject, - GError *error, - gpointer user_data) -{ - GError *local = NULL; - - if (error) { - g_dbus_method_invocation_return_gerror (context, error); - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, FALSE, NULL, subject, error->message); - return; - } - - /* Authorized */ - nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, TRUE, NULL, subject, NULL); - if (nm_device_unrealize (self, TRUE, &local)) - g_dbus_method_invocation_return_value (context, NULL); - else - g_dbus_method_invocation_take_error (context, local); +delete_cb(NMDevice * self, + GDBusMethodInvocation *context, + NMAuthSubject * subject, + GError * error, + gpointer user_data) +{ + GError *local = NULL; + + if (error) { + g_dbus_method_invocation_return_gerror(context, error); + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DELETE, + self, + FALSE, + NULL, + subject, + error->message); + return; + } + + /* Authorized */ + nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DELETE, self, TRUE, NULL, subject, NULL); + if (nm_device_unrealize(self, TRUE, &local)) + g_dbus_method_invocation_return_value(context, NULL); + else + g_dbus_method_invocation_take_error(context, local); } static void -impl_device_delete (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) -{ - NMDevice *self = NM_DEVICE (obj); - - if ( !nm_device_is_software (self) - || !nm_device_is_real (self)) { - g_dbus_method_invocation_return_error_literal (invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_SOFTWARE, - "This device is not a software device or is not realized"); - return; - } - - nm_device_auth_request (self, - invocation, - NULL, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - NULL, - delete_cb, - NULL); +impl_device_delete(NMDBusObject * obj, + const NMDBusInterfaceInfoExtended *interface_info, + const NMDBusMethodInfoExtended * method_info, + GDBusConnection * connection, + const char * sender, + GDBusMethodInvocation * invocation, + GVariant * parameters) +{ + NMDevice *self = NM_DEVICE(obj); + + if (!nm_device_is_software(self) || !nm_device_is_real(self)) { + g_dbus_method_invocation_return_error_literal( + invocation, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_SOFTWARE, + "This device is not a software device or is not realized"); + return; + } + + nm_device_auth_request(self, + invocation, + NULL, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + TRUE, + NULL, + delete_cb, + NULL); } static void -_device_activate (NMDevice *self, NMActRequest *req) +_device_activate(NMDevice *self, NMActRequest *req) { - NMConnection *connection; + NMConnection *connection; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_ACT_REQUEST (req)); - nm_assert (nm_device_is_real (self)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_IS_ACT_REQUEST(req)); + nm_assert(nm_device_is_real(self)); - /* Ensure the activation request is still valid; the master may have - * already failed in which case activation of this device should not proceed. - */ - if (nm_active_connection_get_state (NM_ACTIVE_CONNECTION (req)) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) - return; + /* Ensure the activation request is still valid; the master may have + * already failed in which case activation of this device should not proceed. + */ + if (nm_active_connection_get_state(NM_ACTIVE_CONNECTION(req)) + >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) + return; - if (!nm_device_get_managed (self, FALSE)) { - /* It's unclear why the device would be unmanaged at this point. - * Just to be sure, handle it and error out. */ - _LOGE (LOGD_DEVICE, "Activation: failed activating connection '%s' because device is still unmanaged", - nm_active_connection_get_settings_connection_id ((NMActiveConnection *) req)); - nm_active_connection_set_state_fail ((NMActiveConnection *) req, - NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN, - NULL); - return; - } + if (!nm_device_get_managed(self, FALSE)) { + /* It's unclear why the device would be unmanaged at this point. + * Just to be sure, handle it and error out. */ + _LOGE(LOGD_DEVICE, + "Activation: failed activating connection '%s' because device is still unmanaged", + nm_active_connection_get_settings_connection_id((NMActiveConnection *) req)); + nm_active_connection_set_state_fail((NMActiveConnection *) req, + NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN, + NULL); + return; + } - connection = nm_act_request_get_applied_connection (req); - nm_assert (connection); + connection = nm_act_request_get_applied_connection(req); + nm_assert(connection); - _LOGI (LOGD_DEVICE, "Activation: starting connection '%s' (%s)", - nm_connection_get_id (connection), - nm_connection_get_uuid (connection)); + _LOGI(LOGD_DEVICE, + "Activation: starting connection '%s' (%s)", + nm_connection_get_id(connection), + nm_connection_get_uuid(connection)); - delete_on_deactivate_unschedule (self); + delete_on_deactivate_unschedule(self); - act_request_set (self, req); + act_request_set(self, req); - nm_device_activate_schedule_stage1_device_prepare (self, FALSE); + nm_device_activate_schedule_stage1_device_prepare(self, FALSE); } static void -_carrier_wait_check_queued_act_request (NMDevice *self) +_carrier_wait_check_queued_act_request(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if ( !priv->queued_act_request - || !priv->queued_act_request_is_waiting_for_carrier) - return; + if (!priv->queued_act_request || !priv->queued_act_request_is_waiting_for_carrier) + return; - priv->queued_act_request_is_waiting_for_carrier = FALSE; - if (!priv->carrier) { - _LOGD (LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout"); - _clear_queued_act_request (priv, - NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); - } else if (priv->state == NM_DEVICE_STATE_DISCONNECTED) { - gs_unref_object NMActRequest *queued_req = NULL; + priv->queued_act_request_is_waiting_for_carrier = FALSE; + if (!priv->carrier) { + _LOGD(LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout"); + _clear_queued_act_request(priv, NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); + } else if (priv->state == NM_DEVICE_STATE_DISCONNECTED) { + gs_unref_object NMActRequest *queued_req = NULL; - _LOGD (LOGD_DEVICE, "Activate queued activation request as we now have carrier"); - queued_req = g_steal_pointer (&priv->queued_act_request); - _device_activate (self, queued_req); - } + _LOGD(LOGD_DEVICE, "Activate queued activation request as we now have carrier"); + queued_req = g_steal_pointer(&priv->queued_act_request); + _device_activate(self, queued_req); + } } static gboolean -_carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - - /* If we have carrier or if we are not waiting for it, the activation - * request is not blocked waiting for carrier. */ - if (priv->carrier) - return FALSE; - if (priv->carrier_wait_id == 0) - return FALSE; - - connection = nm_act_request_get_applied_connection (req); - if (!connection_requires_carrier (connection)) - return FALSE; - - if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL, NULL)) { - /* We passed all @flags we have, and no @specific_object. - * This equals maximal availability, if a connection is not available - * in this case, it is not waiting for carrier. - * - * Actually, why are we even trying to activate it? Strange, but whatever - * the reason, don't wait for carrier. - */ - return FALSE; - } - - if (nm_device_check_connection_available (self, connection, - NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, - NULL, NULL)) { - /* The connection was available with flags ALL, and it is still available - * if we pretend not to wait for carrier. That means that the - * connection is available now, and does not wait for carrier. - * - * Since the flags increase the availability of a connection, when checking - * ALL&~WAITING_CARRIER, it means that we certainly would wait for carrier. */ - return FALSE; - } - - /* The activation request must wait for carrier. */ - return TRUE; +_carrier_wait_check_act_request_must_queue(NMDevice *self, NMActRequest *req) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + + /* If we have carrier or if we are not waiting for it, the activation + * request is not blocked waiting for carrier. */ + if (priv->carrier) + return FALSE; + if (priv->carrier_wait_id == 0) + return FALSE; + + connection = nm_act_request_get_applied_connection(req); + if (!connection_requires_carrier(connection)) + return FALSE; + + if (!nm_device_check_connection_available(self, + connection, + NM_DEVICE_CHECK_CON_AVAILABLE_ALL, + NULL, + NULL)) { + /* We passed all @flags we have, and no @specific_object. + * This equals maximal availability, if a connection is not available + * in this case, it is not waiting for carrier. + * + * Actually, why are we even trying to activate it? Strange, but whatever + * the reason, don't wait for carrier. + */ + return FALSE; + } + + if (nm_device_check_connection_available( + self, + connection, + NM_DEVICE_CHECK_CON_AVAILABLE_ALL + & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, + NULL, + NULL)) { + /* The connection was available with flags ALL, and it is still available + * if we pretend not to wait for carrier. That means that the + * connection is available now, and does not wait for carrier. + * + * Since the flags increase the availability of a connection, when checking + * ALL&~WAITING_CARRIER, it means that we certainly would wait for carrier. */ + return FALSE; + } + + /* The activation request must wait for carrier. */ + return TRUE; } void -nm_device_disconnect_active_connection (NMActiveConnection *active, - NMDeviceStateReason device_reason, - NMActiveConnectionStateReason active_reason) -{ - NMDevice *self; - NMDevicePrivate *priv; - - g_return_if_fail (NM_IS_ACTIVE_CONNECTION (active)); - - self = nm_active_connection_get_device (active); - if (!self) { - /* hm, no device? Just fail the active connection. */ - goto do_fail; - } - - priv = NM_DEVICE_GET_PRIVATE (self); - - if (NM_ACTIVE_CONNECTION (priv->queued_act_request) == active) { - _clear_queued_act_request (priv, active_reason); - return; - } - - if (NM_ACTIVE_CONNECTION (priv->act_request.obj) == active) { - if (priv->state < NM_DEVICE_STATE_DEACTIVATING) { - nm_device_state_changed (self, - NM_DEVICE_STATE_DEACTIVATING, - device_reason); - } else { - /* @active is the current ac of @self, but it's going down already. - * Nothing to do. */ - } - return; - } - - /* the active connection references this device, but it's neither the - * queued_act_request nor the current act_request. Just set it to fail... */ +nm_device_disconnect_active_connection(NMActiveConnection * active, + NMDeviceStateReason device_reason, + NMActiveConnectionStateReason active_reason) +{ + NMDevice * self; + NMDevicePrivate *priv; + + g_return_if_fail(NM_IS_ACTIVE_CONNECTION(active)); + + self = nm_active_connection_get_device(active); + if (!self) { + /* hm, no device? Just fail the active connection. */ + goto do_fail; + } + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (NM_ACTIVE_CONNECTION(priv->queued_act_request) == active) { + _clear_queued_act_request(priv, active_reason); + return; + } + + if (NM_ACTIVE_CONNECTION(priv->act_request.obj) == active) { + if (priv->state < NM_DEVICE_STATE_DEACTIVATING) { + nm_device_state_changed(self, NM_DEVICE_STATE_DEACTIVATING, device_reason); + } else { + /* @active is the current ac of @self, but it's going down already. + * Nothing to do. */ + } + return; + } + + /* the active connection references this device, but it's neither the + * queued_act_request nor the current act_request. Just set it to fail... */ do_fail: - nm_active_connection_set_state_fail (active, - active_reason, - NULL); + nm_active_connection_set_state_fail(active, active_reason, NULL); } void -nm_device_queue_activation (NMDevice *self, NMActRequest *req) +nm_device_queue_activation(NMDevice *self, NMActRequest *req) { - NMDevicePrivate *priv; - gboolean must_queue; + NMDevicePrivate *priv; + gboolean must_queue; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_ACT_REQUEST (req)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_IS_ACT_REQUEST(req)); - nm_keep_alive_arm (nm_active_connection_get_keep_alive (NM_ACTIVE_CONNECTION (req))); + nm_keep_alive_arm(nm_active_connection_get_keep_alive(NM_ACTIVE_CONNECTION(req))); - if (nm_active_connection_get_state (NM_ACTIVE_CONNECTION (req)) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { - /* it's already deactivating. Nothing to do. */ - nm_assert (NM_IN_SET (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (req)), NULL, self)); - return; - } + if (nm_active_connection_get_state(NM_ACTIVE_CONNECTION(req)) + >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { + /* it's already deactivating. Nothing to do. */ + nm_assert( + NM_IN_SET(nm_active_connection_get_device(NM_ACTIVE_CONNECTION(req)), NULL, self)); + return; + } - nm_assert (self == nm_active_connection_get_device (NM_ACTIVE_CONNECTION (req))); + nm_assert(self == nm_active_connection_get_device(NM_ACTIVE_CONNECTION(req))); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - must_queue = _carrier_wait_check_act_request_must_queue (self, req); + must_queue = _carrier_wait_check_act_request_must_queue(self, req); - if ( !priv->act_request.obj - && !must_queue - && nm_device_is_real (self)) { - _device_activate (self, req); - return; - } + if (!priv->act_request.obj && !must_queue && nm_device_is_real(self)) { + _device_activate(self, req); + return; + } - /* supersede any already-queued request */ - _clear_queued_act_request (priv, - NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); - priv->queued_act_request = g_object_ref (req); - priv->queued_act_request_is_waiting_for_carrier = must_queue; + /* supersede any already-queued request */ + _clear_queued_act_request(priv, NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); + priv->queued_act_request = g_object_ref(req); + priv->queued_act_request_is_waiting_for_carrier = must_queue; - _LOGD (LOGD_DEVICE, "queue activation request waiting for %s", must_queue ? "carrier" : "currently active connection to disconnect"); + _LOGD(LOGD_DEVICE, + "queue activation request waiting for %s", + must_queue ? "carrier" : "currently active connection to disconnect"); - /* Deactivate existing activation request first */ - if (priv->act_request.obj) { - _LOGI (LOGD_DEVICE, "disconnecting for new activation request."); - nm_device_state_changed (self, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_NEW_ACTIVATION); - } + /* Deactivate existing activation request first */ + if (priv->act_request.obj) { + _LOGI(LOGD_DEVICE, "disconnecting for new activation request."); + nm_device_state_changed(self, + NM_DEVICE_STATE_DEACTIVATING, + NM_DEVICE_STATE_REASON_NEW_ACTIVATION); + } } /* @@ -13155,1293 +13383,1282 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) * */ gboolean -nm_device_is_activating (NMDevice *self) +nm_device_is_activating(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceState state; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceState state; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - state = nm_device_get_state (self); - if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) - return TRUE; + state = nm_device_get_state(self); + if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) + return TRUE; - /* There's a small race between the time when stage 1 is scheduled - * and when the device actually sets STATE_PREPARE when the activation - * handler is actually run. If there's an activation handler scheduled - * we're activating anyway. - */ - return priv->activation_source_id_4 != 0; + /* There's a small race between the time when stage 1 is scheduled + * and when the device actually sets STATE_PREPARE when the activation + * handler is actually run. If there's an activation handler scheduled + * we're activating anyway. + */ + return priv->activation_source_id_4 != 0; } NMProxyConfig * -nm_device_get_proxy_config (NMDevice *self) +nm_device_get_proxy_config(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->proxy_config; + return NM_DEVICE_GET_PRIVATE(self)->proxy_config; } static void -nm_device_set_proxy_config (NMDevice *self, const char *pac_url) +nm_device_set_proxy_config(NMDevice *self, const char *pac_url) { - NMDevicePrivate *priv; - NMConnection *connection; - NMSettingProxy *s_proxy = NULL; + NMDevicePrivate *priv; + NMConnection * connection; + NMSettingProxy * s_proxy = NULL; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - g_clear_object (&priv->proxy_config); - priv->proxy_config = nm_proxy_config_new (); + g_clear_object(&priv->proxy_config); + priv->proxy_config = nm_proxy_config_new(); - if (pac_url) { - nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); - nm_proxy_config_set_pac_url (priv->proxy_config, pac_url); - _LOGD (LOGD_PROXY, "proxy: PAC url \"%s\"", pac_url); - } else - nm_proxy_config_set_method (priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); + if (pac_url) { + nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); + nm_proxy_config_set_pac_url(priv->proxy_config, pac_url); + _LOGD(LOGD_PROXY, "proxy: PAC url \"%s\"", pac_url); + } else + nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); - connection = nm_device_get_applied_connection (self); - if (connection) - s_proxy = nm_connection_get_setting_proxy (connection); + connection = nm_device_get_applied_connection(self); + if (connection) + s_proxy = nm_connection_get_setting_proxy(connection); - if (s_proxy) - nm_proxy_config_merge_setting (priv->proxy_config, s_proxy); + if (s_proxy) + nm_proxy_config_merge_setting(priv->proxy_config, s_proxy); } /* IP Configuration stuff */ NMDhcpConfig * -nm_device_get_dhcp_config (NMDevice *self, int addr_family) +nm_device_get_dhcp_config(NMDevice *self, int addr_family) { - const gboolean IS_IPv4 = (addr_family == AF_INET); + const gboolean IS_IPv4 = (addr_family == AF_INET); - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - nm_assert_addr_family (addr_family); + nm_assert_addr_family(addr_family); - return NM_DEVICE_GET_PRIVATE (self)->dhcp_data_x[IS_IPv4].config; + return NM_DEVICE_GET_PRIVATE(self)->dhcp_data_x[IS_IPv4].config; } NMIP4Config * -nm_device_get_ip4_config (NMDevice *self) +nm_device_get_ip4_config(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->ip_config_4; + return NM_DEVICE_GET_PRIVATE(self)->ip_config_4; } static gboolean -nm_device_set_ip_config (NMDevice *self, - int addr_family, - NMIPConfig *new_config, - gboolean commit, - GPtrArray *ip4_dev_route_blacklist) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMIPConfig *old_config; - gboolean has_changes = FALSE; - gboolean success = TRUE; - NMSettingsConnection *settings_connection; - - nm_assert_addr_family (addr_family); - nm_assert (!new_config || nm_ip_config_get_addr_family (new_config) == addr_family); - nm_assert ( !new_config - || ( new_config - && ({ - int ip_ifindex = nm_device_get_ip_ifindex (self); - - ( ip_ifindex > 0 - && ip_ifindex == nm_ip_config_get_ifindex (new_config)); - }))); - nm_assert (IS_IPv4 || !ip4_dev_route_blacklist); - - _LOGD (LOGD_IP_from_af (addr_family), - "ip%c-config: update (commit=%d, new-config=%p)", - nm_utils_addr_family_to_char (addr_family), - commit, - new_config); - - /* Always commit to nm-platform to update lifetimes */ - if (commit && new_config) { - - _commit_mtu (self, - IS_IPv4 - ? NM_IP4_CONFIG (new_config) - : priv->ip_config_4); - - if (IS_IPv4) { - success = nm_ip4_config_commit (NM_IP4_CONFIG (new_config), - nm_device_get_platform (self), - _get_route_table_sync_mode_stateful (self, - AF_INET)); - nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), - nm_ip_config_get_ifindex (new_config), - ip4_dev_route_blacklist); - } else { - gs_unref_ptrarray GPtrArray *temporary_not_available = NULL; - - success = nm_ip6_config_commit (NM_IP6_CONFIG (new_config), - nm_device_get_platform (self), - _get_route_table_sync_mode_stateful (self, - AF_INET6), - &temporary_not_available); - - if (!_rt6_temporary_not_available_set (self, temporary_not_available)) - success = FALSE; - } - } - - old_config = priv->ip_config_x[IS_IPv4]; - - if (new_config && old_config) { - /* has_changes is set only on relevant changes, because when the configuration changes, - * this causes a re-read and reset. This should only happen for relevant changes */ - nm_ip_config_replace (old_config, new_config, &has_changes); - if (has_changes) { - _LOGD (LOGD_IP_from_af (addr_family), - "ip%c-config: update IP Config instance (%s)", - nm_utils_addr_family_to_char (addr_family), - nm_dbus_object_get_path (NM_DBUS_OBJECT (old_config))); - } - } else if (new_config /*&& !old_config*/) { - has_changes = TRUE; - priv->ip_config_x[IS_IPv4] = g_object_ref (new_config); - if (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (new_config))) - nm_dbus_object_export (NM_DBUS_OBJECT (new_config)); - - _LOGD (LOGD_IP_from_af (addr_family), - "ip%c-config: set IP Config instance (%s)", - nm_utils_addr_family_to_char (addr_family), - nm_dbus_object_get_path (NM_DBUS_OBJECT (new_config))); - } else if (old_config /*&& !new_config*/) { - has_changes = TRUE; - priv->ip_config_x[IS_IPv4] = NULL; - _LOGD (LOGD_IP_from_af (addr_family), - "ip%c-config: clear IP Config instance (%s)", - nm_utils_addr_family_to_char (addr_family), - nm_dbus_object_get_path (NM_DBUS_OBJECT (old_config))); - if (IS_IPv4) { - /* Device config is invalid if combined config is invalid */ - applied_config_clear (&priv->dev_ip_config_4); - } else - priv->needs_ip6_subnet = FALSE; - } - - if (has_changes) { - - if (IS_IPv4) - _update_ip4_address (self); - - if (old_config != priv->ip_config_x[IS_IPv4]) - _notify (self, IS_IPv4 ? PROP_IP4_CONFIG : PROP_IP6_CONFIG); - - g_signal_emit (self, - signals[IS_IPv4 ? IP4_CONFIG_CHANGED : IP6_CONFIG_CHANGED], - 0, - priv->ip_config_x[IS_IPv4], - old_config); - - if (old_config != priv->ip_config_x[IS_IPv4]) - nm_dbus_object_clear_and_unexport (&old_config); - - if ( nm_device_sys_iface_state_is_external (self) - && (settings_connection = nm_device_get_settings_connection (self)) - && NM_FLAGS_HAS (nm_settings_connection_get_flags (settings_connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL) - && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request.obj)) == NM_ACTIVATION_TYPE_EXTERNAL) { - gs_unref_object NMConnection *new_connection = NULL; - - new_connection = nm_simple_connection_new_clone (nm_settings_connection_get_connection (settings_connection)); - - nm_connection_add_setting (new_connection, - IS_IPv4 - ? nm_ip4_config_create_setting (priv->ip_config_4) - : nm_ip6_config_create_setting (priv->ip_config_6)); - - nm_settings_connection_update (settings_connection, - new_connection, - NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, - "update-external", - NULL); - } - - nm_device_queue_recheck_assume (self); - - if (!IS_IPv4) { - if (priv->ndisc) - ndisc_set_router_config (priv->ndisc, self); - } - } - - nm_assert (!old_config || old_config == priv->ip_config_x[IS_IPv4]); - - return success; +nm_device_set_ip_config(NMDevice * self, + int addr_family, + NMIPConfig *new_config, + gboolean commit, + GPtrArray * ip4_dev_route_blacklist) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); + NMIPConfig * old_config; + gboolean has_changes = FALSE; + gboolean success = TRUE; + NMSettingsConnection *settings_connection; + + nm_assert_addr_family(addr_family); + nm_assert(!new_config || nm_ip_config_get_addr_family(new_config) == addr_family); + nm_assert(!new_config + || (new_config && ({ + int ip_ifindex = nm_device_get_ip_ifindex(self); + + (ip_ifindex > 0 && ip_ifindex == nm_ip_config_get_ifindex(new_config)); + }))); + nm_assert(IS_IPv4 || !ip4_dev_route_blacklist); + + _LOGD(LOGD_IP_from_af(addr_family), + "ip%c-config: update (commit=%d, new-config=%p)", + nm_utils_addr_family_to_char(addr_family), + commit, + new_config); + + /* Always commit to nm-platform to update lifetimes */ + if (commit && new_config) { + _commit_mtu(self, IS_IPv4 ? NM_IP4_CONFIG(new_config) : priv->ip_config_4); + + if (IS_IPv4) { + success = nm_ip4_config_commit(NM_IP4_CONFIG(new_config), + nm_device_get_platform(self), + _get_route_table_sync_mode_stateful(self, AF_INET)); + nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), + nm_ip_config_get_ifindex(new_config), + ip4_dev_route_blacklist); + } else { + gs_unref_ptrarray GPtrArray *temporary_not_available = NULL; + + success = nm_ip6_config_commit(NM_IP6_CONFIG(new_config), + nm_device_get_platform(self), + _get_route_table_sync_mode_stateful(self, AF_INET6), + &temporary_not_available); + + if (!_rt6_temporary_not_available_set(self, temporary_not_available)) + success = FALSE; + } + } + + old_config = priv->ip_config_x[IS_IPv4]; + + if (new_config && old_config) { + /* has_changes is set only on relevant changes, because when the configuration changes, + * this causes a re-read and reset. This should only happen for relevant changes */ + nm_ip_config_replace(old_config, new_config, &has_changes); + if (has_changes) { + _LOGD(LOGD_IP_from_af(addr_family), + "ip%c-config: update IP Config instance (%s)", + nm_utils_addr_family_to_char(addr_family), + nm_dbus_object_get_path(NM_DBUS_OBJECT(old_config))); + } + } else if (new_config /*&& !old_config*/) { + has_changes = TRUE; + priv->ip_config_x[IS_IPv4] = g_object_ref(new_config); + if (!nm_dbus_object_is_exported(NM_DBUS_OBJECT(new_config))) + nm_dbus_object_export(NM_DBUS_OBJECT(new_config)); + + _LOGD(LOGD_IP_from_af(addr_family), + "ip%c-config: set IP Config instance (%s)", + nm_utils_addr_family_to_char(addr_family), + nm_dbus_object_get_path(NM_DBUS_OBJECT(new_config))); + } else if (old_config /*&& !new_config*/) { + has_changes = TRUE; + priv->ip_config_x[IS_IPv4] = NULL; + _LOGD(LOGD_IP_from_af(addr_family), + "ip%c-config: clear IP Config instance (%s)", + nm_utils_addr_family_to_char(addr_family), + nm_dbus_object_get_path(NM_DBUS_OBJECT(old_config))); + if (IS_IPv4) { + /* Device config is invalid if combined config is invalid */ + applied_config_clear(&priv->dev_ip_config_4); + } else + priv->needs_ip6_subnet = FALSE; + } + + if (has_changes) { + if (old_config != priv->ip_config_x[IS_IPv4]) + _notify(self, IS_IPv4 ? PROP_IP4_CONFIG : PROP_IP6_CONFIG); + + g_signal_emit(self, + signals[IS_IPv4 ? IP4_CONFIG_CHANGED : IP6_CONFIG_CHANGED], + 0, + priv->ip_config_x[IS_IPv4], + old_config); + + if (old_config != priv->ip_config_x[IS_IPv4]) + nm_dbus_object_clear_and_unexport(&old_config); + + if (nm_device_sys_iface_state_is_external(self) + && (settings_connection = nm_device_get_settings_connection(self)) + && NM_FLAGS_HAS(nm_settings_connection_get_flags(settings_connection), + NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL) + && nm_active_connection_get_activation_type(NM_ACTIVE_CONNECTION(priv->act_request.obj)) + == NM_ACTIVATION_TYPE_EXTERNAL) { + gs_unref_object NMConnection *new_connection = NULL; + + new_connection = nm_simple_connection_new_clone( + nm_settings_connection_get_connection(settings_connection)); + + nm_connection_add_setting( + new_connection, + IS_IPv4 ? nm_ip4_config_create_setting(priv->ip_config_4) + : nm_ip6_config_create_setting(priv->ip_config_6, + _get_maybe_ipv6_disabled(self))); + + nm_settings_connection_update(settings_connection, + new_connection, + NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, + "update-external", + NULL); + } + + nm_device_queue_recheck_assume(self); + + if (!IS_IPv4) { + if (priv->ndisc) + ndisc_set_router_config(priv->ndisc, self); + } + } + + nm_assert(!old_config || old_config == priv->ip_config_x[IS_IPv4]); + + return success; } static gboolean -_replace_vpn_config_in_list (GSList **plist, GObject *old, GObject *new) -{ - GSList *old_link; - - /* Below, assert that @new is not yet tracked, but still behave - * correctly in any case. Don't complain for missing @old since - * it could have been removed when the parent device became - * unmanaged. */ - - if ( old - && (old_link = g_slist_find (*plist, old))) { - if (old != new) { - if (new) - old_link->data = g_object_ref (new); - else - *plist = g_slist_delete_link (*plist, old_link); - g_object_unref (old); - } - return TRUE; - } - - if (new) { - if (!g_slist_find (*plist, new)) - *plist = g_slist_append (*plist, g_object_ref (new)); - else - g_return_val_if_reached (TRUE); - return TRUE; - } - - return FALSE; +_replace_vpn_config_in_list(GSList **plist, GObject *old, GObject *new) +{ + GSList *old_link; + + /* Below, assert that @new is not yet tracked, but still behave + * correctly in any case. Don't complain for missing @old since + * it could have been removed when the parent device became + * unmanaged. */ + + if (old && (old_link = g_slist_find(*plist, old))) { + if (old != new) { + if (new) + old_link->data = g_object_ref(new); + else + *plist = g_slist_delete_link(*plist, old_link); + g_object_unref(old); + } + return TRUE; + } + + if (new) { + if (!g_slist_find(*plist, new)) + *plist = g_slist_append(*plist, g_object_ref(new)); + else + g_return_val_if_reached(TRUE); + return TRUE; + } + + return FALSE; } void -nm_device_replace_vpn4_config (NMDevice *self, NMIP4Config *old, NMIP4Config *config) +nm_device_replace_vpn4_config(NMDevice *self, NMIP4Config *old, NMIP4Config *config) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert (!old || NM_IS_IP4_CONFIG (old)); - nm_assert (!config || NM_IS_IP4_CONFIG (config)); - nm_assert (!old || nm_ip4_config_get_ifindex (old) == nm_device_get_ip_ifindex (self)); - nm_assert (!config || nm_ip4_config_get_ifindex (config) == nm_device_get_ip_ifindex (self)); + nm_assert(!old || NM_IS_IP4_CONFIG(old)); + nm_assert(!config || NM_IS_IP4_CONFIG(config)); + nm_assert(!old || nm_ip4_config_get_ifindex(old) == nm_device_get_ip_ifindex(self)); + nm_assert(!config || nm_ip4_config_get_ifindex(config) == nm_device_get_ip_ifindex(self)); - if (!_replace_vpn_config_in_list (&priv->vpn_configs_4, (GObject *) old, (GObject *) config)) - return; + if (!_replace_vpn_config_in_list(&priv->vpn_configs_4, (GObject *) old, (GObject *) config)) + return; - /* NULL to use existing configs */ - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) - _LOGW (LOGD_IP4, "failed to set VPN routes for device"); + /* NULL to use existing configs */ + if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) + _LOGW(LOGD_IP4, "failed to set VPN routes for device"); } void -nm_device_set_dev2_ip_config (NMDevice *self, - int addr_family, - NMIPConfig *config) +nm_device_set_dev2_ip_config(NMDevice *self, int addr_family, NMIPConfig *config) { - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); + NMDevicePrivate *priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - g_return_if_fail ( !config - || nm_ip_config_get_addr_family (config) == addr_family); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); + g_return_if_fail(!config || nm_ip_config_get_addr_family(config) == addr_family); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - applied_config_init (&priv->dev2_ip_config_x[IS_IPv4], config); - if (!ip_config_merge_and_apply (self, addr_family, TRUE)) { - _LOGW (LOGD_IP, "failed to set extra device IPv%c configuration", - nm_utils_addr_family_to_char (addr_family)); - } + applied_config_init(&priv->dev2_ip_config_x[IS_IPv4], config); + if (!ip_config_merge_and_apply(self, addr_family, TRUE)) { + _LOGW(LOGD_IP, + "failed to set extra device IPv%c configuration", + nm_utils_addr_family_to_char(addr_family)); + } } void -nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *config) +nm_device_replace_vpn6_config(NMDevice *self, NMIP6Config *old, NMIP6Config *config) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert (!old || NM_IS_IP6_CONFIG (old)); - nm_assert (!config || NM_IS_IP6_CONFIG (config)); - nm_assert (!old || nm_ip6_config_get_ifindex (old) == nm_device_get_ip_ifindex (self)); - nm_assert (!config || nm_ip6_config_get_ifindex (config) == nm_device_get_ip_ifindex (self)); + nm_assert(!old || NM_IS_IP6_CONFIG(old)); + nm_assert(!config || NM_IS_IP6_CONFIG(config)); + nm_assert(!old || nm_ip6_config_get_ifindex(old) == nm_device_get_ip_ifindex(self)); + nm_assert(!config || nm_ip6_config_get_ifindex(config) == nm_device_get_ip_ifindex(self)); - if (!_replace_vpn_config_in_list (&priv->vpn_configs_6, (GObject *) old, (GObject *) config)) - return; + if (!_replace_vpn_config_in_list(&priv->vpn_configs_6, (GObject *) old, (GObject *) config)) + return; - /* NULL to use existing configs */ - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "failed to set VPN routes for device"); + /* NULL to use existing configs */ + if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) + _LOGW(LOGD_IP6, "failed to set VPN routes for device"); } NMIP6Config * -nm_device_get_ip6_config (NMDevice *self) +nm_device_get_ip6_config(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->ip_config_6; + return NM_DEVICE_GET_PRIVATE(self)->ip_config_6; } /*****************************************************************************/ static gboolean -dispatcher_cleanup (NMDevice *self) +dispatcher_cleanup(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!priv->dispatcher.call_id) - return FALSE; + if (!priv->dispatcher.call_id) + return FALSE; - nm_dispatcher_call_cancel (g_steal_pointer (&priv->dispatcher.call_id)); - priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - return TRUE; + nm_dispatcher_call_cancel(g_steal_pointer(&priv->dispatcher.call_id)); + priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; + priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; + return TRUE; } static void -dispatcher_complete_proceed_state (NMDispatcherCallId *call_id, gpointer user_data) +dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - g_return_if_fail (call_id == priv->dispatcher.call_id); + g_return_if_fail(call_id == priv->dispatcher.call_id); - priv->dispatcher.call_id = NULL; - nm_device_queue_state (self, - priv->dispatcher.post_state, - priv->dispatcher.post_state_reason); - priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; + priv->dispatcher.call_id = NULL; + nm_device_queue_state(self, priv->dispatcher.post_state, priv->dispatcher.post_state_reason); + priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; + priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; } /*****************************************************************************/ static void -ip_check_pre_up (NMDevice *self) +ip_check_pre_up(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (dispatcher_cleanup (self)) - nm_assert_not_reached (); + if (dispatcher_cleanup(self)) + nm_assert_not_reached(); - priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - if (!nm_dispatcher_call_device (NM_DISPATCHER_ACTION_PRE_UP, - self, - NULL, - dispatcher_complete_proceed_state, - self, - &priv->dispatcher.call_id)) { - /* Just proceed on errors */ - dispatcher_complete_proceed_state (0, self); - } + priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES; + priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; + if (!nm_dispatcher_call_device(NM_DISPATCHER_ACTION_PRE_UP, + self, + NULL, + dispatcher_complete_proceed_state, + self, + &priv->dispatcher.call_id)) { + /* Just proceed on errors */ + dispatcher_complete_proceed_state(0, self); + } } static void -ip_check_gw_ping_cleanup (NMDevice *self) +ip_check_gw_ping_cleanup(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_clear_g_source (&priv->gw_ping.watch); - nm_clear_g_source (&priv->gw_ping.timeout); + nm_clear_g_source(&priv->gw_ping.watch); + nm_clear_g_source(&priv->gw_ping.timeout); - if (priv->gw_ping.pid) { - nm_utils_kill_child_async (priv->gw_ping.pid, SIGTERM, priv->gw_ping.log_domain, "ping", 1000, NULL, NULL); - priv->gw_ping.pid = 0; - } + if (priv->gw_ping.pid) { + nm_utils_kill_child_async(priv->gw_ping.pid, + SIGTERM, + priv->gw_ping.log_domain, + "ping", + 1000, + NULL, + NULL); + priv->gw_ping.pid = 0; + } - nm_clear_g_free (&priv->gw_ping.binary); - nm_clear_g_free (&priv->gw_ping.address); + nm_clear_g_free(&priv->gw_ping.binary); + nm_clear_g_free(&priv->gw_ping.address); } static gboolean -spawn_ping (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gs_free char *str_timeout = NULL; - gs_free char *tmp_str = NULL; - const char *args[] = { priv->gw_ping.binary, "-I", nm_device_get_ip_iface (self), - "-c", "1", "-w", NULL, priv->gw_ping.address, NULL }; - gs_free_error GError *error = NULL; - gboolean ret; - - args[6] = str_timeout = g_strdup_printf ("%u", priv->gw_ping.deadline); - tmp_str = g_strjoinv (" ", (char **) args); - _LOGD (priv->gw_ping.log_domain, "ping: running '%s'", tmp_str); - - ret = g_spawn_async ("/", - (char **) args, - NULL, - G_SPAWN_DO_NOT_REAP_CHILD, - NULL, - NULL, - &priv->gw_ping.pid, - &error); - - if (!ret) { - _LOGW (priv->gw_ping.log_domain, "ping: could not spawn %s: %s", - priv->gw_ping.binary, error->message); - } - - return ret; +spawn_ping(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gs_free char * str_timeout = NULL; + gs_free char * tmp_str = NULL; + const char * args[] = {priv->gw_ping.binary, + "-I", + nm_device_get_ip_iface(self), + "-c", + "1", + "-w", + NULL, + priv->gw_ping.address, + NULL}; + gs_free_error GError *error = NULL; + gboolean ret; + + args[6] = str_timeout = g_strdup_printf("%u", priv->gw_ping.deadline); + tmp_str = g_strjoinv(" ", (char **) args); + _LOGD(priv->gw_ping.log_domain, "ping: running '%s'", tmp_str); + + ret = g_spawn_async("/", + (char **) args, + NULL, + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, + NULL, + &priv->gw_ping.pid, + &error); + + if (!ret) { + _LOGW(priv->gw_ping.log_domain, + "ping: could not spawn %s: %s", + priv->gw_ping.binary, + error->message); + } + + return ret; } static gboolean -respawn_ping_cb (gpointer user_data) +respawn_ping_cb(gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->gw_ping.watch = 0; + priv->gw_ping.watch = 0; - if (spawn_ping (self)) { - priv->gw_ping.watch = g_child_watch_add (priv->gw_ping.pid, - ip_check_ping_watch_cb, self); - } else { - ip_check_gw_ping_cleanup (self); - ip_check_pre_up (self); - } + if (spawn_ping(self)) { + priv->gw_ping.watch = g_child_watch_add(priv->gw_ping.pid, ip_check_ping_watch_cb, self); + } else { + ip_check_gw_ping_cleanup(self); + ip_check_pre_up(self); + } - return FALSE; + return FALSE; } static void -ip_check_ping_watch_cb (GPid pid, int status, gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMLogDomain log_domain = priv->gw_ping.log_domain; - gboolean success = FALSE; - - if (!priv->gw_ping.watch) - return; - priv->gw_ping.watch = 0; - priv->gw_ping.pid = 0; - - if (WIFEXITED (status)) { - if (WEXITSTATUS (status) == 0) { - _LOGD (log_domain, "ping: gateway ping succeeded"); - success = TRUE; - } else { - _LOGW (log_domain, "ping: gateway ping failed with error code %d", - WEXITSTATUS (status)); - } - } else - _LOGW (log_domain, "ping: stopped unexpectedly with status %d", status); - - if (success) { - /* We've got connectivity, proceed to pre_up */ - ip_check_gw_ping_cleanup (self); - ip_check_pre_up (self); - } else { - /* If ping exited with an error it may have returned early, - * wait 1 second and restart it */ - priv->gw_ping.watch = g_timeout_add_seconds (1, respawn_ping_cb, self); - } +ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data) +{ + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMLogDomain log_domain = priv->gw_ping.log_domain; + gboolean success = FALSE; + + if (!priv->gw_ping.watch) + return; + priv->gw_ping.watch = 0; + priv->gw_ping.pid = 0; + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == 0) { + _LOGD(log_domain, "ping: gateway ping succeeded"); + success = TRUE; + } else { + _LOGW(log_domain, "ping: gateway ping failed with error code %d", WEXITSTATUS(status)); + } + } else + _LOGW(log_domain, "ping: stopped unexpectedly with status %d", status); + + if (success) { + /* We've got connectivity, proceed to pre_up */ + ip_check_gw_ping_cleanup(self); + ip_check_pre_up(self); + } else { + /* If ping exited with an error it may have returned early, + * wait 1 second and restart it */ + priv->gw_ping.watch = g_timeout_add_seconds(1, respawn_ping_cb, self); + } } static gboolean -ip_check_ping_timeout_cb (gpointer user_data) +ip_check_ping_timeout_cb(gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->gw_ping.timeout = 0; + priv->gw_ping.timeout = 0; - _LOGW (priv->gw_ping.log_domain, "ping: gateway ping timed out"); + _LOGW(priv->gw_ping.log_domain, "ping: gateway ping timed out"); - ip_check_gw_ping_cleanup (self); - ip_check_pre_up (self); - return FALSE; + ip_check_gw_ping_cleanup(self); + ip_check_pre_up(self); + return FALSE; } static gboolean -start_ping (NMDevice *self, - NMLogDomain log_domain, - const char *binary, - const char *address, - guint timeout) +start_ping(NMDevice * self, + NMLogDomain log_domain, + const char *binary, + const char *address, + guint timeout) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - g_return_val_if_fail (priv->gw_ping.watch == 0, FALSE); - g_return_val_if_fail (priv->gw_ping.timeout == 0, FALSE); + g_return_val_if_fail(priv->gw_ping.watch == 0, FALSE); + g_return_val_if_fail(priv->gw_ping.timeout == 0, FALSE); - priv->gw_ping.log_domain = log_domain; - priv->gw_ping.address = g_strdup (address); - priv->gw_ping.binary = g_strdup (binary); - priv->gw_ping.deadline = timeout + 10; /* the proper termination is enforced by a timer */ + priv->gw_ping.log_domain = log_domain; + priv->gw_ping.address = g_strdup(address); + priv->gw_ping.binary = g_strdup(binary); + priv->gw_ping.deadline = timeout + 10; /* the proper termination is enforced by a timer */ - if (spawn_ping (self)) { - priv->gw_ping.watch = g_child_watch_add (priv->gw_ping.pid, ip_check_ping_watch_cb, self); - priv->gw_ping.timeout = g_timeout_add_seconds (timeout, ip_check_ping_timeout_cb, self); - return TRUE; - } + if (spawn_ping(self)) { + priv->gw_ping.watch = g_child_watch_add(priv->gw_ping.pid, ip_check_ping_watch_cb, self); + priv->gw_ping.timeout = g_timeout_add_seconds(timeout, ip_check_ping_timeout_cb, self); + return TRUE; + } - ip_check_gw_ping_cleanup (self); - return FALSE; + ip_check_gw_ping_cleanup(self); + return FALSE; } static void -nm_device_start_ip_check (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; - NMSettingConnection *s_con; - guint timeout = 0; - const char *ping_binary = NULL; - char buf[NM_UTILS_INET_ADDRSTRLEN]; - NMLogDomain log_domain = LOGD_IP4; - - /* Shouldn't be any active ping here, since IP_CHECK happens after the - * first IP method completes. Any subsequently completing IP method doesn't - * get checked. - */ - g_return_if_fail (!priv->gw_ping.watch); - g_return_if_fail (!priv->gw_ping.timeout); - g_return_if_fail (!priv->gw_ping.pid); - g_return_if_fail (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE || priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE); - - connection = nm_device_get_applied_connection (self); - g_assert (connection); - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - timeout = nm_setting_connection_get_gateway_ping_timeout (s_con); - - buf[0] = '\0'; - if (timeout) { - const NMPObject *gw; - - if (priv->ip_config_4 && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - gw = nm_ip4_config_best_default_route_get (priv->ip_config_4); - if (gw) { - _nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (gw)->gateway, buf); - ping_binary = nm_utils_find_helper ("ping", "/usr/bin/ping", NULL); - log_domain = LOGD_IP4; - } - } else if (priv->ip_config_6 && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { - gw = nm_ip6_config_best_default_route_get (priv->ip_config_6); - if (gw) { - _nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (gw)->gateway, buf); - ping_binary = nm_utils_find_helper ("ping6", "/usr/bin/ping6", NULL); - log_domain = LOGD_IP6; - } - } - } - - if (buf[0]) - start_ping (self, log_domain, ping_binary, buf, timeout); - - /* If no ping was started, just advance to pre_up */ - if (!priv->gw_ping.pid) - ip_check_pre_up (self); +nm_device_start_ip_check(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + NMSettingConnection *s_con; + guint timeout = 0; + const char * ping_binary = NULL; + char buf[NM_UTILS_INET_ADDRSTRLEN]; + NMLogDomain log_domain = LOGD_IP4; + + /* Shouldn't be any active ping here, since IP_CHECK happens after the + * first IP method completes. Any subsequently completing IP method doesn't + * get checked. + */ + g_return_if_fail(!priv->gw_ping.watch); + g_return_if_fail(!priv->gw_ping.timeout); + g_return_if_fail(!priv->gw_ping.pid); + g_return_if_fail(priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE + || priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE); + + connection = nm_device_get_applied_connection(self); + g_assert(connection); + + s_con = nm_connection_get_setting_connection(connection); + g_assert(s_con); + timeout = nm_setting_connection_get_gateway_ping_timeout(s_con); + + buf[0] = '\0'; + if (timeout) { + const NMPObject *gw; + + if (priv->ip_config_4 && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { + gw = nm_ip4_config_best_default_route_get(priv->ip_config_4); + if (gw) { + _nm_utils_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); + ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL); + log_domain = LOGD_IP4; + } + } else if (priv->ip_config_6 && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { + gw = nm_ip6_config_best_default_route_get(priv->ip_config_6); + if (gw) { + _nm_utils_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); + ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL); + log_domain = LOGD_IP6; + } + } + } + + if (buf[0]) + start_ping(self, log_domain, ping_binary, buf, timeout); + + /* If no ping was started, just advance to pre_up */ + if (!priv->gw_ping.pid) + ip_check_pre_up(self); } /*****************************************************************************/ static gboolean -carrier_wait_timeout (gpointer user_data) +carrier_wait_timeout(gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(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; + 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; } static gboolean -nm_device_is_up (NMDevice *self) +nm_device_is_up(NMDevice *self) { - int ifindex; + int ifindex; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - ifindex = nm_device_get_ip_ifindex (self); - return ifindex > 0 ? nm_platform_link_is_up (nm_device_get_platform (self), ifindex) : TRUE; + ifindex = nm_device_get_ip_ifindex(self); + return ifindex > 0 ? nm_platform_link_is_up(nm_device_get_platform(self), ifindex) : TRUE; } static gint64 -_get_carrier_wait_ms (NMDevice *self) +_get_carrier_wait_ms(NMDevice *self) { - gs_free char *value = NULL; + gs_free char *value = NULL; - value = nm_config_data_get_device_config (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, - self, - NULL); - return _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, CARRIER_WAIT_TIME_MS); + value = nm_config_data_get_device_config(NM_CONFIG_GET_DATA, + NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, + self, + NULL); + return _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXINT32, CARRIER_WAIT_TIME_MS); } gboolean -nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean device_is_up = FALSE; - NMDeviceCapabilities capabilities; - int ifindex; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - NM_SET_OUT (no_firmware, FALSE); - - if (!nm_device_get_enabled (self)) { - _LOGD (LOGD_PLATFORM, "bringing up device ignored due to disabled"); - return FALSE; - } - - ifindex = nm_device_get_ip_ifindex (self); - _LOGD (LOGD_PLATFORM, "bringing up device %d", ifindex); - if (ifindex <= 0) { - /* assume success. */ - } else { - if (!nm_platform_link_set_up (nm_device_get_platform (self), ifindex, no_firmware)) - return FALSE; - } - - /* Store carrier immediately. */ - nm_device_set_carrier_from_platform (self); - - device_is_up = nm_device_is_up (self); - if (block && !device_is_up) { - gint64 wait_until = nm_utils_get_monotonic_timestamp_usec () + 10000 /* microseconds */; - - do { - g_usleep (200); - if (!nm_platform_link_refresh (nm_device_get_platform (self), ifindex)) - return FALSE; - device_is_up = nm_device_is_up (self); - } while (!device_is_up && nm_utils_get_monotonic_timestamp_usec () < wait_until); - } - - if (!device_is_up) { - if (block) - _LOGW (LOGD_PLATFORM, "device not up after timeout!"); - else - _LOGD (LOGD_PLATFORM, "device not up immediately"); - return FALSE; - } - - /* some ethernet devices fail to report capabilities unless the device - * is up. Re-read the capabilities. */ - capabilities = 0; - if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) - capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); - _add_capabilities (self, capabilities); - - /* Devices that support carrier detect must be IFF_UP to report carrier - * changes; so after setting the device IFF_UP we must suppress startup - * complete (via a pending action) until either the carrier turns on, or - * a timeout is reached. - */ - if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { - gint64 now_ms, until_ms; - - /* 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); - - now_ms = nm_utils_get_monotonic_timestamp_msec (); - until_ms = NM_MAX (now_ms + _get_carrier_wait_ms (self), priv->carrier_wait_until_ms); - priv->carrier_wait_id = g_timeout_add (until_ms - now_ms, carrier_wait_timeout, self); - } - - /* Can only get HW address of some devices when they are up */ - nm_device_update_hw_address (self); - - _update_ip4_address (self); - - /* when the link comes up, we must restore IP configuration if necessary. */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) - _LOGW (LOGD_IP4, "failed applying IP4 config after bringing link up"); - } - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP6, "failed applying IP6 config after bringing link up"); - } - - return TRUE; +nm_device_bring_up(NMDevice *self, gboolean block, gboolean *no_firmware) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + gboolean device_is_up = FALSE; + NMDeviceCapabilities capabilities; + int ifindex; + + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + + NM_SET_OUT(no_firmware, FALSE); + + if (!nm_device_get_enabled(self)) { + _LOGD(LOGD_PLATFORM, "bringing up device ignored due to disabled"); + return FALSE; + } + + ifindex = nm_device_get_ip_ifindex(self); + _LOGD(LOGD_PLATFORM, "bringing up device %d", ifindex); + if (ifindex <= 0) { + /* assume success. */ + } else { + if (!nm_platform_link_set_up(nm_device_get_platform(self), ifindex, no_firmware)) + return FALSE; + } + + /* Store carrier immediately. */ + nm_device_set_carrier_from_platform(self); + + device_is_up = nm_device_is_up(self); + if (block && !device_is_up) { + gint64 wait_until = nm_utils_get_monotonic_timestamp_usec() + 10000 /* microseconds */; + + do { + g_usleep(200); + if (!nm_platform_link_refresh(nm_device_get_platform(self), ifindex)) + return FALSE; + device_is_up = nm_device_is_up(self); + } while (!device_is_up && nm_utils_get_monotonic_timestamp_usec() < wait_until); + } + + if (!device_is_up) { + if (block) + _LOGW(LOGD_PLATFORM, "device not up after timeout!"); + else + _LOGD(LOGD_PLATFORM, "device not up immediately"); + return FALSE; + } + + /* some ethernet devices fail to report capabilities unless the device + * is up. Re-read the capabilities. */ + capabilities = 0; + if (NM_DEVICE_GET_CLASS(self)->get_generic_capabilities) + capabilities |= NM_DEVICE_GET_CLASS(self)->get_generic_capabilities(self); + _add_capabilities(self, capabilities); + + /* Devices that support carrier detect must be IFF_UP to report carrier + * changes; so after setting the device IFF_UP we must suppress startup + * complete (via a pending action) until either the carrier turns on, or + * a timeout is reached. + */ + if (nm_device_has_capability(self, NM_DEVICE_CAP_CARRIER_DETECT)) { + gint64 now_ms, until_ms; + + /* 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); + + now_ms = nm_utils_get_monotonic_timestamp_msec(); + until_ms = NM_MAX(now_ms + _get_carrier_wait_ms(self), priv->carrier_wait_until_ms); + priv->carrier_wait_id = g_timeout_add(until_ms - now_ms, carrier_wait_timeout, self); + } + + /* Can only get HW address of some devices when they are up */ + nm_device_update_hw_address(self); + + /* when the link comes up, we must restore IP configuration if necessary. */ + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { + if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) + _LOGW(LOGD_IP4, "failed applying IP4 config after bringing link up"); + } + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { + if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) + _LOGW(LOGD_IP6, "failed applying IP6 config after bringing link up"); + } + + return TRUE; } void -nm_device_take_down (NMDevice *self, gboolean block) +nm_device_take_down(NMDevice *self, gboolean block) { - int ifindex; - gboolean device_is_up; + int ifindex; + gboolean device_is_up; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - ifindex = nm_device_get_ip_ifindex (self); - _LOGD (LOGD_PLATFORM, "taking down device %d", ifindex); - if (ifindex <= 0) { - /* devices without ifindex are always up. */ - return; - } + ifindex = nm_device_get_ip_ifindex(self); + _LOGD(LOGD_PLATFORM, "taking down device %d", ifindex); + if (ifindex <= 0) { + /* devices without ifindex are always up. */ + return; + } - if (!nm_platform_link_set_down (nm_device_get_platform (self), ifindex)) - return; + if (!nm_platform_link_set_down(nm_device_get_platform(self), ifindex)) + return; - device_is_up = nm_device_is_up (self); - if (block && device_is_up) { - gint64 wait_until = nm_utils_get_monotonic_timestamp_usec () + 10000 /* microseconds */; + device_is_up = nm_device_is_up(self); + if (block && device_is_up) { + gint64 wait_until = nm_utils_get_monotonic_timestamp_usec() + 10000 /* microseconds */; - do { - g_usleep (200); - if (!nm_platform_link_refresh (nm_device_get_platform (self), ifindex)) - return; - device_is_up = nm_device_is_up (self); - } while (device_is_up && nm_utils_get_monotonic_timestamp_usec () < wait_until); - } + do { + g_usleep(200); + if (!nm_platform_link_refresh(nm_device_get_platform(self), ifindex)) + return; + device_is_up = nm_device_is_up(self); + } while (device_is_up && nm_utils_get_monotonic_timestamp_usec() < wait_until); + } - if (device_is_up) { - if (block) - _LOGW (LOGD_PLATFORM, "device not down after timeout!"); - else - _LOGD (LOGD_PLATFORM, "device not down immediately"); - } + if (device_is_up) { + if (block) + _LOGW(LOGD_PLATFORM, "device not down after timeout!"); + else + _LOGD(LOGD_PLATFORM, "device not down immediately"); + } } void -nm_device_set_firmware_missing (NMDevice *self, gboolean new_missing) +nm_device_set_firmware_missing(NMDevice *self, gboolean new_missing) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->firmware_missing != new_missing) { - priv->firmware_missing = new_missing; - _notify (self, PROP_FIRMWARE_MISSING); - } + priv = NM_DEVICE_GET_PRIVATE(self); + if (priv->firmware_missing != new_missing) { + priv->firmware_missing = new_missing; + _notify(self, PROP_FIRMWARE_MISSING); + } } gboolean -nm_device_get_firmware_missing (NMDevice *self) +nm_device_get_firmware_missing(NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->firmware_missing; + return NM_DEVICE_GET_PRIVATE(self)->firmware_missing; } static void -intersect_ext_config (NMDevice *self, - AppliedConfig *config, - gboolean intersect_addresses, - gboolean intersect_routes) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMIPConfig *ext; - guint32 penalty; - int family; - - if (!config->orig) - return; - - family = nm_ip_config_get_addr_family (config->orig); - penalty = default_route_metric_penalty_get (self, family); - ext = family == AF_INET - ? (NMIPConfig *) priv->ext_ip_config_4 - : (NMIPConfig *) priv->ext_ip_config_6; - - if (config->current) { - nm_ip_config_intersect (config->current, - ext, - intersect_addresses, - intersect_routes, - penalty); - } else { - config->current = nm_ip_config_intersect_alloc (config->orig, - ext, - intersect_addresses, - intersect_routes, - penalty); - } +intersect_ext_config(NMDevice * self, + AppliedConfig *config, + gboolean intersect_addresses, + gboolean intersect_routes) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMIPConfig * ext; + guint32 penalty; + int family; + + if (!config->orig) + return; + + family = nm_ip_config_get_addr_family(config->orig); + penalty = default_route_metric_penalty_get(self, family); + ext = family == AF_INET ? (NMIPConfig *) priv->ext_ip_config_4 + : (NMIPConfig *) priv->ext_ip_config_6; + + if (config->current) { + nm_ip_config_intersect(config->current, + ext, + intersect_addresses, + intersect_routes, + penalty); + } else { + config->current = nm_ip_config_intersect_alloc(config->orig, + ext, + intersect_addresses, + intersect_routes, + penalty); + } } static gboolean -update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_configs) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - int ifindex; - GSList *iter; - gboolean is_up; - - nm_assert_addr_family (addr_family); - - ifindex = nm_device_get_ip_ifindex (self); - if (!ifindex) - return FALSE; - - is_up = nm_platform_link_is_up (nm_device_get_platform (self), ifindex); - - if (addr_family == AF_INET) { - - g_clear_object (&priv->ext_ip_config_4); - priv->ext_ip_config_4 = nm_ip4_config_capture (nm_device_get_multi_index (self), - nm_device_get_platform (self), - ifindex); - if (priv->ext_ip_config_4) { - if (intersect_configs) { - /* This function was called upon external changes. Remove the configuration - * (addresses,routes) that is no longer present externally from the internal - * config. This way, we don't re-add addresses that were manually removed - * by the user. */ - if (priv->con_ip_config_4) { - nm_ip4_config_intersect (priv->con_ip_config_4, priv->ext_ip_config_4, - TRUE, - is_up, - default_route_metric_penalty_get (self, AF_INET)); - } - - intersect_ext_config (self, &priv->dev_ip_config_4, TRUE, is_up); - intersect_ext_config (self, &priv->dev2_ip_config_4, TRUE, is_up); - - for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_intersect (iter->data, priv->ext_ip_config_4, TRUE, is_up, 0); - } - - /* Remove parts from ext_ip_config_4 to only contain the information that - * was configured externally -- we already have the same configuration from - * internal origins. */ - if (priv->con_ip_config_4) { - nm_ip4_config_subtract (priv->ext_ip_config_4, priv->con_ip_config_4, - default_route_metric_penalty_get (self, AF_INET)); - } - if (applied_config_get_current (&priv->dev_ip_config_4)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current (&priv->dev_ip_config_4), - default_route_metric_penalty_get (self, AF_INET)); - } - if (applied_config_get_current (&priv->dev2_ip_config_4)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current (&priv->dev2_ip_config_4), - default_route_metric_penalty_get (self, AF_INET)); - } - for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_subtract (priv->ext_ip_config_4, iter->data, 0); - } - - } else { - nm_assert (addr_family == AF_INET6); - - g_clear_object (&priv->ext_ip_config_6); - g_clear_object (&priv->ext_ip6_config_captured); - priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self), - nm_device_get_platform (self), - ifindex, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - if (priv->ext_ip6_config_captured) { - - priv->ext_ip_config_6 = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured); - - if (intersect_configs) { - /* This function was called upon external changes. Remove the configuration - * (addresses,routes) that is no longer present externally from the internal - * config. This way, we don't re-add addresses that were manually removed - * by the user. */ - if (priv->con_ip_config_6) { - nm_ip6_config_intersect (priv->con_ip_config_6, priv->ext_ip_config_6, - is_up, - is_up, - default_route_metric_penalty_get (self, AF_INET6)); - } - - intersect_ext_config (self, &priv->ac_ip6_config, is_up, is_up); - intersect_ext_config (self, &priv->dhcp6.ip6_config, is_up, is_up); - intersect_ext_config (self, &priv->dev2_ip_config_6, is_up, is_up); - - for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, is_up, is_up, 0); - - if ( is_up - && priv->ipv6ll_has - && !nm_ip6_config_lookup_address (priv->ext_ip_config_6, &priv->ipv6ll_addr)) - priv->ipv6ll_has = FALSE; - } - - /* Remove parts from ext_ip_config_6 to only contain the information that - * was configured externally -- we already have the same configuration from - * internal origins. */ - if (priv->con_ip_config_6) { - nm_ip6_config_subtract (priv->ext_ip_config_6, priv->con_ip_config_6, - default_route_metric_penalty_get (self, AF_INET6)); - } - if (applied_config_get_current (&priv->ac_ip6_config)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current (&priv->ac_ip6_config), - default_route_metric_penalty_get (self, AF_INET6)); - } - if (applied_config_get_current (&priv->dhcp6.ip6_config)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current (&priv->dhcp6.ip6_config), - default_route_metric_penalty_get (self, AF_INET6)); - } - if (applied_config_get_current (&priv->dev2_ip_config_6)) { - nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current (&priv->dev2_ip_config_6), - default_route_metric_penalty_get (self, AF_INET6)); - } - for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_subtract (priv->ext_ip_config_6, iter->data, 0); - } - } - - return TRUE; +update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + int ifindex; + GSList * iter; + gboolean is_up; + + nm_assert_addr_family(addr_family); + + ifindex = nm_device_get_ip_ifindex(self); + if (!ifindex) + return FALSE; + + is_up = nm_platform_link_is_up(nm_device_get_platform(self), ifindex); + + if (addr_family == AF_INET) { + g_clear_object(&priv->ext_ip_config_4); + priv->ext_ip_config_4 = nm_ip4_config_capture(nm_device_get_multi_index(self), + nm_device_get_platform(self), + ifindex); + if (priv->ext_ip_config_4) { + if (intersect_configs) { + /* This function was called upon external changes. Remove the configuration + * (addresses,routes) that is no longer present externally from the internal + * config. This way, we don't re-add addresses that were manually removed + * by the user. */ + if (priv->con_ip_config_4) { + nm_ip4_config_intersect(priv->con_ip_config_4, + priv->ext_ip_config_4, + TRUE, + is_up, + default_route_metric_penalty_get(self, AF_INET)); + } + + intersect_ext_config(self, &priv->dev_ip_config_4, TRUE, is_up); + intersect_ext_config(self, &priv->dev2_ip_config_4, TRUE, is_up); + + for (iter = priv->vpn_configs_4; iter; iter = iter->next) + nm_ip4_config_intersect(iter->data, priv->ext_ip_config_4, TRUE, is_up, 0); + } + + /* Remove parts from ext_ip_config_4 to only contain the information that + * was configured externally -- we already have the same configuration from + * internal origins. */ + if (priv->con_ip_config_4) { + nm_ip4_config_subtract(priv->ext_ip_config_4, + priv->con_ip_config_4, + default_route_metric_penalty_get(self, AF_INET)); + } + if (applied_config_get_current(&priv->dev_ip_config_4)) { + nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_4, + applied_config_get_current(&priv->dev_ip_config_4), + default_route_metric_penalty_get(self, AF_INET)); + } + if (applied_config_get_current(&priv->dev2_ip_config_4)) { + nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_4, + applied_config_get_current(&priv->dev2_ip_config_4), + default_route_metric_penalty_get(self, AF_INET)); + } + for (iter = priv->vpn_configs_4; iter; iter = iter->next) + nm_ip4_config_subtract(priv->ext_ip_config_4, iter->data, 0); + } + + } else { + nm_assert(addr_family == AF_INET6); + + g_clear_object(&priv->ext_ip_config_6); + g_clear_object(&priv->ext_ip6_config_captured); + priv->ext_ip6_config_captured = + nm_ip6_config_capture(nm_device_get_multi_index(self), + nm_device_get_platform(self), + ifindex, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + if (priv->ext_ip6_config_captured) { + priv->ext_ip_config_6 = nm_ip6_config_new_cloned(priv->ext_ip6_config_captured); + + if (intersect_configs) { + /* This function was called upon external changes. Remove the configuration + * (addresses,routes) that is no longer present externally from the internal + * config. This way, we don't re-add addresses that were manually removed + * by the user. */ + if (priv->con_ip_config_6) { + nm_ip6_config_intersect(priv->con_ip_config_6, + priv->ext_ip_config_6, + is_up, + is_up, + default_route_metric_penalty_get(self, AF_INET6)); + } + + intersect_ext_config(self, &priv->ac_ip6_config, is_up, is_up); + intersect_ext_config(self, &priv->dhcp6.ip6_config, is_up, is_up); + intersect_ext_config(self, &priv->dev2_ip_config_6, is_up, is_up); + + for (iter = priv->vpn_configs_6; iter; iter = iter->next) + nm_ip6_config_intersect(iter->data, priv->ext_ip_config_6, is_up, is_up, 0); + + if (is_up && priv->ipv6ll_has + && !nm_ip6_config_lookup_address(priv->ext_ip_config_6, &priv->ipv6ll_addr)) + priv->ipv6ll_has = FALSE; + } + + /* Remove parts from ext_ip_config_6 to only contain the information that + * was configured externally -- we already have the same configuration from + * internal origins. */ + if (priv->con_ip_config_6) { + nm_ip6_config_subtract(priv->ext_ip_config_6, + priv->con_ip_config_6, + default_route_metric_penalty_get(self, AF_INET6)); + } + if (applied_config_get_current(&priv->ac_ip6_config)) { + nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, + applied_config_get_current(&priv->ac_ip6_config), + default_route_metric_penalty_get(self, AF_INET6)); + } + if (applied_config_get_current(&priv->dhcp6.ip6_config)) { + nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, + applied_config_get_current(&priv->dhcp6.ip6_config), + default_route_metric_penalty_get(self, AF_INET6)); + } + if (applied_config_get_current(&priv->dev2_ip_config_6)) { + nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, + applied_config_get_current(&priv->dev2_ip_config_6), + default_route_metric_penalty_get(self, AF_INET6)); + } + for (iter = priv->vpn_configs_6; iter; iter = iter->next) + nm_ip6_config_subtract(priv->ext_ip_config_6, iter->data, 0); + } + } + + return TRUE; } static void -update_ip_config (NMDevice *self, int addr_family) +update_ip_config(NMDevice *self, int addr_family) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert_addr_family (addr_family); + nm_assert_addr_family(addr_family); - if (addr_family == AF_INET) - priv->update_ip_config_completed_v4 = TRUE; - else - priv->update_ip_config_completed_v6 = TRUE; + if (addr_family == AF_INET) + priv->update_ip_config_completed_v4 = TRUE; + else + priv->update_ip_config_completed_v6 = TRUE; - if (update_ext_ip_config (self, addr_family, TRUE)) { - if (addr_family == AF_INET) { - if (priv->ext_ip_config_4) - ip_config_merge_and_apply (self, AF_INET, FALSE); - } else { - if (priv->ext_ip6_config_captured) - ip_config_merge_and_apply (self, AF_INET6, FALSE); - } - } + if (update_ext_ip_config(self, addr_family, TRUE)) { + if (addr_family == AF_INET) { + if (priv->ext_ip_config_4) + ip_config_merge_and_apply(self, AF_INET, FALSE); + } else { + if (priv->ext_ip6_config_captured) + ip_config_merge_and_apply(self, AF_INET6, FALSE); + } + } } void -nm_device_capture_initial_config (NMDevice *self) +nm_device_capture_initial_config(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!priv->update_ip_config_completed_v4) - update_ip_config (self, AF_INET); - if (!priv->update_ip_config_completed_v6) - update_ip_config (self, AF_INET6); + if (!priv->update_ip_config_completed_v4) + update_ip_config(self, AF_INET); + if (!priv->update_ip_config_completed_v6) + update_ip_config(self, AF_INET6); } static gboolean -queued_ip_config_change (NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); - - priv = NM_DEVICE_GET_PRIVATE (self); - - /* Wait for any queued state changes */ - if (priv->queued_state.id) - return G_SOURCE_CONTINUE; - - /* If a commit is scheduled, this function would potentially interfere with - * it changing IP configurations before they are applied. Postpone the - * update in such case. - */ - if ( priv->activation_source_id_x[IS_IPv4] != 0 - && priv->activation_source_func_x[IS_IPv4] == activate_stage5_ip_config_result_x[IS_IPv4]) - return G_SOURCE_CONTINUE; - - priv->queued_ip_config_id_x[IS_IPv4] = 0; - - update_ip_config (self, addr_family); - - if (!IS_IPv4) { - /* Check whether we need to complete waiting for link-local. - * We are also called from an idle handler, so no problem doing state transitions - * now. */ - linklocal6_check_complete (self); - } - - if (!IS_IPv4) { - NMPlatform *platform; - GSList *dad6_failed_addrs, *iter; - const NMPlatformLink *pllink; - - dad6_failed_addrs = g_steal_pointer (&priv->dad6_failed_addrs); - - if ( priv->state > NM_DEVICE_STATE_DISCONNECTED - && priv->state < NM_DEVICE_STATE_DEACTIVATING - && priv->ifindex > 0 - && !nm_device_sys_iface_state_is_external (self) - && (platform = nm_device_get_platform (self)) - && (pllink = nm_platform_link_get (platform, priv->ifindex)) - && (pllink->n_ifi_flags & IFF_UP)) { - gboolean need_ipv6ll = FALSE; - NMNDiscConfigMap ndisc_config_changed = NM_NDISC_CONFIG_NONE; - - /* Handle DAD failures */ - for (iter = dad6_failed_addrs; iter; iter = iter->next) { - const NMPObject *obj = iter->data; - const NMPlatformIP6Address *addr; - - if (!nm_ndisc_dad_addr_is_fail_candidate (platform, obj)) - continue; - - addr = NMP_OBJECT_CAST_IP6_ADDRESS (obj); - - _LOGI (LOGD_IP6, "ipv6: duplicate address check failed for the %s address", - nm_platform_ip6_address_to_string (addr, NULL, 0)); - - if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) - need_ipv6ll = TRUE; - else if (priv->ndisc) - ndisc_config_changed |= nm_ndisc_dad_failed (priv->ndisc, &addr->address, FALSE); - } - - if (ndisc_config_changed != NM_NDISC_CONFIG_NONE) - nm_ndisc_emit_config_change (priv->ndisc, ndisc_config_changed); - - /* If no IPv6 link-local address exists but other addresses do then we - * must add the LL address to remain conformant with RFC 3513 chapter 2.1 - * ("Addressing Model"): "All interfaces are required to have at least - * one link-local unicast address". - */ - if ( priv->ip_config_6 - && nm_ip6_config_get_num_addresses (priv->ip_config_6)) - need_ipv6ll = TRUE; - if (need_ipv6ll) - check_and_add_ipv6ll_addr (self); - } - - g_slist_free_full (dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - } - - if (!IS_IPv4) { - /* Check if DAD is still pending */ - if ( priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF - && priv->dad6_ip6_config - && priv->ext_ip6_config_captured - && !nm_ip6_config_has_any_dad_pending (priv->ext_ip6_config_captured, - priv->dad6_ip6_config)) { - _LOGD (LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); - g_clear_object (&priv->dad6_ip6_config); - _set_ip_state (self, addr_family, NM_DEVICE_IP_STATE_DONE); - check_ip_state (self, FALSE, TRUE); - if (priv->rt6_temporary_not_available) - nm_device_activate_schedule_ip_config_result (self, AF_INET6, NULL); - } - } - - set_unmanaged_external_down (self, TRUE); - - return G_SOURCE_REMOVE; +queued_ip_config_change(NMDevice *self, int addr_family) +{ + NMDevicePrivate *priv; + const gboolean IS_IPv4 = (addr_family == AF_INET); + + g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); + + priv = NM_DEVICE_GET_PRIVATE(self); + + /* Wait for any queued state changes */ + if (priv->queued_state.id) + return G_SOURCE_CONTINUE; + + /* If a commit is scheduled, this function would potentially interfere with + * it changing IP configurations before they are applied. Postpone the + * update in such case. + */ + if (priv->activation_source_id_x[IS_IPv4] != 0 + && priv->activation_source_func_x[IS_IPv4] == activate_stage5_ip_config_result_x[IS_IPv4]) + return G_SOURCE_CONTINUE; + + priv->queued_ip_config_id_x[IS_IPv4] = 0; + + update_ip_config(self, addr_family); + + if (!IS_IPv4) { + /* Check whether we need to complete waiting for link-local. + * We are also called from an idle handler, so no problem doing state transitions + * now. */ + linklocal6_check_complete(self); + } + + if (!IS_IPv4) { + NMPlatform * platform; + GSList * dad6_failed_addrs, *iter; + const NMPlatformLink *pllink; + + dad6_failed_addrs = g_steal_pointer(&priv->dad6_failed_addrs); + + if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state < NM_DEVICE_STATE_DEACTIVATING + && priv->ifindex > 0 && !nm_device_sys_iface_state_is_external(self) + && (platform = nm_device_get_platform(self)) + && (pllink = nm_platform_link_get(platform, priv->ifindex)) + && (pllink->n_ifi_flags & IFF_UP)) { + gboolean need_ipv6ll = FALSE; + NMNDiscConfigMap ndisc_config_changed = NM_NDISC_CONFIG_NONE; + + /* Handle DAD failures */ + for (iter = dad6_failed_addrs; iter; iter = iter->next) { + const NMPObject * obj = iter->data; + const NMPlatformIP6Address *addr; + + if (!nm_ndisc_dad_addr_is_fail_candidate(platform, obj)) + continue; + + addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); + + _LOGI(LOGD_IP6, + "ipv6: duplicate address check failed for the %s address", + nm_platform_ip6_address_to_string(addr, NULL, 0)); + + if (IN6_IS_ADDR_LINKLOCAL(&addr->address)) + need_ipv6ll = TRUE; + else if (priv->ndisc) + ndisc_config_changed |= nm_ndisc_dad_failed(priv->ndisc, &addr->address, FALSE); + } + + if (ndisc_config_changed != NM_NDISC_CONFIG_NONE) + nm_ndisc_emit_config_change(priv->ndisc, ndisc_config_changed); + + /* If no IPv6 link-local address exists but other addresses do then we + * must add the LL address to remain conformant with RFC 3513 chapter 2.1 + * ("Addressing Model"): "All interfaces are required to have at least + * one link-local unicast address". + */ + if (priv->ip_config_6 && nm_ip6_config_get_num_addresses(priv->ip_config_6)) + need_ipv6ll = TRUE; + if (need_ipv6ll) + check_and_add_ipv6ll_addr(self); + } + + g_slist_free_full(dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); + } + + if (!IS_IPv4) { + /* Check if DAD is still pending */ + if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF && priv->dad6_ip6_config + && priv->ext_ip6_config_captured + && !nm_ip6_config_has_any_dad_pending(priv->ext_ip6_config_captured, + priv->dad6_ip6_config)) { + _LOGD(LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); + g_clear_object(&priv->dad6_ip6_config); + _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_DONE); + check_ip_state(self, FALSE, TRUE); + if (priv->rt6_temporary_not_available) + nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + } + } + + set_unmanaged_external_down(self, TRUE); + + return G_SOURCE_REMOVE; } static gboolean -queued_ip4_config_change (gpointer user_data) +queued_ip4_config_change(gpointer user_data) { - return queued_ip_config_change (user_data, AF_INET); + return queued_ip_config_change(user_data, AF_INET); } static gboolean -queued_ip6_config_change (gpointer user_data) +queued_ip6_config_change(gpointer user_data) { - return queued_ip_config_change (user_data, AF_INET6); + return queued_ip_config_change(user_data, AF_INET6); } static void -device_ipx_changed (NMPlatform *platform, - int obj_type_i, - int ifindex, - gconstpointer platform_object, - int change_type_i, - NMDevice *self) -{ - const NMPObjectType obj_type = obj_type_i; - const NMPlatformSignalChangeType change_type = change_type_i; - NMDevicePrivate *priv; - const NMPlatformIP6Address *addr; - - if (nm_device_get_ip_ifindex (self) != ifindex) - return; - - if (!nm_device_is_real (self)) - return; - - if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) { - /* ignore all platform signals until the link is initialized in platform. */ - return; - } - - priv = NM_DEVICE_GET_PRIVATE (self); - - switch (obj_type) { - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP4_ROUTE: - if (!priv->queued_ip_config_id_4) { - priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self); - _LOGD (LOGD_DEVICE, "queued IP4 config change"); - } - break; - case NMP_OBJECT_TYPE_IP6_ADDRESS: - addr = platform_object; - - if ( priv->state > NM_DEVICE_STATE_DISCONNECTED - && priv->state < NM_DEVICE_STATE_DEACTIVATING - && nm_ndisc_dad_addr_is_fail_candidate_event (change_type, addr)) { - priv->dad6_failed_addrs = g_slist_prepend (priv->dad6_failed_addrs, - (gpointer) nmp_object_ref (NMP_OBJECT_UP_CAST (addr))); - } - - /* fall-through */ - case NMP_OBJECT_TYPE_IP6_ROUTE: - if (!priv->queued_ip_config_id_6) { - priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self); - _LOGD (LOGD_DEVICE, "queued IP6 config change"); - } - break; - default: - g_return_if_reached (); - } +device_ipx_changed(NMPlatform * platform, + int obj_type_i, + int ifindex, + gconstpointer platform_object, + int change_type_i, + NMDevice * self) +{ + const NMPObjectType obj_type = obj_type_i; + const NMPlatformSignalChangeType change_type = change_type_i; + NMDevicePrivate * priv; + const NMPlatformIP6Address * addr; + + if (nm_device_get_ip_ifindex(self) != ifindex) + return; + + if (!nm_device_is_real(self)) + return; + + if (nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { + /* ignore all platform signals until the link is initialized in platform. */ + return; + } + + priv = NM_DEVICE_GET_PRIVATE(self); + + switch (obj_type) { + case NMP_OBJECT_TYPE_IP4_ADDRESS: + case NMP_OBJECT_TYPE_IP4_ROUTE: + if (!priv->queued_ip_config_id_4) { + priv->queued_ip_config_id_4 = g_idle_add(queued_ip4_config_change, self); + _LOGD(LOGD_DEVICE, "queued IP4 config change"); + } + break; + case NMP_OBJECT_TYPE_IP6_ADDRESS: + addr = platform_object; + + if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state < NM_DEVICE_STATE_DEACTIVATING + && nm_ndisc_dad_addr_is_fail_candidate_event(change_type, addr)) { + priv->dad6_failed_addrs = + g_slist_prepend(priv->dad6_failed_addrs, + (gpointer) nmp_object_ref(NMP_OBJECT_UP_CAST(addr))); + } + + /* fall-through */ + case NMP_OBJECT_TYPE_IP6_ROUTE: + if (!priv->queued_ip_config_id_6) { + priv->queued_ip_config_id_6 = g_idle_add(queued_ip6_config_change, self); + _LOGD(LOGD_DEVICE, "queued IP6 config change"); + } + break; + default: + g_return_if_reached(); + } } /*****************************************************************************/ -NM_UTILS_FLAGS2STR_DEFINE (nm_unmanaged_flags2str, NMUnmanagedFlags, - NM_UTILS_FLAGS2STR (NM_UNMANAGED_SLEEPING, "sleeping"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_QUITTING, "quitting"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_PARENT, "parent"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_BY_TYPE, "by-type"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_PLATFORM_INIT, "platform-init"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_EXPLICIT, "user-explicit"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_BY_DEFAULT, "by-default"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_SETTINGS, "user-settings"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_CONF, "user-conf"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_UDEV, "user-udev"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_EXTERNAL_DOWN, "external-down"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_IS_SLAVE, "is-slave"), -); +NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str, + NMUnmanagedFlags, + NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_PARENT, "parent"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_TYPE, "by-type"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_PLATFORM_INIT, "platform-init"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_EXPLICIT, "user-explicit"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_DEFAULT, "by-default"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_SETTINGS, "user-settings"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_CONF, "user-conf"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_UDEV, "user-udev"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_EXTERNAL_DOWN, "external-down"), + NM_UTILS_FLAGS2STR(NM_UNMANAGED_IS_SLAVE, "is-slave"), ); static const char * -_unmanaged_flags2str (NMUnmanagedFlags flags, NMUnmanagedFlags mask, char *buf, gsize len) +_unmanaged_flags2str(NMUnmanagedFlags flags, NMUnmanagedFlags mask, char *buf, gsize len) { - char buf2[512]; - char *b; - char *tmp, *tmp2; - gsize l; + char buf2[512]; + char *b; + char *tmp, *tmp2; + gsize l; - nm_utils_to_string_buffer_init (&buf, &len); - if (!len) - return buf; + nm_utils_to_string_buffer_init(&buf, &len); + if (!len) + return buf; - b = buf; + b = buf; - mask |= flags; + mask |= flags; - nm_unmanaged_flags2str (flags, b, len); - l = strlen (b); - b += l; - len -= l; + nm_unmanaged_flags2str(flags, b, len); + l = strlen(b); + b += l; + len -= l; - nm_unmanaged_flags2str (mask & ~flags, buf2, sizeof (buf2)); - if (buf2[0]) { - gboolean add_separator = l > 0; + nm_unmanaged_flags2str(mask & ~flags, buf2, sizeof(buf2)); + if (buf2[0]) { + gboolean add_separator = l > 0; - tmp = buf2; - while (TRUE) { - if (add_separator) - nm_utils_strbuf_append_c (&b, &len, ','); - add_separator = TRUE; + tmp = buf2; + while (TRUE) { + if (add_separator) + nm_utils_strbuf_append_c(&b, &len, ','); + add_separator = TRUE; - tmp2 = strchr (tmp, ','); - if (tmp2) - tmp2[0] = '\0'; + tmp2 = strchr(tmp, ','); + if (tmp2) + tmp2[0] = '\0'; - nm_utils_strbuf_append_c (&b, &len, '!'); - nm_utils_strbuf_append_str (&b, &len, tmp); - if (!tmp2) - break; + nm_utils_strbuf_append_c(&b, &len, '!'); + nm_utils_strbuf_append_str(&b, &len, tmp); + if (!tmp2) + break; - tmp = &tmp2[1]; - } - } + tmp = &tmp2[1]; + } + } - return buf; + return buf; } static gboolean _get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean for_user_request) { - /* Evaluate the managed state based on the unmanaged flags. - * - * Some flags are authoritative, meaning they always cause - * the device to be unmanaged (e.g. @NM_UNMANAGED_PLATFORM_INIT). - * - * OTOH, some flags can be overwritten. For example NM_UNMANAGED_USER_UDEV - * is ignored once NM_UNMANAGED_USER_EXPLICIT is set. The idea is that - * the flag from the configuration has no effect once the user explicitly - * touches the unmanaged flags. */ - - if (for_user_request) { - - /* @for_user_request can make the result only ~more~ managed. - * If the flags already indicate a managed state for a non-user-request, - * then it is also managed for an explicit user-request. - * - * Effectively, this check is redundant, as the code below already - * already ensures that. Still, express this invariant explicitly here. */ - if (_get_managed_by_flags (flags, mask, FALSE)) - return TRUE; - - /* A for-user-request, is effectively the same as pretending - * that user-explicit flag is cleared. */ - mask |= NM_UNMANAGED_USER_EXPLICIT; - flags &= ~NM_UNMANAGED_USER_EXPLICIT; - } - - if ( NM_FLAGS_ANY (mask, NM_UNMANAGED_USER_SETTINGS) - && !NM_FLAGS_ANY (flags, NM_UNMANAGED_USER_SETTINGS)) { - /* NM_UNMANAGED_USER_SETTINGS can only explicitly unmanage a device. It cannot - * *manage* it. Having NM_UNMANAGED_USER_SETTINGS explicitly not set, is the - * same as having it not set at all. */ - mask &= ~NM_UNMANAGED_USER_SETTINGS; - } - - if (NM_FLAGS_ANY (mask, NM_UNMANAGED_USER_UDEV)) { - /* configuration from udev or nm-config overwrites the by-default flag - * which is based on the device type. - * configuration from udev overwrites external-down */ - flags &= ~( NM_UNMANAGED_BY_DEFAULT - | NM_UNMANAGED_EXTERNAL_DOWN); - } - - if (NM_FLAGS_ANY (mask, NM_UNMANAGED_USER_CONF)) { - /* configuration from NetworkManager.conf overwrites the by-default flag - * which is based on the device type. - * It also overwrites the udev configuration and external-down */ - flags &= ~( NM_UNMANAGED_BY_DEFAULT - | NM_UNMANAGED_USER_UDEV - | NM_UNMANAGED_EXTERNAL_DOWN); - } - - if ( NM_FLAGS_HAS (mask, NM_UNMANAGED_IS_SLAVE) - && !NM_FLAGS_HAS (flags, NM_UNMANAGED_IS_SLAVE)) { - /* for an enslaved device, by-default doesn't matter */ - flags &= ~NM_UNMANAGED_BY_DEFAULT; - } - - if (NM_FLAGS_HAS (mask, NM_UNMANAGED_USER_EXPLICIT)) { - /* if the device is managed by user-decision, certain other flags - * are ignored. */ - flags &= ~( NM_UNMANAGED_BY_DEFAULT - | NM_UNMANAGED_USER_UDEV - | NM_UNMANAGED_USER_CONF - | NM_UNMANAGED_EXTERNAL_DOWN); - } - - return flags == NM_UNMANAGED_NONE; + /* Evaluate the managed state based on the unmanaged flags. + * + * Some flags are authoritative, meaning they always cause + * the device to be unmanaged (e.g. @NM_UNMANAGED_PLATFORM_INIT). + * + * OTOH, some flags can be overwritten. For example NM_UNMANAGED_USER_UDEV + * is ignored once NM_UNMANAGED_USER_EXPLICIT is set. The idea is that + * the flag from the configuration has no effect once the user explicitly + * touches the unmanaged flags. */ + + if (for_user_request) { + /* @for_user_request can make the result only ~more~ managed. + * If the flags already indicate a managed state for a non-user-request, + * then it is also managed for an explicit user-request. + * + * Effectively, this check is redundant, as the code below already + * already ensures that. Still, express this invariant explicitly here. */ + if (_get_managed_by_flags(flags, mask, FALSE)) + return TRUE; + + /* A for-user-request, is effectively the same as pretending + * that user-explicit flag is cleared. */ + mask |= NM_UNMANAGED_USER_EXPLICIT; + flags &= ~NM_UNMANAGED_USER_EXPLICIT; + } + + if (NM_FLAGS_ANY(mask, NM_UNMANAGED_USER_SETTINGS) + && !NM_FLAGS_ANY(flags, NM_UNMANAGED_USER_SETTINGS)) { + /* NM_UNMANAGED_USER_SETTINGS can only explicitly unmanage a device. It cannot + * *manage* it. Having NM_UNMANAGED_USER_SETTINGS explicitly not set, is the + * same as having it not set at all. */ + mask &= ~NM_UNMANAGED_USER_SETTINGS; + } + + if (NM_FLAGS_ANY(mask, NM_UNMANAGED_USER_UDEV)) { + /* configuration from udev or nm-config overwrites the by-default flag + * which is based on the device type. + * configuration from udev overwrites external-down */ + flags &= ~(NM_UNMANAGED_BY_DEFAULT | NM_UNMANAGED_EXTERNAL_DOWN); + } + + if (NM_FLAGS_ANY(mask, NM_UNMANAGED_USER_CONF)) { + /* configuration from NetworkManager.conf overwrites the by-default flag + * which is based on the device type. + * It also overwrites the udev configuration and external-down */ + flags &= ~(NM_UNMANAGED_BY_DEFAULT | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_EXTERNAL_DOWN); + } + + if (NM_FLAGS_HAS(mask, NM_UNMANAGED_IS_SLAVE) && !NM_FLAGS_HAS(flags, NM_UNMANAGED_IS_SLAVE)) { + /* for an enslaved device, by-default doesn't matter */ + flags &= ~NM_UNMANAGED_BY_DEFAULT; + } + + if (NM_FLAGS_HAS(mask, NM_UNMANAGED_USER_EXPLICIT)) { + /* if the device is managed by user-decision, certain other flags + * are ignored. */ + flags &= ~(NM_UNMANAGED_BY_DEFAULT | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_CONF + | NM_UNMANAGED_EXTERNAL_DOWN); + } + + return flags == NM_UNMANAGED_NONE; } /** @@ -14457,20 +14674,20 @@ _get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean fo * Returns: %TRUE if the device is unmanaged because of the flags. */ gboolean -nm_device_get_managed (NMDevice *self, gboolean for_user_request) +nm_device_get_managed(NMDevice *self, gboolean for_user_request) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - if (!nm_device_is_real (self)) { - /* a unrealized device is always considered unmanaged. */ - return FALSE; - } + if (!nm_device_is_real(self)) { + /* a unrealized device is always considered unmanaged. */ + return FALSE; + } - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - return _get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, for_user_request); + return _get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, for_user_request); } /** @@ -14483,12 +14700,12 @@ nm_device_get_managed (NMDevice *self, gboolean for_user_request) * Returns: the flags of the device ( & @flag) */ NMUnmanagedFlags -nm_device_get_unmanaged_mask (NMDevice *self, NMUnmanagedFlags flag) +nm_device_get_unmanaged_mask(NMDevice *self, NMUnmanagedFlags flag) { - g_return_val_if_fail (NM_IS_DEVICE (self), NM_UNMANAGED_NONE); - g_return_val_if_fail (flag != NM_UNMANAGED_NONE, NM_UNMANAGED_NONE); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_UNMANAGED_NONE); + g_return_val_if_fail(flag != NM_UNMANAGED_NONE, NM_UNMANAGED_NONE); - return NM_DEVICE_GET_PRIVATE (self)->unmanaged_mask & flag; + return NM_DEVICE_GET_PRIVATE(self)->unmanaged_mask & flag; } /** @@ -14501,12 +14718,12 @@ nm_device_get_unmanaged_mask (NMDevice *self, NMUnmanagedFlags flag) * Returns: the flags of the device ( & @flag) */ NMUnmanagedFlags -nm_device_get_unmanaged_flags (NMDevice *self, NMUnmanagedFlags flag) +nm_device_get_unmanaged_flags(NMDevice *self, NMUnmanagedFlags flag) { - g_return_val_if_fail (NM_IS_DEVICE (self), NM_UNMANAGED_NONE); - g_return_val_if_fail (flag != NM_UNMANAGED_NONE, NM_UNMANAGED_NONE); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_UNMANAGED_NONE); + g_return_val_if_fail(flag != NM_UNMANAGED_NONE, NM_UNMANAGED_NONE); - return NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags & flag; + return NM_DEVICE_GET_PRIVATE(self)->unmanaged_flags & flag; } /** @@ -14527,122 +14744,119 @@ nm_device_get_unmanaged_flags (NMDevice *self, NMUnmanagedFlags flag) * Set the unmanaged flags of the device. **/ static void -_set_unmanaged_flags (NMDevice *self, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op, - gboolean allow_state_transition, - gboolean now, - NMDeviceStateReason reason) -{ - NMDevicePrivate *priv; - gboolean was_managed, transition_state; - NMUnmanagedFlags old_flags, old_mask; - NMDeviceState new_state; - const char *operation = NULL; - char str1[512]; - char str2[512]; - gboolean do_notify_has_pending_actions = FALSE; - gboolean had_pending_actions = FALSE; - - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (flags); - - priv = NM_DEVICE_GET_PRIVATE (self); - - if (!priv->real) - allow_state_transition = FALSE; - was_managed = allow_state_transition && nm_device_get_managed (self, FALSE); - - if ( NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_PLATFORM_INIT) - && NM_FLAGS_HAS (flags, NM_UNMANAGED_PLATFORM_INIT) - && NM_IN_SET (set_op, NM_UNMAN_FLAG_OP_SET_MANAGED)) { - /* we are clearing the platform-init flags. This triggers additional actions. */ - if (!NM_FLAGS_HAS (flags, NM_UNMANAGED_USER_SETTINGS)) { - gboolean unmanaged; - - unmanaged = nm_device_spec_match_list (self, - nm_settings_get_unmanaged_specs (NM_DEVICE_GET_PRIVATE (self)->settings)); - nm_device_set_unmanaged_flags (self, - NM_UNMANAGED_USER_SETTINGS, - !!unmanaged); - } - - /* trigger an initial update of IP configuration. */ - nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_4)); - nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_6)); - priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self); - priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self); - - if (!priv->pending_actions) { - do_notify_has_pending_actions = TRUE; - had_pending_actions = nm_device_has_pending_action (self); - } - } - - old_flags = priv->unmanaged_flags; - old_mask = priv->unmanaged_mask; - - switch (set_op) { - case NM_UNMAN_FLAG_OP_FORGET: - priv->unmanaged_mask &= ~flags; - priv->unmanaged_flags &= ~flags; - operation = "forget"; - break; - case NM_UNMAN_FLAG_OP_SET_UNMANAGED: - priv->unmanaged_mask |= flags; - priv->unmanaged_flags |= flags; - operation = "set-unmanaged"; - break; - case NM_UNMAN_FLAG_OP_SET_MANAGED: - priv->unmanaged_mask |= flags; - priv->unmanaged_flags &= ~flags; - operation = "set-managed"; - break; - default: - g_return_if_reached (); - } - - if ( old_flags == priv->unmanaged_flags - && old_mask == priv->unmanaged_mask) - return; - - transition_state = allow_state_transition - && was_managed != nm_device_get_managed (self, FALSE) - && ( was_managed - || ( !was_managed - && nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)); - - _LOGD (LOGD_DEVICE, "unmanaged: flags set to [%s%s0x%0x/0x%x/%s%s], %s [%s=0x%0x]%s%s%s)", - _unmanaged_flags2str (priv->unmanaged_flags, priv->unmanaged_mask, str1, sizeof (str1)), \ - (priv->unmanaged_flags | priv->unmanaged_mask) ? "=" : "", \ - (guint) priv->unmanaged_flags, \ - (guint) priv->unmanaged_mask, \ - (_get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, FALSE) \ - ? "managed" \ - : (_get_managed_by_flags (priv->unmanaged_flags, priv->unmanaged_mask, TRUE) \ - ? "manageable" \ - : "unmanaged")), - priv->real ? "" : "/unrealized", - operation, - nm_unmanaged_flags2str (flags, str2, sizeof (str2)), - flags, - NM_PRINT_FMT_QUOTED (allow_state_transition, - ", reason ", - reason_to_string_a (reason), - transition_state ? ", transition-state" : "", - "")); - - if ( do_notify_has_pending_actions - && had_pending_actions != nm_device_has_pending_action (self)) - _notify (self, PROP_HAS_PENDING_ACTION); - - if (transition_state) { - new_state = was_managed ? NM_DEVICE_STATE_UNMANAGED : NM_DEVICE_STATE_UNAVAILABLE; - if (now) - nm_device_state_changed (self, new_state, reason); - else - nm_device_queue_state (self, new_state, reason); - } +_set_unmanaged_flags(NMDevice * self, + NMUnmanagedFlags flags, + NMUnmanFlagOp set_op, + gboolean allow_state_transition, + gboolean now, + NMDeviceStateReason reason) +{ + NMDevicePrivate *priv; + gboolean was_managed, transition_state; + NMUnmanagedFlags old_flags, old_mask; + NMDeviceState new_state; + const char * operation = NULL; + char str1[512]; + char str2[512]; + gboolean do_notify_has_pending_actions = FALSE; + gboolean had_pending_actions = FALSE; + + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(flags); + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (!priv->real) + allow_state_transition = FALSE; + was_managed = allow_state_transition && nm_device_get_managed(self, FALSE); + + if (NM_FLAGS_HAS(priv->unmanaged_flags, NM_UNMANAGED_PLATFORM_INIT) + && NM_FLAGS_HAS(flags, NM_UNMANAGED_PLATFORM_INIT) + && NM_IN_SET(set_op, NM_UNMAN_FLAG_OP_SET_MANAGED)) { + /* we are clearing the platform-init flags. This triggers additional actions. */ + if (!NM_FLAGS_HAS(flags, NM_UNMANAGED_USER_SETTINGS)) { + gboolean unmanaged; + + unmanaged = nm_device_spec_match_list( + self, + nm_settings_get_unmanaged_specs(NM_DEVICE_GET_PRIVATE(self)->settings)); + nm_device_set_unmanaged_flags(self, NM_UNMANAGED_USER_SETTINGS, !!unmanaged); + } + + /* trigger an initial update of IP configuration. */ + nm_assert_se(!nm_clear_g_source(&priv->queued_ip_config_id_4)); + nm_assert_se(!nm_clear_g_source(&priv->queued_ip_config_id_6)); + priv->queued_ip_config_id_4 = g_idle_add(queued_ip4_config_change, self); + priv->queued_ip_config_id_6 = g_idle_add(queued_ip6_config_change, self); + + if (!priv->pending_actions) { + do_notify_has_pending_actions = TRUE; + had_pending_actions = nm_device_has_pending_action(self); + } + } + + old_flags = priv->unmanaged_flags; + old_mask = priv->unmanaged_mask; + + switch (set_op) { + case NM_UNMAN_FLAG_OP_FORGET: + priv->unmanaged_mask &= ~flags; + priv->unmanaged_flags &= ~flags; + operation = "forget"; + break; + case NM_UNMAN_FLAG_OP_SET_UNMANAGED: + priv->unmanaged_mask |= flags; + priv->unmanaged_flags |= flags; + operation = "set-unmanaged"; + break; + case NM_UNMAN_FLAG_OP_SET_MANAGED: + priv->unmanaged_mask |= flags; + priv->unmanaged_flags &= ~flags; + operation = "set-managed"; + break; + default: + g_return_if_reached(); + } + + if (old_flags == priv->unmanaged_flags && old_mask == priv->unmanaged_mask) + return; + + transition_state = + allow_state_transition && was_managed != nm_device_get_managed(self, FALSE) + && (was_managed + || (!was_managed && nm_device_get_state(self) == NM_DEVICE_STATE_UNMANAGED)); + + _LOGD(LOGD_DEVICE, + "unmanaged: flags set to [%s%s0x%0x/0x%x/%s%s], %s [%s=0x%0x]%s%s%s)", + _unmanaged_flags2str(priv->unmanaged_flags, priv->unmanaged_mask, str1, sizeof(str1)), + (priv->unmanaged_flags | priv->unmanaged_mask) ? "=" : "", + (guint) priv->unmanaged_flags, + (guint) priv->unmanaged_mask, + (_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, FALSE) + ? "managed" + : (_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, TRUE) + ? "manageable" + : "unmanaged")), + priv->real ? "" : "/unrealized", + operation, + nm_unmanaged_flags2str(flags, str2, sizeof(str2)), + flags, + NM_PRINT_FMT_QUOTED(allow_state_transition, + ", reason ", + reason_to_string_a(reason), + transition_state ? ", transition-state" : "", + "")); + + if (do_notify_has_pending_actions && had_pending_actions != nm_device_has_pending_action(self)) + _notify(self, PROP_HAS_PENDING_ACTION); + + if (transition_state) { + new_state = was_managed ? NM_DEVICE_STATE_UNMANAGED : NM_DEVICE_STATE_UNAVAILABLE; + if (now) + nm_device_state_changed(self, new_state, reason); + else + nm_device_queue_state(self, new_state, reason); + } } /** @@ -14655,11 +14869,9 @@ _set_unmanaged_flags (NMDevice *self, * Set the unmanaged flags of the device (does not trigger a state change). **/ void -nm_device_set_unmanaged_flags (NMDevice *self, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op) +nm_device_set_unmanaged_flags(NMDevice *self, NMUnmanagedFlags flags, NMUnmanFlagOp set_op) { - _set_unmanaged_flags (self, flags, set_op, FALSE, FALSE, NM_DEVICE_STATE_REASON_NONE); + _set_unmanaged_flags(self, flags, set_op, FALSE, FALSE, NM_DEVICE_STATE_REASON_NONE); } /** @@ -14675,21 +14887,21 @@ nm_device_set_unmanaged_flags (NMDevice *self, * Set the unmanaged flags of the device and possibly trigger a state change. **/ void -nm_device_set_unmanaged_by_flags (NMDevice *self, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op, - NMDeviceStateReason reason) +nm_device_set_unmanaged_by_flags(NMDevice * self, + NMUnmanagedFlags flags, + NMUnmanFlagOp set_op, + NMDeviceStateReason reason) { - _set_unmanaged_flags (self, flags, set_op, TRUE, TRUE, reason); + _set_unmanaged_flags(self, flags, set_op, TRUE, TRUE, reason); } void -nm_device_set_unmanaged_by_flags_queue (NMDevice *self, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op, - NMDeviceStateReason reason) +nm_device_set_unmanaged_by_flags_queue(NMDevice * self, + NMUnmanagedFlags flags, + NMUnmanFlagOp set_op, + NMDeviceStateReason reason) { - _set_unmanaged_flags (self, flags, set_op, TRUE, FALSE, reason); + _set_unmanaged_flags(self, flags, set_op, TRUE, FALSE, reason); } /** @@ -14699,378 +14911,389 @@ nm_device_set_unmanaged_by_flags_queue (NMDevice *self, * or user configuration. */ gboolean -nm_device_check_unrealized_device_managed (NMDevice *self) +nm_device_check_unrealized_device_managed(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert (!nm_device_is_real (self)); + nm_assert(!nm_device_is_real(self)); - if (!nm_config_data_get_device_config_boolean (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, - self, - TRUE, - TRUE)) - return FALSE; + if (!nm_config_data_get_device_config_boolean(NM_CONFIG_GET_DATA, + NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, + self, + TRUE, + TRUE)) + return FALSE; - if (nm_device_spec_match_list (self, nm_settings_get_unmanaged_specs (priv->settings))) - return FALSE; + if (nm_device_spec_match_list(self, nm_settings_get_unmanaged_specs(priv->settings))) + return FALSE; - return TRUE; + return TRUE; } void -nm_device_set_unmanaged_by_user_settings (NMDevice *self) +nm_device_set_unmanaged_by_user_settings(NMDevice *self) { - gboolean unmanaged; + gboolean unmanaged; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) { - /* the device is already unmanaged due to platform-init. - * - * We want to delay evaluating the device spec, because it will freeze - * the permanent MAC address. That should not be done, before the platform - * link is fully initialized (via UDEV). - * - * Note that when clearing NM_UNMANAGED_PLATFORM_INIT, we will re-evaluate - * whether the device is unmanaged by user-settings. */ - return; - } + if (nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { + /* the device is already unmanaged due to platform-init. + * + * We want to delay evaluating the device spec, because it will freeze + * the permanent MAC address. That should not be done, before the platform + * link is fully initialized (via UDEV). + * + * Note that when clearing NM_UNMANAGED_PLATFORM_INIT, we will re-evaluate + * whether the device is unmanaged by user-settings. */ + return; + } - unmanaged = nm_device_spec_match_list (self, - nm_settings_get_unmanaged_specs (NM_DEVICE_GET_PRIVATE (self)->settings)); + unmanaged = nm_device_spec_match_list( + self, + nm_settings_get_unmanaged_specs(NM_DEVICE_GET_PRIVATE(self)->settings)); - nm_device_set_unmanaged_by_flags (self, - NM_UNMANAGED_USER_SETTINGS, - !!unmanaged, - unmanaged - ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED - : NM_DEVICE_STATE_REASON_NOW_MANAGED); + nm_device_set_unmanaged_by_flags(self, + NM_UNMANAGED_USER_SETTINGS, + !!unmanaged, + unmanaged ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED + : NM_DEVICE_STATE_REASON_NOW_MANAGED); } void -nm_device_set_unmanaged_by_user_udev (NMDevice *self) +nm_device_set_unmanaged_by_user_udev(NMDevice *self) { - int ifindex; - gboolean platform_unmanaged = FALSE; + int ifindex; + gboolean platform_unmanaged = FALSE; - ifindex = self->_priv->ifindex; + ifindex = self->_priv->ifindex; - if ( ifindex <= 0 - || !nm_platform_link_get_unmanaged (nm_device_get_platform (self), ifindex, &platform_unmanaged)) - return; + if (ifindex <= 0 + || !nm_platform_link_get_unmanaged(nm_device_get_platform(self), + ifindex, + &platform_unmanaged)) + return; - nm_device_set_unmanaged_by_flags (self, - NM_UNMANAGED_USER_UDEV, - platform_unmanaged, - NM_DEVICE_STATE_REASON_USER_REQUESTED); + nm_device_set_unmanaged_by_flags(self, + NM_UNMANAGED_USER_UDEV, + platform_unmanaged, + NM_DEVICE_STATE_REASON_USER_REQUESTED); } void -nm_device_set_unmanaged_by_user_conf (NMDevice *self) -{ - gboolean value; - NMUnmanFlagOp set_op; - - value = nm_config_data_get_device_config_boolean (NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, - self, - -1, - TRUE); - switch (value) { - case TRUE: - set_op = NM_UNMAN_FLAG_OP_SET_MANAGED; - break; - case FALSE: - set_op = NM_UNMAN_FLAG_OP_SET_UNMANAGED; - break; - default: - set_op = NM_UNMAN_FLAG_OP_FORGET; - break; - } - - nm_device_set_unmanaged_by_flags (self, - NM_UNMANAGED_USER_CONF, - set_op, - NM_DEVICE_STATE_REASON_USER_REQUESTED); +nm_device_set_unmanaged_by_user_conf(NMDevice *self) +{ + gboolean value; + NMUnmanFlagOp set_op; + + value = nm_config_data_get_device_config_boolean(NM_CONFIG_GET_DATA, + NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, + self, + -1, + TRUE); + switch (value) { + case TRUE: + set_op = NM_UNMAN_FLAG_OP_SET_MANAGED; + break; + case FALSE: + set_op = NM_UNMAN_FLAG_OP_SET_UNMANAGED; + break; + default: + set_op = NM_UNMAN_FLAG_OP_FORGET; + break; + } + + nm_device_set_unmanaged_by_flags(self, + NM_UNMANAGED_USER_CONF, + set_op, + NM_DEVICE_STATE_REASON_USER_REQUESTED); } void -nm_device_set_unmanaged_by_quitting (NMDevice *self) +nm_device_set_unmanaged_by_quitting(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean need_deactivate = nm_device_is_activating (self) || - priv->state == NM_DEVICE_STATE_ACTIVATED; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean need_deactivate = + nm_device_is_activating(self) || priv->state == NM_DEVICE_STATE_ACTIVATED; - /* It's OK to block here because we're quitting */ - if (need_deactivate) - _set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NOW_UNMANAGED, TRUE); + /* It's OK to block here because we're quitting */ + if (need_deactivate) + _set_state_full(self, + NM_DEVICE_STATE_DEACTIVATING, + NM_DEVICE_STATE_REASON_NOW_UNMANAGED, + TRUE); - nm_device_set_unmanaged_by_flags (self, - NM_UNMANAGED_QUITTING, - TRUE, - need_deactivate ? NM_DEVICE_STATE_REASON_REMOVED - : NM_DEVICE_STATE_REASON_NOW_UNMANAGED); + nm_device_set_unmanaged_by_flags(self, + NM_UNMANAGED_QUITTING, + TRUE, + need_deactivate ? NM_DEVICE_STATE_REASON_REMOVED + : NM_DEVICE_STATE_REASON_NOW_UNMANAGED); } /*****************************************************************************/ void -nm_device_set_dhcp_anycast_address (NMDevice *self, const char *addr) +nm_device_set_dhcp_anycast_address(NMDevice *self, const char *addr) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (!addr || nm_utils_hwaddr_valid (addr, ETH_ALEN)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(!addr || nm_utils_hwaddr_valid(addr, ETH_ALEN)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - g_free (priv->dhcp_anycast_address); - priv->dhcp_anycast_address = g_strdup (addr); + g_free(priv->dhcp_anycast_address); + priv->dhcp_anycast_address = g_strdup(addr); } void -nm_device_reapply_settings_immediately (NMDevice *self) +nm_device_reapply_settings_immediately(NMDevice *self) { - NMConnection *applied_connection; - NMSettingsConnection *settings_connection; - NMDeviceState state; - NMSettingConnection *s_con_settings; - NMSettingConnection *s_con_applied; - const char *zone; - NMMetered metered; - guint64 version_id; - - g_return_if_fail (NM_IS_DEVICE (self)); - - state = nm_device_get_state (self); - if ( state <= NM_DEVICE_STATE_DISCONNECTED - || state > NM_DEVICE_STATE_ACTIVATED) - return; + NMConnection * applied_connection; + NMSettingsConnection *settings_connection; + NMDeviceState state; + NMSettingConnection * s_con_settings; + NMSettingConnection * s_con_applied; + const char * zone; + NMMetered metered; + guint64 version_id; - applied_connection = nm_device_get_applied_connection (self); - settings_connection = nm_device_get_settings_connection (self); + g_return_if_fail(NM_IS_DEVICE(self)); - if (!nm_settings_connection_has_unmodified_applied_connection (settings_connection, - applied_connection, - NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)) - return; + state = nm_device_get_state(self); + if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_ACTIVATED) + return; - s_con_settings = nm_connection_get_setting_connection (nm_settings_connection_get_connection (settings_connection)); - s_con_applied = nm_connection_get_setting_connection (applied_connection); + applied_connection = nm_device_get_applied_connection(self); + settings_connection = nm_device_get_settings_connection(self); - if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)), - nm_setting_connection_get_zone (s_con_applied)) != 0) { + if (!nm_settings_connection_has_unmodified_applied_connection( + settings_connection, + applied_connection, + NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)) + return; - version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request.obj); - _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s (version-id %llu)", NM_PRINT_FMT_QUOTE_STRING (zone), (unsigned long long) version_id); + s_con_settings = nm_connection_get_setting_connection( + nm_settings_connection_get_connection(settings_connection)); + s_con_applied = nm_connection_get_setting_connection(applied_connection); - g_object_set (G_OBJECT (s_con_applied), - NM_SETTING_CONNECTION_ZONE, zone, - NULL); + if (!nm_streq0((zone = nm_setting_connection_get_zone(s_con_settings)), + nm_setting_connection_get_zone(s_con_applied))) { + version_id = nm_active_connection_version_id_bump( + (NMActiveConnection *) self->_priv->act_request.obj); + _LOGD(LOGD_DEVICE, + "reapply setting: zone = %s%s%s (version-id %llu)", + NM_PRINT_FMT_QUOTE_STRING(zone), + (unsigned long long) version_id); - nm_device_update_firewall_zone (self); - } + g_object_set(G_OBJECT(s_con_applied), NM_SETTING_CONNECTION_ZONE, zone, NULL); - if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) { + nm_device_update_firewall_zone(self); + } - version_id = nm_active_connection_version_id_bump ((NMActiveConnection *) self->_priv->act_request.obj); - _LOGD (LOGD_DEVICE, "reapply setting: metered = %d (version-id %llu)", (int) metered, (unsigned long long) version_id); + if ((metered = nm_setting_connection_get_metered(s_con_settings)) + != nm_setting_connection_get_metered(s_con_applied)) { + version_id = nm_active_connection_version_id_bump( + (NMActiveConnection *) self->_priv->act_request.obj); + _LOGD(LOGD_DEVICE, + "reapply setting: metered = %d (version-id %llu)", + (int) metered, + (unsigned long long) version_id); - g_object_set (G_OBJECT (s_con_applied), - NM_SETTING_CONNECTION_METERED, metered, - NULL); + g_object_set(G_OBJECT(s_con_applied), NM_SETTING_CONNECTION_METERED, metered, NULL); - nm_device_update_metered (self); - } + nm_device_update_metered(self); + } } void -nm_device_update_firewall_zone (NMDevice *self) +nm_device_update_firewall_zone(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if ( priv->fw_state >= FIREWALL_STATE_INITIALIZED - && !nm_device_sys_iface_state_is_external (self)) - fw_change_zone (self); + if (priv->fw_state >= FIREWALL_STATE_INITIALIZED + && !nm_device_sys_iface_state_is_external(self)) + fw_change_zone(self); } void -nm_device_update_metered (NMDevice *self) +nm_device_update_metered(NMDevice *self) { #define NM_METERED_INVALID ((NMMetered) -1) - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMSettingConnection *setting; - NMMetered conn_value, value = NM_METERED_INVALID; - NMConnection *connection = NULL; - NMDeviceState state; - - g_return_if_fail (NM_IS_DEVICE (self)); - - state = nm_device_get_state (self); - if ( state <= NM_DEVICE_STATE_DISCONNECTED - || state > NM_DEVICE_STATE_ACTIVATED) - value = NM_METERED_UNKNOWN; - - if (value == NM_METERED_INVALID) { - connection = nm_device_get_applied_connection (self); - if (connection) { - setting = nm_connection_get_setting_connection (connection); - if (setting) { - conn_value = nm_setting_connection_get_metered (setting); - if (conn_value != NM_METERED_UNKNOWN) - value = conn_value; - } - } - } - - if ( value == NM_METERED_INVALID - && NM_DEVICE_GET_CLASS (self)->get_guessed_metered - && NM_DEVICE_GET_CLASS (self)->get_guessed_metered (self)) - value = NM_METERED_GUESS_YES; - - /* Try to guess a value using the metered flag in IP configuration */ - if (value == NM_METERED_INVALID) { - if ( priv->ip_config_4 - && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - && nm_ip4_config_get_metered (priv->ip_config_4)) - value = NM_METERED_GUESS_YES; - } - - /* Otherwise look at connection type. For Bluetooth, we look at the type of - * Bluetooth sharing: for PANU/DUN (where we are receiving internet from - * another device) we set GUESS_YES; for NAP (where we are sharing internet - * to another device) we set GUESS_NO. We ignore WiMAX here as it’s no - * longer supported by NetworkManager. */ - if ( value == NM_METERED_INVALID - && nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { - - if (_nm_connection_get_setting_bluetooth_for_nap (connection)) { - /* NAP types are not metered, but other types are. */ - value = NM_METERED_GUESS_NO; - } else - value = NM_METERED_GUESS_YES; - } - - if (value == NM_METERED_INVALID) { - if ( nm_connection_is_type (connection, NM_SETTING_GSM_SETTING_NAME) - || nm_connection_is_type (connection, NM_SETTING_CDMA_SETTING_NAME)) - value = NM_METERED_GUESS_YES; - else - value = NM_METERED_GUESS_NO; - } - - if (value != priv->metered) { - _LOGD (LOGD_DEVICE, "set metered value %d", value); - priv->metered = value; - _notify (self, PROP_METERED); - } + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingConnection *setting; + NMMetered conn_value, value = NM_METERED_INVALID; + NMConnection * connection = NULL; + NMDeviceState state; + + g_return_if_fail(NM_IS_DEVICE(self)); + + state = nm_device_get_state(self); + if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_ACTIVATED) + value = NM_METERED_UNKNOWN; + + if (value == NM_METERED_INVALID) { + connection = nm_device_get_applied_connection(self); + if (connection) { + setting = nm_connection_get_setting_connection(connection); + if (setting) { + conn_value = nm_setting_connection_get_metered(setting); + if (conn_value != NM_METERED_UNKNOWN) + value = conn_value; + } + } + } + + if (value == NM_METERED_INVALID && NM_DEVICE_GET_CLASS(self)->get_guessed_metered + && NM_DEVICE_GET_CLASS(self)->get_guessed_metered(self)) + value = NM_METERED_GUESS_YES; + + /* Try to guess a value using the metered flag in IP configuration */ + if (value == NM_METERED_INVALID) { + if (priv->ip_config_4 && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE + && nm_ip4_config_get_metered(priv->ip_config_4)) + value = NM_METERED_GUESS_YES; + } + + /* Otherwise, look at connection type. For Bluetooth, we look at the type of + * Bluetooth sharing: for PANU/DUN (where we are receiving internet from + * another device) we set GUESS_YES; for NAP (where we are sharing internet + * to another device) we set GUESS_NO. We ignore WiMAX here as it’s no + * longer supported by NetworkManager. */ + if (value == NM_METERED_INVALID + && nm_connection_is_type(connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { + if (_nm_connection_get_setting_bluetooth_for_nap(connection)) { + /* NAP types are not metered, but other types are. */ + value = NM_METERED_GUESS_NO; + } else + value = NM_METERED_GUESS_YES; + } + + if (value == NM_METERED_INVALID) { + if (nm_connection_is_type(connection, NM_SETTING_GSM_SETTING_NAME) + || nm_connection_is_type(connection, NM_SETTING_CDMA_SETTING_NAME)) + value = NM_METERED_GUESS_YES; + else + value = NM_METERED_GUESS_NO; + } + + if (value != priv->metered) { + _LOGD(LOGD_DEVICE, "set metered value %d", value); + priv->metered = value; + _notify(self, PROP_METERED); + } } static NMDeviceCheckDevAvailableFlags -_device_check_dev_available_flags_from_con (NMDeviceCheckConAvailableFlags con_flags) +_device_check_dev_available_flags_from_con(NMDeviceCheckConAvailableFlags con_flags) { - NMDeviceCheckDevAvailableFlags dev_flags; + NMDeviceCheckDevAvailableFlags dev_flags; - dev_flags = NM_DEVICE_CHECK_DEV_AVAILABLE_NONE; + dev_flags = NM_DEVICE_CHECK_DEV_AVAILABLE_NONE; - if (NM_FLAGS_HAS (con_flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)) - dev_flags |= _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER; + if (NM_FLAGS_HAS(con_flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)) + dev_flags |= _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER; - return dev_flags; + return dev_flags; } static gboolean -_nm_device_check_connection_available (NMDevice *self, - NMConnection *connection, - NMDeviceCheckConAvailableFlags flags, - const char *specific_object, - GError **error) -{ - NMDeviceState state; - GError *local = NULL; - - /* an unrealized software device is always available, hardware devices never. */ - if (!nm_device_is_real (self)) { - if (nm_device_is_software (self)) { - if (!nm_device_check_connection_compatible (self, connection, - error ? &local : NULL)) { - if (error) { - g_return_val_if_fail (local, FALSE); - nm_utils_error_set (error, - local->domain == NM_UTILS_ERROR - ? local->code - : NM_UTILS_ERROR_UNKNOWN, - "profile is not compatible with software device (%s)", - local->message); - g_error_free (local); - } - return FALSE; - } - return TRUE; - } - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "hardware device is not realized"); - return FALSE; - } - - state = nm_device_get_state (self); - if (state < NM_DEVICE_STATE_UNMANAGED) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "device is in unknown state"); - return FALSE; - } - if (state < NM_DEVICE_STATE_UNAVAILABLE) { - if (nm_device_get_managed (self, FALSE)) { - /* device is managed, both for user-requests and non-user-requests alike. */ - } else { - if (!nm_device_get_managed (self, TRUE)) { - /* device is strictly unmanaged by authoritative unmanaged reasons. */ - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "device is strictly unmanaged"); - return FALSE; - } - if (!NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED)) { - /* device could be managed for an explict user-request, but this is not such a request. */ - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "device is currently unmanaged"); - return FALSE; - } - } - } - if ( state < NM_DEVICE_STATE_DISCONNECTED - && !nm_device_is_software (self)) { - if (!nm_device_is_available (self, _device_check_dev_available_flags_from_con (flags))) { - if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)) { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device is not available"); - } else { - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device is not available for internal request"); - } - return FALSE; - } - } - - if (!nm_device_check_connection_compatible (self, connection, - error ? &local : NULL)) { - if (error) { - nm_utils_error_set (error, - local->domain == NM_UTILS_ERROR - ? local->code - : NM_UTILS_ERROR_UNKNOWN, - "profile is not compatible with device (%s)", - local->message); - g_error_free (local); - } - return FALSE; - } - - return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object, error); +_nm_device_check_connection_available(NMDevice * self, + NMConnection * connection, + NMDeviceCheckConAvailableFlags flags, + const char * specific_object, + GError ** error) +{ + NMDeviceState state; + GError * local = NULL; + + /* an unrealized software device is always available, hardware devices never. */ + if (!nm_device_is_real(self)) { + if (nm_device_is_software(self)) { + if (!nm_device_check_connection_compatible(self, connection, error ? &local : NULL)) { + if (error) { + g_return_val_if_fail(local, FALSE); + nm_utils_error_set(error, + local->domain == NM_UTILS_ERROR ? local->code + : NM_UTILS_ERROR_UNKNOWN, + "profile is not compatible with software device (%s)", + local->message); + g_error_free(local); + } + return FALSE; + } + return TRUE; + } + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "hardware device is not realized"); + return FALSE; + } + + state = nm_device_get_state(self); + if (state < NM_DEVICE_STATE_UNMANAGED) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is in unknown state"); + return FALSE; + } + if (state < NM_DEVICE_STATE_UNAVAILABLE) { + if (nm_device_get_managed(self, FALSE)) { + /* device is managed, both for user-requests and non-user-requests alike. */ + } else { + if (!nm_device_get_managed(self, TRUE)) { + /* device is strictly unmanaged by authoritative unmanaged reasons. */ + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is strictly unmanaged"); + return FALSE; + } + if (!NM_FLAGS_HAS(flags, + _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED)) { + /* device could be managed for an explict user-request, but this is not such a request. */ + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is currently unmanaged"); + return FALSE; + } + } + } + if (state < NM_DEVICE_STATE_DISCONNECTED && !nm_device_is_software(self)) { + if (!nm_device_is_available(self, _device_check_dev_available_flags_from_con(flags))) { + if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device is not available"); + } else { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device is not available for internal request"); + } + return FALSE; + } + } + + if (!nm_device_check_connection_compatible(self, connection, error ? &local : NULL)) { + if (error) { + nm_utils_error_set(error, + local->domain == NM_UTILS_ERROR ? local->code + : NM_UTILS_ERROR_UNKNOWN, + "profile is not compatible with device (%s)", + local->message); + g_error_free(local); + } + return FALSE; + } + + return NM_DEVICE_GET_CLASS(self)->check_connection_available(self, + connection, + flags, + specific_object, + error); } /** @@ -15090,147 +15313,148 @@ _nm_device_check_connection_available (NMDevice *self, * Returns: %TRUE if @connection can be activated on @self */ gboolean -nm_device_check_connection_available (NMDevice *self, - NMConnection *connection, - NMDeviceCheckConAvailableFlags flags, - const char *specific_object, - GError **error) +nm_device_check_connection_available(NMDevice * self, + NMConnection * connection, + NMDeviceCheckConAvailableFlags flags, + const char * specific_object, + GError ** error) { - gboolean available; + gboolean available; - available = _nm_device_check_connection_available (self, connection, flags, specific_object, error); + available = + _nm_device_check_connection_available(self, connection, flags, specific_object, error); #if NM_MORE_ASSERTS >= 2 - { - /* The meaning of the flags is so that *adding* a flag relaxes a condition, thus making - * the device *more* available. Assert against that requirement by testing all the flags. */ - NMDeviceCheckConAvailableFlags i, j, k; - gboolean available_all[NM_DEVICE_CHECK_CON_AVAILABLE_ALL + 1] = { FALSE }; - - for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) - available_all[i] = _nm_device_check_connection_available (self, connection, i, specific_object, NULL); - - for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) { - for (j = 1; j <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; j <<= 1) { - if (NM_FLAGS_ANY (i, j)) { - k = i & ~j; - nm_assert ( available_all[i] == available_all[k] - || available_all[i]); - } - } - } - } + { + /* The meaning of the flags is so that *adding* a flag relaxes a condition, thus making + * the device *more* available. Assert against that requirement by testing all the flags. */ + NMDeviceCheckConAvailableFlags i, j, k; + gboolean available_all[NM_DEVICE_CHECK_CON_AVAILABLE_ALL + 1] = {FALSE}; + + for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) + available_all[i] = + _nm_device_check_connection_available(self, connection, i, specific_object, NULL); + + for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) { + for (j = 1; j <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; j <<= 1) { + if (NM_FLAGS_ANY(i, j)) { + k = i & ~j; + nm_assert(available_all[i] == available_all[k] || available_all[i]); + } + } + } + } #endif - return available; + return available; } static gboolean -available_connections_del_all (NMDevice *self) +available_connections_del_all(NMDevice *self) { - if (g_hash_table_size (self->_priv->available_connections) == 0) - return FALSE; - g_hash_table_remove_all (self->_priv->available_connections); - return TRUE; + if (g_hash_table_size(self->_priv->available_connections) == 0) + return FALSE; + g_hash_table_remove_all(self->_priv->available_connections); + return TRUE; } static gboolean -available_connections_add (NMDevice *self, NMSettingsConnection *sett_conn) +available_connections_add(NMDevice *self, NMSettingsConnection *sett_conn) { - return g_hash_table_add (self->_priv->available_connections, g_object_ref (sett_conn)); + return g_hash_table_add(self->_priv->available_connections, g_object_ref(sett_conn)); } static gboolean -available_connections_del (NMDevice *self, NMSettingsConnection *sett_conn) +available_connections_del(NMDevice *self, NMSettingsConnection *sett_conn) { - return g_hash_table_remove (self->_priv->available_connections, sett_conn); + return g_hash_table_remove(self->_priv->available_connections, sett_conn); } static gboolean -check_connection_available (NMDevice *self, - NMConnection *connection, - NMDeviceCheckConAvailableFlags flags, - const char *specific_object, - GError **error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - /* Connections which require a network connection are not available when - * the device has no carrier, even with ignore-carrer=TRUE. - */ - if ( priv->carrier - || !connection_requires_carrier (connection)) - return TRUE; - - if ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) - && priv->carrier_wait_id != 0) { - /* The device has no carrier though the connection requires it. - * - * If we are still waiting for carrier, the connection is available - * for an explicit user-request. */ - return TRUE; - } - - /* master types are always available even without carrier. - * Making connection non-available would un-enslave slaves which - * is not desired. */ - if (nm_device_is_master (self)) - return TRUE; - - nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has no carrier"); - return FALSE; +check_connection_available(NMDevice * self, + NMConnection * connection, + NMDeviceCheckConAvailableFlags flags, + const char * specific_object, + GError ** error) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + /* Connections which require a network connection are not available when + * the device has no carrier, even with ignore-carrer=TRUE. + */ + if (priv->carrier || !connection_requires_carrier(connection)) + return TRUE; + + if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) + && priv->carrier_wait_id != 0) { + /* The device has no carrier though the connection requires it. + * + * If we are still waiting for carrier, the connection is available + * for an explicit user-request. */ + return TRUE; + } + + /* master types are always available even without carrier. + * Making connection non-available would un-enslave slaves which + * is not desired. */ + if (nm_device_is_master(self)) + return TRUE; + + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no carrier"); + return FALSE; } void -nm_device_recheck_available_connections (NMDevice *self) -{ - NMDevicePrivate *priv; - NMSettingsConnection *const*connections; - gboolean changed = FALSE; - GHashTableIter h_iter; - NMSettingsConnection *sett_conn; - guint i; - gs_unref_hashtable GHashTable *prune_list = NULL; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (g_hash_table_size (priv->available_connections) > 0) { - prune_list = g_hash_table_new (nm_direct_hash, NULL); - g_hash_table_iter_init (&h_iter, priv->available_connections); - while (g_hash_table_iter_next (&h_iter, (gpointer *) &sett_conn, NULL)) - g_hash_table_add (prune_list, sett_conn); - } - - connections = nm_settings_get_connections (priv->settings, NULL); - for (i = 0; connections[i]; i++) { - sett_conn = connections[i]; - - if (nm_device_check_connection_available (self, - nm_settings_connection_get_connection (sett_conn), - NM_DEVICE_CHECK_CON_AVAILABLE_NONE, - NULL, - NULL)) { - if (available_connections_add (self, sett_conn)) - changed = TRUE; - if (prune_list) - g_hash_table_remove (prune_list, sett_conn); - } - } - - if (prune_list) { - g_hash_table_iter_init (&h_iter, prune_list); - while (g_hash_table_iter_next (&h_iter, (gpointer *) &sett_conn, NULL)) { - if (available_connections_del (self, sett_conn)) - changed = TRUE; - } - } - - if (changed) - _notify (self, PROP_AVAILABLE_CONNECTIONS); - available_connections_check_delete_unrealized (self); +nm_device_recheck_available_connections(NMDevice *self) +{ + NMDevicePrivate * priv; + NMSettingsConnection *const *connections; + gboolean changed = FALSE; + GHashTableIter h_iter; + NMSettingsConnection * sett_conn; + guint i; + gs_unref_hashtable GHashTable *prune_list = NULL; + + g_return_if_fail(NM_IS_DEVICE(self)); + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (g_hash_table_size(priv->available_connections) > 0) { + prune_list = g_hash_table_new(nm_direct_hash, NULL); + g_hash_table_iter_init(&h_iter, priv->available_connections); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &sett_conn, NULL)) + g_hash_table_add(prune_list, sett_conn); + } + + connections = nm_settings_get_connections(priv->settings, NULL); + for (i = 0; connections[i]; i++) { + sett_conn = connections[i]; + + if (nm_device_check_connection_available(self, + nm_settings_connection_get_connection(sett_conn), + NM_DEVICE_CHECK_CON_AVAILABLE_NONE, + NULL, + NULL)) { + if (available_connections_add(self, sett_conn)) + changed = TRUE; + if (prune_list) + g_hash_table_remove(prune_list, sett_conn); + } + } + + if (prune_list) { + g_hash_table_iter_init(&h_iter, prune_list); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &sett_conn, NULL)) { + if (available_connections_del(self, sett_conn)) + changed = TRUE; + } + } + + if (changed) + _notify(self, PROP_AVAILABLE_CONNECTIONS); + available_connections_check_delete_unrealized(self); } /** @@ -15245,99 +15469,104 @@ nm_device_recheck_available_connections (NMDevice *self) * Returns: the #NMSettingsConnection or %NULL (setting an @error) */ NMSettingsConnection * -nm_device_get_best_connection (NMDevice *self, - const char *specific_object, - GError **error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMSettingsConnection *sett_conn = NULL; - NMSettingsConnection *candidate; - guint64 best_timestamp = 0; - GHashTableIter iter; - - g_hash_table_iter_init (&iter, priv->available_connections); - while (g_hash_table_iter_next (&iter, (gpointer) &candidate, NULL)) { - guint64 candidate_timestamp = 0; - - /* If a specific object is given, only include connections that are - * compatible with it. - */ - if ( specific_object /* << Optimization: we know that the connection is available without @specific_object. */ - && !nm_device_check_connection_available (self, - nm_settings_connection_get_connection (candidate), - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, - specific_object, - NULL)) - continue; - - nm_settings_connection_get_timestamp (candidate, &candidate_timestamp); - if (!sett_conn || (candidate_timestamp > best_timestamp)) { - sett_conn = candidate; - best_timestamp = candidate_timestamp; - } - } - - if (!sett_conn) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "The device '%s' has no connections available for activation.", - nm_device_get_iface (self)); - } - - return sett_conn; +nm_device_get_best_connection(NMDevice *self, const char *specific_object, GError **error) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingsConnection *sett_conn = NULL; + NMSettingsConnection *candidate; + guint64 best_timestamp = 0; + GHashTableIter iter; + + g_hash_table_iter_init(&iter, priv->available_connections); + while (g_hash_table_iter_next(&iter, (gpointer) &candidate, NULL)) { + guint64 candidate_timestamp = 0; + + /* If a specific object is given, only include connections that are + * compatible with it. + */ + if (specific_object /* << Optimization: we know that the connection is available without @specific_object. */ + && !nm_device_check_connection_available( + self, + nm_settings_connection_get_connection(candidate), + _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + specific_object, + NULL)) + continue; + + nm_settings_connection_get_timestamp(candidate, &candidate_timestamp); + if (!sett_conn || (candidate_timestamp > best_timestamp)) { + sett_conn = candidate; + best_timestamp = candidate_timestamp; + } + } + + if (!sett_conn) { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_CONNECTION, + "The device '%s' has no connections available for activation.", + nm_device_get_iface(self)); + } + + return sett_conn; } static void -cp_connection_added_or_updated (NMDevice *self, NMSettingsConnection *sett_conn) +cp_connection_added_or_updated(NMDevice *self, NMSettingsConnection *sett_conn) { - gboolean changed; + gboolean changed; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn)); + g_return_if_fail(NM_IS_DEVICE(self)); + g_return_if_fail(NM_IS_SETTINGS_CONNECTION(sett_conn)); - if (nm_device_check_connection_available (self, - nm_settings_connection_get_connection (sett_conn), - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, - NULL, - NULL)) - changed = available_connections_add (self, sett_conn); - else - changed = available_connections_del (self, sett_conn); + if (nm_device_check_connection_available(self, + nm_settings_connection_get_connection(sett_conn), + _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, + NULL)) + changed = available_connections_add(self, sett_conn); + else + changed = available_connections_del(self, sett_conn); - if (changed) { - _notify (self, PROP_AVAILABLE_CONNECTIONS); - available_connections_check_delete_unrealized (self); - } + if (changed) { + _notify(self, PROP_AVAILABLE_CONNECTIONS); + available_connections_check_delete_unrealized(self); + } } static void -cp_connection_added (NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) +cp_connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) { - cp_connection_added_or_updated (user_data, sett_conn); + cp_connection_added_or_updated(user_data, sett_conn); } static void -cp_connection_updated (NMSettings *settings, NMSettingsConnection *sett_conn, guint update_reason_u, gpointer user_data) +cp_connection_updated(NMSettings * settings, + NMSettingsConnection *sett_conn, + guint update_reason_u, + gpointer user_data) { - cp_connection_added_or_updated (user_data, sett_conn); + cp_connection_added_or_updated(user_data, sett_conn); } static void -cp_connection_removed (NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) +cp_connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) { - NMDevice *self = user_data; + NMDevice *self = user_data; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail(NM_IS_DEVICE(self)); - if (available_connections_del (self, sett_conn)) { - _notify (self, PROP_AVAILABLE_CONNECTIONS); - available_connections_check_delete_unrealized (self); - } + if (available_connections_del(self, sett_conn)) { + _notify(self, PROP_AVAILABLE_CONNECTIONS); + available_connections_check_delete_unrealized(self); + } } gboolean -nm_device_supports_vlans (NMDevice *self) +nm_device_supports_vlans(NMDevice *self) { - return nm_platform_link_supports_vlans (nm_device_get_platform (self), nm_device_get_ifindex (self)); + return nm_platform_link_supports_vlans(nm_device_get_platform(self), + nm_device_get_ifindex(self)); } /** @@ -15356,39 +15585,43 @@ nm_device_supports_vlans (NMDevice *self) * a second time. */ gboolean -nm_device_add_pending_action (NMDevice *self, const char *action, gboolean assert_not_yet_pending) +nm_device_add_pending_action(NMDevice *self, const char *action, gboolean assert_not_yet_pending) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - GSList *iter; - guint count = 0; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + GSList * iter; + guint count = 0; - g_return_val_if_fail (action, FALSE); + g_return_val_if_fail(action, FALSE); - /* Check if the action is already pending. Cannot add duplicate actions */ - for (iter = priv->pending_actions; iter; iter = iter->next) { - if (!strcmp (action, iter->data)) { - if (assert_not_yet_pending) { - _LOGW (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending", - count + g_slist_length (iter), action); - g_return_val_if_reached (FALSE); - } else { - _LOGT (LOGD_DEVICE, "add_pending_action (%d): '%s' already pending (expected)", - count + g_slist_length (iter), action); - } - return FALSE; - } - count++; - } + /* Check if the action is already pending. Cannot add duplicate actions */ + for (iter = priv->pending_actions; iter; iter = iter->next) { + if (nm_streq(action, iter->data)) { + if (assert_not_yet_pending) { + _LOGW(LOGD_DEVICE, + "add_pending_action (%d): '%s' already pending", + count + g_slist_length(iter), + action); + g_return_val_if_reached(FALSE); + } else { + _LOGT(LOGD_DEVICE, + "add_pending_action (%d): '%s' already pending (expected)", + count + g_slist_length(iter), + action); + } + return FALSE; + } + count++; + } - priv->pending_actions = g_slist_prepend (priv->pending_actions, (char *) action); - count++; + priv->pending_actions = g_slist_prepend(priv->pending_actions, (char *) action); + count++; - _LOGD (LOGD_DEVICE, "add_pending_action (%d): '%s'", count, action); + _LOGD(LOGD_DEVICE, "add_pending_action (%d): '%s'", count, action); - if (count == 1) - _notify (self, PROP_HAS_PENDING_ACTION); + if (count == 1) + _notify(self, PROP_HAS_PENDING_ACTION); - return TRUE; + return TRUE; } /** @@ -15404,198 +15637,195 @@ nm_device_add_pending_action (NMDevice *self, const char *action, gboolean asser * Returns: whether the @action was pending and is now removed. */ gboolean -nm_device_remove_pending_action (NMDevice *self, const char *action, gboolean assert_is_pending) -{ - NMDevicePrivate *priv; - GSList *iter, *next; - guint count = 0; - - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (action, FALSE); - - priv = NM_DEVICE_GET_PRIVATE (self); - - for (iter = priv->pending_actions; iter; iter = next) { - next = iter->next; - if (!strcmp (action, iter->data)) { - _LOGD (LOGD_DEVICE, "remove_pending_action (%d): '%s'", - count + g_slist_length (iter->next), /* length excluding 'iter' */ - action); - priv->pending_actions = g_slist_delete_link (priv->pending_actions, iter); - if (priv->pending_actions == NULL) - _notify (self, PROP_HAS_PENDING_ACTION); - return TRUE; - } - count++; - } - - if (assert_is_pending) { - _LOGW (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending", count, action); - g_return_val_if_reached (FALSE); - } else - _LOGT (LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending (expected)", count, action); - - return FALSE; +nm_device_remove_pending_action(NMDevice *self, const char *action, gboolean assert_is_pending) +{ + NMDevicePrivate *priv; + GSList * iter, *next; + guint count = 0; + + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(action, FALSE); + + priv = NM_DEVICE_GET_PRIVATE(self); + + for (iter = priv->pending_actions; iter; iter = next) { + next = iter->next; + if (nm_streq(action, iter->data)) { + _LOGD(LOGD_DEVICE, + "remove_pending_action (%d): '%s'", + count + g_slist_length(iter->next), /* length excluding 'iter' */ + action); + priv->pending_actions = g_slist_delete_link(priv->pending_actions, iter); + if (priv->pending_actions == NULL) + _notify(self, PROP_HAS_PENDING_ACTION); + return TRUE; + } + count++; + } + + if (assert_is_pending) { + _LOGW(LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending", count, action); + g_return_val_if_reached(FALSE); + } else + _LOGT(LOGD_DEVICE, + "remove_pending_action (%d): '%s' not pending (expected)", + count, + action); + + return FALSE; } const char * -nm_device_has_pending_action_reason (NMDevice *self) +nm_device_has_pending_action_reason(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->pending_actions) { + if (priv->pending_actions) { + if (!priv->pending_actions->next && nm_device_get_state(self) == NM_DEVICE_STATE_ACTIVATED + && nm_streq(priv->pending_actions->data, NM_PENDING_ACTION_CARRIER_WAIT)) { + /* if the device is already in activated state, and the only reason + * why it appears still busy is "carrier-wait", then we are already complete. */ + return NULL; + } - if ( !priv->pending_actions->next - && nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED - && nm_streq (priv->pending_actions->data, NM_PENDING_ACTION_CARRIER_WAIT)) { - /* if the device is already in activated state, and the only reason - * why it appears still busy is "carrier-wait", then we are already complete. */ - return NULL; - } + return priv->pending_actions->data; + } - return priv->pending_actions->data; - } + if (nm_device_is_real(self) + && nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { + /* as long as the platform link is not yet initialized, we have a pending + * action. */ + return NM_PENDING_ACTION_LINK_INIT; + } - if ( nm_device_is_real (self) - && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) { - /* as long as the platform link is not yet initialized, we have a pending - * action. */ - return NM_PENDING_ACTION_LINK_INIT; - } - - return NULL; + return NULL; } /*****************************************************************************/ static void -_cancel_activation (NMDevice *self) +_cancel_activation(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->fw_call) { - nm_firewall_manager_cancel_call (priv->fw_call); - nm_assert (!priv->fw_call); - priv->fw_call = NULL; - priv->fw_state = FIREWALL_STATE_INITIALIZED; - } + if (priv->fw_call) { + nm_firewall_manager_cancel_call(priv->fw_call); + nm_assert(!priv->fw_call); + priv->fw_call = NULL; + priv->fw_state = FIREWALL_STATE_INITIALIZED; + } - ip_check_gw_ping_cleanup (self); + ip_check_gw_ping_cleanup(self); - /* Break the activation chain */ - activation_source_clear (self, AF_INET); - activation_source_clear (self, AF_INET6); + /* Break the activation chain */ + activation_source_clear(self, AF_INET); + activation_source_clear(self, AF_INET6); } static void -_cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type) +_cleanup_generic_pre(NMDevice *self, CleanupType cleanup_type) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + _cancel_activation(self); - _cancel_activation (self); + priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_INIT; - priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_INIT; + if (cleanup_type != CLEANUP_TYPE_KEEP) { + nm_manager_device_route_metric_clear(NM_MANAGER_GET, nm_device_get_ip_ifindex(self)); + } - if (cleanup_type != CLEANUP_TYPE_KEEP) { - nm_manager_device_route_metric_clear (NM_MANAGER_GET, - nm_device_get_ip_ifindex (self)); - } + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE && priv->fw_state >= FIREWALL_STATE_INITIALIZED + && priv->fw_mgr && !nm_device_sys_iface_state_is_external(self)) { + nm_firewall_manager_remove_from_zone(priv->fw_mgr, + nm_device_get_ip_iface(self), + NULL, + NULL, + NULL); + } + priv->fw_state = FIREWALL_STATE_UNMANAGED; + g_clear_object(&priv->fw_mgr); - if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE - && priv->fw_state >= FIREWALL_STATE_INITIALIZED - && priv->fw_mgr - && !nm_device_sys_iface_state_is_external (self)) { - nm_firewall_manager_remove_from_zone (priv->fw_mgr, - nm_device_get_ip_iface (self), - NULL, - NULL, - NULL); - } - priv->fw_state = FIREWALL_STATE_UNMANAGED; - g_clear_object (&priv->fw_mgr); + queued_state_clear(self); - queued_state_clear (self); + nm_clear_pointer(&priv->shared_ip_handle, nm_netns_shared_ip_release); - _cleanup_ip_pre (self, AF_INET, cleanup_type); - _cleanup_ip_pre (self, AF_INET6, cleanup_type); + _cleanup_ip_pre(self, AF_INET, cleanup_type); + _cleanup_ip_pre(self, AF_INET6, cleanup_type); } static void -_cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - priv->v4_commit_first_time = TRUE; - priv->v6_commit_first_time = TRUE; - - priv->v4_route_table_initialized = FALSE; - priv->v6_route_table_initialized = FALSE; - - priv->v4_route_table_all_sync_before = FALSE; - priv->v6_route_table_all_sync_before = FALSE; - - priv->default_route_metric_penalty_ip4_has = FALSE; - priv->default_route_metric_penalty_ip6_has = FALSE; - - priv->linklocal6_dad_counter = 0; - - /* Clean up IP configs; this does not actually deconfigure the - * interface; the caller must flush routes and addresses explicitly. - */ - nm_device_set_ip_config (self, AF_INET, NULL, TRUE, NULL); - nm_device_set_ip_config (self, AF_INET6, NULL, TRUE, NULL); - g_clear_object (&priv->proxy_config); - g_clear_object (&priv->con_ip_config_4); - applied_config_clear (&priv->dev_ip_config_4); - applied_config_clear (&priv->dev2_ip_config_4); - g_clear_object (&priv->ext_ip_config_4); - g_clear_object (&priv->ip_config_4); - g_clear_object (&priv->con_ip_config_6); - applied_config_clear (&priv->ac_ip6_config); - g_clear_object (&priv->ext_ip_config_6); - g_clear_object (&priv->ext_ip6_config_captured); - applied_config_clear (&priv->dev2_ip_config_6); - g_clear_object (&priv->ip_config_6); - g_clear_object (&priv->dad6_ip6_config); - priv->ipv6ll_has = FALSE; - memset (&priv->ipv6ll_addr, 0, sizeof (priv->ipv6ll_addr)); - - nm_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source (&priv->rt6_temporary_not_available_id); - - g_slist_free_full (priv->vpn_configs_4, g_object_unref); - priv->vpn_configs_4 = NULL; - g_slist_free_full (priv->vpn_configs_6, g_object_unref); - priv->vpn_configs_6 = NULL; - - /* We no longer accept the delegations. nm_device_set_ip_config(NULL) - * above disables them. */ - nm_assert (priv->needs_ip6_subnet == FALSE); - - if (priv->act_request.obj) { - nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request.obj), AF_INET, FALSE); - nm_clear_g_signal_handler (priv->act_request.obj, &priv->master_ready_id); - act_request_set (self, NULL); - } - - /* Clear legacy IPv4 address property */ - if (priv->ip4_address) { - priv->ip4_address = 0; - _notify (self, PROP_IP4_ADDRESS); - } - - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { - /* Check if the device was deactivated, and if so, delete_link. - * Don't call delete_link synchronously because we are currently - * handling a state change -- which is not reentrant. */ - delete_on_deactivate_check_and_schedule (self, nm_device_get_ip_ifindex (self)); - } - - /* ip_iface should be cleared after flushing all routes and addresses, since - * those are identified by ip_iface, not by iface (which might be a tty - * or ATM device). - */ - _set_ip_ifindex (self, 0, NULL); +_cleanup_generic_post(NMDevice *self, CleanupType cleanup_type) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + priv->v4_commit_first_time = TRUE; + priv->v6_commit_first_time = TRUE; + + priv->v4_route_table_initialized = FALSE; + priv->v6_route_table_initialized = FALSE; + + priv->v4_route_table_all_sync_before = FALSE; + priv->v6_route_table_all_sync_before = FALSE; + + priv->default_route_metric_penalty_ip4_has = FALSE; + priv->default_route_metric_penalty_ip6_has = FALSE; + + priv->linklocal6_dad_counter = 0; + + /* Clean up IP configs; this does not actually deconfigure the + * interface; the caller must flush routes and addresses explicitly. + */ + nm_device_set_ip_config(self, AF_INET, NULL, TRUE, NULL); + nm_device_set_ip_config(self, AF_INET6, NULL, TRUE, NULL); + g_clear_object(&priv->proxy_config); + g_clear_object(&priv->con_ip_config_4); + applied_config_clear(&priv->dev_ip_config_4); + applied_config_clear(&priv->dev2_ip_config_4); + g_clear_object(&priv->ext_ip_config_4); + g_clear_object(&priv->ip_config_4); + g_clear_object(&priv->con_ip_config_6); + applied_config_clear(&priv->ac_ip6_config); + g_clear_object(&priv->ext_ip_config_6); + g_clear_object(&priv->ext_ip6_config_captured); + applied_config_clear(&priv->dev2_ip_config_6); + g_clear_object(&priv->ip_config_6); + g_clear_object(&priv->dad6_ip6_config); + priv->ipv6ll_has = FALSE; + memset(&priv->ipv6ll_addr, 0, sizeof(priv->ipv6ll_addr)); + + nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); + nm_clear_g_source(&priv->rt6_temporary_not_available_id); + + g_slist_free_full(priv->vpn_configs_4, g_object_unref); + priv->vpn_configs_4 = NULL; + g_slist_free_full(priv->vpn_configs_6, g_object_unref); + priv->vpn_configs_6 = NULL; + + /* We no longer accept the delegations. nm_device_set_ip_config(NULL) + * above disables them. */ + nm_assert(priv->needs_ip6_subnet == FALSE); + + if (priv->act_request.obj) { + nm_active_connection_set_default(NM_ACTIVE_CONNECTION(priv->act_request.obj), + AF_INET, + FALSE); + nm_clear_g_signal_handler(priv->act_request.obj, &priv->master_ready_id); + act_request_set(self, NULL); + } + + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { + /* Check if the device was deactivated, and if so, delete_link. + * Don't call delete_link synchronously because we are currently + * handling a state change -- which is not reentrant. */ + delete_on_deactivate_check_and_schedule(self, nm_device_get_ip_ifindex(self)); + } + + /* ip_iface should be cleared after flushing all routes and addresses, since + * those are identified by ip_iface, not by iface (which might be a tty + * or ATM device). + */ + _set_ip_ifindex(self, 0, NULL); } /* @@ -15605,1418 +15835,1332 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) * */ static void -nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType cleanup_type) -{ - NMDevicePrivate *priv; - int ifindex; - - g_return_if_fail (NM_IS_DEVICE (self)); - - if (reason == NM_DEVICE_STATE_REASON_NOW_MANAGED) - _LOGD (LOGD_DEVICE, "preparing device"); - else - _LOGD (LOGD_DEVICE, "deactivating device (reason '%s') [%d]", reason_to_string_a (reason), reason); - - /* Save whether or not we tried IPv6 for later */ - priv = NM_DEVICE_GET_PRIVATE (self); - - _cleanup_generic_pre (self, cleanup_type); - - /* Turn off kernel IPv6 */ - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { - set_disable_ipv6 (self, "1"); - nm_device_sysctl_ip_conf_set (self, AF_INET6, "use_tempaddr", "0"); - } - - /* Call device type-specific deactivation */ - if (NM_DEVICE_GET_CLASS (self)->deactivate) - NM_DEVICE_GET_CLASS (self)->deactivate (self); - - ifindex = nm_device_get_ip_ifindex (self); - - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { - /* master: release slaves */ - nm_device_master_release_slaves (self); - - /* Take out any entries in the routing table and any IP address the device had. */ - if (ifindex > 0) { - NMPlatform *platform = nm_device_get_platform (self); - NMUtilsIPv6IfaceId iid = { }; - - nm_platform_ip_route_flush (platform, AF_UNSPEC, ifindex); - nm_platform_ip_address_flush (platform, AF_UNSPEC, ifindex); - nm_platform_tfilter_sync (platform, ifindex, NULL); - nm_platform_qdisc_sync (platform, ifindex, NULL); - set_ipv6_token (self, iid, "::"); - } - } - - _routing_rules_sync (self, - cleanup_type == CLEANUP_TYPE_KEEP - ? NM_TERNARY_DEFAULT - : NM_TERNARY_FALSE); - - if (ifindex > 0) - nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), ifindex, NULL); - - /* slave: mark no longer enslaved */ - if ( priv->master - && priv->ifindex > 0 - && 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); - - nm_device_update_metered (self); - - if (ifindex > 0) { - /* during device cleanup, we want to reset the MAC address of the device - * to the initial state. - * - * We certainly want to do that when reaching the UNMANAGED state... */ - if (nm_device_get_state (self) <= NM_DEVICE_STATE_UNMANAGED) - nm_device_hw_addr_reset (self, "unmanage"); - else { - /* for other device states (UNAVAILABLE, DISCONNECTED), allow the - * device to overwrite the reset behavior, so that Wi-Fi can set - * a randomized MAC address used during scanning. */ - NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self); - } - } - - priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; - priv->ip6_mtu = 0; - if (priv->mtu_initial || priv->ip6_mtu_initial) { - ifindex = nm_device_get_ip_ifindex (self); - - if ( ifindex > 0 - && cleanup_type == CLEANUP_TYPE_DECONFIGURE) { - _LOGT (LOGD_DEVICE, "mtu: reset device-mtu: %u, ipv6-mtu: %u, ifindex: %d", - (guint) priv->mtu_initial, (guint) priv->ip6_mtu_initial, ifindex); - if (priv->mtu_initial) { - nm_platform_link_set_mtu (nm_device_get_platform (self), ifindex, priv->mtu_initial); - priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_msec () + CARRIER_WAIT_TIME_AFTER_MTU_MS; - } - if (priv->ip6_mtu_initial) { - char sbuf[64]; - - nm_device_sysctl_ip_conf_set (self, AF_INET6, "mtu", - nm_sprintf_buf (sbuf, "%u", (unsigned) priv->ip6_mtu_initial)); - } - } - priv->mtu_initial = 0; - priv->ip6_mtu_initial = 0; - } - - _ethtool_state_reset (self); - - _cleanup_generic_post (self, cleanup_type); +nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanup_type) +{ + NMDevicePrivate *priv; + int ifindex; + + g_return_if_fail(NM_IS_DEVICE(self)); + + if (reason == NM_DEVICE_STATE_REASON_NOW_MANAGED) + _LOGD(LOGD_DEVICE, "preparing device"); + else + _LOGD(LOGD_DEVICE, + "deactivating device (reason '%s') [%d]", + reason_to_string_a(reason), + reason); + + /* Save whether or not we tried IPv6 for later */ + priv = NM_DEVICE_GET_PRIVATE(self); + + _cleanup_generic_pre(self, cleanup_type); + + /* Turn off kernel IPv6 */ + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { + set_disable_ipv6(self, "1"); + nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", "0"); + } + + /* Call device type-specific deactivation */ + if (NM_DEVICE_GET_CLASS(self)->deactivate) + NM_DEVICE_GET_CLASS(self)->deactivate(self); + + ifindex = nm_device_get_ip_ifindex(self); + + if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { + /* master: release slaves */ + nm_device_master_release_slaves(self); + + /* Take out any entries in the routing table and any IP address the device had. */ + if (ifindex > 0) { + NMPlatform * platform = nm_device_get_platform(self); + NMUtilsIPv6IfaceId iid = {}; + + nm_platform_ip_route_flush(platform, AF_UNSPEC, ifindex); + nm_platform_ip_address_flush(platform, AF_UNSPEC, ifindex); + nm_platform_tfilter_sync(platform, ifindex, NULL); + nm_platform_qdisc_sync(platform, ifindex, NULL); + set_ipv6_token(self, iid, "::"); + } + } + + _routing_rules_sync(self, + cleanup_type == CLEANUP_TYPE_KEEP ? NM_TERNARY_DEFAULT : NM_TERNARY_FALSE); + + if (ifindex > 0) + nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), ifindex, NULL); + + /* slave: mark no longer enslaved */ + if (priv->master && priv->ifindex > 0 + && nm_platform_link_get_master(nm_device_get_platform(self), priv->ifindex) <= 0) + nm_device_master_release_one_slave(priv->master, + self, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + + if (priv->lldp_listener) + nm_lldp_listener_stop(priv->lldp_listener); + + nm_device_update_metered(self); + + if (ifindex > 0) { + /* during device cleanup, we want to reset the MAC address of the device + * to the initial state. + * + * We certainly want to do that when reaching the UNMANAGED state... */ + if (nm_device_get_state(self) <= NM_DEVICE_STATE_UNMANAGED) + nm_device_hw_addr_reset(self, "unmanage"); + else { + /* for other device states (UNAVAILABLE, DISCONNECTED), allow the + * device to overwrite the reset behavior, so that Wi-Fi can set + * a randomized MAC address used during scanning. */ + NM_DEVICE_GET_CLASS(self)->deactivate_reset_hw_addr(self); + } + } + + priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; + priv->ip6_mtu = 0; + if (priv->mtu_initial || priv->ip6_mtu_initial) { + ifindex = nm_device_get_ip_ifindex(self); + + if (ifindex > 0 && cleanup_type == CLEANUP_TYPE_DECONFIGURE) { + _LOGT(LOGD_DEVICE, + "mtu: reset device-mtu: %u, ipv6-mtu: %u, ifindex: %d", + (guint) priv->mtu_initial, + (guint) priv->ip6_mtu_initial, + ifindex); + if (priv->mtu_initial) { + nm_platform_link_set_mtu(nm_device_get_platform(self), ifindex, priv->mtu_initial); + priv->carrier_wait_until_ms = + nm_utils_get_monotonic_timestamp_msec() + CARRIER_WAIT_TIME_AFTER_MTU_MS; + } + if (priv->ip6_mtu_initial) { + char sbuf[64]; + + nm_device_sysctl_ip_conf_set( + self, + AF_INET6, + "mtu", + nm_sprintf_buf(sbuf, "%u", (unsigned) priv->ip6_mtu_initial)); + } + } + priv->mtu_initial = 0; + priv->ip6_mtu_initial = 0; + } + + _ethtool_state_reset(self); + + _cleanup_generic_post(self, cleanup_type); } static void -deactivate_reset_hw_addr (NMDevice *self) +deactivate_reset_hw_addr(NMDevice *self) { - nm_device_hw_addr_reset (self, "deactivate"); + nm_device_hw_addr_reset(self, "deactivate"); } static char * -find_dhcp4_address (NMDevice *self) +find_dhcp4_address(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const NMPlatformIP4Address *a; - NMDedupMultiIter ipconf_iter; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const NMPlatformIP4Address *a; + NMDedupMultiIter ipconf_iter; - if (!priv->ip_config_4) - return NULL; + if (!priv->ip_config_4) + return NULL; - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, priv->ip_config_4, &a) { - if (a->addr_source == NM_IP_CONFIG_SOURCE_DHCP) - return nm_utils_inet4_ntop_dup (a->address); - } - return NULL; + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, priv->ip_config_4, &a) { + if (a->addr_source == NM_IP_CONFIG_SOURCE_DHCP) + return nm_utils_inet4_ntop_dup(a->address); + } + return NULL; } void -nm_device_spawn_iface_helper (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean configured = FALSE; - NMConnection *connection; - GError *error = NULL; - const char *method; - GPtrArray *argv; - gs_free char *dhcp4_address = NULL; - char *logging_backend; - NMUtilsStableType stable_type; - const char *stable_id; - - if (priv->state != NM_DEVICE_STATE_ACTIVATED) - return; - if (!nm_device_can_assume_connections (self)) - return; - - connection = nm_device_get_applied_connection (self); - - g_return_if_fail (connection); - - argv = g_ptr_array_sized_new (10); - g_ptr_array_set_free_func (argv, g_free); - - g_ptr_array_add (argv, g_strdup (LIBEXECDIR "/nm-iface-helper")); - g_ptr_array_add (argv, g_strdup ("--ifname")); - g_ptr_array_add (argv, g_strdup (nm_device_get_ip_iface (self))); - g_ptr_array_add (argv, g_strdup ("--uuid")); - g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection))); - - stable_id = _get_stable_id (self, connection, &stable_type); - if (stable_type != NM_UTILS_STABLE_TYPE_UUID) { - g_ptr_array_add (argv, g_strdup ("--stable-id")); - g_ptr_array_add (argv, g_strdup_printf ("%d %s", (int) stable_type, stable_id)); - } - - logging_backend = nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG, - NM_CONFIG_KEYFILE_GROUP_LOGGING, - NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND, - NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); - if (logging_backend) { - g_ptr_array_add (argv, g_strdup ("--logging-backend")); - g_ptr_array_add (argv, logging_backend); - } - - g_ptr_array_add (argv, g_strdup ("--log-level")); - g_ptr_array_add (argv, g_strdup (nm_logging_level_to_string ())); - - g_ptr_array_add (argv, g_strdup ("--log-domains")); - g_ptr_array_add (argv, g_strdup (nm_logging_domains_to_string ())); - - dhcp4_address = find_dhcp4_address (self); - - method = nm_device_get_effective_ip_config_method (self, AF_INET); - if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - NMSettingIPConfig *s_ip4; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - nm_assert (s_ip4); - - g_ptr_array_add (argv, g_strdup ("--priority4")); - g_ptr_array_add (argv, g_strdup_printf ("%u", nm_device_get_route_metric (self, AF_INET))); - - g_ptr_array_add (argv, g_strdup ("--dhcp4")); - g_ptr_array_add (argv, g_strdup (dhcp4_address)); - if (nm_setting_ip_config_get_may_fail (s_ip4) == FALSE) - g_ptr_array_add (argv, g_strdup ("--dhcp4-required")); - - if (priv->dhcp_data_4.client) { - const char *hostname; - GBytes *client_id; - - client_id = nm_dhcp_client_get_client_id (priv->dhcp_data_4.client); - if (client_id) { - g_ptr_array_add (argv, g_strdup ("--dhcp4-clientid")); - g_ptr_array_add (argv, - nm_utils_bin2hexstr_full (g_bytes_get_data (client_id, NULL), - g_bytes_get_size (client_id), - ':', - FALSE, - NULL)); - } - - hostname = nm_dhcp_client_get_hostname (priv->dhcp_data_4.client); - if (hostname) { - if (nm_dhcp_client_get_use_fqdn (priv->dhcp_data_4.client)) - g_ptr_array_add (argv, g_strdup ("--dhcp4-fqdn")); - else - g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname")); - g_ptr_array_add (argv, g_strdup (hostname)); - } - } - - configured = TRUE; - } - - method = nm_utils_get_ip_config_method (connection, AF_INET6); - if (nm_streq (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - NMSettingIPConfig *s_ip6; - NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - g_assert (s_ip6); - - g_ptr_array_add (argv, g_strdup ("--priority6")); - g_ptr_array_add (argv, g_strdup_printf ("%u", nm_device_get_route_metric (self, AF_INET6))); - - g_ptr_array_add (argv, g_strdup ("--slaac")); - - if (nm_setting_ip_config_get_may_fail (s_ip6) == FALSE) - g_ptr_array_add (argv, g_strdup ("--slaac-required")); - - g_ptr_array_add (argv, g_strdup ("--slaac-tempaddr")); - g_ptr_array_add (argv, g_strdup_printf ("%d", priv->ndisc_use_tempaddr)); - - if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) { - g_ptr_array_add (argv, g_strdup ("--iid")); - g_ptr_array_add (argv, - nm_utils_bin2hexstr_full (iid.id_u8, - sizeof (NMUtilsIPv6IfaceId), - ':', - FALSE, - NULL)); - } - - g_ptr_array_add (argv, g_strdup ("--addr-gen-mode")); - g_ptr_array_add (argv, g_strdup_printf ("%d", nm_setting_ip6_config_get_addr_gen_mode (NM_SETTING_IP6_CONFIG (s_ip6)))); - - configured = TRUE; - } - - if (configured) { - GPid pid; - - g_ptr_array_add (argv, NULL); - - if (nm_logging_enabled (LOGL_DEBUG, LOGD_DEVICE)) { - char *tmp; - - tmp = g_strjoinv (" ", (char **) argv->pdata); - _LOGD (LOGD_DEVICE, "running '%s'", tmp); - g_free (tmp); - } - - if (g_spawn_async (NULL, (char **) argv->pdata, NULL, - G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, &error)) { - _LOGI (LOGD_DEVICE, "spawned helper PID %u", (guint) pid); - } else { - _LOGW (LOGD_DEVICE, "failed to spawn helper: %s", error->message); - g_error_free (error); - } - } - - g_ptr_array_unref (argv); +nm_device_spawn_iface_helper(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + gboolean configured = FALSE; + NMConnection * connection; + GError * error = NULL; + const char * method; + GPtrArray * argv; + gs_free char * dhcp4_address = NULL; + char * logging_backend; + NMUtilsStableType stable_type; + const char * stable_id; + + if (priv->state != NM_DEVICE_STATE_ACTIVATED) + return; + if (!nm_device_can_assume_connections(self)) + return; + + connection = nm_device_get_applied_connection(self); + + g_return_if_fail(connection); + + argv = g_ptr_array_sized_new(10); + g_ptr_array_set_free_func(argv, g_free); + + g_ptr_array_add(argv, g_strdup(LIBEXECDIR "/nm-iface-helper")); + g_ptr_array_add(argv, g_strdup("--ifname")); + g_ptr_array_add(argv, g_strdup(nm_device_get_ip_iface(self))); + g_ptr_array_add(argv, g_strdup("--uuid")); + g_ptr_array_add(argv, g_strdup(nm_connection_get_uuid(connection))); + + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + if (stable_type != NM_UTILS_STABLE_TYPE_UUID) { + g_ptr_array_add(argv, g_strdup("--stable-id")); + g_ptr_array_add(argv, g_strdup_printf("%d %s", (int) stable_type, stable_id)); + } + + logging_backend = + nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_LOGGING, + NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND, + NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); + if (logging_backend) { + g_ptr_array_add(argv, g_strdup("--logging-backend")); + g_ptr_array_add(argv, logging_backend); + } + + g_ptr_array_add(argv, g_strdup("--log-level")); + g_ptr_array_add(argv, g_strdup(nm_logging_level_to_string())); + + g_ptr_array_add(argv, g_strdup("--log-domains")); + g_ptr_array_add(argv, g_strdup(nm_logging_domains_to_string())); + + dhcp4_address = find_dhcp4_address(self); + + method = nm_device_get_effective_ip_config_method(self, AF_INET); + if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + NMSettingIPConfig *s_ip4; + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + nm_assert(s_ip4); + + g_ptr_array_add(argv, g_strdup("--priority4")); + g_ptr_array_add(argv, g_strdup_printf("%u", nm_device_get_route_metric(self, AF_INET))); + + g_ptr_array_add(argv, g_strdup("--dhcp4")); + g_ptr_array_add(argv, g_strdup(dhcp4_address)); + if (nm_setting_ip_config_get_may_fail(s_ip4) == FALSE) + g_ptr_array_add(argv, g_strdup("--dhcp4-required")); + + if (priv->dhcp_data_4.client) { + const char *hostname; + GBytes * client_id; + + client_id = nm_dhcp_client_get_client_id(priv->dhcp_data_4.client); + if (client_id) { + g_ptr_array_add(argv, g_strdup("--dhcp4-clientid")); + g_ptr_array_add(argv, + nm_utils_bin2hexstr_full(g_bytes_get_data(client_id, NULL), + g_bytes_get_size(client_id), + ':', + FALSE, + NULL)); + } + + hostname = nm_dhcp_client_get_hostname(priv->dhcp_data_4.client); + if (hostname) { + if (nm_dhcp_client_get_use_fqdn(priv->dhcp_data_4.client)) + g_ptr_array_add(argv, g_strdup("--dhcp4-fqdn")); + else + g_ptr_array_add(argv, g_strdup("--dhcp4-hostname")); + g_ptr_array_add(argv, g_strdup(hostname)); + } + } + + configured = TRUE; + } + + method = nm_utils_get_ip_config_method(connection, AF_INET6); + if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + NMSettingIPConfig *s_ip6; + NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; + + s_ip6 = nm_connection_get_setting_ip6_config(connection); + g_assert(s_ip6); + + g_ptr_array_add(argv, g_strdup("--priority6")); + g_ptr_array_add(argv, g_strdup_printf("%u", nm_device_get_route_metric(self, AF_INET6))); + + g_ptr_array_add(argv, g_strdup("--slaac")); + + if (nm_setting_ip_config_get_may_fail(s_ip6) == FALSE) + g_ptr_array_add(argv, g_strdup("--slaac-required")); + + g_ptr_array_add(argv, g_strdup("--slaac-tempaddr")); + g_ptr_array_add(argv, g_strdup_printf("%d", priv->ndisc_use_tempaddr)); + + if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) { + g_ptr_array_add(argv, g_strdup("--iid")); + g_ptr_array_add( + argv, + nm_utils_bin2hexstr_full(iid.id_u8, sizeof(NMUtilsIPv6IfaceId), ':', FALSE, NULL)); + } + + g_ptr_array_add(argv, g_strdup("--addr-gen-mode")); + g_ptr_array_add( + argv, + g_strdup_printf("%d", + nm_setting_ip6_config_get_addr_gen_mode(NM_SETTING_IP6_CONFIG(s_ip6)))); + + configured = TRUE; + } + + if (configured) { + GPid pid; + + g_ptr_array_add(argv, NULL); + + if (nm_logging_enabled(LOGL_DEBUG, LOGD_DEVICE)) { + char *tmp; + + tmp = g_strjoinv(" ", (char **) argv->pdata); + _LOGD(LOGD_DEVICE, "running '%s'", tmp); + g_free(tmp); + } + + if (g_spawn_async(NULL, + (char **) argv->pdata, + NULL, + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, + NULL, + &pid, + &error)) { + _LOGI(LOGD_DEVICE, "spawned helper PID %u", (guint) pid); + } else { + _LOGW(LOGD_DEVICE, "failed to spawn helper: %s", error->message); + g_error_free(error); + } + } + + g_ptr_array_unref(argv); } /*****************************************************************************/ static gboolean -ip_config_valid (NMDeviceState state) +ip_config_valid(NMDeviceState state) { - return (state == NM_DEVICE_STATE_UNMANAGED) || - (state >= NM_DEVICE_STATE_IP_CHECK && - state <= NM_DEVICE_STATE_DEACTIVATING); + return (state == NM_DEVICE_STATE_UNMANAGED) + || (state >= NM_DEVICE_STATE_IP_CHECK && state <= NM_DEVICE_STATE_DEACTIVATING); } static void -notify_ip_properties (NMDevice *self) +notify_ip_properties(NMDevice *self) { - _notify (self, PROP_IP_IFACE); - _notify (self, PROP_IP4_CONFIG); - _notify (self, PROP_DHCP4_CONFIG); - _notify (self, PROP_IP6_CONFIG); - _notify (self, PROP_DHCP6_CONFIG); + _notify(self, PROP_IP_IFACE); + _notify(self, PROP_IP4_CONFIG); + _notify(self, PROP_DHCP4_CONFIG); + _notify(self, PROP_IP6_CONFIG); + _notify(self, PROP_DHCP6_CONFIG); } static void -ip6_managed_setup (NMDevice *self) +ip6_managed_setup(NMDevice *self) { - set_nm_ipv6ll (self, TRUE); - set_disable_ipv6 (self, "1"); - nm_device_sysctl_ip_conf_set (self, AF_INET6, "accept_ra", "0"); - nm_device_sysctl_ip_conf_set (self, AF_INET6, "use_tempaddr", "0"); - nm_device_sysctl_ip_conf_set (self, AF_INET6, "forwarding", "0"); + set_nm_ipv6ll(self, TRUE); + set_disable_ipv6(self, "1"); + nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", "0"); + nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", "0"); + nm_device_sysctl_ip_conf_set(self, AF_INET6, "forwarding", "0"); } static void -deactivate_ready (NMDevice *self, NMDeviceStateReason reason) +deactivate_ready(NMDevice *self, NMDeviceStateReason reason) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->dispatcher.call_id) - return; + if (priv->dispatcher.call_id) + return; - if (priv->sriov_reset_pending > 0) - return; + if (priv->sriov_reset_pending > 0) + return; - if (priv->state == NM_DEVICE_STATE_DEACTIVATING) - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); + if (priv->state == NM_DEVICE_STATE_DEACTIVATING) + nm_device_queue_state(self, NM_DEVICE_STATE_DISCONNECTED, reason); } static void -sriov_reset_on_deactivate_cb (GError *error, gpointer user_data) +sriov_reset_on_deactivate_cb(GError *error, gpointer user_data) { - NMDevice *self; - NMDevicePrivate *priv; - gpointer reason; + NMDevice * self; + NMDevicePrivate *priv; + gpointer reason; - nm_utils_user_data_unpack (user_data, &self, &reason); - priv = NM_DEVICE_GET_PRIVATE (self); - nm_assert (priv->sriov_reset_pending > 0); - priv->sriov_reset_pending--; + nm_utils_user_data_unpack(user_data, &self, &reason); + priv = NM_DEVICE_GET_PRIVATE(self); + nm_assert(priv->sriov_reset_pending > 0); + priv->sriov_reset_pending--; - if (nm_utils_error_is_cancelled (error)) - return; + if (nm_utils_error_is_cancelled(error)) + return; - deactivate_ready (self, (NMDeviceStateReason) reason); + deactivate_ready(self, GPOINTER_TO_INT(reason)); } static void -sriov_reset_on_failure_cb (GError *error, gpointer user_data) +sriov_reset_on_failure_cb(GError *error, gpointer user_data) { - NMDevice *self = user_data; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice * self = user_data; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert (priv->sriov_reset_pending > 0); - priv->sriov_reset_pending--; + nm_assert(priv->sriov_reset_pending > 0); + priv->sriov_reset_pending--; - if (nm_utils_error_is_cancelled (error)) - return; + if (nm_utils_error_is_cancelled(error)) + return; - if (priv->state == NM_DEVICE_STATE_FAILED) { - nm_device_queue_state (self, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - } + if (priv->state == NM_DEVICE_STATE_FAILED) { + nm_device_queue_state(self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); + } } static void -deactivate_async_ready (NMDevice *self, - GError *error, - gpointer user_data) +deactivate_async_ready(NMDevice *self, GError *error, gpointer user_data) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceStateReason reason = GPOINTER_TO_UINT (user_data); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceStateReason reason = GPOINTER_TO_UINT(user_data); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - _LOGD (LOGD_DEVICE, "Deactivation cancelled"); - return; - } + if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGD(LOGD_DEVICE, "Deactivation cancelled"); + return; + } - g_clear_object (&priv->deactivating_cancellable); + g_clear_object(&priv->deactivating_cancellable); - /* In every other case, transition to the DISCONNECTED state */ - if (error) { - _LOGW (LOGD_DEVICE, "Deactivation failed: %s", - error->message); - } + /* In every other case, transition to the DISCONNECTED state */ + if (error) { + _LOGW(LOGD_DEVICE, "Deactivation failed: %s", error->message); + } - deactivate_ready (self, reason); + deactivate_ready(self, reason); } static void -deactivate_dispatcher_complete (NMDispatcherCallId *call_id, gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceStateReason reason; - - g_return_if_fail (call_id == priv->dispatcher.call_id); - g_return_if_fail (priv->dispatcher.post_state == NM_DEVICE_STATE_DISCONNECTED); - - reason = priv->state_reason; - - priv->dispatcher.call_id = NULL; - priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - - if (nm_clear_g_cancellable (&priv->deactivating_cancellable)) - nm_assert_not_reached (); - - if (NM_DEVICE_GET_CLASS (self)->deactivate_async) { - /* FIXME: the virtual function deactivate_async() has only this caller here. - * And the NMDevice subtypes are well aware of the circumstances when they - * are called. We shall make the function less generic and thus (as the scope - * is narrower) more convenient. - * - * - Drop the callback argument. Instead, when deactivate_async() completes, the - * subtype shall call a method _nm_device_deactivate_async_done(). Because as - * it is currently, subtypes need to pretend this callback and the user-data - * would be opaque, and carry it around. When it's in fact very clear what this - * is. - * - * - Also drop the GCancellable argument. Upon cancellation, NMDevice shall - * call another virtual function deactivate_async_abort(). As it is currently, - * callers need to register to the cancelled signal of the cancellable. It - * seems simpler to just implement the deactivate_async_abort() function. - * On the other hand, some implementations actually use the GCancellable. - * So, NMDevice shall do both: it shall both pass a cancellable, but also - * invoke deactivate_async_abort(). It allow the implementation to honor - * whatever is simpler for their purpose. - * - * - sometimes, the subclass can complete right away. Scheduling the completion - * in an idle handler is cumbersome. Allow the function to return FALSE to - * indicate that the device is already deactivated and the callback (or - * _nm_device_deactivate_async_done()) won't be invoked. - */ - priv->deactivating_cancellable = g_cancellable_new (); - NM_DEVICE_GET_CLASS (self)->deactivate_async (self, - priv->deactivating_cancellable, - deactivate_async_ready, - GUINT_TO_POINTER (reason)); - } else - deactivate_ready (self, reason); +deactivate_dispatcher_complete(NMDispatcherCallId *call_id, gpointer user_data) +{ + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceStateReason reason; + + g_return_if_fail(call_id == priv->dispatcher.call_id); + g_return_if_fail(priv->dispatcher.post_state == NM_DEVICE_STATE_DISCONNECTED); + + reason = priv->state_reason; + + priv->dispatcher.call_id = NULL; + priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; + priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; + + if (nm_clear_g_cancellable(&priv->deactivating_cancellable)) + nm_assert_not_reached(); + + if (NM_DEVICE_GET_CLASS(self)->deactivate_async) { + /* FIXME: the virtual function deactivate_async() has only this caller here. + * And the NMDevice subtypes are well aware of the circumstances when they + * are called. We shall make the function less generic and thus (as the scope + * is narrower) more convenient. + * + * - Drop the callback argument. Instead, when deactivate_async() completes, the + * subtype shall call a method _nm_device_deactivate_async_done(). Because as + * it is currently, subtypes need to pretend this callback and the user-data + * would be opaque, and carry it around. When it's in fact very clear what this + * is. + * + * - Also drop the GCancellable argument. Upon cancellation, NMDevice shall + * call another virtual function deactivate_async_abort(). As it is currently, + * callers need to register to the cancelled signal of the cancellable. It + * seems simpler to just implement the deactivate_async_abort() function. + * On the other hand, some implementations actually use the GCancellable. + * So, NMDevice shall do both: it shall both pass a cancellable, but also + * invoke deactivate_async_abort(). It allow the implementation to honor + * whatever is simpler for their purpose. + * + * - sometimes, the subclass can complete right away. Scheduling the completion + * in an idle handler is cumbersome. Allow the function to return FALSE to + * indicate that the device is already deactivated and the callback (or + * _nm_device_deactivate_async_done()) won't be invoked. + */ + priv->deactivating_cancellable = g_cancellable_new(); + NM_DEVICE_GET_CLASS(self)->deactivate_async(self, + priv->deactivating_cancellable, + deactivate_async_ready, + GUINT_TO_POINTER(reason)); + } else + deactivate_ready(self, reason); } static void -_set_state_full (NMDevice *self, - NMDeviceState state, - NMDeviceStateReason reason, - gboolean quitting) -{ - NMDevicePrivate *priv; - NMDeviceState old_state; - gs_unref_object NMActRequest *req = NULL; - gboolean no_firmware = FALSE; - NMSettingsConnection *sett_conn; - NMSettingSriov *s_sriov; - gboolean concheck_now; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE (self); - - /* Track re-entry */ - g_warn_if_fail (priv->in_state_changed == FALSE); - - old_state = priv->state; - - if ( state == NM_DEVICE_STATE_FAILED - && nm_device_sys_iface_state_is_external_or_assume (self)) { - /* Avoid tearing down assumed connection, assume it's connected */ - state = NM_DEVICE_STATE_ACTIVATED; - reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; - } - - /* Do nothing if state isn't changing, but as a special case allow - * re-setting UNAVAILABLE if the device is missing firmware so that we - * can retry device initialization. - */ - if ( (priv->state == state) - && ( state != NM_DEVICE_STATE_UNAVAILABLE - || !priv->firmware_missing)) { - _LOGD (LOGD_DEVICE, "state change: %s -> %s (reason '%s', sys-iface-state: '%s'%s)", - nm_device_state_to_str (old_state), - nm_device_state_to_str (state), - reason_to_string_a (reason), - _sys_iface_state_to_str (priv->sys_iface_state), - priv->firmware_missing ? ", missing firmware" : ""); - return; - } - - _LOGI (LOGD_DEVICE, "state change: %s -> %s (reason '%s', sys-iface-state: '%s')", - nm_device_state_to_str (old_state), - nm_device_state_to_str (state), - reason_to_string_a (reason), - _sys_iface_state_to_str (priv->sys_iface_state)); - - /* in order to prevent triggering any callback caused - * by the device not having any pending action anymore - * we add one here that gets removed at the end of the function */ - nm_device_add_pending_action (self, - NM_PENDING_ACTION_IN_STATE_CHANGE, - TRUE); - priv->in_state_changed = TRUE; - - priv->state = state; - priv->state_reason = reason; - - queued_state_clear (self); - - dispatcher_cleanup (self); - - nm_clear_g_cancellable (&priv->deactivating_cancellable); - - /* Cache the activation request for the dispatcher */ - req = nm_g_object_ref (priv->act_request.obj); - - if ( state > NM_DEVICE_STATE_UNMANAGED - && state <= NM_DEVICE_STATE_ACTIVATED - && nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_NOW_MANAGED - && NM_IN_SET_TYPED (NMDeviceSysIfaceState, - priv->sys_iface_state, - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - 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 - || state >= NM_DEVICE_STATE_ACTIVATED) - priv->auth_retries = NM_DEVICE_AUTH_RETRIES_UNSET; - - 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); - if (old_state > NM_DEVICE_STATE_UNAVAILABLE) { - _clear_queued_act_request (priv, - NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); - } - } - - /* Update the available connections list when a device first becomes available */ - if (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED) - nm_device_recheck_available_connections (self); - - if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_DEACTIVATING) { - if (nm_clear_g_free (&priv->current_stable_id)) - _LOGT (LOGD_DEVICE, "stable-id: clear"); - } - - /* Handle the new state here; but anything that could trigger - * another state change should be done below. - */ - switch (state) { - case NM_DEVICE_STATE_UNMANAGED: - nm_device_set_firmware_missing (self, FALSE); - if (old_state > NM_DEVICE_STATE_UNMANAGED) { - if (priv->sys_iface_state != NM_DEVICE_SYS_IFACE_STATE_MANAGED) { - nm_device_cleanup (self, reason, - priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_REMOVED - ? CLEANUP_TYPE_REMOVED - : CLEANUP_TYPE_KEEP); - } else { - /* Clean up if the device is now unmanaged but was activated */ - if (nm_device_get_act_request (self)) - nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE); - nm_device_take_down (self, TRUE); - nm_device_hw_addr_reset (self, "unmanage"); - set_nm_ipv6ll (self, FALSE); - restore_ip6_properties (self); - break; - } - } - break; - case NM_DEVICE_STATE_UNAVAILABLE: - if (old_state == NM_DEVICE_STATE_UNMANAGED) { - save_ip6_properties (self); - if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) - ip6_managed_setup (self); - device_init_static_sriov_num_vfs (self); - } - - if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) { - if (old_state == NM_DEVICE_STATE_UNMANAGED || priv->firmware_missing) { - if (!nm_device_bring_up (self, TRUE, &no_firmware) && no_firmware) - _LOGW (LOGD_PLATFORM, "firmware may be missing."); - nm_device_set_firmware_missing (self, no_firmware ? TRUE : FALSE); - } - - /* Ensure the device gets deactivated in response to stuff like - * carrier changes or rfkill. But don't deactivate devices that are - * about to assume a connection since that defeats the purpose of - * assuming the device's existing connection. - * - * Note that we "deactivate" the device even when coming from - * UNMANAGED, to ensure that it's in a clean state. - */ - nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE); - } - break; - case NM_DEVICE_STATE_DISCONNECTED: - if (old_state > NM_DEVICE_STATE_DISCONNECTED) { - /* Ensure devices that previously assumed a connection now have - * userspace IPv6LL enabled. - */ - set_nm_ipv6ll (self, TRUE); - - nm_device_cleanup (self, reason, CLEANUP_TYPE_DECONFIGURE); - } else if (old_state < NM_DEVICE_STATE_DISCONNECTED) { - if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) { - /* Ensure IPv6 is set up as it may not have been done when - * entering the UNAVAILABLE state depending on the reason. - */ - ip6_managed_setup (self); - } - } - break; - case NM_DEVICE_STATE_PREPARE: - nm_device_update_initial_hw_address (self); - break; - case NM_DEVICE_STATE_NEED_AUTH: - if (old_state > NM_DEVICE_STATE_NEED_AUTH) { - /* Clean up any half-done IP operations if the device's layer2 - * finds out it needs authentication during IP config. - */ - _cleanup_ip_pre (self, AF_INET, CLEANUP_TYPE_DECONFIGURE); - _cleanup_ip_pre (self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); - } - break; - default: - break; - } - - /* Reset intern autoconnect flags when the device is activating or connected. */ - if ( state >= NM_DEVICE_STATE_PREPARE - && state <= NM_DEVICE_STATE_ACTIVATED) - nm_device_autoconnect_blocked_unset (self, NM_DEVICE_AUTOCONNECT_BLOCKED_INTERNAL); - - _notify (self, PROP_STATE); - _notify (self, PROP_STATE_REASON); - nm_dbus_object_emit_signal (NM_DBUS_OBJECT (self), - &interface_info_device, - &signal_info_state_changed, - "(uuu)", - (guint32) state, - (guint32) old_state, - (guint32) reason); - g_signal_emit (self, signals[STATE_CHANGED], 0, (guint) state, (guint) old_state, (guint) reason); - - /* Post-process the event after internal notification */ - - switch (state) { - case NM_DEVICE_STATE_UNAVAILABLE: - /* If the device can activate now (ie, it's got a carrier, the supplicant - * is active, or whatever) schedule a delayed transition to DISCONNECTED - * to get things rolling. The device can't transition immediately because - * we can't change states again from the state handler for a variety of - * reasons. - */ - if (nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { - nm_device_queue_recheck_available (self, - NM_DEVICE_STATE_REASON_NONE, - NM_DEVICE_STATE_REASON_NONE); - } else { - _LOGD (LOGD_DEVICE, "device not yet available for transition to DISCONNECTED"); - } - break; - case NM_DEVICE_STATE_DEACTIVATING: - _cancel_activation (self); - - /* We cache the ignore_carrier state to not react on config-reloads while the connection - * is active. But on deactivating, reset the ignore-carrier flag to the current state. */ - priv->ignore_carrier = nm_config_data_get_ignore_carrier (NM_CONFIG_GET_DATA, self); - - if (quitting) { - nm_dispatcher_call_device_sync (NM_DISPATCHER_ACTION_PRE_DOWN, - self, req); - } else { - priv->dispatcher.post_state = NM_DEVICE_STATE_DISCONNECTED; - priv->dispatcher.post_state_reason = reason; - if (!nm_dispatcher_call_device (NM_DISPATCHER_ACTION_PRE_DOWN, - self, - req, - deactivate_dispatcher_complete, - self, - &priv->dispatcher.call_id)) { - /* Just proceed on errors */ - deactivate_dispatcher_complete (0, self); - } - - if ( priv->ifindex > 0 - && (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) { - priv->sriov_reset_pending++; - sriov_op_queue (self, - 0, - NM_TERNARY_TRUE, - sriov_reset_on_deactivate_cb, - nm_utils_user_data_pack (self, (gpointer) reason)); - } - } - - nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); - break; - case NM_DEVICE_STATE_DISCONNECTED: - if ( priv->queued_act_request - && !priv->queued_act_request_is_waiting_for_carrier) { - gs_unref_object NMActRequest *queued_req = NULL; - - queued_req = g_steal_pointer (&priv->queued_act_request); - _device_activate (self, queued_req); - } - break; - case NM_DEVICE_STATE_ACTIVATED: - _LOGI (LOGD_DEVICE, "Activation: successful, device activated."); - nm_device_update_metered (self); - nm_dispatcher_call_device (NM_DISPATCHER_ACTION_UP, - self, - req, - NULL, NULL, NULL); - - if (priv->proxy_config) - _pacrunner_manager_add (self); - break; - case NM_DEVICE_STATE_FAILED: - /* Usually upon failure the activation chain is interrupted in - * one of the stages; but in some cases the device fails for - * external events (as a failure of master connection) while - * the activation sequence is running and so we need to ensure - * that the chain is terminated here. - */ - _cancel_activation (self); - - sett_conn = nm_device_get_settings_connection (self); - _LOGW (LOGD_DEVICE | LOGD_WIFI, - "Activation: failed for connection '%s'", - sett_conn ? nm_settings_connection_get_id (sett_conn) : "<unknown>"); - - /* Notify any slaves of the unexpected failure */ - nm_device_master_release_slaves (self); - - /* If the connection doesn't yet have a timestamp, set it to zero so that - * we can distinguish between connections we've tried to activate and have - * failed (zero timestamp), connections that succeeded (non-zero timestamp), - * and those we haven't tried yet (no timestamp). - */ - if (sett_conn && !nm_settings_connection_get_timestamp (sett_conn, NULL)) - nm_settings_connection_update_timestamp (sett_conn, (guint64) 0); - - if ( priv->ifindex > 0 - && (s_sriov = nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) { - priv->sriov_reset_pending++; - sriov_op_queue (self, - 0, - NM_TERNARY_TRUE, - sriov_reset_on_failure_cb, - self); - break; - } - /* Schedule the transition to DISCONNECTED. The device can't transition - * immediately because we can't change states again from the state - * handler for a variety of reasons. - */ - nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); - break; - case NM_DEVICE_STATE_IP_CHECK: - if ( priv->fw_state >= FIREWALL_STATE_INITIALIZED - && priv->ip_iface - && !nm_device_sys_iface_state_is_external (self)) { - priv->fw_state = FIREWALL_STATE_WAIT_IP_CONFIG; - fw_change_zone (self); - } else - nm_device_start_ip_check (self); - - /* IP-related properties are only valid when the device has IP configuration; - * now that it does, ensure their change notifications are emitted. - */ - notify_ip_properties (self); - break; - case NM_DEVICE_STATE_SECONDARIES: - ip_check_gw_ping_cleanup (self); - _LOGD (LOGD_DEVICE, "device entered SECONDARIES state"); - break; - default: - break; - } - - if (state > NM_DEVICE_STATE_DISCONNECTED) - delete_on_deactivate_unschedule (self); - - if ( (old_state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_DEACTIVATING) - && (state != NM_DEVICE_STATE_DEACTIVATING)) { - if (quitting) { - nm_dispatcher_call_device_sync (NM_DISPATCHER_ACTION_DOWN, - self, req); - } else { - nm_dispatcher_call_device (NM_DISPATCHER_ACTION_DOWN, - self, - req, - NULL, NULL, NULL); - } - } - - /* IP-related properties are only valid when the device has IP configuration. - * If it no longer does, ensure their change notifications are emitted. - */ - if ( ip_config_valid (old_state) - && !ip_config_valid (state)) - notify_ip_properties (self); - - concheck_now = NM_IN_SET (state, NM_DEVICE_STATE_ACTIVATED, - NM_DEVICE_STATE_DISCONNECTED) - || old_state >= NM_DEVICE_STATE_ACTIVATED; - concheck_update_interval (self, AF_INET, concheck_now); - concheck_update_interval (self, AF_INET6, concheck_now); - - priv->in_state_changed = FALSE; - nm_device_remove_pending_action (self, - NM_PENDING_ACTION_IN_STATE_CHANGE, - TRUE); - - if ((old_state > NM_DEVICE_STATE_UNMANAGED) != (state > NM_DEVICE_STATE_UNMANAGED)) - _notify (self, PROP_MANAGED); +_set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting) +{ + NMDevicePrivate *priv; + NMDeviceState old_state; + gs_unref_object NMActRequest *req = NULL; + gboolean no_firmware = FALSE; + NMSettingsConnection * sett_conn; + NMSettingSriov * s_sriov; + gboolean concheck_now; + + g_return_if_fail(NM_IS_DEVICE(self)); + + priv = NM_DEVICE_GET_PRIVATE(self); + + /* Track re-entry */ + g_warn_if_fail(priv->in_state_changed == FALSE); + + old_state = priv->state; + + if (state == NM_DEVICE_STATE_FAILED && nm_device_sys_iface_state_is_external_or_assume(self)) { + /* Avoid tearing down assumed connection, assume it's connected */ + state = NM_DEVICE_STATE_ACTIVATED; + reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; + } + + /* Do nothing if state isn't changing, but as a special case allow + * re-setting UNAVAILABLE if the device is missing firmware so that we + * can retry device initialization. + */ + if ((priv->state == state) + && (state != NM_DEVICE_STATE_UNAVAILABLE || !priv->firmware_missing)) { + _LOGD(LOGD_DEVICE, + "state change: %s -> %s (reason '%s', sys-iface-state: '%s'%s)", + nm_device_state_to_str(old_state), + nm_device_state_to_str(state), + reason_to_string_a(reason), + _sys_iface_state_to_str(priv->sys_iface_state), + priv->firmware_missing ? ", missing firmware" : ""); + return; + } + + _LOGI(LOGD_DEVICE, + "state change: %s -> %s (reason '%s', sys-iface-state: '%s')", + nm_device_state_to_str(old_state), + nm_device_state_to_str(state), + reason_to_string_a(reason), + _sys_iface_state_to_str(priv->sys_iface_state)); + + /* in order to prevent triggering any callback caused + * by the device not having any pending action anymore + * we add one here that gets removed at the end of the function */ + nm_device_add_pending_action(self, NM_PENDING_ACTION_IN_STATE_CHANGE, TRUE); + priv->in_state_changed = TRUE; + + priv->state = state; + priv->state_reason = reason; + + queued_state_clear(self); + + dispatcher_cleanup(self); + + nm_clear_g_cancellable(&priv->deactivating_cancellable); + + /* Cache the activation request for the dispatcher */ + req = nm_g_object_ref(priv->act_request.obj); + + if (state > NM_DEVICE_STATE_UNMANAGED && state <= NM_DEVICE_STATE_ACTIVATED + && nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_NOW_MANAGED + && NM_IN_SET_TYPED(NMDeviceSysIfaceState, + priv->sys_iface_state, + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + 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 || state >= NM_DEVICE_STATE_ACTIVATED) + priv->auth_retries = NM_DEVICE_AUTH_RETRIES_UNSET; + + 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); + if (old_state > NM_DEVICE_STATE_UNAVAILABLE) { + _clear_queued_act_request(priv, NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); + } + } + + /* Update the available connections list when a device first becomes available */ + if (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED) + nm_device_recheck_available_connections(self); + + if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_DEACTIVATING) { + if (nm_clear_g_free(&priv->current_stable_id)) + _LOGT(LOGD_DEVICE, "stable-id: clear"); + } + + /* Handle the new state here; but anything that could trigger + * another state change should be done below. + */ + switch (state) { + case NM_DEVICE_STATE_UNMANAGED: + nm_device_set_firmware_missing(self, FALSE); + if (old_state > NM_DEVICE_STATE_UNMANAGED) { + if (priv->sys_iface_state != NM_DEVICE_SYS_IFACE_STATE_MANAGED) { + nm_device_cleanup(self, + reason, + priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_REMOVED + ? CLEANUP_TYPE_REMOVED + : CLEANUP_TYPE_KEEP); + } else { + /* Clean up if the device is now unmanaged but was activated */ + if (nm_device_get_act_request(self)) + nm_device_cleanup(self, reason, CLEANUP_TYPE_DECONFIGURE); + nm_device_take_down(self, TRUE); + nm_device_hw_addr_reset(self, "unmanage"); + set_nm_ipv6ll(self, FALSE); + restore_ip6_properties(self); + break; + } + } + break; + case NM_DEVICE_STATE_UNAVAILABLE: + if (old_state == NM_DEVICE_STATE_UNMANAGED) { + save_ip6_properties(self); + if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) + ip6_managed_setup(self); + device_init_static_sriov_num_vfs(self); + } + + if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) { + if (old_state == NM_DEVICE_STATE_UNMANAGED || priv->firmware_missing) { + if (!nm_device_bring_up(self, TRUE, &no_firmware) && no_firmware) + _LOGW(LOGD_PLATFORM, "firmware may be missing."); + nm_device_set_firmware_missing(self, no_firmware ? TRUE : FALSE); + } + + /* Ensure the device gets deactivated in response to stuff like + * carrier changes or rfkill. But don't deactivate devices that are + * about to assume a connection since that defeats the purpose of + * assuming the device's existing connection. + * + * Note that we "deactivate" the device even when coming from + * UNMANAGED, to ensure that it's in a clean state. + */ + nm_device_cleanup(self, reason, CLEANUP_TYPE_DECONFIGURE); + } + break; + case NM_DEVICE_STATE_DISCONNECTED: + if (old_state > NM_DEVICE_STATE_DISCONNECTED) { + /* Ensure devices that previously assumed a connection now have + * userspace IPv6LL enabled. + */ + set_nm_ipv6ll(self, TRUE); + + nm_device_cleanup(self, reason, CLEANUP_TYPE_DECONFIGURE); + } else if (old_state < NM_DEVICE_STATE_DISCONNECTED) { + if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) { + /* Ensure IPv6 is set up as it may not have been done when + * entering the UNAVAILABLE state depending on the reason. + */ + ip6_managed_setup(self); + } + } + break; + case NM_DEVICE_STATE_PREPARE: + nm_device_update_initial_hw_address(self); + break; + case NM_DEVICE_STATE_NEED_AUTH: + if (old_state > NM_DEVICE_STATE_NEED_AUTH) { + /* Clean up any half-done IP operations if the device's layer2 + * finds out it needs authentication during IP config. + */ + _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_DECONFIGURE); + _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); + } + break; + default: + break; + } + + /* Reset intern autoconnect flags when the device is activating or connected. */ + if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) + nm_device_autoconnect_blocked_unset(self, NM_DEVICE_AUTOCONNECT_BLOCKED_INTERNAL); + + _notify(self, PROP_STATE); + _notify(self, PROP_STATE_REASON); + nm_dbus_object_emit_signal(NM_DBUS_OBJECT(self), + &interface_info_device, + &signal_info_state_changed, + "(uuu)", + (guint32) state, + (guint32) old_state, + (guint32) reason); + g_signal_emit(self, + signals[STATE_CHANGED], + 0, + (guint) state, + (guint) old_state, + (guint) reason); + + /* Post-process the event after internal notification */ + + switch (state) { + case NM_DEVICE_STATE_UNAVAILABLE: + /* If the device can activate now (ie, it's got a carrier, the supplicant + * is active, or whatever) schedule a delayed transition to DISCONNECTED + * to get things rolling. The device can't transition immediately because + * we can't change states again from the state handler for a variety of + * reasons. + */ + if (nm_device_is_available(self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { + nm_device_queue_recheck_available(self, + NM_DEVICE_STATE_REASON_NONE, + NM_DEVICE_STATE_REASON_NONE); + } else { + _LOGD(LOGD_DEVICE, "device not yet available for transition to DISCONNECTED"); + } + break; + case NM_DEVICE_STATE_DEACTIVATING: + _cancel_activation(self); + + /* We cache the ignore_carrier state to not react on config-reloads while the connection + * is active. But on deactivating, reset the ignore-carrier flag to the current state. */ + priv->ignore_carrier = nm_config_data_get_ignore_carrier(NM_CONFIG_GET_DATA, self); + + if (quitting) { + nm_dispatcher_call_device_sync(NM_DISPATCHER_ACTION_PRE_DOWN, self, req); + } else { + priv->dispatcher.post_state = NM_DEVICE_STATE_DISCONNECTED; + priv->dispatcher.post_state_reason = reason; + if (!nm_dispatcher_call_device(NM_DISPATCHER_ACTION_PRE_DOWN, + self, + req, + deactivate_dispatcher_complete, + self, + &priv->dispatcher.call_id)) { + /* Just proceed on errors */ + deactivate_dispatcher_complete(0, self); + } + + if (priv->ifindex > 0 + && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { + priv->sriov_reset_pending++; + sriov_op_queue(self, + 0, + NM_TERNARY_TRUE, + sriov_reset_on_deactivate_cb, + nm_utils_user_data_pack(self, GINT_TO_POINTER(reason))); + } + } + + nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); + break; + case NM_DEVICE_STATE_DISCONNECTED: + if (priv->queued_act_request && !priv->queued_act_request_is_waiting_for_carrier) { + gs_unref_object NMActRequest *queued_req = NULL; + + queued_req = g_steal_pointer(&priv->queued_act_request); + _device_activate(self, queued_req); + } + break; + case NM_DEVICE_STATE_ACTIVATED: + _LOGI(LOGD_DEVICE, "Activation: successful, device activated."); + nm_device_update_metered(self); + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_UP, self, req, NULL, NULL, NULL); + + if (priv->proxy_config) + _pacrunner_manager_add(self); + break; + case NM_DEVICE_STATE_FAILED: + /* Usually upon failure the activation chain is interrupted in + * one of the stages; but in some cases the device fails for + * external events (as a failure of master connection) while + * the activation sequence is running and so we need to ensure + * that the chain is terminated here. + */ + _cancel_activation(self); + + sett_conn = nm_device_get_settings_connection(self); + _LOGW(LOGD_DEVICE | LOGD_WIFI, + "Activation: failed for connection '%s'", + sett_conn ? nm_settings_connection_get_id(sett_conn) : "<unknown>"); + + /* Notify any slaves of the unexpected failure */ + nm_device_master_release_slaves(self); + + /* If the connection doesn't yet have a timestamp, set it to zero so that + * we can distinguish between connections we've tried to activate and have + * failed (zero timestamp), connections that succeeded (non-zero timestamp), + * and those we haven't tried yet (no timestamp). + */ + if (sett_conn && !nm_settings_connection_get_timestamp(sett_conn, NULL)) + nm_settings_connection_update_timestamp(sett_conn, (guint64) 0); + + if (priv->ifindex > 0 + && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { + priv->sriov_reset_pending++; + sriov_op_queue(self, 0, NM_TERNARY_TRUE, sriov_reset_on_failure_cb, self); + break; + } + /* Schedule the transition to DISCONNECTED. The device can't transition + * immediately because we can't change states again from the state + * handler for a variety of reasons. + */ + nm_device_queue_state(self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); + break; + case NM_DEVICE_STATE_IP_CHECK: + if (priv->fw_state >= FIREWALL_STATE_INITIALIZED && priv->ip_iface + && !nm_device_sys_iface_state_is_external(self)) { + priv->fw_state = FIREWALL_STATE_WAIT_IP_CONFIG; + fw_change_zone(self); + } else + nm_device_start_ip_check(self); + + /* IP-related properties are only valid when the device has IP configuration; + * now that it does, ensure their change notifications are emitted. + */ + notify_ip_properties(self); + break; + case NM_DEVICE_STATE_SECONDARIES: + ip_check_gw_ping_cleanup(self); + _LOGD(LOGD_DEVICE, "device entered SECONDARIES state"); + break; + default: + break; + } + + if (state > NM_DEVICE_STATE_DISCONNECTED) + delete_on_deactivate_unschedule(self); + + if ((old_state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_DEACTIVATING) + && (state != NM_DEVICE_STATE_DEACTIVATING)) { + if (quitting) { + nm_dispatcher_call_device_sync(NM_DISPATCHER_ACTION_DOWN, self, req); + } else { + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DOWN, self, req, NULL, NULL, NULL); + } + } + + /* IP-related properties are only valid when the device has IP configuration. + * If it no longer does, ensure their change notifications are emitted. + */ + if (ip_config_valid(old_state) && !ip_config_valid(state)) + notify_ip_properties(self); + + concheck_now = NM_IN_SET(state, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_DISCONNECTED) + || old_state >= NM_DEVICE_STATE_ACTIVATED; + concheck_update_interval(self, AF_INET, concheck_now); + concheck_update_interval(self, AF_INET6, concheck_now); + + priv->in_state_changed = FALSE; + nm_device_remove_pending_action(self, NM_PENDING_ACTION_IN_STATE_CHANGE, TRUE); + + if ((old_state > NM_DEVICE_STATE_UNMANAGED) != (state > NM_DEVICE_STATE_UNMANAGED)) + _notify(self, PROP_MANAGED); } void -nm_device_state_changed (NMDevice *self, - NMDeviceState state, - NMDeviceStateReason reason) +nm_device_state_changed(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason) { - _set_state_full (self, state, reason, FALSE); + _set_state_full(self, state, reason, FALSE); } static gboolean -queued_state_set (gpointer user_data) +queued_state_set(gpointer user_data) { - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceState new_state; - NMDeviceStateReason new_reason; + NMDevice * self = NM_DEVICE(user_data); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceState new_state; + NMDeviceStateReason new_reason; - nm_assert (priv->queued_state.id); + nm_assert(priv->queued_state.id); - _LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", - nm_device_state_to_str (priv->queued_state.state), - reason_to_string_a (priv->queued_state.reason), - priv->queued_state.id, - "change state"); + _LOGD(LOGD_DEVICE, + "queue-state[%s, reason:%s, id:%u]: %s", + nm_device_state_to_str(priv->queued_state.state), + reason_to_string_a(priv->queued_state.reason), + priv->queued_state.id, + "change state"); - /* Clear queued state struct before triggering state change, since - * the state change may queue another state. - */ - priv->queued_state.id = 0; - new_state = priv->queued_state.state; - new_reason = priv->queued_state.reason; + /* Clear queued state struct before triggering state change, since + * the state change may queue another state. + */ + priv->queued_state.id = 0; + new_state = priv->queued_state.state; + new_reason = priv->queued_state.reason; - nm_device_state_changed (self, new_state, new_reason); - nm_device_remove_pending_action (self, queued_state_to_string (new_state), TRUE); + nm_device_state_changed(self, new_state, new_reason); + nm_device_remove_pending_action(self, queued_state_to_string(new_state), TRUE); - return G_SOURCE_REMOVE; + return G_SOURCE_REMOVE; } void -nm_device_queue_state (NMDevice *self, - NMDeviceState state, - NMDeviceStateReason reason) -{ - NMDevicePrivate *priv; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE (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", - nm_device_state_to_str (priv->queued_state.state), - reason_to_string_a (priv->queued_state.reason), - priv->queued_state.id, - "ignore queuing same state change", - NM_PRINT_FMT_QUOTED (priv->queued_state.reason != reason, - " (reason differs: ", reason_to_string_a (reason), ")", "")); - return; - } - - /* Add pending action for the new state before clearing the queued states, so - * that we don't accidentally pop all pending states and reach 'startup complete' */ - nm_device_add_pending_action (self, queued_state_to_string (state), TRUE); - - /* 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", - nm_device_state_to_str (priv->queued_state.state), - reason_to_string_a (priv->queued_state.reason), - priv->queued_state.id, - "replace previously queued state change"); - nm_clear_g_source (&priv->queued_state.id); - nm_device_remove_pending_action (self, queued_state_to_string (priv->queued_state.state), TRUE); - } - - priv->queued_state.state = state; - priv->queued_state.reason = reason; - priv->queued_state.id = g_idle_add (queued_state_set, self); - - _LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", - nm_device_state_to_str (state), - reason_to_string_a (reason), - priv->queued_state.id, - "queue state change"); +nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason) +{ + NMDevicePrivate *priv; + + g_return_if_fail(NM_IS_DEVICE(self)); + + priv = NM_DEVICE_GET_PRIVATE(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", + nm_device_state_to_str(priv->queued_state.state), + reason_to_string_a(priv->queued_state.reason), + priv->queued_state.id, + "ignore queuing same state change", + NM_PRINT_FMT_QUOTED(priv->queued_state.reason != reason, + " (reason differs: ", + reason_to_string_a(reason), + ")", + "")); + return; + } + + /* Add pending action for the new state before clearing the queued states, so + * that we don't accidentally pop all pending states and reach 'startup complete' */ + nm_device_add_pending_action(self, queued_state_to_string(state), TRUE); + + /* 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", + nm_device_state_to_str(priv->queued_state.state), + reason_to_string_a(priv->queued_state.reason), + priv->queued_state.id, + "replace previously queued state change"); + nm_clear_g_source(&priv->queued_state.id); + nm_device_remove_pending_action(self, + queued_state_to_string(priv->queued_state.state), + TRUE); + } + + priv->queued_state.state = state; + priv->queued_state.reason = reason; + priv->queued_state.id = g_idle_add(queued_state_set, self); + + _LOGD(LOGD_DEVICE, + "queue-state[%s, reason:%s, id:%u]: %s", + nm_device_state_to_str(state), + reason_to_string_a(reason), + priv->queued_state.id, + "queue state change"); } static void -queued_state_clear (NMDevice *self) +queued_state_clear(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (!priv->queued_state.id) - return; + if (!priv->queued_state.id) + return; - _LOGD (LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", - nm_device_state_to_str (priv->queued_state.state), - reason_to_string_a (priv->queued_state.reason), - priv->queued_state.id, - "clear queued state change"); - nm_clear_g_source (&priv->queued_state.id); - nm_device_remove_pending_action (self, queued_state_to_string (priv->queued_state.state), TRUE); + _LOGD(LOGD_DEVICE, + "queue-state[%s, reason:%s, id:%u]: %s", + nm_device_state_to_str(priv->queued_state.state), + reason_to_string_a(priv->queued_state.reason), + priv->queued_state.id, + "clear queued state change"); + nm_clear_g_source(&priv->queued_state.id); + nm_device_remove_pending_action(self, queued_state_to_string(priv->queued_state.state), TRUE); } NMDeviceState -nm_device_get_state (NMDevice *self) +nm_device_get_state(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NM_DEVICE_STATE_UNKNOWN); + g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_STATE_UNKNOWN); - return NM_DEVICE_GET_PRIVATE (self)->state; + return NM_DEVICE_GET_PRIVATE(self)->state; } /*****************************************************************************/ /* NMConfigDevice interface related stuff */ const char * -nm_device_get_hw_address (NMDevice *self) +nm_device_get_hw_address(NMDevice *self) { - NMDevicePrivate *priv; - char buf[NM_UTILS_HWADDR_LEN_MAX]; - gsize l; + NMDevicePrivate *priv; + char buf[NM_UTILS_HWADDR_LEN_MAX]; + gsize l; - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert ( (!priv->hw_addr && priv->hw_addr_len == 0) - || ( priv->hw_addr - && _nm_utils_hwaddr_aton (priv->hw_addr, buf, sizeof (buf), &l) - && l == priv->hw_addr_len)); + nm_assert((!priv->hw_addr && priv->hw_addr_len == 0) + || (priv->hw_addr && _nm_utils_hwaddr_aton(priv->hw_addr, buf, sizeof(buf), &l) + && l == priv->hw_addr_len)); - return priv->hw_addr; + return priv->hw_addr; } gboolean -nm_device_update_hw_address (NMDevice *self) -{ - NMDevicePrivate *priv; - const guint8 *hwaddr; - gsize hwaddrlen = 0; - - priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->ifindex <= 0) - return FALSE; - - hwaddr = nm_platform_link_get_address (nm_device_get_platform (self), priv->ifindex, &hwaddrlen); - - if ( priv->type == NM_DEVICE_TYPE_ETHERNET - && hwaddr - && nm_utils_hwaddr_matches (hwaddr, hwaddrlen, nm_ip_addr_zero.addr_eth, sizeof (nm_ip_addr_zero.addr_eth))) - hwaddrlen = 0; - - if (!hwaddrlen) - return FALSE; - - if ( priv->hw_addr_len - && priv->hw_addr_len != hwaddrlen) { - char s_buf[NM_UTILS_HWADDR_LEN_MAX_STR]; - - /* we cannot change the address length of a device once it is set (except - * unrealizing the device). - * - * The reason is that the permanent and initial MAC addresses also must have the - * same address length, so it's unclear what it would mean that the length changes. */ - _LOGD (LOGD_PLATFORM | LOGD_DEVICE, - "hw-addr: read a MAC address with differing length (%s vs. %s)", - priv->hw_addr, - nm_utils_hwaddr_ntoa_buf (hwaddr, hwaddrlen, TRUE, s_buf, sizeof (s_buf))); - return FALSE; - } - - if ( priv->hw_addr - && nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) - return FALSE; - - g_free (priv->hw_addr); - priv->hw_addr_len_ = hwaddrlen; - priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen); - - _LOGD (LOGD_PLATFORM | LOGD_DEVICE, "hw-addr: hardware address now %s", priv->hw_addr); - _notify (self, PROP_HW_ADDRESS); - - if ( !priv->hw_addr_initial - || ( priv->hw_addr_type == HW_ADDR_TYPE_UNSET - && priv->state < NM_DEVICE_STATE_PREPARE - && !nm_device_is_activating (self))) { - /* when we get a hw_addr the first time or while the device - * is not activated (with no explicit hw address set), always - * update our initial hw-address as well. */ - nm_device_update_initial_hw_address (self); - } - return TRUE; +nm_device_update_hw_address(NMDevice *self) +{ + NMDevicePrivate *priv; + const guint8 * hwaddr; + gsize hwaddrlen = 0; + + priv = NM_DEVICE_GET_PRIVATE(self); + if (priv->ifindex <= 0) + return FALSE; + + hwaddr = nm_platform_link_get_address(nm_device_get_platform(self), priv->ifindex, &hwaddrlen); + + if (priv->type == NM_DEVICE_TYPE_ETHERNET && hwaddr + && nm_utils_hwaddr_matches(hwaddr, + hwaddrlen, + &nm_ether_addr_zero, + sizeof(nm_ether_addr_zero))) + hwaddrlen = 0; + + if (!hwaddrlen) + return FALSE; + + if (priv->hw_addr_len && priv->hw_addr_len != hwaddrlen) { + char s_buf[NM_UTILS_HWADDR_LEN_MAX_STR]; + + /* we cannot change the address length of a device once it is set (except + * unrealizing the device). + * + * The reason is that the permanent and initial MAC addresses also must have the + * same address length, so it's unclear what it would mean that the length changes. */ + _LOGD(LOGD_PLATFORM | LOGD_DEVICE, + "hw-addr: read a MAC address with differing length (%s vs. %s)", + priv->hw_addr, + _nm_utils_hwaddr_ntoa(hwaddr, hwaddrlen, TRUE, s_buf, sizeof(s_buf))); + return FALSE; + } + + if (priv->hw_addr && nm_utils_hwaddr_matches(priv->hw_addr, -1, hwaddr, hwaddrlen)) + return FALSE; + + g_free(priv->hw_addr); + priv->hw_addr_len_ = hwaddrlen; + priv->hw_addr = nm_utils_hwaddr_ntoa(hwaddr, hwaddrlen); + + _LOGD(LOGD_PLATFORM | LOGD_DEVICE, "hw-addr: hardware address now %s", priv->hw_addr); + _notify(self, PROP_HW_ADDRESS); + + if (!priv->hw_addr_initial + || (priv->hw_addr_type == HW_ADDR_TYPE_UNSET && priv->state < NM_DEVICE_STATE_PREPARE + && !nm_device_is_activating(self))) { + /* when we get a hw_addr the first time or while the device + * is not activated (with no explicit hw address set), always + * update our initial hw-address as well. */ + nm_device_update_initial_hw_address(self); + } + return TRUE; } void -nm_device_update_initial_hw_address (NMDevice *self) +nm_device_update_initial_hw_address(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if ( priv->hw_addr - && !nm_streq0 (priv->hw_addr_initial, priv->hw_addr)) { - if ( priv->hw_addr_initial - && priv->hw_addr_type != HW_ADDR_TYPE_UNSET) { - /* once we have the initial hw address set, we only allow - * update if the currently type is "unset". */ - return; - } - g_free (priv->hw_addr_initial); - priv->hw_addr_initial = g_strdup (priv->hw_addr); - _LOGD (LOGD_DEVICE, "hw-addr: update initial MAC address %s", - priv->hw_addr_initial); - } + if (priv->hw_addr && !nm_streq0(priv->hw_addr_initial, priv->hw_addr)) { + if (priv->hw_addr_initial && priv->hw_addr_type != HW_ADDR_TYPE_UNSET) { + /* once we have the initial hw address set, we only allow + * update if the currently type is "unset". */ + return; + } + g_free(priv->hw_addr_initial); + priv->hw_addr_initial = g_strdup(priv->hw_addr); + _LOGD(LOGD_DEVICE, "hw-addr: update initial MAC address %s", priv->hw_addr_initial); + } } void -nm_device_update_permanent_hw_address (NMDevice *self, gboolean force_freeze) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; - size_t len = 0; - gboolean success_read; - int ifindex; - const NMPlatformLink *pllink; - const NMConfigDeviceStateData *dev_state; - - if (priv->hw_addr_perm) { - /* the permanent hardware address is only read once and not - * re-read later. - * - * Except during unrealize/realize cycles, where we clear the permanent - * hardware address during unrealization. */ - return; - } - - ifindex = priv->ifindex; - if (ifindex <= 0) - return; - - /* the user is advised to configure stable MAC addresses for software devices via - * UDEV. Thus, check whether the link is fully initialized. */ - pllink = nm_platform_link_get (nm_device_get_platform (self), ifindex); - if ( !pllink - || !pllink->initialized) { - if (!force_freeze) { - /* we can afford to wait. Back off and leave the permanent MAC address - * undecided for now. */ - return; - } - /* try to refresh the link just to give UDEV a bit more time... */ - nm_platform_link_refresh (nm_device_get_platform (self), ifindex); - /* maybe the MAC address changed... */ - nm_device_update_hw_address (self); - } else if (!priv->hw_addr_len) - nm_device_update_hw_address (self); - - if (!priv->hw_addr_len) { - /* we need the current MAC address because we require the permanent MAC address - * to have the same length as the current address. - * - * Abort if there is no current MAC address. */ - return; - } - - success_read = nm_platform_link_get_permanent_address (nm_device_get_platform (self), ifindex, buf, &len); - if (success_read && priv->hw_addr_len == len) { - priv->hw_addr_perm_fake = FALSE; - priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, len); - _LOGD (LOGD_DEVICE, "hw-addr: read permanent MAC address '%s'", - priv->hw_addr_perm); - goto notify_and_out; - } - - /* we failed to read a permanent MAC address, thus we use a fake address, - * that is the current MAC address of the device. - * - * Note that the permanet MAC address of a NMDevice instance does not change - * after being set once. Thus, we use now a fake address and stick to that - * (until we unrealize the device). */ - priv->hw_addr_perm_fake = TRUE; - - /* We also persist our choice of the fake address to the device state - * file to use the same address on restart of NetworkManager. - * First, try to reload the address from the state file. */ - dev_state = nm_config_device_state_get (nm_config_get (), ifindex); - if ( dev_state - && dev_state->perm_hw_addr_fake - && nm_utils_hwaddr_aton (dev_state->perm_hw_addr_fake, buf, priv->hw_addr_len) - && !nm_utils_hwaddr_matches (buf, priv->hw_addr_len, priv->hw_addr, -1)) { - _LOGD (LOGD_PLATFORM | LOGD_ETHER, "hw-addr: %s (use from statefile: %s, current: %s)", - success_read - ? "read HW addr length of permanent MAC address differs" - : "unable to read permanent MAC address", - dev_state->perm_hw_addr_fake, - priv->hw_addr); - priv->hw_addr_perm = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len); - goto notify_and_out; - } - - _LOGD (LOGD_PLATFORM | LOGD_ETHER, "hw-addr: %s (use current: %s)", - success_read - ? "read HW addr length of permanent MAC address differs" - : "unable to read permanent MAC address", - priv->hw_addr); - priv->hw_addr_perm = g_strdup (priv->hw_addr); +nm_device_update_permanent_hw_address(NMDevice *self, gboolean force_freeze) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + size_t len = 0; + gboolean success_read; + int ifindex; + const NMPlatformLink * pllink; + const NMConfigDeviceStateData *dev_state; + + if (priv->hw_addr_perm) { + /* the permanent hardware address is only read once and not + * re-read later. + * + * Except during unrealize/realize cycles, where we clear the permanent + * hardware address during unrealization. */ + return; + } + + ifindex = priv->ifindex; + if (ifindex <= 0) + return; + + /* the user is advised to configure stable MAC addresses for software devices via + * UDEV. Thus, check whether the link is fully initialized. */ + pllink = nm_platform_link_get(nm_device_get_platform(self), ifindex); + if (!pllink || !pllink->initialized) { + if (!force_freeze) { + /* we can afford to wait. Back off and leave the permanent MAC address + * undecided for now. */ + return; + } + /* try to refresh the link just to give UDEV a bit more time... */ + nm_platform_link_refresh(nm_device_get_platform(self), ifindex); + /* maybe the MAC address changed... */ + nm_device_update_hw_address(self); + } else if (!priv->hw_addr_len) + nm_device_update_hw_address(self); + + if (!priv->hw_addr_len) { + /* we need the current MAC address because we require the permanent MAC address + * to have the same length as the current address. + * + * Abort if there is no current MAC address. */ + return; + } + + success_read = + nm_platform_link_get_permanent_address(nm_device_get_platform(self), ifindex, buf, &len); + if (success_read && priv->hw_addr_len == len) { + priv->hw_addr_perm_fake = FALSE; + priv->hw_addr_perm = nm_utils_hwaddr_ntoa(buf, len); + _LOGD(LOGD_DEVICE, "hw-addr: read permanent MAC address '%s'", priv->hw_addr_perm); + goto notify_and_out; + } + + /* we failed to read a permanent MAC address, thus we use a fake address, + * that is the current MAC address of the device. + * + * Note that the permanet MAC address of a NMDevice instance does not change + * after being set once. Thus, we use now a fake address and stick to that + * (until we unrealize the device). */ + priv->hw_addr_perm_fake = TRUE; + + /* We also persist our choice of the fake address to the device state + * file to use the same address on restart of NetworkManager. + * First, try to reload the address from the state file. */ + dev_state = nm_config_device_state_get(nm_config_get(), ifindex); + if (dev_state && dev_state->perm_hw_addr_fake + && nm_utils_hwaddr_aton(dev_state->perm_hw_addr_fake, buf, priv->hw_addr_len) + && !nm_utils_hwaddr_matches(buf, priv->hw_addr_len, priv->hw_addr, -1)) { + _LOGD(LOGD_PLATFORM | LOGD_ETHER, + "hw-addr: %s (use from statefile: %s, current: %s)", + success_read ? "read HW addr length of permanent MAC address differs" + : "unable to read permanent MAC address", + dev_state->perm_hw_addr_fake, + priv->hw_addr); + priv->hw_addr_perm = nm_utils_hwaddr_ntoa(buf, priv->hw_addr_len); + goto notify_and_out; + } + + _LOGD(LOGD_PLATFORM | LOGD_ETHER, + "hw-addr: %s (use current: %s)", + success_read ? "read HW addr length of permanent MAC address differs" + : "unable to read permanent MAC address", + priv->hw_addr); + priv->hw_addr_perm = g_strdup(priv->hw_addr); notify_and_out: - _notify (self, PROP_PERM_HW_ADDRESS); -} - -static const char * -_get_cloned_mac_address_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_addr) -{ - NMSetting *setting; - const char *addr = NULL; - - nm_assert (out_addr && !*out_addr); - - setting = nm_connection_get_setting (connection, - is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); - if (setting) { - addr = is_wifi - ? nm_setting_wireless_get_cloned_mac_address ((NMSettingWireless *) setting) - : nm_setting_wired_get_cloned_mac_address ((NMSettingWired *) setting); - } - - if (!addr) { - gs_free char *a = NULL; - - a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - is_wifi - ? NM_CON_DEFAULT ("wifi.cloned-mac-address") - : NM_CON_DEFAULT ("ethernet.cloned-mac-address"), - self); - - addr = NM_CLONED_MAC_PRESERVE; - - if (!a) { - if (is_wifi) { - NMSettingMacRandomization v; - - /* for backward compatibility, read the deprecated wifi.mac-address-randomization setting. */ - a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("wifi.mac-address-randomization"), - self); - v = _nm_utils_ascii_str_to_int64 (a, 10, - NM_SETTING_MAC_RANDOMIZATION_DEFAULT, - NM_SETTING_MAC_RANDOMIZATION_ALWAYS, - NM_SETTING_MAC_RANDOMIZATION_DEFAULT); - if (v == NM_SETTING_MAC_RANDOMIZATION_ALWAYS) - addr = NM_CLONED_MAC_RANDOM; - } - } else if ( NM_CLONED_MAC_IS_SPECIAL (a) - || nm_utils_hwaddr_valid (a, ETH_ALEN)) - addr = *out_addr = g_steal_pointer (&a); - } - - return addr; -} - -static const char * -_get_generate_mac_address_mask_setting (NMDevice *self, NMConnection *connection, gboolean is_wifi, char **out_value) -{ - NMSetting *setting; - const char *value = NULL; - char *a; - - nm_assert (out_value && !*out_value); - - setting = nm_connection_get_setting (connection, - is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); - if (setting) { - value = is_wifi - ? nm_setting_wireless_get_generate_mac_address_mask ((NMSettingWireless *) setting) - : nm_setting_wired_get_generate_mac_address_mask ((NMSettingWired *) setting); - if (value) - return value; - } - - a = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - is_wifi - ? NM_CON_DEFAULT ("wifi.generate-mac-address-mask") - : NM_CON_DEFAULT ("ethernet.generate-mac-address-mask"), - self); - if (!a) - return NULL; - *out_value = a; - return a; + _notify(self, PROP_PERM_HW_ADDRESS); } gboolean -nm_device_hw_addr_is_explict (NMDevice *self) +nm_device_hw_addr_is_explict(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - priv = NM_DEVICE_GET_PRIVATE (self); - return !NM_IN_SET ((HwAddrType) priv->hw_addr_type, - HW_ADDR_TYPE_PERMANENT, - HW_ADDR_TYPE_UNSET); + priv = NM_DEVICE_GET_PRIVATE(self); + return !NM_IN_SET((HwAddrType) priv->hw_addr_type, HW_ADDR_TYPE_PERMANENT, HW_ADDR_TYPE_UNSET); } static gboolean -_hw_addr_matches (NMDevice *self, const guint8 *addr, gsize addr_len) +_hw_addr_matches(NMDevice *self, const guint8 *addr, gsize addr_len) { - const char *cur_addr; + const char *cur_addr; - cur_addr = nm_device_get_hw_address (self); - return cur_addr && nm_utils_hwaddr_matches (addr, addr_len, cur_addr, -1); + cur_addr = nm_device_get_hw_address(self); + return cur_addr && nm_utils_hwaddr_matches(addr, addr_len, cur_addr, -1); } static gboolean -_hw_addr_set (NMDevice *self, - const char *const addr, - const char *const operation, - const char *const detail) -{ - NMDevicePrivate *priv; - gboolean success = FALSE; - int r; - guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX]; - gsize addr_len; - gboolean was_taken_down = FALSE; - gboolean retry_down; - - nm_assert (NM_IS_DEVICE (self)); - nm_assert (addr); - nm_assert (operation); - - priv = NM_DEVICE_GET_PRIVATE (self); - - if (!_nm_utils_hwaddr_aton (addr, addr_bytes, sizeof (addr_bytes), &addr_len)) - g_return_val_if_reached (FALSE); - - /* Do nothing if current MAC is same */ - if (_hw_addr_matches (self, addr_bytes, addr_len)) { - _LOGT (LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", addr); - return TRUE; - } - - if ( priv->hw_addr_len - && priv->hw_addr_len != addr_len) { - _LOGT (LOGD_DEVICE, "set-hw-addr: setting MAC address to '%s' (%s, %s) failed because of wrong address length (should be %u bytes)", addr, operation, detail, priv->hw_addr_len); - return FALSE; - } - - _LOGT (LOGD_DEVICE, "set-hw-addr: setting MAC address to '%s' (%s, %s)...", addr, operation, detail); - - if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_WIFI) { - /* Always take the device down for Wi-Fi because - * wpa_supplicant needs it to properly detect the MAC - * change. */ - retry_down = FALSE; - was_taken_down = TRUE; - nm_device_take_down (self, FALSE); - } +_hw_addr_set(NMDevice * self, + const char *const addr, + const char *const operation, + const char *const detail) +{ + NMDevicePrivate *priv; + gboolean success = FALSE; + int r; + guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX]; + gsize addr_len; + gboolean was_taken_down = FALSE; + gboolean retry_down; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(addr); + nm_assert(operation); + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (!_nm_utils_hwaddr_aton(addr, addr_bytes, sizeof(addr_bytes), &addr_len)) + g_return_val_if_reached(FALSE); + + /* Do nothing if current MAC is same */ + if (_hw_addr_matches(self, addr_bytes, addr_len)) { + _LOGT(LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", addr); + return TRUE; + } + + if (priv->hw_addr_len && priv->hw_addr_len != addr_len) { + _LOGT(LOGD_DEVICE, + "set-hw-addr: setting MAC address to '%s' (%s, %s) failed because of wrong address " + "length (should be %u bytes)", + addr, + operation, + detail, + priv->hw_addr_len); + return FALSE; + } + + _LOGT(LOGD_DEVICE, + "set-hw-addr: setting MAC address to '%s' (%s, %s)...", + addr, + operation, + detail); + + if (nm_device_get_device_type(self) == NM_DEVICE_TYPE_WIFI) { + /* Always take the device down for Wi-Fi because + * wpa_supplicant needs it to properly detect the MAC + * change. */ + retry_down = FALSE; + was_taken_down = TRUE; + nm_device_take_down(self, FALSE); + } again: - r = nm_platform_link_set_address (nm_device_get_platform (self), nm_device_get_ip_ifindex (self), addr_bytes, addr_len); - success = (r >= 0); - if (!success) { - retry_down = !was_taken_down - && r != -NME_PL_NOT_FOUND - && nm_platform_link_is_up (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self)); - _NMLOG ( ( retry_down - || r == -NME_PL_NOT_FOUND) - ? LOGL_DEBUG - : LOGL_WARN, - LOGD_DEVICE, - "set-hw-addr: failed to %s MAC address to %s (%s) (%s)%s", - operation, addr, detail, - nm_strerror (r), - retry_down ? " (retry with taking down)" : ""); - } else { - /* MAC address successfully changed; update the current MAC to match */ - nm_device_update_hw_address (self); - - if (!_hw_addr_matches (self, addr_bytes, addr_len)) { - gint64 poll_end, now; - - _LOGD (LOGD_DEVICE, - "set-hw-addr: new MAC address %s not successfully %s (%s) (refresh link)", - addr, operation, detail); - - /* The platform call indicated success, however the address is not - * as expected. That is either due to a driver issue (brcmfmac, bgo#770456, - * rh#1374023) or a race where externally the MAC address was reset. - * The race is rather unlikely. - * - * The alternative would be to postpone the activation in case the - * MAC address is not yet ready and poll without blocking. However, - * that is rather complicated and it is not expected that this case - * happens for regular drivers. - * Note that brcmfmac can block NetworkManager for 500 msec while - * taking down the device. Let's add another 100 msec to that. - * - * wait/poll up to 100 msec until it changes. */ - - poll_end = nm_utils_get_monotonic_timestamp_usec () + (100 * 1000); - for (;;) { - if (!nm_platform_link_refresh (nm_device_get_platform (self), nm_device_get_ip_ifindex (self))) - goto handle_fail; - if (!nm_device_update_hw_address (self)) - goto handle_wait; - if (!_hw_addr_matches (self, addr_bytes, addr_len)) - goto handle_fail; - - break; + r = nm_platform_link_set_address(nm_device_get_platform(self), + nm_device_get_ip_ifindex(self), + addr_bytes, + addr_len); + success = (r >= 0); + if (!success) { + retry_down = + !was_taken_down && r != -NME_PL_NOT_FOUND + && nm_platform_link_is_up(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); + _NMLOG((retry_down || r == -NME_PL_NOT_FOUND) ? LOGL_DEBUG : LOGL_WARN, + LOGD_DEVICE, + "set-hw-addr: failed to %s MAC address to %s (%s) (%s)%s", + operation, + addr, + detail, + nm_strerror(r), + retry_down ? " (retry with taking down)" : ""); + } else { + /* MAC address successfully changed; update the current MAC to match */ + nm_device_update_hw_address(self); + + if (!_hw_addr_matches(self, addr_bytes, addr_len)) { + gint64 poll_end, now; + + _LOGD(LOGD_DEVICE, + "set-hw-addr: new MAC address %s not successfully %s (%s) (refresh link)", + addr, + operation, + detail); + + /* The platform call indicated success, however the address is not + * as expected. That is either due to a driver issue (brcmfmac, bgo#770456, + * rh#1374023) or a race where externally the MAC address was reset. + * The race is rather unlikely. + * + * The alternative would be to postpone the activation in case the + * MAC address is not yet ready and poll without blocking. However, + * that is rather complicated and it is not expected that this case + * happens for regular drivers. + * Note that brcmfmac can block NetworkManager for 500 msec while + * taking down the device. Let's add another 100 msec to that. + * + * wait/poll up to 100 msec until it changes. */ + + poll_end = nm_utils_get_monotonic_timestamp_usec() + (100 * 1000); + for (;;) { + if (!nm_platform_link_refresh(nm_device_get_platform(self), + nm_device_get_ip_ifindex(self))) + goto handle_fail; + if (!nm_device_update_hw_address(self)) + goto handle_wait; + if (!_hw_addr_matches(self, addr_bytes, addr_len)) + goto handle_fail; + + break; handle_wait: - now = nm_utils_get_monotonic_timestamp_usec (); - if (now < poll_end) { - g_usleep (NM_MIN (poll_end - now, 500)); - continue; - } + now = nm_utils_get_monotonic_timestamp_usec(); + if (now < poll_end) { + g_usleep(NM_MIN(poll_end - now, 500)); + continue; + } handle_fail: - success = FALSE; - break; - } - } - - if (success) { - retry_down = FALSE; - _LOGI (LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)", - operation, addr, detail); - } else { - retry_down = !was_taken_down - && nm_platform_link_is_up (nm_device_get_platform (self), - nm_device_get_ip_ifindex (self)); - - _NMLOG ( retry_down - ? LOGL_DEBUG - : LOGL_WARN, - LOGD_DEVICE, - "set-hw-addr: new MAC address %s not successfully %s (%s)%s", - addr, - operation, - detail, - retry_down ? " (retry with taking down)" : ""); - } - } - - if (retry_down) { - /* changing the MAC address failed, but also the device was up (and we did not yet try to take - * it down). Optimally, we change the MAC address without taking the device down, but some - * devices don't like that. So, retry with taking the device down. */ - retry_down = FALSE; - was_taken_down = TRUE; - nm_device_take_down (self, FALSE); - goto again; - } - - if (was_taken_down) { - if (!nm_device_bring_up (self, TRUE, NULL)) - return FALSE; - } - - return success; + success = FALSE; + break; + } + } + + if (success) { + retry_down = FALSE; + _LOGI(LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)", operation, addr, detail); + } else { + retry_down = !was_taken_down + && nm_platform_link_is_up(nm_device_get_platform(self), + nm_device_get_ip_ifindex(self)); + + _NMLOG(retry_down ? LOGL_DEBUG : LOGL_WARN, + LOGD_DEVICE, + "set-hw-addr: new MAC address %s not successfully %s (%s)%s", + addr, + operation, + detail, + retry_down ? " (retry with taking down)" : ""); + } + } + + if (retry_down) { + /* changing the MAC address failed, but also the device was up (and we did not yet try to take + * it down). Optimally, we change the MAC address without taking the device down, but some + * devices don't like that. So, retry with taking the device down. */ + retry_down = FALSE; + was_taken_down = TRUE; + nm_device_take_down(self, FALSE); + goto again; + } + + if (was_taken_down) { + if (!nm_device_bring_up(self, TRUE, NULL)) + return FALSE; + } + + return success; } gboolean -nm_device_hw_addr_set (NMDevice *self, - const char *addr, - const char *detail, - gboolean set_permanent) +nm_device_hw_addr_set(NMDevice *self, const char *addr, const char *detail, gboolean set_permanent) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if (!addr) - g_return_val_if_reached (FALSE); + if (!addr) + g_return_val_if_reached(FALSE); - if (set_permanent) { - /* The type is set to PERMANENT by NMDeviceVlan when taking the MAC - * address from the parent and by NMDeviceWifi when setting a random MAC - * address during scanning. - */ - priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT; - } + if (set_permanent) { + /* The type is set to PERMANENT by NMDeviceVlan when taking the MAC + * address from the parent and by NMDeviceWifi when setting a random MAC + * address during scanning. + */ + priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT; + } - return _hw_addr_set (self, addr, "set", detail); + return _hw_addr_set(self, addr, "set", detail); } /* @@ -17041,222 +17185,250 @@ nm_device_hw_addr_set (NMDevice *self, * %TRUE otherwise */ static gboolean -_hw_addr_get_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi, - gboolean *preserve, char **hwaddr, HwAddrType *hwaddr_type, - char **hwaddr_detail, GError **error) -{ - NMDevicePrivate *priv; - gs_free char *addr_setting_free = NULL; - gs_free char *hw_addr_generated = NULL; - gs_free char *generate_mac_address_mask_tmp = NULL; - const char *addr, *addr_setting; - char *addr_out; - HwAddrType type_out; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - priv = NM_DEVICE_GET_PRIVATE (self); - - if (!connection) - g_return_val_if_reached (FALSE); - - addr = addr_setting = _get_cloned_mac_address_setting (self, connection, is_wifi, &addr_setting_free); - - if (nm_streq (addr, NM_CLONED_MAC_PRESERVE)) { - /* "preserve" means to reset the initial MAC address. */ - NM_SET_OUT (preserve, TRUE); - NM_SET_OUT (hwaddr, NULL); - NM_SET_OUT (hwaddr_type, HW_ADDR_TYPE_UNSET); - NM_SET_OUT (hwaddr_detail, g_steal_pointer (&addr_setting_free) ?: g_strdup (addr_setting)); - return TRUE; - } - - if (nm_streq (addr, NM_CLONED_MAC_PERMANENT)) { - gboolean is_fake; - - addr = nm_device_get_permanent_hw_address_full (self, TRUE, &is_fake); - if (is_fake) { - /* Preserve the current address if the permanent address if fake */ - NM_SET_OUT (preserve, TRUE); - NM_SET_OUT (hwaddr, NULL); - NM_SET_OUT (hwaddr_type, HW_ADDR_TYPE_UNSET); - NM_SET_OUT (hwaddr_detail, g_steal_pointer (&addr_setting_free) ?: g_strdup (addr_setting)); - return TRUE; - } else if (!addr) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed to retrieve permanent address"); - return FALSE; - } - addr_out = g_strdup (addr); - type_out = HW_ADDR_TYPE_PERMANENT; - } else if (NM_IN_STRSET (addr, NM_CLONED_MAC_RANDOM)) { - if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { - /* hm, we already use a generate MAC address. Most certainly, that is from the same - * activation request, so we should not create a new random address, instead keep - * the current. */ - goto out_no_action; - } - hw_addr_generated = nm_utils_hw_addr_gen_random_eth (nm_device_get_initial_hw_address (self), - _get_generate_mac_address_mask_setting (self, connection, - is_wifi, - &generate_mac_address_mask_tmp)); - if (!hw_addr_generated) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed to generate %s MAC address", "random"); - return FALSE; - } - - addr_out = g_steal_pointer (&hw_addr_generated); - type_out = HW_ADDR_TYPE_GENERATED; - } else if (NM_IN_STRSET (addr, NM_CLONED_MAC_STABLE)) { - NMUtilsStableType stable_type; - const char *stable_id; - - if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { - /* hm, we already use a generate MAC address. Most certainly, that is from the same - * activation request, so let's skip creating the stable address anew. */ - goto out_no_action; - } - - stable_id = _get_stable_id (self, connection, &stable_type); - hw_addr_generated = nm_utils_hw_addr_gen_stable_eth (stable_type, stable_id, - nm_device_get_ip_iface (self), - nm_device_get_initial_hw_address (self), - _get_generate_mac_address_mask_setting (self, connection, is_wifi, &generate_mac_address_mask_tmp)); - if (!hw_addr_generated) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed to generate %s MAC address", "stable"); - return FALSE; - } - - addr_out = g_steal_pointer (&hw_addr_generated); - type_out = HW_ADDR_TYPE_GENERATED; - } else { - /* this must be a valid address. Otherwise, we shouldn't come here. */ - if (!nm_utils_hwaddr_valid (addr, -1)) - g_return_val_if_reached (FALSE); - - addr_out = g_strdup (addr); - type_out = HW_ADDR_TYPE_EXPLICIT; - } - - NM_SET_OUT (preserve, FALSE); - NM_SET_OUT (hwaddr, addr_out); - NM_SET_OUT (hwaddr_type, type_out); - NM_SET_OUT (hwaddr_detail, g_steal_pointer (&addr_setting_free) ?: g_strdup (addr_setting)); - return TRUE; +_hw_addr_get_cloned(NMDevice * self, + NMConnection *connection, + gboolean is_wifi, + gboolean * preserve, + char ** hwaddr, + HwAddrType * hwaddr_type, + char ** hwaddr_detail, + GError ** error) +{ + NMDevicePrivate *priv; + gs_free char * addr_setting_free = NULL; + gs_free char * hw_addr_generated = NULL; + gs_free char * generate_mac_address_mask_tmp = NULL; + const char * addr, *addr_setting; + char * addr_out; + HwAddrType type_out; + + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + + priv = NM_DEVICE_GET_PRIVATE(self); + + if (!connection) + g_return_val_if_reached(FALSE); + + addr = addr_setting = + _prop_get_x_cloned_mac_address(self, connection, is_wifi, &addr_setting_free); + + if (nm_streq(addr, NM_CLONED_MAC_PRESERVE)) { + /* "preserve" means to reset the initial MAC address. */ + NM_SET_OUT(preserve, TRUE); + NM_SET_OUT(hwaddr, NULL); + NM_SET_OUT(hwaddr_type, HW_ADDR_TYPE_UNSET); + NM_SET_OUT(hwaddr_detail, g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); + return TRUE; + } + + if (nm_streq(addr, NM_CLONED_MAC_PERMANENT)) { + gboolean is_fake; + + addr = nm_device_get_permanent_hw_address_full(self, TRUE, &is_fake); + if (is_fake) { + /* Preserve the current address if the permanent address if fake */ + NM_SET_OUT(preserve, TRUE); + NM_SET_OUT(hwaddr, NULL); + NM_SET_OUT(hwaddr_type, HW_ADDR_TYPE_UNSET); + NM_SET_OUT(hwaddr_detail, + g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); + return TRUE; + } else if (!addr) { + g_set_error_literal(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "failed to retrieve permanent address"); + return FALSE; + } + addr_out = g_strdup(addr); + type_out = HW_ADDR_TYPE_PERMANENT; + } else if (NM_IN_STRSET(addr, NM_CLONED_MAC_RANDOM)) { + if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { + /* hm, we already use a generate MAC address. Most certainly, that is from the same + * activation request, so we should not create a new random address, instead keep + * the current. */ + goto out_no_action; + } + hw_addr_generated = nm_utils_hw_addr_gen_random_eth( + nm_device_get_initial_hw_address(self), + _prop_get_x_generate_mac_address_mask(self, + connection, + is_wifi, + &generate_mac_address_mask_tmp)); + if (!hw_addr_generated) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "failed to generate %s MAC address", + "random"); + return FALSE; + } + + addr_out = g_steal_pointer(&hw_addr_generated); + type_out = HW_ADDR_TYPE_GENERATED; + } else if (NM_IN_STRSET(addr, NM_CLONED_MAC_STABLE)) { + NMUtilsStableType stable_type; + const char * stable_id; + + if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { + /* hm, we already use a generate MAC address. Most certainly, that is from the same + * activation request, so let's skip creating the stable address anew. */ + goto out_no_action; + } + + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + hw_addr_generated = nm_utils_hw_addr_gen_stable_eth( + stable_type, + stable_id, + nm_device_get_ip_iface(self), + nm_device_get_initial_hw_address(self), + _prop_get_x_generate_mac_address_mask(self, + connection, + is_wifi, + &generate_mac_address_mask_tmp)); + if (!hw_addr_generated) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "failed to generate %s MAC address", + "stable"); + return FALSE; + } + + addr_out = g_steal_pointer(&hw_addr_generated); + type_out = HW_ADDR_TYPE_GENERATED; + } else { + /* this must be a valid address. Otherwise, we shouldn't come here. */ + if (!nm_utils_hwaddr_valid(addr, -1)) + g_return_val_if_reached(FALSE); + + addr_out = g_strdup(addr); + type_out = HW_ADDR_TYPE_EXPLICIT; + } + + NM_SET_OUT(preserve, FALSE); + NM_SET_OUT(hwaddr, addr_out); + NM_SET_OUT(hwaddr_type, type_out); + NM_SET_OUT(hwaddr_detail, g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); + return TRUE; out_no_action: - NM_SET_OUT (preserve, FALSE); - NM_SET_OUT (hwaddr, NULL); - NM_SET_OUT (hwaddr_type, HW_ADDR_TYPE_UNSET); - NM_SET_OUT (hwaddr_detail, NULL); - return TRUE; + NM_SET_OUT(preserve, FALSE); + NM_SET_OUT(hwaddr, NULL); + NM_SET_OUT(hwaddr_type, HW_ADDR_TYPE_UNSET); + NM_SET_OUT(hwaddr_detail, NULL); + return TRUE; } gboolean -nm_device_hw_addr_get_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi, - char **hwaddr, gboolean *preserve, GError **error) +nm_device_hw_addr_get_cloned(NMDevice * self, + NMConnection *connection, + gboolean is_wifi, + char ** hwaddr, + gboolean * preserve, + GError ** error) { - if (!_hw_addr_get_cloned (self, connection, is_wifi, preserve, hwaddr, NULL, NULL, error)) - return FALSE; + if (!_hw_addr_get_cloned(self, connection, is_wifi, preserve, hwaddr, NULL, NULL, error)) + return FALSE; - return TRUE; + return TRUE; } gboolean -nm_device_hw_addr_set_cloned (NMDevice *self, NMConnection *connection, gboolean is_wifi) +nm_device_hw_addr_set_cloned(NMDevice *self, NMConnection *connection, gboolean is_wifi) { - NMDevicePrivate *priv; - gboolean preserve = FALSE; - gs_free char *hwaddr = NULL; - gs_free char *detail = NULL; - HwAddrType type = HW_ADDR_TYPE_UNSET; - gs_free_error GError *error = NULL; + NMDevicePrivate *priv; + gboolean preserve = FALSE; + gs_free char * hwaddr = NULL; + gs_free char * detail = NULL; + HwAddrType type = HW_ADDR_TYPE_UNSET; + gs_free_error GError *error = NULL; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - priv = NM_DEVICE_GET_PRIVATE (self); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + priv = NM_DEVICE_GET_PRIVATE(self); - if (!_hw_addr_get_cloned (self, connection, is_wifi, &preserve, &hwaddr, &type, &detail, &error)) { - _LOGW (LOGD_DEVICE, "set-hw-addr: %s", error->message); - return FALSE; - } + if (!_hw_addr_get_cloned(self, + connection, + is_wifi, + &preserve, + &hwaddr, + &type, + &detail, + &error)) { + _LOGW(LOGD_DEVICE, "set-hw-addr: %s", error->message); + return FALSE; + } - if (preserve) - return nm_device_hw_addr_reset (self, detail); + if (preserve) + return nm_device_hw_addr_reset(self, detail); - if (hwaddr) { - priv->hw_addr_type = type; - return _hw_addr_set (self, hwaddr, "set-cloned", detail); - } + if (hwaddr) { + priv->hw_addr_type = type; + return _hw_addr_set(self, hwaddr, "set-cloned", detail); + } - return TRUE; + return TRUE; } gboolean -nm_device_hw_addr_reset (NMDevice *self, const char *detail) +nm_device_hw_addr_reset(NMDevice *self, const char *detail) { - NMDevicePrivate *priv; - const char *addr; + NMDevicePrivate *priv; + const char * addr; - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->hw_addr_type == HW_ADDR_TYPE_UNSET) - return TRUE; + if (priv->hw_addr_type == HW_ADDR_TYPE_UNSET) + return TRUE; - priv->hw_addr_type = HW_ADDR_TYPE_UNSET; - addr = nm_device_get_initial_hw_address (self); - if (!addr) { - /* as hw_addr_type is not UNSET, we expect that we can get an - * initial address to which to reset. */ - g_return_val_if_reached (FALSE); - } + priv->hw_addr_type = HW_ADDR_TYPE_UNSET; + addr = nm_device_get_initial_hw_address(self); + if (!addr) { + /* as hw_addr_type is not UNSET, we expect that we can get an + * initial address to which to reset. */ + g_return_val_if_reached(FALSE); + } - return _hw_addr_set (self, addr, "reset", detail); + return _hw_addr_set(self, addr, "reset", detail); } const char * -nm_device_get_permanent_hw_address_full (NMDevice *self, gboolean force_freeze, gboolean *out_is_fake) +nm_device_get_permanent_hw_address_full(NMDevice *self, + gboolean force_freeze, + gboolean *out_is_fake) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - priv = NM_DEVICE_GET_PRIVATE (self); + priv = NM_DEVICE_GET_PRIVATE(self); - if ( !priv->hw_addr_perm - && force_freeze) { - /* somebody requests a permanent MAC address, but we don't have it set - * yet. We cannot delay it any longer and try to get it without waiting - * for UDEV. */ - nm_device_update_permanent_hw_address (self, TRUE); - } + if (!priv->hw_addr_perm && force_freeze) { + /* somebody requests a permanent MAC address, but we don't have it set + * yet. We cannot delay it any longer and try to get it without waiting + * for UDEV. */ + nm_device_update_permanent_hw_address(self, TRUE); + } - NM_SET_OUT (out_is_fake, priv->hw_addr_perm && priv->hw_addr_perm_fake); - return priv->hw_addr_perm; + NM_SET_OUT(out_is_fake, priv->hw_addr_perm && priv->hw_addr_perm_fake); + return priv->hw_addr_perm; } const char * -nm_device_get_permanent_hw_address (NMDevice *self) +nm_device_get_permanent_hw_address(NMDevice *self) { - return nm_device_get_permanent_hw_address_full (self, TRUE, NULL); + return nm_device_get_permanent_hw_address_full(self, TRUE, NULL); } const char * -nm_device_get_initial_hw_address (NMDevice *self) +nm_device_get_initial_hw_address(NMDevice *self) { - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - return NM_DEVICE_GET_PRIVATE (self)->hw_addr_initial; + return NM_DEVICE_GET_PRIVATE(self)->hw_addr_initial; } /** @@ -17281,1167 +17453,1310 @@ nm_device_get_initial_hw_address (NMDevice *self) * Returns: #TRUE if @self matches one of the specs in @specs */ gboolean -nm_device_spec_match_list (NMDevice *self, const GSList *specs) +nm_device_spec_match_list(NMDevice *self, const GSList *specs) { - return nm_device_spec_match_list_full (self, specs, FALSE); + return nm_device_spec_match_list_full(self, specs, FALSE); } int -nm_device_spec_match_list_full (NMDevice *self, const GSList *specs, int no_match_value) -{ - NMDeviceClass *klass; - NMMatchSpecMatchType m; - const char *hw_address = NULL; - gboolean is_fake; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - klass = NM_DEVICE_GET_CLASS (self); - hw_address = nm_device_get_permanent_hw_address_full (self, - !nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT), - &is_fake); - - m = nm_match_spec_device (specs, - nm_device_get_iface (self), - nm_device_get_type_description (self), - nm_device_get_driver (self), - nm_device_get_driver_version (self), - is_fake ? NULL : hw_address, - klass->get_s390_subchannels ? klass->get_s390_subchannels (self) : NULL, - nm_dhcp_manager_get_config (nm_dhcp_manager_get ())); - - switch (m) { - case NM_MATCH_SPEC_MATCH: - return TRUE; - case NM_MATCH_SPEC_NEG_MATCH: - return FALSE; - case NM_MATCH_SPEC_NO_MATCH: - return no_match_value; - } - nm_assert_not_reached (); - return no_match_value; +nm_device_spec_match_list_full(NMDevice *self, const GSList *specs, int no_match_value) +{ + NMDeviceClass * klass; + NMMatchSpecMatchType m; + const char * hw_address = NULL; + gboolean is_fake; + + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + + klass = NM_DEVICE_GET_CLASS(self); + hw_address = nm_device_get_permanent_hw_address_full( + self, + !nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT), + &is_fake); + + m = nm_match_spec_device(specs, + nm_device_get_iface(self), + nm_device_get_type_description(self), + nm_device_get_driver(self), + nm_device_get_driver_version(self), + is_fake ? NULL : hw_address, + klass->get_s390_subchannels ? klass->get_s390_subchannels(self) : NULL, + nm_dhcp_manager_get_config(nm_dhcp_manager_get())); + + switch (m) { + case NM_MATCH_SPEC_MATCH: + return TRUE; + case NM_MATCH_SPEC_NEG_MATCH: + return FALSE; + case NM_MATCH_SPEC_NO_MATCH: + return no_match_value; + } + nm_assert_not_reached(); + return no_match_value; } guint -nm_device_get_supplicant_timeout (NMDevice *self) +nm_device_get_supplicant_timeout(NMDevice *self) { - NMConnection *connection; - NMSetting8021x *s_8021x; - int timeout; + NMConnection * connection; + NMSetting8021x *s_8021x; + int timeout; #define SUPPLICANT_DEFAULT_TIMEOUT 25 - g_return_val_if_fail (NM_IS_DEVICE (self), SUPPLICANT_DEFAULT_TIMEOUT); + g_return_val_if_fail(NM_IS_DEVICE(self), SUPPLICANT_DEFAULT_TIMEOUT); - connection = nm_device_get_applied_connection (self); + connection = nm_device_get_applied_connection(self); - g_return_val_if_fail (connection, SUPPLICANT_DEFAULT_TIMEOUT); + g_return_val_if_fail(connection, SUPPLICANT_DEFAULT_TIMEOUT); - s_8021x = nm_connection_get_setting_802_1x (connection); - if (s_8021x) { - timeout = nm_setting_802_1x_get_auth_timeout (s_8021x); - if (timeout > 0) - return timeout; - } + s_8021x = nm_connection_get_setting_802_1x(connection); + if (s_8021x) { + timeout = nm_setting_802_1x_get_auth_timeout(s_8021x); + if (timeout > 0) + return timeout; + } - return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("802-1x.auth-timeout"), - self, - 1, - G_MAXINT32, - SUPPLICANT_DEFAULT_TIMEOUT); + return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("802-1x.auth-timeout"), + self, + 1, + G_MAXINT32, + SUPPLICANT_DEFAULT_TIMEOUT); } gboolean -nm_device_auth_retries_try_next (NMDevice *self) -{ - NMDevicePrivate *priv; - NMSettingConnection *s_con; - int auth_retries; - - g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE (self); - auth_retries = priv->auth_retries; - - if (G_UNLIKELY (auth_retries == NM_DEVICE_AUTH_RETRIES_UNSET)) { - auth_retries = -1; - - s_con = nm_device_get_applied_setting (self, NM_TYPE_SETTING_CONNECTION); - if (s_con) - auth_retries = nm_setting_connection_get_auth_retries (s_con); - - if (auth_retries == -1) { - auth_retries = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, - NM_CON_DEFAULT ("connection.auth-retries"), - self, - -1, G_MAXINT32, -1); - } - - if (auth_retries == 0) - auth_retries = NM_DEVICE_AUTH_RETRIES_INFINITY; - else if (auth_retries == -1) - auth_retries = NM_DEVICE_AUTH_RETRIES_DEFAULT; - else - nm_assert (auth_retries > 0); - - priv->auth_retries = auth_retries; - } - - if (auth_retries == NM_DEVICE_AUTH_RETRIES_INFINITY) - return TRUE; - if (auth_retries <= 0) { - nm_assert (auth_retries == 0); - return FALSE; - } - priv->auth_retries--; - return TRUE; +nm_device_auth_retries_try_next(NMDevice *self) +{ + NMDevicePrivate * priv; + NMSettingConnection *s_con; + int auth_retries; + + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); + + priv = NM_DEVICE_GET_PRIVATE(self); + auth_retries = priv->auth_retries; + + if (G_UNLIKELY(auth_retries == NM_DEVICE_AUTH_RETRIES_UNSET)) { + auth_retries = -1; + + s_con = nm_device_get_applied_setting(self, NM_TYPE_SETTING_CONNECTION); + if (s_con) + auth_retries = nm_setting_connection_get_auth_retries(s_con); + + if (auth_retries == -1) { + auth_retries = nm_config_data_get_connection_default_int64( + NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.auth-retries"), + self, + -1, + G_MAXINT32, + -1); + } + + if (auth_retries == 0) + auth_retries = NM_DEVICE_AUTH_RETRIES_INFINITY; + else if (auth_retries == -1) + auth_retries = NM_DEVICE_AUTH_RETRIES_DEFAULT; + else + nm_assert(auth_retries > 0); + + priv->auth_retries = auth_retries; + } + + if (auth_retries == NM_DEVICE_AUTH_RETRIES_INFINITY) + return TRUE; + if (auth_retries <= 0) { + nm_assert(auth_retries == 0); + return FALSE; + } + priv->auth_retries--; + return TRUE; } /*****************************************************************************/ static const char * -_activation_func_to_string (ActivationHandleFunc func) +_activation_func_to_string(ActivationHandleFunc func) { #define FUNC_TO_STRING_CHECK_AND_RETURN(func, f) \ - G_STMT_START { \ - if ((func) == (f)) \ - return #f; \ - } G_STMT_END - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage1_device_prepare); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage2_device_config); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage3_ip_config_start); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip_config_timeout_4); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip_config_timeout_6); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip_config_result_4); - FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip_config_result_6); - g_return_val_if_reached ("unknown"); + G_STMT_START \ + { \ + if ((func) == (f)) \ + return #f; \ + } \ + G_STMT_END + FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage1_device_prepare); + FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage2_device_config); + FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage3_ip_config_start); + FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage4_ip_config_timeout_4); + FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage4_ip_config_timeout_6); + FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage5_ip_config_result_4); + FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage5_ip_config_result_6); + g_return_val_if_reached("unknown"); } /*****************************************************************************/ static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDevice *self = NM_DEVICE (object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - GVariantBuilder array_builder; - - switch (prop_id) { - case PROP_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_PATH: - g_value_take_string (value, - nm_utils_str_utf8safe_escape_cp (priv->path, - NM_UTILS_STR_UTF8_SAFE_FLAG_NONE)); - break; - case PROP_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_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_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_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_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)); - break; - case PROP_IP4_ADDRESS: - g_value_set_uint (value, priv->ip4_address); - break; - case PROP_CARRIER: - g_value_set_boolean (value, priv->carrier); - break; - case PROP_MTU: - g_value_set_uint (value, priv->mtu); - break; - case PROP_IP4_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->ip_config_4 : NULL); - break; - case PROP_DHCP4_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->dhcp_data_4.config : NULL); - break; - case PROP_IP6_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->ip_config_6 : NULL); - break; - case PROP_DHCP6_CONFIG: - nm_dbus_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->dhcp_data_6.config : NULL); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_STATE_REASON: - g_value_take_variant (value, - g_variant_new ("(uu)", priv->state, priv->state_reason)); - break; - case PROP_ACTIVE_CONNECTION: - g_value_set_string (value, nm_dbus_track_obj_path_get (&priv->act_request)); - break; - case PROP_DEVICE_TYPE: - g_value_set_uint (value, priv->type); - break; - case PROP_LINK_TYPE: - g_value_set_uint (value, priv->link_type); - break; - case PROP_MANAGED: - /* The managed state exposed on D-Bus only depends on the current device state alone. */ - g_value_set_boolean (value, nm_device_get_state (self) > NM_DEVICE_STATE_UNMANAGED); - break; - case PROP_AUTOCONNECT: - g_value_set_boolean (value, - nm_device_autoconnect_blocked_get (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL) - ? FALSE - : TRUE); - break; - case PROP_FIRMWARE_MISSING: - g_value_set_boolean (value, priv->firmware_missing); - break; - case PROP_NM_PLUGIN_MISSING: - g_value_set_boolean (value, priv->nm_plugin_missing); - break; - case PROP_TYPE_DESC: - g_value_set_string (value, priv->type_desc); - break; - case PROP_RFKILL_TYPE: - g_value_set_uint (value, priv->rfkill_type); - break; - case PROP_AVAILABLE_CONNECTIONS: - nm_dbus_utils_g_value_set_object_path_from_hash (value, - priv->available_connections, - TRUE); - break; - case PROP_PHYSICAL_PORT_ID: - g_value_set_string (value, priv->physical_port_id); - break; - case PROP_MASTER: - g_value_set_object (value, nm_device_get_master (self)); - break; - case PROP_PARENT: - g_value_set_string (value, nm_dbus_track_obj_path_get (&priv->parent_device)); - break; - case PROP_HW_ADDRESS: - g_value_set_string (value, priv->hw_addr); - break; - case PROP_PERM_HW_ADDRESS: { - const char *perm_hw_addr; - gboolean perm_hw_addr_is_fake; - - perm_hw_addr = nm_device_get_permanent_hw_address_full (self, FALSE, &perm_hw_addr_is_fake); - /* this property is exposed on D-Bus for NMDeviceEthernet and NMDeviceWifi. */ - g_value_set_string (value, perm_hw_addr && !perm_hw_addr_is_fake ? perm_hw_addr : NULL); - break; - } - case PROP_HAS_PENDING_ACTION: - g_value_set_boolean (value, nm_device_has_pending_action (self)); - break; - case PROP_METERED: - g_value_set_uint (value, priv->metered); - break; - case PROP_LLDP_NEIGHBORS: - if (priv->lldp_listener) - g_value_set_variant (value, nm_lldp_listener_get_neighbors (priv->lldp_listener)); - else { - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); - g_value_take_variant (value, g_variant_builder_end (&array_builder)); - } - break; - case PROP_REAL: - g_value_set_boolean (value, nm_device_is_real (self)); - break; - case PROP_SLAVES: { - CList *slave_iter; - char **slave_list; - gsize i, n; - - n = c_list_length (&priv->slaves); - slave_list = g_new (char *, n + 1); - i = 0; - c_list_for_each (slave_iter, &priv->slaves) { - SlaveInfo *info = c_list_entry (slave_iter, SlaveInfo, lst_slave); - const char *path; - - if (!NM_DEVICE_GET_PRIVATE (info->slave)->is_enslaved) - continue; - path = nm_dbus_object_get_path (NM_DBUS_OBJECT (info->slave)); - if (path) - slave_list[i++] = g_strdup (path); - } - nm_assert (i <= n); - slave_list[i] = NULL; - g_value_take_boxed (value, slave_list); - break; - } - case PROP_STATISTICS_REFRESH_RATE_MS: - g_value_set_uint (value, priv->stats.refresh_rate_ms); - break; - case PROP_STATISTICS_TX_BYTES: - g_value_set_uint64 (value, priv->stats.tx_bytes); - break; - case PROP_STATISTICS_RX_BYTES: - g_value_set_uint64 (value, priv->stats.rx_bytes); - break; - case PROP_IP4_CONNECTIVITY: - g_value_set_uint (value, priv->concheck_x[1].state); - break; - case PROP_IP6_CONNECTIVITY: - g_value_set_uint (value, priv->concheck_x[0].state); - break; - case PROP_INTERFACE_FLAGS: - g_value_set_uint (value, priv->interface_flags); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMDevice * self = NM_DEVICE(object); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + GVariantBuilder array_builder; + + switch (prop_id) { + case PROP_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_PATH: + g_value_take_string( + value, + nm_utils_str_utf8safe_escape_cp(priv->path, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE)); + break; + case PROP_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_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_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_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_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)); + break; + case PROP_IP4_ADDRESS: + g_value_set_variant(value, nm_g_variant_singleton_u_0()); + break; + case PROP_CARRIER: + g_value_set_boolean(value, priv->carrier); + break; + case PROP_MTU: + g_value_set_uint(value, priv->mtu); + break; + case PROP_IP4_CONFIG: + nm_dbus_utils_g_value_set_object_path(value, + ip_config_valid(priv->state) ? priv->ip_config_4 + : NULL); + break; + case PROP_DHCP4_CONFIG: + nm_dbus_utils_g_value_set_object_path( + value, + ip_config_valid(priv->state) ? priv->dhcp_data_4.config : NULL); + break; + case PROP_IP6_CONFIG: + nm_dbus_utils_g_value_set_object_path(value, + ip_config_valid(priv->state) ? priv->ip_config_6 + : NULL); + break; + case PROP_DHCP6_CONFIG: + nm_dbus_utils_g_value_set_object_path( + value, + ip_config_valid(priv->state) ? priv->dhcp_data_6.config : NULL); + break; + case PROP_STATE: + g_value_set_uint(value, priv->state); + break; + case PROP_STATE_REASON: + g_value_take_variant(value, g_variant_new("(uu)", priv->state, priv->state_reason)); + break; + case PROP_ACTIVE_CONNECTION: + g_value_set_string(value, nm_dbus_track_obj_path_get(&priv->act_request)); + break; + case PROP_DEVICE_TYPE: + g_value_set_uint(value, priv->type); + break; + case PROP_LINK_TYPE: + g_value_set_uint(value, priv->link_type); + break; + case PROP_MANAGED: + /* The managed state exposed on D-Bus only depends on the current device state alone. */ + g_value_set_boolean(value, nm_device_get_state(self) > NM_DEVICE_STATE_UNMANAGED); + break; + case PROP_AUTOCONNECT: + g_value_set_boolean( + value, + nm_device_autoconnect_blocked_get(self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL) ? FALSE + : TRUE); + break; + case PROP_FIRMWARE_MISSING: + g_value_set_boolean(value, priv->firmware_missing); + break; + case PROP_NM_PLUGIN_MISSING: + g_value_set_boolean(value, priv->nm_plugin_missing); + break; + case PROP_TYPE_DESC: + g_value_set_string(value, priv->type_desc); + break; + case PROP_RFKILL_TYPE: + g_value_set_uint(value, priv->rfkill_type); + break; + case PROP_AVAILABLE_CONNECTIONS: + nm_dbus_utils_g_value_set_object_path_from_hash(value, priv->available_connections, TRUE); + break; + case PROP_PHYSICAL_PORT_ID: + g_value_set_string(value, priv->physical_port_id); + break; + case PROP_MASTER: + g_value_set_object(value, nm_device_get_master(self)); + break; + case PROP_PARENT: + g_value_set_string(value, nm_dbus_track_obj_path_get(&priv->parent_device)); + break; + case PROP_HW_ADDRESS: + g_value_set_string(value, priv->hw_addr); + break; + case PROP_PERM_HW_ADDRESS: + { + const char *perm_hw_addr; + gboolean perm_hw_addr_is_fake; + + perm_hw_addr = nm_device_get_permanent_hw_address_full(self, FALSE, &perm_hw_addr_is_fake); + /* this property is exposed on D-Bus for NMDeviceEthernet and NMDeviceWifi. */ + g_value_set_string(value, perm_hw_addr && !perm_hw_addr_is_fake ? perm_hw_addr : NULL); + break; + } + case PROP_HAS_PENDING_ACTION: + g_value_set_boolean(value, nm_device_has_pending_action(self)); + break; + case PROP_METERED: + g_value_set_uint(value, priv->metered); + break; + case PROP_LLDP_NEIGHBORS: + if (priv->lldp_listener) + g_value_set_variant(value, nm_lldp_listener_get_neighbors(priv->lldp_listener)); + else { + g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aa{sv}")); + g_value_take_variant(value, g_variant_builder_end(&array_builder)); + } + break; + case PROP_REAL: + g_value_set_boolean(value, nm_device_is_real(self)); + break; + case PROP_SLAVES: + { + CList *slave_iter; + char **slave_list; + gsize i, n; + + n = c_list_length(&priv->slaves); + slave_list = g_new(char *, n + 1); + i = 0; + c_list_for_each (slave_iter, &priv->slaves) { + SlaveInfo * info = c_list_entry(slave_iter, SlaveInfo, lst_slave); + const char *path; + + if (!NM_DEVICE_GET_PRIVATE(info->slave)->is_enslaved) + continue; + path = nm_dbus_object_get_path(NM_DBUS_OBJECT(info->slave)); + if (path) + slave_list[i++] = g_strdup(path); + } + nm_assert(i <= n); + slave_list[i] = NULL; + g_value_take_boxed(value, slave_list); + break; + } + case PROP_STATISTICS_REFRESH_RATE_MS: + g_value_set_uint(value, priv->stats.refresh_rate_ms); + break; + case PROP_STATISTICS_TX_BYTES: + g_value_set_uint64(value, priv->stats.tx_bytes); + break; + case PROP_STATISTICS_RX_BYTES: + g_value_set_uint64(value, priv->stats.rx_bytes); + break; + case PROP_IP4_CONNECTIVITY: + g_value_set_uint(value, priv->concheck_x[1].state); + break; + case PROP_IP6_CONNECTIVITY: + g_value_set_uint(value, priv->concheck_x[0].state); + break; + case PROP_INTERFACE_FLAGS: + g_value_set_uint(value, priv->interface_flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } } static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMDevice *self = (NMDevice *) object; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - switch (prop_id) { - case PROP_UDI: - /* construct-only */ - priv->udi = g_value_dup_string (value); - break; - case PROP_IFACE: - /* construct-only */ - priv->iface = g_value_dup_string (value); - break; - case PROP_DRIVER: - /* construct-only */ - priv->driver = g_value_dup_string (value); - break; - case PROP_MANAGED: - /* via D-Bus */ - if (nm_device_is_real (self)) { - gboolean managed; - NMDeviceStateReason reason; - - managed = g_value_get_boolean (value); - if (managed) { - reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; - 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); - } - nm_device_set_unmanaged_by_flags (self, - NM_UNMANAGED_USER_EXPLICIT, - !managed, - reason); - } - break; - case PROP_AUTOCONNECT: - /* via D-Bus */ - if (g_value_get_boolean (value)) - nm_device_autoconnect_blocked_unset (self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL); - else - nm_device_autoconnect_blocked_set (self, NM_DEVICE_AUTOCONNECT_BLOCKED_USER); - break; - case PROP_NM_PLUGIN_MISSING: - /* construct-only */ - priv->nm_plugin_missing = g_value_get_boolean (value); - break; - case PROP_DEVICE_TYPE: - /* construct-only */ - nm_assert (priv->type == NM_DEVICE_TYPE_UNKNOWN); - priv->type = g_value_get_uint (value); - nm_assert (priv->type > NM_DEVICE_TYPE_UNKNOWN); - nm_assert (priv->type <= NM_DEVICE_TYPE_VRF); - break; - case PROP_LINK_TYPE: - /* construct-only */ - nm_assert (priv->link_type == NM_LINK_TYPE_NONE); - priv->link_type = g_value_get_uint (value); - break; - case PROP_TYPE_DESC: - /* construct-only */ - priv->type_desc = g_value_dup_string (value); - break; - case PROP_RFKILL_TYPE: - /* construct-only */ - priv->rfkill_type = g_value_get_uint (value); - break; - case PROP_PERM_HW_ADDRESS: - /* construct-only */ - priv->hw_addr_perm = g_value_dup_string (value); - break; - case PROP_STATISTICS_REFRESH_RATE_MS: - /* via D-Bus */ - _stats_set_refresh_rate (self, g_value_get_uint (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } +set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + NMDevice * self = (NMDevice *) object; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + switch (prop_id) { + case PROP_UDI: + /* construct-only */ + priv->udi = g_value_dup_string(value); + break; + case PROP_IFACE: + /* construct-only */ + priv->iface_ = g_value_dup_string(value); + break; + case PROP_DRIVER: + /* construct-only */ + priv->driver = g_value_dup_string(value); + break; + case PROP_MANAGED: + /* via D-Bus */ + if (nm_device_is_real(self)) { + gboolean managed; + NMDeviceStateReason reason; + + managed = g_value_get_boolean(value); + if (managed) { + reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; + 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); + } + nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_USER_EXPLICIT, !managed, reason); + } + break; + case PROP_AUTOCONNECT: + /* via D-Bus */ + if (g_value_get_boolean(value)) + nm_device_autoconnect_blocked_unset(self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL); + else + nm_device_autoconnect_blocked_set(self, NM_DEVICE_AUTOCONNECT_BLOCKED_USER); + break; + case PROP_NM_PLUGIN_MISSING: + /* construct-only */ + priv->nm_plugin_missing = g_value_get_boolean(value); + break; + case PROP_DEVICE_TYPE: + /* construct-only */ + nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN); + priv->type = g_value_get_uint(value); + nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN); + nm_assert(priv->type <= NM_DEVICE_TYPE_VRF); + break; + case PROP_LINK_TYPE: + /* construct-only */ + nm_assert(priv->link_type == NM_LINK_TYPE_NONE); + priv->link_type = g_value_get_uint(value); + break; + case PROP_TYPE_DESC: + /* construct-only */ + priv->type_desc = g_value_dup_string(value); + break; + case PROP_RFKILL_TYPE: + /* construct-only */ + priv->rfkill_type = g_value_get_uint(value); + break; + case PROP_PERM_HW_ADDRESS: + /* construct-only */ + priv->hw_addr_perm = g_value_dup_string(value); + break; + case PROP_STATISTICS_REFRESH_RATE_MS: + /* via D-Bus */ + _stats_set_refresh_rate(self, g_value_get_uint(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } } /*****************************************************************************/ static void -nm_device_init (NMDevice *self) +nm_device_init(NMDevice *self) { - NMDevicePrivate *priv; + NMDevicePrivate *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_DEVICE, NMDevicePrivate); + priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_DEVICE, NMDevicePrivate); - self->_priv = priv; + self->_priv = priv; - c_list_init (&priv->concheck_lst_head); - c_list_init (&self->devices_lst); - c_list_init (&priv->slaves); + c_list_init(&priv->concheck_lst_head); + c_list_init(&self->devices_lst); + c_list_init(&priv->slaves); - priv->concheck_x[0].state = NM_CONNECTIVITY_UNKNOWN; - priv->concheck_x[1].state = NM_CONNECTIVITY_UNKNOWN; + priv->concheck_x[0].state = NM_CONNECTIVITY_UNKNOWN; + priv->concheck_x[1].state = NM_CONNECTIVITY_UNKNOWN; - nm_dbus_track_obj_path_init (&priv->parent_device, G_OBJECT (self), obj_properties[PROP_PARENT]); - nm_dbus_track_obj_path_init (&priv->act_request, G_OBJECT (self), obj_properties[PROP_ACTIVE_CONNECTION]); + nm_dbus_track_obj_path_init(&priv->parent_device, G_OBJECT(self), obj_properties[PROP_PARENT]); + nm_dbus_track_obj_path_init(&priv->act_request, + G_OBJECT(self), + obj_properties[PROP_ACTIVE_CONNECTION]); - priv->netns = g_object_ref (NM_NETNS_GET); + priv->netns = g_object_ref(NM_NETNS_GET); - priv->autoconnect_blocked_flags = DEFAULT_AUTOCONNECT - ? NM_DEVICE_AUTOCONNECT_BLOCKED_NONE - : NM_DEVICE_AUTOCONNECT_BLOCKED_USER; + priv->autoconnect_blocked_flags = DEFAULT_AUTOCONNECT ? NM_DEVICE_AUTOCONNECT_BLOCKED_NONE + : NM_DEVICE_AUTOCONNECT_BLOCKED_USER; - priv->auth_retries = NM_DEVICE_AUTH_RETRIES_UNSET; - priv->type = NM_DEVICE_TYPE_UNKNOWN; - priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; - priv->state = NM_DEVICE_STATE_UNMANAGED; - priv->state_reason = NM_DEVICE_STATE_REASON_NONE; - priv->rfkill_type = RFKILL_TYPE_UNKNOWN; - priv->unmanaged_flags = NM_UNMANAGED_PLATFORM_INIT; - priv->unmanaged_mask = priv->unmanaged_flags; - priv->available_connections = g_hash_table_new_full (nm_direct_hash, NULL, g_object_unref, NULL); - priv->ip6_saved_properties = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_free); - priv->sys_iface_state = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; + priv->auth_retries = NM_DEVICE_AUTH_RETRIES_UNSET; + priv->type = NM_DEVICE_TYPE_UNKNOWN; + priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; + priv->state = NM_DEVICE_STATE_UNMANAGED; + priv->state_reason = NM_DEVICE_STATE_REASON_NONE; + priv->rfkill_type = RFKILL_TYPE_UNKNOWN; + priv->unmanaged_flags = NM_UNMANAGED_PLATFORM_INIT; + priv->unmanaged_mask = priv->unmanaged_flags; + priv->available_connections = g_hash_table_new_full(nm_direct_hash, NULL, g_object_unref, NULL); + priv->ip6_saved_properties = g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, g_free); + priv->sys_iface_state_ = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; - priv->v4_commit_first_time = TRUE; - priv->v6_commit_first_time = TRUE; + priv->v4_commit_first_time = TRUE; + priv->v6_commit_first_time = TRUE; } -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) +static GObject * +constructor(GType type, guint n_construct_params, GObjectConstructParam *construct_params) { - GObject *object; - GObjectClass *klass; - NMDevice *self; - NMDevicePrivate *priv; - const NMPlatformLink *pllink; + GObject * object; + GObjectClass * klass; + NMDevice * self; + NMDevicePrivate * priv; + const NMPlatformLink *pllink; - klass = G_OBJECT_CLASS (nm_device_parent_class); - object = klass->constructor (type, n_construct_params, construct_params); - if (!object) - return NULL; + klass = G_OBJECT_CLASS(nm_device_parent_class); + object = klass->constructor(type, n_construct_params, construct_params); + if (!object) + return NULL; - self = NM_DEVICE (object); - priv = NM_DEVICE_GET_PRIVATE (self); + self = NM_DEVICE(object); + priv = NM_DEVICE_GET_PRIVATE(self); - if ( priv->iface - && G_LIKELY (!nm_utils_get_testing ())) { - pllink = nm_platform_link_get_by_ifname (nm_device_get_platform (self), priv->iface); + if (priv->iface && G_LIKELY(!nm_utils_get_testing())) { + pllink = nm_platform_link_get_by_ifname(nm_device_get_platform(self), priv->iface); - if (pllink && link_type_compatible (self, pllink->type, NULL, NULL)) { - priv->ifindex = pllink->ifindex; - priv->up = NM_FLAGS_HAS (pllink->n_ifi_flags, IFF_UP); - } - } + if (pllink && link_type_compatible(self, pllink->type, NULL, NULL)) { + _set_ifindex(self, pllink->ifindex, FALSE); + priv->up = NM_FLAGS_HAS(pllink->n_ifi_flags, IFF_UP); + } + } - if (priv->hw_addr_perm) { - guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; - gsize l; + if (priv->hw_addr_perm) { + guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + gsize l; - if (!_nm_utils_hwaddr_aton (priv->hw_addr_perm, buf, sizeof (buf), &l)) { - nm_clear_g_free (&priv->hw_addr_perm); - g_return_val_if_reached (object); - } + if (!_nm_utils_hwaddr_aton(priv->hw_addr_perm, buf, sizeof(buf), &l)) { + nm_clear_g_free(&priv->hw_addr_perm); + g_return_val_if_reached(object); + } - priv->hw_addr_len_ = l; - priv->hw_addr = nm_utils_hwaddr_ntoa (buf, l); - _LOGT (LOGD_DEVICE, "hw-addr: has permanent hw-address '%s'", priv->hw_addr_perm); - } + priv->hw_addr_len_ = l; + priv->hw_addr = nm_utils_hwaddr_ntoa(buf, l); + _LOGT(LOGD_DEVICE, "hw-addr: has permanent hw-address '%s'", priv->hw_addr_perm); + } - return object; + return object; } static void -constructed (GObject *object) -{ - NMDevice *self = NM_DEVICE (object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPlatform *platform; - - if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) - priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); - - /* Watch for external IP config changes */ - platform = nm_device_get_platform (self); - g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (device_ipx_changed), self); - g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (device_ipx_changed), self); - g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self); - g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self); - g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self); - - priv->manager = g_object_ref (NM_MANAGER_GET); - priv->settings = g_object_ref (NM_SETTINGS_GET); - - g_signal_connect (priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_ADDED, - G_CALLBACK (cp_connection_added), - self); - g_signal_connect (priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, - G_CALLBACK (cp_connection_updated), - self); - g_signal_connect (priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK (cp_connection_removed), - self); - - G_OBJECT_CLASS (nm_device_parent_class)->constructed (object); - - _LOGD (LOGD_DEVICE, "constructed (%s)", G_OBJECT_TYPE_NAME (self)); +constructed(GObject *object) +{ + NMDevice * self = NM_DEVICE(object); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMPlatform * platform; + + if (NM_DEVICE_GET_CLASS(self)->get_generic_capabilities) + priv->capabilities |= NM_DEVICE_GET_CLASS(self)->get_generic_capabilities(self); + + /* Watch for external IP config changes */ + platform = nm_device_get_platform(self); + g_signal_connect(platform, + NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, + G_CALLBACK(device_ipx_changed), + self); + g_signal_connect(platform, + NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, + G_CALLBACK(device_ipx_changed), + self); + g_signal_connect(platform, + NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, + G_CALLBACK(device_ipx_changed), + self); + g_signal_connect(platform, + NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, + G_CALLBACK(device_ipx_changed), + self); + g_signal_connect(platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK(link_changed_cb), self); + + priv->manager = g_object_ref(NM_MANAGER_GET); + priv->settings = g_object_ref(NM_SETTINGS_GET); + + g_signal_connect(priv->settings, + NM_SETTINGS_SIGNAL_CONNECTION_ADDED, + G_CALLBACK(cp_connection_added), + self); + g_signal_connect(priv->settings, + NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, + G_CALLBACK(cp_connection_updated), + self); + g_signal_connect(priv->settings, + NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, + G_CALLBACK(cp_connection_removed), + self); + + G_OBJECT_CLASS(nm_device_parent_class)->constructed(object); + + _LOGD(LOGD_DEVICE, "constructed (%s)", G_OBJECT_TYPE_NAME(self)); } static void -dispose (GObject *object) +dispose(GObject *object) { - NMDevice *self = NM_DEVICE (object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPlatform *platform; - NMDeviceConnectivityHandle *con_handle; - gs_free_error GError *cancelled_error = NULL; + NMDevice * self = NM_DEVICE(object); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMPlatform * platform; + NMDeviceConnectivityHandle *con_handle; + gs_free_error GError *cancelled_error = NULL; - _LOGD (LOGD_DEVICE, "disposing"); + _LOGD(LOGD_DEVICE, "disposing"); - nm_assert (c_list_is_empty (&self->devices_lst)); + nm_assert(c_list_is_empty(&self->devices_lst)); - while ((con_handle = c_list_first_entry (&priv->concheck_lst_head, NMDeviceConnectivityHandle, concheck_lst))) { - if (!cancelled_error) - nm_utils_error_set_cancelled (&cancelled_error, FALSE, "NMDevice"); - concheck_handle_complete (con_handle, cancelled_error); - } + while ((con_handle = c_list_first_entry(&priv->concheck_lst_head, + NMDeviceConnectivityHandle, + concheck_lst))) { + if (!cancelled_error) + nm_utils_error_set_cancelled(&cancelled_error, FALSE, "NMDevice"); + concheck_handle_complete(con_handle, cancelled_error); + } - nm_clear_g_cancellable (&priv->deactivating_cancellable); + nm_clear_g_cancellable(&priv->deactivating_cancellable); - nm_device_assume_state_reset (self); + nm_device_assume_state_reset(self); - _parent_set_ifindex (self, 0, FALSE); + _parent_set_ifindex(self, 0, FALSE); - platform = nm_device_get_platform (self); - g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self); - g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self); + platform = nm_device_get_platform(self); + g_signal_handlers_disconnect_by_func(platform, G_CALLBACK(device_ipx_changed), self); + g_signal_handlers_disconnect_by_func(platform, G_CALLBACK(link_changed_cb), self); - arp_cleanup (self); + arp_cleanup(self); - nm_clear_g_signal_handler (nm_config_get (), &priv->config_changed_id); + nm_clear_g_signal_handler(nm_config_get(), &priv->config_changed_id); - dispatcher_cleanup (self); + dispatcher_cleanup(self); - nm_pacrunner_manager_remove_clear (&priv->pacrunner_conf_id); + nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); - _cleanup_generic_pre (self, CLEANUP_TYPE_KEEP); + _cleanup_generic_pre(self, CLEANUP_TYPE_KEEP); - nm_assert (c_list_is_empty (&priv->slaves)); + nm_assert(c_list_is_empty(&priv->slaves)); - /* Let the kernel manage IPv6LL again */ - set_nm_ipv6ll (self, FALSE); + /* Let the kernel manage IPv6LL again */ + set_nm_ipv6ll(self, FALSE); - _cleanup_generic_post (self, CLEANUP_TYPE_KEEP); + _cleanup_generic_post(self, CLEANUP_TYPE_KEEP); - nm_assert (priv->master_ready_id == 0); + nm_assert(priv->master_ready_id == 0); - g_hash_table_remove_all (priv->ip6_saved_properties); + g_hash_table_remove_all(priv->ip6_saved_properties); - nm_clear_g_source (&priv->recheck_assume_id); - nm_clear_g_source (&priv->recheck_available.call_id); + nm_clear_g_source(&priv->recheck_assume_id); + nm_clear_g_source(&priv->recheck_available.call_id); - nm_clear_g_source (&priv->check_delete_unrealized_id); + nm_clear_g_source(&priv->check_delete_unrealized_id); - nm_clear_g_source (&priv->stats.timeout_id); + nm_clear_g_source(&priv->stats.timeout_id); - carrier_disconnected_action_cancel (self); + carrier_disconnected_action_cancel(self); - if (priv->ifindex > 0) { - priv->ifindex = 0; - _notify (self, PROP_IFINDEX); - } + _set_ifindex(self, 0, FALSE); + _set_ifindex(self, 0, TRUE); - if (priv->settings) { - g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_added, self); - g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_updated, self); - g_signal_handlers_disconnect_by_func (priv->settings, cp_connection_removed, self); - } + if (priv->settings) { + g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_added, self); + g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_updated, self); + g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_removed, self); + } - available_connections_del_all (self); + available_connections_del_all(self); - if (nm_clear_g_source (&priv->carrier_wait_id)) - nm_device_remove_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); + 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, - NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); + _clear_queued_act_request(priv, NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); - nm_clear_g_source (&priv->device_link_changed_id); - nm_clear_g_source (&priv->device_ip_link_changed_id); + nm_clear_g_source(&priv->device_link_changed_id); + nm_clear_g_source(&priv->device_ip_link_changed_id); - if (priv->lldp_listener) { - g_signal_handlers_disconnect_by_func (priv->lldp_listener, - G_CALLBACK (lldp_neighbors_changed), - self); - nm_lldp_listener_stop (priv->lldp_listener); - g_clear_object (&priv->lldp_listener); - } + if (priv->lldp_listener) { + g_signal_handlers_disconnect_by_func(priv->lldp_listener, + G_CALLBACK(lldp_neighbors_changed), + self); + nm_lldp_listener_stop(priv->lldp_listener); + g_clear_object(&priv->lldp_listener); + } - nm_clear_g_source (&priv->concheck_x[0].p_cur_id); - nm_clear_g_source (&priv->concheck_x[1].p_cur_id); + nm_clear_g_source(&priv->concheck_x[0].p_cur_id); + nm_clear_g_source(&priv->concheck_x[1].p_cur_id); - nm_assert (!priv->sriov.pending); - if (priv->sriov.next) { - nm_g_slice_free (priv->sriov.next); - priv->sriov.next = NULL; - } + nm_assert(!priv->sriov.pending); + if (priv->sriov.next) { + nm_g_slice_free(priv->sriov.next); + priv->sriov.next = NULL; + } - G_OBJECT_CLASS (nm_device_parent_class)->dispose (object); + G_OBJECT_CLASS(nm_device_parent_class)->dispose(object); - if (nm_clear_g_source (&priv->queued_state.id)) { - /* FIXME: we'd expect the queud_state to be already cleared and this statement - * not being necessary. Add this check here to hopefully investigate crash - * rh#1270247. */ - g_return_if_reached (); - } + if (nm_clear_g_source(&priv->queued_state.id)) { + /* FIXME: we'd expect the queud_state to be already cleared and this statement + * not being necessary. Add this check here to hopefully investigate crash + * rh#1270247. */ + g_return_if_reached(); + } } static void -finalize (GObject *object) +finalize(GObject *object) { - NMDevice *self = NM_DEVICE (object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice * self = NM_DEVICE(object); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - _LOGD (LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME (self)); + _LOGD(LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME(self)); - g_free (priv->hw_addr); - g_free (priv->hw_addr_perm); - g_free (priv->hw_addr_initial); - g_slist_free (priv->pending_actions); - g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - nm_clear_g_free (&priv->physical_port_id); - g_free (priv->udi); - g_free (priv->path); - g_free (priv->iface); - g_free (priv->ip_iface); - g_free (priv->driver); - g_free (priv->driver_version); - g_free (priv->firmware_version); - g_free (priv->type_desc); - g_free (priv->dhcp_anycast_address); - g_free (priv->current_stable_id); + g_free(priv->hw_addr); + g_free(priv->hw_addr_perm); + g_free(priv->hw_addr_initial); + g_slist_free(priv->pending_actions); + g_slist_free_full(priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); + nm_clear_g_free(&priv->physical_port_id); + g_free(priv->udi); + g_free(priv->path); + g_free(priv->iface_); + g_free(priv->ip_iface_); + g_free(priv->driver); + g_free(priv->driver_version); + g_free(priv->firmware_version); + g_free(priv->type_desc); + g_free(priv->dhcp_anycast_address); + g_free(priv->current_stable_id); - g_hash_table_unref (priv->ip6_saved_properties); - g_hash_table_unref (priv->available_connections); + g_hash_table_unref(priv->ip6_saved_properties); + g_hash_table_unref(priv->available_connections); - nm_dbus_track_obj_path_deinit (&priv->parent_device); - nm_dbus_track_obj_path_deinit (&priv->act_request); + nm_dbus_track_obj_path_deinit(&priv->parent_device); + nm_dbus_track_obj_path_deinit(&priv->act_request); - G_OBJECT_CLASS (nm_device_parent_class)->finalize (object); + G_OBJECT_CLASS(nm_device_parent_class)->finalize(object); - /* for testing, NMDeviceTest does not invoke NMDevice::constructed, - * and thus @settings might be unset. */ - nm_g_object_unref (priv->settings); - nm_g_object_unref (priv->manager); + /* for testing, NMDeviceTest does not invoke NMDevice::constructed, + * and thus @settings might be unset. */ + nm_g_object_unref(priv->settings); + nm_g_object_unref(priv->manager); - nm_g_object_unref (priv->concheck_mgr); + nm_g_object_unref(priv->concheck_mgr); - g_object_unref (priv->netns); + g_object_unref(priv->netns); } /*****************************************************************************/ -static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "StateChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("new_state", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("old_state", "u"), - NM_DEFINE_GDBUS_ARG_INFO ("reason", "u"), - ), -); +static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( + "StateChanged", + .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("new_state", "u"), + NM_DEFINE_GDBUS_ARG_INFO("old_state", "u"), + NM_DEFINE_GDBUS_ARG_INFO("reason", "u"), ), ); static const NMDBusInterfaceInfoExtended interface_info_device = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Reapply", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO ("version_id", "t"), - NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"), - ), - ), - .handle = impl_device_reapply, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "GetAppliedConnection", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("flags", "u"), - ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO ("version_id", "t"), - ), - ), - .handle = impl_device_get_applied_connection, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Disconnect", - ), - .handle = impl_device_disconnect, - ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED ( - NM_DEFINE_GDBUS_METHOD_INFO_INIT ( - "Delete", - ), - .handle = impl_device_delete, - ), - ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &signal_info_state_changed, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Udi", "s", NM_DEVICE_UDI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Path", "s", NM_DEVICE_PATH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Interface", "s", NM_DEVICE_IFACE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("IpInterface", "s", NM_DEVICE_IP_IFACE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Driver", "s", NM_DEVICE_DRIVER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DriverVersion", "s", NM_DEVICE_DRIVER_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("FirmwareVersion", "s", NM_DEVICE_FIRMWARE_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Capabilities", "u", NM_DEVICE_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip4Address", "u", NM_DEVICE_IP4_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("State", "u", NM_DEVICE_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("StateReason", "(uu)", NM_DEVICE_STATE_REASON), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("ActiveConnection", "o", NM_DEVICE_ACTIVE_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip4Config", "o", NM_DEVICE_IP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Dhcp4Config", "o", NM_DEVICE_DHCP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Ip6Config", "o", NM_DEVICE_IP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Dhcp6Config", "o", NM_DEVICE_DHCP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("Managed", "b", NM_DEVICE_MANAGED, NM_AUTH_PERMISSION_NETWORK_CONTROL, NM_AUDIT_OP_DEVICE_MANAGED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L ("Autoconnect", "b", NM_DEVICE_AUTOCONNECT, NM_AUTH_PERMISSION_NETWORK_CONTROL, NM_AUDIT_OP_DEVICE_AUTOCONNECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("FirmwareMissing", "b", NM_DEVICE_FIRMWARE_MISSING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("NmPluginMissing", "b", NM_DEVICE_NM_PLUGIN_MISSING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DeviceType", "u", NM_DEVICE_DEVICE_TYPE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AvailableConnections", "ao", NM_DEVICE_AVAILABLE_CONNECTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("PhysicalPortId", "s", NM_DEVICE_PHYSICAL_PORT_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mtu", "u", NM_DEVICE_MTU), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Metered", "u", NM_DEVICE_METERED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("LldpNeighbors", "aa{sv}", NM_DEVICE_LLDP_NEIGHBORS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Real", "b", NM_DEVICE_REAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Ip4Connectivity", "u", NM_DEVICE_IP4_CONNECTIVITY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("Ip6Connectivity", "u", NM_DEVICE_IP6_CONNECTIVITY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("InterfaceFlags", "u", NM_DEVICE_INTERFACE_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - ), - ), + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_DEVICE, + .methods = NM_DEFINE_GDBUS_METHOD_INFOS( + NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( + NM_DEFINE_GDBUS_METHOD_INFO_INIT( + "Reapply", + .in_args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), + NM_DEFINE_GDBUS_ARG_INFO("version_id", "t"), + NM_DEFINE_GDBUS_ARG_INFO("flags", "u"), ), ), + .handle = impl_device_reapply, ), + NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( + NM_DEFINE_GDBUS_METHOD_INFO_INIT( + "GetAppliedConnection", + .in_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("flags", "u"), ), + .out_args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), + NM_DEFINE_GDBUS_ARG_INFO("version_id", "t"), ), ), + .handle = impl_device_get_applied_connection, ), + NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(NM_DEFINE_GDBUS_METHOD_INFO_INIT("Disconnect", ), + .handle = impl_device_disconnect, ), + NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(NM_DEFINE_GDBUS_METHOD_INFO_INIT("Delete", ), + .handle = impl_device_delete, ), ), + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_state_changed, ), + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Udi", "s", NM_DEVICE_UDI), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Path", "s", NM_DEVICE_PATH), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Interface", "s", NM_DEVICE_IFACE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("IpInterface", + "s", + NM_DEVICE_IP_IFACE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Driver", "s", NM_DEVICE_DRIVER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DriverVersion", + "s", + NM_DEVICE_DRIVER_VERSION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("FirmwareVersion", + "s", + NM_DEVICE_FIRMWARE_VERSION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Capabilities", + "u", + NM_DEVICE_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip4Address", + "u", + NM_DEVICE_IP4_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("State", "u", NM_DEVICE_STATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("StateReason", + "(uu)", + NM_DEVICE_STATE_REASON), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ActiveConnection", + "o", + NM_DEVICE_ACTIVE_CONNECTION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip4Config", + "o", + NM_DEVICE_IP4_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Dhcp4Config", + "o", + NM_DEVICE_DHCP4_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip6Config", + "o", + NM_DEVICE_IP6_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Dhcp6Config", + "o", + NM_DEVICE_DHCP6_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L("Managed", + "b", + NM_DEVICE_MANAGED, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + NM_AUDIT_OP_DEVICE_MANAGED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L("Autoconnect", + "b", + NM_DEVICE_AUTOCONNECT, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + NM_AUDIT_OP_DEVICE_AUTOCONNECT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("FirmwareMissing", + "b", + NM_DEVICE_FIRMWARE_MISSING), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("NmPluginMissing", + "b", + NM_DEVICE_NM_PLUGIN_MISSING), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DeviceType", + "u", + NM_DEVICE_DEVICE_TYPE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AvailableConnections", + "ao", + NM_DEVICE_AVAILABLE_CONNECTIONS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PhysicalPortId", + "s", + NM_DEVICE_PHYSICAL_PORT_ID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mtu", "u", NM_DEVICE_MTU), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Metered", "u", NM_DEVICE_METERED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("LldpNeighbors", + "aa{sv}", + NM_DEVICE_LLDP_NEIGHBORS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Real", "b", NM_DEVICE_REAL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip4Connectivity", + "u", + NM_DEVICE_IP4_CONNECTIVITY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip6Connectivity", + "u", + NM_DEVICE_IP6_CONNECTIVITY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("InterfaceFlags", + "u", + NM_DEVICE_INTERFACE_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", + "s", + NM_DEVICE_HW_ADDRESS), ), ), }; const NMDBusInterfaceInfoExtended nm_interface_info_device_statistics = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_STATISTICS, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE ("RefreshRateMs", "u", NM_DEVICE_STATISTICS_REFRESH_RATE_MS, NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS, NM_AUDIT_OP_STATISTICS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("TxBytes", "t", NM_DEVICE_STATISTICS_TX_BYTES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("RxBytes", "t", NM_DEVICE_STATISTICS_RX_BYTES), - ), - ), + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_DEVICE_STATISTICS, + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE( + "RefreshRateMs", + "u", + NM_DEVICE_STATISTICS_REFRESH_RATE_MS, + NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS, + NM_AUDIT_OP_STATISTICS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("TxBytes", + "t", + NM_DEVICE_STATISTICS_TX_BYTES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RxBytes", + "t", + NM_DEVICE_STATISTICS_RX_BYTES), ), ), }; static void -nm_device_class_init (NMDeviceClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMDevicePrivate)); - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/Devices"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device, - &nm_interface_info_device_statistics); - - object_class->dispose = dispose; - object_class->finalize = finalize; - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->constructor = constructor; - object_class->constructed = constructed; - - klass->link_changed = link_changed; - - klass->is_available = is_available; - klass->act_stage2_config = act_stage2_config; - klass->act_stage3_ip_config_start = act_stage3_ip_config_start; - klass->act_stage4_ip_config_timeout = act_stage4_ip_config_timeout; - - klass->get_type_description = get_type_description; - klass->can_auto_connect = can_auto_connect; - klass->can_update_from_platform_link = can_update_from_platform_link; - klass->check_connection_compatible = check_connection_compatible; - klass->check_connection_available = check_connection_available; - klass->can_unmanaged_external_down = can_unmanaged_external_down; - klass->realize_start_notify = realize_start_notify; - klass->unrealize_notify = unrealize_notify; - 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; - klass->parent_changed_notify = parent_changed_notify; - klass->can_reapply_change = can_reapply_change; - klass->reapply_connection = reapply_connection; - klass->set_platform_mtu = set_platform_mtu; - - obj_properties[PROP_UDI] = - g_param_spec_string (NM_DEVICE_UDI, "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PATH] = - g_param_spec_string (NM_DEVICE_PATH, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFACE] = - g_param_spec_string (NM_DEVICE_IFACE, "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP_IFACE] = - g_param_spec_string (NM_DEVICE_IP_IFACE, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DRIVER] = - g_param_spec_string (NM_DEVICE_DRIVER, "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DRIVER_VERSION] = - g_param_spec_string (NM_DEVICE_DRIVER_VERSION, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FIRMWARE_VERSION] = - g_param_spec_string (NM_DEVICE_FIRMWARE_VERSION, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_CAPABILITIES] = - g_param_spec_uint (NM_DEVICE_CAPABILITIES, "", "", - 0, G_MAXUINT32, NM_DEVICE_CAP_NONE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_CARRIER] = - g_param_spec_boolean (NM_DEVICE_CARRIER, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_MTU] = - g_param_spec_uint (NM_DEVICE_MTU, "", "", - 0, G_MAXUINT32, 1500, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP4_ADDRESS] = - g_param_spec_uint (NM_DEVICE_IP4_ADDRESS, "", "", - 0, G_MAXUINT32, 0, /* FIXME */ - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP4_CONFIG] = - g_param_spec_string (NM_DEVICE_IP4_CONFIG, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DHCP4_CONFIG] = - g_param_spec_string (NM_DEVICE_DHCP4_CONFIG, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP6_CONFIG] = - g_param_spec_string (NM_DEVICE_IP6_CONFIG, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DHCP6_CONFIG] = - g_param_spec_string (NM_DEVICE_DHCP6_CONFIG, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STATE] = - g_param_spec_uint (NM_DEVICE_STATE, "", "", - 0, G_MAXUINT32, NM_DEVICE_STATE_UNKNOWN, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STATE_REASON] = - g_param_spec_variant (NM_DEVICE_STATE_REASON, "", "", - G_VARIANT_TYPE ("(uu)"), - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ACTIVE_CONNECTION] = - g_param_spec_string (NM_DEVICE_ACTIVE_CONNECTION, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DEVICE_TYPE] = - g_param_spec_uint (NM_DEVICE_DEVICE_TYPE, "", "", - 0, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_LINK_TYPE] = - g_param_spec_uint (NM_DEVICE_LINK_TYPE, "", "", - 0, G_MAXUINT32, NM_LINK_TYPE_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_MANAGED] = - g_param_spec_boolean (NM_DEVICE_MANAGED, "", "", - FALSE, - G_PARAM_READWRITE | /* via D-Bus */ - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_AUTOCONNECT] = - g_param_spec_boolean (NM_DEVICE_AUTOCONNECT, "", "", - DEFAULT_AUTOCONNECT, - G_PARAM_READWRITE | /* via D-Bus */ - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FIRMWARE_MISSING] = - g_param_spec_boolean (NM_DEVICE_FIRMWARE_MISSING, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_NM_PLUGIN_MISSING] = - g_param_spec_boolean (NM_DEVICE_NM_PLUGIN_MISSING, "", "", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_TYPE_DESC] = - g_param_spec_string (NM_DEVICE_TYPE_DESC, "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_RFKILL_TYPE] = - g_param_spec_uint (NM_DEVICE_RFKILL_TYPE, "", "", - RFKILL_TYPE_WLAN, - RFKILL_TYPE_MAX, - RFKILL_TYPE_UNKNOWN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFINDEX] = - g_param_spec_int (NM_DEVICE_IFINDEX, "", "", - 0, G_MAXINT, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_AVAILABLE_CONNECTIONS] = - g_param_spec_boxed (NM_DEVICE_AVAILABLE_CONNECTIONS, "", "", - G_TYPE_STRV, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PHYSICAL_PORT_ID] = - g_param_spec_string (NM_DEVICE_PHYSICAL_PORT_ID, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_MASTER] = - g_param_spec_object (NM_DEVICE_MASTER, "", "", - NM_TYPE_DEVICE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PARENT] = - g_param_spec_string (NM_DEVICE_PARENT, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_HW_ADDRESS] = - g_param_spec_string (NM_DEVICE_HW_ADDRESS, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PERM_HW_ADDRESS] = - g_param_spec_string (NM_DEVICE_PERM_HW_ADDRESS, "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_HAS_PENDING_ACTION] = - g_param_spec_boolean (NM_DEVICE_HAS_PENDING_ACTION, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_METERED] = - g_param_spec_uint (NM_DEVICE_METERED, "", "", - 0, G_MAXUINT32, NM_METERED_UNKNOWN, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_LLDP_NEIGHBORS] = - g_param_spec_variant (NM_DEVICE_LLDP_NEIGHBORS, "", "", - G_VARIANT_TYPE ("aa{sv}"), - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_REAL] = - g_param_spec_boolean (NM_DEVICE_REAL, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_SLAVES] = - g_param_spec_boxed (NM_DEVICE_SLAVES, "", "", - G_TYPE_STRV, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_STATISTICS_REFRESH_RATE_MS] = - g_param_spec_uint (NM_DEVICE_STATISTICS_REFRESH_RATE_MS, "", "", - 0, UINT32_MAX, 0, - G_PARAM_READWRITE | /* via D-Bus */ - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STATISTICS_TX_BYTES] = - g_param_spec_uint64 (NM_DEVICE_STATISTICS_TX_BYTES, "", "", - 0, UINT64_MAX, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STATISTICS_RX_BYTES] = - g_param_spec_uint64 (NM_DEVICE_STATISTICS_RX_BYTES, "", "", - 0, UINT64_MAX, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IP4_CONNECTIVITY] = - g_param_spec_uint (NM_DEVICE_IP4_CONNECTIVITY, "", "", - NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP6_CONNECTIVITY] = - g_param_spec_uint (NM_DEVICE_IP6_CONNECTIVITY, "", "", - NM_CONNECTIVITY_UNKNOWN, NM_CONNECTIVITY_FULL, NM_CONNECTIVITY_UNKNOWN, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_INTERFACE_FLAGS] = - g_param_spec_uint (NM_DEVICE_INTERFACE_FLAGS, "", "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[STATE_CHANGED] = - g_signal_new (NM_DEVICE_STATE_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceClass, state_changed), - NULL, NULL, NULL, - G_TYPE_NONE, 3, - G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT); - - signals[AUTOCONNECT_ALLOWED] = - g_signal_new (NM_DEVICE_AUTOCONNECT_ALLOWED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - autoconnect_allowed_accumulator, NULL, NULL, - G_TYPE_BOOLEAN, 0); - - signals[IP4_CONFIG_CHANGED] = - g_signal_new (NM_DEVICE_IP4_CONFIG_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT); - - signals[IP6_CONFIG_CHANGED] = - g_signal_new (NM_DEVICE_IP6_CONFIG_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_OBJECT); - - signals[IP6_PREFIX_DELEGATED] = - g_signal_new (NM_DEVICE_IP6_PREFIX_DELEGATED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[IP6_SUBNET_NEEDED] = - g_signal_new (NM_DEVICE_IP6_SUBNET_NEEDED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); - - signals[REMOVED] = - g_signal_new (NM_DEVICE_REMOVED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); - - signals[RECHECK_AUTO_ACTIVATE] = - g_signal_new (NM_DEVICE_RECHECK_AUTO_ACTIVATE, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); - - signals[RECHECK_ASSUME] = - g_signal_new (NM_DEVICE_RECHECK_ASSUME, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); +nm_device_class_init(NMDeviceClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + + g_type_class_add_private(object_class, sizeof(NMDevicePrivate)); + + dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/Devices"); + dbus_object_class->interface_infos = + NM_DBUS_INTERFACE_INFOS(&interface_info_device, &nm_interface_info_device_statistics); + + object_class->dispose = dispose; + object_class->finalize = finalize; + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->constructor = constructor; + object_class->constructed = constructed; + + klass->link_changed = link_changed; + + klass->is_available = is_available; + klass->act_stage2_config = act_stage2_config; + klass->act_stage3_ip_config_start = act_stage3_ip_config_start; + klass->act_stage4_ip_config_timeout = act_stage4_ip_config_timeout; + + klass->get_type_description = get_type_description; + klass->can_auto_connect = can_auto_connect; + klass->can_update_from_platform_link = can_update_from_platform_link; + klass->check_connection_compatible = check_connection_compatible; + klass->check_connection_available = check_connection_available; + klass->can_unmanaged_external_down = can_unmanaged_external_down; + klass->realize_start_notify = realize_start_notify; + klass->unrealize_notify = unrealize_notify; + 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; + klass->parent_changed_notify = parent_changed_notify; + klass->can_reapply_change = can_reapply_change; + klass->reapply_connection = reapply_connection; + klass->set_platform_mtu = set_platform_mtu; + + obj_properties[PROP_UDI] = + g_param_spec_string(NM_DEVICE_UDI, + "", + "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PATH] = g_param_spec_string(NM_DEVICE_PATH, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IFACE] = + g_param_spec_string(NM_DEVICE_IFACE, + "", + "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IP_IFACE] = g_param_spec_string(NM_DEVICE_IP_IFACE, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DRIVER] = + g_param_spec_string(NM_DEVICE_DRIVER, + "", + "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DRIVER_VERSION] = + g_param_spec_string(NM_DEVICE_DRIVER_VERSION, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_FIRMWARE_VERSION] = + g_param_spec_string(NM_DEVICE_FIRMWARE_VERSION, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_CAPABILITIES] = + g_param_spec_uint(NM_DEVICE_CAPABILITIES, + "", + "", + 0, + G_MAXUINT32, + NM_DEVICE_CAP_NONE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_CARRIER] = g_param_spec_boolean(NM_DEVICE_CARRIER, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_MTU] = g_param_spec_uint(NM_DEVICE_MTU, + "", + "", + 0, + G_MAXUINT32, + 1500, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IP4_ADDRESS] = + g_param_spec_variant(NM_DEVICE_IP4_ADDRESS, + "", + "", + G_VARIANT_TYPE_UINT32, + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IP4_CONFIG] = + g_param_spec_string(NM_DEVICE_IP4_CONFIG, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DHCP4_CONFIG] = + g_param_spec_string(NM_DEVICE_DHCP4_CONFIG, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IP6_CONFIG] = + g_param_spec_string(NM_DEVICE_IP6_CONFIG, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DHCP6_CONFIG] = + g_param_spec_string(NM_DEVICE_DHCP6_CONFIG, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_STATE] = g_param_spec_uint(NM_DEVICE_STATE, + "", + "", + 0, + G_MAXUINT32, + NM_DEVICE_STATE_UNKNOWN, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_STATE_REASON] = + g_param_spec_variant(NM_DEVICE_STATE_REASON, + "", + "", + G_VARIANT_TYPE("(uu)"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_ACTIVE_CONNECTION] = + g_param_spec_string(NM_DEVICE_ACTIVE_CONNECTION, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DEVICE_TYPE] = + g_param_spec_uint(NM_DEVICE_DEVICE_TYPE, + "", + "", + 0, + G_MAXUINT32, + NM_DEVICE_TYPE_UNKNOWN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_LINK_TYPE] = + g_param_spec_uint(NM_DEVICE_LINK_TYPE, + "", + "", + 0, + G_MAXUINT32, + NM_LINK_TYPE_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_MANAGED] = g_param_spec_boolean(NM_DEVICE_MANAGED, + "", + "", + FALSE, + G_PARAM_READWRITE | /* via D-Bus */ + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_AUTOCONNECT] = g_param_spec_boolean(NM_DEVICE_AUTOCONNECT, + "", + "", + DEFAULT_AUTOCONNECT, + G_PARAM_READWRITE | /* via D-Bus */ + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_FIRMWARE_MISSING] = + g_param_spec_boolean(NM_DEVICE_FIRMWARE_MISSING, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_NM_PLUGIN_MISSING] = + g_param_spec_boolean(NM_DEVICE_NM_PLUGIN_MISSING, + "", + "", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_TYPE_DESC] = + g_param_spec_string(NM_DEVICE_TYPE_DESC, + "", + "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_RFKILL_TYPE] = + g_param_spec_uint(NM_DEVICE_RFKILL_TYPE, + "", + "", + RFKILL_TYPE_WLAN, + RFKILL_TYPE_MAX, + RFKILL_TYPE_UNKNOWN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IFINDEX] = g_param_spec_int(NM_DEVICE_IFINDEX, + "", + "", + 0, + G_MAXINT, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_AVAILABLE_CONNECTIONS] = + g_param_spec_boxed(NM_DEVICE_AVAILABLE_CONNECTIONS, + "", + "", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PHYSICAL_PORT_ID] = + g_param_spec_string(NM_DEVICE_PHYSICAL_PORT_ID, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_MASTER] = g_param_spec_object(NM_DEVICE_MASTER, + "", + "", + NM_TYPE_DEVICE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PARENT] = g_param_spec_string(NM_DEVICE_PARENT, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_HW_ADDRESS] = + g_param_spec_string(NM_DEVICE_HW_ADDRESS, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_PERM_HW_ADDRESS] = + g_param_spec_string(NM_DEVICE_PERM_HW_ADDRESS, + "", + "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_HAS_PENDING_ACTION] = + g_param_spec_boolean(NM_DEVICE_HAS_PENDING_ACTION, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_METERED] = g_param_spec_uint(NM_DEVICE_METERED, + "", + "", + 0, + G_MAXUINT32, + NM_METERED_UNKNOWN, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_LLDP_NEIGHBORS] = + g_param_spec_variant(NM_DEVICE_LLDP_NEIGHBORS, + "", + "", + G_VARIANT_TYPE("aa{sv}"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_REAL] = g_param_spec_boolean(NM_DEVICE_REAL, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_SLAVES] = g_param_spec_boxed(NM_DEVICE_SLAVES, + "", + "", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_STATISTICS_REFRESH_RATE_MS] = + g_param_spec_uint(NM_DEVICE_STATISTICS_REFRESH_RATE_MS, + "", + "", + 0, + UINT32_MAX, + 0, + G_PARAM_READWRITE | /* via D-Bus */ + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_STATISTICS_TX_BYTES] = + g_param_spec_uint64(NM_DEVICE_STATISTICS_TX_BYTES, + "", + "", + 0, + UINT64_MAX, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_STATISTICS_RX_BYTES] = + g_param_spec_uint64(NM_DEVICE_STATISTICS_RX_BYTES, + "", + "", + 0, + UINT64_MAX, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_IP4_CONNECTIVITY] = + g_param_spec_uint(NM_DEVICE_IP4_CONNECTIVITY, + "", + "", + NM_CONNECTIVITY_UNKNOWN, + NM_CONNECTIVITY_FULL, + NM_CONNECTIVITY_UNKNOWN, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IP6_CONNECTIVITY] = + g_param_spec_uint(NM_DEVICE_IP6_CONNECTIVITY, + "", + "", + NM_CONNECTIVITY_UNKNOWN, + NM_CONNECTIVITY_FULL, + NM_CONNECTIVITY_UNKNOWN, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_INTERFACE_FLAGS] = + g_param_spec_uint(NM_DEVICE_INTERFACE_FLAGS, + "", + "", + 0, + G_MAXUINT32, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + signals[STATE_CHANGED] = g_signal_new(NM_DEVICE_STATE_CHANGED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(NMDeviceClass, state_changed), + NULL, + NULL, + NULL, + G_TYPE_NONE, + 3, + G_TYPE_UINT, + G_TYPE_UINT, + G_TYPE_UINT); + + signals[AUTOCONNECT_ALLOWED] = g_signal_new(NM_DEVICE_AUTOCONNECT_ALLOWED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_LAST, + 0, + autoconnect_allowed_accumulator, + NULL, + NULL, + G_TYPE_BOOLEAN, + 0); + + signals[IP4_CONFIG_CHANGED] = g_signal_new(NM_DEVICE_IP4_CONFIG_CHANGED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + G_TYPE_OBJECT, + G_TYPE_OBJECT); + + signals[IP6_CONFIG_CHANGED] = g_signal_new(NM_DEVICE_IP6_CONFIG_CHANGED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + G_TYPE_OBJECT, + G_TYPE_OBJECT); + + signals[IP6_PREFIX_DELEGATED] = g_signal_new(NM_DEVICE_IP6_PREFIX_DELEGATED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + signals[IP6_SUBNET_NEEDED] = g_signal_new(NM_DEVICE_IP6_SUBNET_NEEDED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + + signals[REMOVED] = g_signal_new(NM_DEVICE_REMOVED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + + signals[RECHECK_AUTO_ACTIVATE] = g_signal_new(NM_DEVICE_RECHECK_AUTO_ACTIVATE, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); + + signals[RECHECK_ASSUME] = g_signal_new(NM_DEVICE_RECHECK_ASSUME, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 0); } /* Connection defaults from plugins */ -NM_CON_DEFAULT_NOP ("cdma.mtu"); -NM_CON_DEFAULT_NOP ("gsm.mtu"); -NM_CON_DEFAULT_NOP ("wifi.powersave"); -NM_CON_DEFAULT_NOP ("wifi.wake-on-wlan"); -NM_CON_DEFAULT_NOP ("wifi-sec.pmf"); -NM_CON_DEFAULT_NOP ("wifi-sec.fils"); +NM_CON_DEFAULT_NOP("cdma.mtu"); +NM_CON_DEFAULT_NOP("gsm.mtu"); +NM_CON_DEFAULT_NOP("wifi.ap-isolation"); +NM_CON_DEFAULT_NOP("wifi.powersave"); +NM_CON_DEFAULT_NOP("wifi.wake-on-wlan"); +NM_CON_DEFAULT_NOP("wifi-sec.pmf"); +NM_CON_DEFAULT_NOP("wifi-sec.fils"); |