summaryrefslogtreecommitdiff
path: root/src/core/devices/nm-device.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-08-06 15:17:05 +0200
committerThomas Haller <thaller@redhat.com>2021-09-30 09:56:19 +0200
commitd64b4a30d21fa98f6a7d11c28ac21a8f9d8ee299 (patch)
treeddb782113363dea1fa8e0a38e2570c269b98ff24 /src/core/devices/nm-device.c
parentf20431bf89fd00c88659275f69419601cf98cb6b (diff)
downloadNetworkManager-next.tar.gz
core: rework IP configuration in NetworkManager using layer 3 configurationnext
Completely rework IP configuration in the daemon. Use NML3Cfg as layer 3 manager for the IP configuration of an interface. Use NML3ConfigData as pieces of configuration that the various components collect and configure. NMDevice is managing most of the IP configuration at a higher level, that is, it starts DHCP and other IP methods. Rework the state handling there. This is a huge rework of how NetworkManager daemon handles IP configuration. Some fallout is to be expected. It appears the patch deletes many lines of code. That is not accurate, because you also have to count the files `src/core/nm-l3*`, which were unused previously. Co-authored-by: Beniamino Galvani <bgalvani@redhat.com>
Diffstat (limited to 'src/core/devices/nm-device.c')
-rw-r--r--src/core/devices/nm-device.c7365
1 files changed, 2917 insertions, 4448 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 7faec23c8e..a9b77fe05c 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -34,6 +34,8 @@
#include "nm-device-private.h"
#include "nm-l3cfg.h"
#include "nm-l3-config-data.h"
+#include "nm-l3-ipv4ll.h"
+#include "nm-l3-ipv6ll.h"
#include "NetworkManagerUtils.h"
#include "nm-manager.h"
#include "libnm-platform/nm-platform.h"
@@ -42,14 +44,13 @@
#include "libnm-platform/nmp-rules-manager.h"
#include "ndisc/nm-ndisc.h"
#include "ndisc/nm-lndp-ndisc.h"
+
#include "dhcp/nm-dhcp-manager.h"
#include "dhcp/nm-dhcp-utils.h"
#include "nm-act-request.h"
-#include "nm-proxy-config.h"
-#include "nm-ip4-config.h"
-#include "nm-ip6-config.h"
#include "nm-pacrunner-manager.h"
#include "dnsmasq/nm-dnsmasq-manager.h"
+#include "nm-ip-config.h"
#include "nm-dhcp-config.h"
#include "nm-rfkill-manager.h"
#include "nm-firewall-utils.h"
@@ -66,7 +67,6 @@
#include "nm-config.h"
#include "c-list/src/c-list.h"
#include "dns/nm-dns-manager.h"
-#include "nm-acd-manager.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-systemd-core/nm-sd.h"
#include "nm-lldp-listener.h"
@@ -86,19 +86,7 @@
#define DEFAULT_AUTOCONNECT TRUE
-static guint32
-dhcp_grace_period_from_timeout(guint32 timeout)
-{
-#define DHCP_GRACE_PERIOD_MULTIPLIER 2U
-
- nm_assert(timeout > 0);
- nm_assert(timeout < G_MAXINT32);
-
- if (timeout < G_MAXUINT32 / DHCP_GRACE_PERIOD_MULTIPLIER)
- return timeout * DHCP_GRACE_PERIOD_MULTIPLIER;
-
- return G_MAXUINT32;
-}
+#define GRACE_PERIOD_MULTIPLIER 2U
#define CARRIER_WAIT_TIME_MS 6000
#define CARRIER_WAIT_TIME_AFTER_MTU_MS 10000
@@ -117,6 +105,13 @@ typedef enum {
CLEANUP_TYPE_DECONFIGURE,
} CleanupType;
+typedef enum _nm_packed {
+ ADDR_METHOD_STATE_DISABLED,
+ ADDR_METHOD_STATE_PENDING,
+ ADDR_METHOD_STATE_GOOD,
+ ADDR_METHOD_STATE_FAILED,
+} AddrMethodState;
+
typedef struct {
CList lst_slave;
NMDevice *slave;
@@ -139,28 +134,61 @@ typedef struct {
NMOptionBool autoprobe;
} SriovOp;
-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_LL_6,
+
+#define L3_CONFIG_DATA_TYPE_LL_X(IS_IPv4) \
+ ((IS_IPv4) ? L3_CONFIG_DATA_TYPE_LL_4 : L3_CONFIG_DATA_TYPE_LL_6)
+
L3_CONFIG_DATA_TYPE_AC_6,
+ L3_CONFIG_DATA_TYPE_PD_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,
+
+#define L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4) \
+ ((IS_IPv4) ? L3_CONFIG_DATA_TYPE_DHCP_4 : L3_CONFIG_DATA_TYPE_DHCP_6)
+
+ L3_CONFIG_DATA_TYPE_SHARED_4,
+ L3_CONFIG_DATA_TYPE_DEVIP_UNSPEC,
+ L3_CONFIG_DATA_TYPE_DEVIP_4,
+ L3_CONFIG_DATA_TYPE_DEVIP_6,
+
+#define L3_CONFIG_DATA_TYPE_DEVIP(addr_family) \
+ ({ \
+ L3ConfigDataType _t; \
+ \
+ switch (addr_family) { \
+ case AF_INET: \
+ _t = L3_CONFIG_DATA_TYPE_DEVIP_4; \
+ break; \
+ case AF_INET6: \
+ _t = L3_CONFIG_DATA_TYPE_DEVIP_6; \
+ break; \
+ default: \
+ nm_assert_not_reached(); \
+ /* fall-through */ \
+ case AF_UNSPEC: \
+ _t = L3_CONFIG_DATA_TYPE_DEVIP_UNSPEC; \
+ break; \
+ } \
+ \
+ _t; \
+ })
+
+ L3_CONFIG_DATA_TYPE_MANUALIP,
+
_L3_CONFIG_DATA_TYPE_NUM,
_L3_CONFIG_DATA_TYPE_NONE,
+ _L3_CONFIG_DATA_TYPE_ACD_ONLY,
} L3ConfigDataType;
-typedef struct {
- AcdCallback callback;
- NMDevice * device;
- NMIP4Config **configs;
-} AcdData;
+G_STATIC_ASSERT(NM_L3CFG_CONFIG_PRIORITY_IPV4LL == L3_CONFIG_DATA_TYPE_LL_4);
typedef enum {
HW_ADDR_TYPE_UNSET = 0,
@@ -177,19 +205,73 @@ typedef enum {
} 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. */
-} AppliedConfig;
+ NMIPConfig *ip_config;
+} L3IPData;
+
+typedef struct {
+ GSource *check_async_source;
+ GSource *req_timeout_source;
+ union {
+ const NMDeviceIPState state;
+ NMDeviceIPState state_;
+ };
+ bool wait_for_carrier : 1;
+ bool wait_for_ports : 1;
+ bool is_disabled : 1;
+ bool is_ignore : 1;
+ bool do_reapply : 1;
+} IPStateData;
typedef struct {
- NMDhcpClient *client;
- NMDhcpConfig *config;
- gulong notify_sigid;
- guint grace_id;
- bool grace_pending : 1;
- bool was_active : 1;
-} DhcpData;
+ NMDhcpClient * client;
+ NMDhcpConfig * config;
+ gulong notify_sigid;
+ NMDeviceIPState state;
+ union {
+ struct {
+ } v4;
+ struct {
+ guint needed_prefixes;
+ NMNDiscDHCPLevel mode;
+ } v6;
+ };
+} IPDhcpStateData;
+
+typedef struct {
+ NMDeviceIPState state;
+ NMDeviceStateReason failed_reason;
+} IPDevStateData;
+
+typedef struct {
+ NMDeviceIPState state;
+ union {
+ struct {
+ NMDnsMasqManager * dnsmasq_manager;
+ NMNetnsSharedIPHandle *shared_ip_handle;
+ NMFirewallConfig * firewall_config;
+ gulong dnsmasq_state_id;
+ } v4;
+ struct {
+ } v6;
+ };
+} IPSharedStateData;
+
+typedef struct {
+ NMDeviceIPState state;
+ union {
+ struct {
+ NML3IPv4LL * ipv4ll;
+ NML3IPv4LLRegistration *ipv4ll_registation;
+ GSource * timeout_source;
+ } v4;
+ struct {
+ NML3IPv6LL * ipv6ll;
+ GSource * retry_source;
+ NML3IPv6LLState llstate;
+ struct in6_addr lladdr;
+ } v6;
+ };
+} IPLLStateData;
struct _NMDeviceConnectivityHandle {
CList concheck_lst;
@@ -234,8 +316,7 @@ typedef struct {
enum {
STATE_CHANGED,
AUTOCONNECT_ALLOWED,
- IP4_CONFIG_CHANGED,
- IP6_CONFIG_CHANGED,
+ L3CD_CHANGED,
IP6_PREFIX_DELEGATED,
IP6_SUBNET_NEEDED,
REMOVED,
@@ -260,6 +341,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDevice,
PROP_IP4_ADDRESS,
PROP_IP4_CONFIG,
PROP_DHCP4_CONFIG,
+
+#define PROP_DHCPX_CONFIG(IS_IPv4) ((IS_IPv4) ? PROP_DHCP4_CONFIG : PROP_DHCP6_CONFIG)
+
PROP_IP6_CONFIG,
PROP_DHCP6_CONFIG,
PROP_STATE,
@@ -293,8 +377,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDevice,
PROP_INTERFACE_FLAGS, );
typedef struct _NMDevicePrivate {
- bool in_state_changed;
-
guint device_link_changed_id;
guint device_ip_link_changed_id;
@@ -308,22 +390,12 @@ typedef struct _NMDevicePrivate {
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];
- };
-
struct {
const char **arr;
guint len;
guint alloc;
} pending_actions;
- GSList *dad6_failed_addrs;
-
NMDBusTrackObjPath parent_device;
char *udi;
@@ -339,15 +411,33 @@ typedef struct _NMDevicePrivate {
};
union {
+ NML3Cfg *const l3cfg;
+ NML3Cfg * l3cfg_;
+ };
+
+ union {
+ struct {
+ L3IPData l3ipdata_6;
+ L3IPData l3ipdata_4;
+ };
+ L3IPData l3ipdata_x[2];
+ };
+
+ NML3CfgCommitTypeHandle *l3cfg_commit_type;
+
+ union {
const int ifindex;
int ifindex_;
};
+
union {
const int ip_ifindex;
int ip_ifindex_;
};
- NMNetnsSharedIPHandle *shared_ip_handle;
+ union {
+ const NML3ConfigData *d;
+ } l3cds[_L3_CONFIG_DATA_TYPE_NUM];
int parent_ifindex;
@@ -370,9 +460,6 @@ typedef struct _NMDevicePrivate {
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;
@@ -386,6 +473,8 @@ typedef struct _NMDevicePrivate {
bool
hw_addr_perm_fake : 1; /* whether the permanent HW address could not be read and is a fake */
+ guint8 in_state_changed : 4;
+
NMUtilsStableType current_stable_id_type : 3;
bool nm_owned : 1; /* whether the device is a device owned and created by NM */
@@ -413,21 +502,8 @@ typedef struct _NMDevicePrivate {
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];
- };
+ GSource * activation_idle_source;
+ ActivationHandleFunc activation_func;
guint recheck_assume_id;
@@ -451,7 +527,7 @@ typedef struct _NMDevicePrivate {
gulong config_changed_id;
gulong ifindex_changed_id;
guint32 mtu;
- guint32 ip6_mtu;
+ guint32 ip6_mtu; /* FIXME(l3cfg) */
guint32 mtu_initial;
guint32 ip6_mtu_initial;
NMDeviceMtuSource mtu_source;
@@ -468,6 +544,14 @@ typedef struct _NMDevicePrivate {
gint64 carrier_wait_until_ms;
union {
+ struct {
+ NML3ConfigMergeFlags l3config_merge_flags_6;
+ NML3ConfigMergeFlags l3config_merge_flags_4;
+ };
+ NML3ConfigMergeFlags l3config_merge_flags_x[2];
+ };
+
+ union {
const NMDeviceSysIfaceState sys_iface_state;
NMDeviceSysIfaceState sys_iface_state_;
};
@@ -477,9 +561,6 @@ typedef struct _NMDevicePrivate {
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;
@@ -495,102 +576,86 @@ typedef struct _NMDevicePrivate {
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;
-
- bool ip_config_started : 1;
bool tc_committed : 1;
- char *current_stable_id;
+ NMDeviceStageState stage1_sriov_state : 3;
- union {
- struct {
- GSource *ip_req_timeout_source_6;
- GSource *ip_req_timeout_source_4;
- };
- GSource *ip_req_timeout_source_x[2];
- };
+ char *current_stable_id;
- /* Proxy Configuration */
- NMProxyConfig * proxy_config;
NMPacrunnerConfId *pacrunner_conf_id;
- /* IP configuration info. Combined config from VPN, settings, and device */
+ struct {
+ union {
+ const NMDeviceIPState state;
+ NMDeviceIPState state_;
+ };
+ } ip_data;
+
union {
struct {
- NMIP6Config *ip_config_6;
- NMIP4Config *ip_config_4;
+ IPStateData ip_data_6;
+ IPStateData ip_data_4;
};
- NMIPConfig *ip_config_x[2];
+ IPStateData ip_data_x[2];
};
- /* Config from DHCP, PPP, LLv4, etc */
- AppliedConfig dev_ip_config_4;
+ struct {
+ NMDeviceIPState state;
+ } ipmanual_data;
- /* config from the setting */
union {
struct {
- NMIP6Config *con_ip_config_6;
- NMIP4Config *con_ip_config_4;
+ IPDhcpStateData ipdhcp_data_6;
+ IPDhcpStateData ipdhcp_data_4;
};
- NMIPConfig *con_ip_config_x[2];
+ IPDhcpStateData ipdhcp_data_x[2];
};
- /* Stuff added outside NM */
+ struct {
+ NMNDisc * ndisc;
+ GSource * ndisc_grace_source;
+ gulong ndisc_changed_id;
+ gulong ndisc_timeout_id;
+ NMDeviceIPState state;
+ } ipac6_data;
+
union {
struct {
- NMIP6Config *ext_ip_config_6;
- NMIP4Config *ext_ip_config_4;
+ IPLLStateData ipll_data_6;
+ IPLLStateData ipll_data_4;
};
- NMIPConfig *ext_ip_config_x[2];
+ IPLLStateData ipll_data_x[2];
};
- /* VPNs which use this device */
union {
struct {
- GSList *vpn_configs_6;
- GSList *vpn_configs_4;
+ IPSharedStateData ipshared_data_6;
+ IPSharedStateData ipshared_data_4;
};
- GSList *vpn_configs_x[2];
+ IPSharedStateData ipshared_data_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;
+ IPDevStateData ipdev_data_6;
+ IPDevStateData ipdev_data_4;
};
- AppliedConfig dev2_ip_config_x[2];
+ IPDevStateData ipdev_data_x[2];
};
- /* DHCPv4 tracking */
- struct {
- char *pac_url;
- } dhcp4;
+ IPDevStateData ipdev_data_unspec;
struct {
- /* IP6 config from DHCP */
- AppliedConfig ip6_config;
- /* Event ID of the current IP6 config from DHCP */
- char * event_id;
- NMNDiscDHCPLevel mode;
- guint needed_prefixes;
- } dhcp6;
+ /* If we set the addrgenmode6, this records the previously set value. */
+ guint8 previous_mode_val;
- union {
- struct {
- DhcpData dhcp_data_6;
- DhcpData dhcp_data_4;
- };
- DhcpData dhcp_data_x[2];
- };
+ /* whether @previous_mode_val is set. */
+ bool previous_mode_has : 1;
+ } addrgenmode6_data;
struct {
NMLogDomain log_domain;
@@ -602,58 +667,15 @@ typedef struct _NMDevicePrivate {
guint deadline;
} gw_ping;
- /* dnsmasq stuff for shared connections */
- NMDnsMasqManager *dnsmasq_manager;
- gulong dnsmasq_state_id;
-
/* Firewall */
FirewallState fw_state : 4;
NMFirewalldManager * fw_mgr;
NMFirewalldManagerCallId *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;
@@ -709,6 +731,8 @@ typedef struct _NMDevicePrivate {
bool mtu_force_set_done : 1;
+ bool needs_ip6_subnet : 1;
+
NMOptionBool promisc_reset;
} NMDevicePrivate;
@@ -718,59 +742,83 @@ G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT)
/*****************************************************************************/
+static NMSettingConnectionMdns _prop_get_connection_mdns(NMDevice *self);
+static NMSettingConnectionLlmnr _prop_get_connection_llmnr(NMDevice *self);
+
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 void _dev_l3_cfg_commit(NMDevice *self, gboolean do_sync);
-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 void _dev_l3_cfg_commit_type_reset(NMDevice *self);
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 _dev_ipll6_start(NMDevice *self);
-static guint32 default_route_metric_penalty_get(NMDevice *self, int addr_family);
+static void _dev_ipac6_start_continue(NMDevice *self);
-static guint _prop_get_ipv4_dad_timeout(NMDevice *self);
+static guint32 _dev_default_route_metric_penalty_get(NMDevice *self, int addr_family);
-static NMIP6Config *dad6_get_pending_addresses(NMDevice *self);
+static guint32 _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 GBytes *_prop_get_ipv6_dhcp_duid(NMDevice * self,
+ NMConnection *connection,
+ GBytes * hwaddr,
+ gboolean * out_enforce);
+
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 queued_state_clear(NMDevice *device);
+static void ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data);
+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);
+static void _cancel_activation(NMDevice *self);
+
+static void _dev_ipll4_notify_event(NMDevice *self);
+
+static void _dev_ip_state_check(NMDevice *self, int addr_family);
+
+static void _dev_ipmanual_check_ready(NMDevice *self);
+
+static void
+_dev_ipdhcpx_cleanup(NMDevice *self, int addr_family, gboolean reset_dhcp_config, gboolean release);
+
+static void _dev_ip_state_check_async(NMDevice *self, int addr_family);
+
+static void _dev_ipdhcpx_set_state(NMDevice *self, int addr_family, NMDeviceIPState state);
+
+static void _dev_ipdhcpx_restart(NMDevice *self, int addr_family, gboolean release);
+
+static void _dev_ipdhcpx_handle_accept(NMDevice *self, int addr_family, const NML3ConfigData *l3cd);
+
+static gboolean
+_dev_ipac6_grace_period_start(NMDevice *self, guint32 timeout_sec, gboolean force_restart);
+
+static void _dev_ipac6_start(NMDevice *self);
+
+static void _dev_unamanged_check_external_down(NMDevice *self, gboolean only_if_unmanaged);
+
+static void _dev_ipshared4_start(NMDevice *self);
+
+static void _dev_ipshared6_start(NMDevice *self);
+
+static void _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type);
static void concheck_update_state(NMDevice * self,
int addr_family,
@@ -780,8 +828,79 @@ static void concheck_update_state(NMDevice * self,
static void sriov_op_cb(GError *error, gpointer user_data);
static void device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice *self);
-static gboolean device_link_changed(NMDevice *self);
-static void check_ip_state(NMDevice *self, gboolean may_fail, gboolean full_state_update);
+static gboolean device_link_changed(gpointer user_data);
+
+/*****************************************************************************/
+
+#define _NMLOG_addr_family(level, prefix, addr_family, fmt, ...) \
+ G_STMT_START \
+ { \
+ const int _addr_family2 = (addr_family); \
+ \
+ _NMLOG(level, \
+ (_addr_family2 == AF_UNSPEC ? LOGD_IP : LOGD_IPX(NM_IS_IPv4(_addr_family2))), \
+ "" prefix "%s: " fmt, \
+ nm_utils_addr_family_to_str(_addr_family2), \
+ ##__VA_ARGS__); \
+ } \
+ G_STMT_END
+
+#define _NMLOG_ip(level, ...) _NMLOG_addr_family(level, "ip", __VA_ARGS__)
+#define _LOGT_ip(...) _NMLOG_ip(LOGL_TRACE, __VA_ARGS__)
+#define _LOGD_ip(...) _NMLOG_ip(LOGL_DEBUG, __VA_ARGS__)
+#define _LOGI_ip(...) _NMLOG_ip(LOGL_INFO, __VA_ARGS__)
+#define _LOGW_ip(...) _NMLOG_ip(LOGL_WARN, __VA_ARGS__)
+
+#define _NMLOG_ipll(level, ...) _NMLOG_addr_family(level, "ip:ll", __VA_ARGS__)
+#define _LOGT_ipll(...) _NMLOG_ipll(LOGL_TRACE, __VA_ARGS__)
+#define _LOGD_ipll(...) _NMLOG_ipll(LOGL_DEBUG, __VA_ARGS__)
+#define _LOGI_ipll(...) _NMLOG_ipll(LOGL_INFO, __VA_ARGS__)
+#define _LOGW_ipll(...) _NMLOG_ipll(LOGL_WARN, __VA_ARGS__)
+
+#define _NMLOG_ipdev(level, ...) _NMLOG_addr_family(level, "ip:dev", __VA_ARGS__)
+#define _LOGT_ipdev(...) _NMLOG_ipdev(LOGL_TRACE, __VA_ARGS__)
+#define _LOGD_ipdev(...) _NMLOG_ipdev(LOGL_DEBUG, __VA_ARGS__)
+#define _LOGI_ipdev(...) _NMLOG_ipdev(LOGL_INFO, __VA_ARGS__)
+#define _LOGW_ipdev(...) _NMLOG_ipdev(LOGL_WARN, __VA_ARGS__)
+
+#define _NMLOG_ipdhcp(level, ...) _NMLOG_addr_family(level, "ip:dhcp", __VA_ARGS__)
+#define _LOGT_ipdhcp(...) _NMLOG_ipdhcp(LOGL_TRACE, __VA_ARGS__)
+#define _LOGD_ipdhcp(...) _NMLOG_ipdhcp(LOGL_DEBUG, __VA_ARGS__)
+#define _LOGI_ipdhcp(...) _NMLOG_ipdhcp(LOGL_INFO, __VA_ARGS__)
+#define _LOGW_ipdhcp(...) _NMLOG_ipdhcp(LOGL_WARN, __VA_ARGS__)
+
+#define _NMLOG_ipshared(level, ...) _NMLOG_addr_family(level, "ip:shared", __VA_ARGS__)
+#define _LOGT_ipshared(...) _NMLOG_ipshared(LOGL_TRACE, __VA_ARGS__)
+#define _LOGD_ipshared(...) _NMLOG_ipshared(LOGL_DEBUG, __VA_ARGS__)
+#define _LOGI_ipshared(...) _NMLOG_ipshared(LOGL_INFO, __VA_ARGS__)
+#define _LOGW_ipshared(...) _NMLOG_ipshared(LOGL_WARN, __VA_ARGS__)
+
+#define _NMLOG_ipac6(level, ...) _NMLOG_addr_family(level, "ip:ac6", AF_UNSPEC, __VA_ARGS__)
+#define _LOGT_ipac6(...) _NMLOG_ipac6(LOGL_TRACE, __VA_ARGS__)
+#define _LOGD_ipac6(...) _NMLOG_ipac6(LOGL_DEBUG, __VA_ARGS__)
+#define _LOGI_ipac6(...) _NMLOG_ipac6(LOGL_INFO, __VA_ARGS__)
+#define _LOGW_ipac6(...) _NMLOG_ipac6(LOGL_WARN, __VA_ARGS__)
+
+#define _NMLOG_ipmanual(level, ...) _NMLOG_addr_family(level, "ip:manual", AF_UNSPEC, __VA_ARGS__)
+#define _LOGT_ipmanual(...) _NMLOG_ipmanual(LOGL_TRACE, __VA_ARGS__)
+#define _LOGD_ipmanual(...) _NMLOG_ipmanual(LOGL_DEBUG, __VA_ARGS__)
+#define _LOGI_ipmanual(...) _NMLOG_ipmanual(LOGL_INFO, __VA_ARGS__)
+#define _LOGW_ipmanual(...) _NMLOG_ipmanual(LOGL_WARN, __VA_ARGS__)
+
+/*****************************************************************************/
+
+#define _CACHED_BOOL(cached_value, cmd) \
+ ({ \
+ NMTernary *const _cached_value = (cached_value); \
+ \
+ nm_assert(_cached_value); \
+ nm_assert_is_ternary(*_cached_value); \
+ \
+ if (*_cached_value == NM_TERNARY_DEFAULT) \
+ *_cached_value = !!(cmd); \
+ \
+ !!(*_cached_value); \
+ })
/*****************************************************************************/
@@ -1309,7 +1428,7 @@ _prop_get_connection_lldp(NMDevice *self)
return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX;
}
-static guint
+static guint32
_prop_get_ipv4_dad_timeout(NMDevice *self)
{
NMConnection * connection;
@@ -1321,6 +1440,9 @@ _prop_get_ipv4_dad_timeout(NMDevice *self)
s_ip4 = nm_connection_get_setting_ip4_config(connection);
if (s_ip4)
timeout = nm_setting_ip_config_get_dad_timeout(s_ip4);
+
+ nm_assert(timeout >= -1 && timeout <= NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX);
+
if (timeout >= 0)
return timeout;
@@ -1337,8 +1459,8 @@ _prop_get_ipvx_dhcp_timeout(NMDevice *self, int addr_family)
{
NMDeviceClass *klass;
NMConnection * connection;
- int timeout_i;
guint32 timeout;
+ int timeout_i;
nm_assert(NM_IS_DEVICE(self));
nm_assert_addr_family(addr_family);
@@ -1381,6 +1503,37 @@ out:
}
static guint32
+_prop_get_ipvx_dns_priority(NMDevice *self, int addr_family)
+{
+ NMConnection * connection;
+ NMSettingIPConfig *s_ip;
+ int prio = 0;
+
+ connection = nm_device_get_applied_connection(self);
+ s_ip = nm_connection_get_setting_ip_config(connection, addr_family);
+ if (s_ip)
+ prio = nm_setting_ip_config_get_dns_priority(s_ip);
+
+ if (prio == 0) {
+ prio = nm_config_data_get_connection_default_int64(
+ NM_CONFIG_GET_DATA,
+ NM_IS_IPv4(addr_family) ? NM_CON_DEFAULT("ipv4.dns-priority")
+ : NM_CON_DEFAULT("ipv6.dns-priority"),
+ self,
+ G_MININT32,
+ G_MAXINT32,
+ 0);
+ if (prio == 0) {
+ prio = nm_device_is_vpn(self) ? NM_DNS_PRIORITY_DEFAULT_VPN
+ : NM_DNS_PRIORITY_DEFAULT_NORMAL;
+ }
+ }
+
+ nm_assert(prio != 0);
+ return prio;
+}
+
+static guint32
_prop_get_ipvx_required_timeout(NMDevice *self, int addr_family)
{
NMConnection * connection;
@@ -1414,6 +1567,25 @@ _prop_get_ipvx_required_timeout(NMDevice *self, int addr_family)
0);
}
+static gboolean
+_prop_get_ipvx_may_fail(NMDevice *self, int addr_family)
+{
+ NMConnection * connection;
+ NMSettingIPConfig *s_ip = NULL;
+
+ connection = nm_device_get_applied_connection(self);
+ if (connection)
+ s_ip = nm_connection_get_setting_ip_config(connection, addr_family);
+
+ return !s_ip || nm_setting_ip_config_get_may_fail(s_ip);
+}
+
+static gboolean
+_prop_get_ipvx_may_fail_cached(NMDevice *self, int addr_family, NMTernary *cache)
+{
+ return _CACHED_BOOL(cache, _prop_get_ipvx_may_fail(self, addr_family));
+}
+
/**
* _prop_get_ipvx_dhcp_iaid:
* @self: the #NMDevice
@@ -2390,27 +2562,6 @@ concheck_get_mgr(NMDevice *self)
return priv->concheck_mgr;
}
-NMIP4Config *
-nm_device_ip4_config_new(NMDevice *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)
-{
- 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_assert_addr_family(addr_family);
-
- return NM_IS_IPv4(addr_family) ? (gpointer) nm_device_ip4_config_new(self)
- : (gpointer) nm_device_ip6_config_new(self);
-}
-
NML3ConfigData *
nm_device_create_l3_config_data(NMDevice *self, NMIPConfigSource source)
{
@@ -2425,98 +2576,27 @@ nm_device_create_l3_config_data(NMDevice *self, NMIPConfigSource source)
return nm_l3_config_data_new(nm_device_get_multi_index(self), ifindex, source);
}
-static void
-applied_config_clear(AppliedConfig *config)
-{
- g_clear_object(&config->current);
- g_clear_object(&config->orig);
-}
-
-static void
-applied_config_init(AppliedConfig *config, gpointer ip_config)
+const NML3ConfigData *
+nm_device_create_l3_config_data_from_connection(NMDevice *self, NMConnection *connection)
{
- 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));
+ NML3ConfigData *l3cd;
+ int ifindex;
- 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)
-{
- gs_unref_object NMIPConfig *c = nm_device_ip_config_new(self, addr_family);
-
- applied_config_init(config, c);
-}
-
-static NMIPConfig *
-applied_config_get_current(AppliedConfig *config)
-{
- return config->current ?: config->orig;
-}
-
-static void
-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->current)
- nm_ip_config_add_address(config->current, address);
-}
-
-static void
-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->current)
- nm_ip_config_add_nameserver(config->current, ns);
-}
-
-static void
-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->current)
- nm_ip_config_add_search(config->current, new);
-}
-
-static void
-applied_config_reset_searches(AppliedConfig *config)
-{
- if (config->orig)
- nm_ip_config_reset_searches(config->orig);
- else
- nm_assert(!config->current);
+ nm_assert(NM_IS_DEVICE(self));
+ nm_assert(!connection || NM_IS_CONNECTION(connection));
- if (config->current)
- nm_ip_config_reset_searches(config->current);
-}
+ if (!connection)
+ return NULL;
-static void
-applied_config_reset_nameservers(AppliedConfig *config)
-{
- if (config->orig)
- nm_ip_config_reset_nameservers(config->orig);
- else
- nm_assert(!config->current);
+ ifindex = nm_device_get_ip_ifindex(self);
+ if (ifindex <= 0)
+ g_return_val_if_reached(NULL);
- if (config->current)
- nm_ip_config_reset_nameservers(config->current);
+ l3cd =
+ nm_l3_config_data_new_from_connection(nm_device_get_multi_index(self), ifindex, connection);
+ nm_l3_config_data_set_mdns(l3cd, _prop_get_connection_mdns(self));
+ nm_l3_config_data_set_llmnr(l3cd, _prop_get_connection_llmnr(self));
+ return l3cd;
}
/*****************************************************************************/
@@ -2562,6 +2642,7 @@ nm_device_sys_iface_state_set(NMDevice *self, NMDeviceSysIfaceState sys_iface_st
nm_device_sys_iface_state_to_string(priv->sys_iface_state),
nm_device_sys_iface_state_to_string(sys_iface_state));
priv->sys_iface_state_ = sys_iface_state;
+ _dev_l3_cfg_commit_type_reset(self);
}
/* this function only sets a flag, no immediate actions are initiated.
@@ -2674,33 +2755,6 @@ nm_device_assume_state_reset(NMDevice *self)
/*****************************************************************************/
-static void
-init_ip_config_dns_priority(NMDevice *self, NMIPConfig *config)
-{
- 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");
-
- 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;
- }
-
- nm_ip_config_set_dns_priority(config, priority);
-}
-
-/*****************************************************************************/
-
static char *
nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property)
{
@@ -2837,93 +2891,878 @@ _add_capabilities(NMDevice *self, NMDeviceCapabilities capabilities)
/*****************************************************************************/
+static void
+_dev_ip_state_req_timeout_cancel(NMDevice *self, int addr_family)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+
+ if (addr_family == AF_UNSPEC) {
+ _dev_ip_state_req_timeout_cancel(self, AF_INET);
+ _dev_ip_state_req_timeout_cancel(self, AF_INET6);
+ return;
+ }
+
+ if (nm_clear_g_source_inst(&priv->ip_data_x[NM_IS_IPv4(addr_family)].req_timeout_source))
+ _LOGD_ip(addr_family, "required-timeout: cancelled");
+}
+
static gboolean
-ip_required_timeout_x(NMDevice *self, int addr_family)
+_dev_ip_state_req_timeout_cb_x(NMDevice *self, int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- _LOGD(LOGD_CORE,
- "required-timeout expired for IPv%c",
- nm_utils_addr_family_to_char(addr_family));
- nm_clear_g_source_inst(&priv->ip_req_timeout_source_x[NM_IS_IPv4(addr_family)]);
- check_ip_state(self, FALSE, TRUE);
+ _LOGD_ip(addr_family, "required-timeout: expired");
+ nm_clear_g_source_inst(&priv->ip_data_x[NM_IS_IPv4(addr_family)].req_timeout_source);
+ _dev_ip_state_check(self, addr_family);
return G_SOURCE_CONTINUE;
}
static gboolean
-ip_required_timeout_4(gpointer data)
+_dev_ip_state_req_timeout_cb_4(gpointer user_data)
{
- return ip_required_timeout_x(data, AF_INET);
+ return _dev_ip_state_req_timeout_cb_x(user_data, AF_INET);
}
static gboolean
-ip_required_timeout_6(gpointer data)
+_dev_ip_state_req_timeout_cb_6(gpointer user_data)
{
- return ip_required_timeout_x(data, AF_INET6);
+ return _dev_ip_state_req_timeout_cb_x(user_data, AF_INET6);
}
static void
-_set_ip_state(NMDevice *self, int addr_family, NMDeviceIPState new_state)
+_dev_ip_state_req_timeout_schedule(NMDevice *self, int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
- guint timeout_msec;
- int v4;
+ guint32 timeout_msec;
+ char buf[32];
- nm_assert_addr_family(addr_family);
+ nm_assert(!priv->ip_data_x[IS_IPv4].req_timeout_source);
- if (new_state == NM_DEVICE_IP_STATE_CONF && !priv->ip_config_started) {
- /* Start the required-timeout timers when one of IPv4/IPv6
- * enters the CONF state. This means that if there is no carrier and
- * ipv4.method=auto,ipv6.method=manual, the timeout for IPv4 will
- * start as soon as connection is activated, even if DHCPv4 did not
- * start yet.
- */
- priv->ip_config_started = TRUE;
+ timeout_msec = _prop_get_ipvx_required_timeout(self, addr_family);
+ if (timeout_msec == 0) {
+ _LOGD_ip(addr_family, "required-timeout: disabled");
+ return;
+ }
- for (v4 = 1; v4 >= 0; v4--) {
- char buf[32];
+ _LOGD_ip(addr_family,
+ "required-timeout: started (%s msec)",
+ timeout_msec == G_MAXINT32 ? "∞" : nm_sprintf_buf(buf, "%u", timeout_msec));
- nm_assert(!priv->ip_req_timeout_source_x[v4]);
- if ((timeout_msec = _prop_get_ipvx_required_timeout(self, v4 ? AF_INET : AF_INET6))) {
- _LOGD(LOGD_CORE,
- "required-timeout in %s msec for IPv%c",
- timeout_msec == G_MAXINT32 ? "∞" : nm_sprintf_buf(buf, "%u", timeout_msec),
- v4 ? '4' : '6');
+ if (timeout_msec == G_MAXINT32) {
+ priv->ip_data_x[IS_IPv4].req_timeout_source = g_source_ref(nm_g_source_sentinel_get(0));
+ } else {
+ priv->ip_data_x[IS_IPv4].req_timeout_source = nm_g_timeout_add_source(
+ timeout_msec,
+ IS_IPv4 ? _dev_ip_state_req_timeout_cb_4 : _dev_ip_state_req_timeout_cb_6,
+ self);
+ }
+}
- if (timeout_msec == G_MAXINT32) {
- priv->ip_req_timeout_source_x[v4] = g_source_ref(nm_g_source_sentinel_get(0));
- } else {
- priv->ip_req_timeout_source_x[v4] =
- nm_g_timeout_add_source(timeout_msec,
- v4 ? ip_required_timeout_4 : ip_required_timeout_6,
- self);
+static gboolean
+_dev_ip_state_set_state(NMDevice * self,
+ int addr_family,
+ NMDeviceIPState ip_state,
+ const char * reason)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ int IS_IPv4;
+
+ if (addr_family == AF_UNSPEC) {
+ if (priv->ip_data.state == ip_state)
+ return FALSE;
+ _LOGD_ip(addr_family,
+ "set (combined) state %s (was %s, reason: %s)",
+ nm_device_ip_state_to_string(ip_state),
+ nm_device_ip_state_to_string(priv->ip_data.state),
+ reason);
+ priv->ip_data.state_ = ip_state;
+ return TRUE;
+ }
+
+ IS_IPv4 = NM_IS_IPv4(addr_family);
+
+ if (priv->ip_data_x[IS_IPv4].state_ == ip_state)
+ return FALSE;
+
+ _LOGD_ip(addr_family,
+ "set state %s (was %s, reason: %s)",
+ nm_device_ip_state_to_string(ip_state),
+ nm_device_ip_state_to_string(priv->ip_data_x[IS_IPv4].state),
+ reason);
+ priv->ip_data_x[IS_IPv4].state_ = ip_state;
+ return TRUE;
+}
+
+static void
+_device_ip_state_accumulate(NMDeviceIPState state,
+ gboolean * out_is_started,
+ gboolean * out_is_pending,
+ gboolean * out_is_failed)
+{
+ switch (state) {
+ case NM_DEVICE_IP_STATE_NONE:
+ return;
+ case NM_DEVICE_IP_STATE_PENDING:
+ *out_is_started = TRUE;
+ *out_is_pending = TRUE;
+ return;
+ case NM_DEVICE_IP_STATE_READY:
+ *out_is_started = TRUE;
+ return;
+ case NM_DEVICE_IP_STATE_FAILED:
+ *out_is_started = TRUE;
+ *out_is_failed = TRUE;
+ return;
+ }
+ nm_assert_not_reached();
+ return;
+}
+
+static void
+_dev_ip_state_check(NMDevice *self, int addr_family)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ gboolean s_is_started = FALSE;
+ gboolean s_is_failed = FALSE;
+ gboolean s_is_pending = FALSE;
+ gboolean v_bool;
+ NMDeviceIPState ip_state;
+ NMDeviceIPState ip_state_other;
+ NMDeviceIPState combinedip_state;
+ NMTernary may_fail = NM_TERNARY_DEFAULT;
+ NMTernary may_fail_other = NM_TERNARY_DEFAULT;
+
+ /* State handling in NMDevice:
+ *
+ * NMDevice manages a lot of state, that is for the various IP addressing methods, the state
+ * of the interface (controller/port), and a overall nm_device_get_state().
+ *
+ * The idea is to compartmentalize these states into smaller units, and combine them as appropriate.
+ *
+ * For example, NMDhcpClient already provides an API that hides most of the complexity. But it still
+ * needs to expose some state, like whether we are still trying to get a lease (PENDING), whether there
+ * was a critical failure (FAILED) or we have a lease (READY). This state is grouped in NMDevice
+ * under priv->ipdhcp_data_x. Most important is priv->ipdhcp_data_x[].state, which distills all of this
+ * into 4 values of type NMDeviceIPState. This state is cached, so whenever something changes (e.g.
+ * an event from NMDhcpClient), we determine the new state and compare it with what is cached. If
+ * the cached state is as the new state, we are done. Otherwise, the change gets escalated (which
+ * means to call _dev_ip_state_check_async()).
+ *
+ * Then, the various sub-states escalate their changes to this function (_dev_ip_state_check). This
+ * function first takes the sub-states related to one IP address family, and combines them into
+ * priv->ip_data_x[] (and in particular priv->ip_data_x[].state). The same repeats. The current
+ * state is cached in priv->ip_data_x[].state, and _dev_ip_state_check() determines the new state.
+ * If there is no change, it ends here. Otherwise, it gets escalated. In this case, the escaplation
+ * happens in _dev_ip_state_check() below by combining the combined per-address-family into
+ * priv->ip_data. In particular this step needs to take into account settings like "may-fail"
+ * and "required-timeout".
+ *
+ * The escalation and compartmentalization priv->ip_data repeats. This time it escalates
+ * to the overall device state (nm_device_state_changed() and nm_device_get_state()), which then
+ * triggers larger state changes (e.g. the activation might fail).
+ */
+
+ if (priv->l3cfg && nm_l3cfg_commit_on_idle_is_scheduled(priv->l3cfg)) {
+ /* we have an update on NML3Cfg scheduled. We first process that, before
+ * progressing the IP state. When that's done, we will be called again. */
+ _dev_ip_state_check_async(self, addr_family);
+ return;
+ }
+
+ if (priv->ip_data_x[IS_IPv4].state == NM_DEVICE_IP_STATE_NONE) {
+ ip_state = NM_DEVICE_IP_STATE_NONE;
+ goto got_ip_state;
+ }
+
+ if (nm_device_sys_iface_state_is_external(self)) {
+ ip_state = NM_DEVICE_IP_STATE_READY;
+ goto got_ip_state;
+ }
+
+ if (priv->ip_data_x[IS_IPv4].state == NM_DEVICE_IP_STATE_PENDING
+ && (priv->state < NM_DEVICE_STATE_IP_CONFIG || priv->state > NM_DEVICE_STATE_ACTIVATED)) {
+ /* we can only leave pending state, if we are between (including) IP_CONFIG and ACTIVATED states. */
+ ip_state = NM_DEVICE_IP_STATE_PENDING;
+ goto got_ip_state;
+ }
+
+ if (priv->ip_data_x[IS_IPv4].state == NM_DEVICE_IP_STATE_PENDING
+ && nm_active_connection_get_master(NM_ACTIVE_CONNECTION(priv->act_request.obj))
+ && !priv->is_enslaved) {
+ /* Don't progress into IP_CHECK or SECONDARIES if we're waiting for the
+ * master to enslave us. */
+ ip_state = NM_DEVICE_IP_STATE_PENDING;
+ goto got_ip_state;
+ }
+
+ if (priv->ip_data_x[IS_IPv4].wait_for_carrier || priv->ip_data_x[IS_IPv4].wait_for_ports) {
+ ip_state = NM_DEVICE_IP_STATE_PENDING;
+ goto got_ip_state;
+ }
+
+ if (priv->ip_data_x[IS_IPv4].is_disabled || priv->ip_data_x[IS_IPv4].is_ignore) {
+ ip_state = NM_DEVICE_IP_STATE_READY;
+ goto got_ip_state;
+ }
+
+ _device_ip_state_accumulate(priv->ipmanual_data.state,
+ &s_is_started,
+ &s_is_pending,
+ &s_is_failed);
+
+ _device_ip_state_accumulate(priv->ipll_data_x[IS_IPv4].state,
+ &s_is_started,
+ &s_is_pending,
+ &s_is_failed);
+
+ if (!IS_IPv4) {
+ _device_ip_state_accumulate(priv->ipac6_data.state,
+ &s_is_started,
+ &s_is_pending,
+ &s_is_failed);
+ }
+
+ v_bool = FALSE;
+ _device_ip_state_accumulate(priv->ipdhcp_data_x[IS_IPv4].state,
+ &s_is_started,
+ &s_is_pending,
+ &v_bool);
+ if (v_bool) {
+ if (!IS_IPv4 && priv->ipdhcp_data_6.v6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) {
+ /* DHCPv6 is best-effort and not required. */
+ } else
+ s_is_failed = TRUE;
+ }
+
+ _device_ip_state_accumulate(priv->ipdev_data_x[IS_IPv4].state,
+ &s_is_started,
+ &s_is_pending,
+ &s_is_failed);
+
+ _device_ip_state_accumulate(priv->ipdev_data_unspec.state,
+ &s_is_started,
+ &s_is_pending,
+ &s_is_failed);
+
+ if (s_is_failed)
+ ip_state = NM_DEVICE_IP_STATE_FAILED;
+ else if (s_is_pending)
+ ip_state = NM_DEVICE_IP_STATE_PENDING;
+ else if (s_is_started)
+ ip_state = NM_DEVICE_IP_STATE_READY;
+ else
+ ip_state = NM_DEVICE_IP_STATE_PENDING;
+
+got_ip_state:
+
+#define _state_str_a(state, name) \
+ ({ \
+ const NMDeviceIPState _state = (state); \
+ char * _s = ""; \
+ \
+ if (_state != NM_DEVICE_IP_STATE_NONE) { \
+ _s = nm_sprintf_bufa(NM_STRLEN(name) + 11, \
+ " " name "=%s", \
+ nm_device_ip_state_to_string(_state)); \
+ } \
+ _s; \
+ })
+
+ nm_assert(!priv->ip_data_4.is_ignore);
+
+ _LOGT_ip(addr_family,
+ "check-state: state %s => %s, is_failed=%d, is_pending=%d, is_started=%d, "
+ "may-fail-4=%d, may-fail-6=%d;"
+ "%s;%s%s%s%s%s;%s%s%s%s%s%s%s",
+ nm_device_ip_state_to_string(priv->ip_data_x[IS_IPv4].state),
+ nm_device_ip_state_to_string(ip_state),
+ s_is_failed,
+ s_is_pending,
+ s_is_started,
+ _prop_get_ipvx_may_fail_cached(self, AF_INET, IS_IPv4 ? &may_fail : &may_fail_other),
+ _prop_get_ipvx_may_fail_cached(self, AF_INET6, !IS_IPv4 ? &may_fail : &may_fail_other),
+ _state_str_a(priv->ipmanual_data.state, "manualip"),
+ priv->ip_data_4.is_disabled ? " disabled4" : "",
+ _state_str_a(priv->ipll_data_4.state, "ll4"),
+ _state_str_a(priv->ipdhcp_data_4.state, "dhcp4"),
+ _state_str_a(priv->ipdev_data_4.state, "dev4"),
+ _state_str_a(priv->ipshared_data_4.state, "shared4"),
+ priv->ip_data_6.is_disabled ? " disabled6" : "",
+ priv->ip_data_6.is_ignore ? " ignore6" : "",
+ _state_str_a(priv->ipll_data_6.state, "ll6"),
+ _state_str_a(priv->ipac6_data.state, "ac6"),
+ _state_str_a(priv->ipdhcp_data_6.state, "dhcp6"),
+ _state_str_a(priv->ipdev_data_6.state, "dev6"),
+ _state_str_a(priv->ipshared_data_6.state, "shared6"));
+
+ if (priv->ip_data_x[IS_IPv4].state == ip_state) {
+ /* no change. We can stop here. However, we also cancel the pending check, if any,
+ * because we just determined that there is no change. */
+ } else {
+ _dev_ip_state_set_state(self, addr_family, ip_state, "check-ip-state");
+ }
+
+ if (ip_state == NM_DEVICE_IP_STATE_NONE) {
+ /* Nothing to do. This almost cannot happen, and there is probably nothing
+ * to do about this case. */
+ goto out_done;
+ }
+
+ ip_state_other = priv->ip_data_x[!IS_IPv4].state;
+
+ if (ip_state == NM_DEVICE_IP_STATE_READY) {
+ /* we only set NM_ACTIVATION_STATE_FLAG_IP_READY_X() flag once we reach NM_DEVICE_IP_STATE_READY state.
+ * We don't ever clear it, even if we later enter NM_DEVICE_IP_STATE_FAILED state.
+ *
+ * This is not documented/guaranteed behavior, but seems to make sense for now. */
+ _active_connection_set_state_flags(self, NM_ACTIVATION_STATE_FLAG_IP_READY_X(IS_IPv4));
+ }
+
+ if (ip_state == NM_DEVICE_IP_STATE_READY && ip_state_other == NM_DEVICE_IP_STATE_READY)
+ combinedip_state = NM_DEVICE_IP_STATE_READY;
+ else if (ip_state == NM_DEVICE_IP_STATE_READY && ip_state_other == NM_DEVICE_IP_STATE_PENDING
+ && (priv->ip_data_x[IS_IPv4].is_disabled || priv->ip_data_x[IS_IPv4].is_ignore)) {
+ /* This IP method is disabled/ignore, but the other family is still pending.
+ * Regardless of ipvx.may-fail, this means that we always require the other IP family
+ * to get ready too. */
+ combinedip_state = NM_DEVICE_IP_STATE_PENDING;
+ } else if (ip_state == NM_DEVICE_IP_STATE_READY && ip_state_other == NM_DEVICE_IP_STATE_PENDING
+ && (priv->ip_data_x[!IS_IPv4].req_timeout_source
+ || !_prop_get_ipvx_may_fail_cached(self,
+ nm_utils_addr_family_other(addr_family),
+ &may_fail_other)))
+ combinedip_state = NM_DEVICE_IP_STATE_PENDING;
+ else if (ip_state == NM_DEVICE_IP_STATE_READY && ip_state_other == NM_DEVICE_IP_STATE_PENDING
+ && _prop_get_ipvx_may_fail_cached(self,
+ nm_utils_addr_family_other(addr_family),
+ &may_fail_other))
+ combinedip_state = NM_DEVICE_IP_STATE_READY;
+ else if (ip_state == NM_DEVICE_IP_STATE_FAILED
+ && !_prop_get_ipvx_may_fail_cached(self, addr_family, &may_fail))
+ combinedip_state = NM_DEVICE_IP_STATE_FAILED;
+ else {
+ if (priv->ip_data.state == NM_DEVICE_IP_STATE_NONE)
+ combinedip_state = NM_DEVICE_IP_STATE_PENDING;
+ else
+ combinedip_state = priv->ip_data.state;
+ }
+
+ _LOGT_ip(AF_UNSPEC,
+ "check-state: (combined) state %s => %s",
+ nm_device_ip_state_to_string(priv->ip_data.state),
+ nm_device_ip_state_to_string(combinedip_state));
+
+ if (!_dev_ip_state_set_state(self, AF_UNSPEC, combinedip_state, "check-ip-state"))
+ goto out_done;
+
+ switch (combinedip_state) {
+ case NM_DEVICE_IP_STATE_PENDING:
+ break;
+ case NM_DEVICE_IP_STATE_READY:
+ _dev_ip_state_req_timeout_cancel(self, AF_UNSPEC);
+ if (priv->state == NM_DEVICE_STATE_IP_CONFIG) {
+ nm_device_state_changed(self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE);
+ }
+ break;
+ case NM_DEVICE_IP_STATE_FAILED:
+ nm_device_state_changed(self,
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+ break;
+ case NM_DEVICE_IP_STATE_NONE:
+ default:
+ nm_assert_not_reached();
+ }
+
+out_done:
+ /* we just checked the state. We can cancel the pending async check. */
+ nm_clear_g_source_inst(&priv->ip_data_x[IS_IPv4].check_async_source);
+}
+
+static gboolean
+_dev_ip_state_check_async_cb(NMDevice *self, int addr_family)
+{
+ _dev_ip_state_check(self, addr_family);
+ return G_SOURCE_CONTINUE;
+}
+
+static gboolean
+_dev_ip_state_check_async_cb_4(gpointer user_data)
+{
+ return _dev_ip_state_check_async_cb(user_data, AF_INET);
+}
+
+static gboolean
+_dev_ip_state_check_async_cb_6(gpointer user_data)
+{
+ return _dev_ip_state_check_async_cb(user_data, AF_INET6);
+}
+
+static void
+_dev_ip_state_check_async(NMDevice *self, int addr_family)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ int IS_IPv4;
+
+ if (addr_family == AF_UNSPEC) {
+ _dev_ip_state_check_async(self, AF_INET);
+ _dev_ip_state_check_async(self, AF_INET6);
+ return;
+ }
+
+ IS_IPv4 = NM_IS_IPv4(addr_family);
+ if (!priv->ip_data_x[IS_IPv4].check_async_source) {
+ priv->ip_data_x[IS_IPv4].check_async_source = nm_g_idle_add_source(
+ (IS_IPv4 ? _dev_ip_state_check_async_cb_4 : _dev_ip_state_check_async_cb_6),
+ self);
+ }
+}
+
+static void
+_dev_ip_state_cleanup(NMDevice *self, int addr_family)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ int IS_IPv4;
+
+ if (addr_family == AF_UNSPEC) {
+ _dev_ip_state_set_state(self, addr_family, NM_DEVICE_IP_STATE_NONE, "ip-state-clear");
+ return;
+ }
+
+ IS_IPv4 = NM_IS_IPv4(addr_family);
+
+ nm_clear_g_source_inst(&priv->ip_data_x[IS_IPv4].check_async_source);
+ nm_clear_g_source_inst(&priv->ip_data_x[IS_IPv4].req_timeout_source);
+ _dev_ip_state_set_state(self, addr_family, NM_DEVICE_IP_STATE_NONE, "ip-state-clear");
+ priv->ip_data_x[IS_IPv4].wait_for_carrier = FALSE;
+ priv->ip_data_x[IS_IPv4].wait_for_ports = FALSE;
+ priv->ip_data_x[IS_IPv4].is_disabled = FALSE;
+ priv->ip_data_x[IS_IPv4].is_ignore = FALSE;
+ priv->ip_data_x[IS_IPv4].do_reapply = FALSE;
+}
+
+/*****************************************************************************/
+
+static gpointer
+_dev_l3_config_data_tag_get(NMDevicePrivate *priv, L3ConfigDataType l3cd_type)
+{
+ nm_assert(_NM_INT_NOT_NEGATIVE(l3cd_type) && l3cd_type < G_N_ELEMENTS(priv->l3cds));
+
+ return &priv->l3cds[l3cd_type];
+}
+
+static L3ConfigDataType
+_dev_l3_config_data_tag_to_type(NMDevice *self, gconstpointer tag)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ int d;
+
+ /* In C it is undefined behavior to compare unrelated pointers.
+ * Work around that by using nm_ptr_to_uintptr(), which casts the pointers
+ * to integers.
+ *
+ * I guess, theoretically it's still a problem to assume that if tag pointers
+ * somewhere inside priv->l3cds, that the uintptr_t case would also yield
+ * a value in that range. In practice, I couldn't imaging this not not work
+ * reliably. */
+
+ if (nm_ptr_to_uintptr(tag) < nm_ptr_to_uintptr(&priv->l3cds[0])
+ || nm_ptr_to_uintptr(tag) >= nm_ptr_to_uintptr(&priv->l3cds[G_N_ELEMENTS(priv->l3cds)]))
+ return _L3_CONFIG_DATA_TYPE_NONE;
+
+ d = ((typeof(priv->l3cds[0]) *) tag) - (&priv->l3cds[0]);
+
+ nm_assert(d >= 0);
+ nm_assert(d < _L3_CONFIG_DATA_TYPE_NUM);
+ nm_assert(tag == &priv->l3cds[d]);
+ nm_assert(tag == _dev_l3_config_data_tag_get(priv, d));
+ return d;
+}
+
+static L3ConfigDataType
+_dev_l3_config_data_acd_addr_info_to_type(NMDevice * self,
+ const NML3AcdAddrInfo *addr_info,
+ guint i_track_infos)
+{
+ nm_assert(NM_IS_DEVICE(self));
+ nm_assert(addr_info);
+ nm_assert(i_track_infos < addr_info->n_track_infos);
+
+ return _dev_l3_config_data_tag_to_type(self, addr_info->track_infos[i_track_infos].tag);
+}
+
+// FIXME(l3cfg): unused function??
+_nm_unused static const NML3AcdAddrTrackInfo *
+_dev_l3_config_data_acd_addr_info_has_by_type(NMDevice * self,
+ const NML3AcdAddrInfo *addr_info,
+ L3ConfigDataType l3cd_type)
+{
+ guint i;
+
+ nm_assert(NM_IS_DEVICE(self));
+ nm_assert(addr_info);
+ nm_assert(_NM_INT_NOT_NEGATIVE(l3cd_type) && l3cd_type < _L3_CONFIG_DATA_TYPE_NUM);
+
+ for (i = 0; i < addr_info->n_track_infos; i++) {
+ if (l3cd_type == _dev_l3_config_data_acd_addr_info_to_type(self, addr_info, i))
+ return &addr_info->track_infos[i];
+ }
+ return NULL;
+}
+
+static void
+_dev_l3_get_config_settings(NMDevice * self,
+ L3ConfigDataType type,
+ NML3ConfigMergeFlags *out_merge_flags,
+ NML3AcdDefendType * out_acd_defend_type,
+ guint32 * out_acd_timeout_msec)
+{
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ NML3ConfigMergeFlags flags;
+ NMConnection * connection;
+ NMSettingIPConfig * s_ip;
+
+ nm_assert(_NM_INT_NOT_NEGATIVE(type) && type < _L3_CONFIG_DATA_TYPE_NUM);
+
+ if (G_UNLIKELY(!priv->l3config_merge_flags_has)) {
+ int IS_IPv4;
+
+ connection = nm_device_get_applied_connection(self);
+
+ for (IS_IPv4 = 0; IS_IPv4 < 2; IS_IPv4++) {
+ flags = NM_L3_CONFIG_MERGE_FLAGS_NONE;
+
+ if (connection
+ && (s_ip = nm_connection_get_setting_ip_config(connection,
+ IS_IPv4 ? AF_INET : AF_INET6))) {
+ if (nm_setting_ip_config_get_ignore_auto_routes(s_ip))
+ flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES;
+
+ if (nm_setting_ip_config_get_ignore_auto_dns(s_ip))
+ flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_DNS;
+
+ if (nm_setting_ip_config_get_never_default(s_ip)
+ || nm_setting_ip_config_get_gateway(s_ip)) {
+ /* if the connection has an explicit gateway, we also ignore
+ * the default routes from other sources. */
+ flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES;
}
}
+
+ priv->l3config_merge_flags_x[IS_IPv4] = flags;
+ }
+ priv->l3config_merge_flags_has = TRUE;
+ }
+
+ switch (type) {
+ case L3_CONFIG_DATA_TYPE_DEVIP_UNSPEC:
+ case L3_CONFIG_DATA_TYPE_MANUALIP:
+ case L3_CONFIG_DATA_TYPE_LL_4:
+ case L3_CONFIG_DATA_TYPE_LL_6:
+ case L3_CONFIG_DATA_TYPE_PD_6:
+ case L3_CONFIG_DATA_TYPE_SHARED_4:
+ case L3_CONFIG_DATA_TYPE_DEVIP_4:
+ case L3_CONFIG_DATA_TYPE_AC_6:
+ case L3_CONFIG_DATA_TYPE_DHCP_6:
+ case L3_CONFIG_DATA_TYPE_DEVIP_6:
+ *out_acd_timeout_msec = _prop_get_ipv4_dad_timeout(self);
+ goto after_acd_timeout;
+
+ case L3_CONFIG_DATA_TYPE_DHCP_4:
+ /* For DHCP, we perform ACD separately, because we want to decline the
+ * lease in case of a conflict. */
+ *out_acd_timeout_msec = 0;
+ goto after_acd_timeout;
+
+ case _L3_CONFIG_DATA_TYPE_NUM:
+ case _L3_CONFIG_DATA_TYPE_NONE:
+ case _L3_CONFIG_DATA_TYPE_ACD_ONLY:
+ break;
+ }
+ *out_acd_timeout_msec = nm_assert_unreachable_val(0);
+
+after_acd_timeout:
+ switch (type) {
+ case L3_CONFIG_DATA_TYPE_LL_4:
+ *out_acd_defend_type = NM_L3_ACD_DEFEND_TYPE_ONCE;
+ goto after_acd_defend_type;
+
+ case L3_CONFIG_DATA_TYPE_DEVIP_UNSPEC:
+ case L3_CONFIG_DATA_TYPE_MANUALIP:
+ case L3_CONFIG_DATA_TYPE_LL_6:
+ case L3_CONFIG_DATA_TYPE_PD_6:
+ case L3_CONFIG_DATA_TYPE_SHARED_4:
+ case L3_CONFIG_DATA_TYPE_DHCP_4:
+ case L3_CONFIG_DATA_TYPE_DEVIP_4:
+ case L3_CONFIG_DATA_TYPE_AC_6:
+ case L3_CONFIG_DATA_TYPE_DHCP_6:
+ case L3_CONFIG_DATA_TYPE_DEVIP_6:
+ *out_acd_defend_type = NM_L3_ACD_DEFEND_TYPE_ALWAYS;
+ goto after_acd_defend_type;
+
+ case _L3_CONFIG_DATA_TYPE_NUM:
+ case _L3_CONFIG_DATA_TYPE_NONE:
+ case _L3_CONFIG_DATA_TYPE_ACD_ONLY:
+ break;
+ }
+ *out_acd_defend_type = nm_assert_unreachable_val(NM_L3_ACD_DEFEND_TYPE_ALWAYS);
+
+after_acd_defend_type:
+ switch (type) {
+ case L3_CONFIG_DATA_TYPE_DEVIP_UNSPEC:
+ case L3_CONFIG_DATA_TYPE_MANUALIP:
+ case L3_CONFIG_DATA_TYPE_LL_4:
+ case L3_CONFIG_DATA_TYPE_LL_6:
+ case L3_CONFIG_DATA_TYPE_PD_6:
+ case L3_CONFIG_DATA_TYPE_SHARED_4:
+ *out_merge_flags = NM_L3_CONFIG_MERGE_FLAGS_NONE;
+ goto after_merge_flags;
+
+ case L3_CONFIG_DATA_TYPE_DHCP_4:
+ case L3_CONFIG_DATA_TYPE_DEVIP_4:
+ *out_merge_flags = priv->l3config_merge_flags_4;
+ goto after_merge_flags;
+
+ case L3_CONFIG_DATA_TYPE_AC_6:
+ case L3_CONFIG_DATA_TYPE_DHCP_6:
+ case L3_CONFIG_DATA_TYPE_DEVIP_6:
+ *out_merge_flags = priv->l3config_merge_flags_6;
+ goto after_merge_flags;
+
+ case _L3_CONFIG_DATA_TYPE_NUM:
+ case _L3_CONFIG_DATA_TYPE_NONE:
+ case _L3_CONFIG_DATA_TYPE_ACD_ONLY:
+ break;
+ }
+ *out_merge_flags = nm_assert_unreachable_val(NM_L3_CONFIG_MERGE_FLAGS_NONE);
+
+after_merge_flags:
+ return;
+}
+
+static gboolean
+_dev_l3_register_l3cds_add_config(NMDevice *self, L3ConfigDataType l3cd_type)
+{
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ NML3ConfigMergeFlags merge_flags;
+ NML3AcdDefendType acd_defend_type;
+ guint32 acd_timeout_msec;
+
+ _dev_l3_get_config_settings(self, l3cd_type, &merge_flags, &acd_defend_type, &acd_timeout_msec);
+ return nm_l3cfg_add_config(priv->l3cfg,
+ _dev_l3_config_data_tag_get(priv, l3cd_type),
+ FALSE,
+ priv->l3cds[l3cd_type].d,
+ l3cd_type,
+ nm_device_get_route_table(self, AF_INET),
+ nm_device_get_route_table(self, AF_INET6),
+ nm_device_get_route_metric(self, AF_INET),
+ nm_device_get_route_metric(self, AF_INET6),
+ _dev_default_route_metric_penalty_get(self, AF_INET),
+ _dev_default_route_metric_penalty_get(self, AF_INET6),
+ _prop_get_ipvx_dns_priority(self, AF_INET),
+ _prop_get_ipvx_dns_priority(self, AF_INET6),
+ acd_defend_type,
+ acd_timeout_msec,
+ NM_L3CFG_CONFIG_FLAGS_NONE,
+ merge_flags);
+}
+
+static gboolean
+_dev_l3_register_l3cds_set_one(NMDevice * self,
+ L3ConfigDataType l3cd_type,
+ const NML3ConfigData *l3cd,
+ NMTernary commit_sync)
+{
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL;
+ gboolean changed = FALSE;
+
+ if (priv->l3cds[l3cd_type].d != l3cd) {
+ if (nm_l3_config_data_equal(priv->l3cds[l3cd_type].d, l3cd)) {
+ /* we would set to a different instance, but the same content!
+ * We keep the previous one and ignore the new @l3cd.
+ *
+ * Warning: this means, that after calling this function,
+ * priv->l3cds[l3cd_type].d still might point to a different
+ * (though semantically equal) l3cd instance. */
+ } else {
+ l3cd_old = g_steal_pointer(&priv->l3cds[l3cd_type].d);
+ if (l3cd)
+ priv->l3cds[l3cd_type].d = nm_l3_config_data_ref_and_seal(l3cd);
+ }
+ }
+
+ if (priv->l3cfg) {
+ if (priv->l3cds[l3cd_type].d) {
+ if (_dev_l3_register_l3cds_add_config(self, l3cd_type))
+ changed = TRUE;
+ }
+
+ if (l3cd_old) {
+ if (nm_l3cfg_remove_config(priv->l3cfg,
+ _dev_l3_config_data_tag_get(priv, l3cd_type),
+ l3cd_old))
+ changed = TRUE;
+ }
+ }
+
+ if (changed && commit_sync != NM_TERNARY_DEFAULT)
+ _dev_l3_cfg_commit(self, !!commit_sync);
+
+ return changed;
+}
+
+static gboolean
+_dev_l3_register_l3cds(NMDevice *self,
+ NML3Cfg * l3cfg,
+ gboolean do_add /* else remove */,
+ NMTernary do_commit)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ gboolean is_external;
+ gboolean changed;
+ int i;
+
+ if (!l3cfg)
+ return FALSE;
+
+ is_external = nm_device_sys_iface_state_is_external(self);
+
+ changed = FALSE;
+ for (i = 0; i < (int) G_N_ELEMENTS(priv->l3cds); i++) {
+ if (!priv->l3cds[i].d)
+ continue;
+ if (!do_add) {
+ if (nm_l3cfg_remove_config(l3cfg,
+ _dev_l3_config_data_tag_get(priv, i),
+ priv->l3cds[i].d))
+ changed = TRUE;
+ continue;
}
+ if (is_external)
+ continue;
+ if (_dev_l3_register_l3cds_add_config(self, i))
+ changed = TRUE;
}
- if (priv->ip_state_x[IS_IPv4] == new_state)
+ if (do_commit == NM_TERNARY_DEFAULT)
+ do_commit = changed;
+ if (do_commit)
+ _dev_l3_cfg_commit(self, TRUE);
+
+ return changed;
+}
+
+/*****************************************************************************/
+
+void
+nm_device_l3cfg_commit(NMDevice *self, NML3CfgCommitType commit_type, gboolean do_sync)
+{
+ NMDevicePrivate *priv;
+
+ g_return_if_fail(NM_IS_DEVICE(self));
+
+ priv = NM_DEVICE_GET_PRIVATE(self);
+
+ if (!priv->l3cfg)
return;
- _LOGT(LOGD_DEVICE,
- "ip%c-state: set to %d (%s)",
- nm_utils_addr_family_to_char(addr_family),
- (int) new_state,
- nm_device_ip_state_to_string(new_state));
+ if (!do_sync) {
+ nm_l3cfg_commit_on_idle_schedule(priv->l3cfg, commit_type);
+ return;
+ }
- priv->ip_state_x_[IS_IPv4] = new_state;
+ nm_l3cfg_commit(priv->l3cfg, commit_type);
+}
- 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,
- NM_IS_IPv4(addr_family)
- ? NM_ACTIVATION_STATE_FLAG_IP4_READY
- : NM_ACTIVATION_STATE_FLAG_IP6_READY);
+static void
+_dev_l3_cfg_commit(NMDevice *self, gboolean do_sync)
+{
+ nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO, do_sync);
+}
+
+static void
+_dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+
+ nm_assert(l3cfg == priv->l3cfg);
+
+ switch (notify_data->notify_type) {
+ case NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED:
+ if (notify_data->l3cd_changed.commited) {
+ g_signal_emit(self,
+ signals[L3CD_CHANGED],
+ 0,
+ notify_data->l3cd_changed.l3cd_old,
+ notify_data->l3cd_changed.l3cd_new);
+ }
+ return;
+ case NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT:
+ {
+ const NML3AcdAddrInfo *addr_info = &notify_data->acd_event.info;
+
+ if (addr_info->state > NM_L3_ACD_ADDR_STATE_PROBING)
+ _dev_ipmanual_check_ready(self);
+ return;
+ }
+ case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT:
+ _dev_ipmanual_check_ready(self);
+ return;
+ case NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT:
+ nm_assert(NM_IS_L3_IPV4LL(notify_data->ipv4ll_event.ipv4ll));
+ if (priv->ipll_data_4.v4.ipv4ll == notify_data->ipv4ll_event.ipv4ll)
+ _dev_ipll4_notify_event(self);
+ return;
+ case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE:
+ return;
+ case NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED:
+ /* we commit again. This way we try to configure the routes.*/
+ _dev_l3_cfg_commit(self, FALSE);
+ return;
+ case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE:
+ if (NM_FLAGS_ANY(notify_data->platform_change_on_idle.obj_type_flags,
+ nmp_object_type_to_flags(NMP_OBJECT_TYPE_LINK)))
+ _dev_unamanged_check_external_down(self, TRUE);
+ _dev_ipmanual_check_ready(self);
+ return;
+
+ case _NM_L3_CONFIG_NOTIFY_TYPE_NUM:
+ break;
}
+ nm_assert_not_reached();
+}
+
+static void
+_dev_l3_cfg_commit_type_reset(NMDevice *self)
+{
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ NML3CfgCommitType commit_type;
+
+ if (!priv->l3cfg)
+ return;
+
+ switch (priv->sys_iface_state) {
+ case NM_DEVICE_SYS_IFACE_STATE_EXTERNAL:
+ case NM_DEVICE_SYS_IFACE_STATE_REMOVED:
+ commit_type = NM_L3_CFG_COMMIT_TYPE_NONE;
+ goto do_set;
+ case NM_DEVICE_SYS_IFACE_STATE_ASSUME:
+ commit_type = NM_L3_CFG_COMMIT_TYPE_ASSUME;
+ goto do_set;
+ case NM_DEVICE_SYS_IFACE_STATE_MANAGED:
+ commit_type = NM_L3_CFG_COMMIT_TYPE_UPDATE;
+ goto do_set;
+ }
+ nm_assert_not_reached();
+ return;
+
+do_set:
+ priv->l3cfg_commit_type =
+ nm_l3cfg_commit_type_register(priv->l3cfg, commit_type, priv->l3cfg_commit_type, "device");
}
/*****************************************************************************/
@@ -2947,11 +3786,18 @@ nm_device_get_iface(NMDevice *self)
static gboolean
_set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- int * p_ifindex;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ gs_unref_object NML3Cfg *l3cfg_old = NULL;
+ NML3CfgCommitTypeHandle *l3cfg_commit_type_old = NULL;
+ gboolean l3_changed;
+ int ip_ifindex_new;
+ int * p_ifindex;
+ gboolean l3cfg_was_reset = FALSE;
- if (ifindex < 0)
+ if (ifindex < 0) {
+ nm_assert_not_reached();
ifindex = 0;
+ }
p_ifindex = is_ip_ifindex ? &priv->ip_ifindex_ : &priv->ifindex_;
@@ -2960,13 +3806,74 @@ _set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex)
*p_ifindex = ifindex;
- _LOGD(LOGD_DEVICE, "ifindex: set %sifindex %d", is_ip_ifindex ? "ip-" : "", ifindex);
+ ip_ifindex_new = nm_device_get_ip_ifindex(self);
- if (!is_ip_ifindex)
- _notify(self, PROP_IFINDEX);
+ if (priv->l3cfg) {
+ if (ip_ifindex_new <= 0 || ip_ifindex_new != nm_l3cfg_get_ifindex(priv->l3cfg)) {
+ g_signal_handlers_disconnect_by_func(priv->l3cfg,
+ G_CALLBACK(_dev_l3_cfg_notify_cb),
+ self);
+ l3cfg_old = g_steal_pointer(&priv->l3cfg_);
+ l3cfg_commit_type_old = g_steal_pointer(&priv->l3cfg_commit_type);
+ l3cfg_was_reset = TRUE;
+ }
+ }
+ if (!priv->l3cfg && ip_ifindex_new > 0) {
+ priv->l3cfg_ = nm_netns_access_l3cfg(priv->netns, ip_ifindex_new);
+
+ g_signal_connect(priv->l3cfg,
+ NM_L3CFG_SIGNAL_NOTIFY,
+ G_CALLBACK(_dev_l3_cfg_notify_cb),
+ self);
+
+ _dev_l3_cfg_commit_type_reset(self);
+ l3cfg_was_reset = TRUE;
+ }
+
+ _LOGD(LOGD_DEVICE,
+ "ifindex: set %sifindex %d%s%s%s%s%s%s",
+ is_ip_ifindex ? "ip-" : "",
+ ifindex,
+ NM_PRINT_FMT_QUOTED(l3cfg_old && l3cfg_old != priv->l3cfg,
+ " (old-l3cfg: ",
+ nm_hash_obfuscated_ptr_str_a(l3cfg_old),
+ ")",
+ ""),
+ NM_PRINT_FMT_QUOTED(priv->l3cfg && l3cfg_old != priv->l3cfg,
+ " (l3cfg: ",
+ nm_hash_obfuscated_ptr_str_a(priv->l3cfg),
+ ")",
+ ""));
if (priv->manager)
nm_manager_emit_device_ifindex_changed(priv->manager, self);
+
+ if (!is_ip_ifindex)
+ _notify(self, PROP_IFINDEX);
+
+ if (l3cfg_was_reset) {
+ nm_ip_config_take_and_unexport_on_idle(g_steal_pointer(&priv->l3ipdata_4.ip_config));
+ nm_ip_config_take_and_unexport_on_idle(g_steal_pointer(&priv->l3ipdata_6.ip_config));
+ if (priv->l3cfg) {
+ priv->l3ipdata_4.ip_config = nm_ip_config_new(AF_INET, priv->l3cfg, FALSE);
+ priv->l3ipdata_6.ip_config = nm_ip_config_new(AF_INET6, priv->l3cfg, FALSE);
+ }
+ _notify(self, PROP_IP4_CONFIG);
+ _notify(self, PROP_IP6_CONFIG);
+ }
+
+ l3_changed = FALSE;
+ if (_dev_l3_register_l3cds(self, priv->l3cfg, TRUE, FALSE))
+ l3_changed = TRUE;
+ if (_dev_l3_register_l3cds(self, l3cfg_old, FALSE, FALSE))
+ l3_changed = TRUE;
+
+ if (l3_changed)
+ _dev_l3_cfg_commit(self, TRUE);
+
+ if (l3cfg_commit_type_old)
+ nm_l3cfg_commit_type_unregister(l3cfg_old, l3cfg_commit_type_old);
+
return TRUE;
}
@@ -3703,8 +4610,10 @@ nm_device_get_route_metric_default(NMDeviceType device_type)
return 11000;
}
-static gboolean
-default_route_metric_penalty_detect(NMDevice *self, int addr_family)
+/* FIXME(l3cfg): we currently never call this function. We need to react
+ * to changes and re-commit the IP configuration with updated penalty. */
+_nm_unused static gboolean
+_dev_default_route_metric_penalty_detect(NMDevice *self, int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
@@ -3719,7 +4628,7 @@ default_route_metric_penalty_detect(NMDevice *self, int addr_family)
}
static guint32
-default_route_metric_penalty_get(NMDevice *self, int addr_family)
+_dev_default_route_metric_penalty_get(NMDevice *self, int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
@@ -3787,28 +4696,23 @@ nm_device_get_route_table(NMDevice *self, int addr_family)
return route_table ?: (guint32) RT_TABLE_MAIN;
}
-static NMIPRouteTableSyncMode
+/* FIXME(l3cfg): need to properly handle the route-table sync mode and
+ * use it during commit. */
+_nm_unused static NMIPRouteTableSyncMode
_get_route_table_sync_mode_stateful(NMDevice *self, int addr_family)
{
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- NMDedupMultiIter ipconf_iter;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
gboolean all_sync_now;
gboolean all_sync_eff;
all_sync_now = _prop_get_ipvx_route_table(self, addr_family) != 0u;
if (!all_sync_now) {
- const NMPlatformIPRoute *route;
+ const NML3ConfigData *l3cd = priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d;
/* If there's a local route switch to all-sync in order
* to properly manage the local table */
- nm_ip_config_iter_ip_route_for_each (&ipconf_iter, priv->con_ip_config_x[IS_IPv4], &route) {
- if (nm_platform_route_type_uncoerce(route->type_coerced) == RTN_LOCAL) {
- all_sync_now = TRUE;
- break;
- }
- }
+ all_sync_now = l3cd && nm_l3_config_data_has_routes_with_type_local(l3cd, addr_family);
}
if (all_sync_now)
@@ -3840,18 +4744,20 @@ nm_device_get_best_default_route(NMDevice *self, int addr_family)
{
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);
- }
+ if (!priv->l3cfg)
+ return NULL;
+
+ /* FIXME(l3cfg): this function returns the best default route that we
+ * *want* to configure. What is the meaning of that? Possibly the caller
+ * cares whether there *is* a default route configured, for which they
+ * should ask platform.
+ *
+ * Check callers why they call this. Quite possibly this whole notion of
+ * "has a default route" is wrong to being with, regardless whether we
+ * look at the desired or actual configuration. That is, because "has a default route"
+ * does not do justice to the complexity of routing (with policy routing,
+ * etc.). */
+ return nm_l3cfg_get_best_default_route(priv->l3cfg, addr_family, TRUE);
}
const char *
@@ -4406,14 +5312,8 @@ concheck_update_state(NMDevice * self,
_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");
- }
+ if (priv->state == NM_DEVICE_STATE_ACTIVATED && !nm_device_sys_iface_state_is_external(self))
+ _dev_l3_register_l3cds(self, priv->l3cfg, TRUE, NM_TERNARY_DEFAULT);
}
static const char *
@@ -4748,16 +5648,14 @@ find_slave_info(NMDevice *self, NMDevice *slave)
static gboolean
nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection)
{
- NMDevicePrivate *priv;
- SlaveInfo * info;
- gboolean success = FALSE;
- gboolean configure;
+ 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);
- priv = NM_DEVICE_GET_PRIVATE(self);
info = find_slave_info(self, slave);
if (!info)
return FALSE;
@@ -4780,22 +5678,17 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co
*/
nm_device_update_hw_address(self);
+ /* Since slave devices don't have their own IP configuration,
+ * set the MTU here.
+ */
+ _commit_mtu(slave);
+
/* 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_ip_start(self, AF_INET);
-
- if (priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT)
- nm_device_activate_stage3_ip_start(self, AF_INET6);
- }
-
- /* 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);
+ if (success)
+ nm_device_activate_schedule_stage3_ip_config(self, FALSE);
return success;
}
@@ -4882,6 +5775,8 @@ nm_device_master_release_one_slave(NMDevice * self,
NM_DEVICE_STATE_REASON_REMOVED);
}
+/*****************************************************************************/
+
/**
* can_unmanaged_external_down:
* @self: the device
@@ -4896,7 +5791,7 @@ can_unmanaged_external_down(NMDevice *self)
}
static NMUnmanFlagOp
-is_unmanaged_external_down(NMDevice *self, gboolean consider_can)
+_dev_unmanaged_is_external_down(NMDevice *self, gboolean consider_can)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
@@ -4913,7 +5808,7 @@ is_unmanaged_external_down(NMDevice *self, gboolean consider_can)
}
static void
-set_unmanaged_external_down(NMDevice *self, gboolean only_if_unmanaged)
+_dev_unamanged_check_external_down(NMDevice *self, gboolean only_if_unmanaged)
{
NMUnmanFlagOp ext_flags;
@@ -4925,7 +5820,7 @@ set_unmanaged_external_down(NMDevice *self, gboolean only_if_unmanaged)
return;
}
- ext_flags = is_unmanaged_external_down(self, FALSE);
+ ext_flags = _dev_unmanaged_is_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.
@@ -4953,26 +5848,15 @@ nm_device_update_dynamic_ip_setup(NMDevice *self)
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) {
+ if (priv->ipdhcp_data_4.state != NM_DEVICE_IP_STATE_NONE)
+ _dev_ipdhcpx_restart(self, AF_INET, FALSE);
+ if (priv->ipdhcp_data_6.state != NM_DEVICE_IP_STATE_NONE)
+ _dev_ipdhcpx_restart(self, AF_INET6, FALSE);
+
+ if (priv->ipac6_data.ndisc) {
/* FIXME: todo */
}
- if (priv->dnsmasq_manager) {
+ if (priv->ipshared_data_4.v4.dnsmasq_manager) {
/* FIXME: todo */
}
}
@@ -5007,10 +5891,7 @@ carrier_changed(NMDevice *self, gboolean carrier)
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_ip_start(self, AF_INET);
- if (nm_device_activate_ip6_state_in_wait(self))
- nm_device_activate_stage3_ip_start(self, AF_INET6);
+ nm_device_activate_schedule_stage3_ip_config(self, FALSE);
return;
}
/* fall-through and change state of device */
@@ -5108,10 +5989,6 @@ nm_device_set_carrier(NMDevice *self, gboolean carrier)
nm_device_remove_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE);
_carrier_wait_check_queued_act_request(self);
}
-
- /* Send ARP announcements if did not yet and have carrier. */
- if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !priv->acd.announcing)
- nm_device_arp_announce(self);
} else {
if (priv->carrier_wait_id)
nm_device_add_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE);
@@ -5243,85 +6120,6 @@ device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice
}
static void
-ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- gs_unref_array GArray *addresses = NULL;
- gs_unref_array GArray *dns_servers = NULL;
- gs_unref_array GArray * dns_domains = NULL;
- guint len;
- guint i;
- const NMDedupMultiHeadEntry *head_entry;
- NMDedupMultiIter ipconf_iter;
-
- if (nm_ndisc_get_node_type(ndisc) != NM_NDISC_NODE_TYPE_ROUTER)
- return;
-
- 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;
- guint32 preferred;
-
- 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;
-
- lifetime = nmp_utils_lifetime_get(addr->timestamp,
- addr->lifetime,
- addr->preferred,
- NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000,
- &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->expiry_msec =
- _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, lifetime);
- ndisc_addr->expiry_preferred_msec =
- _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, 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->expiry_msec =
- _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, 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->expiry_msec =
- _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME);
- }
-
- nm_ndisc_set_config(ndisc, addresses, dns_servers, dns_domains);
-}
-
-static void
device_update_interface_flags(NMDevice *self, const NMPlatformLink *plink)
{
NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
@@ -5352,8 +6150,9 @@ device_update_interface_flags(NMDevice *self, const NMPlatformLink *plink)
}
static gboolean
-device_link_changed(NMDevice *self)
+device_link_changed(gpointer user_data)
{
+ NMDevice * self = user_data;
NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self);
NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
gboolean ip_ifname_changed = FALSE;
@@ -5438,8 +6237,8 @@ device_link_changed(NMDevice *self)
nm_device_emit_recheck_auto_activate(self);
}
- if (priv->ndisc && pllink->inet6_token.id) {
- if (nm_ndisc_set_iid(priv->ndisc, pllink->inet6_token))
+ if (priv->ipac6_data.ndisc && pllink->inet6_token.id) {
+ if (nm_ndisc_set_iid(priv->ipac6_data.ndisc, pllink->inet6_token))
_LOGD(LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
}
@@ -5486,23 +6285,14 @@ device_link_changed(NMDevice *self)
nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason);
}
- set_unmanaged_external_down(self, FALSE);
+ _dev_unamanged_check_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");
- }
+ _dev_l3_cfg_commit(self, TRUE);
}
if (update_unmanaged_specs)
@@ -5524,8 +6314,9 @@ device_link_changed(NMDevice *self)
}
static gboolean
-device_ip_link_changed(NMDevice *self)
+device_ip_link_changed(gpointer user_data)
{
+ NMDevice * self = user_data;
NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
const NMPlatformLink *pllink;
const char * ip_iface;
@@ -5588,13 +6379,12 @@ link_changed_cb(NMPlatform * platform,
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);
+ priv->device_link_changed_id = g_idle_add(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);
+ priv->device_ip_link_changed_id = g_idle_add(device_ip_link_changed, self);
_LOGD(LOGD_DEVICE, "queued link change for ip-ifindex %d", ifindex);
}
}
@@ -6045,8 +6835,6 @@ realize_start_setup(NMDevice * self,
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",
@@ -6093,9 +6881,6 @@ realize_start_setup(NMDevice * self,
if (priv->firmware_version)
_notify(self, PROP_FIRMWARE_VERSION);
- priv->ipv6ll_handle = (nm_platform_link_get_inet6_addr_gen_mode(platform, priv->ifindex)
- == NM_IN6_ADDR_GEN_MODE_NONE);
-
if (nm_platform_link_supports_sriov(platform, priv->ifindex))
capabilities |= NM_DEVICE_CAP_SRIOV;
}
@@ -6153,7 +6938,7 @@ realize_start_setup(NMDevice * self,
* or have IP addressing */
nm_device_set_unmanaged_flags(self,
NM_UNMANAGED_EXTERNAL_DOWN,
- is_unmanaged_external_down(self, TRUE));
+ _dev_unmanaged_is_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
@@ -6192,9 +6977,6 @@ nm_device_realize_finish(NMDevice *self, const NMPlatformLink *plink)
if (plink)
device_recheck_slave_status(self, plink);
- priv->update_ip_config_completed_v4 = FALSE;
- priv->update_ip_config_completed_v6 = FALSE;
-
priv->real = TRUE;
_notify(self, PROP_REAL);
@@ -6290,9 +7072,6 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error)
}
}
- 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);
@@ -6656,117 +7435,6 @@ nm_device_get_master(NMDevice *self)
return NULL;
}
-static gboolean
-get_ip_config_may_fail(NMDevice *self, int addr_family)
-{
- NMConnection * connection;
- NMSettingIPConfig *s_ip;
-
- connection = nm_device_get_applied_connection(self);
-
- s_ip = nm_connection_get_setting_ip_config(connection, addr_family);
-
- return !s_ip || nm_setting_ip_config_get_may_fail(s_ip);
-}
-
-/*
- * check_ip_state
- *
- * When @full_state_update is TRUE, transition the device from IP_CONFIG to the
- * next state according to the outcome of IPv4 and IPv6 configuration. @may_fail
- * indicates that we are called just after the initial configuration and thus
- * IPv4/IPv6 are allowed to fail if the ipvx.may-fail properties say so, because
- * the IP methods couldn't even be started.
- * If @full_state_update is FALSE, just check if the connection should be failed
- * 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;
- int IS_IPv4;
-
- 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;
- }
-
- for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
- if (priv->ip_state_x[IS_IPv4] == NM_DEVICE_IP_STATE_CONF
- && priv->ip_req_timeout_source_x[IS_IPv4]) {
- 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;
- }
-}
-
/**
* nm_device_slave_notify_enslave:
* @self: the slave device
@@ -6804,13 +7472,17 @@ nm_device_slave_notify_enslave(NMDevice *self, gboolean success)
}
}
- 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
+ if (!activating) {
nm_device_queue_recheck_assume(self);
+ return;
+ }
+
+ if (!success) {
+ nm_device_queue_state(self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN);
+ return;
+ }
+
+ nm_device_activate_schedule_stage3_ip_config(self, FALSE);
}
/**
@@ -6881,6 +7553,9 @@ nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config)
g_return_if_fail(NM_IS_DEVICE(self));
+ _dev_ipdhcpx_cleanup(self, AF_INET, TRUE, FALSE);
+ _dev_ipdhcpx_cleanup(self, AF_INET6, TRUE, FALSE);
+
priv = NM_DEVICE_GET_PRIVATE(self);
if (priv->master) {
/* this is called when something externally messes with the slave or during shut-down.
@@ -6892,15 +7567,7 @@ nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config)
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);
- }
+ _dev_l3_register_l3cds(self, priv->l3cfg, FALSE, TRUE);
}
static gboolean
@@ -7158,22 +7825,36 @@ nm_device_can_auto_connect(NMDevice *self, NMSettingsConnection *sett_conn, char
static gboolean
device_has_config(NMDevice *self)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ const NMDedupMultiHeadEntry *head_entry;
+ const NMPlatformLink * pllink;
+ NMPLookup lookup;
+
+ pllink = nm_l3cfg_get_pllink(priv->l3cfg, TRUE);
+ if (!pllink)
+ return FALSE;
- /* Check for IP configuration. */
- if (priv->ip_config_4 && nm_ip4_config_get_num_addresses(priv->ip_config_4))
+ if (pllink->master > 0) {
+ /* Master-slave relationship is also a configuration */
return TRUE;
- if (priv->ip_config_6 && nm_ip6_config_get_num_addresses(priv->ip_config_6))
+ }
+
+ head_entry = nm_platform_lookup(
+ nm_device_get_platform(self),
+ nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, pllink->ifindex));
+ if (head_entry)
return TRUE;
- /* The existence of a software device is good enough. */
- if (nm_device_is_software(self) && nm_device_is_real(self))
+ head_entry = nm_platform_lookup(
+ nm_device_get_platform(self),
+ nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, pllink->ifindex));
+ if (head_entry)
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)
+ if (nm_device_is_software(self) && nm_device_is_real(self)) {
+ /* The existence of a software device is good enough. */
return TRUE;
+ }
return FALSE;
}
@@ -7331,10 +8012,16 @@ nm_device_generate_connection(NMDevice *self,
}
} else {
/* Only regular and master devices get IP configuration; slaves do not */
- s_ip4 = nm_ip4_config_create_setting(priv->ip_config_4);
+ s_ip4 = nm_utils_platform_capture_ip_setting(nm_device_get_platform(self),
+ AF_INET,
+ nm_device_get_ip_ifindex(self),
+ FALSE);
nm_connection_add_setting(connection, s_ip4);
- s_ip6 = nm_ip6_config_create_setting(priv->ip_config_6, _get_maybe_ipv6_disabled(self));
+ s_ip6 = nm_utils_platform_capture_ip_setting(nm_device_get_platform(self),
+ AF_INET6,
+ nm_device_get_ip_ifindex(self),
+ _get_maybe_ipv6_disabled(self));
nm_connection_add_setting(connection, s_ip6);
nm_connection_add_setting(connection, nm_setting_proxy_new());
@@ -7800,20 +8487,6 @@ nm_device_emit_recheck_auto_activate(NMDevice *self)
g_signal_emit(self, signals[RECHECK_AUTO_ACTIVATE], 0);
}
-static void
-dnsmasq_state_changed_cb(NMDnsMasqManager *manager, guint32 status, gpointer 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;
- }
-}
-
void
nm_device_auth_request(NMDevice * self,
GDBusMethodInvocation * context,
@@ -7838,148 +8511,112 @@ nm_device_auth_request(NMDevice * self,
/*****************************************************************************/
static void
-activation_source_clear(NMDevice *self, int addr_family)
+activation_source_clear(NMDevice *self)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- if (priv->activation_source_id_x[IS_IPv4] != 0) {
+ if (nm_clear_g_source_inst(&priv->activation_idle_source)) {
_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;
+ "activation-stage: clear %s",
+ _activation_func_to_string(priv->activation_func));
+ priv->activation_func = NULL;
}
}
static gboolean
-activation_source_handle_cb(NMDevice *self, int addr_family)
+activation_source_handle_cb(gpointer user_data)
{
+ NMDevice * self = user_data;
NMDevicePrivate * priv;
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
- ActivationHandleFunc activation_source_func;
- guint activation_source_id;
+ ActivationHandleFunc activation_func;
g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE);
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];
+ g_return_val_if_fail(priv->activation_idle_source, G_SOURCE_REMOVE);
- g_return_val_if_fail(activation_source_id != 0, G_SOURCE_REMOVE);
- nm_assert(activation_source_func);
+ nm_assert(priv->activation_func);
- priv->activation_source_func_x[IS_IPv4] = NULL;
- priv->activation_source_id_x[IS_IPv4] = 0;
+ activation_func = priv->activation_func;
+ priv->activation_func = NULL;
- _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);
+ nm_clear_g_source_inst(&priv->activation_idle_source);
- activation_source_func(self);
+ _LOGD(LOGD_DEVICE, "activation-stage: invoke %s", _activation_func_to_string(activation_func));
- _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);
+ activation_func(self);
- return G_SOURCE_REMOVE;
-}
-
-static gboolean
-activation_source_handle_cb_4(gpointer user_data)
-{
- return activation_source_handle_cb(user_data, AF_INET);
-}
-
-static gboolean
-activation_source_handle_cb_6(gpointer user_data)
-{
- return activation_source_handle_cb(user_data, AF_INET6);
+ return G_SOURCE_CONTINUE;
}
static void
-activation_source_schedule(NMDevice *self, ActivationHandleFunc func, int addr_family)
+activation_source_schedule(NMDevice *self, ActivationHandleFunc func)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
- guint new_id = 0;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- if (priv->activation_source_id_x[IS_IPv4] != 0
- && priv->activation_source_func_x[IS_IPv4] == func) {
+ if (priv->activation_idle_source && priv->activation_func == 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]);
+ "activation-stage: already scheduled %s",
+ _activation_func_to_string(func));
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) {
+ if (priv->activation_idle_source) {
_LOGD(LOGD_DEVICE,
- "activation-stage: schedule %s,v%c which replaces %s,v%c (id %u -> %u)",
+ "activation-stage: schedule %s (which replaces %s)",
_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]);
+ _activation_func_to_string(priv->activation_func));
+ nm_clear_g_source_inst(&priv->activation_idle_source);
} 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);
+ _LOGD(LOGD_DEVICE, "activation-stage: schedule %s", _activation_func_to_string(func));
}
- priv->activation_source_func_x[IS_IPv4] = func;
- priv->activation_source_id_x[IS_IPv4] = new_id;
+ priv->activation_idle_source = nm_g_idle_add_source(activation_source_handle_cb, self);
+ priv->activation_func = func;
}
static void
-activation_source_invoke_sync(NMDevice *self, ActivationHandleFunc func, int addr_family)
+activation_source_invoke_sync(NMDevice *self, ActivationHandleFunc func)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- if (priv->activation_source_id_x[IS_IPv4] == 0) {
+ if (!priv->activation_idle_source) {
_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) {
+ "activation-stage: synchronously invoke %s",
+ _activation_func_to_string(func));
+ } else if (priv->activation_func == 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]);
+ "activation-stage: synchronously invoke %s (which was already scheduled)",
+ _activation_func_to_string(func));
} else {
_LOGD(LOGD_DEVICE,
- "activation-stage: synchronously invoke %s,v%c which replaces %s,v%c (id %u)",
+ "activation-stage: synchronously invoke %s (which replaces %s)",
_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]);
+ _activation_func_to_string(priv->activation_func));
}
- nm_clear_g_source(&priv->activation_source_id_x[IS_IPv4]);
- priv->activation_source_func_x[IS_IPv4] = NULL;
+ nm_clear_g_source_inst(&priv->activation_idle_source);
+ priv->activation_func = NULL;
func(self);
}
+static void
+activation_source_invoke_or_schedule(NMDevice *self, ActivationHandleFunc func, gboolean do_sync)
+{
+ nm_assert(NM_IS_DEVICE(self));
+ nm_assert(NM_DEVICE_GET_PRIVATE(self)->act_request.obj);
+ nm_assert(func);
+
+ if (do_sync) {
+ activation_source_invoke_sync(self, func);
+ return;
+ }
+ activation_source_schedule(self, func);
+}
+
/*****************************************************************************/
static void
@@ -8148,14 +8785,20 @@ activate_stage1_device_prepare(NMDevice *self)
NMActiveConnection *master;
NMDeviceClass * klass;
- priv->v4_route_table_initialized = FALSE;
- priv->v6_route_table_initialized = FALSE;
+ nm_assert((priv->ip_data_4.state == NM_DEVICE_IP_STATE_NONE)
+ == (priv->ip_data_6.state == NM_DEVICE_IP_STATE_NONE));
- _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_NONE);
- _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_NONE);
+ if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_NONE) {
+ _dev_ip_state_set_state(self, AF_INET, NM_DEVICE_IP_STATE_PENDING, "stage1");
+ _dev_ip_state_set_state(self, AF_INET6, NM_DEVICE_IP_STATE_PENDING, "stage1");
- /* Notify the new ActiveConnection along with the state change */
- nm_dbus_track_obj_path_set(&priv->act_request, priv->act_request.obj, TRUE);
+ /* Notify the new ActiveConnection along with the state change */
+ nm_dbus_track_obj_path_set(&priv->act_request, priv->act_request.obj, TRUE);
+
+ priv->v4_route_table_initialized = FALSE;
+ priv->v6_route_table_initialized = FALSE;
+ priv->l3config_merge_flags_has = FALSE;
+ }
nm_device_state_changed(self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
@@ -8216,6 +8859,7 @@ activate_stage1_device_prepare(NMDevice *self)
priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_PENDING;
return;
}
+
priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_COMPLETED;
}
@@ -8291,15 +8935,7 @@ activate_stage1_device_prepare(NMDevice *self)
void
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);
-
- 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_or_schedule(self, activate_stage1_device_prepare, do_sync);
}
static NMActStageReturn
@@ -8591,1084 +9227,732 @@ activate_stage2_device_config(NMDevice *self)
lldp_setup(self, NM_TERNARY_DEFAULT);
- _commit_mtu(self, NULL);
+ _commit_mtu(self);
- nm_device_activate_schedule_stage3_ip_config_start(self);
+ nm_device_activate_schedule_stage3_ip_config(self, TRUE);
}
void
nm_device_activate_schedule_stage2_device_config(NMDevice *self, gboolean do_sync)
{
- g_return_if_fail(NM_IS_DEVICE(self));
+ activation_source_invoke_or_schedule(self, activate_stage2_device_config, do_sync);
+}
- 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);
+static void
+_dev_ipllx_set_state(NMDevice *self, int addr_family, NMDeviceIPState state)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
+
+ if (priv->ipll_data_x[IS_IPv4].state != state) {
+ _LOGD_ipll(addr_family,
+ "set state %s (was %s)",
+ nm_device_ip_state_to_string(state),
+ nm_device_ip_state_to_string(priv->ipll_data_x[IS_IPv4].state));
+ priv->ipll_data_x[IS_IPv4].state = state;
+ }
}
-void
-nm_device_ip_method_failed(NMDevice *self, int addr_family, NMDeviceStateReason reason)
+static void
+_dev_ipllx_cleanup(NMDevice *self, int addr_family)
{
- g_return_if_fail(NM_IS_DEVICE(self));
- g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6));
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_FAIL);
+ if (IS_IPv4) {
+ if (nm_clear_pointer(&priv->ipll_data_4.v4.ipv4ll, nm_l3_ipv4ll_unref))
+ nm_clear_pointer(&priv->ipll_data_4.v4.ipv4ll_registation,
+ nm_l3_ipv4ll_register_remove);
+ else
+ nm_assert(!priv->ipll_data_4.v4.ipv4ll_registation);
- 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);
+ nm_clear_g_source_inst(&priv->ipll_data_4.v4.timeout_source);
+ } else {
+ nm_clear_pointer(&priv->ipll_data_6.v6.ipv6ll, nm_l3_ipv6ll_destroy);
+ priv->ipll_data_6.v6.llstate = NM_L3_IPV6LL_STATE_NONE;
+ priv->ipll_data_6.v6.lladdr = nm_ip_addr_zero.addr6;
+ nm_clear_g_source_inst(&priv->ipll_data_6.v6.retry_source);
+ }
+
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_LL_X(IS_IPv4), NULL, FALSE);
+
+ _dev_ipllx_set_state(self, addr_family, NM_DEVICE_IP_STATE_NONE);
}
/*****************************************************************************/
static void
-acd_data_destroy(gpointer ptr)
+_dev_ipll4_notify_event(NMDevice *self)
{
- AcdData *data = ptr;
- int i;
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ NML3IPv4LLState ipv4ll_state;
+ const NML3ConfigData *l3cd;
+ NMDeviceIPState state;
+
+ nm_assert(NM_IS_L3_IPV4LL(priv->ipll_data_4.v4.ipv4ll));
+ nm_assert(priv->ipll_data_4.state >= NM_DEVICE_IP_STATE_PENDING);
+
+ ipv4ll_state = nm_l3_ipv4ll_get_state(priv->ipll_data_4.v4.ipv4ll);
+
+ if (nm_l3_ipv4ll_state_is_good(ipv4ll_state)) {
+ l3cd = nm_l3_ipv4ll_get_l3cd(priv->ipll_data_4.v4.ipv4ll);
+ nm_assert(NM_IS_L3_CONFIG_DATA(l3cd));
+ nm_assert(!nm_l3_ipv4ll_is_timed_out(priv->ipll_data_4.v4.ipv4ll));
+ state = NM_DEVICE_IP_STATE_READY;
+ } else if (priv->ipll_data_4.v4.ipv4ll
+ && nm_l3_ipv4ll_is_timed_out(priv->ipll_data_4.v4.ipv4ll)) {
+ l3cd = NULL;
+ state = NM_DEVICE_IP_STATE_FAILED;
+ } else {
+ l3cd = NULL;
+ state = (priv->ipll_data_4.state == NM_DEVICE_IP_STATE_PENDING) ? NM_DEVICE_IP_STATE_PENDING
+ : NM_DEVICE_IP_STATE_FAILED;
+ }
+
+ _dev_ipllx_set_state(self, AF_INET, state);
+
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_LL_4, l3cd, FALSE);
- for (i = 0; data->configs && data->configs[i]; i++)
- g_object_unref(data->configs[i]);
- g_free(data->configs);
- g_slice_free(AcdData, data);
+ _dev_ip_state_check_async(self, AF_INET);
}
static void
-ipv4_manual_method_apply(NMDevice *self, NMIP4Config **configs, gboolean success)
+_dev_ipll4_start(NMDevice *self)
{
- 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));
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ guint32 timeout_msec;
- if (!success) {
- nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE);
+ if (priv->ipll_data_4.state >= NM_DEVICE_IP_STATE_PENDING)
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);
- }
+ _dev_ipllx_set_state(self, AF_INET, NM_DEVICE_IP_STATE_PENDING);
+
+ timeout_msec = _prop_get_ipv4_dad_timeout(self);
+ if (timeout_msec == 0)
+ timeout_msec = NM_ACD_TIMEOUT_RFC5227_MSEC;
+
+ priv->ipll_data_4.v4.ipv4ll = nm_l3cfg_access_ipv4ll(priv->l3cfg);
+ priv->ipll_data_4.v4.ipv4ll_registation =
+ nm_l3_ipv4ll_register_new(priv->ipll_data_4.v4.ipv4ll, timeout_msec);
}
-static void
-acd_manager_probe_terminated(NMAcdManager *acd_manager, gpointer user_data)
+/*****************************************************************************/
+
+static const char *
+_device_get_dhcp_anycast_address(NMDevice *self)
{
- AcdData * data = user_data;
- NMDevice * self;
- NMDevicePrivate * priv;
- NMDedupMultiIter ipconf_iter;
- const NMPlatformIP4Address *address;
- gboolean result, success = TRUE;
- int i;
+ NMDeviceClass *klass;
- g_assert(data);
- self = data->device;
- priv = NM_DEVICE_GET_PRIVATE(self);
+ nm_assert(NM_IS_DEVICE(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];
+ klass = NM_DEVICE_GET_CLASS(self);
- result = nm_acd_manager_check_address(acd_manager, address->address);
- success &= result;
+ if (klass->get_dhcp_anycast_address)
+ return klass->get_dhcp_anycast_address(self);
- _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");
- }
- }
+ return NULL;
+}
- 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);
+static IPDevStateData *
+_dev_ipdev_data(NMDevice *self, int addr_family)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+
+ switch (addr_family) {
+ case AF_INET:
+ return &priv->ipdev_data_4;
+ case AF_INET6:
+ return &priv->ipdev_data_6;
+ default:
+ nm_assert_not_reached();
+ /* fall-through */
+ case AF_UNSPEC:
+ return &priv->ipdev_data_unspec;
+ }
}
-/**
- * ipv4_dad_start:
- * @self: device instance
- * @configs: NULL-terminated array of IPv4 configurations
- * @cb: callback function
- *
- * Start IPv4 DAD on device @self, check addresses in @configs and call @cb
- * when the procedure ends. @cb will be called in any case, even if DAD can't
- * be started. @configs will be unreferenced after @cb has been called.
- */
static void
-ipv4_dad_start(NMDevice *self, NMIP4Config **configs, AcdCallback cb)
+_dev_ipdev_cleanup(NMDevice *self, int addr_family)
{
- 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;
+ IPDevStateData *p;
- 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;
- }
+ p = _dev_ipdev_data(self, addr_family);
+ if (p->state != NM_DEVICE_IP_STATE_NONE) {
+ _LOGD_ipdev(addr_family, "reset state");
+ p->state = NM_DEVICE_IP_STATE_NONE;
+ p->failed_reason = NM_DEVICE_STATE_REASON_NONE;
}
+}
- 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);
+NMDeviceIPState
+nm_device_devip_get_state(NMDevice *self, int addr_family)
+{
+ g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_IP_STATE_NONE);
- 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);
+ return _dev_ipdev_data(self, addr_family)->state;
+}
- for (i = 0; configs[i]; i++)
- g_object_unref(configs[i]);
- g_free(configs);
+void
+nm_device_devip_set_state_full(NMDevice * self,
+ int addr_family,
+ NMDeviceIPState ip_state,
+ const NML3ConfigData *l3cd,
+ NMDeviceStateReason failed_reason)
+{
+ NMDevicePrivate *priv;
+ IPDevStateData * p;
- return;
- }
+ g_return_if_fail(NM_IS_DEVICE(self));
- data = g_slice_new0(AcdData);
- data->configs = configs;
- data->callback = cb;
- data->device = self;
+ priv = NM_DEVICE_GET_PRIVATE(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);
+ nm_assert_addr_family_or_unspec(addr_family);
+ nm_assert(NM_IN_SET(ip_state,
+ NM_DEVICE_IP_STATE_PENDING,
+ NM_DEVICE_IP_STATE_READY,
+ NM_DEVICE_IP_STATE_FAILED));
+ nm_assert(!l3cd || NM_IS_L3_CONFIG_DATA(l3cd));
- 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);
- }
+ nm_assert((ip_state != NM_DEVICE_IP_STATE_FAILED)
+ == (failed_reason == NM_DEVICE_STATE_REASON_NONE));
+ nm_assert((ip_state != NM_DEVICE_IP_STATE_FAILED) || !l3cd);
- r = nm_acd_manager_start_probe(acd_manager, timeout);
- if (r < 0) {
- _LOGW(LOGD_DEVICE, "acd probe failed");
+ p = _dev_ipdev_data(self, addr_family);
- /* DAD could not be started, signal success */
- cb(self, configs, TRUE);
+ if (p->state == ip_state && p->failed_reason == failed_reason
+ && priv->l3cds[L3_CONFIG_DATA_TYPE_DEVIP(addr_family)].d == l3cd)
+ return;
- priv->acd.dad_list = g_slist_remove(priv->acd.dad_list, acd_manager);
- nm_acd_manager_free(acd_manager);
+ if (ip_state == NM_DEVICE_IP_STATE_FAILED) {
+ _LOGD_ipdev(addr_family,
+ "set state=failed (reason %s)",
+ nm_device_state_reason_to_string_a(failed_reason));
+ } else {
+ _LOGD_ipdev(addr_family,
+ "set state=%s%s",
+ nm_device_ip_state_to_string(ip_state),
+ l3cd ? " (has extra IP configuration)" : "");
}
+ p->state = ip_state;
+ p->failed_reason = failed_reason;
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DEVIP(addr_family), l3cd, FALSE);
+ _dev_ip_state_check_async(self, addr_family);
}
/*****************************************************************************/
-/* IPv4LL stuff */
static void
-ipv4ll_cleanup(NMDevice *self)
+_dev_ipmanual_set_state(NMDevice *self, NMDeviceIPState state)
{
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->ipmanual_data.state != state) {
+ _LOGD_ipmanual("set state %s", nm_device_ip_state_to_string(state));
+ priv->ipmanual_data.state = state;
}
-
- nm_clear_g_source(&priv->ipv4ll_timeout);
}
-static NMIP4Config *
-ipv4ll_get_ip4_config(NMDevice *self, guint32 lla)
+static void
+_dev_ipmanual_cleanup(NMDevice *self)
{
- NMIP4Config * config = NULL;
- NMPlatformIP4Address address;
- NMPlatformIP4Route route;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- config = nm_device_ip4_config_new(self);
- g_assert(config);
+ if (priv->ipmanual_data.state == NM_DEVICE_IP_STATE_NONE) {
+ nm_assert(!priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d);
+ return;
+ }
- 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);
+ _dev_ipmanual_set_state(self, NM_DEVICE_IP_STATE_NONE);
- /* 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);
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_MANUALIP, NULL, FALSE);
- return config;
+ _dev_ip_state_check_async(self, AF_INET);
+ _dev_ip_state_check_async(self, AF_INET6);
}
static void
-nm_device_handle_ipv4ll_event(sd_ipv4ll *ll, int event, void *data)
+_dev_ipmanual_check_ready(NMDevice *self)
{
- NMDevice * self = data;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- struct in_addr address;
- NMIP4Config * config;
- int r;
- if (priv->act_request.obj == NULL)
+ if (priv->ipmanual_data.state != NM_DEVICE_IP_STATE_PENDING) {
+ /* we only care about PENDING to get it READY. Currently not other
+ * conditions are implemented. That is, we cannot get to FAILED
+ * (maybe we should, if DAD fails) and we cannot get from anything
+ * once we are READY. */
return;
+ }
- nm_assert(nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET),
- NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL));
+ if (!nm_l3cfg_check_ready(priv->l3cfg,
+ priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d,
+ NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY
+ | NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY))
+ return;
- 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;
- }
+ _dev_ipmanual_set_state(self, NM_DEVICE_IP_STATE_READY);
+ _dev_ip_state_check_async(self, AF_UNSPEC);
+}
- 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;
- }
+static void
+_dev_ipmanual_start(NMDevice *self)
+{
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL;
- 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->ipmanual_data.state != NM_DEVICE_IP_STATE_NONE)
+ 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();
+ l3cd = nm_device_create_l3_config_data_from_connection(self,
+ nm_device_get_applied_connection(self));
- 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);
+ if (!l3cd) {
+ _dev_ipmanual_cleanup(self);
+ return;
}
-}
-
-static gboolean
-ipv4ll_timeout_cb(gpointer user_data)
-{
- 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);
+ /* Initially we set the state to pending, because we (maybe) have to perform ACD first. */
+ _dev_ipmanual_set_state(self, NM_DEVICE_IP_STATE_PENDING);
- if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF)
- nm_device_activate_schedule_ip_config_timeout(self, AF_INET);
- }
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_MANUALIP, l3cd, FALSE);
- return FALSE;
+ _dev_ip_state_check_async(self, AF_INET);
+ _dev_ip_state_check_async(self, AF_INET6);
}
-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);
+static void
+_dev_ipdhcpx_set_state(NMDevice *self, int addr_family, NMDeviceIPState state)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
- 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;
+ if (priv->ipdhcp_data_x[IS_IPv4].state != state) {
+ _LOGD_ipdhcp(addr_family,
+ "set state %s (was %s)",
+ nm_device_ip_state_to_string(state),
+ nm_device_ip_state_to_string(priv->ipdhcp_data_x[IS_IPv4].state));
+ priv->ipdhcp_data_x[IS_IPv4].state = state;
}
+}
- 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;
- }
+static void
+_dev_ipdhcpx_cleanup(NMDevice *self, int addr_family, gboolean full_cleanup, gboolean release)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
- 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;
- }
+ _dev_ipdhcpx_set_state(self, addr_family, NM_DEVICE_IP_STATE_NONE);
- 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;
+ if (full_cleanup && !IS_IPv4) {
+ priv->ipdhcp_data_6.v6.mode = NM_NDISC_DHCP_LEVEL_NONE;
+ priv->ipdhcp_data_6.v6.needed_prefixes = 0;
}
- 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;
- }
+ if (full_cleanup)
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4), NULL, FALSE);
- 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;
+ if (priv->ipdhcp_data_x[IS_IPv4].client) {
+ nm_clear_g_signal_handler(priv->ipdhcp_data_x[IS_IPv4].client,
+ &priv->ipdhcp_data_x[IS_IPv4].notify_sigid);
+ nm_dhcp_client_stop(priv->ipdhcp_data_x[IS_IPv4].client, release);
+ g_clear_object(&priv->ipdhcp_data_x[IS_IPv4].client);
}
- 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;
- }
+ if (full_cleanup && priv->ipdhcp_data_x[IS_IPv4].config) {
+ gs_unref_object NMDhcpConfig *config =
+ g_steal_pointer(&priv->ipdhcp_data_x[IS_IPv4].config);
- _LOGI(LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started");
+ _notify(self, PROP_DHCPX_CONFIG(IS_IPv4));
+ nm_dbus_object_unexport_on_idle(g_steal_pointer(&config));
+ }
- /* 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;
+ _dev_ip_state_check_async(self, addr_family);
}
-/*****************************************************************************/
-
static void
-ensure_con_ip_config(NMDevice *self, int addr_family)
+_dev_ipdhcpx_handle_fail(NMDevice *self, int addr_family, const char *reason)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- NMConnection * connection;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
- NMIPConfig * con_ip_config;
- if (priv->con_ip_config_x[IS_IPv4])
+ if (priv->ipdhcp_data_x[IS_IPv4].state == NM_DEVICE_IP_STATE_FAILED)
return;
- connection = nm_device_get_applied_connection(self);
- if (!connection)
- return;
+ _LOGT_ipdhcp(addr_family, "DHCP failing: %s", reason ?: "unknown reason");
- con_ip_config = nm_device_ip_config_new(self, addr_family);
+ _dev_ipdhcpx_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED);
- 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));
- }
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4), NULL, FALSE);
- 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 (priv->ipdhcp_data_x[IS_IPv4].config)
+ nm_dhcp_config_set_lease(priv->ipdhcp_data_x[IS_IPv4].config, NULL);
- priv->con_ip_config_x[IS_IPv4] = con_ip_config;
-}
-
-/*****************************************************************************/
-
-static const char *
-_device_get_dhcp_anycast_address(NMDevice *self)
-{
- NMDeviceClass *klass;
-
- nm_assert(NM_IS_DEVICE(self));
-
- klass = NM_DEVICE_GET_CLASS(self);
-
- if (klass->get_dhcp_anycast_address)
- return klass->get_dhcp_anycast_address(self);
-
- return NULL;
+ _dev_ip_state_check_async(self, addr_family);
}
static void
-dhcp4_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release)
+_dev_ipdhcpx_handle_accept(NMDevice *self, int addr_family, const NML3ConfigData *l3cd)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
- 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_assert(NM_IS_L3_CONFIG_DATA(l3cd));
- 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.notify_sigid);
+ _dev_ipdhcpx_set_state(self, addr_family, NM_DEVICE_IP_STATE_READY);
- if (cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED)
- nm_dhcp_client_stop(priv->dhcp_data_4.client, release);
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4), l3cd, FALSE);
- g_clear_object(&priv->dhcp_data_4.client);
- }
+ nm_dhcp_config_set_lease(priv->ipdhcp_data_x[IS_IPv4].config, l3cd);
- if (priv->dhcp_data_4.config) {
- nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config);
- _notify(self, PROP_DHCP4_CONFIG);
- }
+ nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP_CHANGE_X(IS_IPv4),
+ self,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ _dev_ip_state_check_async(self, addr_family);
}
-static gboolean
-ip_config_merge_and_apply(NMDevice *self, int addr_family, gboolean commit)
+static void
+_dev_ipdhcpx_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_data, NMDevice *self)
{
- 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 int IS_IPv4 = NM_IS_IPv4(addr_family);
-
- if (nm_device_sys_iface_state_is_external(self))
- commit = FALSE;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int addr_family = nm_dhcp_client_get_addr_family(client);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
- connection = nm_device_get_applied_connection(self);
+ nm_assert(notify_data);
+ nm_assert(priv->ipdhcp_data_x[IS_IPv4].state > NM_DEVICE_IP_STATE_NONE);
+ nm_assert(client && priv->ipdhcp_data_x[IS_IPv4].client == client);
- /* Apply ignore-auto-routes and ignore-auto-dns settings */
- if (connection) {
- NMSettingIPConfig *s_ip;
+ switch (notify_data->notify_type) {
+ case NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED:
+ nm_assert(!IS_IPv4);
+ /* 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, notify_data->prefix_delegated.prefix);
+ return;
- 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);
+ case NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT:
+ /* Here we also fail if we had a lease and it expired. Maybe,
+ * ipv[46].dhcp-timeout should only cover the time until we get
+ * a lease for the first time. How it is here, it means that a
+ * connection can fail after being connected successfully for a
+ * longer time. */
+ _dev_ipdhcpx_handle_fail(self, addr_family, "timeout getting lease");
+ return;
- /* 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);
+ case NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD:
+ /* Like NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT, this does not
+ * apply only if we never got a lease, but also after being fully
+ * connected. We can also fail then. */
+ _dev_ipdhcpx_handle_fail(self, addr_family, notify_data->it_looks_bad.reason);
+ return;
- if (!IS_IPv4) {
- NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG(s_ip);
+ case NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE:
- 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);
- }
+ if (!notify_data->lease_update.l3cd) {
+ _LOGT_ipdhcp(addr_family, "lease lost");
+ _dev_ipdhcpx_handle_fail(self, addr_family, "lease lost");
+ return;
}
- }
-
- 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);
+ _LOGT_ipdhcp(addr_family, "lease update");
+ _dev_ipdhcpx_handle_accept(self, addr_family, notify_data->lease_update.l3cd);
+ return;
}
- init_ip_config_dns_priority(self, composite);
+ nm_assert_not_reached();
+}
+
+/*****************************************************************************/
- 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);
+static void
+_dev_ipdhcpx_start(NMDevice *self, int addr_family)
+{
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ NMConnection * connection;
+ NMSettingConnection * s_con;
+ NMSettingIPConfig * s_ip;
+ const NML3ConfigData *previous_lease;
+ gs_unref_bytes GBytes *hwaddr = NULL;
+ gboolean enforce_duid = FALSE;
+ gs_free_error GError *error = NULL;
+ const NMPlatformLink *pllink;
+ guint no_lease_timeout_sec;
+ int ifindex;
+ const char * str;
+ gboolean request_broadcast;
+ const char * fail_reason;
+
+ if (priv->ipdhcp_data_x[IS_IPv4].state == NM_DEVICE_IP_STATE_NONE)
+ _dev_ipdhcpx_set_state(self, addr_family, NM_DEVICE_IP_STATE_PENDING);
+ else if (priv->ipdhcp_data_x[IS_IPv4].state > NM_DEVICE_IP_STATE_PENDING) {
+ /* already started. Nothing to do. */
+ return;
}
- 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 (nm_device_sys_iface_state_is_external(self)) {
+ fail_reason = nm_assert_unreachable_val("cannot run DHCP on external interface");
+ goto out_fail;
}
- 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;
+ connection = nm_device_get_applied_connection(self);
+ if (!connection) {
+ fail_reason = nm_assert_unreachable_val("no applied connection for starting DHCP");
+ goto out_fail;
}
- /* Merge all the IP configs into the composite config */
+ s_con = nm_connection_get_setting_connection(connection);
+ s_ip = nm_connection_get_setting_ip_config(connection, addr_family);
+ nm_assert(s_con);
+ nm_assert(s_ip);
- 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));
- }
+ ifindex = 0;
+ pllink = nm_l3cfg_get_pllink(priv->l3cfg, TRUE);
+ if (pllink) {
+ ifindex = pllink->ifindex;
+ nm_assert(ifindex > 0);
+ nm_assert(ifindex == nm_device_get_ip_ifindex(self));
}
-
- 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 (ifindex <= 0) {
+ fail_reason = "cannot start DHCP without interface";
+ goto out_fail;
}
+ hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address);
+
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));
+ if (!hwaddr) {
+ fail_reason = "interface has no MAC address to start DHCPv6";
+ goto out_fail;
}
}
- 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);
- }
+ request_broadcast = FALSE;
+ if (pllink) {
+ str = nmp_object_link_udev_device_get_property_value(NMP_OBJECT_UP_CAST(pllink),
+ "ID_NET_DHCP_BROADCAST");
+ if (str && _nm_utils_ascii_str_to_bool(str, FALSE)) {
+ /* Use the device property ID_NET_DHCP_BROADCAST setting, which may be set for interfaces
+ * requiring that the DHCPOFFER message is being broadcast because they can't handle unicast
+ * messages while not fully configured.
+ */
+ request_broadcast = TRUE;
}
}
- /* 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 (!IS_IPv4
+ && NM_IN_SET(priv->ipll_data_6.state,
+ NM_DEVICE_IP_STATE_NONE,
+ NM_DEVICE_IP_STATE_PENDING)) {
+ _dev_ipll6_start(self);
+ return;
}
- if (commit) {
- gboolean is_vrf;
+ no_lease_timeout_sec = _prop_get_ipvx_dhcp_timeout(self, addr_family);
+
+ if (IS_IPv4) {
+ NMDhcpClientConfig config;
+ gs_unref_bytes GBytes *bcast_hwaddr = NULL;
+ gs_unref_bytes GBytes *client_id = NULL;
+ gs_unref_bytes GBytes *vendor_class_identifier = NULL;
+ const char *const * reject_servers;
+ const char * hostname;
+ gboolean hostname_is_fqdn;
+
+ 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_ip));
+ reject_servers = nm_setting_ip_config_get_dhcp_reject_servers(s_ip, NULL);
- is_vrf = priv->master && nm_device_get_device_type(priv->master) == NM_DEVICE_TYPE_VRF;
+ bcast_hwaddr = nmp_link_address_get_as_bytes(&pllink->l_broadcast);
- 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);
+ hostname = nm_setting_ip4_config_get_dhcp_fqdn(NM_SETTING_IP4_CONFIG(s_ip));
+ if (hostname) {
+ hostname_is_fqdn = TRUE;
} 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);
+ hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip);
}
- }
- 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));
- }
- }
+ config = (NMDhcpClientConfig){
+ .addr_family = AF_INET,
+ .l3cfg = nm_device_get_l3cfg(self),
+ .iface = nm_device_get_ip_iface(self),
+ .uuid = nm_connection_get_uuid(connection),
+ .hwaddr = hwaddr,
+ .bcast_hwaddr = bcast_hwaddr,
+ .send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip),
+ .hostname = hostname,
+ .hostname_flags = _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET),
+ .client_id = client_id,
+ .mud_url = _prop_get_connection_mud_url(self, s_con),
+ .timeout = no_lease_timeout_sec,
+ .anycast_address = _device_get_dhcp_anycast_address(self),
+ .vendor_class_identifier = vendor_class_identifier,
+ .use_fqdn = hostname_is_fqdn,
+ .reject_servers = reject_servers,
+ .v4.request_broadcast = request_broadcast,
+ };
- if (!IS_IPv4) {
- NMUtilsIPv6IfaceId iid;
+ priv->ipdhcp_data_4.client =
+ nm_dhcp_manager_start_client(nm_dhcp_manager_get(), &config, &error);
+ } else {
+ gs_unref_bytes GBytes *duid = NULL;
+ gboolean iaid_explicit;
+ guint32 iaid;
+ NMDhcpClientConfig config;
- 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);
+ if (!IN6_IS_ADDR_LINKLOCAL(&priv->ipll_data_6.v6.lladdr)) {
+ /* FIXME(l3cfg:dhcp): NMDhcpClient should monitor the IPv6 link local addresses.
+ * NMDevice kicks off NML3IPv6LL to generate an LL6 address, thereby trying
+ * that we have an LL address, but NMDhcpClient needs automatically monitor those
+ * addresses and choose a suitable one.
+ *
+ * This also means, NMDhcpClientConfig.v6.ll_addr needs to go away. */
+ fail_reason = "interface has no IPv6 link local address to start DHCPv6";
+ goto out_fail;
}
- }
- 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;
-}
+ iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, FALSE, &iaid_explicit);
+ duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid);
+
+ config = (NMDhcpClientConfig){
+ .addr_family = AF_INET6,
+ .l3cfg = nm_device_get_l3cfg(self),
+ .iface = nm_device_get_ip_iface(self),
+ .uuid = nm_connection_get_uuid(connection),
+ .send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip),
+ .hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip),
+ .hostname_flags = _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6),
+ .client_id = duid,
+ .mud_url = _prop_get_connection_mud_url(self, s_con),
+ .timeout = no_lease_timeout_sec,
+ .anycast_address = _device_get_dhcp_anycast_address(self),
+ .v6.ll_addr = &priv->ipll_data_6.v6.lladdr,
+ .v6.enforce_duid = enforce_duid,
+ .v6.iaid = iaid,
+ .v6.iaid_explicit = iaid_explicit,
+ .v6.info_only = (priv->ipdhcp_data_6.v6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF),
+ .v6.needed_prefixes = priv->ipdhcp_data_6.v6.needed_prefixes,
+ };
-static gboolean
-dhcp4_lease_change(NMDevice *self, NMIP4Config *config, gboolean bound)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- gs_free_error GError *error = NULL;
+ priv->ipdhcp_data_6.client =
+ nm_dhcp_manager_start_client(nm_dhcp_manager_get(), &config, &error);
+ }
- g_return_val_if_fail(config, FALSE);
+ if (!priv->ipdhcp_data_x[IS_IPv4].client) {
+ fail_reason = error->message;
+ goto out_fail;
+ }
- applied_config_init(&priv->dev_ip_config_4, config);
+ priv->ipdhcp_data_x[IS_IPv4].notify_sigid =
+ g_signal_connect(priv->ipdhcp_data_x[IS_IPv4].client,
+ NM_DHCP_CLIENT_NOTIFY,
+ G_CALLBACK(_dev_ipdhcpx_notify),
+ self);
- if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) {
- _LOGW(LOGD_DHCP4, "failed to update IPv4 config for DHCP change.");
- return FALSE;
- }
+ /* FIXME(l3cfg:dhcp:previous-lease): take the NML3ConfigData from the previous lease (if any)
+ * and pass it on to NMDhcpClient. This is a fake lease that we use initially (until
+ * NMDhcpClient got a real lease). Note that NMDhcpClient needs to check whether the
+ * lease already expired. */
- /* 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;
+ previous_lease = nm_dhcp_client_get_lease(priv->ipdhcp_data_x[IS_IPv4].client);
+ if (!priv->ipdhcp_data_x[IS_IPv4].config) {
+ priv->ipdhcp_data_x[IS_IPv4].config = nm_dhcp_config_new(addr_family, previous_lease);
+ _notify(self, PROP_DHCPX_CONFIG(IS_IPv4));
}
+ if (previous_lease)
+ _dev_ipdhcpx_handle_accept(self, addr_family, previous_lease);
- nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP_CHANGE_4, self, NULL, NULL, NULL, NULL);
+ return;
- return TRUE;
+out_fail:
+ _dev_ipdhcpx_handle_fail(self, addr_family, fail_reason);
}
-static gboolean
-dhcp_grace_period_expired(NMDevice *self, int addr_family)
+static void
+_dev_ipdhcpx_start_continue(NMDevice *self, int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
- priv->dhcp_data_x[IS_IPv4].grace_id = 0;
- priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE;
-
- _LOGI(LOGD_DHCPX(IS_IPv4),
- "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 */
-
- return G_SOURCE_REMOVE;
+ if (priv->ipdhcp_data_x[IS_IPv4].state != NM_DEVICE_IP_STATE_NONE)
+ _dev_ipdhcpx_start(self, addr_family);
}
-static gboolean
-dhcp_grace_period_expired_4(gpointer user_data)
-{
- return dhcp_grace_period_expired(user_data, AF_INET);
-}
-
-static gboolean
-dhcp_grace_period_expired_6(gpointer user_data)
-{
- return dhcp_grace_period_expired(user_data, AF_INET6);
-}
-
-static gboolean
-dhcp_grace_period_start(NMDevice *self, int addr_family)
+static void
+_dev_ipdhcpx_restart(NMDevice *self, int addr_family, gboolean release)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
const int IS_IPv4 = NM_IS_IPv4(addr_family);
- 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;
+ if (priv->ipdhcp_data_x[IS_IPv4].state != NM_DEVICE_IP_STATE_NONE) {
+ _LOGI_ipdhcp(addr_family, "restarting%s", release ? " (release lease)" : "");
+ _dev_ipdhcpx_cleanup(self, addr_family, FALSE, release);
}
- /* 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_DHCPX(IS_IPv4),
- "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_DHCPX(IS_IPv4),
- "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)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
-
- _LOGD(LOGD_DHCP4,
- "DHCPv4 failed (ip_state %s, was_active %d)",
- nm_device_ip_state_to_string(priv->ip_state_4),
- priv->dhcp_data_4.was_active);
-
- /* 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;
-
- /* ... 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;
- }
-
- if (dhcp_grace_period_start(self, AF_INET))
- goto clear_config;
-
- 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);
- }
-}
-
-static void
-dhcp4_dad_cb(NMDevice *self, NMIP4Config **configs, gboolean success)
-{
- 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);
- }
+ _dev_ipdhcpx_start(self, addr_family);
}
static void
-dhcp4_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_data, NMDevice *self)
+_dev_ipdhcp6_set_dhcp_level(NMDevice *self, NMNDiscDHCPLevel dhcp_level)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- NMIP4Config * manual;
- NMIP4Config ** configs;
- NMConnection * connection;
- NMDhcpState state;
- NMIP4Config * ip4_config;
- GHashTable * options;
-
- nm_assert(nm_dhcp_client_get_addr_family(client) == AF_INET);
- nm_assert(notify_data);
- nm_assert(notify_data->notify_type == NM_DHCP_CLIENT_NOTIFY_TYPE_STATE_CHANGED);
-
- state = notify_data->state_changed.dhcp_state;
- ip4_config = NM_IP4_CONFIG(notify_data->state_changed.ip_config);
- options = notify_data->state_changed.options;
-
- nm_assert(!ip4_config || NM_IS_IP4_CONFIG(ip4_config));
-
- _LOGD(LOGD_DHCP4, "new DHCPv4 client state %d", (int) 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;
- }
-}
-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;
- NMConnection * connection;
- NMSettingConnection * s_con;
- GError * error = NULL;
- const NMPlatformLink * pllink;
- const char *const * reject_servers;
- gboolean request_broadcast;
- const char * str;
+ nm_assert(NM_IN_SET(dhcp_level,
+ NM_NDISC_DHCP_LEVEL_NONE,
+ NM_NDISC_DHCP_LEVEL_OTHERCONF,
+ NM_NDISC_DHCP_LEVEL_MANAGED));
- connection = nm_device_get_applied_connection(self);
- g_return_val_if_fail(connection, FALSE);
+ if (dhcp_level == NM_NDISC_DHCP_LEVEL_NONE && priv->ipdhcp_data_6.v6.needed_prefixes > 0)
+ dhcp_level = NM_NDISC_DHCP_LEVEL_OTHERCONF;
- 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);
-
- request_broadcast = FALSE;
+ if (priv->ipdhcp_data_6.v6.mode == dhcp_level)
+ return;
- 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);
+ _LOGD_ipdhcp(AF_INET6, "level: set to %s", nm_ndisc_dhcp_level_to_string(dhcp_level));
- str = nmp_object_link_udev_device_get_property_value(NMP_OBJECT_UP_CAST(pllink),
- "ID_NET_DHCP_BROADCAST");
- if (str && _nm_utils_ascii_str_to_bool(str, FALSE)) {
- /* Use the device property ID_NET_DHCP_BROADCAST setting, which may be set for interfaces
- * requiring that the DHCPOFFER message is being broadcast because they can't handle unicast
- * messages while not fully configured.
- */
- request_broadcast = TRUE;
- }
+ if (dhcp_level == NM_NDISC_DHCP_LEVEL_NONE) {
+ _dev_ipdhcpx_cleanup(self, AF_INET6, TRUE, TRUE);
+ return;
}
- 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),
- request_broadcast ? NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST : NM_DHCP_CLIENT_FLAGS_NONE,
- 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),
- client_id,
- _prop_get_ipvx_dhcp_timeout(self, AF_INET),
- _device_get_dhcp_anycast_address(self),
- 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.notify_sigid = g_signal_connect(priv->dhcp_data_4.client,
- NM_DHCP_CLIENT_NOTIFY,
- G_CALLBACK(dhcp4_notify),
- 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;
+ priv->ipdhcp_data_6.v6.mode = dhcp_level;
+ _dev_ipdhcpx_restart(self, AF_INET6, TRUE);
}
-gboolean
-nm_device_dhcp4_renew(NMDevice *self, gboolean release)
+/*
+ * Called on the requesting interface when a subnet can't be obtained
+ * from known prefixes for a newly active shared connection.
+ */
+void
+nm_device_request_ip6_prefixes(NMDevice *self, guint needed_prefixes)
{
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");
-
- /* Terminate old DHCP instance and release the old lease */
- dhcp4_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release);
-
- /* Start DHCP again on the interface */
- return dhcp4_start(self) != NM_ACT_STAGE_RETURN_FAILURE;
-}
-
-/*****************************************************************************/
-
-static NMIP4Config *
-shared4_new_config(NMDevice *self, NMConnection *connection)
-{
- NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
- NMIP4Config * config;
- NMSettingIPConfig * s_ip4;
- NMPlatformIP4Address address = {
- .addr_source = NM_IP_CONFIG_SOURCE_SHARED,
- };
+ if (priv->ipdhcp_data_6.v6.needed_prefixes == needed_prefixes)
+ return;
- g_return_val_if_fail(self, NULL);
- g_return_val_if_fail(connection, NULL);
+ _LOGD(LOGD_IP6, "ipv6-pd: asking DHCPv6 for %u prefixes", needed_prefixes);
- 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;
+ priv->ipdhcp_data_6.v6.needed_prefixes = needed_prefixes;
- 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);
+ if (priv->ipdhcp_data_6.v6.mode == NM_NDISC_DHCP_LEVEL_NONE) {
+ priv->ipdhcp_data_6.v6.mode = NM_NDISC_DHCP_LEVEL_OTHERCONF;
+ _LOGD_ipdhcp(AF_INET6,
+ "level: set to %s",
+ nm_ndisc_dhcp_level_to_string(NM_NDISC_DHCP_LEVEL_OTHERCONF));
}
- config = nm_device_ip4_config_new(self);
- nm_ip4_config_add_address(config, &address);
-
- return config;
+ _dev_ipdhcpx_restart(self, AF_INET6, TRUE);
}
/*****************************************************************************/
@@ -9766,392 +10050,6 @@ have_any_ready_slaves(NMDevice *self)
}
/*****************************************************************************/
-/* DHCPv6 stuff */
-
-static void
-dhcp6_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release)
-{
- 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;
-
- if (priv->dhcp_data_6.client) {
- nm_clear_g_signal_handler(priv->dhcp_data_6.client, &priv->dhcp_data_6.notify_sigid);
-
- 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);
- }
-
- 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)
-{
- 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;
- }
-
- g_assert(priv->dhcp_data_6.client); /* sanity check */
-
- 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;
- }
-
- nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP_CHANGE_6, self, NULL, NULL, NULL, NULL);
-
- 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)",
- nm_device_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);
- }
-}
-
-static void
-dhcp6_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_data, NMDevice *self)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- gs_free char * event_id = NULL;
- NMDhcpState state;
- NMIP6Config * ip6_config;
- GHashTable * options;
-
- nm_assert(nm_dhcp_client_get_addr_family(client) == AF_INET6);
- nm_assert(notify_data);
-
- if (notify_data->notify_type == NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED) {
- /* 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, notify_data->prefix_delegated.prefix);
- return;
- }
-
- nm_assert(notify_data->notify_type == NM_DHCP_CLIENT_NOTIFY_TYPE_STATE_CHANGED);
-
- state = notify_data->state_changed.dhcp_state;
- ip6_config = NM_IP6_CONFIG(notify_data->state_changed.ip_config);
- options = notify_data->state_changed.options;
-
- nm_assert(!ip6_config || NM_IS_IP6_CONFIG(ip6_config));
-
- _LOGD(LOGD_DHCP6, "new DHCPv6 client state %d", (int) 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 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;
- GError * error = NULL;
- guint32 iaid;
- gboolean iaid_explicit;
- NMSettingConnection * s_con;
- const NMPlatformIP6Address *ll_addr = NULL;
- int ip_ifindex;
-
- 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_ip_config_find_first_address(NM_IP_CONFIG(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;
- }
-
- ip_ifindex = nm_device_get_ip_ifindex(self);
- if (ip_ifindex <= 0) {
- _LOGD(LOGD_DHCP6, "can't start DHCPv6: interface is gone");
- return FALSE;
- }
-
- pllink = nm_platform_link_get(nm_device_get_platform(self), ip_ifindex);
- if (pllink)
- hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address);
-
- iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, TRUE, &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),
- ip_ifindex,
- &ll_addr->address,
- nm_connection_get_uuid(connection),
- nm_device_get_route_table(self, AF_INET6),
- nm_device_get_route_metric(self, AF_INET6),
- (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY
- : NM_DHCP_CLIENT_FLAGS_NONE,
- 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),
- duid,
- enforce_duid,
- iaid,
- iaid_explicit,
- _prop_get_ipvx_dhcp_timeout(self, AF_INET6),
- _device_get_dhcp_anycast_address(self),
- 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.notify_sigid = g_signal_connect(priv->dhcp_data_6.client,
- NM_DHCP_CLIENT_NOTIFY,
- G_CALLBACK(dhcp6_notify),
- 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)
-{
- 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_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);
-
- 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;
-
- return TRUE;
-}
-
-gboolean
-nm_device_dhcp6_renew(NMDevice *self, gboolean release)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- NMNDiscDHCPLevel mode;
-
- g_return_val_if_fail(priv->dhcp_data_6.client != NULL, FALSE);
-
- _LOGI(LOGD_DHCP6, "DHCPv6 lease renewal requested");
-
- /* Terminate old DHCP instance and release the old lease */
- mode = priv->dhcp6.mode;
- dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release);
- priv->dhcp6.mode = mode;
-
- /* Start DHCP again on the interface */
- return dhcp6_start(self, FALSE);
-}
-
-/*****************************************************************************/
-
-/*
- * Called on the requesting interface when a subnet can't be obtained
- * from known prefixes for a newly active shared connection.
- */
-void
-nm_device_request_ip6_prefixes(NMDevice *self, int needed_prefixes)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
-
- 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 {
- priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_OTHERCONF;
- _LOGD(LOGD_DEVICE | LOGD_DHCP6, "ipv6-pd: starting DHCPv6 to request a prefix");
- dhcp6_start(self, FALSE);
- }
-}
gboolean
nm_device_needs_ip6_subnet(NMDevice *self)
@@ -10166,25 +10064,24 @@ nm_device_needs_ip6_subnet(NMDevice *self)
void
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];
+ nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
+ char sbuf[sizeof(_nm_utils_to_string_buffer)];
+ NMPlatformIP6Address address;
- if (!applied_config_get_current(&priv->ac_ip6_config))
- applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6);
+ l3cd = nm_device_create_l3_config_data(self, NM_IP_CONFIG_SOURCE_SHARED);
/* Assign a ::1 address in the subnet for us. */
+ address = *subnet;
address.address.s6_addr32[3] |= htonl(1);
- applied_config_add_address(&priv->ac_ip6_config, NM_PLATFORM_IP_ADDRESS_CAST(&address));
+
+ nm_l3_config_data_add_address_6(l3cd, &address);
_LOGD(LOGD_IP6,
- "ipv6-pd: using %s address (preferred for %u seconds)",
- _nm_utils_inet6_ntop(&address.address, sbuf),
- subnet->preferred);
+ "ipv6-pd: using %s",
+ nm_platform_ip6_address_to_string(&address, sbuf, sizeof(sbuf)));
- /* 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");
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_PD_6, l3cd, FALSE);
+ _dev_l3_cfg_commit(self, TRUE);
}
/*
@@ -10194,137 +10091,184 @@ nm_device_use_ip6_subnet(NMDevice *self, const NMPlatformIP6Address *subnet)
void
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);
+ NMDevicePrivate * priv_src;
+ nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
+ const NML3ConfigData * l3cd_src;
- 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);
+ /* FIXME(l3cfg): this entire code an approach seems flawed. It's flawed, because the
+ * very next RA will reset the changes. */
+
+ if (priv->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d) {
+ l3cd = nm_l3_config_data_new_clone(priv->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d, 0);
+ nm_l3_config_data_clear_nameservers(l3cd, AF_INET6);
+ nm_l3_config_data_clear_searches(l3cd, AF_INET6);
} else
- applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6);
+ l3cd = nm_device_create_l3_config_data(self, NM_IP_CONFIG_SOURCE_SHARED);
- if (from_device)
- from_config = nm_device_get_ip6_config(from_device);
- if (!from_config)
- return;
+ priv_src = NM_DEVICE_GET_PRIVATE(from_device);
+ l3cd_src = priv_src->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d;
+ if (l3cd_src) {
+ const char *const * strvarr;
+ const struct in6_addr *const *addrs;
+ guint n;
+ guint 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));
- }
+ addrs = nm_l3_config_data_get_nameservers(l3cd_src, AF_INET6, &n);
+ for (i = 0; i < n; i++)
+ nm_l3_config_data_add_nameserver(l3cd, AF_INET6, addrs[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));
+ strvarr = nm_l3_config_data_get_searches(l3cd_src, AF_INET6, &n);
+ for (i = 0; i < n; i++)
+ nm_l3_config_data_add_search(l3cd, AF_INET6, strvarr[i]);
}
- if (!ip_config_merge_and_apply(self, AF_INET6, TRUE))
- _LOGW(LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing");
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_AC_6, l3cd, FALSE);
+
+ _dev_l3_cfg_commit(self, TRUE);
}
/*****************************************************************************/
-static void
-linklocal6_failed(NMDevice *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);
-}
-
static gboolean
-linklocal6_timeout_cb(gpointer user_data)
+_dev_ipll6_state_retry_cb(gpointer user_data)
{
- NMDevice *self = user_data;
+ NMDevice * self = user_data;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- _LOGD(LOGD_DEVICE, "linklocal6: waiting for link-local addresses failed due to timeout");
- linklocal6_failed(self);
- return G_SOURCE_REMOVE;
+ nm_clear_g_source_inst(&priv->ipll_data_6.v6.retry_source);
+ _dev_ipll6_start(self);
+ return G_SOURCE_CONTINUE;
}
static void
-linklocal6_check_complete(NMDevice *self)
+_dev_ipll6_set_llstate(NMDevice *self, NML3IPv6LLState llstate, const struct in6_addr *lladdr)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- NMConnection * connection;
- const char * method;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ gboolean changed = FALSE;
+ NMDeviceIPState state;
+ NMDeviceIPState old_state;
+
+ if (!lladdr)
+ lladdr = &nm_ip_addr_zero.addr6;
+
+ if (priv->ipll_data_6.v6.llstate != llstate
+ || !IN6_ARE_ADDR_EQUAL(&priv->ipll_data_6.v6.lladdr, lladdr)) {
+ changed = TRUE;
+ priv->ipll_data_6.v6.llstate = llstate;
+ priv->ipll_data_6.v6.lladdr = *lladdr;
+ }
+
+ nm_assert((priv->ipll_data_6.v6.ipv6ll
+ && NM_IN_SET(priv->ipll_data_6.v6.llstate,
+ NM_L3_IPV6LL_STATE_STARTING,
+ NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS,
+ NM_L3_IPV6LL_STATE_READY,
+ NM_L3_IPV6LL_STATE_DAD_FAILED))
+ || (!priv->ipll_data_6.v6.ipv6ll
+ && NM_IN_SET(priv->ipll_data_6.v6.llstate,
+ NM_L3_IPV6LL_STATE_NONE,
+ NM_L3_IPV6LL_STATE_DEFUNCT)));
+
+ switch (priv->ipll_data_6.v6.llstate) {
+ case NM_L3_IPV6LL_STATE_NONE:
+ state = NM_DEVICE_IP_STATE_NONE;
+ break;
+ case NM_L3_IPV6LL_STATE_DEFUNCT:
+ case NM_L3_IPV6LL_STATE_DAD_FAILED:
+ state = NM_DEVICE_IP_STATE_FAILED;
+ break;
+ case NM_L3_IPV6LL_STATE_READY:
+ state = NM_DEVICE_IP_STATE_READY;
+ break;
+ case NM_L3_IPV6LL_STATE_STARTING:
+ case NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS:
+ state = NM_DEVICE_IP_STATE_PENDING;
+ break;
+ default:
+ state = nm_assert_unreachable_val(NM_DEVICE_IP_STATE_FAILED);
+ break;
+ }
- if (!priv->linklocal6_timeout_id) {
- /* we are not waiting for linklocal to complete. Nothing to do. */
- return;
+ old_state = priv->ipll_data_6.state;
+ if (priv->ipll_data_6.state != state) {
+ priv->ipll_data_6.state = state;
+ changed = TRUE;
}
- if (!priv->ext_ip6_config_captured
- || !nm_ip_config_find_first_address(NM_IP_CONFIG(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;
+ if (priv->ipll_data_6.v6.llstate != NM_L3_IPV6LL_STATE_DEFUNCT)
+ nm_clear_g_source_inst(&priv->ipll_data_6.v6.retry_source);
+ else if (!priv->ipll_data_6.v6.retry_source) {
+ /* we schedule a timer to try to recover from this... Possibly some higher layer
+ * will however fail the activation... */
+ priv->ipll_data_6.v6.retry_source =
+ nm_g_timeout_add_source(10000, _dev_ipll6_state_retry_cb, self);
}
- nm_clear_g_source(&priv->linklocal6_timeout_id);
+ if (changed) {
+ char sbuf[NM_UTILS_INET_ADDRSTRLEN];
- connection = nm_device_get_applied_connection(self);
- g_assert(connection);
+ _LOGT_ipll(AF_INET6,
+ "set state %s (was %s, llstate=%s, lladdr=%s)",
+ nm_device_ip_state_to_string(priv->ipll_data_6.state),
+ nm_device_ip_state_to_string(old_state),
+ nm_l3_ipv6ll_state_to_string(priv->ipll_data_6.v6.llstate),
+ nm_ip_addr_is_null(AF_INET6, &priv->ipll_data_6.v6.lladdr)
+ ? "(none)"
+ : _nm_utils_inet6_ntop(&priv->ipll_data_6.v6.lladdr, sbuf));
+ }
- method = nm_device_get_effective_ip_config_method(self, AF_INET6);
+ if (changed)
+ _dev_ip_state_check_async(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);
+ if (priv->ipll_data_6.v6.llstate == NM_L3_IPV6LL_STATE_READY) {
+ /* if we got an IPv6LL address, we might poke some other methods
+ * to progress... */
+ _dev_ipac6_start_continue(self);
+ _dev_ipdhcpx_start_continue(self, AF_INET6);
+ }
}
static void
-check_and_add_ipv6ll_addr(NMDevice *self)
+_dev_ipll6_state_change_cb(NML3IPv6LL * ipv6ll,
+ NML3IPv6LLState llstate,
+ const struct in6_addr *lladdr,
+ gpointer user_data)
{
- 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];
+ _dev_ipll6_set_llstate(user_data, llstate, lladdr);
+}
- if (!priv->ipv6ll_handle)
- return;
+static void
+_dev_ipll6_start(NMDevice *self)
+{
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ NMConnection * connection;
+ NMSettingIP6Config * s_ip6 = NULL;
+ gboolean assume;
+ const char * ifname;
+ NML3IPv6LLState llstate;
+ const struct in6_addr *lladdr;
- if (priv->ext_ip6_config_captured
- && nm_ip_config_find_first_address(NM_IP_CONFIG(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 */
+ if (priv->ipll_data_6.v6.ipv6ll)
return;
- }
- priv->ipv6ll_has = FALSE;
- memset(&priv->ipv6ll_addr, 0, sizeof(priv->ipv6ll_addr));
+ if (!priv->l3cfg) {
+ _LOGD(LOGD_IP6, "linklocal6: no IP link for IPv6");
+ goto out_fail;
+ }
- memset(&lladdr, 0, sizeof(lladdr));
- lladdr.s6_addr16[0] = htons(0xfe80);
+ ifname = nm_device_get_ip_iface(self);
+ if (!ifname) {
+ _LOGD(LOGD_IP6, "linklocal6: no interface name for IPv6");
+ goto out_fail;
+ }
connection = nm_device_get_applied_connection(self);
if (connection)
s_ip6 = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection));
+ assume = nm_device_sys_iface_state_is_external_or_assume(self);
+
if (s_ip6
&& nm_setting_ip6_config_get_addr_gen_mode(s_ip6)
== NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) {
@@ -10332,73 +10276,31 @@ check_and_add_ipv6ll_addr(NMDevice *self)
const char * stable_id;
stable_id = _prop_get_connection_stable_id(self, connection, &stable_type);
- if (!nm_utils_ipv6_addr_set_stable_privacy_may_fail(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";
+ priv->ipll_data_6.v6.ipv6ll = nm_l3_ipv6ll_new_stable_privacy(priv->l3cfg,
+ assume,
+ stable_type,
+ ifname,
+ stable_id,
+ _dev_ipll6_state_change_cb,
+ self);
} 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;
+ goto out_fail;
}
- 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)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- nm_clear_g_source(&priv->linklocal6_timeout_id);
-
- if (priv->ext_ip6_config_captured
- && nm_ip_config_find_first_address(NM_IP_CONFIG(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));
+ priv->ipll_data_6.v6.ipv6ll =
+ nm_l3_ipv6ll_new_token(priv->l3cfg, assume, &iid, _dev_ipll6_state_change_cb, self);
+ }
- check_and_add_ipv6ll_addr(self);
+ llstate = nm_l3_ipv6ll_get_state(priv->ipll_data_6.v6.ipv6ll, &lladdr);
+ _dev_ipll6_set_llstate(self, llstate, lladdr);
+ return;
- /* 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;
+out_fail:
+ _dev_ipll6_set_llstate(self, NM_L3_IPV6LL_STATE_DEFUNCT, NULL);
}
/*****************************************************************************/
@@ -10561,13 +10463,16 @@ set_platform_mtu(NMDevice *self, guint32 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;
+_commit_mtu(NMDevice *self)
+{
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ NMDeviceMtuSource source = NM_DEVICE_MTU_SOURCE_NONE;
+ const NML3ConfigData *l3cd;
+ guint32 ip6_mtu_orig;
+ guint32 ip6_mtu;
+ guint32 mtu_desired_orig;
+ guint32 mtu_desired;
+ guint32 mtu_plat;
struct {
gboolean initialized;
guint32 value;
@@ -10575,7 +10480,9 @@ _commit_mtu(NMDevice *self, const NMIP4Config *config)
0,
};
int ifindex;
- char sbuf[64], sbuf1[64], sbuf2[64];
+ char sbuf[64];
+ char sbuf1[64];
+ char sbuf2[64];
gboolean success = TRUE;
ifindex = nm_device_get_ip_ifindex(self);
@@ -10589,8 +10496,11 @@ _commit_mtu(NMDevice *self, const NMIP4Config *config)
return;
}
+ l3cd = nm_l3cfg_get_combined_l3cd(priv->l3cfg, FALSE);
+
{
- guint32 mtu = 0;
+ guint32 mtu = 0;
+ guint32 mtu2;
gboolean force = FALSE;
/* We take the MTU from various sources: (in order of increasing
@@ -10617,9 +10527,9 @@ _commit_mtu(NMDevice *self, const NMIP4Config *config)
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);
+ if (l3cd && !force && source < NM_DEVICE_MTU_SOURCE_IP_CONFIG
+ && (mtu2 = nm_l3_config_data_get_mtu(l3cd)) > 0) {
+ mtu = mtu2;
source = NM_DEVICE_MTU_SOURCE_IP_CONFIG;
}
@@ -10808,239 +10718,181 @@ nm_device_commit_mtu(NMDevice *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);
+ _commit_mtu(self);
} else
_LOGT(LOGD_DEVICE,
"mtu: commit-mtu... skip due to state %s",
nm_device_state_to_string(state));
}
+/*****************************************************************************/
+
static void
-ndisc_config_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, NMDevice *self)
+_dev_ipac6_ndisc_set_router_config(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) {
- 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 = 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;
-
- nm_ip6_config_reset_addresses_ndisc((NMIP6Config *) priv->ac_ip6_config.orig,
- rdata->addresses,
- rdata->addresses_n,
- 64,
- 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,
- 64,
- ifa_flags);
- }
- }
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ const NML3ConfigData *l3cd;
- 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));
- 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));
- }
- }
+ if (!priv->ipac6_data.ndisc)
+ return;
- if (changed & NM_NDISC_CONFIG_DNS_SERVERS) {
- /* Rebuild DNS server list from neighbor discovery cache. */
- applied_config_reset_nameservers(&priv->ac_ip6_config);
+ if (nm_ndisc_get_node_type(priv->ipac6_data.ndisc) != NM_NDISC_NODE_TYPE_ROUTER)
+ return;
- for (i = 0; i < rdata->dns_servers_n; i++)
- applied_config_add_nameserver(&priv->ac_ip6_config,
- (const NMIPAddr *) &rdata->dns_servers[i].address);
- }
+ /* FIXME(l3cfg): this doesn't seem right. What is the meaning of the l3cd at this
+ * point? Also, when do we need to reset the config (and call this function again?). */
+ l3cd = nm_l3cfg_get_combined_l3cd(priv->l3cfg, FALSE);
+ if (l3cd)
+ nm_ndisc_set_config(priv->ipac6_data.ndisc, l3cd);
+}
- if (changed & NM_NDISC_CONFIG_DNS_DOMAINS) {
- /* Rebuild domain list from neighbor discovery cache. */
- applied_config_reset_searches(&priv->ac_ip6_config);
+static void
+_dev_ipac6_set_state(NMDevice *self, NMDeviceIPState state)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- for (i = 0; i < rdata->dns_domains_n; i++)
- applied_config_add_search(&priv->ac_ip6_config, rdata->dns_domains[i].domain);
+ if (priv->ipac6_data.state != state) {
+ _LOGD_ipac6("set state: %s (was %s)",
+ nm_device_ip_state_to_string(state),
+ nm_device_ip_state_to_string(priv->ipac6_data.state));
+ priv->ipac6_data.state = state;
}
+}
- 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;
- }
- }
- }
- }
+static void
+_dev_ipac6_ndisc_config_changed(NMNDisc * ndisc,
+ const NMNDiscData * rdata,
+ guint changed_i,
+ const NML3ConfigData *l3cd,
+ NMDevice * self)
+{
+ _dev_ipac6_grace_period_start(self, 0, TRUE);
- 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);
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_AC_6, l3cd, FALSE);
- 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);
- }
+ _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY);
- 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);
- }
+ _dev_ipdhcp6_set_dhcp_level(self, rdata->dhcp_level);
- 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;
- }
- }
+ _dev_l3_cfg_commit(self, FALSE);
- nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL);
+ _dev_ip_state_check_async(self, AF_INET6);
}
static void
-ndisc_ra_timeout(NMNDisc *ndisc, NMDevice *self)
+_dev_ipac6_handle_timeout(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_ipac6("timeout for autoconf (IPv6 router advertisement) reached");
- _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_ip_config_find_first_address(NM_IP_CONFIG(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);
- }
+ nm_clear_g_source_inst(&priv->ipac6_data.ndisc_grace_source);
+
+ _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_FAILED);
+
+ _dev_ip_state_check_async(self, AF_INET6);
}
static void
-addrconf6_start_with_link_ready(NMDevice *self)
+_dev_ipac6_ndisc_ra_timeout(NMNDisc *ndisc, NMDevice *self)
{
- NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
- NMUtilsIPv6IfaceId iid;
+ _dev_ipac6_handle_timeout(self);
+}
- g_assert(priv->ndisc);
+static gboolean
+_dev_ipac6_grace_period_expired(gpointer user_data)
+{
+ _dev_ipac6_handle_timeout(user_data);
+ return G_SOURCE_REMOVE;
+}
- 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");
+static gboolean
+_dev_ipac6_grace_period_start(NMDevice *self, guint32 timeout_sec, gboolean force_restart)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ gboolean stopped;
+
+ /* In any other case (expired lease, assumed connection, etc.),
+ * wait for some time before failing the IP method.
+ */
+ if (!force_restart && priv->ipac6_data.ndisc_grace_source) {
+ /* already pending. */
+ return FALSE;
}
- /* 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");
+ /* Start a grace period equal to the RA timeout multiplied
+ * by a constant factor. */
+
+ stopped = nm_clear_g_source_inst(&priv->ipac6_data.ndisc_grace_source);
- 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);
+ if (timeout_sec == 0) {
+ if (stopped)
+ _LOGD_ipac6("grace period stopped");
+ return FALSE;
}
- 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);
+ nm_assert(timeout_sec <= G_MAXINT32);
- ndisc_set_router_config(priv->ndisc, self);
- nm_ndisc_start(priv->ndisc);
- priv->ndisc_started = TRUE;
- return;
+ if (timeout_sec >= G_MAXUINT / (GRACE_PERIOD_MULTIPLIER * 1000u))
+ timeout_sec = NM_RA_TIMEOUT_INFINITY;
+
+ if (timeout_sec == NM_RA_TIMEOUT_INFINITY) {
+ _LOGD_ipac6("grace period starts with infinity timeout");
+ priv->ipac6_data.ndisc_grace_source = g_source_ref(nm_g_source_sentinel_get(0));
+ } else {
+ _LOGD_ipac6("grace period starts with %u seconds", timeout_sec);
+ priv->ipac6_data.ndisc_grace_source =
+ nm_g_timeout_add_source(timeout_sec * (GRACE_PERIOD_MULTIPLIER * 1000u),
+ _dev_ipac6_grace_period_expired,
+ self);
+ }
+
+ return TRUE;
}
-static gboolean
-addrconf6_start(NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
+static void
+_dev_ipac6_start(NMDevice *self)
{
NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
NMConnection * connection;
- NMSettingIP6Config *s_ip6 = NULL;
- GError * error = NULL;
+ NMSettingIP6Config *s_ip = NULL;
+ NMNDiscNodeType node_type;
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;
+ NMUtilsIPv6IfaceId iid;
- if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) {
- _LOGI(LOGD_IP6, "addrconf6: kernel does not support IPv6");
- return FALSE;
+ if (priv->ipac6_data.state == NM_DEVICE_IP_STATE_NONE) {
+ if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) {
+ _LOGI_ipac6("addrconf6: kernel does not support IPv6");
+ _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_FAILED);
+ _dev_ip_state_check_async(self, AF_INET6);
+ return;
+ }
+
+ _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_PENDING);
}
- connection = nm_device_get_applied_connection(self);
- g_assert(connection);
+ if (NM_IN_SET(priv->ipll_data_6.state, NM_DEVICE_IP_STATE_NONE, NM_DEVICE_IP_STATE_PENDING)) {
+ _dev_ipac6_grace_period_start(self, 30, TRUE);
+ _dev_ipll6_start(self);
+ return;
+ }
- nm_assert(!applied_config_get_current(&priv->ac_ip6_config));
- applied_config_clear(&priv->ac_ip6_config);
+ if (priv->ipac6_data.ndisc) {
+ /* we already started. Nothing to do. */
+ return;
+ }
- nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref);
- nm_clear_g_source(&priv->rt6_temporary_not_available_id);
+ connection = nm_device_get_applied_connection(self);
+ if (connection)
+ s_ip = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection));
- s_ip6 = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection));
- g_assert(s_ip6);
+ g_return_if_fail(s_ip);
if (nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET6),
NM_SETTING_IP6_CONFIG_METHOD_SHARED))
@@ -11063,60 +10915,95 @@ addrconf6_start(NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
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;
+ stable_id = _prop_get_connection_stable_id(self, connection, &stable_type);
+
+ {
+ const NMNDiscConfig config = {
+ .l3cfg = nm_device_get_l3cfg(self),
+ .ifname = nm_device_get_ip_iface(self),
+ .stable_type = stable_type,
+ .network_id = stable_id,
+ .addr_gen_mode = nm_setting_ip6_config_get_addr_gen_mode(s_ip),
+ .node_type = node_type,
+ .max_addresses = max_addresses,
+ .router_solicitations = router_solicitations,
+ .router_solicitation_interval = router_solicitation_interval,
+ .ra_timeout = ra_timeout,
+ .ip6_privacy = _prop_get_ipv6_ip6_privacy(self),
+ };
+
+ priv->ipac6_data.ndisc = nm_lndp_ndisc_new(&config);
+
+ priv->ipac6_data.ndisc_changed_id =
+ g_signal_connect(priv->ipac6_data.ndisc,
+ NM_NDISC_CONFIG_RECEIVED,
+ G_CALLBACK(_dev_ipac6_ndisc_config_changed),
+ self);
+ priv->ipac6_data.ndisc_timeout_id =
+ g_signal_connect(priv->ipac6_data.ndisc,
+ NM_NDISC_RA_TIMEOUT_SIGNAL,
+ G_CALLBACK(_dev_ipac6_ndisc_ra_timeout),
+ self);
}
- priv->ndisc_use_tempaddr = use_tempaddr;
+ if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) {
+ _LOGD_ipac6("using the device EUI-64 identifier");
+ nm_ndisc_set_iid(priv->ipac6_data.ndisc, iid);
+ } else {
+ /* Don't abort the addrconf at this point -- if ndisc needs the iid
+ * it will notice this itself. */
+ _LOGD_ipac6("no interface identifier; IPv6 address creation may fail");
+ }
- /* ensure link local is ready... */
- if (!linklocal6_start(self)) {
- /* wait for the LL address to show up */
- return TRUE;
+ if (nm_ndisc_get_node_type(priv->ipac6_data.ndisc) == NM_NDISC_NODE_TYPE_ROUTER) {
+ nm_device_sysctl_ip_conf_set(self, AF_INET6, "forwarding", "1");
+ priv->needs_ip6_subnet = TRUE;
+ g_signal_emit(self, signals[IP6_SUBNET_NEEDED], 0);
}
- /* already have the LL address; kick off neighbor discovery */
- addrconf6_start_with_link_ready(self);
- return TRUE;
+ _dev_ipac6_ndisc_set_router_config(self);
+
+ if (node_type == NM_NDISC_NODE_TYPE_ROUTER)
+ _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY);
+ else
+ _dev_ipac6_grace_period_start(self, ra_timeout, TRUE);
+
+ nm_ndisc_start(priv->ipac6_data.ndisc);
}
static void
-addrconf6_cleanup(NMDevice *self)
+_dev_ipac6_start_continue(NMDevice *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);
+ if (priv->ipac6_data.state != NM_DEVICE_IP_STATE_NONE)
+ _dev_ipac6_start(self);
+}
+
+static void
+_dev_ipac6_cleanup(NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- 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);
+ nm_clear_g_source_inst(&priv->ipac6_data.ndisc_grace_source);
+
+ nm_clear_g_signal_handler(priv->ipac6_data.ndisc, &priv->ipac6_data.ndisc_changed_id);
+ nm_clear_g_signal_handler(priv->ipac6_data.ndisc, &priv->ipac6_data.ndisc_timeout_id);
+
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_AC_6, NULL, FALSE);
+
+ if (priv->ipac6_data.ndisc) {
+ nm_ndisc_stop(priv->ipac6_data.ndisc);
+ g_clear_object(&priv->ipac6_data.ndisc);
}
+
+ _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_NONE);
}
/*****************************************************************************/
static void
-save_ip6_properties(NMDevice *self)
+_dev_sysctl_save_ip6_properties(NMDevice *self)
{
static const char *const ip6_properties_to_save[] = {
"accept_ra",
@@ -11149,61 +11036,80 @@ save_ip6_properties(NMDevice *self)
}
static void
-restore_ip6_properties(NMDevice *self)
+_dev_sysctl_restore_ip6_properties(NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
GHashTableIter iter;
- gpointer key, value;
+ gpointer key;
+ gpointer 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;
+ while (g_hash_table_iter_next(&iter, &key, &value))
nm_device_sysctl_ip_conf_set(self, AF_INET6, key, value);
- }
}
static void
-set_disable_ipv6(NMDevice *self, const char *value)
+_dev_sysctl_set_disable_ipv6(NMDevice *self, gboolean do_disable)
{
- /* 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);
+ nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", do_disable ? "1" : "0");
}
+/*****************************************************************************/
+
static void
-set_nm_ipv6ll(NMDevice *self, gboolean enable)
+_dev_addrgenmode6_set(NMDevice *self, guint8 addr_gen_mode)
{
- 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);
+ const NMPlatformLink *plink;
+ int r;
+ int cur_addr_gen_mode;
+ char sbuf[100];
- priv->ipv6ll_handle = enable;
- if (ifindex > 0) {
- int r;
-
- _LOGD(LOGD_IP6, "will %s userland IPv6LL", enable ? "enable" : "disable");
- r = nm_platform_link_set_inet6_addr_gen_mode(nm_device_get_platform(self),
- ifindex,
- enable ? NM_IN6_ADDR_GEN_MODE_NONE
- : NM_IN6_ADDR_GEN_MODE_EUI64);
- 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)",
- enable ? "enable" : "disable",
- nm_strerror(r));
- }
+ if (ifindex <= 0)
+ return;
- if (enable) {
- gs_free char *value = NULL;
+ plink = nm_platform_link_get(nm_device_get_platform(self), ifindex);
+ if (!plink)
+ return;
- /* 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");
+ cur_addr_gen_mode = _nm_platform_link_get_inet6_addr_gen_mode(plink);
+ nm_assert(cur_addr_gen_mode >= 0 && cur_addr_gen_mode <= 255);
+
+ if (!priv->addrgenmode6_data.previous_mode_has) {
+ priv->addrgenmode6_data.previous_mode_has = TRUE;
+ priv->addrgenmode6_data.previous_mode_val = cur_addr_gen_mode;
+ nm_assert(priv->addrgenmode6_data.previous_mode_val == cur_addr_gen_mode);
+ }
+
+ _LOGD_ip(AF_INET6,
+ "addrgenmode6: set %s%s",
+ nm_platform_link_inet6_addrgenmode2str(addr_gen_mode, sbuf, sizeof(sbuf)),
+ (cur_addr_gen_mode == addr_gen_mode) ? " (already set)" : "");
+
+ if (cur_addr_gen_mode == addr_gen_mode)
+ return;
+
+ r = nm_platform_link_set_inet6_addr_gen_mode(nm_device_get_platform(self),
+ ifindex,
+ addr_gen_mode);
+ if (r < 0) {
+ _NMLOG_ip(NM_IN_SET(r, -NME_PL_NOT_FOUND, -NME_PL_OPNOTSUPP) ? LOGL_DEBUG : LOGL_WARN,
+ AF_INET6,
+ "addrgenmode6: failed to set %s: (%s)",
+ nm_platform_link_inet6_addrgenmode2str(addr_gen_mode, sbuf, sizeof(sbuf)),
+ nm_strerror(r));
+ }
- /* Ensure IPv6 is enabled */
+ if (addr_gen_mode == NM_IN6_ADDR_GEN_MODE_NONE) {
+ gs_free char *value = NULL;
+
+ /* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */
+ _LOGD_ip(AF_INET6,
+ "addrgenmode6: toggle disable_ipv6 sysctl after disabling addr-gen-mode");
+ 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");
nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "0");
}
}
@@ -11229,30 +11135,44 @@ ip_requires_slaves(NMDevice *self, int addr_family)
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)
+static void
+activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family)
{
const int IS_IPv4 = NM_IS_IPv4(addr_family);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self);
NMConnection * connection;
- NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
+ int ip_ifindex;
const char * method;
- nm_assert_addr_family(addr_family);
+ if (nm_device_sys_iface_state_is_external(self))
+ goto out;
connection = nm_device_get_applied_connection(self);
+ g_return_if_fail(connection);
- g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE);
+ ip_ifindex = nm_device_get_ip_ifindex(self);
+
+ if (ip_ifindex >= 0 && !nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex)
+ && !nm_device_sys_iface_state_is_external(self)) {
+ nm_platform_link_change_flags(nm_device_get_platform(self), ip_ifindex, IFF_UP, TRUE);
+ 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 (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 (!priv->ip_data_x[IS_IPv4].wait_for_carrier) {
+ _LOGT_ip(addr_family, "waiting until carrier is on");
+ priv->ip_data_x[IS_IPv4].wait_for_carrier = TRUE;
+ }
+ goto out;
+ }
+ if (priv->ip_data_x[IS_IPv4].wait_for_carrier) {
+ _LOGT_ip(addr_family, "waiting until carrier completed");
+ priv->ip_data_x[IS_IPv4].wait_for_carrier = FALSE;
}
if (nm_device_is_master(self) && ip_requires_slaves(self, addr_family)) {
@@ -11260,93 +11180,46 @@ act_stage3_ip_config_start(NMDevice * self,
* 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 (!priv->ip_data_x[IS_IPv4].wait_for_ports) {
+ _LOGT_ip(addr_family, "waiting for ports");
+ priv->ip_data_x[IS_IPv4].wait_for_ports = TRUE;
+ }
+ goto out;
}
}
-
- if (!IS_IPv4)
- priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE;
+ if (priv->ip_data_x[IS_IPv4].wait_for_ports) {
+ _LOGT_ip(addr_family, "waiting until ports completed");
+ priv->ip_data_x[IS_IPv4].wait_for_ports = FALSE;
+ }
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);
+ _dev_ipmanual_start(self);
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_IP4_CONFIG_METHOD_AUTO))
+ _dev_ipdhcpx_start(self, AF_INET);
+ else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
+ _dev_ipll4_start(self);
+ else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED))
+ _dev_ipshared4_start(self);
+ else if (NM_IN_STRSET(method,
+ NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
+ NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
+ /* pass */
+ } else
+ nm_assert_not_reached();
+ }
+ if (!IS_IPv4) {
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->ip_data_x[IS_IPv4].is_disabled) {
+ priv->ip_data_x[IS_IPv4].is_disabled = TRUE;
+ nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1");
+ }
+ } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
+ if (!priv->ip_data_x[IS_IPv4].is_ignore) {
+ priv->ip_data_x[IS_IPv4].is_ignore = TRUE;
if (priv->master) {
/* If a device only has an IPv6 link-local address,
* we don't generate an assumed connection. Therefore,
@@ -11356,165 +11229,62 @@ act_stage3_ip_config_start(NMDevice * self,
* 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);
+ if (ip_ifindex > 0) {
+ nm_platform_ip_route_flush(nm_device_get_platform(self),
+ AF_INET6,
+ ip_ifindex);
+ nm_platform_ip_address_flush(nm_device_get_platform(self),
+ AF_INET6,
+ ip_ifindex);
}
} 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);
+ _dev_addrgenmode6_set(self, NM_IN6_ADDR_GEN_MODE_EUI64);
+ _dev_sysctl_set_disable_ipv6(self, TRUE);
+ _dev_sysctl_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 {
+ /* 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);
+
+ /* 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.
+ */
+ _dev_addrgenmode6_set(self, NM_IN6_ADDR_GEN_MODE_NONE);
+
+ /* Re-enable IPv6 on the interface */
+ nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", "0");
+ _dev_sysctl_set_disable_ipv6(self, FALSE);
+
+ if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL))
+ _dev_ipll6_start(self);
+ else if (NM_IN_STRSET(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO))
+ _dev_ipac6_start(self);
+ else if (NM_IN_STRSET(method, NM_SETTING_IP6_CONFIG_METHOD_SHARED))
+ _dev_ipshared6_start(self);
+ else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
+ priv->ipdhcp_data_6.v6.mode = NM_NDISC_DHCP_LEVEL_MANAGED;
+ _dev_ipdhcpx_start(self, AF_INET6);
+ } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+ /* pass */
} 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);
+ nm_assert_not_reached();
}
-
- return ret;
}
-}
-gboolean
-nm_device_activate_stage3_ip_start(NMDevice *self, int addr_family)
-{
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
- NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
- NMActStageReturn ret;
- NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE;
- gs_unref_object NMIPConfig *ip_config = NULL;
-
- g_assert(priv->ip_state_x[IS_IPv4] == NM_DEVICE_IP_STATE_WAIT);
+ if (klass->act_stage3_ip_config)
+ klass->act_stage3_ip_config(self, addr_family);
- if (nm_device_sys_iface_state_is_external(self)) {
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_DONE);
- check_ip_state(self, FALSE, TRUE);
- return TRUE;
- }
-
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_CONF);
-
- ret = NM_DEVICE_GET_CLASS(self)->act_stage3_ip_config_start(self,
- addr_family,
- (gpointer *) &ip_config,
- &failure_reason);
-
- switch (ret) {
- case NM_ACT_STAGE_RETURN_SUCCESS:
- if (!IS_IPv4) {
- /* Here we get a static IPv6 config, like for Shared where it's
- * autogenerated or from modems where it comes from ModemManager.
- */
- if (!ip_config)
- ip_config = nm_device_ip_config_new(self, addr_family);
- nm_assert(!applied_config_get_current(&priv->ac_ip6_config));
- applied_config_init(&priv->ac_ip6_config, ip_config);
- ip_config = NULL;
- }
- nm_device_activate_schedule_ip_config_result(self, addr_family, ip_config);
- break;
- case NM_ACT_STAGE_RETURN_IP_DONE:
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_DONE);
- check_ip_state(self, FALSE, TRUE);
- break;
- case NM_ACT_STAGE_RETURN_FAILURE:
- nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason);
- return FALSE;
- case NM_ACT_STAGE_RETURN_IP_FAIL:
- /* Activation not wanted */
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_FAIL);
- break;
- case NM_ACT_STAGE_RETURN_IP_WAIT:
- /* Wait for something to try IP config again */
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_WAIT);
- break;
- default:
- g_assert(ret == NM_ACT_STAGE_RETURN_POSTPONE);
- }
-
- return TRUE;
+out:
+ _dev_ip_state_check_async(self, addr_family);
}
static void
@@ -11541,12 +11311,12 @@ fw_change_zone_cb(NMFirewalldManager * firewalld_manager,
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);
+ nm_device_activate_schedule_stage3_ip_config(self, TRUE);
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)
+ if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY
+ || priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY)
nm_device_start_ip_check(self);
break;
case FIREWALL_STATE_INITIALIZED:
@@ -11598,24 +11368,48 @@ fw_change_zone(NMDevice *self)
self);
}
-/*
- * activate_stage3_ip_config_start
- *
- * Begin automatic/manual IP configuration
- *
- */
static void
-activate_stage3_ip_config_start(NMDevice *self)
+activate_stage3_ip_config(NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
int ifindex;
+ /* stage3 is different from stage1+2.
+ *
+ * What is true in all cases is that when we start a stage, we call the corresponding
+ * nm_device_activate_schedule_stage*() function. But usually the stage cannot complete
+ * right away but needs to wait for some things to happen. So the activate_stage*() function
+ * returns, and will be later proceeded by calling *the same* stage again. That means,
+ * activate_stage*() must be re-entrant and be called repeatedly until we can proceed
+ * to the next stage. Only when the stage is completed, we schedule the next one.
+ *
+ * stage3 is different. It does IP configuration and as such (the stage handling itself)
+ * cannot fail. If a failure happens (for example for DHCP), we remember that (in priv->ipdhcp_data_x)
+ * and issue _dev_ip_state_check_async(). That one combines the DHCP state to determine the
+ * overall per-address-family state (priv->ip_data_x). Those states are then combined
+ * further into priv->combinedip_state, which then leads to nm_device_state_changed()
+ * (which for example can make the device fully ACTIVATED or FAILED).
+ *
+ * The difference between stage1+2 and stage3 is that IP configuration is running continuously
+ * while the device is active. As such the activate_stage3_ip_config() does not fail directly,
+ * unlike the other stages which can abort via NM_ACT_STAGE_RETURN_FAILURE. */
+
g_return_if_fail(priv->act_request.obj);
ifindex = nm_device_get_ip_ifindex(self);
+ if (priv->ip_data_4.do_reapply) {
+ _LOGD_ip(AF_INET, "reapply...");
+ _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_DECONFIGURE);
+ }
+ if (priv->ip_data_6.do_reapply) {
+ _LOGD_ip(AF_INET6, "reapply...");
+ _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_DECONFIGURE);
+ }
+
/* Add the interface to the specified firewall zone */
- if (priv->fw_state == FIREWALL_STATE_UNMANAGED) {
+ switch (priv->fw_state) {
+ case FIREWALL_STATE_UNMANAGED:
if (nm_device_sys_iface_state_is_external(self)) {
/* fake success */
priv->fw_state = FIREWALL_STATE_INITIALIZED;
@@ -11625,143 +11419,140 @@ activate_stage3_ip_config_start(NMDevice *self)
return;
}
/* no ifindex, nothing to do for now */
- } else if (priv->fw_state == FIREWALL_STATE_WAIT_STAGE_3) {
+ break;
+ case FIREWALL_STATE_WAIT_STAGE_3:
/* a firewall call for stage3 is pending. Return and wait. */
return;
+ default:
+ nm_assert(NM_IN_SET((FirewallState) priv->fw_state,
+ FIREWALL_STATE_INITIALIZED,
+ FIREWALL_STATE_WAIT_IP_CONFIG));
+ break;
}
-
nm_assert(ifindex <= 0 || priv->fw_state == FIREWALL_STATE_INITIALIZED);
- _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);
-
- 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 (!nm_device_sys_iface_state_is_external(self)
- && (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));
+ if (priv->state < NM_DEVICE_STATE_IP_CONFIG) {
+ _dev_ip_state_req_timeout_schedule(self, AF_INET);
+ _dev_ip_state_req_timeout_schedule(self, AF_INET6);
- if (nm_device_activate_ip4_state_in_wait(self)
- && !nm_device_activate_stage3_ip_start(self, AF_INET))
- return;
+ _active_connection_set_state_flags(self, NM_ACTIVATION_STATE_FLAG_LAYER2_READY);
- if (nm_device_activate_ip6_state_in_wait(self)
- && !nm_device_activate_stage3_ip_start(self, AF_INET6))
- return;
+ nm_device_state_changed(self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE);
- /* Proxy */
- nm_device_set_proxy_config(self, NULL);
+ /* Device should be up before we can do anything with it */
+ if (!nm_device_sys_iface_state_is_external(self) && ifindex > 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));
+ }
- check_ip_state(self, TRUE, TRUE);
+ activate_stage3_ip_config_for_addr_family(self, AF_INET);
+ activate_stage3_ip_config_for_addr_family(self, AF_INET6);
}
-/*
- * nm_device_activate_schedule_stage3_ip_config_start
- *
- * Schedule IP configuration start
- */
void
-nm_device_activate_schedule_stage3_ip_config_start(NMDevice *self)
+nm_device_activate_schedule_stage3_ip_config(NMDevice *self, gboolean do_sync)
{
- NMDevicePrivate *priv;
-
- g_return_if_fail(NM_IS_DEVICE(self));
-
- priv = NM_DEVICE_GET_PRIVATE(self);
-
- g_return_if_fail(priv->act_request.obj);
-
- activation_source_schedule(self, activate_stage3_ip_config_start, AF_INET);
+ activation_source_invoke_or_schedule(self, activate_stage3_ip_config, do_sync);
}
-static NMActStageReturn
-act_stage4_ip_config_timeout(NMDevice * self,
- int addr_family,
- NMDeviceStateReason *out_failure_reason)
+/*****************************************************************************/
+
+static void
+_dev_ipsharedx_set_state(NMDevice *self, int addr_family, NMDeviceIPState state)
{
- nm_assert_addr_family(addr_family);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int IS_IPv4 = NM_IS_IPv4(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 (priv->ipshared_data_x[IS_IPv4].state != state) {
+ _LOGD_ipshared(addr_family,
+ "set state %s (was %s)",
+ nm_device_ip_state_to_string(state),
+ nm_device_ip_state_to_string(priv->ipshared_data_x[IS_IPv4].state));
+ priv->ipshared_data_x[IS_IPv4].state = state;
}
-
- return NM_ACT_STAGE_RETURN_SUCCESS;
}
static void
-activate_stage4_ip_config_timeout_x(NMDevice *self, int addr_family)
+_dev_ipsharedx_cleanup(NMDevice *self, int addr_family)
{
- NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE;
- NMActStageReturn ret;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
- ret =
- NM_DEVICE_GET_CLASS(self)->act_stage4_ip_config_timeout(self, addr_family, &failure_reason);
+ if (IS_IPv4) {
+ if (priv->ipshared_data_4.v4.dnsmasq_manager) {
+ nm_clear_g_signal_handler(priv->ipshared_data_4.v4.dnsmasq_manager,
+ &priv->ipshared_data_4.v4.dnsmasq_state_id);
+ nm_dnsmasq_manager_stop(priv->ipshared_data_4.v4.dnsmasq_manager);
+ g_clear_object(&priv->ipshared_data_4.v4.dnsmasq_manager);
+ }
- if (ret == NM_ACT_STAGE_RETURN_POSTPONE)
- return;
+ if (priv->ipshared_data_4.v4.firewall_config) {
+ nm_firewall_config_apply(priv->ipshared_data_4.v4.firewall_config, FALSE);
+ nm_clear_pointer(&priv->ipshared_data_4.v4.firewall_config, nm_firewall_config_free);
+ }
- if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
- nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason);
- return;
+ nm_clear_pointer(&priv->ipshared_data_4.v4.shared_ip_handle, nm_netns_shared_ip_release);
}
- g_assert(ret == NM_ACT_STAGE_RETURN_SUCCESS);
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_FAIL);
- check_ip_state(self, FALSE, TRUE);
+ _dev_ipsharedx_set_state(self, addr_family, NM_DEVICE_IP_STATE_NONE);
}
-static void
-activate_stage4_ip_config_timeout_4(NMDevice *self)
-{
- activate_stage4_ip_config_timeout_x(self, AF_INET);
-}
+/*****************************************************************************/
-static void
-activate_stage4_ip_config_timeout_6(NMDevice *self)
+static const NML3ConfigData *
+_dev_ipshared4_new_l3cd(NMDevice *self, NMConnection *connection, NMPlatformIP4Address *out_addr4)
{
- activate_stage4_ip_config_timeout_x(self, AF_INET6);
-}
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
+ NMSettingIPConfig * s_ip4;
+ NMPlatformIP4Address address = {
+ .addr_source = NM_IP_CONFIG_SOURCE_SHARED,
+ };
-#define activate_stage4_ip_config_timeout_x_fcn(addr_family) \
- (NM_IS_IPv4(addr_family) ? activate_stage4_ip_config_timeout_4 \
- : activate_stage4_ip_config_timeout_6)
+ g_return_val_if_fail(self, NULL);
+ g_return_val_if_fail(connection, NULL);
-void
-nm_device_activate_schedule_ip_config_timeout(NMDevice *self, int addr_family)
-{
- NMDevicePrivate *priv;
+ 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;
- g_return_if_fail(NM_IS_DEVICE(self));
+ 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->ipshared_data_4.v4.shared_ip_handle, nm_netns_shared_ip_release);
+ } else {
+ if (!priv->ipshared_data_4.v4.shared_ip_handle)
+ priv->ipshared_data_4.v4.shared_ip_handle =
+ nm_netns_shared_ip_reserve(nm_device_get_netns(self));
+ nm_platform_ip4_address_set_addr(&address,
+ priv->ipshared_data_4.v4.shared_ip_handle->addr,
+ 24);
+ }
- priv = NM_DEVICE_GET_PRIVATE(self);
+ l3cd = nm_device_create_l3_config_data(self, NM_IP_CONFIG_SOURCE_SHARED);
+ nm_l3_config_data_add_address_4(l3cd, &address);
- g_return_if_fail(priv->act_request.obj);
+ NM_SET_OUT(out_addr4, address);
- activation_source_schedule(self,
- activate_stage4_ip_config_timeout_x_fcn(addr_family),
- addr_family);
+ return nm_l3_config_data_seal(g_steal_pointer(&l3cd));
}
static gboolean
-share_init(NMDevice *self, GError **error)
-{
- const char *const modules[] = {"ip_tables",
- "iptable_nat",
- "nf_nat_ftp",
- "nf_nat_irc",
- "nf_nat_sip",
- "nf_nat_tftp",
- "nf_nat_pptp",
- "nf_nat_h323"};
- guint i;
- int errsv;
+_dev_ipshared4_init(NMDevice *self)
+{
+ static const char *const modules[] = {"ip_tables",
+ "iptable_nat",
+ "nf_nat_ftp",
+ "nf_nat_irc",
+ "nf_nat_sip",
+ "nf_nat_tftp",
+ "nf_nat_pptp",
+ "nf_nat_h323"};
+ int errsv;
+ guint i;
if (nm_platform_sysctl_get_int32(nm_device_get_platform(self),
NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"),
@@ -11772,15 +11563,7 @@ share_init(NMDevice *self, GError **error)
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));
+ _LOGW_ipshared(AF_INET, "error enabling IPv4 forwarding: %s", nm_strerror_native(errsv));
return FALSE;
}
@@ -11793,10 +11576,9 @@ share_init(NMDevice *self, GError **error)
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));
+ _LOGD_ipshared(AF_INET,
+ "share: error enabling dynamic addresses: %s",
+ nm_strerror_native(errsv));
}
for (i = 0; i < G_N_ELEMENTS(modules); i++)
@@ -11805,48 +11587,59 @@ share_init(NMDevice *self, GError **error)
return TRUE;
}
-static gboolean
-start_sharing(NMDevice *self, NMIP4Config *config, GError **error)
+static void
+_dev_ipshared4_dnsmasq_state_changed_cb(NMDnsMasqManager *manager, guint status, gpointer user_data)
{
- NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
- NMActRequest * req;
- const NMPlatformIP4Address *ip4_addr = NULL;
- const char * ip_iface;
- GError * local = NULL;
- NMConnection * conn;
- NMSettingConnection * s_con;
- gboolean announce_android_metered;
- NMFirewallConfig * firewall_config;
+ NMDevice *self = NM_DEVICE(user_data);
- g_return_val_if_fail(config, FALSE);
+ if (status != NM_DNSMASQ_STATUS_DEAD)
+ return;
+
+ _dev_ipsharedx_set_state(self, AF_INET, NM_DEVICE_IP_STATE_FAILED);
+ _dev_ip_state_check_async(self, AF_INET);
+}
+
+static void
+_dev_ipshared4_start(NMDevice *self)
+{
+ nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL;
+ NMPlatformIP4Address ip4_addr;
+ NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self);
+ const char * ip_iface;
+ gs_free_error GError *error = NULL;
+ NMSettingConnection * s_con;
+ gboolean announce_android_metered;
+ NMConnection * applied;
+
+ if (priv->ipshared_data_4.state != NM_DEVICE_IP_STATE_NONE)
+ return;
+
+ nm_assert(!priv->ipshared_data_4.v4.firewall_config);
+ nm_assert(!priv->ipshared_data_4.v4.dnsmasq_manager);
+ nm_assert(priv->ipshared_data_4.v4.dnsmasq_state_id == 0);
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;
- }
+ g_return_if_fail(ip_iface);
- 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;
- }
+ applied = nm_device_get_applied_connection(self);
+ g_return_if_fail(applied);
- if (!share_init(self, error))
- return FALSE;
+ _dev_ipsharedx_set_state(self, AF_INET, NM_DEVICE_IP_STATE_PENDING);
- req = nm_device_get_act_request(self);
- g_return_val_if_fail(req, FALSE);
+ l3cd = _dev_ipshared4_new_l3cd(self, applied, &ip4_addr);
+ if (!l3cd) {
+ nm_assert_not_reached();
+ goto out_fail;
+ }
- firewall_config = nm_firewall_config_new(ip_iface, ip4_addr->address, ip4_addr->plen);
+ if (!_dev_ipshared4_init(self))
+ goto out_fail;
- nm_act_request_set_shared(req, firewall_config);
+ priv->ipshared_data_4.v4.firewall_config =
+ nm_firewall_config_new(ip_iface, ip4_addr.address, ip4_addr.plen);
+ nm_firewall_config_apply(priv->ipshared_data_4.v4.firewall_config, TRUE);
- conn = nm_act_request_get_applied_connection(req);
- s_con = nm_connection_get_setting_connection(conn);
+ s_con = nm_connection_get_setting_connection(applied);
switch (nm_setting_connection_get_metered(s_con)) {
case NM_METERED_YES:
@@ -11868,353 +11661,55 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error)
break;
}
- if (!nm_dnsmasq_manager_start(priv->dnsmasq_manager,
- config,
+ priv->ipshared_data_4.v4.dnsmasq_manager = nm_dnsmasq_manager_new(ip_iface);
+
+ if (!nm_dnsmasq_manager_start(priv->ipshared_data_4.v4.dnsmasq_manager,
+ l3cd,
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, NULL);
- return FALSE;
+ &error)) {
+ _LOGW_ipshared(AF_INET, "could not start dnsmasq: %s", error->message);
+ goto out_fail;
}
- 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;
-}
+ priv->ipshared_data_4.v4.dnsmasq_state_id =
+ g_signal_connect(priv->ipshared_data_4.v4.dnsmasq_manager,
+ NM_DNS_MASQ_MANAGER_STATE_CHANGED,
+ G_CALLBACK(_dev_ipshared4_dnsmasq_state_changed_cb),
+ self);
-static void
-arp_cleanup(NMDevice *self)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
+ _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, l3cd, FALSE);
+ _dev_ip_state_check_async(self, AF_INET);
+ return;
- nm_clear_pointer(&priv->acd.announcing, nm_acd_manager_free);
+out_fail:
+ _dev_ipsharedx_set_state(self, AF_INET, NM_DEVICE_IP_STATE_FAILED);
+ _dev_ip_state_check_async(self, AF_INET);
}
-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);
-}
+/*****************************************************************************/
static void
-activate_stage5_ip_config_result_x(NMDevice *self, int addr_family)
+_dev_ipshared6_start(NMDevice *self)
{
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
- 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);
-
- nm_clear_g_source_inst(&priv->ip_req_timeout_source_x[IS_IPv4]);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- /* 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);
+ _dev_ipac6_start(self);
- if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex)
- && !nm_device_sys_iface_state_is_external(self)) {
- nm_platform_link_change_flags(nm_device_get_platform(self), ip_ifindex, IFF_UP, TRUE);
- 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, addr_family, TRUE)) {
- _LOGD(LOGD_DEVICE | LOGD_IPX(IS_IPv4),
- "Activation: Stage 5 of 5 (IPv%c Commit) failed",
- nm_utils_addr_family_to_char(addr_family));
- nm_device_ip_method_failed(self, addr_family, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+ if (priv->ipshared_data_6.state != NM_DEVICE_IP_STATE_NONE)
return;
- }
-
- if (!IS_IPv4) {
- 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_DHCP_CHANGE_6,
- self,
- NULL,
- NULL,
- NULL,
- NULL);
- } else {
- /* still waiting for first dhcp6 lease. */
- return;
- }
- }
- }
-
- /* Start IPv4 sharing/IPv6 forwarding if we need it */
- method = nm_device_get_effective_ip_config_method(self, addr_family);
- if (IS_IPv4) {
- 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;
- }
- }
- } else {
- 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);
- return;
- }
- }
- }
-
- if (IS_IPv4) {
- 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_DHCP_CHANGE_4,
- self,
- NULL,
- NULL,
- NULL,
- NULL);
- }
- }
-
- if (!IS_IPv4) {
- /* 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);
- }
- }
- }
-
- if (IS_IPv4 && priv->carrier) {
- /* We send ARP announcements only when the link gets carrier,
- * otherwise the announcements would be lost. Furthermore, for
- * controllers having carrier implies that there is at least one
- * port and therefore the MAC address is the correct one.
- */
- nm_device_arp_announce(self);
- }
-
- if (IS_IPv4) {
- /* 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);
- }
-}
-
-static void
-activate_stage5_ip_config_result_4(NMDevice *self)
-{
- activate_stage5_ip_config_result_x(self, AF_INET);
-}
-
-static void
-activate_stage5_ip_config_result_6(NMDevice *self)
-{
- activate_stage5_ip_config_result_x(self, AF_INET6);
-}
-
-#define activate_stage5_ip_config_result_x_fcn(addr_family) \
- (NM_IS_IPv4(addr_family) ? activate_stage5_ip_config_result_4 \
- : activate_stage5_ip_config_result_6)
-
-void
-nm_device_activate_schedule_ip_config_result(NMDevice *self, int addr_family, NMIPConfig *config)
-{
- NMDevicePrivate *priv;
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
-
- g_return_if_fail(NM_IS_DEVICE(self));
- g_return_if_fail(!config || (IS_IPv4 && nm_ip_config_get_addr_family(config) == AF_INET));
-
- 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);
- }
-
- activation_source_schedule(self,
- activate_stage5_ip_config_result_x_fcn(addr_family),
- addr_family);
-}
-
-NMDeviceIPState
-nm_device_activate_get_ip_state(NMDevice *self, int addr_family)
-{
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
-
- 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];
-}
-
-static void
-dad6_add_pending_address(NMDevice * self,
- NMPlatform * platform,
- int ifindex,
- const struct in6_addr *address,
- NMIP6Config ** dad6_config)
-{
- 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));
-
- if (!*dad6_config)
- *dad6_config = nm_device_ip6_config_new(self);
-
- nm_ip6_config_add_address(*dad6_config, pl_addr);
- }
-}
-
-/*
- * Returns a NMIP6Config containing NM-configured addresses which
- * 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);
- }
+ if (!nm_platform_sysctl_set(
+ nm_device_get_platform(self),
+ NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv6/conf/all/forwarding"),
+ "1")) {
+ _LOGW_ipshared(AF_INET6, "failure to enable ipv6 forwarding");
+ _dev_ipsharedx_set_state(self, AF_INET6, NM_DEVICE_IP_STATE_FAILED);
+ _dev_ip_state_check_async(self, AF_INET6);
+ return;
}
- return dad6_config;
+ _dev_ipsharedx_set_state(self, AF_INET6, NM_DEVICE_IP_STATE_READY);
+ _dev_ip_state_check_async(self, AF_INET6);
}
/*****************************************************************************/
@@ -12255,21 +11750,6 @@ act_request_set(NMDevice *self, NMActRequest *act_request)
}
}
-static void
-dnsmasq_cleanup(NMDevice *self)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
-
- if (!priv->dnsmasq_manager)
- return;
-
- 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)
{
@@ -12356,32 +11836,23 @@ delete_on_deactivate_check_and_schedule(NMDevice *self)
static void
_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_NONE);
+ _dev_ipsharedx_cleanup(self, addr_family);
- 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));
- }
+ _dev_ipdev_cleanup(self, 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);
- }
+ _dev_ipdhcpx_cleanup(self, addr_family, TRUE, FALSE);
+
+ if (!IS_IPv4)
+ _dev_ipac6_cleanup(self);
+
+ _dev_ipllx_cleanup(self, addr_family);
+
+ _dev_ipmanual_cleanup(self);
+
+ _dev_ip_state_cleanup(self, AF_UNSPEC);
+ _dev_ip_state_cleanup(self, addr_family);
}
gboolean
@@ -12452,127 +11923,6 @@ _nm_device_hash_check_invalid_keys(GHashTable * hash,
return FALSE;
}
-void
-nm_device_reactivate_ip_config(NMDevice * self,
- int addr_family,
- NMSettingIPConfig *s_ip_old,
- NMSettingIPConfig *s_ip_new)
-{
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
- NMDevicePrivate *priv;
- const char * method_old;
- const char * method_new;
-
- g_return_if_fail(NM_IS_DEVICE(self));
-
- priv = NM_DEVICE_GET_PRIVATE(self);
-
- if (priv->ip_state_x[IS_IPv4] == NM_DEVICE_IP_STATE_NONE)
- return;
-
- g_clear_object(&priv->con_ip_config_x[IS_IPv4]);
- g_clear_object(&priv->ext_ip_config_x[IS_IPv4]);
- if (IS_IPv4) {
- g_clear_object(&priv->dev_ip_config_4.current);
- } else {
- g_clear_object(&priv->ac_ip6_config.current);
- g_clear_object(&priv->dhcp6.ip6_config.current);
- }
- g_clear_object(&priv->dev2_ip_config_x[IS_IPv4].current);
-
- if (!IS_IPv4) {
- if (priv->ipv6ll_handle && !IN6_IS_ADDR_UNSPECIFIED(&priv->ipv6ll_addr))
- priv->ipv6ll_has = TRUE;
- }
-
- priv->con_ip_config_x[IS_IPv4] = nm_device_ip_config_new(self, addr_family);
-
- if (IS_IPv4) {
- nm_ip4_config_merge_setting(priv->con_ip_config_4,
- s_ip_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));
- } else {
- nm_ip6_config_merge_setting(priv->con_ip_config_6,
- s_ip_new,
- nm_device_get_route_table(self, AF_INET6),
- nm_device_get_route_metric(self, AF_INET6));
- }
-
- method_old = (s_ip_old ? nm_setting_ip_config_get_method(s_ip_old) : NULL)
- ?: (IS_IPv4 ? NM_SETTING_IP4_CONFIG_METHOD_DISABLED
- : NM_SETTING_IP6_CONFIG_METHOD_IGNORE);
- method_new = (s_ip_new ? nm_setting_ip_config_get_method(s_ip_new) : NULL)
- ?: (IS_IPv4 ? NM_SETTING_IP4_CONFIG_METHOD_DISABLED
- : NM_SETTING_IP6_CONFIG_METHOD_IGNORE);
-
- if (!nm_streq0(method_old, method_new)) {
- _cleanup_ip_pre(self, addr_family, CLEANUP_TYPE_DECONFIGURE);
- _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_WAIT);
- if (!nm_device_activate_stage3_ip_start(self, addr_family)) {
- _LOGW(LOGD_IP4,
- "Failed to apply IPv%c configuration",
- nm_utils_addr_family_to_char(addr_family));
- }
- return;
- }
-
- if (s_ip_old && s_ip_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_ip_old);
- metric_new = nm_setting_ip_config_get_route_metric(s_ip_new);
-
- if (metric_old != metric_new) {
- if (IS_IPv4) {
- 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));
- }
- } else {
- 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, addr_family, TRUE)) {
- _LOGW(LOGD_IPX(IS_IPv4),
- "Failed to reapply IPv%c configuration",
- nm_utils_addr_family_to_char(addr_family));
- }
-}
-
static void
_pacrunner_manager_add(NMDevice *self)
{
@@ -12581,10 +11931,8 @@ _pacrunner_manager_add(NMDevice *self)
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);
+ nm_device_get_l3cd(self, TRUE));
}
static void
@@ -12592,12 +11940,12 @@ reactivate_proxy_config(NMDevice *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)
+ _pacrunner_manager_add(self);
}
+/*****************************************************************************/
+
static gboolean
can_reapply_change(NMDevice * self,
const char *setting_name,
@@ -12692,9 +12040,8 @@ check_and_reapply_connection(NMDevice * 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;
+ NMConnection * con_old;
+ NMConnection * con_new;
GHashTableIter iter;
if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) {
@@ -12743,11 +12090,11 @@ check_and_reapply_connection(NMDevice * self,
&& 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");
+ 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;
}
@@ -12810,11 +12157,9 @@ check_and_reapply_connection(NMDevice * self,
} 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;
+ priv->l3config_merge_flags_has = FALSE;
/**************************************************************************
* Reapply changes
@@ -12831,20 +12176,21 @@ check_and_reapply_connection(NMDevice * self,
lldp_setup(self, NM_TERNARY_DEFAULT);
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_ip_config(self, AF_INET, s_ip4_old, s_ip4_new);
- nm_device_reactivate_ip_config(self, AF_INET6, s_ip6_old, s_ip6_new);
+ if (nm_g_hash_table_lookup(diffs, NM_SETTING_IP4_CONFIG_SETTING_NAME))
+ priv->ip_data_4.do_reapply = TRUE;
+ if (nm_g_hash_table_lookup(diffs, NM_SETTING_IP6_CONFIG_SETTING_NAME))
+ priv->ip_data_6.do_reapply = TRUE;
+
+ nm_device_activate_schedule_stage3_ip_config(self, FALSE);
_routing_rules_sync(self, NM_TERNARY_TRUE);
reactivate_proxy_config(self);
+
+ nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE);
}
if (priv->state >= NM_DEVICE_STATE_IP_CHECK)
@@ -13074,96 +12420,6 @@ impl_device_get_applied_connection(NMDBusObject * obj,
/*****************************************************************************/
-typedef struct {
- gint64 timestamp_ms;
- bool dirty;
-} IP6RoutesTemporaryNotAvailableData;
-
-static gboolean
-_rt6_temporary_not_available_timeout(gpointer user_data)
-{
- 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);
-
- 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;
-}
-
-/*****************************************************************************/
-
static void
disconnect_cb(NMDevice * self,
GDBusMethodInvocation *context,
@@ -13543,324 +12799,44 @@ nm_device_is_activating(NMDevice *self)
* 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)
-{
- g_return_val_if_fail(NM_IS_DEVICE(self), NULL);
-
- return NM_DEVICE_GET_PRIVATE(self)->proxy_config;
-}
-
-static void
-nm_device_set_proxy_config(NMDevice *self, const char *pac_url)
-{
- NMDevicePrivate *priv;
- NMConnection * connection;
- NMSettingProxy * s_proxy = NULL;
-
- g_return_if_fail(NM_IS_DEVICE(self));
-
- priv = NM_DEVICE_GET_PRIVATE(self);
-
- 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);
-
- 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);
+ return !!priv->activation_idle_source;
}
-/* IP Configuration stuff */
NMDhcpConfig *
nm_device_get_dhcp_config(NMDevice *self, int addr_family)
{
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
-
g_return_val_if_fail(NM_IS_DEVICE(self), NULL);
- nm_assert_addr_family(addr_family);
-
- return NM_DEVICE_GET_PRIVATE(self)->dhcp_data_x[IS_IPv4].config;
+ return NM_DEVICE_GET_PRIVATE(self)->ipdhcp_data_x[NM_IS_IPv4(addr_family)].config;
}
-NMIP4Config *
-nm_device_get_ip4_config(NMDevice *self)
+NML3Cfg *
+nm_device_get_l3cfg(NMDevice *self)
{
g_return_val_if_fail(NM_IS_DEVICE(self), NULL);
- 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 int IS_IPv4 = NM_IS_IPv4(addr_family);
- NMIPConfig * old_config;
- gboolean has_changes = FALSE;
- gboolean success = TRUE;
- NMSettingsConnection * settings_connection;
- NMIPRouteTableSyncMode route_table_sync_mode;
-
- 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);
-
- if (commit && new_config)
- route_table_sync_mode = _get_route_table_sync_mode_stateful(self, addr_family);
- else
- route_table_sync_mode = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE;
-
- _LOGD(LOGD_IPX(IS_IPv4),
- "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT
- ", route-table-sync-mode=%d)",
- nm_utils_addr_family_to_char(addr_family),
- commit,
- NM_HASH_OBFUSCATE_PTR(new_config),
- (int) route_table_sync_mode);
-
- /* 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),
- route_table_sync_mode);
- 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),
- route_table_sync_mode,
- &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_IPX(IS_IPv4),
- "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_IPX(IS_IPv4),
- "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_IPX(IS_IPv4),
- "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_UPDATE_NON_SECRET,
- "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;
+ return NM_DEVICE_GET_PRIVATE(self)->l3cfg;
}
-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;
-}
-
-void
-nm_device_replace_vpn4_config(NMDevice *self, NMIP4Config *old, NMIP4Config *config)
-{
- 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));
-
- 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");
-}
-
-void
-nm_device_set_dev2_ip_config(NMDevice *self, int addr_family, NMIPConfig *config)
+const NML3ConfigData *
+nm_device_get_l3cd(NMDevice *self, gboolean get_commited)
{
NMDevicePrivate *priv;
- const int IS_IPv4 = NM_IS_IPv4(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);
+ g_return_val_if_fail(NM_IS_DEVICE(self), NULL);
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));
- }
-}
-
-void
-nm_device_replace_vpn6_config(NMDevice *self, NMIP6Config *old, NMIP6Config *config)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- NMDeviceState state;
-
- nm_assert(!old || NM_IS_IP6_CONFIG(old));
- nm_assert(!old || nm_ip6_config_get_ifindex(old) > 0);
- nm_assert(!old || nm_device_get_ip_ifindex(self) == 0
- || nm_device_get_ip_ifindex(self) == nm_ip6_config_get_ifindex(old));
- nm_assert(!config || NM_IS_IP6_CONFIG(config));
- nm_assert(!config || nm_ip6_config_get_ifindex(config) > 0);
- nm_assert(!config || nm_device_get_ip_ifindex(self) == nm_ip6_config_get_ifindex(config));
-
- if (!_replace_vpn_config_in_list(&priv->vpn_configs_6, (GObject *) old, (GObject *) config))
- return;
-
- state = nm_device_get_state(self);
- if (state >= NM_DEVICE_STATE_IP_CONFIG && state <= NM_DEVICE_STATE_ACTIVATED) {
- 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)
-{
- g_return_val_if_fail(NM_IS_DEVICE(self), NULL);
+ if (!priv->l3cfg)
+ return NULL;
- return NM_DEVICE_GET_PRIVATE(self)->ip_config_6;
+ return nm_l3cfg_get_combined_l3cd(priv->l3cfg, get_commited);
}
/*****************************************************************************/
static gboolean
-dispatcher_cleanup(NMDevice *self)
+_dispatcher_cleanup(NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
@@ -13874,7 +12850,7 @@ dispatcher_cleanup(NMDevice *self)
}
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);
@@ -13894,7 +12870,7 @@ ip_check_pre_up(NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
- if (dispatcher_cleanup(self))
+ if (_dispatcher_cleanup(self))
nm_assert_not_reached();
priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES;
@@ -13902,11 +12878,11 @@ ip_check_pre_up(NMDevice *self)
if (!nm_dispatcher_call_device(NM_DISPATCHER_ACTION_PRE_UP,
self,
NULL,
- dispatcher_complete_proceed_state,
+ _dispatcher_complete_proceed_state,
self,
&priv->dispatcher.call_id)) {
/* Just proceed on errors */
- dispatcher_complete_proceed_state(0, self);
+ _dispatcher_complete_proceed_state(0, self);
}
}
@@ -14086,8 +13062,8 @@ nm_device_start_ip_check(NMDevice *self)
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);
+ g_return_if_fail(priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY
+ || priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY);
connection = nm_device_get_applied_connection(self);
g_assert(connection);
@@ -14098,17 +13074,21 @@ nm_device_start_ip_check(NMDevice *self)
buf[0] = '\0';
if (timeout) {
- const NMPObject *gw;
+ const NMPObject * gw;
+ const NML3ConfigData *l3cd;
- 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);
+ l3cd = priv->l3cfg ? nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE) : NULL;
+ if (!l3cd) {
+ /* pass */
+ } else if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY) {
+ gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET);
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);
+ } else if (priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY) {
+ gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET6);
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);
@@ -14248,15 +13228,7 @@ nm_device_bring_up(NMDevice *self, gboolean block, gboolean *no_firmware)
/* 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");
- }
+ _dev_l3_cfg_commit(self, TRUE);
return TRUE;
}
@@ -14319,381 +13291,6 @@ nm_device_get_firmware_missing(NMDevice *self)
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);
- }
-}
-
-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 (NM_IS_IPv4(addr_family)) {
- 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(!NM_IS_IPv4(addr_family));
-
- 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)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
-
- nm_assert_addr_family(addr_family);
-
- if (NM_IS_IPv4(addr_family))
- 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 (NM_IS_IPv4(addr_family)) {
- 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)
-{
- 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);
-}
-
-static gboolean
-queued_ip_config_change(NMDevice *self, int addr_family)
-{
- NMDevicePrivate *priv;
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
-
- 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_fcn(addr_family))
- 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)
-{
- return queued_ip_config_change(user_data, AF_INET);
-}
-
-static gboolean
-queued_ip6_config_change(gpointer user_data)
-{
- 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();
- }
-}
-
/*****************************************************************************/
NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str,
@@ -14946,12 +13543,6 @@ _set_unmanaged_flags(NMDevice * self,
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.len == 0) {
do_notify_has_pending_actions = TRUE;
had_pending_actions = nm_device_has_pending_action(self);
@@ -15303,9 +13894,13 @@ nm_device_update_metered(NMDevice *self)
/* 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;
+ if (priv->l3cfg) {
+ const NML3ConfigData *l3cd;
+
+ l3cd = nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE);
+ if (l3cd && nm_l3_config_data_get_metered(l3cd))
+ value = NM_METERED_GUESS_YES;
+ }
}
/* Otherwise, look at connection type. For Bluetooth, we look at the type of
@@ -15876,12 +14471,11 @@ _cancel_activation(NMDevice *self)
priv->fw_state = FIREWALL_STATE_INITIALIZED;
}
- dispatcher_cleanup(self);
+ _dispatcher_cleanup(self);
ip_check_gw_ping_cleanup(self);
/* Break the activation chain */
- activation_source_clear(self, AF_INET);
- activation_source_clear(self, AF_INET6);
+ activation_source_clear(self);
}
static void
@@ -15911,17 +14505,13 @@ _cleanup_generic_pre(NMDevice *self, CleanupType cleanup_type)
queued_state_clear(self);
- nm_clear_pointer(&priv->shared_ip_handle, nm_netns_shared_ip_release);
-
for (i = 0; i < 2; i++)
nm_clear_pointer(&priv->hostname_resolver_x[i], _hostname_resolver_free);
_cleanup_ip_pre(self, AF_INET, cleanup_type);
_cleanup_ip_pre(self, AF_INET6, cleanup_type);
- priv->ip_config_started = FALSE;
- nm_clear_g_source_inst(&priv->ip_req_timeout_source_4);
- nm_clear_g_source_inst(&priv->ip_req_timeout_source_6);
+ _dev_ip_state_req_timeout_cancel(self, AF_UNSPEC);
}
static void
@@ -15929,11 +14519,9 @@ _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->l3config_merge_flags_has = FALSE;
priv->v4_route_table_all_sync_before = FALSE;
priv->v6_route_table_all_sync_before = FALSE;
@@ -15941,42 +14529,9 @@ _cleanup_generic_post(NMDevice *self, CleanupType cleanup_type)
priv->default_route_metric_penalty_ip4_has = FALSE;
priv->default_route_metric_penalty_ip6_has = FALSE;
- priv->linklocal6_dad_counter = 0;
-
priv->mtu_force_set_done = FALSE;
- /* 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);
+ priv->needs_ip6_subnet = FALSE;
if (priv->act_request.obj) {
nm_active_connection_set_default(NM_ACTIVE_CONNECTION(priv->act_request.obj),
@@ -15998,6 +14553,9 @@ _cleanup_generic_post(NMDevice *self, CleanupType cleanup_type)
* or ATM device).
*/
_set_ip_ifindex(self, 0, NULL);
+
+ nm_clear_g_source_inst(&priv->ip_data_4.check_async_source);
+ nm_clear_g_source_inst(&priv->ip_data_6.check_async_source);
}
/*
@@ -16029,7 +14587,7 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu
/* Turn off kernel IPv6 */
if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
- set_disable_ipv6(self, "1");
+ _dev_sysctl_set_disable_ipv6(self, TRUE);
nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", "0");
}
@@ -16146,18 +14704,19 @@ deactivate_reset_hw_addr(NMDevice *self)
static char *
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 NMPObject *obj;
- if (!priv->ip_config_4)
+ if (!priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_4].d)
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;
+ obj = nm_l3_config_data_get_first_obj(priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_4].d,
+ NMP_OBJECT_TYPE_IP4_ADDRESS,
+ NULL);
+ if (!obj)
+ return NULL;
+
+ return nm_utils_inet4_ntop_dup(NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address);
}
void
@@ -16169,7 +14728,6 @@ nm_device_spawn_iface_helper(NMDevice *self)
GError * error = NULL;
const char * method;
GPtrArray * argv;
- gs_free char * dhcp4_address = NULL;
char * logging_backend;
NMUtilsStableType stable_type;
const char * stable_id;
@@ -16214,10 +14772,9 @@ nm_device_spawn_iface_helper(NMDevice *self)
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)) {
+ char * dhcp4_address;
NMSettingIPConfig *s_ip4;
s_ip4 = nm_connection_get_setting_ip4_config(connection);
@@ -16226,34 +14783,36 @@ nm_device_spawn_iface_helper(NMDevice *self)
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));
+ dhcp4_address = find_dhcp4_address(self);
+ if (dhcp4_address) {
+ g_ptr_array_add(argv, g_strdup("--dhcp4"));
+ g_ptr_array_add(argv, 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;
+ if (priv->ipdhcp_data_4.client) {
+ const NMDhcpClientConfig *config;
+
+ config = nm_dhcp_client_get_config(priv->ipdhcp_data_4.client);
- client_id = nm_dhcp_client_get_client_id(priv->dhcp_data_4.client);
- if (client_id) {
+ if (config->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),
+ nm_utils_bin2hexstr_full(g_bytes_get_data(config->client_id, NULL),
+ g_bytes_get_size(config->client_id),
':',
FALSE,
NULL));
}
- hostname = nm_dhcp_client_get_hostname(priv->dhcp_data_4.client);
- if (hostname) {
- if (NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(priv->dhcp_data_4.client),
- NM_DHCP_CLIENT_FLAGS_USE_FQDN))
+ if (config->hostname) {
+ if (config->use_fqdn)
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));
+ g_ptr_array_add(argv, g_strdup(config->hostname));
}
}
@@ -16277,7 +14836,7 @@ nm_device_spawn_iface_helper(NMDevice *self)
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));
+ g_ptr_array_add(argv, g_strdup_printf("%d", (int) _prop_get_ipv6_ip6_privacy(self)));
if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) {
g_ptr_array_add(argv, g_strdup("--iid"));
@@ -16328,28 +14887,11 @@ nm_device_spawn_iface_helper(NMDevice *self)
/*****************************************************************************/
-static gboolean
-ip_config_valid(NMDeviceState state)
-{
- 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(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)
{
- set_nm_ipv6ll(self, TRUE);
- set_disable_ipv6(self, "1");
+ _dev_addrgenmode6_set(self, NM_IN6_ADDR_GEN_MODE_NONE);
+ _dev_sysctl_set_disable_ipv6(self, TRUE);
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");
@@ -16483,9 +15025,9 @@ deactivate_dispatcher_complete(NMDispatcherCallId *call_id, gpointer user_data)
static void
_set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting)
{
- NMDevicePrivate *priv;
- NMDeviceState old_state;
- gs_unref_object NMActRequest *req = NULL;
+ gs_unref_object NMActRequest *req = NULL;
+ NMDevicePrivate * priv;
+ NMDeviceState old_state;
gboolean no_firmware = FALSE;
NMSettingsConnection * sett_conn;
NMSettingSriov * s_sriov;
@@ -16495,8 +15037,7 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
priv = NM_DEVICE_GET_PRIVATE(self);
- /* Track re-entry */
- g_warn_if_fail(priv->in_state_changed == FALSE);
+ g_return_if_fail(priv->in_state_changed == 0);
old_state = priv->state;
@@ -16533,14 +15074,14 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
* 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->in_state_changed++;
priv->state = state;
priv->state_reason = reason;
queued_state_clear(self);
- dispatcher_cleanup(self);
+ _dispatcher_cleanup(self);
nm_clear_g_cancellable(&priv->deactivating_cancellable);
@@ -16597,15 +15138,15 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
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);
+ _dev_addrgenmode6_set(self, NM_IN6_ADDR_GEN_MODE_EUI64);
+ _dev_sysctl_restore_ip6_properties(self);
}
}
nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL);
break;
case NM_DEVICE_STATE_UNAVAILABLE:
if (old_state == NM_DEVICE_STATE_UNMANAGED) {
- save_ip6_properties(self);
+ _dev_sysctl_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);
@@ -16634,7 +15175,7 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
/* Ensure devices that previously assumed a connection now have
* userspace IPv6LL enabled.
*/
- set_nm_ipv6ll(self, TRUE);
+ _dev_addrgenmode6_set(self, NM_IN6_ADDR_GEN_MODE_NONE);
nm_device_cleanup(self, reason, CLEANUP_TYPE_DECONFIGURE);
} else if (old_state < NM_DEVICE_STATE_DISCONNECTED) {
@@ -16747,9 +15288,7 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
_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);
+ _pacrunner_manager_add(self);
break;
case NM_DEVICE_STATE_FAILED:
/* Usually upon failure the activation chain is interrupted in
@@ -16809,11 +15348,6 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
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:
@@ -16836,18 +15370,13 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
}
}
- /* 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;
+ priv->in_state_changed--;
+
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))
@@ -17869,15 +16398,16 @@ nm_device_clear_dns_lookup_data(NMDevice *self)
const char *
nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean *out_wait)
{
- NMDevicePrivate * priv;
const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ NMDevicePrivate * priv;
HostnameResolver *resolver;
- NMIPConfig * ip_config;
const char * method;
+ int ifindex;
gboolean address_changed = FALSE;
gs_unref_object GInetAddress *new_address = NULL;
g_return_val_if_fail(NM_IS_DEVICE(self), NULL);
+
priv = NM_DEVICE_GET_PRIVATE(self);
/* If the device is not supposed to have addresses,
@@ -17917,39 +16447,29 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean
/* Determine the most suitable address of the interface
* and whether it changed from the previous lookup */
- ip_config = priv->ip_config_x[IS_IPv4];
- if (ip_config) {
- const NMPlatformIPAddress *addr = NULL;
-
- if (IS_IPv4) {
- addr = nm_ip_config_get_first_address(ip_config);
- } else {
- /* For IPv6 prefer, in order:
- * - !link-local, !deprecated
- * - !link-local, deprecated
- * - link-local
- */
- addr = nm_ip_config_find_first_address(ip_config,
- NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL
- | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL);
- if (!addr) {
- addr = nm_ip_config_find_first_address(
- ip_config,
- NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL
- | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED);
- }
- if (!addr) {
- addr = nm_ip_config_find_first_address(ip_config,
- NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL
- | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY);
+ ifindex = nm_device_get_ip_ifindex(self);
+ if (ifindex > 0) {
+ NMPLookup lookup;
+ const NMDedupMultiHeadEntry *head_entry;
+ const NMDedupMultiEntry * iter;
+
+ /* FIXME(l3cfg): now we lookup the address from platform. Should we instead look
+ * it up from NML3Cfg? That is, take an address that we want to configure as
+ * opposed to an address that is configured? */
+ head_entry = nm_platform_lookup(
+ nm_device_get_platform(self),
+ nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex));
+
+ if (head_entry) {
+ c_list_for_each_entry (iter, &head_entry->lst_entries_head, lst_entries) {
+ const NMPlatformIPAddress *addr = NMP_OBJECT_CAST_IP_ADDRESS(iter->obj);
+
+ new_address = g_inet_address_new_from_bytes(addr->address_ptr,
+ IS_IPv4 ? G_SOCKET_FAMILY_IPV4
+ : G_SOCKET_FAMILY_IPV6);
+ break;
}
}
-
- if (addr) {
- new_address = g_inet_address_new_from_bytes(addr->address_ptr,
- IS_IPv4 ? G_SOCKET_FAMILY_IPV4
- : G_SOCKET_FAMILY_IPV6);
- }
}
if (new_address && resolver->address) {
@@ -18023,11 +16543,7 @@ _activation_func_to_string(ActivationHandleFunc func)
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);
+ FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage3_ip_config);
g_return_val_if_reached("unknown");
}
@@ -18059,13 +16575,10 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
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);
+ 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));
break;
case PROP_IFINDEX:
g_value_set_int(value, priv->ifindex);
@@ -18100,24 +16613,16 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
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);
+ nm_dbus_utils_g_value_set_object_path(value, priv->l3ipdata_4.ip_config);
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);
+ nm_dbus_utils_g_value_set_object_path(value, priv->ipdhcp_data_4.config);
break;
case PROP_IP6_CONFIG:
- nm_dbus_utils_g_value_set_object_path(value,
- ip_config_valid(priv->state) ? priv->ip_config_6
- : NULL);
+ nm_dbus_utils_g_value_set_object_path(value, priv->l3ipdata_6.ip_config);
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);
+ nm_dbus_utils_g_value_set_object_path(value, priv->ipdhcp_data_6.config);
break;
case PROP_STATE:
g_value_set_uint(value, priv->state);
@@ -18344,6 +16849,8 @@ nm_device_init(NMDevice *self)
c_list_init(&self->devices_lst);
c_list_init(&priv->slaves);
+ priv->ipdhcp_data_6.v6.mode = NM_NDISC_DHCP_LEVEL_NONE;
+
priv->concheck_x[0].state = NM_CONNECTIVITY_UNKNOWN;
priv->concheck_x[1].state = NM_CONNECTIVITY_UNKNOWN;
@@ -18369,9 +16876,6 @@ nm_device_init(NMDevice *self)
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->promisc_reset = NM_OPTION_BOOL_DEFAULT;
}
@@ -18428,24 +16932,7 @@ constructed(GObject *object)
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);
@@ -18497,15 +16984,12 @@ dispose(GObject *object)
_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);
- arp_cleanup(self);
-
nm_clear_g_signal_handler(nm_config_get(), &priv->config_changed_id);
nm_clear_g_signal_handler(priv->manager, &priv->ifindex_changed_id);
- dispatcher_cleanup(self);
+ _dispatcher_cleanup(self);
nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id);
@@ -18514,7 +16998,7 @@ dispose(GObject *object)
nm_assert(c_list_is_empty(&priv->slaves));
/* Let the kernel manage IPv6LL again */
- set_nm_ipv6ll(self, FALSE);
+ _dev_addrgenmode6_set(self, NM_IN6_ADDR_GEN_MODE_EUI64);
_cleanup_generic_post(self, CLEANUP_TYPE_KEEP);
@@ -18583,7 +17067,6 @@ finalize(GObject *object)
g_free(priv->hw_addr_perm);
g_free(priv->hw_addr_initial);
g_free(priv->pending_actions.arr);
- 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);
@@ -18763,10 +17246,8 @@ nm_device_class_init(NMDeviceClass *klass)
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->is_available = is_available;
+ klass->act_stage2_config = act_stage2_config;
klass->get_type_description = get_type_description;
klass->can_auto_connect = can_auto_connect;
@@ -19098,29 +17579,17 @@ nm_device_class_init(NMDeviceClass *klass)
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[L3CD_CHANGED] = g_signal_new(NM_DEVICE_L3CD_CHANGED,
+ G_OBJECT_CLASS_TYPE(object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_POINTER, /* (const NML3ConfigData *l3cd_old) */
+ G_TYPE_POINTER /* (const NML3ConfigData *l3cd_new) */);
signals[IP6_PREFIX_DELEGATED] =
g_signal_new(NM_DEVICE_IP6_PREFIX_DELEGATED,