diff --git a/cli/src/devices.c b/cli/src/devices.c index 7dd32960a..43f8bd067 100644 --- a/cli/src/devices.c +++ b/cli/src/devices.c @@ -549,6 +549,10 @@ show_device_info (gpointer data, gpointer user_data) guint32 multiline_flag = nmc->multiline_output ? NMC_PF_FLAG_MULTILINE : 0; guint32 escape_flag = nmc->escape_values ? NMC_PF_FLAG_ESCAPE : 0; gboolean was_output = FALSE; + NMIP4Config *cfg4; + NMIP6Config *cfg6; + NMDHCP4Config *dhcp4; + NMDHCP6Config *dhcp6; if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) fields_str = fields_common; @@ -813,28 +817,26 @@ show_device_info (gpointer data, gpointer user_data) #endif /* IP configuration info */ - if (state == NM_DEVICE_STATE_ACTIVATED) { - NMIP4Config *cfg4 = nm_device_get_ip4_config (device); - NMIP6Config *cfg6 = nm_device_get_ip6_config (device); - NMDHCP4Config *dhcp4 = nm_device_get_dhcp4_config (device); - NMDHCP6Config *dhcp6 = nm_device_get_dhcp6_config (device); + cfg4 = nm_device_get_ip4_config (device); + cfg6 = nm_device_get_ip6_config (device); + dhcp4 = nm_device_get_dhcp4_config (device); + dhcp6 = nm_device_get_dhcp6_config (device); - /* IP4 */ - if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[7].name)) - was_output = print_ip4_config (cfg4, nmc, nmc_fields_dev_show_sections[7].name); + /* IP4 */ + if (cfg4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[7].name)) + was_output = print_ip4_config (cfg4, nmc, nmc_fields_dev_show_sections[7].name); - /* DHCP4 */ - if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[8].name)) - was_output = print_dhcp4_config (dhcp4, nmc, nmc_fields_dev_show_sections[8].name); + /* DHCP4 */ + if (dhcp4 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[8].name)) + was_output = print_dhcp4_config (dhcp4, nmc, nmc_fields_dev_show_sections[8].name); - /* IP6 */ - if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[9].name)) - was_output = print_ip6_config (cfg6, nmc, nmc_fields_dev_show_sections[9].name); + /* IP6 */ + if (cfg6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[9].name)) + was_output = print_ip6_config (cfg6, nmc, nmc_fields_dev_show_sections[9].name); - /* DHCP6 */ - if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[10].name)) - was_output = print_dhcp6_config (dhcp6, nmc, nmc_fields_dev_show_sections[10].name); - } + /* DHCP6 */ + if (dhcp6 && !strcasecmp (nmc_fields_dev_show_sections[section_idx].name, nmc_fields_dev_show_sections[10].name)) + was_output = print_dhcp6_config (dhcp6, nmc, nmc_fields_dev_show_sections[10].name); /* Bond-specific information */ if ((NM_IS_DEVICE_BOND (device))) { diff --git a/src/nm-device.c b/src/nm-device.c index 0692f3971..37fcfb786 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -68,6 +68,7 @@ #include "nm-dispatcher.h" #include "nm-config-device.h" #include "nm-config.h" +#include "nm-platform.h" static void impl_device_disconnect (NMDevice *device, DBusGMethodInvocation *context); @@ -169,6 +170,7 @@ typedef struct { NMDeviceState state; NMDeviceStateReason state_reason; QueuedState queued_state; + guint queued_ip_config_id; char * udi; char * path; @@ -312,10 +314,32 @@ static const char *state_to_string (NMDeviceState state); static void carrier_changed (GObject *object, GParamSpec *param, gpointer user_data); static void carrier_action_defer_clear (NMDevice *self); +static void nm_device_queued_ip_config_change_clear (NMDevice *self); +static void update_ip_config (NMDevice *self); +static void device_ip_changed (NMPlatform *platform, int ifindex, gpointer platform_object, gpointer user_data); + +static const char const *platform_ip_signals[] = { + NM_PLATFORM_IP4_ADDRESS_ADDED, + NM_PLATFORM_IP4_ADDRESS_CHANGED, + NM_PLATFORM_IP4_ADDRESS_REMOVED, + NM_PLATFORM_IP4_ROUTE_ADDED, + NM_PLATFORM_IP4_ROUTE_CHANGED, + NM_PLATFORM_IP4_ROUTE_REMOVED, + NM_PLATFORM_IP6_ADDRESS_ADDED, + NM_PLATFORM_IP6_ADDRESS_CHANGED, + NM_PLATFORM_IP6_ADDRESS_REMOVED, + NM_PLATFORM_IP6_ROUTE_ADDED, + NM_PLATFORM_IP6_ROUTE_CHANGED, + NM_PLATFORM_IP6_ROUTE_REMOVED, +}; +static const int n_platform_ip_signals = G_N_ELEMENTS (platform_ip_signals); + static void nm_device_init (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMPlatform *platform; + int i; priv->type = NM_DEVICE_TYPE_UNKNOWN; priv->capabilities = NM_DEVICE_CAP_NONE; @@ -325,6 +349,13 @@ nm_device_init (NMDevice *self) priv->rfkill_type = RFKILL_TYPE_UNKNOWN; priv->autoconnect = DEFAULT_AUTOCONNECT; priv->available_connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); + + /* Watch for external IP config changes */ + platform = nm_platform_get (); + for (i = 0; i < n_platform_ip_signals; i++) { + g_signal_connect (platform, platform_ip_signals[i], + G_CALLBACK (device_ip_changed), self); + } } static void @@ -478,6 +509,7 @@ constructor (GType type, update_accept_ra_save (dev); update_ip6_privacy_save (dev); + update_ip_config (dev); priv->initialized = TRUE; return object; @@ -3973,6 +4005,7 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason) /* Clear any queued transitions */ nm_device_queued_state_clear (self); + nm_device_queued_ip_config_change_clear (self); priv->ip4_state = priv->ip6_state = IP_NONE; @@ -4446,6 +4479,7 @@ dispose (GObject *object) NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gboolean take_down = TRUE; + NMPlatform *platform; if (priv->disposed || !priv->initialized) goto out; @@ -4479,6 +4513,7 @@ dispose (GObject *object) /* Clear any queued transitions */ nm_device_queued_state_clear (self); + nm_device_queued_ip_config_change_clear (self); /* Clean up and stop DHCP */ dhcp4_cleanup (self, take_down, FALSE); @@ -4541,6 +4576,9 @@ dispose (GObject *object) clear_act_request (self); + platform = nm_platform_get (); + g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ip_changed), self); + out: G_OBJECT_CLASS (nm_device_parent_class)->dispose (object); } @@ -4672,9 +4710,16 @@ set_property (GObject *object, guint prop_id, } static gboolean -_is_connected (NMDeviceState state) +has_ip_config (NMDevice *self) { - return (state >= NM_DEVICE_STATE_IP_CONFIG && state <= NM_DEVICE_STATE_DEACTIVATING); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (!priv->ip4_config && !priv->ip6_config) + return FALSE; + + return ( ( priv->state >= NM_DEVICE_STATE_IP_CONFIG + && priv->state <= NM_DEVICE_STATE_DEACTIVATING) + || (priv->state == NM_DEVICE_STATE_UNMANAGED)); } static void @@ -4683,14 +4728,11 @@ get_property (GObject *object, guint prop_id, { NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceState state; const char *ac_path = NULL; GPtrArray *array; GHashTableIter iter; NMConnection *connection; - state = nm_device_get_state (self); - switch (prop_id) { case PROP_UDI: g_value_set_string (value, priv->udi); @@ -4699,7 +4741,7 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, priv->iface); break; case PROP_IP_IFACE: - if (_is_connected (state)) + if (has_ip_config (self)) g_value_set_string (value, nm_device_get_ip_iface (self)); else g_value_set_string (value, NULL); @@ -4723,25 +4765,25 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->ip4_address); break; case PROP_IP4_CONFIG: - if (_is_connected (state) && priv->ip4_config) + if (has_ip_config (self) && priv->ip4_config) g_value_set_boxed (value, nm_ip4_config_get_dbus_path (priv->ip4_config)); else g_value_set_boxed (value, "/"); break; case PROP_DHCP4_CONFIG: - if (_is_connected (state) && priv->dhcp4_client) + if (has_ip_config (self) && priv->dhcp4_client) g_value_set_boxed (value, nm_dhcp4_config_get_dbus_path (priv->dhcp4_config)); else g_value_set_boxed (value, "/"); break; case PROP_IP6_CONFIG: - if (_is_connected (state) && priv->ip6_config) + if (has_ip_config (self) && priv->ip6_config) g_value_set_boxed (value, nm_ip6_config_get_dbus_path (priv->ip6_config)); else g_value_set_boxed (value, "/"); break; case PROP_DHCP6_CONFIG: - if (_is_connected (state) && priv->dhcp6_client) + if (has_ip_config (self) && priv->dhcp6_client) g_value_set_boxed (value, nm_dhcp6_config_get_dbus_path (priv->dhcp6_config)); else g_value_set_boxed (value, "/"); @@ -5517,6 +5559,78 @@ nm_device_get_state (NMDevice *device) return NM_DEVICE_GET_PRIVATE (device)->state; } +static void +update_ip_config (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; + NMIP4Config *ip4_config; + NMIP6Config *ip6_config; + int ifindex; + + if (priv->state != NM_DEVICE_STATE_UNMANAGED) + return; + + ifindex = nm_device_get_ip_ifindex (self); + if (!ifindex) + return; + + ip4_config = nm_ip4_config_new_for_interface (ifindex); + ip6_config = nm_ip6_config_new_for_interface (ifindex); + + nm_device_set_ip4_config (self, ip4_config, TRUE, &ignored); + nm_device_set_ip6_config (self, ip6_config, TRUE, &ignored); + + if (ip4_config) + g_object_unref (ip4_config); + if (ip6_config) + g_object_unref (ip6_config); +} + +static gboolean +queued_ip_config_change (gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + /* Wait for any queued state changes */ + if (priv->queued_state.id) + return TRUE; + + priv->queued_ip_config_id = 0; + update_ip_config (self); + return FALSE; +} + +static void +device_ip_changed (NMPlatform *platform, int ifindex, gpointer platform_object, gpointer user_data) +{ + NMDevice *self = user_data; + + if (nm_device_get_ip_ifindex (self) == ifindex) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (!priv->queued_ip_config_id) + priv->queued_ip_config_id = g_idle_add (queued_ip_config_change, self); + + nm_log_dbg (LOGD_DEVICE, "(%s): queued IP config change", + nm_device_get_iface (self)); + } +} + +void +nm_device_queued_ip_config_change_clear (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->queued_ip_config_id) { + nm_log_dbg (LOGD_DEVICE, "(%s): clearing queued IP config change", + nm_device_get_iface (self)); + g_source_remove (priv->queued_ip_config_id); + priv->queued_ip_config_id = 0; + } +} + gboolean nm_device_get_managed (NMDevice *device) { diff --git a/src/nm-device.h b/src/nm-device.h index 009c498e7..ea3cc0e70 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -297,6 +297,8 @@ void nm_device_queue_state (NMDevice *self, NMDeviceState state, NMDeviceStateReason reason); +void nm_device_queue_ip_config_change (NMDevice *self); + gboolean nm_device_get_firmware_missing (NMDevice *self); void nm_device_activate (NMDevice *device, NMActRequest *req); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 07e423ee1..14a83f9ff 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -27,6 +27,7 @@ #include "NetworkManager.h" #include "NetworkManagerUtils.h" #include "nm-setting-ip4-config.h" +#include "nm-platform.h" #include "nm-utils.h" #include @@ -97,6 +98,49 @@ nm_ip4_config_new (void) return (NMIP4Config *) g_object_new (NM_TYPE_IP4_CONFIG, NULL); } +NMIP4Config * +nm_ip4_config_new_for_interface (int ifindex) +{ + NMIP4Config *ip4; + GArray *addrs_array, *routes_array; + NMPlatformIP4Address *addrs; + NMPlatformIP4Route *routes; + NMIP4Address *addr; + NMIP4Route *route; + int i; + + addrs_array = nm_platform_ip4_address_get_all (ifindex); + if (addrs_array->len == 0) { + g_array_unref (addrs_array); + return NULL; + } + + ip4 = nm_ip4_config_new (); + + addrs = (NMPlatformIP4Address *)addrs_array->data; + for (i = 0; i < addrs_array->len; i++) { + addr = nm_ip4_address_new (); + nm_ip4_address_set_address (addr, addrs[i].address); + nm_ip4_address_set_prefix (addr, addrs[i].plen); + nm_ip4_config_take_address (ip4, addr); + } + g_array_unref (addrs_array); + + routes_array = nm_platform_ip4_route_get_all (ifindex); + routes = (NMPlatformIP4Route *)routes_array->data; + for (i = 0; i < routes_array->len; i++) { + route = nm_ip4_route_new (); + nm_ip4_route_set_dest (route, routes[i].network); + nm_ip4_route_set_prefix (route, routes[i].plen); + nm_ip4_route_set_next_hop (route, routes[i].gateway); + nm_ip4_route_set_metric (route, routes[i].metric); + nm_ip4_config_take_route (ip4, route); + } + g_array_unref (routes_array); + + return ip4; +} + void nm_ip4_config_export (NMIP4Config *config) { diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 5433768cd..309f9edd3 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -51,6 +51,8 @@ GType nm_ip4_config_get_type (void); NMIP4Config * nm_ip4_config_new (void); +NMIP4Config * nm_ip4_config_new_for_interface (int ifindex); + void nm_ip4_config_export (NMIP4Config *config); const char * nm_ip4_config_get_dbus_path (NMIP4Config *config); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 65c947f70..c491439a7 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -27,6 +27,7 @@ #include "NetworkManager.h" #include "NetworkManagerUtils.h" #include "nm-setting-ip6-config.h" +#include "nm-platform.h" #include "nm-utils.h" #include @@ -94,6 +95,49 @@ nm_ip6_config_new (void) return (NMIP6Config *) g_object_new (NM_TYPE_IP6_CONFIG, NULL); } +NMIP6Config * +nm_ip6_config_new_for_interface (int ifindex) +{ + NMIP6Config *ip6; + GArray *addrs_array, *routes_array; + NMPlatformIP6Address *addrs; + NMPlatformIP6Route *routes; + NMIP6Address *addr; + NMIP6Route *route; + int i; + + addrs_array = nm_platform_ip6_address_get_all (ifindex); + if (addrs_array->len == 0) { + g_array_unref (addrs_array); + return NULL; + } + + ip6 = nm_ip6_config_new (); + + addrs = (NMPlatformIP6Address *)addrs_array->data; + for (i = 0; i < addrs_array->len; i++) { + addr = nm_ip6_address_new (); + nm_ip6_address_set_address (addr, &addrs[i].address); + nm_ip6_address_set_prefix (addr, addrs[i].plen); + nm_ip6_config_take_address (ip6, addr); + } + g_array_unref (addrs_array); + + routes_array = nm_platform_ip6_route_get_all (ifindex); + routes = (NMPlatformIP6Route *)routes_array->data; + for (i = 0; i < routes_array->len; i++) { + route = nm_ip6_route_new (); + nm_ip6_route_set_dest (route, &routes[i].network); + nm_ip6_route_set_prefix (route, routes[i].plen); + nm_ip6_route_set_next_hop (route, &routes[i].gateway); + nm_ip6_route_set_metric (route, routes[i].metric); + nm_ip6_config_take_route (ip6, route); + } + g_array_unref (routes_array); + + return ip6; +} + void nm_ip6_config_export (NMIP6Config *config) { diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 158f54945..889678ee0 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -50,6 +50,8 @@ GType nm_ip6_config_get_type (void); NMIP6Config * nm_ip6_config_new (void); +NMIP6Config * nm_ip6_config_new_for_interface (int ifindex); + void nm_ip6_config_export (NMIP6Config *config); const char * nm_ip6_config_get_dbus_path (NMIP6Config *config); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 8f4063617..e173069c9 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -29,6 +29,7 @@ test_dhcp_options_LDADD = \ $(top_builddir)/libnm-util/libnm-util.la \ $(top_builddir)/src/dhcp-manager/libdhcp-manager.la \ $(top_builddir)/src/libtest-dhcp.la \ + $(top_builddir)/src/platform/libnm-platform.la \ $(GLIB_LIBS) \ $(DBUS_LIBS)