From fb6c929d887f652967d4fb978d50e9104788ad24 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 14:51:47 -0700 Subject: [PATCH 001/105] libnm-util: add IPv4 'disabled' method Allowing IPv4 configuration to be completely disabled for a connection. --- libnm-util/nm-setting-ip4-config.c | 57 ++++++++++++++++-------------- libnm-util/nm-setting-ip4-config.h | 3 +- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/libnm-util/nm-setting-ip4-config.c b/libnm-util/nm-setting-ip4-config.c index 46ebbd377f..c1d7f01c76 100644 --- a/libnm-util/nm-setting-ip4-config.c +++ b/libnm-util/nm-setting-ip4-config.c @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2010 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -462,7 +462,8 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } } else if ( !strcmp (priv->method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) - || !strcmp (priv->method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { + || !strcmp (priv->method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) + || !strcmp (priv->method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { if (priv->dns && priv->dns->len) { g_set_error (error, NM_SETTING_IP4_CONFIG_ERROR, @@ -721,7 +722,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) * network access to other computers) then the interface is assigned an * address in the 10.42.x.1/24 range and a DHCP and forwarding DNS server * are started, and the interface is NAT-ed to the current default network - * connection. This property must be set. + * connection. 'disabled' means IPv4 will not be used on this connection. + * This property must be set. **/ g_object_class_install_property (object_class, PROP_METHOD, @@ -742,7 +744,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) "address in the 10.42.x.1/24 range and a DHCP and " "forwarding DNS server are started, and the " "interface is NAT-ed to the current default network " - "connection. This property must be set.", + "connection. 'disabled' means IPv4 will not be " + "used on this connection. This property must be set.", NULL, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); @@ -751,8 +754,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) * * List of DNS servers (network byte order). For the 'auto' method, these * DNS servers are appended to those (if any) returned by automatic - * configuration. DNS servers cannot be used with the 'shared' or - * 'link-local' methods as there is no usptream network. In all other + * configuration. DNS servers cannot be used with the 'shared', 'link-local', + * or 'disabled' methods as there is no usptream network. In all other * methods, these DNS servers are used as the only DNS servers for this * connection. **/ @@ -764,10 +767,10 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) "the 'auto' method, these DNS servers are " "appended to those (if any) returned by automatic " "configuration. DNS servers cannot be used with " - "the 'shared' or 'link-local' methods as there is " - "no usptream network. In all other methods, " - "these DNS servers are used as the only DNS " - "servers for this connection.", + "the 'shared', 'link-local', or 'disabled' " + "methods as there is no usptream network. In all " + "other methods, these DNS servers are used as the " + "only DNS servers for this connection.", DBUS_TYPE_G_UINT_ARRAY, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); @@ -776,9 +779,9 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) * * List of DNS search domains. For the 'auto' method, these search domains * are appended to those returned by automatic configuration. Search domains - * cannot be used with the 'shared' or 'link-local' methods as there is no - * upstream network. In all other methods, these search domains are used - * as the only search domains for this connection. + * cannot be used with the 'shared', 'link-local', or 'disabled' methods as + * there is no upstream network. In all other methods, these search domains + * are used as the only search domains for this connection. **/ g_object_class_install_property (object_class, PROP_DNS_SEARCH, @@ -787,11 +790,11 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) "List of DNS search domains. For the 'auto' " "method, these search domains are appended to " "those returned by automatic configuration. " - "Search domains cannot be used with the 'shared' " - "or 'link-local' methods as there is no upstream " - "network. In all other methods, these search " - "domains are used as the only search domains for " - "this connection.", + "Search domains cannot be used with the 'shared', " + "'link-local', or 'disabled' methods as there is " + "no upstream network. In all other methods, these " + "search domains are used as the only search domains " + "for this connection.", DBUS_TYPE_G_LIST_OF_STRING, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); @@ -804,8 +807,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) * (network byte order). The gateway may be left as 0 if no gateway exists * for that subnet. For the 'auto' method, given IP addresses are appended * to those returned by automatic configuration. Addresses cannot be used - * with the 'shared' or 'link-local' methods as the interface is - * automatically assigned an address with these methods. + * with the 'shared', 'link-local', or 'disabled' methods as addressing is + * either automatic or disabled with these methods. **/ g_object_class_install_property (object_class, PROP_ADDRESSES, @@ -820,9 +823,9 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) "for that subnet. For the 'auto' method, given " "IP addresses are appended to those returned by " "automatic configuration. Addresses cannot be " - "used with the 'shared' or 'link-local' methods " - "as the interface is automatically assigned an " - "address with these methods.", + "used with the 'shared', 'link-local', or " + "'disabled' methods as addressing is either " + "automatic or disabled with these methods.", DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); @@ -835,8 +838,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) * address prefix (1 - 32), the third being the next-hop (network byte * order) if any, and the fourth being the route metric. For the 'auto' * method, given IP routes are appended to those returned by automatic - * configuration. Routes cannot be used with the 'shared' or 'link-local' - * methods because there is no upstream network. + * configuration. Routes cannot be used with the 'shared', 'link-local', + * or 'disabled' methods because there is no upstream network. **/ g_object_class_install_property (object_class, PROP_ROUTES, @@ -852,8 +855,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) "For the 'auto' method, given IP routes are " "appended to those returned by automatic " "configuration. Routes cannot be used with the " - "'shared' or 'link-local' methods as there is no " - "upstream network.", + "'shared', 'link-local', or 'disabled', methods " + "as there is no upstream network.", DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); diff --git a/libnm-util/nm-setting-ip4-config.h b/libnm-util/nm-setting-ip4-config.h index 2362982f51..777f53f126 100644 --- a/libnm-util/nm-setting-ip4-config.h +++ b/libnm-util/nm-setting-ip4-config.h @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2010 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -69,6 +69,7 @@ GQuark nm_setting_ip4_config_error_quark (void); #define NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL "link-local" #define NM_SETTING_IP4_CONFIG_METHOD_MANUAL "manual" #define NM_SETTING_IP4_CONFIG_METHOD_SHARED "shared" +#define NM_SETTING_IP4_CONFIG_METHOD_DISABLED "disabled" typedef struct NMIP4Address NMIP4Address; From fe25e20f6ad541915d8f3a9079f802008020c3b2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 14:52:43 -0700 Subject: [PATCH 002/105] ifcfg-rh: handle disabled IPv4 correctly Instead of not including the IP4 setting, set its method to disabled. In reality either one is legal, but including the IP4 setting wtih the method set to 'disabled' is more explicit. --- system-settings/plugins/ifcfg-rh/reader.c | 5 +++- .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 27 +++++++++++++++---- system-settings/plugins/ifcfg-rh/writer.c | 6 ++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/system-settings/plugins/ifcfg-rh/reader.c b/system-settings/plugins/ifcfg-rh/reader.c index 32575f3953..378aff4e00 100644 --- a/system-settings/plugins/ifcfg-rh/reader.c +++ b/system-settings/plugins/ifcfg-rh/reader.c @@ -1215,7 +1215,10 @@ make_ip4_setting (shvarFile *ifcfg, if (!tmp_ip4 && !tmp_prefix && !tmp_netmask) { if (valid_ip6_config) { /* Nope, no IPv4 */ - goto done; + g_object_set (s_ip4, + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + return NM_SETTING (s_ip4); } method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; diff --git a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index cfe93d6ec0..2f77be2ca9 100644 --- a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -2165,6 +2165,7 @@ test_read_wired_ipv6_only (void) const char *expected_dns1 = "1:2:3:4::a"; NMIP6Address *ip6_addr; struct in6_addr addr; + const char *method; connection = connection_from_file (TEST_IFCFG_WIRED_IPV6_ONLY, NULL, @@ -2217,11 +2218,18 @@ test_read_wired_ipv6_only (void) /* ===== IPv4 SETTING ===== */ s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG)); - ASSERT (s_ip4 == NULL, - "wired-ipv6-only-verify-ip4", "failed to verify %s: unexpected %s setting", + ASSERT (s_ip4 != NULL, + "wired-ipv6-only-verify-ip4", "failed to verify %s: missing %s setting", TEST_IFCFG_WIRED_IPV6_MANUAL, NM_SETTING_IP4_CONFIG_SETTING_NAME); + method = nm_setting_ip4_config_get_method (s_ip4); + ASSERT (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0, + "wired-ipv6-only-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_WIRED_IPV6_MANUAL, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_METHOD); + /* ===== IPv6 SETTING ===== */ s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG)); @@ -5264,6 +5272,7 @@ test_write_wired_static_ip6_only (void) NMConnection *reread; NMSettingConnection *s_con; NMSettingWired *s_wired; + NMSettingIP4Config *s_ip4; NMSettingIP6Config *s_ip6; static unsigned char tmpmac[] = { 0x31, 0x33, 0x33, 0x37, 0xbe, 0xcd }; GByteArray *mac; @@ -5317,6 +5326,17 @@ test_write_wired_static_ip6_only (void) g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL); g_byte_array_free (mac, TRUE); + /* IP4 setting */ + s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new (); + ASSERT (s_ip4 != NULL, + "wired-static-ip6-only-write", "failed to allocate new %s setting", + NM_SETTING_IP4_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + /* IP6 setting */ s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); ASSERT (s_ip6 != NULL, @@ -5373,9 +5393,6 @@ test_write_wired_static_ip6_only (void) ASSERT (nm_connection_verify (reread, &error), "wired-static-ip6-only-write-reread-verify", "failed to verify %s: %s", testfile, error->message); - ASSERT (nm_connection_get_setting (reread, NM_TYPE_SETTING_IP4_CONFIG) == NULL, - "wired-static-ip6-only-write-reread-verify", "unexpected IPv4 setting"); - ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, "wired-static-ip6-only-write", "written and re-read connection weren't the same."); diff --git a/system-settings/plugins/ifcfg-rh/writer.c b/system-settings/plugins/ifcfg-rh/writer.c index cc24a96f58..8085584cca 100644 --- a/system-settings/plugins/ifcfg-rh/writer.c +++ b/system-settings/plugins/ifcfg-rh/writer.c @@ -908,9 +908,13 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) guint32 i, num; GString *searches; gboolean success = FALSE; + const char *method = NULL; s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); - if (!s_ip4) { + if (s_ip4) + method = nm_setting_ip4_config_get_method (s_ip4); + + if (!s_ip4 || (method && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED))) { int result; /* IPv4 disabled, clear IPv4 related parameters */ From c049680515a7c1a6719287940498fa6ed127dbdd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 14:54:22 -0700 Subject: [PATCH 003/105] core: use constant instead of hardcoding a string --- src/nm-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nm-device.c b/src/nm-device.c index 280d4e4105..c5051dc99b 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -2248,7 +2248,7 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data) if (s_ip4) method = nm_setting_ip4_config_get_method (s_ip4); - if (s_ip4 && !strcmp (method, "shared")) { + if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { if (!start_sharing (self)) { nm_log_warn (LOGD_SHARING, "Activation (%s) Stage 5 of 5 (IP Configure Commit) start sharing failed.", iface); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); From c35bec214c42f60bb53a355237d4d471d8133486 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 14:54:42 -0700 Subject: [PATCH 004/105] dhcp: ensure the IP4 method is compatible with DHCP --- src/dhcp-manager/nm-dhcp-manager.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index 94109adcf6..635fe320b0 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -482,6 +482,13 @@ nm_dhcp_manager_start_ip4 (NMDHCPManager *self, priv = NM_DHCP_MANAGER_GET_PRIVATE (self); if (s_ip4) { + const char *method = nm_setting_ip4_config_get_method (s_ip4); + + if (method) { + /* Method must be 'auto' */ + g_return_val_if_fail (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0, NULL); + } + if ( nm_setting_ip4_config_get_dhcp_send_hostname (s_ip4) && (nm_setting_ip4_config_get_dhcp_hostname (s_ip4) == NULL) && priv->hostname_provider != NULL) { From 5e6ae3b226ecf6b05924b8d4113501fa2c4a82ea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 14:59:29 -0700 Subject: [PATCH 005/105] core: don't require IPv4 configuration during activation --- src/nm-device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nm-device.c b/src/nm-device.c index c5051dc99b..1ee7510321 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1674,7 +1674,8 @@ real_act_stage4_get_ip4_config (NMDevice *self, *config = nm_device_new_ip4_shared_config (self, reason); if (*config) priv->dnsmasq_manager = nm_dnsmasq_manager_new (ip_iface); - } + } else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) + ret = NM_ACT_STAGE_RETURN_SUCCESS; } if (!*config) { From e2ad8c2a5410c734a58ab22ee4e14579dfc6542b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 15:18:08 -0700 Subject: [PATCH 006/105] core: add 'default6' property for ActiveConnection objects Since IPv4 and IPv6 have different routing one device can have the active IPv4 connection and a completely different one can have the active IPv6 one. --- introspection/nm-active-connection.xml | 5 ++- libnm-glib/Makefile.am | 2 +- libnm-glib/libnm-glib.ver | 1 + libnm-glib/nm-active-connection.c | 62 ++++++++++++++++++++++---- libnm-glib/nm-active-connection.h | 4 +- 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/introspection/nm-active-connection.xml b/introspection/nm-active-connection.xml index ff55f63885..765830a1dc 100644 --- a/introspection/nm-active-connection.xml +++ b/introspection/nm-active-connection.xml @@ -18,7 +18,10 @@ The state of this active connection. - Whether this active connection is the default connection, i.e. whether it currently owns the default route. + Whether this active connection is the default IPv4 connection, i.e. whether it currently owns the default IPv4 route. + + + Whether this active connection is the default IPv6 connection, i.e. whether it currently owns the default IPv6 route. Whether this active connection is also a VPN connection. diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am index 58b5bc559e..8f03b0abda 100644 --- a/libnm-glib/Makefile.am +++ b/libnm-glib/Makefile.am @@ -132,7 +132,7 @@ libnm_glib_la_LIBADD = \ $(GUDEV_LIBS) libnm_glib_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib.ver \ - -version-info "4:1:2" + -version-info "4:2:2" noinst_PROGRAMS = libnm-glib-test diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver index 1caa2d42ba..46051e8784 100644 --- a/libnm-glib/libnm-glib.ver +++ b/libnm-glib/libnm-glib.ver @@ -18,6 +18,7 @@ global: nm_access_point_new; nm_active_connection_get_connection; nm_active_connection_get_default; + nm_active_connection_get_default6; nm_active_connection_get_devices; nm_active_connection_get_scope; nm_active_connection_get_service_name; diff --git a/libnm-glib/nm-active-connection.c b/libnm-glib/nm-active-connection.c index df8bb98271..2468da099f 100644 --- a/libnm-glib/nm-active-connection.c +++ b/libnm-glib/nm-active-connection.c @@ -17,7 +17,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. * Copyright (C) 2008 Novell, Inc. */ @@ -50,6 +50,7 @@ typedef struct { GPtrArray *devices; NMActiveConnectionState state; gboolean is_default; + gboolean is_default6; } NMActiveConnectionPrivate; enum { @@ -60,6 +61,7 @@ enum { PROP_DEVICES, PROP_STATE, PROP_DEFAULT, + PROP_DEFAULT6, LAST_PROP }; @@ -70,6 +72,7 @@ enum { #define DBUS_PROP_DEVICES "Devices" #define DBUS_PROP_STATE "State" #define DBUS_PROP_DEFAULT "Default" +#define DBUS_PROP_DEFAULT6 "Default6" /** * nm_active_connection_new: @@ -263,10 +266,10 @@ nm_active_connection_get_state (NMActiveConnection *connection) * nm_active_connection_get_default: * @connection: a #NMActiveConnection * - * Whether the active connection is the default one (that is, is used for the default route - * and DNS information). + * Whether the active connection is the default IPv4 one (that is, is used for + * the default IPv4 route and DNS information). * - * Returns: %TRUE if the active connection is the default one + * Returns: %TRUE if the active connection is the default IPv4 connection **/ gboolean nm_active_connection_get_default (NMActiveConnection *connection) @@ -278,13 +281,39 @@ nm_active_connection_get_default (NMActiveConnection *connection) priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection); if (!priv->is_default) { priv->is_default = _nm_object_get_boolean_property (NM_OBJECT (connection), - NM_DBUS_INTERFACE_ACTIVE_CONNECTION, - DBUS_PROP_DEFAULT); + NM_DBUS_INTERFACE_ACTIVE_CONNECTION, + DBUS_PROP_DEFAULT); } return priv->is_default; } +/** + * nm_active_connection_get_default6: + * @connection: a #NMActiveConnection + * + * Whether the active connection is the default IPv6 one (that is, is used for + * the default IPv6 route and DNS information). + * + * Returns: %TRUE if the active connection is the default IPv6 connection + **/ +gboolean +nm_active_connection_get_default6 (NMActiveConnection *connection) +{ + NMActiveConnectionPrivate *priv; + + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), FALSE); + + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection); + if (!priv->is_default6) { + priv->is_default6 = _nm_object_get_boolean_property (NM_OBJECT (connection), + NM_DBUS_INTERFACE_ACTIVE_CONNECTION, + DBUS_PROP_DEFAULT6); + } + + return priv->is_default6; +} + static void nm_active_connection_init (NMActiveConnection *ap) { @@ -350,6 +379,9 @@ get_property (GObject *object, case PROP_DEFAULT: g_value_set_boolean (value, nm_active_connection_get_default (self)); break; + case PROP_DEFAULT6: + g_value_set_boolean (value, nm_active_connection_get_default6 (self)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -392,6 +424,7 @@ register_for_property_changed (NMActiveConnection *connection) { NM_ACTIVE_CONNECTION_DEVICES, demarshal_devices, &priv->devices }, { NM_ACTIVE_CONNECTION_STATE, _nm_object_demarshal_generic, &priv->state }, { NM_ACTIVE_CONNECTION_DEFAULT, _nm_object_demarshal_generic, &priv->is_default }, + { NM_ACTIVE_CONNECTION_DEFAULT6, _nm_object_demarshal_generic, &priv->is_default6 }, { NULL }, }; @@ -512,13 +545,26 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class) /** * NMActiveConnection:default: * - * Whether the active connection is the default one. + * Whether the active connection is the default IPv4 one. **/ g_object_class_install_property (object_class, PROP_DEFAULT, g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT, "Default", - "Is the default active connection", + "Is the default IPv4 active connection", + FALSE, + G_PARAM_READABLE)); + + /** + * NMActiveConnection:default6: + * + * Whether the active connection is the default IPv6 one. + **/ + g_object_class_install_property + (object_class, PROP_DEFAULT6, + g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6, + "Default6", + "Is the default IPv6 active connection", FALSE, G_PARAM_READABLE)); } diff --git a/libnm-glib/nm-active-connection.h b/libnm-glib/nm-active-connection.h index f717c055ef..30edf047a0 100644 --- a/libnm-glib/nm-active-connection.h +++ b/libnm-glib/nm-active-connection.h @@ -17,7 +17,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. * Copyright (C) 2008 Novell, Inc. */ @@ -45,6 +45,7 @@ G_BEGIN_DECLS #define NM_ACTIVE_CONNECTION_DEVICES "devices" #define NM_ACTIVE_CONNECTION_STATE "state" #define NM_ACTIVE_CONNECTION_DEFAULT "default" +#define NM_ACTIVE_CONNECTION_DEFAULT6 "default6" typedef struct { NMObject parent; @@ -73,6 +74,7 @@ const char * nm_active_connection_get_specific_object (NMActiveConnection *c const GPtrArray *nm_active_connection_get_devices (NMActiveConnection *connection); NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *connection); gboolean nm_active_connection_get_default (NMActiveConnection *connection); +gboolean nm_active_connection_get_default6 (NMActiveConnection *connection); G_END_DECLS From 37c411abc91714e8a14c7811fe8ef6c133a280f5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 15:26:11 -0700 Subject: [PATCH 007/105] core: add 'default6' property to ActiveConnection implementations --- src/nm-activation-request.c | 45 +++++++++++++++++++++++++++-- src/nm-activation-request.h | 6 +++- src/nm-active-connection.h | 3 +- src/vpn-manager/nm-vpn-connection.c | 14 ++++++++- 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 1335c35e46..2529e77f65 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -72,6 +72,7 @@ typedef struct { NMActiveConnectionState state; gboolean is_default; + gboolean is_default6; gboolean shared; GSList *share_rules; @@ -88,6 +89,7 @@ enum { PROP_DEVICES, PROP_STATE, PROP_DEFAULT, + PROP_DEFAULT6, PROP_VPN, LAST_PROP @@ -104,7 +106,7 @@ device_state_changed (NMDevice *device, NMActRequest *self = NM_ACT_REQUEST (user_data); NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); NMActiveConnectionState new_ac_state; - gboolean new_default = FALSE; + gboolean new_default = FALSE, new_default6 = FALSE; /* Set NMActiveConnection state based on the device's state */ switch (new_state) { @@ -117,6 +119,7 @@ device_state_changed (NMDevice *device, case NM_DEVICE_STATE_ACTIVATED: new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED; new_default = priv->is_default; + new_default6 = priv->is_default6; break; default: new_ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; @@ -132,6 +135,11 @@ device_state_changed (NMDevice *device, priv->is_default = new_default; g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT); } + + if (new_default6 != priv->is_default6) { + priv->is_default6 = new_default6; + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT6); + } } NMActRequest * @@ -271,6 +279,9 @@ get_property (GObject *object, guint prop_id, case PROP_DEFAULT: g_value_set_boolean (value, priv->is_default); break; + case PROP_DEFAULT6: + g_value_set_boolean (value, priv->is_default6); + break; case PROP_VPN: g_value_set_boolean (value, FALSE); break; @@ -334,7 +345,14 @@ nm_act_request_class_init (NMActRequestClass *req_class) (object_class, PROP_DEFAULT, g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT, "Default", - "Is the default active connection", + "Is the default IPv4 active connection", + FALSE, + G_PARAM_READABLE)); + g_object_class_install_property + (object_class, PROP_DEFAULT6, + g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6, + "Default6", + "Is the default IPv6 active connection", FALSE, G_PARAM_READABLE)); g_object_class_install_property @@ -548,6 +566,29 @@ nm_act_request_get_default (NMActRequest *req) return NM_ACT_REQUEST_GET_PRIVATE (req)->is_default; } +void +nm_act_request_set_default6 (NMActRequest *req, gboolean is_default6) +{ + NMActRequestPrivate *priv; + + g_return_if_fail (NM_IS_ACT_REQUEST (req)); + + priv = NM_ACT_REQUEST_GET_PRIVATE (req); + if (priv->is_default6 == is_default6) + return; + + priv->is_default6 = is_default6; + g_object_notify (G_OBJECT (req), NM_ACTIVE_CONNECTION_DEFAULT6); +} + +gboolean +nm_act_request_get_default6 (NMActRequest *req) +{ + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + + return NM_ACT_REQUEST_GET_PRIVATE (req)->is_default6; +} + static void share_child_setup (gpointer user_data G_GNUC_UNUSED) { diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index a3c0d97446..a243694521 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2005 - 2008 Red Hat, Inc. + * (C) Copyright 2005 - 2010 Red Hat, Inc. */ #ifndef NM_ACTIVATION_REQUEST_H @@ -76,6 +76,10 @@ void nm_act_request_set_default (NMActRequest *req, gboolean is_default gboolean nm_act_request_get_default (NMActRequest *req); +void nm_act_request_set_default6 (NMActRequest *req, gboolean is_default6); + +gboolean nm_act_request_get_default6 (NMActRequest *req); + gboolean nm_act_request_get_shared (NMActRequest *req); void nm_act_request_set_shared (NMActRequest *req, gboolean shared); diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 4a1f2e1477..6a463cb257 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2010 Red Hat, Inc. */ #ifndef NM_ACTIVE_CONNECTION_H @@ -30,6 +30,7 @@ #define NM_ACTIVE_CONNECTION_DEVICES "devices" #define NM_ACTIVE_CONNECTION_STATE "state" #define NM_ACTIVE_CONNECTION_DEFAULT "default" +#define NM_ACTIVE_CONNECTION_DEFAULT6 "default6" #define NM_ACTIVE_CONNECTION_VPN "vpn" char *nm_active_connection_get_next_object_path (void); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 01f639acc5..a594df59b5 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -69,6 +69,7 @@ typedef struct { gulong device_ip4; gboolean is_default; + gboolean is_default6; NMActiveConnectionState state; NMVPNConnectionState vpn_state; @@ -102,6 +103,7 @@ enum { PROP_DEVICES, PROP_STATE, PROP_DEFAULT, + PROP_DEFAULT6, PROP_VPN, PROP_VPN_STATE, PROP_BANNER, @@ -1052,6 +1054,9 @@ get_property (GObject *object, guint prop_id, case PROP_DEFAULT: g_value_set_boolean (value, priv->is_default); break; + case PROP_DEFAULT6: + g_value_set_boolean (value, priv->is_default6); + break; case PROP_VPN: g_value_set_boolean (value, TRUE); break; @@ -1122,7 +1127,14 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class) (object_class, PROP_DEFAULT, g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT, "Default", - "Is the default active connection", + "Is the default IPv4 active connection", + FALSE, + G_PARAM_READABLE)); + g_object_class_install_property + (object_class, PROP_DEFAULT6, + g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6, + "Default6", + "Is the default IPv6 active connection", FALSE, G_PARAM_READABLE)); g_object_class_install_property From d8f0ba554c645e8af3036e96dc034642c1675280 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 15:28:42 -0700 Subject: [PATCH 008/105] policy: reconfigure routing and DNS when either IPv4 or IPv6 changes --- src/nm-policy.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index 7159eafb57..5cbf0cdbcd 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -828,9 +828,9 @@ device_state_changed (NMDevice *device, } static void -device_ip4_config_changed (NMDevice *device, - GParamSpec *pspec, - gpointer user_data) +device_ip_config_changed (NMDevice *device, + GParamSpec *pspec, + gpointer user_data) { update_routing_and_dns ((NMPolicy *) user_data, TRUE); } @@ -872,7 +872,12 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data) policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); id = g_signal_connect (device, "notify::" NM_DEVICE_INTERFACE_IP4_CONFIG, - G_CALLBACK (device_ip4_config_changed), + G_CALLBACK (device_ip_config_changed), + policy); + policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); + + id = g_signal_connect (device, "notify::" NM_DEVICE_INTERFACE_IP6_CONFIG, + G_CALLBACK (device_ip_config_changed), policy); policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device); From 44ea07a5d77fb42e4f7cc97126836270319cf981 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 17 Apr 2010 10:26:53 -0700 Subject: [PATCH 009/105] libnm-util: add gateway member to IPv6 addresses --- include/nm-dbus-glib-types.h | 2 +- libnm-util/Makefile.am | 2 +- libnm-util/libnm-util.ver | 2 ++ libnm-util/nm-setting-ip6-config.c | 24 ++++++++++++++ libnm-util/nm-setting-ip6-config.h | 4 +++ libnm-util/nm-utils.c | 53 +++++++++++++++++++++++++----- 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/include/nm-dbus-glib-types.h b/include/nm-dbus-glib-types.h index cfb08274c6..0f8c542e82 100644 --- a/include/nm-dbus-glib-types.h +++ b/include/nm-dbus-glib-types.h @@ -34,7 +34,7 @@ #define DBUS_TYPE_G_MAP_OF_STRING (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING)) #define DBUS_TYPE_G_LIST_OF_STRING (dbus_g_type_get_collection ("GSList", G_TYPE_STRING)) -#define DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID)) +#define DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_INVALID)) #define DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_IP6_ADDRESS)) #define DBUS_TYPE_G_IP6_ROUTE (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID)) #define DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_IP6_ROUTE)) diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index 8f6a0cc95d..bb4736f45b 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -59,7 +59,7 @@ libnm_util_la_SOURCES= \ libnm_util_la_LIBADD = $(GLIB_LIBS) $(DBUS_LIBS) $(UUID_LIBS) libnm_util_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-util.ver \ - -version-info "4:2:3" + -version-info "4:3:3" if WITH_GNUTLS libnm_util_la_SOURCES += crypto_gnutls.c diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index 44d9ac5aec..1c8446ba2e 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -177,6 +177,8 @@ global: nm_ip6_address_compare; nm_ip6_address_get_address; nm_ip6_address_set_address; + nm_ip6_address_get_gateway; + nm_ip6_address_set_gateway; nm_ip6_address_get_prefix; nm_ip6_address_set_prefix; nm_ip6_route_new; diff --git a/libnm-util/nm-setting-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index 3fbf1a2bc4..c383b2d270 100644 --- a/libnm-util/nm-setting-ip6-config.c +++ b/libnm-util/nm-setting-ip6-config.c @@ -797,10 +797,13 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class) } +/********************************************************************/ + struct NMIP6Address { guint32 refcount; struct in6_addr address; guint32 prefix; + struct in6_addr gateway; }; NMIP6Address * @@ -902,6 +905,27 @@ nm_ip6_address_set_prefix (NMIP6Address *address, guint32 prefix) address->prefix = prefix; } +const struct in6_addr * +nm_ip6_address_get_gateway (NMIP6Address *address) +{ + g_return_val_if_fail (address != NULL, 0); + g_return_val_if_fail (address->refcount > 0, 0); + + return &address->gateway; +} + +void +nm_ip6_address_set_gateway (NMIP6Address *address, const struct in6_addr *gw) +{ + g_return_if_fail (address != NULL); + g_return_if_fail (address->refcount > 0); + g_return_if_fail (gw != NULL); + + memcpy (&address->gateway, gw, sizeof (struct in6_addr)); +} + +/********************************************************************/ + struct NMIP6Route { guint32 refcount; diff --git a/libnm-util/nm-setting-ip6-config.h b/libnm-util/nm-setting-ip6-config.h index b089679e4e..78617c4547 100644 --- a/libnm-util/nm-setting-ip6-config.h +++ b/libnm-util/nm-setting-ip6-config.h @@ -88,6 +88,10 @@ guint32 nm_ip6_address_get_prefix (NMIP6Address *address); void nm_ip6_address_set_prefix (NMIP6Address *address, guint32 prefix); +const struct in6_addr *nm_ip6_address_get_gateway (NMIP6Address *address); +void nm_ip6_address_set_gateway (NMIP6Address *address, + const struct in6_addr *gw); + typedef struct NMIP6Route NMIP6Route; NMIP6Route * nm_ip6_route_new (void); diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c index 5ca3014d79..405288d361 100644 --- a/libnm-util/nm-utils.c +++ b/libnm-util/nm-utils.c @@ -1459,8 +1459,8 @@ nm_utils_ip4_get_default_prefix (guint32 ip) * @value: gvalue containing a GPtrArray of GValueArrays of (GArray of guchars) and guint32 * * Utility function to convert a #GPtrArray of #GValueArrays of (#GArray of guchars) and guint32 - * representing a list of NetworkManager IPv6 addresses (which is a pair of address - * and prefix), into a GSList of #NMIP6Address objects. The specific format of + * representing a list of NetworkManager IPv6 addresses (which is a tuple of address, + * prefix, and gateway), into a GSList of #NMIP6Address objects. The specific format of * this serialization is not guaranteed to be stable and the #GValueArray may be * extended in the future. * @@ -1479,16 +1479,28 @@ nm_utils_ip6_addresses_from_gvalue (const GValue *value) GValueArray *elements = (GValueArray *) g_ptr_array_index (addresses, i); GValue *tmp; GByteArray *ba_addr; + GByteArray *ba_gw = NULL; NMIP6Address *addr; guint32 prefix; - if ( (elements->n_values != 2) - || (G_VALUE_TYPE (g_value_array_get_nth (elements, 0)) != DBUS_TYPE_G_UCHAR_ARRAY) + if (elements->n_values < 2 || elements->n_values > 3) { + nm_warning ("%s: ignoring invalid IP6 address structure", __func__); + continue; + } + + if ( (G_VALUE_TYPE (g_value_array_get_nth (elements, 0)) != DBUS_TYPE_G_UCHAR_ARRAY) || (G_VALUE_TYPE (g_value_array_get_nth (elements, 1)) != G_TYPE_UINT)) { nm_warning ("%s: ignoring invalid IP6 address structure", __func__); continue; } + /* Check optional 3rd element (gateway) */ + if ( elements->n_values == 3 + && (G_VALUE_TYPE (g_value_array_get_nth (elements, 2)) != DBUS_TYPE_G_UCHAR_ARRAY)) { + nm_warning ("%s: ignoring invalid IP6 address structure", __func__); + continue; + } + tmp = g_value_array_get_nth (elements, 0); ba_addr = g_value_get_boxed (tmp); if (ba_addr->len != 16) { @@ -1505,9 +1517,22 @@ nm_utils_ip6_addresses_from_gvalue (const GValue *value) continue; } + if (elements->n_values == 3) { + tmp = g_value_array_get_nth (elements, 2); + ba_gw = g_value_get_boxed (tmp); + if (ba_gw->len != 16) { + nm_warning ("%s: ignoring invalid IP6 gateway address of length %d", + __func__, ba_gw->len); + continue; + } + } + addr = nm_ip6_address_new (); nm_ip6_address_set_prefix (addr, prefix); nm_ip6_address_set_address (addr, (const struct in6_addr *) ba_addr->data); + if (ba_gw) + nm_ip6_address_set_gateway (addr, (const struct in6_addr *) ba_gw->data); + list = g_slist_prepend (list, addr); } @@ -1522,10 +1547,10 @@ nm_utils_ip6_addresses_from_gvalue (const GValue *value) * g_value_unset(). * * Utility function to convert a #GSList of #NMIP6Address objects into a - * GPtrArray of GValueArrays of (GArray or guchars) and guint32 representing a list - * of NetworkManager IPv6 addresses (which is a pair of address and prefix). - * The specific format of this serialization is not guaranteed to be stable and may be - * extended in the future. + * GPtrArray of GValueArrays representing a list of NetworkManager IPv6 addresses + * (which is a tuple of address, prefix, and gateway). The specific format of + * this serialization is not guaranteed to be stable and may be extended in the + * future. **/ void nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value) @@ -1541,8 +1566,9 @@ nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value) GValue element = {0, }; GByteArray *ba; - array = g_value_array_new (2); + array = g_value_array_new (3); + /* IP address */ g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); ba = g_byte_array_new (); g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_address (addr), 16); @@ -1550,11 +1576,20 @@ nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value) g_value_array_append (array, &element); g_value_unset (&element); + /* Prefix */ g_value_init (&element, G_TYPE_UINT); g_value_set_uint (&element, nm_ip6_address_get_prefix (addr)); g_value_array_append (array, &element); g_value_unset (&element); + /* Gateway */ + g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); + ba = g_byte_array_new (); + g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_gateway (addr), 16); + g_value_take_boxed (&element, ba); + g_value_array_append (array, &element); + g_value_unset (&element); + g_ptr_array_add (addresses, array); } From 1d409aeb532e9927d6d15033f2365709c342464a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 17 Apr 2010 17:19:30 -0700 Subject: [PATCH 010/105] core: fix Address property type of IP6Config objects We can change the property's D-Bus signature (and thus API) here because querying the IP6Config object's properties caused NM to crash. Apparently we forgot to change the type of the Address property when we C&P-ed the IP4Config into the IP6Config, and DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT is certainly the wrong type to use since the backing object that dbus-glib would marshal into the ARRAY_OF_ARRAY_OF_UINT wasn't that type, causing a crash in dbus-glib when a client got the IP6Config. --- introspection/nm-ip6-config.xml | 4 ++-- src/nm-ip6-config.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/introspection/nm-ip6-config.xml b/introspection/nm-ip6-config.xml index d1349b0c21..604781857e 100644 --- a/introspection/nm-ip6-config.xml +++ b/introspection/nm-ip6-config.xml @@ -2,8 +2,8 @@ - - Tuples of IPv6 address/prefix. + + Tuples of IPv6 address/prefix/gateway. The nameservers in use. diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 66c328eef9..d2a17a0e5c 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2008 Red Hat, Inc. + * Copyright (C) 2005 - 2010 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -697,7 +697,7 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class) g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES, "Addresses", "IP6 addresses", - DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, + DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS, G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_NAMESERVERS, From 73a7e6b8e06b1f6db13fa671a2e7a7fc89bfd4f3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 18 Apr 2010 11:43:43 -0700 Subject: [PATCH 011/105] core: fix IP6Config property types to match introspection spec --- src/nm-ip6-config.c | 55 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index d2a17a0e5c..e3fe92dbd3 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -692,34 +692,33 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class) object_class->finalize = finalize; /* properties */ - g_object_class_install_property - (object_class, PROP_ADDRESSES, - g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES, - "Addresses", - "IP6 addresses", - DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS, - G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_NAMESERVERS, - g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS, - "Nameservers", - "DNS list", - DBUS_TYPE_G_UINT_ARRAY, - G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_DOMAINS, - g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS, - "Domains", - "Domains", - DBUS_TYPE_G_ARRAY_OF_STRING, - G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_ROUTES, - g_param_spec_boxed (NM_IP6_CONFIG_ROUTES, - "Routes", - "Routes", - DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, - G_PARAM_READABLE)); + g_object_class_install_property (object_class, PROP_ADDRESSES, + g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES, + "Addresses", + "IP6 addresses", + DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_NAMESERVERS, + g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS, + "Nameservers", + "DNS list", + DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_DOMAINS, + g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS, + "Domains", + "Domains", + DBUS_TYPE_G_ARRAY_OF_STRING, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_ROUTES, + g_param_spec_boxed (NM_IP6_CONFIG_ROUTES, + "Routes", + "Routes", + DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE, + G_PARAM_READABLE)); dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (config_class), &dbus_glib_nm_ip6_config_object_info); From 83652e6b8e79c12def7e4f42af8b01fbf61d9097 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 19 Apr 2010 10:14:44 -0700 Subject: [PATCH 012/105] libnm-util: convert from old IP6 address format to new Ensure it still works correctly if something tries to set the 'addresses' property using the old GType. Also make sure that the various IP6 address comparison operations and string conversion functions handle the gateway. --- libnm-util/nm-param-spec-specialized.c | 18 ++++- libnm-util/nm-utils.c | 70 ++++++++++++++++++ libnm-util/tests/test-general.c | 99 +++++++++++++++++++++++++- 3 files changed, 182 insertions(+), 5 deletions(-) diff --git a/libnm-util/nm-param-spec-specialized.c b/libnm-util/nm-param-spec-specialized.c index ad0febfcf6..f5a362ce41 100644 --- a/libnm-util/nm-param-spec-specialized.c +++ b/libnm-util/nm-param-spec-specialized.c @@ -19,7 +19,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2010 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ @@ -377,6 +377,7 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2) GValue *tmp_val; GByteArray *addr1, *addr2; guint32 prefix1, prefix2; + GByteArray *gw1, *gw2; gint ret = 0; int i; @@ -387,8 +388,8 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2) /* Since they are NM IPv6 address structures, we expect both * to contain two elements as specified in nm-dbus-glib-types.h. */ - g_return_val_if_fail (values1->n_values == 2, 0); - g_return_val_if_fail (values2->n_values == 2, 0); + g_return_val_if_fail (values1->n_values == 3, 0); + g_return_val_if_fail (values2->n_values == 3, 0); /* First struct IPv6 address */ tmp_val = g_value_array_get_nth (values1, 0); @@ -396,6 +397,9 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2) /* First struct IPv6 prefix */ tmp_val = g_value_array_get_nth (values1, 1); prefix1 = g_value_get_uint (tmp_val); + /* First struct IPv6 gateway */ + tmp_val = g_value_array_get_nth (values1, 2); + gw1 = g_value_get_boxed (tmp_val); /* Second struct IPv6 address */ tmp_val = g_value_array_get_nth (values2, 0); @@ -403,6 +407,9 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2) /* Second struct IPv6 prefix */ tmp_val = g_value_array_get_nth (values2, 1); prefix2 = g_value_get_uint (tmp_val); + /* Second struct IPv6 gateway */ + tmp_val = g_value_array_get_nth (values2, 2); + gw2 = g_value_get_boxed (tmp_val); /* Compare IPv6 addresses */ if (prefix1 != prefix2) @@ -413,6 +420,11 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2) ret = addr1->data[i] < addr2->data[i] ? -1 : addr1->data[i] > addr2->data[i]; } + if (!IN6_ARE_ADDR_EQUAL ((struct in6_addr *) gw1->data, (struct in6_addr *) gw2->data)) { + for (i = 0; ret == 0 && i < gw1->len; i++) + ret = gw1->data[i] < gw2->data[i] ? -1 : gw1->data[i] > gw2->data[i]; + } + return ret; } diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c index 405288d361..808169471f 100644 --- a/libnm-util/nm-utils.c +++ b/libnm-util/nm-utils.c @@ -275,6 +275,8 @@ nm_utils_init (GError **error) if (!crypto_init (error)) return FALSE; + _nm_utils_register_value_transformations (); + atexit (nm_utils_deinit); initialized = TRUE; } @@ -886,6 +888,19 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu continue; } g_string_append_printf (printable, "px = %u", prefix); + g_string_append (printable, ", "); + + /* IPv6 Gateway */ + tmp = g_value_array_get_nth (elements, 2); + ba_addr = g_value_get_boxed (tmp); + if (ba_addr->len != 16) { + g_string_append (printable, "invalid"); + continue; + } + addr = (struct in6_addr *) ba_addr->data; + memset (buf, 0, sizeof (buf)); + nm_utils_inet6_ntop (addr, buf); + g_string_append_printf (printable, "gw = %s", buf); g_string_append (printable, " }"); } g_string_append_c (printable, ']'); @@ -977,6 +992,58 @@ nm_utils_convert_ip6_route_struct_array_to_string (const GValue *src_value, GVal g_string_free (printable, FALSE); } +#define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID)) +#define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS)) + +static void +nm_utils_convert_old_ip6_addr_array (const GValue *src_value, GValue *dst_value) +{ + GPtrArray *src_outer_array; + GPtrArray *dst_outer_array; + guint i; + + g_return_if_fail (g_type_is_a (G_VALUE_TYPE (src_value), OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS)); + + src_outer_array = (GPtrArray *) g_value_get_boxed (src_value); + dst_outer_array = g_ptr_array_new (); + + for (i = 0; src_outer_array && (i < src_outer_array->len); i++) { + GValueArray *src_addr_array; + GValueArray *dst_addr_array; + GValue element = {0, }; + GValue *src_addr, *src_prefix; + GByteArray *ba; + + src_addr_array = (GValueArray *) g_ptr_array_index (src_outer_array, i); + + if ( (src_addr_array->n_values != 2) + || (G_VALUE_TYPE (g_value_array_get_nth (src_addr_array, 0)) != DBUS_TYPE_G_UCHAR_ARRAY) + || (G_VALUE_TYPE (g_value_array_get_nth (src_addr_array, 1)) != G_TYPE_UINT)) { + g_warning ("%s: invalid old IPv6 address type", __func__); + return; + } + + dst_addr_array = g_value_array_new (3); + + src_addr = g_value_array_get_nth (src_addr_array, 0); + g_value_array_append (dst_addr_array, src_addr); + src_prefix = g_value_array_get_nth (src_addr_array, 1); + g_value_array_append (dst_addr_array, src_prefix); + + /* Blank Gateway */ + g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); + ba = g_byte_array_new (); + g_byte_array_append (ba, (guint8 *) "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16); + g_value_take_boxed (&element, ba); + g_value_array_append (dst_addr_array, &element); + g_value_unset (&element); + + g_ptr_array_add (dst_outer_array, dst_addr_array); + } + + g_value_take_boxed (dst_value, dst_outer_array); +} + void _nm_utils_register_value_transformations (void) { @@ -1013,6 +1080,9 @@ _nm_utils_register_value_transformations (void) g_value_register_transform_func (DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE, G_TYPE_STRING, nm_utils_convert_ip6_route_struct_array_to_string); + g_value_register_transform_func (OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS, + DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS, + nm_utils_convert_old_ip6_addr_array); registered = TRUE; } } diff --git a/libnm-util/tests/test-general.c b/libnm-util/tests/test-general.c index d00ec994e1..9530445959 100644 --- a/libnm-util/tests/test-general.c +++ b/libnm-util/tests/test-general.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 - 2009 Red Hat, Inc. + * Copyright (C) 2008 - 2010 Red Hat, Inc. * */ @@ -28,7 +28,8 @@ #include "nm-setting-connection.h" #include "nm-setting-vpn.h" - +#include "nm-setting-ip6-config.h" +#include "nm-dbus-glib-types.h" static void vpn_check_func (const char *key, const char *value, gpointer user_data) @@ -128,6 +129,99 @@ test_setting_vpn_items (void) g_object_unref (s_vpn); } +#define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID)) +#define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS)) + +/* Test that setting the IPv6 setting's 'addresses' property using the old + * IPv6 address format still works, i.e. that the GValue transformation function + * from old->new is working correctly. + */ +static void +test_setting_ip6_config_old_address_array (void) +{ + NMSettingIP6Config *s_ip6; + GPtrArray *addresses, *read_addresses; + GValueArray *array, *read_array; + GValue element = {0, }, written_value = {0, }, read_value = {0, }; + GByteArray *ba; + const guint8 addr[16] = { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, + 0x11, 0x22, 0x33, 0x44, 0x66, 0x77, 0x88, 0x99 }; + const guint8 gw[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + guint32 prefix = 56; + GValue *read_addr, *read_prefix, *read_gw; + + s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new (); + ASSERT (s_ip6 != NULL, + "ip6-old-addr", "error creating IP6 setting"); + + g_value_init (&written_value, OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS); + + addresses = g_ptr_array_new (); + array = g_value_array_new (3); + + /* IP address */ + g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); + ba = g_byte_array_new (); + g_byte_array_append (ba, &addr[0], sizeof (addr)); + g_value_take_boxed (&element, ba); + g_value_array_append (array, &element); + g_value_unset (&element); + + /* Prefix */ + g_value_init (&element, G_TYPE_UINT); + g_value_set_uint (&element, prefix); + g_value_array_append (array, &element); + g_value_unset (&element); + + g_ptr_array_add (addresses, array); + g_value_set_boxed (&written_value, addresses); + + /* Set the address array on the object */ + g_object_set_property (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_ADDRESSES, &written_value); + + /* Get it back so we can compare it */ + g_value_init (&read_value, DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS); + g_object_get_property (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_ADDRESSES, &read_value); + + ASSERT (G_VALUE_HOLDS (&read_value, DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS), + "ip6-old-addr", "wrong addresses property value type '%s'", + G_VALUE_TYPE_NAME (&read_value)); + + read_addresses = (GPtrArray *) g_value_get_boxed (&read_value); + ASSERT (read_addresses != NULL, + "ip6-old-addr", "missing addresses on readback"); + ASSERT (read_addresses->len == 1, + "ip6-old-addr", "expected one address on readback"); + + read_array = (GValueArray *) g_ptr_array_index (read_addresses, 0); + + read_addr = g_value_array_get_nth (read_array, 0); + ba = g_value_get_boxed (read_addr); + ASSERT (ba->len == sizeof (addr), + "ip6-old-addr", "unexpected address item length %d", ba->len); + ASSERT (memcmp (ba->data, &addr[0], sizeof (addr)) == 0, + "ip6-old-addr", "unexpected failure comparing addresses"); + + read_prefix = g_value_array_get_nth (read_array, 1); + ASSERT (g_value_get_uint (read_prefix) == prefix, + "ip6-old-addr", "unexpected failure comparing prefix"); + + /* Ensure the gateway is all zeros, which is how the 2-item to 3-item + * conversion happens. + */ + read_gw = g_value_array_get_nth (read_array, 2); + ba = g_value_get_boxed (read_gw); + ASSERT (ba->len == sizeof (gw), + "ip6-old-addr", "unexpected gateway item length %d", ba->len); + ASSERT (memcmp (ba->data, &gw[0], sizeof (gw)) == 0, + "ip6-old-addr", "unexpected failure comparing gateways"); + + g_value_unset (&written_value); + g_value_unset (&read_value); + g_object_unref (s_ip6); +} + int main (int argc, char **argv) { GError *error = NULL; @@ -142,6 +236,7 @@ int main (int argc, char **argv) /* The tests */ test_setting_vpn_items (); + test_setting_ip6_config_old_address_array (); base = g_path_get_basename (argv[0]); fprintf (stdout, "%s: SUCCESS\n", base); From c5ff30fa71f2f80046f043b680384cf76c445f3c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 19 Apr 2010 15:07:18 -0700 Subject: [PATCH 013/105] doc: update settings spec generator for IPv6 address changes --- docs/generate-settings-spec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/generate-settings-spec.c b/docs/generate-settings-spec.c index d7a391f9b0..6ec8f7c5e0 100644 --- a/docs/generate-settings-spec.c +++ b/docs/generate-settings-spec.c @@ -17,7 +17,7 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2009 Red Hat, Inc. + * (C) Copyright 2009 - 2010 Red Hat, Inc. */ #include @@ -86,7 +86,7 @@ static TypeNameElement name_map[] = { { "GPtrArray_GArray_guint__", "array of array of uint32" }, { "GPtrArray_GArray_guchar__", "array of byte array" }, { "GHashTable_gchararray+gchararray_", "dict of (string::string)" }, - { "GPtrArray_GValueArray_GArray_guchar_+guint__", "array of (byte array, uint32)" }, + { "GPtrArray_GValueArray_GArray_guchar_+guint+GArray_guchar___", "array of (byte array, uint32, byte array)" }, { "GPtrArray_GValueArray_GArray_guchar_+guint+GArray_guchar_+guint__", "array of (byte array, uint32, byte array, uint32)" }, { NULL, NULL } }; From 151a2b4c5a0587e72e6c757a0a5fc75dfa493a62 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 19 Apr 2010 15:10:03 -0700 Subject: [PATCH 014/105] libnm-util: quiet harmless message in type conversion --- libnm-util/nm-utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c index 808169471f..c9c34f1ba6 100644 --- a/libnm-util/nm-utils.c +++ b/libnm-util/nm-utils.c @@ -747,7 +747,8 @@ nm_utils_convert_string_hash_to_string (const GValue *src_value, GValue *dest_va hash = (GHashTable *) g_value_get_boxed (src_value); printable = g_string_new ("["); - g_hash_table_foreach (hash, convert_one_string_hash_entry, printable); + if (hash) + g_hash_table_foreach (hash, convert_one_string_hash_entry, printable); g_string_append (printable, " ]"); g_value_take_string (dest_value, printable->str); From 31590021ab007c426c6acacfef8db8064f04f4bb Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 19 Apr 2010 15:10:17 -0700 Subject: [PATCH 015/105] libnm-util: update IPv6 address property description --- libnm-util/nm-setting-ip6-config.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/libnm-util/nm-setting-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index c383b2d270..3e42216cbd 100644 --- a/libnm-util/nm-setting-ip6-config.c +++ b/libnm-util/nm-setting-ip6-config.c @@ -684,25 +684,32 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class) * NMSettingIP6Config:addresses: * * Array of IPv6 address structures. Each IPv6 address structure is - * composed of 2 members, the first being a byte array containing the IPv6 - * address (network byte order) and the second a 32-bit integer containing - * the IPv6 address prefix. For the 'auto' method, given IP addresses are - * appended to those returned by automatic configuration. Addresses cannot - * be used with the 'shared' or 'link-local' methods as the interface is - * automatically assigned an address with these methods. + * composed of 3 members, the first being a byte array containing the IPv6 + * address (network byte order), the second a 32-bit integer containing the + * IPv6 address prefix, and the third a byte array containing the IPv6 + * address (network byte order) of the gateway associated with this address, + * if any. If no gateway is given, the third element should be given as + * all zeros. For the 'auto' method, given IP addresses are appended to + * those returned by automatic configuration. Addresses cannot be used with + * the 'shared' or 'link-local' methods as the interface is automatically + * assigned an address with these methods. **/ g_object_class_install_property (object_class, PROP_ADDRESSES, _nm_param_spec_specialized (NM_SETTING_IP6_CONFIG_ADDRESSES, "Addresses", "Array of IPv6 address structures. Each IPv6 " - "address structure is composed of 2 members, the " + "address structure is composed of 3 members, the " "first being a byte array containing the IPv6 " - "address (network byte order) and the second a " + "address (network byte order), the second a " "32-bit integer containing the IPv6 address " - "prefix. For the 'auto' method, given IP " - "addresses are appended to those returned by " - "automatic configuration. Addresses cannot be " + "prefix, and the third a byte array containing " + "the IPv6 address (network byte order) of the " + "gateway associated with this address, if any. " + "If no gateway is given, the third element should " + "be given as all zeros. For the 'auto' method, " + "given IP addresses are appended to those returned " + "by automatic configuration. Addresses cannot be " "used with the 'shared' or 'link-local' methods " "as the interface is automatically assigned an " "address with these methods.", From b04ebe5cc3d11984332e86d48c5a8975b8d758cd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 19 Apr 2010 16:55:40 -0700 Subject: [PATCH 016/105] keyfile: fix writing IPv6 addresses with new format --- system-settings/plugins/keyfile/io/writer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system-settings/plugins/keyfile/io/writer.c b/system-settings/plugins/keyfile/io/writer.c index d9f36af7a6..2e194072e3 100644 --- a/system-settings/plugins/keyfile/io/writer.c +++ b/system-settings/plugins/keyfile/io/writer.c @@ -298,9 +298,9 @@ ip6_addr_writer (GKeyFile *file, GValueArray *values = g_ptr_array_index (array, i); char *key_name, *ip6_addr; - if (values->n_values % 2) { - nm_warning ("%s: error writing IP6 address %d; address array length" - " %d is not a multiple of 2.", + if (values->n_values != 3) { + nm_warning ("%s: error writing IP6 address %d (address array length " + "%d is not 3)", __func__, i, values->n_values); continue; } From fbcdc95a21173c3ede100b4710d6cda30d554971 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 19 Apr 2010 16:56:50 -0700 Subject: [PATCH 017/105] logging: logger needs -ldl for dladdr() --- src/logging/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/logging/Makefile.am b/src/logging/Makefile.am index d2e3e25112..51a6b25dc0 100644 --- a/src/logging/Makefile.am +++ b/src/logging/Makefile.am @@ -10,5 +10,6 @@ libnm_logging_la_CPPFLAGS = \ -DG_DISABLE_DEPRECATED libnm_logging_la_LIBADD = \ + -ldl \ $(GLIB_LIBS) From f9113079961887b93a2bbf4a0a5dd2212e53743a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 19 Apr 2010 16:59:34 -0700 Subject: [PATCH 018/105] policy: move hostname/lookup thread operations into separate file --- src/Makefile.am | 4 + src/nm-policy-hostname.c | 196 ++++++++++++++++++++++++++++ src/nm-policy-hostname.h | 47 +++++++ src/nm-policy-hosts.c | 62 +++++++++ src/nm-policy-hosts.h | 10 +- src/nm-policy.c | 271 +++++---------------------------------- 6 files changed, 346 insertions(+), 244 deletions(-) create mode 100644 src/nm-policy-hostname.c create mode 100644 src/nm-policy-hostname.h diff --git a/src/Makefile.am b/src/Makefile.am index 214f7545c3..ca1ce6bbd2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -68,9 +68,11 @@ libtest_policy_hosts_la_SOURCES = \ nm-policy-hosts.h libtest_policy_hosts_la_CPPFLAGS = \ + -DSYSCONFDIR=\"$(sysconfdir)\" \ $(GLIB_CFLAGS) libtest_policy_hosts_la_LIBADD = \ + ${top_builddir}/src/logging/libnm-logging.la \ $(GLIB_LIBS) @@ -123,6 +125,8 @@ NetworkManager_SOURCES = \ nm-policy.h \ nm-policy-hosts.c \ nm-policy-hosts.h \ + nm-policy-hostname.c \ + nm-policy-hostname.h \ NetworkManagerUtils.c \ NetworkManagerUtils.h \ nm-system.c \ diff --git a/src/nm-policy-hostname.c b/src/nm-policy-hostname.c new file mode 100644 index 0000000000..02eb560263 --- /dev/null +++ b/src/nm-policy-hostname.c @@ -0,0 +1,196 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2004 - 2010 Red Hat, Inc. + * Copyright (C) 2007 - 2008 Novell, Inc. + */ + +#include +#include +#include +#include +#include + +#include + +#include "nm-logging.h" +#include "nm-policy-hostname.h" +#include "nm-policy-hosts.h" + +/************************************************************************/ + +struct HostnameThread { + GThread *thread; + + GMutex *lock; + gboolean dead; + int ret; + + guint32 ip4_addr; + char hostname[NI_MAXHOST + 1]; + + HostnameThreadCallback callback; + gpointer user_data; +}; + +static gboolean +hostname_thread_run_cb (gpointer user_data) +{ + HostnameThread *ht = (HostnameThread *) user_data; + + (*ht->callback) (ht, ht->ret, ht->hostname, ht->user_data); + return FALSE; +} + +static gpointer +hostname_thread_worker (gpointer data) +{ + HostnameThread *ht = (HostnameThread *) data; + struct sockaddr_in addr; + int i; + + g_mutex_lock (ht->lock); + if (ht->dead) { + g_mutex_unlock (ht->lock); + return (gpointer) NULL; + } + g_mutex_unlock (ht->lock); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ht->ip4_addr; + + ht->ret = getnameinfo ((struct sockaddr *) &addr, sizeof (struct sockaddr_in), + ht->hostname, NI_MAXHOST, NULL, 0, + NI_NAMEREQD); + if (ht->ret == 0) { + for (i = 0; i < strlen (ht->hostname); i++) + ht->hostname[i] = tolower (ht->hostname[i]); + } + + /* Don't track the idle handler ID because by the time the g_idle_add() + * returns the ID, the handler may already have run and freed the + * HostnameThread. + */ + g_idle_add (hostname_thread_run_cb, ht); + return (gpointer) TRUE; +} + +void +hostname_thread_free (HostnameThread *ht) +{ + g_return_if_fail (ht != NULL); + + g_mutex_free (ht->lock); + memset (ht, 0, sizeof (HostnameThread)); + g_free (ht); +} + +HostnameThread * +hostname_thread_new (guint32 ip4_addr, HostnameThreadCallback callback, gpointer user_data) +{ + HostnameThread *ht; + + ht = g_malloc0 (sizeof (HostnameThread)); + g_assert (ht); + + ht->lock = g_mutex_new (); + ht->callback = callback; + ht->user_data = user_data; + ht->ip4_addr = ip4_addr; + + ht->thread = g_thread_create (hostname_thread_worker, ht, FALSE, NULL); + if (!ht->thread) { + hostname_thread_free (ht); + ht = NULL; + } + + return ht; +} + +void +hostname_thread_kill (HostnameThread *ht) +{ + g_return_if_fail (ht != NULL); + + g_mutex_lock (ht->lock); + ht->dead = TRUE; + g_mutex_unlock (ht->lock); +} + +gboolean +hostname_thread_is_dead (HostnameThread *ht) +{ + g_return_val_if_fail (ht != NULL, TRUE); + + return ht->dead; +} + +/************************************************************************/ + +#define FALLBACK_HOSTNAME "localhost.localdomain" + +gboolean +nm_policy_set_system_hostname (const char *new_hostname, const char *msg) +{ + char old_hostname[HOST_NAME_MAX + 1]; + int ret = 0; + const char *name = new_hostname ? new_hostname : FALLBACK_HOSTNAME; + gboolean set_hostname = TRUE, changed = FALSE; + + old_hostname[HOST_NAME_MAX] = '\0'; + errno = 0; + ret = gethostname (old_hostname, HOST_NAME_MAX); + if (ret != 0) { + nm_log_warn (LOGD_DNS, "couldn't get the system hostname: (%d) %s", + errno, strerror (errno)); + } else { + /* Don't set the hostname if it isn't actually changing */ + if ( (new_hostname && !strcmp (old_hostname, new_hostname)) + || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME))) + set_hostname = FALSE; + } + + if (set_hostname) { + nm_log_info (LOGD_DNS, "Setting system hostname to '%s' (%s)", name, msg); + ret = sethostname (name, strlen (name)); + if (ret != 0) { + nm_log_warn (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s", + name, errno, strerror (errno)); + return FALSE; + } + } + + /* But even if the hostname isn't changing, always try updating /etc/hosts + * just in case the hostname changed while NM wasn't running; we need to + * make sure that /etc/hosts has valid mappings for '127.0.0.1' and the + * current system hostname. If those exist, + * nm_policy_hosts_update_etc_hosts() will just return and won't touch + * /etc/hosts at all. + */ + if (!nm_policy_hosts_update_etc_hosts (name, FALLBACK_HOSTNAME, &changed)) { + /* error updating /etc/hosts; fallback to localhost.localdomain */ + nm_log_info (LOGD_DNS, "Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)"); + ret = sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME)); + if (ret != 0) { + nm_log_warn (LOGD_DNS, "couldn't set the fallback system hostname (%s): (%d) %s", + FALLBACK_HOSTNAME, errno, strerror (errno)); + } + } + + return changed; +} + diff --git a/src/nm-policy-hostname.h b/src/nm-policy-hostname.h new file mode 100644 index 0000000000..c59ca41078 --- /dev/null +++ b/src/nm-policy-hostname.h @@ -0,0 +1,47 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2004 - 2010 Red Hat, Inc. + * Copyright (C) 2007 - 2008 Novell, Inc. + */ + +#ifndef NM_POLICY_HOSTNAME_H +#define NM_POLICY_HOSTNAME_H + +#include + +gboolean nm_policy_set_system_hostname (const char *new_hostname, const char *msg); + + +typedef struct HostnameThread HostnameThread; + +typedef void (*HostnameThreadCallback) (HostnameThread *ht, + int error, + const char *hostname, + gpointer user_data); + +HostnameThread * hostname_thread_new (guint32 ip4_addr, + HostnameThreadCallback callback, + gpointer user_data); + +void hostname_thread_free (HostnameThread *ht); + +gboolean hostname_thread_is_dead (HostnameThread *ht); + +void hostname_thread_kill (HostnameThread *ht); + +#endif /* NM_POLICY_HOSTNAME_H */ diff --git a/src/nm-policy-hosts.c b/src/nm-policy-hosts.c index 35a0b9d60c..7723c99759 100644 --- a/src/nm-policy-hosts.c +++ b/src/nm-policy-hosts.c @@ -25,6 +25,7 @@ #include #include "nm-policy-hosts.h" +#include "nm-logging.h" gboolean nm_policy_hosts_find_token (const char *line, const char *token) @@ -171,3 +172,64 @@ nm_policy_get_etc_hosts (const char **lines, return contents; } +gboolean +nm_policy_hosts_update_etc_hosts (const char *hostname, + const char *fallback_hostname, + gboolean *out_changed) +{ + char *contents = NULL; + char **lines = NULL; + GError *error = NULL; + GString *new_contents = NULL; + gsize contents_len = 0; + gboolean success = FALSE; + + g_return_val_if_fail (hostname != NULL, FALSE); + g_return_val_if_fail (out_changed != NULL, FALSE); + + if (!g_file_get_contents (SYSCONFDIR "/hosts", &contents, &contents_len, &error)) { + nm_log_warn (LOGD_DNS, "couldn't read " SYSCONFDIR "/hosts: (%d) %s", + error ? error->code : 0, + (error && error->message) ? error->message : "(unknown)"); + g_clear_error (&error); + return FALSE; + } + + /* Get the new /etc/hosts contents */ + lines = g_strsplit_set (contents, "\n\r", 0); + new_contents = nm_policy_get_etc_hosts ((const char **) lines, + contents_len, + hostname, + fallback_hostname, + &error); + g_strfreev (lines); + g_free (contents); + + if (new_contents) { + nm_log_info (LOGD_DNS, "Updating /etc/hosts with new system hostname"); + + g_clear_error (&error); + /* And actually update /etc/hosts */ + if (!g_file_set_contents (SYSCONFDIR "/hosts", new_contents->str, -1, &error)) { + nm_log_warn (LOGD_DNS, "couldn't update " SYSCONFDIR "/hosts: (%d) %s", + error ? error->code : 0, + (error && error->message) ? error->message : "(unknown)"); + g_clear_error (&error); + } else { + success = TRUE; + *out_changed = TRUE; + } + + g_string_free (new_contents, TRUE); + } else if (!error) { + /* No change required */ + success = TRUE; + } else { + nm_log_warn (LOGD_DNS, "couldn't read " SYSCONFDIR "/hosts: (%d) %s", + error->code, error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } + + return success; +} + diff --git a/src/nm-policy-hosts.h b/src/nm-policy-hosts.h index 4130ad0037..0a77e6678a 100644 --- a/src/nm-policy-hosts.h +++ b/src/nm-policy-hosts.h @@ -23,14 +23,18 @@ #include +gboolean nm_policy_hosts_update_etc_hosts (const char *hostname, + const char *fallback_hostname, + gboolean *out_changed); + +/* Only for testcases; don't use outside of nm-policy-hosts.c */ +gboolean nm_policy_hosts_find_token (const char *line, const char *token); + GString *nm_policy_get_etc_hosts (const char **lines, gsize existing_len, const char *hostname, const char *fallback_hostname, GError **error); -/* Only for testcases; don't use outside of nm-policy-hosts.c */ -gboolean nm_policy_hosts_find_token (const char *line, const char *token); - #endif /* NM_POLICY_HOSTS_H */ diff --git a/src/nm-policy.c b/src/nm-policy.c index 5cbf0cdbcd..4fccaf4d11 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -42,24 +42,7 @@ #include "nm-named-manager.h" #include "nm-vpn-manager.h" #include "nm-policy-hosts.h" - -typedef struct LookupThread LookupThread; - -typedef void (*LookupCallback) (LookupThread *thread, gpointer user_data); - -struct LookupThread { - GThread *thread; - - GMutex *lock; - gboolean die; - int ret; - - guint32 ip4_addr; - char hostname[NI_MAXHOST + 1]; - - LookupCallback callback; - gpointer user_data; -}; +#include "nm-policy-hostname.h" struct NMPolicy { NMManager *manager; @@ -74,97 +57,11 @@ struct NMPolicy { NMDevice *default_device; - LookupThread *lookup; + HostnameThread *lookup; char *orig_hostname; /* hostname at NM start time */ }; -static gboolean -lookup_thread_run_cb (gpointer user_data) -{ - LookupThread *thread = (LookupThread *) user_data; - - (*thread->callback) (thread, thread->user_data); - return FALSE; -} - -static gpointer -lookup_thread_worker (gpointer data) -{ - LookupThread *thread = (LookupThread *) data; - struct sockaddr_in addr; - - g_mutex_lock (thread->lock); - if (thread->die) { - g_mutex_unlock (thread->lock); - return (gpointer) NULL; - } - g_mutex_unlock (thread->lock); - - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = thread->ip4_addr; - - thread->ret = getnameinfo ((struct sockaddr *) &addr, sizeof (struct sockaddr_in), - thread->hostname, NI_MAXHOST, NULL, 0, - NI_NAMEREQD); - if (thread->ret == 0) { - int i; - - for (i = 0; i < strlen (thread->hostname); i++) - thread->hostname[i] = tolower (thread->hostname[i]); - } - - /* Don't track the idle handler ID because by the time the g_idle_add() - * returns the ID, the handler may already have run and freed the - * LookupThread. - */ - g_idle_add (lookup_thread_run_cb, thread); - return (gpointer) TRUE; -} - -static void -lookup_thread_free (LookupThread *thread) -{ - g_return_if_fail (thread != NULL); - - g_mutex_free (thread->lock); - memset (thread, 0, sizeof (LookupThread)); - g_free (thread); -} - -static LookupThread * -lookup_thread_new (guint32 ip4_addr, LookupCallback callback, gpointer user_data) -{ - LookupThread *thread; - - thread = g_malloc0 (sizeof (LookupThread)); - if (!thread) - return NULL; - - thread->lock = g_mutex_new (); - thread->callback = callback; - thread->user_data = user_data; - thread->ip4_addr = ip4_addr; - - thread->thread = g_thread_create (lookup_thread_worker, thread, FALSE, NULL); - if (!thread->thread) { - lookup_thread_free (thread); - return NULL; - } - - return thread; -} - -static void -lookup_thread_die (LookupThread *thread) -{ - g_return_if_fail (thread != NULL); - - g_mutex_lock (thread->lock); - thread->die = TRUE; - g_mutex_unlock (thread->lock); -} - #define INVALID_TAG "invalid" static const char * @@ -253,142 +150,34 @@ get_best_device (NMManager *manager, NMActRequest **out_req) return best; } -#define FALLBACK_HOSTNAME "localhost.localdomain" - -static gboolean -update_etc_hosts (const char *hostname, gboolean *out_changed) -{ - char *contents = NULL; - char **lines = NULL; - GError *error = NULL; - GString *new_contents = NULL; - gsize contents_len = 0; - gboolean success = FALSE; - - g_return_val_if_fail (hostname != NULL, FALSE); - g_return_val_if_fail (out_changed != NULL, FALSE); - - if (!g_file_get_contents (SYSCONFDIR "/hosts", &contents, &contents_len, &error)) { - nm_log_warn (LOGD_DNS, "couldn't read " SYSCONFDIR "/hosts: (%d) %s", - error ? error->code : 0, - (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - return FALSE; - } - - /* Get the new /etc/hosts contents */ - lines = g_strsplit_set (contents, "\n\r", 0); - new_contents = nm_policy_get_etc_hosts ((const char **) lines, - contents_len, - hostname, - FALLBACK_HOSTNAME, - &error); - g_strfreev (lines); - g_free (contents); - - if (new_contents) { - nm_log_info (LOGD_DNS, "Updating /etc/hosts with new system hostname"); - - g_clear_error (&error); - /* And actually update /etc/hosts */ - if (!g_file_set_contents (SYSCONFDIR "/hosts", new_contents->str, -1, &error)) { - nm_log_warn (LOGD_DNS, "couldn't update " SYSCONFDIR "/hosts: (%d) %s", - error ? error->code : 0, - (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - } else { - success = TRUE; - *out_changed = TRUE; - } - - g_string_free (new_contents, TRUE); - } else if (!error) { - /* No change required */ - success = TRUE; - } else { - nm_log_warn (LOGD_DNS, "couldn't read " SYSCONFDIR "/hosts: (%d) %s", - error->code, error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } - - return success; -} - static void -set_system_hostname (const char *new_hostname, const char *msg) +_set_hostname (const char *new_hostname, const char *msg) { - char old_hostname[HOST_NAME_MAX + 1]; - int ret = 0; - const char *name = new_hostname ? new_hostname : FALLBACK_HOSTNAME; - gboolean set_hostname = TRUE, changed = FALSE; - - old_hostname[HOST_NAME_MAX] = '\0'; - errno = 0; - ret = gethostname (old_hostname, HOST_NAME_MAX); - if (ret != 0) { - nm_log_warn (LOGD_DNS, "couldn't get the system hostname: (%d) %s", - errno, strerror (errno)); - } else { - /* Don't set the hostname if it isn't actually changing */ - if ( (new_hostname && !strcmp (old_hostname, new_hostname)) - || (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME))) - set_hostname = FALSE; - } - - if (set_hostname) { - nm_log_info (LOGD_DNS, "Setting system hostname to '%s' (%s)", name, msg); - ret = sethostname (name, strlen (name)); - if (ret != 0) { - nm_log_warn (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s", - name, errno, strerror (errno)); - return; - } - } - - /* But still always try updating /etc/hosts just in case the hostname - * changed while NM wasn't running; we need to make sure that /etc/hosts - * has valid mappings for '127.0.0.1' and the current system hostname. If - * those exist, update_etc_hosts() will just return and won't touch - * /etc/hosts at all. - */ - if (!update_etc_hosts (name, &changed)) { - /* error updating /etc/hosts; fallback to localhost.localdomain */ - nm_log_info (LOGD_DNS, "Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)"); - ret = sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME)); - if (ret != 0) { - nm_log_warn (LOGD_DNS, "couldn't set the fallback system hostname (%s): (%d) %s", - FALLBACK_HOSTNAME, errno, strerror (errno)); - } - } - - if (changed) + if (nm_policy_set_system_hostname (new_hostname, msg)) nm_utils_call_dispatcher ("hostname", NULL, NULL, NULL); } static void -lookup_callback (LookupThread *thread, gpointer user_data) +lookup_callback (HostnameThread *thread, + int result, + const char *hostname, + gpointer user_data) { NMPolicy *policy = (NMPolicy *) user_data; + char *msg; - /* If the thread was told to die or it's not the current in-progress - * hostname lookup, nothing to do. - */ - if (thread->die || (thread != policy->lookup)) - goto done; - - policy->lookup = NULL; - if (!strlen (thread->hostname)) { - char *msg; - - /* No valid IP4 config (!!); fall back to localhost.localdomain */ - msg = g_strdup_printf ("address lookup failed: %d", thread->ret); - set_system_hostname (NULL, msg); - g_free (msg); - } else - set_system_hostname (thread->hostname, "from address lookup"); - -done: - lookup_thread_free (thread); + /* Update the hostname if the calling lookup thread is the in-progress one */ + if (!hostname_thread_is_dead (thread) && (thread == policy->lookup)) { + policy->lookup = NULL; + if (!hostname) { + /* No valid IP4 config (!!); fall back to localhost.localdomain */ + msg = g_strdup_printf ("address lookup failed: %d", result); + _set_hostname (NULL, msg); + g_free (msg); + } else + _set_hostname (hostname, "from address lookup"); + } + hostname_thread_free (thread); } static void @@ -403,7 +192,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) g_return_if_fail (policy != NULL); if (policy->lookup) { - lookup_thread_die (policy->lookup); + hostname_thread_kill (policy->lookup); policy->lookup = NULL; } @@ -419,7 +208,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) /* Try a persistent hostname first */ g_object_get (G_OBJECT (policy->manager), NM_MANAGER_HOSTNAME, &configured_hostname, NULL); if (configured_hostname) { - set_system_hostname (configured_hostname, "from system configuration"); + _set_hostname (configured_hostname, "from system configuration"); g_free (configured_hostname); return; } @@ -432,7 +221,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) /* No best device; fall back to original hostname or if there wasn't * one, 'localhost.localdomain' */ - set_system_hostname (policy->orig_hostname, "no default device"); + _set_hostname (policy->orig_hostname, "no default device"); return; } @@ -446,7 +235,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) /* Sanity check */ while (*p) { if (!isblank (*p++)) { - set_system_hostname (dhcp4_hostname, "from DHCP"); + _set_hostname (dhcp4_hostname, "from DHCP"); return; } } @@ -459,7 +248,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) * when NM started up. */ if (policy->orig_hostname) { - set_system_hostname (policy->orig_hostname, "from system startup"); + _set_hostname (policy->orig_hostname, "from system startup"); return; } @@ -471,7 +260,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) || (nm_ip4_config_get_num_nameservers (ip4_config) == 0) || (nm_ip4_config_get_num_addresses (ip4_config) == 0)) { /* No valid IP4 config (!!); fall back to localhost.localdomain */ - set_system_hostname (NULL, "no IPv4 config"); + _set_hostname (NULL, "no IPv4 config"); return; } @@ -479,10 +268,10 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) g_assert (addr); /* checked for > 1 address above */ /* Start the hostname lookup thread */ - policy->lookup = lookup_thread_new (nm_ip4_address_get_address (addr), lookup_callback, policy); + policy->lookup = hostname_thread_new (nm_ip4_address_get_address (addr), lookup_callback, policy); if (!policy->lookup) { /* Fall back to 'localhost.localdomain' */ - set_system_hostname (NULL, "error starting hostname thread"); + _set_hostname (NULL, "error starting hostname thread"); } } @@ -1088,7 +877,7 @@ nm_policy_destroy (NMPolicy *policy) * by the lookup thread callback. */ if (policy->lookup) { - lookup_thread_die (policy->lookup); + hostname_thread_kill (policy->lookup); policy->lookup = NULL; } From e2d28adeb058bab0d1615db136a1180d39628d57 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 10:45:01 -0700 Subject: [PATCH 019/105] core: simplify netlink monitor code a bit --- src/nm-netlink-monitor.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 918d637d72..913a5887bb 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -47,14 +47,9 @@ #include "nm-marshal.h" #include "nm-netlink.h" -#define NM_NETLINK_MONITOR_EVENT_CONDITIONS \ - ((GIOCondition) (G_IO_IN | G_IO_PRI)) - -#define NM_NETLINK_MONITOR_ERROR_CONDITIONS \ - ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) - -#define NM_NETLINK_MONITOR_DISCONNECT_CONDITIONS \ - ((GIOCondition) (G_IO_HUP)) +#define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) +#define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) +#define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP)) #define NM_NETLINK_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ NM_TYPE_NETLINK_MONITOR, \ @@ -374,9 +369,7 @@ nm_netlink_monitor_attach (NMNetlinkMonitor *monitor) g_return_if_fail (priv->event_id == 0); priv->event_id = g_io_add_watch (priv->io_channel, - (NM_NETLINK_MONITOR_EVENT_CONDITIONS | - NM_NETLINK_MONITOR_ERROR_CONDITIONS | - NM_NETLINK_MONITOR_DISCONNECT_CONDITIONS), + (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS), nm_netlink_monitor_event_handler, monitor); } @@ -450,12 +443,12 @@ nm_netlink_monitor_event_handler (GIOChannel *channel, priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); g_return_val_if_fail (priv->event_id > 0, TRUE); - if (io_condition & NM_NETLINK_MONITOR_ERROR_CONDITIONS) + if (io_condition & ERROR_CONDITIONS) return nm_netlink_monitor_error_handler (channel, io_condition, monitor); - else if (io_condition & NM_NETLINK_MONITOR_DISCONNECT_CONDITIONS) + else if (io_condition & DISCONNECT_CONDITIONS) return nm_netlink_monitor_disconnect_handler (channel, io_condition, monitor); - g_return_val_if_fail (!(io_condition & ~(NM_NETLINK_MONITOR_EVENT_CONDITIONS)), FALSE); + g_return_val_if_fail (!(io_condition & ~EVENT_CONDITIONS), FALSE); if (nl_recvmsgs_default (priv->nlh) < 0) { error = g_error_new (NM_NETLINK_MONITOR_ERROR, @@ -482,7 +475,7 @@ nm_netlink_monitor_error_handler (GIOChannel *channel, int err_code; socklen_t err_len; - g_return_val_if_fail (io_condition & NM_NETLINK_MONITOR_ERROR_CONDITIONS, FALSE); + g_return_val_if_fail (io_condition & ERROR_CONDITIONS, FALSE); err_code = 0; err_len = sizeof (err_code); @@ -512,7 +505,7 @@ nm_netlink_monitor_disconnect_handler (GIOChannel *channel, NMNetlinkMonitor *monitor) { - g_return_val_if_fail (!(io_condition & ~(NM_NETLINK_MONITOR_DISCONNECT_CONDITIONS)), FALSE); + g_return_val_if_fail (!(io_condition & ~DISCONNECT_CONDITIONS), FALSE); return FALSE; } From 3da6854f1f0be5599ce3ecd0c9b749b08fac5909 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 10:55:40 -0700 Subject: [PATCH 020/105] core: more netlink monitor cleanup and reorg --- src/nm-netlink-monitor.c | 145 ++++++++++++++------------------------- 1 file changed, 51 insertions(+), 94 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 913a5887bb..a984ebe236 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -66,18 +66,6 @@ typedef struct { guint request_status_id; } NMNetlinkMonitorPrivate; -static gboolean nm_netlink_monitor_event_handler (GIOChannel *channel, - GIOCondition io_condition, - gpointer user_data); - -static gboolean nm_netlink_monitor_error_handler (GIOChannel *channel, - GIOCondition io_condition, - NMNetlinkMonitor *monitor); - -static gboolean nm_netlink_monitor_disconnect_handler (GIOChannel *channel, - GIOCondition io_condition, - NMNetlinkMonitor *monitor); - enum { CARRIER_ON = 0, CARRIER_OFF, @@ -232,6 +220,56 @@ netlink_event_input (struct nl_msg *msg, void *arg) return NL_STOP; } +static gboolean +event_handler (GIOChannel *channel, + GIOCondition io_condition, + gpointer user_data) +{ + NMNetlinkMonitor *monitor = (NMNetlinkMonitor *) user_data; + NMNetlinkMonitorPrivate *priv; + GError *error = NULL; + + g_return_val_if_fail (NM_IS_NETLINK_MONITOR (monitor), TRUE); + + priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); + g_return_val_if_fail (priv->event_id > 0, TRUE); + + if (io_condition & ERROR_CONDITIONS) { + const char *err_msg; + int err_code = 0; + socklen_t err_len = sizeof (err_code); + + /* Grab error information */ + if (getsockopt (g_io_channel_unix_get_fd (channel), + SOL_SOCKET, SO_ERROR, (void *) &err_code, &err_len)) + err_msg = strerror (err_code); + else + err_msg = _("error occurred while waiting for data on socket"); + + error = g_error_new (NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA, + "%s", err_msg); + g_signal_emit (monitor, signals[ERROR], 0, error); + g_error_free (error); + return TRUE; + } else if (io_condition & DISCONNECT_CONDITIONS) + return FALSE; + + g_return_val_if_fail (!(io_condition & ~EVENT_CONDITIONS), FALSE); + + /* Process the netlink messages */ + if (nl_recvmsgs_default (priv->nlh) < 0) { + error = g_error_new (NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE, + _("error processing netlink message: %s"), + nl_geterror ()); + g_signal_emit (G_OBJECT (monitor), signals[ERROR], 0, error); + g_error_free (error); + } + + return TRUE; +} + gboolean nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, GError **error) @@ -370,8 +408,7 @@ nm_netlink_monitor_attach (NMNetlinkMonitor *monitor) priv->event_id = g_io_add_watch (priv->io_channel, (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS), - nm_netlink_monitor_event_handler, - monitor); + event_handler, monitor); } void @@ -429,86 +466,6 @@ nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor, return TRUE; } -static gboolean -nm_netlink_monitor_event_handler (GIOChannel *channel, - GIOCondition io_condition, - gpointer user_data) -{ - NMNetlinkMonitor *monitor = (NMNetlinkMonitor *) user_data; - NMNetlinkMonitorPrivate *priv; - GError *error = NULL; - - g_return_val_if_fail (NM_IS_NETLINK_MONITOR (monitor), TRUE); - - priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); - g_return_val_if_fail (priv->event_id > 0, TRUE); - - if (io_condition & ERROR_CONDITIONS) - return nm_netlink_monitor_error_handler (channel, io_condition, monitor); - else if (io_condition & DISCONNECT_CONDITIONS) - return nm_netlink_monitor_disconnect_handler (channel, io_condition, monitor); - - g_return_val_if_fail (!(io_condition & ~EVENT_CONDITIONS), FALSE); - - if (nl_recvmsgs_default (priv->nlh) < 0) { - error = g_error_new (NM_NETLINK_MONITOR_ERROR, - NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE, - _("error processing netlink message: %s"), - nl_geterror ()); - - g_signal_emit (G_OBJECT (monitor), - signals[ERROR], - 0, error); - g_error_free (error); - } - - return TRUE; -} - -static gboolean -nm_netlink_monitor_error_handler (GIOChannel *channel, - GIOCondition io_condition, - NMNetlinkMonitor *monitor) -{ - GError *socket_error; - const char *err_msg; - int err_code; - socklen_t err_len; - - g_return_val_if_fail (io_condition & ERROR_CONDITIONS, FALSE); - - err_code = 0; - err_len = sizeof (err_code); - if (getsockopt (g_io_channel_unix_get_fd (channel), - SOL_SOCKET, SO_ERROR, (void *) &err_code, &err_len)) - err_msg = strerror (err_code); - else - err_msg = _("error occurred while waiting for data on socket"); - - socket_error = g_error_new (NM_NETLINK_MONITOR_ERROR, - NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA, - "%s", - err_msg); - - g_signal_emit (G_OBJECT (monitor), - signals[ERROR], - 0, socket_error); - - g_error_free (socket_error); - - return TRUE; -} - -static gboolean -nm_netlink_monitor_disconnect_handler (GIOChannel *channel, - GIOCondition io_condition, - NMNetlinkMonitor *monitor) -{ - - g_return_val_if_fail (!(io_condition & ~DISCONNECT_CONDITIONS), FALSE); - return FALSE; -} - typedef struct { NMNetlinkMonitor *self; struct rtnl_link *filter; From cadc56abc80b62b328ff345f22a3642e124c4740 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 15:22:36 -0700 Subject: [PATCH 021/105] netlink: loosen sender checks to allow other multicast messages We need the IFLA_PROTINFO messages, and these are apparently sent (still by the kernel) but with our own PID. So the current checks that limit the netlink PID to zero block these messages out. Instead (like udev) we should be checking the actual sender of the message usign unix socket credentials. Second, at least at this point only privileged processes can send netlink multicast messages, so as long as the: * the other end of the socket is UID 0 AND * the netlink PID is 0 OR * the message is multicast and sent to our netlink PID the we accept the message and process it as normal. For another example of this, see 'netlink.c' from the dhcp6s program; do a Google search for "IFLA_PROTINFO" to find it. --- src/nm-netlink-monitor.c | 45 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index a984ebe236..2f11ff154e 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -25,6 +25,9 @@ * Copyright (C) 2004 Novell, Inc. */ +/* for struct ucred */ +#include + #include #include #include @@ -209,15 +212,41 @@ out: static int netlink_event_input (struct nl_msg *msg, void *arg) { + NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg); + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); struct nlmsghdr *hdr = nlmsg_hdr (msg); + struct ucred *creds = nlmsg_get_creds (msg); + guint32 local_port; + gboolean accept_msg = FALSE; - if (hdr->nlmsg_pid != 0) + /* Only messages sent from the kernel */ + if (!creds || creds->uid != 0) { + nm_log_dbg (LOGD_HW, "ignoring netlink message from UID %d", + creds ? creds->uid : -1); return NL_STOP; + } + + /* Accept any messages from the kernel */ + if (hdr->nlmsg_pid == 0) + accept_msg = TRUE; + + /* And any multicast message directed to our netlink PID, since multicast + * currently requires CAP_ADMIN to use. + */ + local_port = nl_socket_get_local_port (priv->nlh); + if ((hdr->nlmsg_pid == local_port) && (hdr->nlmsg_flags & NLM_F_MULTI)) + accept_msg = TRUE; + + if (accept_msg == FALSE) { + nm_log_dbg (LOGD_HW, "ignoring netlink message from PID %d (local PID %d, multicast %d)", + hdr->nlmsg_pid, + local_port, + (hdr->nlmsg_flags & NLM_F_MULTI)); + return NL_STOP; + } nl_msg_parse (msg, &netlink_object_message_handler, arg); - - /* Stop processing messages */ - return NL_STOP; + return NL_SKIP; } static gboolean @@ -304,6 +333,14 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, goto error; } + if (nl_set_passcred (priv->nlh, 1) < 0) { + g_set_error (error, NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, + _("unable to enable netlink handle credential passing: %s"), + nl_geterror ()); + goto error; + } + if (nl_socket_add_membership (priv->nlh, RTNLGRP_LINK) < 0) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP, From dd3848ea458f3c88f0d347336a97d4d8095fe06f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 15:31:54 -0700 Subject: [PATCH 022/105] netlink: move generic GObject stuff to the bottom --- src/nm-netlink-monitor.c | 189 ++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 94 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 2f11ff154e..df56cd7d53 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -81,89 +81,6 @@ static guint signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (NMNetlinkMonitor, nm_netlink_monitor, G_TYPE_OBJECT); -NMNetlinkMonitor * -nm_netlink_monitor_get (void) -{ - static NMNetlinkMonitor *singleton = NULL; - - if (!singleton) - singleton = NM_NETLINK_MONITOR (g_object_new (NM_TYPE_NETLINK_MONITOR, NULL)); - else - g_object_ref (singleton); - - return singleton; -} - -static void -nm_netlink_monitor_init (NMNetlinkMonitor *monitor) -{ -} - -static void -finalize (GObject *object) -{ - NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (object); - - if (priv->request_status_id) - g_source_remove (priv->request_status_id); - - if (priv->io_channel) - nm_netlink_monitor_close_connection (NM_NETLINK_MONITOR (object)); - - if (priv->nlh_link_cache) { - nl_cache_free (priv->nlh_link_cache); - priv->nlh_link_cache = NULL; - } - - if (priv->nlh) { - nl_handle_destroy (priv->nlh); - priv->nlh = NULL; - } - - if (priv->nlh_cb) { - nl_cb_put (priv->nlh_cb); - priv->nlh_cb = NULL; - } - - G_OBJECT_CLASS (nm_netlink_monitor_parent_class)->finalize (object); -} - -static void -nm_netlink_monitor_class_init (NMNetlinkMonitorClass *monitor_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (monitor_class); - - g_type_class_add_private (monitor_class, sizeof (NMNetlinkMonitorPrivate)); - - /* Virtual methods */ - object_class->finalize = finalize; - - /* Signals */ - signals[CARRIER_ON] = - g_signal_new ("carrier-on", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_on), - NULL, NULL, g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - signals[CARRIER_OFF] = - g_signal_new ("carrier-off", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_off), - NULL, NULL, g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); - - signals[ERROR] = - g_signal_new ("error", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMNetlinkMonitorClass, error), - NULL, NULL, _nm_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); -} - static void netlink_object_message_handler (struct nl_object *obj, void *arg) { @@ -421,17 +338,6 @@ nm_netlink_monitor_close_connection (NMNetlinkMonitor *monitor) priv->io_channel = NULL; } -GQuark -nm_netlink_monitor_error_quark (void) -{ - static GQuark error_quark = 0; - - if (error_quark == 0) - error_quark = g_quark_from_static_string ("nm-netlink-monitor-error-quark"); - - return error_quark; -} - void nm_netlink_monitor_attach (NMNetlinkMonitor *monitor) { @@ -591,3 +497,98 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self, return TRUE; /* success */ } +/***************************************************************/ + +NMNetlinkMonitor * +nm_netlink_monitor_get (void) +{ + static NMNetlinkMonitor *singleton = NULL; + + if (!singleton) + singleton = NM_NETLINK_MONITOR (g_object_new (NM_TYPE_NETLINK_MONITOR, NULL)); + else + g_object_ref (singleton); + + return singleton; +} + +static void +nm_netlink_monitor_init (NMNetlinkMonitor *monitor) +{ +} + +static void +finalize (GObject *object) +{ + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (object); + + if (priv->request_status_id) + g_source_remove (priv->request_status_id); + + if (priv->io_channel) + nm_netlink_monitor_close_connection (NM_NETLINK_MONITOR (object)); + + if (priv->nlh_link_cache) { + nl_cache_free (priv->nlh_link_cache); + priv->nlh_link_cache = NULL; + } + + if (priv->nlh) { + nl_handle_destroy (priv->nlh); + priv->nlh = NULL; + } + + if (priv->nlh_cb) { + nl_cb_put (priv->nlh_cb); + priv->nlh_cb = NULL; + } + + G_OBJECT_CLASS (nm_netlink_monitor_parent_class)->finalize (object); +} + +static void +nm_netlink_monitor_class_init (NMNetlinkMonitorClass *monitor_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (monitor_class); + + g_type_class_add_private (monitor_class, sizeof (NMNetlinkMonitorPrivate)); + + /* Virtual methods */ + object_class->finalize = finalize; + + /* Signals */ + signals[CARRIER_ON] = + g_signal_new ("carrier-on", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_on), + NULL, NULL, g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + + signals[CARRIER_OFF] = + g_signal_new ("carrier-off", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_off), + NULL, NULL, g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); + + signals[ERROR] = + g_signal_new ("error", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMNetlinkMonitorClass, error), + NULL, NULL, _nm_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); +} + +GQuark +nm_netlink_monitor_error_quark (void) +{ + static GQuark error_quark = 0; + + if (G_UNLIKELY (error_quark == 0)) + error_quark = g_quark_from_static_string ("nm-netlink-monitor-error-quark"); + return error_quark; +} + From 6695eb7423cb1393c36740b8ce6a73d9ff6a7ebe Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 15:54:55 -0700 Subject: [PATCH 023/105] netlink: let clients get netlink message for generic parsing First step on the way to killing the IPv6-specific netlink listener. --- src/nm-netlink-monitor.c | 49 ++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index df56cd7d53..21ea5ab3dd 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -47,7 +47,6 @@ #include "nm-system.h" #include "nm-netlink-monitor.h" #include "nm-logging.h" -#include "nm-marshal.h" #include "nm-netlink.h" #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) @@ -70,19 +69,19 @@ typedef struct { } NMNetlinkMonitorPrivate; enum { - CARRIER_ON = 0, - CARRIER_OFF, - ERROR, - - LAST_SIGNAL + NOTIFICATION = 0, + CARRIER_ON, + CARRIER_OFF, + ERROR, + LAST_SIGNAL }; - static guint signals[LAST_SIGNAL] = { 0 }; + G_DEFINE_TYPE (NMNetlinkMonitor, nm_netlink_monitor, G_TYPE_OBJECT); static void -netlink_object_message_handler (struct nl_object *obj, void *arg) +link_msg_handler (struct nl_object *obj, void *arg) { NMNetlinkMonitor *monitor = NM_NETLINK_MONITOR (arg); GError *error; @@ -97,9 +96,7 @@ netlink_object_message_handler (struct nl_object *obj, void *arg) NM_NETLINK_MONITOR_ERROR_BAD_ALLOC, _("error processing netlink message: %s"), nl_geterror ()); - g_signal_emit (G_OBJECT (monitor), - signals[ERROR], - 0, error); + g_signal_emit (G_OBJECT (monitor), signals[ERROR], 0, error); g_error_free (error); return; } @@ -162,8 +159,13 @@ netlink_event_input (struct nl_msg *msg, void *arg) return NL_STOP; } - nl_msg_parse (msg, &netlink_object_message_handler, arg); - return NL_SKIP; + /* Let clients handle generic messages */ + g_signal_emit (self, signals[NOTIFICATION], 0, msg); + + /* Parse carrier messages */ + nl_msg_parse (msg, &link_msg_handler, self); + + return NL_OK; } static gboolean @@ -250,6 +252,9 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, goto error; } + /* Enable unix socket peer credentials which we use for verifying that the + * sender of the message is actually the kernel. + */ if (nl_set_passcred (priv->nlh, 1) < 0) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, @@ -381,12 +386,8 @@ deferred_emit_carrier_state (gpointer user_data) */ if (nl_cache_refill (priv->nlh, priv->nlh_link_cache)) { nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror ()); - } else { - nl_cache_foreach_filter (priv->nlh_link_cache, - NULL, - netlink_object_message_handler, - monitor); - } + } else + nl_cache_foreach_filter (priv->nlh_link_cache, NULL, link_msg_handler, monitor); return FALSE; } @@ -557,6 +558,14 @@ nm_netlink_monitor_class_init (NMNetlinkMonitorClass *monitor_class) object_class->finalize = finalize; /* Signals */ + signals[NOTIFICATION] = + g_signal_new ("notification", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMNetlinkMonitorClass, notification), + NULL, NULL, g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, G_TYPE_POINTER); + signals[CARRIER_ON] = g_signal_new ("carrier-on", G_OBJECT_CLASS_TYPE (object_class), @@ -578,7 +587,7 @@ nm_netlink_monitor_class_init (NMNetlinkMonitorClass *monitor_class) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMNetlinkMonitorClass, error), - NULL, NULL, _nm_marshal_VOID__POINTER, + NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); } From 952745d4d341e2a83f850db89563ad94975b63a8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 15:59:18 -0700 Subject: [PATCH 024/105] netlink: add header part of 6695eb7423cb1393c36740b8ce6a73d9ff6a7ebe --- src/nm-netlink-monitor.h | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h index 115eccaaa3..06bbe572db 100644 --- a/src/nm-netlink-monitor.h +++ b/src/nm-netlink-monitor.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2008 Red Hat, Inc. + * Copyright (C) 2005 - 2010 Red Hat, Inc. * Copyright (C) 2005 - 2008 Novell, Inc. * Copyright (C) 2005 Ray Strode */ @@ -25,16 +25,14 @@ #include #include +#include -G_BEGIN_DECLS - -#define NM_TYPE_NETLINK_MONITOR (nm_netlink_monitor_get_type ()) -#define NM_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitor)) +#define NM_TYPE_NETLINK_MONITOR (nm_netlink_monitor_get_type ()) +#define NM_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitor)) #define NM_NETLINK_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitorClass)) -#define NM_IS_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETLINK_MONITOR)) +#define NM_IS_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETLINK_MONITOR)) #define NM_IS_NETLINK_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_NETLINK_MONITOR)) #define NM_NETLINK_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitorClass)) -#define NM_NETLINK_MONITOR_ERROR (nm_netlink_monitor_error_quark ()) typedef enum { NM_NETLINK_MONITOR_ERROR_GENERIC = 0, @@ -56,29 +54,29 @@ typedef struct { GObjectClass parent_class; /* Signals */ - void (*carrier_on) (NMNetlinkMonitor *monitor, int index); - void (*carrier_off) (NMNetlinkMonitor *monitor, int index); - void (*error) (NMNetlinkMonitor *monitor, GError *error); + void (*notification) (NMNetlinkMonitor *monitor, struct nl_msg *msg); + void (*carrier_on) (NMNetlinkMonitor *monitor, int index); + void (*carrier_off) (NMNetlinkMonitor *monitor, int index); + void (*error) (NMNetlinkMonitor *monitor, GError *error); } NMNetlinkMonitorClass; -GType nm_netlink_monitor_get_type (void) G_GNUC_CONST; -GQuark nm_netlink_monitor_error_quark (void) G_GNUC_CONST; +#define NM_NETLINK_MONITOR_ERROR (nm_netlink_monitor_error_quark ()) +GType nm_netlink_monitor_get_type (void) G_GNUC_CONST; +GQuark nm_netlink_monitor_error_quark (void) G_GNUC_CONST; NMNetlinkMonitor *nm_netlink_monitor_get (void); gboolean nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, - GError **error); + GError **error); void nm_netlink_monitor_close_connection (NMNetlinkMonitor *monitor); -void nm_netlink_monitor_attach (NMNetlinkMonitor *monitor); -void nm_netlink_monitor_detach (NMNetlinkMonitor *monitor); +void nm_netlink_monitor_attach (NMNetlinkMonitor *monitor); +void nm_netlink_monitor_detach (NMNetlinkMonitor *monitor); gboolean nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor, - GError **error); + GError **error); gboolean nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *monitor, guint32 ifindex, guint32 *ifflags, GError **error); -G_END_DECLS - #endif /* NM_NETLINK_MONITOR_H */ From b3d833746514050696826c6ff5a0b80bd80bd85f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 15:59:50 -0700 Subject: [PATCH 025/105] netlink: s/monitor/self --- src/nm-netlink-monitor.c | 71 ++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 21ea5ab3dd..4a6818dc13 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -83,7 +83,7 @@ G_DEFINE_TYPE (NMNetlinkMonitor, nm_netlink_monitor, G_TYPE_OBJECT); static void link_msg_handler (struct nl_object *obj, void *arg) { - NMNetlinkMonitor *monitor = NM_NETLINK_MONITOR (arg); + NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg); GError *error; struct rtnl_link *filter; struct rtnl_link *link_obj; @@ -96,7 +96,7 @@ link_msg_handler (struct nl_object *obj, void *arg) NM_NETLINK_MONITOR_ERROR_BAD_ALLOC, _("error processing netlink message: %s"), nl_geterror ()); - g_signal_emit (G_OBJECT (monitor), signals[ERROR], 0, error); + g_signal_emit (self, signals[ERROR], 0, error); g_error_free (error); return; } @@ -115,9 +115,9 @@ link_msg_handler (struct nl_object *obj, void *arg) * b00055aacdb172c05067612278ba27265fcd05ce in 2.6.17. */ if (flags & IFF_LOWER_UP) - g_signal_emit (G_OBJECT (monitor), signals[CARRIER_ON], 0, ifidx); + g_signal_emit (self, signals[CARRIER_ON], 0, ifidx); else - g_signal_emit (G_OBJECT (monitor), signals[CARRIER_OFF], 0, ifidx); + g_signal_emit (self, signals[CARRIER_OFF], 0, ifidx); out: rtnl_link_put (filter); @@ -173,13 +173,13 @@ event_handler (GIOChannel *channel, GIOCondition io_condition, gpointer user_data) { - NMNetlinkMonitor *monitor = (NMNetlinkMonitor *) user_data; + NMNetlinkMonitor *self = (NMNetlinkMonitor *) user_data; NMNetlinkMonitorPrivate *priv; GError *error = NULL; - g_return_val_if_fail (NM_IS_NETLINK_MONITOR (monitor), TRUE); + g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), TRUE); - priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); g_return_val_if_fail (priv->event_id > 0, TRUE); if (io_condition & ERROR_CONDITIONS) { @@ -197,7 +197,7 @@ event_handler (GIOChannel *channel, error = g_error_new (NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA, "%s", err_msg); - g_signal_emit (monitor, signals[ERROR], 0, error); + g_signal_emit (self, signals[ERROR], 0, error); g_error_free (error); return TRUE; } else if (io_condition & DISCONNECT_CONDITIONS) @@ -211,7 +211,7 @@ event_handler (GIOChannel *channel, NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE, _("error processing netlink message: %s"), nl_geterror ()); - g_signal_emit (G_OBJECT (monitor), signals[ERROR], 0, error); + g_signal_emit (self, signals[ERROR], 0, error); g_error_free (error); } @@ -219,17 +219,17 @@ event_handler (GIOChannel *channel, } gboolean -nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, - GError **error) +nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) { NMNetlinkMonitorPrivate *priv; - int fd; GError *channel_error = NULL; GIOFlags channel_flags; + int fd; - g_return_val_if_fail (NM_IS_NETLINK_MONITOR (monitor), FALSE); + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); - priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); g_return_val_if_fail (priv->io_channel == NULL, FALSE); priv->nlh_cb = nl_cb_alloc (NL_CB_VERBOSE); @@ -243,7 +243,7 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, } nl_disable_sequence_check (priv->nlh); - nl_socket_modify_cb (priv->nlh, NL_CB_VALID, NL_CB_CUSTOM, netlink_event_input, monitor); + nl_socket_modify_cb (priv->nlh, NL_CB_VALID, NL_CB_CUSTOM, netlink_event_input, self); if (nl_connect (priv->nlh, NETLINK_ROUTE) < 0) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, @@ -303,7 +303,7 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, error: if (priv->io_channel) - nm_netlink_monitor_close_connection (monitor); + nm_netlink_monitor_close_connection (self); if (priv->nlh_link_cache) { nl_cache_free (priv->nlh_link_cache); @@ -323,17 +323,17 @@ error: } void -nm_netlink_monitor_close_connection (NMNetlinkMonitor *monitor) +nm_netlink_monitor_close_connection (NMNetlinkMonitor *self) { NMNetlinkMonitorPrivate *priv; - g_return_if_fail (NM_IS_NETLINK_MONITOR (monitor)); + g_return_if_fail (NM_IS_NETLINK_MONITOR (self)); - priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); g_return_if_fail (priv->io_channel != NULL); if (priv->event_id) - nm_netlink_monitor_detach (monitor); + nm_netlink_monitor_detach (self); g_io_channel_shutdown (priv->io_channel, TRUE /* flush pending data */, @@ -344,29 +344,29 @@ nm_netlink_monitor_close_connection (NMNetlinkMonitor *monitor) } void -nm_netlink_monitor_attach (NMNetlinkMonitor *monitor) +nm_netlink_monitor_attach (NMNetlinkMonitor *self) { NMNetlinkMonitorPrivate *priv; - g_return_if_fail (NM_IS_NETLINK_MONITOR (monitor)); + g_return_if_fail (NM_IS_NETLINK_MONITOR (self)); - priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); g_return_if_fail (priv->nlh != NULL); g_return_if_fail (priv->event_id == 0); priv->event_id = g_io_add_watch (priv->io_channel, (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS), - event_handler, monitor); + event_handler, self); } void -nm_netlink_monitor_detach (NMNetlinkMonitor *monitor) +nm_netlink_monitor_detach (NMNetlinkMonitor *self) { NMNetlinkMonitorPrivate *priv; - g_return_if_fail (NM_IS_NETLINK_MONITOR (monitor)); + g_return_if_fail (NM_IS_NETLINK_MONITOR (self)); - priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); g_return_if_fail (priv->event_id > 0); g_source_remove (priv->event_id); @@ -376,8 +376,8 @@ nm_netlink_monitor_detach (NMNetlinkMonitor *monitor) static gboolean deferred_emit_carrier_state (gpointer user_data) { - NMNetlinkMonitor *monitor = NM_NETLINK_MONITOR (user_data); - NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); + NMNetlinkMonitor *self = NM_NETLINK_MONITOR (user_data); + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); priv->request_status_id = 0; @@ -387,25 +387,24 @@ deferred_emit_carrier_state (gpointer user_data) if (nl_cache_refill (priv->nlh, priv->nlh_link_cache)) { nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror ()); } else - nl_cache_foreach_filter (priv->nlh_link_cache, NULL, link_msg_handler, monitor); + nl_cache_foreach_filter (priv->nlh_link_cache, NULL, link_msg_handler, self); return FALSE; } gboolean -nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor, - GError **error) +nm_netlink_monitor_request_status (NMNetlinkMonitor *self, GError **error) { NMNetlinkMonitorPrivate *priv; - g_return_val_if_fail (NM_IS_NETLINK_MONITOR (monitor), FALSE); + g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); - priv = NM_NETLINK_MONITOR_GET_PRIVATE (monitor); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); g_return_val_if_fail (priv->event_id > 0, FALSE); /* Schedule the carrier state emission */ if (!priv->request_status_id) - priv->request_status_id = g_idle_add (deferred_emit_carrier_state, monitor); + priv->request_status_id = g_idle_add (deferred_emit_carrier_state, self); return TRUE; } @@ -514,7 +513,7 @@ nm_netlink_monitor_get (void) } static void -nm_netlink_monitor_init (NMNetlinkMonitor *monitor) +nm_netlink_monitor_init (NMNetlinkMonitor *self) { } From d1c7c37863711f34b62f637e842ea3c24cab86e7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 16:32:03 -0700 Subject: [PATCH 026/105] netlink: implement generic group subscription Needed by the IPv6 manager. --- src/nm-netlink-monitor.c | 86 +++++++++++++++++++++++++++++++++++++--- src/nm-netlink-monitor.h | 12 +++++- 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 4a6818dc13..b807d5c37c 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -66,6 +66,8 @@ typedef struct { guint event_id; guint request_status_id; + + GHashTable *subscriptions; } NMNetlinkMonitorPrivate; enum { @@ -263,13 +265,9 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) goto error; } - if (nl_socket_add_membership (priv->nlh, RTNLGRP_LINK) < 0) { - g_set_error (error, NM_NETLINK_MONITOR_ERROR, - NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP, - _("unable to join netlink group for monitoring link status: %s"), - nl_geterror ()); + /* Subscribe to the LINK group for internal carrier signals */ + if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error)) goto error; - } if ((priv->nlh_link_cache = rtnl_link_alloc_cache (priv->nlh)) == NULL) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, @@ -373,6 +371,77 @@ nm_netlink_monitor_detach (NMNetlinkMonitor *self) priv->event_id = 0; } +static int +get_subs (NMNetlinkMonitor *self, int group) +{ + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + return GPOINTER_TO_INT (g_hash_table_lookup (priv->subscriptions, + GINT_TO_POINTER (group))); +} + +static void +set_subs (NMNetlinkMonitor *self, int group, int new_subs) +{ + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + g_hash_table_insert (priv->subscriptions, + GINT_TO_POINTER (group), + GINT_TO_POINTER (new_subs)); +} + +gboolean +nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error) +{ + NMNetlinkMonitorPrivate *priv; + int subs; + + g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); + + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + if (!priv->nlh) { + if (!nm_netlink_monitor_open_connection (self, error)) + return FALSE; + } + + subs = get_subs (self, group) + 1; + if (subs == 1) { + if (nl_socket_add_membership (priv->nlh, group) < 0) { + g_set_error (error, NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP, + _("unable to join netlink group: %s"), + nl_geterror ()); + return FALSE; + } + } + + /* Update # of subscriptions for this group */ + set_subs (self, group, subs); + + return TRUE; +} + +void +nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *self, int group) +{ + NMNetlinkMonitorPrivate *priv; + int subs; + + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_NETLINK_MONITOR (self)); + + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + g_return_if_fail (priv->nlh != NULL); + + subs = get_subs (self, group) - 1; + if (subs == 0) + nl_socket_drop_membership (priv->nlh, group); + + /* Update # of subscriptions for this group */ + set_subs (self, group, subs); +} + static gboolean deferred_emit_carrier_state (gpointer user_data) { @@ -515,6 +584,9 @@ nm_netlink_monitor_get (void) static void nm_netlink_monitor_init (NMNetlinkMonitor *self) { + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + priv->subscriptions = g_hash_table_new (g_int_hash, g_int_equal); } static void @@ -543,6 +615,8 @@ finalize (GObject *object) priv->nlh_cb = NULL; } + g_hash_table_destroy (priv->subscriptions); + G_OBJECT_CLASS (nm_netlink_monitor_parent_class)->finalize (object); } diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h index 06bbe572db..1920704a79 100644 --- a/src/nm-netlink-monitor.h +++ b/src/nm-netlink-monitor.h @@ -67,11 +67,19 @@ GQuark nm_netlink_monitor_error_quark (void) G_GNUC_CONST; NMNetlinkMonitor *nm_netlink_monitor_get (void); -gboolean nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, - GError **error); +gboolean nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, + GError **error); void nm_netlink_monitor_close_connection (NMNetlinkMonitor *monitor); void nm_netlink_monitor_attach (NMNetlinkMonitor *monitor); void nm_netlink_monitor_detach (NMNetlinkMonitor *monitor); + +gboolean nm_netlink_monitor_subscribe (NMNetlinkMonitor *monitor, + int group, + GError **error); +void nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *monitor, + int group); + + gboolean nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor, GError **error); gboolean nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *monitor, From 9476355be2cd2e5c7554f3a403403da82fe02696 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 16:33:55 -0700 Subject: [PATCH 027/105] trivial: remove dead CFLAGS --- src/Makefile.am | 2 -- src/ip6-manager/Makefile.am | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ca1ce6bbd2..80336ab060 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -210,9 +210,7 @@ BUILT_SOURCES = \ NetworkManager_CPPFLAGS = \ $(DBUS_CFLAGS) \ $(GLIB_CFLAGS) \ - $(HAL_CFLAGS) \ $(GUDEV_CFLAGS) \ - $(OPENSSL_CFLAGS) \ $(LIBNL_CFLAGS) \ $(GMODULE_CFLAGS) \ -DG_DISABLE_DEPRECATED \ diff --git a/src/ip6-manager/Makefile.am b/src/ip6-manager/Makefile.am index 9f5229f77b..39d77155f7 100644 --- a/src/ip6-manager/Makefile.am +++ b/src/ip6-manager/Makefile.am @@ -18,7 +18,6 @@ libip6_manager_la_SOURCES = \ libip6_manager_la_CPPFLAGS = \ $(DBUS_CFLAGS) \ $(GLIB_CFLAGS) \ - $(HAL_CFLAGS) \ -DG_DISABLE_DEPRECATED libip6_manager_la_LIBADD = \ From 5b8b9fc608f28d22ceb91d9a8b6cd8a5bd2c805a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 16:46:08 -0700 Subject: [PATCH 028/105] netlink: fix IPv6 RA flag retrieval The RA flags aren't in the link flags, they are in the special PROTINFO flags that the IPv6 stack sends. To get these, because libnl doesn't have native support for them, we get to parse the netlink messages directly. Furthermore, the PROTINFO message isn't sent unless it's explicitly requested with a RTM_GETLINK/AF_INET6 message, meaning we get to poll for it periodically. So switch over to the netlink monitor object (killing a lot of duplicate code) and start requesting the PROTINFO bits from netlink. --- src/ip6-manager/Makefile.am | 4 +- src/ip6-manager/nm-ip6-manager.c | 106 +++++-- src/ip6-manager/nm-netlink-listener.c | 406 -------------------------- src/ip6-manager/nm-netlink-listener.h | 78 ----- src/nm-netlink-monitor.c | 22 ++ src/nm-netlink-monitor.h | 2 + 6 files changed, 103 insertions(+), 515 deletions(-) delete mode 100644 src/ip6-manager/nm-netlink-listener.c delete mode 100644 src/ip6-manager/nm-netlink-listener.h diff --git a/src/ip6-manager/Makefile.am b/src/ip6-manager/Makefile.am index 39d77155f7..c2f5591429 100644 --- a/src/ip6-manager/Makefile.am +++ b/src/ip6-manager/Makefile.am @@ -11,9 +11,7 @@ noinst_LTLIBRARIES = libip6-manager.la libip6_manager_la_SOURCES = \ nm-ip6-manager.c \ - nm-ip6-manager.h \ - nm-netlink-listener.c \ - nm-netlink-listener.h + nm-ip6-manager.h libip6_manager_la_CPPFLAGS = \ $(DBUS_CFLAGS) \ diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index be85ab0dc0..04a3049464 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -25,7 +25,8 @@ #include #include "nm-ip6-manager.h" -#include "nm-netlink-listener.h" +#include "nm-netlink-monitor.h" +#include "nm-netlink.h" #include "NetworkManagerUtils.h" #include "nm-marshal.h" #include "nm-logging.h" @@ -40,7 +41,7 @@ #define IF_RS_SENT 0x10 typedef struct { - NMNetlinkListener *netlink; + NMNetlinkMonitor *monitor; GHashTable *devices_by_iface, *devices_by_index; struct nl_handle *nlh; @@ -82,6 +83,8 @@ typedef struct { GArray *rdnss_servers; guint rdnss_timeout_id; + + guint32 ra_flags; } NMIP6Device; G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT) @@ -96,7 +99,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; static NMIP6Manager *nm_ip6_manager_new (void); -static void netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer user_data); +static void netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data); static void nm_ip6_device_destroy (NMIP6Device *device); @@ -122,12 +125,14 @@ nm_ip6_manager_init (NMIP6Manager *manager) (GDestroyNotify) nm_ip6_device_destroy); priv->devices_by_index = g_hash_table_new (NULL, NULL); - priv->netlink = nm_netlink_listener_get (); - g_signal_connect (priv->netlink, "notification", - G_CALLBACK (netlink_notification), manager); - nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_IPV6_IFADDR, NULL); - nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_IPV6_PREFIX, NULL); - nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_ND_USEROPT, NULL); + priv->monitor = nm_netlink_monitor_get (); + nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL); + nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL); + nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL); + nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL); + + g_signal_connect (priv->monitor, "notification", + G_CALLBACK (netlink_notification), manager); priv->nlh = nm_netlink_get_default_handle (); priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh); @@ -141,7 +146,7 @@ finalize (GObject *object) g_hash_table_destroy (priv->devices_by_iface); g_hash_table_destroy (priv->devices_by_index); - g_object_unref (priv->netlink); + g_object_unref (priv->monitor); nl_cache_free (priv->addr_cache); nl_cache_free (priv->route_cache); @@ -348,8 +353,6 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; - struct rtnl_link *link; - guint flags; CallbackInfo *info; guint dhcp_opts = IP6_DHCP_OPT_NONE; @@ -373,21 +376,16 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) } } - /* Note: we don't want to keep a cache of links, because the - * kernel doesn't send notifications when the flags change, so the - * cached rtnl_links would have out-of-date flags. - */ - link = nm_netlink_index_to_rtnl_link (device->index); - flags = rtnl_link_get_flags (link); - rtnl_link_put (link); - - if ((flags & IF_RA_RCVD) && device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) + if ((device->ra_flags & IF_RA_RCVD) && device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT; - if (flags & IF_RA_MANAGED) + if (device->ra_flags & IF_RA_MANAGED) { dhcp_opts = IP6_DHCP_OPT_MANAGED; - else if (flags & IF_RA_OTHERCONF) + nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6"); + } else if (device->ra_flags & IF_RA_OTHERCONF) { dhcp_opts = IP6_DHCP_OPT_OTHERCONF; + nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6"); + } if (!device->addrconf_complete) { if (device->state >= device->target_state || @@ -598,8 +596,58 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) return NULL; } +static struct nla_policy link_policy[IFLA_MAX + 1] = { + [IFLA_PROTINFO] = { .type = NLA_NESTED }, +}; + +static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = { + [IFLA_INET6_FLAGS] = { .type = NLA_U32 }, +}; + +static NMIP6Device * +process_newlink (NMIP6Manager *manager, struct nl_msg *msg) +{ + struct nlmsghdr *hdr = nlmsg_hdr (msg); + struct ifinfomsg *ifi; + NMIP6Device *device; + struct nlattr *tb[IFLA_MAX + 1]; + struct nlattr *pi[IFLA_INET6_MAX + 1]; + int err; + + ifi = nlmsg_data (hdr); + if (ifi->ifi_family != AF_INET6) + return NULL; + + device = nm_ip6_manager_get_device (manager, ifi->ifi_index); + if (!device || device->addrconf_complete) + return NULL; + + /* FIXME: we have to do this manually for now since libnl doesn't yet + * support the IFLA_PROTINFO attribute of NEWLINK messages. When it does, + * we can get rid of this function and just grab IFLA_PROTINFO from + * nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of + * the PROTINFO. + */ + + err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy); + if (err < 0) + return NULL; + if (!tb[IFLA_PROTINFO]) + return NULL; + + err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy); + if (err < 0) + return NULL; + if (!pi[IFLA_INET6_FLAGS]) + return NULL; + + device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]); + + return device; +} + static void -netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer user_data) +netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data) { NMIP6Manager *manager = (NMIP6Manager *) user_data; NMIP6Device *device; @@ -613,22 +661,22 @@ netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer device = process_addr (manager, msg); config_changed = TRUE; break; - case RTM_NEWROUTE: case RTM_DELROUTE: device = process_route (manager, msg); config_changed = TRUE; break; - case RTM_NEWPREFIX: device = process_prefix (manager, msg); break; - case RTM_NEWNDUSEROPT: device = process_nduseropt (manager, msg); config_changed = TRUE; break; - + case RTM_NEWLINK: + device = process_newlink (manager, msg); + config_changed = TRUE; + break; default: return; } @@ -758,6 +806,7 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", iface); device->addrconf_complete = FALSE; + device->ra_flags = 0; /* Set up a timeout on the transaction to kill it after the timeout */ info = callback_info_new (device, 0); @@ -771,6 +820,7 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, * device is already fully configured and schedule the * ADDRCONF_COMPLETE signal in that case. */ + nm_netlink_monitor_request_ip6_info (priv->monitor, NULL); nm_ip6_device_sync_from_netlink (device, FALSE); } diff --git a/src/ip6-manager/nm-netlink-listener.c b/src/ip6-manager/nm-netlink-listener.c deleted file mode 100644 index 55c4d76ad4..0000000000 --- a/src/ip6-manager/nm-netlink-listener.c +++ /dev/null @@ -1,406 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2005 - 2009 Red Hat, Inc. - * Copyright (C) 2005 - 2008 Novell, Inc. - * Copyright (C) 2005 Ray Strode - * - * Some code borrowed from HAL: - * - * Copyright (C) 2003 David Zeuthen, - * Copyright (C) 2004 Novell, Inc. - */ - -/* FIXME: this should be merged with src/nm-netlink-monitor.c */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "NetworkManager.h" -#include "nm-system.h" -#include "nm-netlink-listener.h" -#include "nm-marshal.h" -#include "nm-netlink.h" - -#define NM_NETLINK_LISTENER_EVENT_CONDITIONS \ - ((GIOCondition) (G_IO_IN | G_IO_PRI)) - -#define NM_NETLINK_LISTENER_ERROR_CONDITIONS \ - ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) - -#define NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS \ - ((GIOCondition) (G_IO_HUP)) - -#define NM_NETLINK_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ - NM_TYPE_NETLINK_LISTENER, \ - NMNetlinkListenerPrivate)) - -typedef struct { - struct nl_handle *nlh; - struct nl_cb * nlh_cb; - struct nl_cache * nlh_link_cache; - - GIOChannel * io_channel; - guint event_id; - - guint request_status_id; -} NMNetlinkListenerPrivate; - -static gboolean nm_netlink_listener_event_handler (GIOChannel *channel, - GIOCondition io_condition, - gpointer user_data); - -static gboolean nm_netlink_listener_error_handler (GIOChannel *channel, - GIOCondition io_condition, - NMNetlinkListener *listener); - -static gboolean nm_netlink_listener_disconnect_handler (GIOChannel *channel, - GIOCondition io_condition, - NMNetlinkListener *listener); - -static void close_connection (NMNetlinkListener *listener); - -enum { - NOTIFICATION = 0, - ERROR, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (NMNetlinkListener, nm_netlink_listener, G_TYPE_OBJECT); - -NMNetlinkListener * -nm_netlink_listener_get (void) -{ - static NMNetlinkListener *singleton = NULL; - - if (!singleton) - singleton = NM_NETLINK_LISTENER (g_object_new (NM_TYPE_NETLINK_LISTENER, NULL)); - else - g_object_ref (singleton); - - return singleton; -} - -static void -nm_netlink_listener_init (NMNetlinkListener *listener) -{ -} - -static void -finalize (GObject *object) -{ - NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (object); - - if (priv->request_status_id) - g_source_remove (priv->request_status_id); - - if (priv->io_channel) - close_connection (NM_NETLINK_LISTENER (object)); - - if (priv->nlh) { - nl_handle_destroy (priv->nlh); - priv->nlh = NULL; - } - - if (priv->nlh_cb) { - nl_cb_put (priv->nlh_cb); - priv->nlh_cb = NULL; - } - - G_OBJECT_CLASS (nm_netlink_listener_parent_class)->finalize (object); -} - -static void -nm_netlink_listener_class_init (NMNetlinkListenerClass *listener_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (listener_class); - - g_type_class_add_private (listener_class, sizeof (NMNetlinkListenerPrivate)); - - /* Virtual methods */ - object_class->finalize = finalize; - - /* Signals */ - signals[NOTIFICATION] = - g_signal_new ("notification", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMNetlinkListenerClass, notification), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[ERROR] = - g_signal_new ("error", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMNetlinkListenerClass, error), - NULL, NULL, _nm_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); -} - -static int -netlink_event_input (struct nl_msg *msg, void *listener) -{ - struct nlmsghdr *hdr = nlmsg_hdr (msg); - - if (hdr->nlmsg_pid != 0) - return NL_STOP; - - g_signal_emit (listener, signals[NOTIFICATION], 0, msg); - - /* Stop processing messages */ - return NL_STOP; -} - -static gboolean -open_connection (NMNetlinkListener *listener, GError **error) -{ - NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener); - int fd; - GError *channel_error = NULL; - GIOFlags channel_flags; - - g_return_val_if_fail (priv->io_channel == NULL, FALSE); - - priv->nlh_cb = nl_cb_alloc (NL_CB_DEFAULT); - priv->nlh = nl_handle_alloc_cb (priv->nlh_cb); - if (!priv->nlh) { - g_set_error (error, NM_NETLINK_LISTENER_ERROR, - NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_HANDLE, - _("unable to allocate netlink handle: %s"), - nl_geterror ()); - goto error; - } - - nl_disable_sequence_check (priv->nlh); - nl_socket_modify_cb (priv->nlh, NL_CB_VALID, NL_CB_CUSTOM, netlink_event_input, listener); - if (nl_connect (priv->nlh, NETLINK_ROUTE) < 0) { - g_set_error (error, NM_NETLINK_LISTENER_ERROR, - NM_NETLINK_LISTENER_ERROR_NETLINK_CONNECT, - _("unable to connect to netlink: %s"), - nl_geterror ()); - goto error; - } - - fd = nl_socket_get_fd (priv->nlh); - priv->io_channel = g_io_channel_unix_new (fd); - - g_io_channel_set_encoding (priv->io_channel, NULL, &channel_error); - /* Encoding is NULL, so no conversion error can possibly occur */ - g_assert (channel_error == NULL); - - g_io_channel_set_close_on_unref (priv->io_channel, TRUE); - channel_flags = g_io_channel_get_flags (priv->io_channel); - channel_error = NULL; - g_io_channel_set_flags (priv->io_channel, - channel_flags | G_IO_FLAG_NONBLOCK, - &channel_error); - if (channel_error != NULL) { - g_propagate_error (error, channel_error); - goto error; - } - - priv->event_id = g_io_add_watch (priv->io_channel, - (NM_NETLINK_LISTENER_EVENT_CONDITIONS | - NM_NETLINK_LISTENER_ERROR_CONDITIONS | - NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS), - nm_netlink_listener_event_handler, - listener); - return TRUE; - -error: - if (priv->io_channel) - close_connection (listener); - - if (priv->nlh) { - nl_handle_destroy (priv->nlh); - priv->nlh = NULL; - } - - if (priv->nlh_cb) { - nl_cb_put (priv->nlh_cb); - priv->nlh_cb = NULL; - } - return FALSE; -} - -static void -close_connection (NMNetlinkListener *listener) -{ - NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener); - - g_return_if_fail (priv->io_channel != NULL); - - if (priv->event_id) { - g_source_remove (priv->event_id); - priv->event_id = 0; - } - - g_io_channel_shutdown (priv->io_channel, - TRUE /* flush pending data */, - NULL); - - g_io_channel_unref (priv->io_channel); - priv->io_channel = NULL; -} - -GQuark -nm_netlink_listener_error_quark (void) -{ - static GQuark error_quark = 0; - - if (error_quark == 0) - error_quark = g_quark_from_static_string ("nm-netlink-listener-error-quark"); - - return error_quark; -} - -gboolean -nm_netlink_listener_subscribe (NMNetlinkListener *listener, - int group, - GError **error) -{ - NMNetlinkListenerPrivate *priv; - - g_return_val_if_fail (NM_IS_NETLINK_LISTENER (listener), FALSE); - - priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener); - - if (!priv->nlh) { - if (!open_connection (listener, error)) - return FALSE; - } - - if (nl_socket_add_membership (priv->nlh, group) < 0) { - g_set_error (error, NM_NETLINK_LISTENER_ERROR, - NM_NETLINK_LISTENER_ERROR_NETLINK_JOIN_GROUP, - _("unable to join netlink group: %s"), - nl_geterror ()); - return FALSE; - } - - return TRUE; -} - -void -nm_netlink_listener_unsubscribe (NMNetlinkListener *listener, int group) -{ - NMNetlinkListenerPrivate *priv; - - g_return_if_fail (NM_IS_NETLINK_LISTENER (listener)); - - priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener); - g_return_if_fail (priv->nlh != NULL); - - nl_socket_drop_membership (priv->nlh, group); -} - -static gboolean -nm_netlink_listener_event_handler (GIOChannel *channel, - GIOCondition io_condition, - gpointer user_data) -{ - NMNetlinkListener *listener = (NMNetlinkListener *) user_data; - NMNetlinkListenerPrivate *priv; - GError *error = NULL; - - g_return_val_if_fail (NM_IS_NETLINK_LISTENER (listener), TRUE); - - priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener); - g_return_val_if_fail (priv->event_id > 0, TRUE); - - if (io_condition & NM_NETLINK_LISTENER_ERROR_CONDITIONS) - return nm_netlink_listener_error_handler (channel, io_condition, listener); - else if (io_condition & NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS) - return nm_netlink_listener_disconnect_handler (channel, io_condition, listener); - - g_return_val_if_fail (!(io_condition & ~(NM_NETLINK_LISTENER_EVENT_CONDITIONS)), FALSE); - - if (nl_recvmsgs_default (priv->nlh) < 0) { - error = g_error_new (NM_NETLINK_LISTENER_ERROR, - NM_NETLINK_LISTENER_ERROR_PROCESSING_MESSAGE, - _("error processing netlink message: %s"), - nl_geterror ()); - - g_signal_emit (G_OBJECT (listener), - signals[ERROR], - 0, error); - g_error_free (error); - } - - return TRUE; -} - -static gboolean -nm_netlink_listener_error_handler (GIOChannel *channel, - GIOCondition io_condition, - NMNetlinkListener *listener) -{ - GError *socket_error; - const char *err_msg; - int err_code; - socklen_t err_len; - - g_return_val_if_fail (io_condition & NM_NETLINK_LISTENER_ERROR_CONDITIONS, FALSE); - - err_code = 0; - err_len = sizeof (err_code); - if (getsockopt (g_io_channel_unix_get_fd (channel), - SOL_SOCKET, SO_ERROR, (void *) &err_code, &err_len)) - err_msg = strerror (err_code); - else - err_msg = _("error occurred while waiting for data on socket"); - - socket_error = g_error_new (NM_NETLINK_LISTENER_ERROR, - NM_NETLINK_LISTENER_ERROR_WAITING_FOR_SOCKET_DATA, - "%s", - err_msg); - - g_signal_emit (G_OBJECT (listener), - signals[ERROR], - 0, socket_error); - - g_error_free (socket_error); - - return TRUE; -} - -static gboolean -nm_netlink_listener_disconnect_handler (GIOChannel *channel, - GIOCondition io_condition, - NMNetlinkListener *listener) -{ - - g_return_val_if_fail (!(io_condition & ~(NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS)), FALSE); - return FALSE; -} - diff --git a/src/ip6-manager/nm-netlink-listener.h b/src/ip6-manager/nm-netlink-listener.h deleted file mode 100644 index 0baabac004..0000000000 --- a/src/ip6-manager/nm-netlink-listener.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Netlink socket listener - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2005 - 2009 Red Hat, Inc. - * Copyright (C) 2005 - 2008 Novell, Inc. - * Copyright (C) 2005 Ray Strode - */ - -#ifndef NM_NETLINK_LISTENER_H -#define NM_NETLINK_LISTENER_H - -#include -#include - -#include "nm-netlink.h" - -G_BEGIN_DECLS - -#define NM_TYPE_NETLINK_LISTENER (nm_netlink_listener_get_type ()) -#define NM_NETLINK_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETLINK_LISTENER, NMNetlinkListener)) -#define NM_NETLINK_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NETLINK_LISTENER, NMNetlinkListenerClass)) -#define NM_IS_NETLINK_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETLINK_LISTENER)) -#define NM_IS_NETLINK_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_NETLINK_LISTENER)) -#define NM_NETLINK_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_NETLINK_LISTENER, NMNetlinkListenerClass)) -#define NM_NETLINK_LISTENER_ERROR (nm_netlink_listener_error_quark ()) - -typedef enum { - NM_NETLINK_LISTENER_ERROR_GENERIC = 0, - NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_HANDLE, - NM_NETLINK_LISTENER_ERROR_NETLINK_CONNECT, - NM_NETLINK_LISTENER_ERROR_NETLINK_JOIN_GROUP, - NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_LINK_CACHE, - NM_NETLINK_LISTENER_ERROR_PROCESSING_MESSAGE, - NM_NETLINK_LISTENER_ERROR_BAD_ALLOC, - NM_NETLINK_LISTENER_ERROR_WAITING_FOR_SOCKET_DATA, - NM_NETLINK_LISTENER_ERROR_LINK_CACHE_UPDATE -} NMNetlinkListenerError; - -typedef struct { - GObject parent; -} NMNetlinkListener; - -typedef struct { - GObjectClass parent_class; - - /* Signals */ - void (*notification) (NMNetlinkListener *listener, struct nl_msg *msg); - void (*error) (NMNetlinkListener *listener, GError *error); -} NMNetlinkListenerClass; - -GType nm_netlink_listener_get_type (void) G_GNUC_CONST; -GQuark nm_netlink_listener_error_quark (void) G_GNUC_CONST; - -NMNetlinkListener *nm_netlink_listener_get (void); - -gboolean nm_netlink_listener_subscribe (NMNetlinkListener *listener, - int group, - GError **error); -void nm_netlink_listener_unsubscribe (NMNetlinkListener *listener, - int group); - -G_END_DECLS - -#endif /* NM_NETLINK_LISTENER_H */ diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index b807d5c37c..24b463ce33 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -442,6 +442,28 @@ nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *self, int group) set_subs (self, group, subs); } +/***************************************************************/ + +gboolean +nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *self, GError **error) +{ + NMNetlinkMonitorPrivate *priv; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); + + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + /* FIXME: nl_rtgen_request() gets the return value screwed up with + * libnl-1.1; revisit this and return a proper error when we port to + * a later libnl. + */ + nl_rtgen_request (priv->nlh, RTM_GETLINK, AF_INET6, NLM_F_DUMP); + + return TRUE; +} + + static gboolean deferred_emit_carrier_state (gpointer user_data) { diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h index 1920704a79..a2b26e6b3b 100644 --- a/src/nm-netlink-monitor.h +++ b/src/nm-netlink-monitor.h @@ -79,6 +79,8 @@ gboolean nm_netlink_monitor_subscribe (NMNetlinkMonitor *monitor void nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *monitor, int group); +gboolean nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *monitor, + GError **error); gboolean nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor, GError **error); From d85583b928a64dbd16a23af819ffff3f201b26a0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 16:53:05 -0700 Subject: [PATCH 029/105] po: remove dead translatable --- po/POTFILES.in | 1 - 1 file changed, 1 deletion(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 2cf4d231c8..6cf236ad37 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -14,7 +14,6 @@ src/nm-netlink-monitor.c src/main.c src/dhcp-manager/nm-dhcp-dhclient.c src/dhcp-manager/nm-dhcp-manager.c -src/ip6-manager/nm-netlink-listener.c src/logging/nm-logging.c src/named-manager/nm-named-manager.c src/system-settings/nm-default-wired-connection.c From f722b180e2fa36709bcb6ec5eda31aae5db8c4dc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 16:55:13 -0700 Subject: [PATCH 030/105] trivial: netlink header cleanup --- src/ip6-manager/nm-ip6-manager.c | 1 + src/nm-device-ethernet.c | 2 ++ src/nm-netlink.c | 1 + src/nm-netlink.h | 3 --- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 04a3049464..0ce694dcf6 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index f4581e9ac6..00942a3d34 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -34,6 +34,8 @@ #include #include +#include + #include "nm-glib-compat.h" #include "nm-device-ethernet.h" #include "nm-device-interface.h" diff --git a/src/nm-netlink.c b/src/nm-netlink.c index c55c093ae8..15eb6c1c34 100644 --- a/src/nm-netlink.c +++ b/src/nm-netlink.c @@ -28,6 +28,7 @@ #include #include #include +#include static struct nl_cache * link_cache = NULL; static struct nl_handle * def_nl_handle = NULL; diff --git a/src/nm-netlink.h b/src/nm-netlink.h index 7b5e1ba573..b77cbf566f 100644 --- a/src/nm-netlink.h +++ b/src/nm-netlink.h @@ -21,10 +21,7 @@ #ifndef NM_NETLINK_H #define NM_NETLINK_H -#include -#include #include -#include #include int nm_netlink_iface_to_index (const char *iface); From 87c6e5db76d8b56656ea26d91bf63f8781c530f2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 17:22:58 -0700 Subject: [PATCH 031/105] netlink: merge nm-netlink.c into nm-netlink-monitor.c --- src/Makefile.am | 2 - src/backends/NetworkManagerGeneric.c | 9 +- src/ip6-manager/nm-ip6-manager.c | 1 - src/nm-device-ethernet.c | 1 - src/nm-device.c | 2 +- src/nm-netlink-monitor.c | 138 ++++++++++++++++++++---- src/nm-netlink-monitor.h | 7 ++ src/nm-netlink.c | 150 --------------------------- src/nm-netlink.h | 33 ------ src/nm-system.c | 2 +- src/vpn-manager/nm-vpn-connection.c | 2 +- 11 files changed, 129 insertions(+), 218 deletions(-) delete mode 100644 src/nm-netlink.c delete mode 100644 src/nm-netlink.h diff --git a/src/Makefile.am b/src/Makefile.am index 80336ab060..5d2db6e36d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -141,8 +141,6 @@ NetworkManager_SOURCES = \ nm-properties-changed-signal.h \ wpa.c \ wpa.h \ - nm-netlink.c \ - nm-netlink.h \ nm-dhcp4-config.c \ nm-dhcp4-config.h \ nm-dhcp6-config.c \ diff --git a/src/backends/NetworkManagerGeneric.c b/src/backends/NetworkManagerGeneric.c index 4f8336d9bb..8f16066fa3 100644 --- a/src/backends/NetworkManagerGeneric.c +++ b/src/backends/NetworkManagerGeneric.c @@ -1,9 +1,5 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager - * - * Timothee Lecomte - * - * Heavily based on NetworkManagerRedhat.c by Dan Williams * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +15,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * (C) Copyright 2004 Red Hat, Inc. + * (C) Copyright 2004 - 2010 Red Hat, Inc. + * (C) Copyright 2006 Timothee Lecomte */ #ifdef HAVE_CONFIG_H @@ -36,8 +33,8 @@ #include "NetworkManagerGeneric.h" #include "nm-system.h" #include "NetworkManagerUtils.h" -#include "nm-netlink.h" #include "nm-logging.h" +#include "nm-netlink-monitor.h" /* Because of a bug in libnl, rtnl.h should be included before route.h */ #include diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 0ce694dcf6..50905c3af5 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -27,7 +27,6 @@ #include "nm-ip6-manager.h" #include "nm-netlink-monitor.h" -#include "nm-netlink.h" #include "NetworkManagerUtils.h" #include "nm-marshal.h" #include "nm-logging.h" diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index 00942a3d34..202584b24b 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -45,7 +45,6 @@ #include "nm-supplicant-manager.h" #include "nm-supplicant-interface.h" #include "nm-supplicant-config.h" -#include "nm-netlink.h" #include "nm-netlink-monitor.h" #include "nm-system.h" #include "nm-setting-connection.h" diff --git a/src/nm-device.c b/src/nm-device.c index 1ee7510321..db0ad914a9 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -45,7 +45,7 @@ #include "nm-named-manager.h" #include "nm-utils.h" #include "nm-logging.h" -#include "nm-netlink.h" +#include "nm-netlink-monitor.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" #include "nm-setting-connection.h" diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 24b463ce33..bfcbab7e7f 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -25,7 +25,7 @@ * Copyright (C) 2004 Novell, Inc. */ -/* for struct ucred */ +/* for struct ucred and LIBNL_NEEDS_ADDR_CACHING_WORKAROUND */ #include #include @@ -38,16 +38,15 @@ #include #include #include -#include +#include +#include +#include #include #include -#include "NetworkManager.h" -#include "nm-system.h" #include "nm-netlink-monitor.h" #include "nm-logging.h" -#include "nm-netlink.h" #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) #define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) @@ -60,7 +59,7 @@ typedef struct { struct nl_handle *nlh; struct nl_cb * nlh_cb; - struct nl_cache * nlh_link_cache; + struct nl_cache * link_cache; GIOChannel * io_channel; guint event_id; @@ -104,8 +103,10 @@ link_msg_handler (struct nl_object *obj, void *arg) } /* Ensure it's a link object */ - if (nl_object_match_filter(obj, OBJ_CAST (filter)) == 0) - goto out; + if (nl_object_match_filter(obj, OBJ_CAST (filter)) == 0) { + rtnl_link_put (filter); + return; + } link_obj = (struct rtnl_link *) obj; flags = rtnl_link_get_flags (link_obj); @@ -121,7 +122,6 @@ link_msg_handler (struct nl_object *obj, void *arg) else g_signal_emit (self, signals[CARRIER_OFF], 0, ifidx); -out: rtnl_link_put (filter); } @@ -227,6 +227,9 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) GError *channel_error = NULL; GIOFlags channel_flags; int fd; +#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND + struct nl_cache *addr_cache; +#endif g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); @@ -265,11 +268,23 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) goto error; } +#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND + /* Work around apparent libnl bug; rtnl_addr requires that all + * addresses have the "peer" attribute set in order to be compared + * for equality, but this attribute is not normally set. As a + * result, most addresses will not compare as equal even to + * themselves, busting caching. + */ + addr_cache = rtnl_addr_alloc_cache (priv->nlh); + nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80; + nl_cache_free (addr_cache); +#endif + /* Subscribe to the LINK group for internal carrier signals */ if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error)) goto error; - if ((priv->nlh_link_cache = rtnl_link_alloc_cache (priv->nlh)) == NULL) { + if ((priv->link_cache = rtnl_link_alloc_cache (priv->nlh)) == NULL) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE, _("unable to allocate netlink link cache for monitoring link status: %s"), @@ -277,7 +292,7 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) goto error; } - nl_cache_mngt_provide (priv->nlh_link_cache); + nl_cache_mngt_provide (priv->link_cache); fd = nl_socket_get_fd (priv->nlh); priv->io_channel = g_io_channel_unix_new (fd); @@ -303,9 +318,9 @@ error: if (priv->io_channel) nm_netlink_monitor_close_connection (self); - if (priv->nlh_link_cache) { - nl_cache_free (priv->nlh_link_cache); - priv->nlh_link_cache = NULL; + if (priv->link_cache) { + nl_cache_free (priv->link_cache); + priv->link_cache = NULL; } if (priv->nlh) { @@ -475,10 +490,10 @@ deferred_emit_carrier_state (gpointer user_data) /* Update the link cache with latest state, and if there are no errors * emit the link states for all the interfaces in the cache. */ - if (nl_cache_refill (priv->nlh, priv->nlh_link_cache)) { + if (nl_cache_refill (priv->nlh, priv->link_cache)) { nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror ()); } else - nl_cache_foreach_filter (priv->nlh_link_cache, NULL, link_msg_handler, self); + nl_cache_foreach_filter (priv->link_cache, NULL, link_msg_handler, self); return FALSE; } @@ -534,7 +549,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self, priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); /* Update the link cache with the latest information */ - if (nl_cache_refill (priv->nlh, priv->nlh_link_cache)) { + if (nl_cache_refill (priv->nlh, priv->link_cache)) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE, @@ -547,7 +562,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self, * otherwise some kernels (or maybe libnl?) only send a few of the * interfaces in the refill request. */ - if (nl_cache_refill (priv->nlh, priv->nlh_link_cache)) { + if (nl_cache_refill (priv->nlh, priv->link_cache)) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE, @@ -572,7 +587,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self, info.self = self; info.filter = filter; info.error = NULL; - nl_cache_foreach_filter (priv->nlh_link_cache, NULL, get_flags_sync_cb, &info); + nl_cache_foreach_filter (priv->link_cache, NULL, get_flags_sync_cb, &info); rtnl_link_put (filter); @@ -590,6 +605,85 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self, /***************************************************************/ +struct nl_handle * +nm_netlink_get_default_handle (void) +{ + NMNetlinkMonitor *self; + struct nl_handle *nlh; + + self = nm_netlink_monitor_get (); + nlh = NM_NETLINK_MONITOR_GET_PRIVATE (self)->nlh; + g_object_unref (self); + + return nlh; +} + +int +nm_netlink_iface_to_index (const char *iface) +{ + NMNetlinkMonitor *self; + NMNetlinkMonitorPrivate *priv; + int idx; + + g_return_val_if_fail (iface != NULL, -1); + + self = nm_netlink_monitor_get (); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + nl_cache_update (priv->nlh, priv->link_cache); + idx = rtnl_link_name2i (priv->link_cache, iface); + g_object_unref (self); + + return idx; +} + +#define MAX_IFACE_LEN 33 +char * +nm_netlink_index_to_iface (int idx) +{ + NMNetlinkMonitor *self; + NMNetlinkMonitorPrivate *priv; + char *buf = NULL; + + g_return_val_if_fail (idx >= 0, NULL); + + self = nm_netlink_monitor_get (); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + buf = g_malloc0 (MAX_IFACE_LEN); + g_assert (buf); + + nl_cache_update (priv->nlh, priv->link_cache); + if (!rtnl_link_i2name (priv->link_cache, idx, buf, MAX_IFACE_LEN - 1)) { + g_free (buf); + buf = NULL; + } + + g_object_unref (self); + return buf; +} + +struct rtnl_link * +nm_netlink_index_to_rtnl_link (int idx) +{ + NMNetlinkMonitor *self; + NMNetlinkMonitorPrivate *priv; + struct rtnl_link *ret = NULL; + + g_return_val_if_fail (idx >= 0, NULL); + + self = nm_netlink_monitor_get (); + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + nl_cache_update (priv->nlh, priv->link_cache); + ret = rtnl_link_get (priv->link_cache, idx); + g_object_unref (self); + + return ret; +} + +/***************************************************************/ + NMNetlinkMonitor * nm_netlink_monitor_get (void) { @@ -622,9 +716,9 @@ finalize (GObject *object) if (priv->io_channel) nm_netlink_monitor_close_connection (NM_NETLINK_MONITOR (object)); - if (priv->nlh_link_cache) { - nl_cache_free (priv->nlh_link_cache); - priv->nlh_link_cache = NULL; + if (priv->link_cache) { + nl_cache_free (priv->link_cache); + priv->link_cache = NULL; } if (priv->nlh) { diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h index a2b26e6b3b..8b57a312d7 100644 --- a/src/nm-netlink-monitor.h +++ b/src/nm-netlink-monitor.h @@ -26,6 +26,7 @@ #include #include #include +#include #define NM_TYPE_NETLINK_MONITOR (nm_netlink_monitor_get_type ()) #define NM_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitor)) @@ -89,4 +90,10 @@ gboolean nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *monitor guint32 *ifflags, GError **error); +/* Generic utility functions */ +int nm_netlink_iface_to_index (const char *iface); +char * nm_netlink_index_to_iface (int idx); +struct rtnl_link *nm_netlink_index_to_rtnl_link (int idx); +struct nl_handle *nm_netlink_get_default_handle (void); + #endif /* NM_NETLINK_MONITOR_H */ diff --git a/src/nm-netlink.c b/src/nm-netlink.c deleted file mode 100644 index 15eb6c1c34..0000000000 --- a/src/nm-netlink.c +++ /dev/null @@ -1,150 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2007 - 2008 Red Hat, Inc. - */ - -#include "config.h" - -#include "nm-netlink.h" -#include "nm-logging.h" - -#include -#include -#include -#include -#include -#include - -static struct nl_cache * link_cache = NULL; -static struct nl_handle * def_nl_handle = NULL; - - -static struct nl_cache * -get_link_cache (void) -{ - struct nl_handle * nlh; - - nlh = nm_netlink_get_default_handle (); - if (G_UNLIKELY (!nlh)) { - nm_log_err (LOGD_HW, "couldn't allocate netlink handle."); - return NULL; - } - - if (G_UNLIKELY (!link_cache)) - link_cache = rtnl_link_alloc_cache (nlh); - - if (G_UNLIKELY (!link_cache)) { - nm_log_err (LOGD_HW, "couldn't allocate netlink link cache: %s", nl_geterror ()); - return NULL; - } - - nl_cache_update (nlh, link_cache); - return link_cache; -} - - -struct nl_handle * -nm_netlink_get_default_handle (void) -{ - struct nl_cb *cb; -#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND - struct nl_cache *addr_cache; -#endif - - if (def_nl_handle) - return def_nl_handle; - - cb = nl_cb_alloc(NL_CB_VERBOSE); - def_nl_handle = nl_handle_alloc_cb (cb); - if (!def_nl_handle) { - nm_log_err (LOGD_HW, "couldn't allocate netlink handle."); - return NULL; - } - - if (nl_connect (def_nl_handle, NETLINK_ROUTE) < 0) { - nm_log_err (LOGD_HW, "couldn't connect to netlink: %s", nl_geterror ()); - return NULL; - } - -#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND - /* Work around apparent libnl bug; rtnl_addr requires that all - * addresses have the "peer" attribute set in order to be compared - * for equality, but this attribute is not normally set. As a - * result, most addresses will not compare as equal even to - * themselves, busting caching. - */ - addr_cache = rtnl_addr_alloc_cache (def_nl_handle); - nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80; - nl_cache_free (addr_cache); -#endif - - return def_nl_handle; -} - -int -nm_netlink_iface_to_index (const char *iface) -{ - struct nl_cache * cache; - - g_return_val_if_fail (iface != NULL, -1); - - cache = get_link_cache (); - if (!cache) - return RTNL_LINK_NOT_FOUND; - - return rtnl_link_name2i (cache, iface); -} - - -#define MAX_IFACE_LEN 33 -char * -nm_netlink_index_to_iface (int idx) -{ - struct nl_cache * cache; - char * buf = NULL; - - cache = get_link_cache (); - if (!cache) - return NULL; - - buf = g_malloc0 (MAX_IFACE_LEN); - if (buf == NULL) { - nm_log_warn (LOGD_HW, "Not enough memory to allocate interface name buffer."); - return NULL; - } - - if (rtnl_link_i2name (cache, idx, buf, MAX_IFACE_LEN - 1) == NULL) { - g_free (buf); - buf = NULL; - } - - return buf; -} - -struct rtnl_link * -nm_netlink_index_to_rtnl_link (int idx) -{ - struct nl_cache *cache; - - cache = get_link_cache (); - if (!cache) - return NULL; - - return rtnl_link_get (cache, idx); -} - diff --git a/src/nm-netlink.h b/src/nm-netlink.h deleted file mode 100644 index b77cbf566f..0000000000 --- a/src/nm-netlink.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2007 - 2008 Red Hat, Inc. - */ - -#ifndef NM_NETLINK_H -#define NM_NETLINK_H - -#include -#include - -int nm_netlink_iface_to_index (const char *iface); -char * nm_netlink_index_to_iface (int idx); -struct rtnl_link * nm_netlink_index_to_rtnl_link (int idx); - -struct nl_handle * nm_netlink_get_default_handle (void); - -#endif /* NM_NETLINK_H */ diff --git a/src/nm-system.c b/src/nm-system.c index bd5f57f51d..0d38ea6cf4 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -48,7 +48,7 @@ #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-logging.h" -#include "nm-netlink.h" +#include "nm-netlink-monitor.h" /* Because of a bug in libnl, rtnl.h should be included before route.h */ #include diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index a594df59b5..a714e991e8 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -45,7 +45,7 @@ #include "nm-dbus-glib-types.h" #include "NetworkManagerUtils.h" #include "nm-named-manager.h" -#include "nm-netlink.h" +#include "nm-netlink-monitor.h" #include "nm-glib-compat.h" #include "nm-vpn-connection-glue.h" From df3f09b63386fa526950e384737fc2dbabc8980d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 20 Apr 2010 17:24:49 -0700 Subject: [PATCH 032/105] netlink: fix group subscription --- src/nm-netlink-monitor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index bfcbab7e7f..09e7d7c21e 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -702,7 +702,7 @@ nm_netlink_monitor_init (NMNetlinkMonitor *self) { NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); - priv->subscriptions = g_hash_table_new (g_int_hash, g_int_equal); + priv->subscriptions = g_hash_table_new (g_direct_hash, g_direct_equal); } static void From 7cec17fcce299acb1bfebef296bf3f9a7d2de101 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Apr 2010 01:05:08 -0700 Subject: [PATCH 033/105] netlink: fix checking multicast groups Got the flags wrong in the previous commit; MULTI isn't about multicast/unicast, but about multi-part packets. Instead we need to check the netlink sockaddr structure for the group mask. --- src/nm-netlink-monitor.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 09e7d7c21e..e1bbfb86e3 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -132,6 +132,7 @@ netlink_event_input (struct nl_msg *msg, void *arg) NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); struct nlmsghdr *hdr = nlmsg_hdr (msg); struct ucred *creds = nlmsg_get_creds (msg); + const struct sockaddr_nl *snl; guint32 local_port; gboolean accept_msg = FALSE; @@ -142,15 +143,18 @@ netlink_event_input (struct nl_msg *msg, void *arg) return NL_STOP; } + snl = nlmsg_get_src (msg); + g_assert (snl); + /* Accept any messages from the kernel */ - if (hdr->nlmsg_pid == 0) + if (hdr->nlmsg_pid == 0 || snl->nl_pid == 0) accept_msg = TRUE; /* And any multicast message directed to our netlink PID, since multicast * currently requires CAP_ADMIN to use. */ local_port = nl_socket_get_local_port (priv->nlh); - if ((hdr->nlmsg_pid == local_port) && (hdr->nlmsg_flags & NLM_F_MULTI)) + if ((hdr->nlmsg_pid == local_port) && snl->nl_groups) accept_msg = TRUE; if (accept_msg == FALSE) { @@ -268,6 +272,14 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) goto error; } + if (nl_socket_recv_pktinfo (priv->nlh, 1) < 0) { + g_set_error (error, NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, + _("unable to enable netlink handle packet info: %s"), + nl_geterror ()); + goto error; + } + #ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND /* Work around apparent libnl bug; rtnl_addr requires that all * addresses have the "peer" attribute set in order to be compared @@ -292,8 +304,6 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) goto error; } - nl_cache_mngt_provide (priv->link_cache); - fd = nl_socket_get_fd (priv->nlh); priv->io_channel = g_io_channel_unix_new (fd); From 9fee99e1230580067efb33f3aaea0fddad5cfe66 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Apr 2010 14:16:07 -0700 Subject: [PATCH 034/105] netlink: provide both blocking and nonblocking netlink connections The non-blocking connection is really only good for listening for events. It doesn't work for request/response operations (like refilling link and address caches) because the message receive loop in libnl will break out from the EAGAIN before it gets the response it needs to update the cache with. This is most evident with link cache refills when requesting the interface index from the name, or vice-versa; the refill request exits early with EAGAIN (due to the non-blocking nature of the connection's socket) and the cache isn't refilled, and the index lookup fails. We need to use blocking netlink operations in quite a few places besides index lookups, from address/route operations to getting the initial device carrier state. So, split the montior's netlink connection into a non-blocking event listener connection, and a synchronous connection which gets used for immediate operations. This also has the effect of validation the synchronous operations for security, which wasn't done before in nm-netlink.c (though it wasn't really a problem). --- src/nm-netlink-monitor.c | 267 ++++++++++++++++++++++++--------------- 1 file changed, 165 insertions(+), 102 deletions(-) diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index e1bbfb86e3..6fb13ef3d1 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -57,13 +57,15 @@ NMNetlinkMonitorPrivate)) typedef struct { - struct nl_handle *nlh; - struct nl_cb * nlh_cb; - struct nl_cache * link_cache; - + /* Async event listener connection */ + struct nl_handle *nlh_event; GIOChannel * io_channel; guint event_id; + /* Sync/blocking request/response connection */ + struct nl_handle *nlh_sync; + struct nl_cache * link_cache; + guint request_status_id; GHashTable *subscriptions; @@ -103,7 +105,7 @@ link_msg_handler (struct nl_object *obj, void *arg) } /* Ensure it's a link object */ - if (nl_object_match_filter(obj, OBJ_CAST (filter)) == 0) { + if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) { rtnl_link_put (filter); return; } @@ -126,10 +128,9 @@ link_msg_handler (struct nl_object *obj, void *arg) } static int -netlink_event_input (struct nl_msg *msg, void *arg) +event_msg_recv (struct nl_msg *msg, void *arg) { - NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg); - NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + struct nl_handle *nlh = arg; struct nlmsghdr *hdr = nlmsg_hdr (msg); struct ucred *creds = nlmsg_get_creds (msg); const struct sockaddr_nl *snl; @@ -140,7 +141,7 @@ netlink_event_input (struct nl_msg *msg, void *arg) if (!creds || creds->uid != 0) { nm_log_dbg (LOGD_HW, "ignoring netlink message from UID %d", creds ? creds->uid : -1); - return NL_STOP; + return NL_SKIP; } snl = nlmsg_get_src (msg); @@ -153,7 +154,7 @@ netlink_event_input (struct nl_msg *msg, void *arg) /* And any multicast message directed to our netlink PID, since multicast * currently requires CAP_ADMIN to use. */ - local_port = nl_socket_get_local_port (priv->nlh); + local_port = nl_socket_get_local_port (nlh); if ((hdr->nlmsg_pid == local_port) && snl->nl_groups) accept_msg = TRUE; @@ -162,9 +163,21 @@ netlink_event_input (struct nl_msg *msg, void *arg) hdr->nlmsg_pid, local_port, (hdr->nlmsg_flags & NLM_F_MULTI)); - return NL_STOP; + return NL_SKIP; } + return NL_OK; +} + +static int +event_msg_ready (struct nl_msg *msg, void *arg) +{ + NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg); + + /* By the time the message gets here we've already checked the sender + * and we're sure it's safe to parse this message. + */ + /* Let clients handle generic messages */ g_signal_emit (self, signals[NOTIFICATION], 0, msg); @@ -212,7 +225,7 @@ event_handler (GIOChannel *channel, g_return_val_if_fail (!(io_condition & ~EVENT_CONDITIONS), FALSE); /* Process the netlink messages */ - if (nl_recvmsgs_default (priv->nlh) < 0) { + if (nl_recvmsgs_default (priv->nlh_event) < 0) { error = g_error_new (NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE, _("error processing netlink message: %s"), @@ -224,26 +237,55 @@ event_handler (GIOChannel *channel, return TRUE; } -gboolean -nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) +static gboolean +nlh_setup (struct nl_handle *nlh, + nl_recvmsg_msg_cb_t valid_func, + gpointer cb_data, + GError **error) { - NMNetlinkMonitorPrivate *priv; + nl_socket_modify_cb (nlh, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, cb_data); + + if (valid_func) + nl_socket_modify_cb (nlh, NL_CB_VALID, NL_CB_CUSTOM, valid_func, cb_data); + + if (nl_connect (nlh, NETLINK_ROUTE) < 0) { + g_set_error (error, NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, + _("unable to connect to netlink for monitoring link status: %s"), + nl_geterror ()); + return FALSE; + } + + /* Enable unix socket peer credentials which we use for verifying that the + * sender of the message is actually the kernel. + */ + if (nl_set_passcred (nlh, 1) < 0) { + g_set_error (error, NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, + _("unable to enable netlink handle credential passing: %s"), + nl_geterror ()); + return FALSE; + } + + return TRUE; +} + +static gboolean +event_connection_setup (NMNetlinkMonitor *self, GError **error) +{ + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); GError *channel_error = NULL; GIOFlags channel_flags; + struct nl_cb *cb; int fd; -#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND - struct nl_cache *addr_cache; -#endif - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); - - priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); g_return_val_if_fail (priv->io_channel == NULL, FALSE); - priv->nlh_cb = nl_cb_alloc (NL_CB_VERBOSE); - priv->nlh = nl_handle_alloc_cb (priv->nlh_cb); - if (!priv->nlh) { + /* Set up the event listener connection */ + cb = nl_cb_alloc (NL_CB_VERBOSE); + priv->nlh_event = nl_handle_alloc_cb (cb); + nl_cb_put (cb); + if (!priv->nlh_event) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE, _("unable to allocate netlink handle for monitoring link status: %s"), @@ -251,60 +293,16 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) goto error; } - nl_disable_sequence_check (priv->nlh); - nl_socket_modify_cb (priv->nlh, NL_CB_VALID, NL_CB_CUSTOM, netlink_event_input, self); - if (nl_connect (priv->nlh, NETLINK_ROUTE) < 0) { - g_set_error (error, NM_NETLINK_MONITOR_ERROR, - NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, - _("unable to connect to netlink for monitoring link status: %s"), - nl_geterror ()); + if (!nlh_setup (priv->nlh_event, event_msg_ready, self, error)) goto error; - } - /* Enable unix socket peer credentials which we use for verifying that the - * sender of the message is actually the kernel. - */ - if (nl_set_passcred (priv->nlh, 1) < 0) { - g_set_error (error, NM_NETLINK_MONITOR_ERROR, - NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, - _("unable to enable netlink handle credential passing: %s"), - nl_geterror ()); - goto error; - } - - if (nl_socket_recv_pktinfo (priv->nlh, 1) < 0) { - g_set_error (error, NM_NETLINK_MONITOR_ERROR, - NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT, - _("unable to enable netlink handle packet info: %s"), - nl_geterror ()); - goto error; - } - -#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND - /* Work around apparent libnl bug; rtnl_addr requires that all - * addresses have the "peer" attribute set in order to be compared - * for equality, but this attribute is not normally set. As a - * result, most addresses will not compare as equal even to - * themselves, busting caching. - */ - addr_cache = rtnl_addr_alloc_cache (priv->nlh); - nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80; - nl_cache_free (addr_cache); -#endif + nl_disable_sequence_check (priv->nlh_event); /* Subscribe to the LINK group for internal carrier signals */ if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error)) goto error; - if ((priv->link_cache = rtnl_link_alloc_cache (priv->nlh)) == NULL) { - g_set_error (error, NM_NETLINK_MONITOR_ERROR, - NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE, - _("unable to allocate netlink link cache for monitoring link status: %s"), - nl_geterror ()); - goto error; - } - - fd = nl_socket_get_fd (priv->nlh); + fd = nl_socket_get_fd (priv->nlh_event); priv->io_channel = g_io_channel_unix_new (fd); g_io_channel_set_encoding (priv->io_channel, NULL, &channel_error); @@ -328,23 +326,90 @@ error: if (priv->io_channel) nm_netlink_monitor_close_connection (self); + if (priv->nlh_event) { + nl_handle_destroy (priv->nlh_event); + priv->nlh_event = NULL; + } + + return FALSE; +} + +static gboolean +sync_connection_setup (NMNetlinkMonitor *self, GError **error) +{ + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + struct nl_cb *cb; +#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND + struct nl_cache *addr_cache; +#endif + + /* Set up the event listener connection */ + cb = nl_cb_alloc (NL_CB_VERBOSE); + priv->nlh_sync = nl_handle_alloc_cb (cb); + nl_cb_put (cb); + if (!priv->nlh_sync) { + g_set_error (error, NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE, + _("unable to allocate netlink handle for monitoring link status: %s"), + nl_geterror ()); + goto error; + } + + if (!nlh_setup (priv->nlh_sync, NULL, self, error)) + goto error; + +#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND + /* Work around apparent libnl bug; rtnl_addr requires that all + * addresses have the "peer" attribute set in order to be compared + * for equality, but this attribute is not normally set. As a + * result, most addresses will not compare as equal even to + * themselves, busting caching. + */ + addr_cache = rtnl_addr_alloc_cache (priv->nlh_sync); + nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80; + nl_cache_free (addr_cache); +#endif + + if ((priv->link_cache = rtnl_link_alloc_cache (priv->nlh_sync)) == NULL) { + g_set_error (error, NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE, + _("unable to allocate netlink link cache for monitoring link status: %s"), + nl_geterror ()); + goto error; + } + nl_cache_mngt_provide (priv->link_cache); + + return TRUE; + +error: if (priv->link_cache) { nl_cache_free (priv->link_cache); priv->link_cache = NULL; } - if (priv->nlh) { - nl_handle_destroy (priv->nlh); - priv->nlh = NULL; + if (priv->nlh_sync) { + nl_handle_destroy (priv->nlh_sync); + priv->nlh_sync = NULL; } - if (priv->nlh_cb) { - nl_cb_put (priv->nlh_cb); - priv->nlh_cb = NULL; - } return FALSE; } +gboolean +nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); + + if (!event_connection_setup (self, error)) + return FALSE; + + if (!sync_connection_setup (self, error)) + return FALSE; + + return TRUE; +} + void nm_netlink_monitor_close_connection (NMNetlinkMonitor *self) { @@ -359,9 +424,8 @@ nm_netlink_monitor_close_connection (NMNetlinkMonitor *self) nm_netlink_monitor_detach (self); g_io_channel_shutdown (priv->io_channel, - TRUE /* flush pending data */, - NULL); - + TRUE /* flush pending data */, + NULL); g_io_channel_unref (priv->io_channel); priv->io_channel = NULL; } @@ -374,7 +438,7 @@ nm_netlink_monitor_attach (NMNetlinkMonitor *self) g_return_if_fail (NM_IS_NETLINK_MONITOR (self)); priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); - g_return_if_fail (priv->nlh != NULL); + g_return_if_fail (priv->nlh_event != NULL); g_return_if_fail (priv->event_id == 0); priv->event_id = g_io_add_watch (priv->io_channel, @@ -425,14 +489,14 @@ nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error) priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); - if (!priv->nlh) { + if (!priv->nlh_event) { if (!nm_netlink_monitor_open_connection (self, error)) return FALSE; } subs = get_subs (self, group) + 1; if (subs == 1) { - if (nl_socket_add_membership (priv->nlh, group) < 0) { + if (nl_socket_add_membership (priv->nlh_event, group) < 0) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP, _("unable to join netlink group: %s"), @@ -457,11 +521,11 @@ nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *self, int group) g_return_if_fail (NM_IS_NETLINK_MONITOR (self)); priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); - g_return_if_fail (priv->nlh != NULL); + g_return_if_fail (priv->nlh_event != NULL); subs = get_subs (self, group) - 1; if (subs == 0) - nl_socket_drop_membership (priv->nlh, group); + nl_socket_drop_membership (priv->nlh_event, group); /* Update # of subscriptions for this group */ set_subs (self, group, subs); @@ -483,7 +547,7 @@ nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *self, GError **error) * libnl-1.1; revisit this and return a proper error when we port to * a later libnl. */ - nl_rtgen_request (priv->nlh, RTM_GETLINK, AF_INET6, NLM_F_DUMP); + nl_rtgen_request (priv->nlh_event, RTM_GETLINK, AF_INET6, NLM_F_DUMP); return TRUE; } @@ -500,7 +564,7 @@ deferred_emit_carrier_state (gpointer user_data) /* Update the link cache with latest state, and if there are no errors * emit the link states for all the interfaces in the cache. */ - if (nl_cache_refill (priv->nlh, priv->link_cache)) { + if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) { nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror ()); } else nl_cache_foreach_filter (priv->link_cache, NULL, link_msg_handler, self); @@ -516,7 +580,6 @@ nm_netlink_monitor_request_status (NMNetlinkMonitor *self, GError **error) g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); - g_return_val_if_fail (priv->event_id > 0, FALSE); /* Schedule the carrier state emission */ if (!priv->request_status_id) @@ -559,7 +622,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self, priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); /* Update the link cache with the latest information */ - if (nl_cache_refill (priv->nlh, priv->link_cache)) { + if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE, @@ -572,7 +635,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self, * otherwise some kernels (or maybe libnl?) only send a few of the * interfaces in the refill request. */ - if (nl_cache_refill (priv->nlh, priv->link_cache)) { + if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE, @@ -622,7 +685,7 @@ nm_netlink_get_default_handle (void) struct nl_handle *nlh; self = nm_netlink_monitor_get (); - nlh = NM_NETLINK_MONITOR_GET_PRIVATE (self)->nlh; + nlh = NM_NETLINK_MONITOR_GET_PRIVATE (self)->nlh_sync; g_object_unref (self); return nlh; @@ -640,7 +703,7 @@ nm_netlink_iface_to_index (const char *iface) self = nm_netlink_monitor_get (); priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); - nl_cache_update (priv->nlh, priv->link_cache); + nl_cache_refill (priv->nlh_sync, priv->link_cache); idx = rtnl_link_name2i (priv->link_cache, iface); g_object_unref (self); @@ -663,7 +726,7 @@ nm_netlink_index_to_iface (int idx) buf = g_malloc0 (MAX_IFACE_LEN); g_assert (buf); - nl_cache_update (priv->nlh, priv->link_cache); + nl_cache_refill (priv->nlh_sync, priv->link_cache); if (!rtnl_link_i2name (priv->link_cache, idx, buf, MAX_IFACE_LEN - 1)) { g_free (buf); buf = NULL; @@ -685,7 +748,7 @@ nm_netlink_index_to_rtnl_link (int idx) self = nm_netlink_monitor_get (); priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); - nl_cache_update (priv->nlh, priv->link_cache); + nl_cache_refill (priv->nlh_sync, priv->link_cache); ret = rtnl_link_get (priv->link_cache, idx); g_object_unref (self); @@ -731,14 +794,14 @@ finalize (GObject *object) priv->link_cache = NULL; } - if (priv->nlh) { - nl_handle_destroy (priv->nlh); - priv->nlh = NULL; + if (priv->nlh_event) { + nl_handle_destroy (priv->nlh_event); + priv->nlh_event = NULL; } - if (priv->nlh_cb) { - nl_cb_put (priv->nlh_cb); - priv->nlh_cb = NULL; + if (priv->nlh_sync) { + nl_handle_destroy (priv->nlh_sync); + priv->nlh_sync = NULL; } g_hash_table_destroy (priv->subscriptions); From 34793c1fb1f92e8acf31382792800a0f47c26002 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Apr 2010 14:58:25 -0700 Subject: [PATCH 035/105] core: use ifindex instead of interface name in a lot of places Where we can do so, let's use ifindex since that's actually unique and doesn't change when the interface name changes. We already use ifindex in a bunch of places, and netlink *only* uses ifindex, so this will make it easier later when we move over to ifindexes fully. --- marshallers/nm-marshal.list | 4 +- src/ip6-manager/nm-ip6-manager.c | 124 ++++++++++++++----------------- src/ip6-manager/nm-ip6-manager.h | 26 +++---- src/nm-device-ethernet.c | 44 ++--------- src/nm-device-ethernet.h | 6 +- src/nm-device-interface.c | 10 ++- src/nm-device-interface.h | 4 +- src/nm-device-olpc-mesh.c | 34 +-------- src/nm-device-olpc-mesh.h | 6 +- src/nm-device-wifi.c | 31 +------- src/nm-device-wifi.h | 6 +- src/nm-device.c | 66 +++++++++++++--- src/nm-device.h | 2 + src/nm-manager.c | 18 ++--- src/nm-netlink-monitor.c | 3 +- src/nm-system.c | 2 +- src/nm-udev-manager.c | 6 +- 17 files changed, 168 insertions(+), 224 deletions(-) diff --git a/marshallers/nm-marshal.list b/marshallers/nm-marshal.list index e19f8befcf..359fbed2d5 100644 --- a/marshallers/nm-marshal.list +++ b/marshallers/nm-marshal.list @@ -15,8 +15,8 @@ VOID:POINTER,POINTER VOID:STRING,STRING,STRING,UINT VOID:OBJECT,UINT,UINT VOID:STRING,INT -VOID:STRING,UINT -VOID:STRING,UINT,BOOLEAN +VOID:INT,UINT +VOID:INT,UINT,BOOLEAN VOID:OBJECT,OBJECT,ENUM VOID:POINTER,STRING VOID:STRING,BOXED diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 50905c3af5..ddecf07cdc 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -42,7 +42,7 @@ typedef struct { NMNetlinkMonitor *monitor; - GHashTable *devices_by_iface, *devices_by_index; + GHashTable *devices; struct nl_handle *nlh; struct nl_cache *addr_cache, *route_cache; @@ -68,7 +68,7 @@ typedef struct { typedef struct { NMIP6Manager *manager; char *iface; - int index; + int ifindex; char *accept_ra_path; gboolean accept_ra_save_valid; @@ -120,10 +120,9 @@ nm_ip6_manager_init (NMIP6Manager *manager) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - priv->devices_by_iface = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, - (GDestroyNotify) nm_ip6_device_destroy); - priv->devices_by_index = g_hash_table_new (NULL, NULL); + priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) nm_ip6_device_destroy); priv->monitor = nm_netlink_monitor_get (); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL); @@ -144,8 +143,7 @@ finalize (GObject *object) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object); - g_hash_table_destroy (priv->devices_by_iface); - g_hash_table_destroy (priv->devices_by_index); + g_hash_table_destroy (priv->devices); g_object_unref (priv->monitor); nl_cache_free (priv->addr_cache); nl_cache_free (priv->route_cache); @@ -170,8 +168,8 @@ nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete), NULL, NULL, - _nm_marshal_VOID__STRING_UINT_BOOLEAN, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN); + _nm_marshal_VOID__INT_UINT_BOOLEAN, + G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN); signals[CONFIG_CHANGED] = g_signal_new ("config-changed", @@ -179,8 +177,8 @@ nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed), NULL, NULL, - _nm_marshal_VOID__STRING_UINT, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT); + _nm_marshal_VOID__INT_UINT, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT); } static void @@ -217,7 +215,7 @@ nm_ip6_manager_new (void) manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL); priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - if (!priv->devices_by_iface || !priv->devices_by_index) { + if (!priv->devices) { nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables"); g_object_unref (manager); manager = NULL; @@ -231,8 +229,7 @@ nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - return g_hash_table_lookup (priv->devices_by_index, - GINT_TO_POINTER (ifindex)); + return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex)); } typedef struct { @@ -246,25 +243,22 @@ finish_addrconf (gpointer user_data) CallbackInfo *info = user_data; NMIP6Device *device = info->device; NMIP6Manager *manager = device->manager; - char *iface_copy; + int ifindex; device->finish_addrconf_id = 0; device->addrconf_complete = TRUE; + ifindex = device->ifindex; if (device->state >= device->target_state) { g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0, - device->iface, info->dhcp_opts, TRUE); + ifindex, info->dhcp_opts, TRUE); } else { nm_log_info (LOGD_IP6, "(%s): IP6 addrconf timed out or failed.", device->iface); - iface_copy = g_strdup (device->iface); - - nm_ip6_manager_cancel_addrconf (manager, device->iface); + nm_ip6_manager_cancel_addrconf (manager, ifindex); g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0, - iface_copy, info->dhcp_opts, FALSE); - - g_free (iface_copy); + ifindex, info->dhcp_opts, FALSE); } return FALSE; @@ -278,7 +272,7 @@ emit_config_changed (gpointer user_data) NMIP6Manager *manager = device->manager; device->config_changed_id = 0; - g_signal_emit (manager, signals[CONFIG_CHANGED], 0, device->iface, info->dhcp_opts); + g_signal_emit (manager, signals[CONFIG_CHANGED], 0, device->ifindex, info->dhcp_opts); return FALSE; } @@ -359,7 +353,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) for (rtnladdr = (struct rtnl_addr *)nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *)nl_cache_get_next ((struct nl_object *)rtnladdr)) { - if (rtnl_addr_get_ifindex (rtnladdr) != device->index) + if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); @@ -686,33 +680,36 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us } static NMIP6Device * -nm_ip6_device_new (NMIP6Manager *manager, const char *iface) +nm_ip6_device_new (NMIP6Manager *manager, int ifindex) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); NMIP6Device *device; GError *error = NULL; char *contents = NULL; + g_return_val_if_fail (ifindex > 0, NULL); + device = g_slice_new0 (NMIP6Device); if (!device) { - nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 addrconf object.", iface); + nm_log_err (LOGD_IP6, "(%d): out of memory creating IP6 addrconf object.", + ifindex); return NULL; } - device->iface = g_strdup (iface); + device->ifindex = ifindex; + device->iface = g_strdup (nm_netlink_index_to_iface (ifindex)); if (!device->iface) { - nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 addrconf object " - "property 'iface'.", - iface); + nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.", + ifindex); goto error; } - device->index = nm_netlink_iface_to_index (iface); - device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", iface); + device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", + device->iface); if (!device->accept_ra_path) { nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 addrconf object " "property 'accept_ra_path'.", - iface); + device->iface); goto error; } @@ -720,15 +717,14 @@ nm_ip6_device_new (NMIP6Manager *manager, const char *iface) device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS)); - g_hash_table_replace (priv->devices_by_iface, device->iface, device); - g_hash_table_replace (priv->devices_by_index, GINT_TO_POINTER (device->index), device); + g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device); /* Grab the original value of "accept_ra" so we can restore it when the * device is taken down. */ if (!g_file_get_contents (device->accept_ra_path, &contents, NULL, &error)) { nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s", - iface, device->accept_ra_path, + device->iface, device->accept_ra_path, error ? error->code : -1, error && error->message ? error->message : "(unknown)"); g_clear_error (&error); @@ -753,7 +749,7 @@ error: void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, - const char *iface, + int ifindex, NMSettingIP6Config *s_ip6) { NMIP6ManagerPrivate *priv; @@ -761,11 +757,11 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager, const char *method = NULL; g_return_if_fail (NM_IS_IP6_MANAGER (manager)); - g_return_if_fail (iface != NULL); + g_return_if_fail (ifindex > 0); priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - device = nm_ip6_device_new (manager, iface); + device = nm_ip6_device_new (manager, ifindex); if (s_ip6) method = nm_setting_ip6_config_get_method (s_ip6); @@ -778,9 +774,9 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager, else device->target_state = NM_IP6_DEVICE_GOT_ADDRESS; - g_return_if_fail (strchr (iface, '/') == NULL && - strcmp (iface, "all") != 0 && - strcmp (iface, "default") != 0); + g_return_if_fail ( strchr (device->iface, '/') == NULL + && strcmp (device->iface, "all") != 0 + && strcmp (device->iface, "default") != 0); /* Turn router advertisement acceptance on or off... */ nm_utils_do_sysctl (device->accept_ra_path, @@ -788,22 +784,21 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager, } void -nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, - const char *iface) +nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex) { NMIP6ManagerPrivate *priv; NMIP6Device *device; CallbackInfo *info; g_return_if_fail (NM_IS_IP6_MANAGER (manager)); - g_return_if_fail (iface != NULL); + g_return_if_fail (ifindex > 0); priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - device = (NMIP6Device *) g_hash_table_lookup (priv->devices_by_iface, iface); + device = (NMIP6Device *) g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex)); g_return_if_fail (device != NULL); - nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", iface); + nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", device->iface); device->addrconf_complete = FALSE; device->ra_flags = 0; @@ -825,27 +820,17 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, } void -nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, - const char *iface) +nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, int ifindex) { - NMIP6ManagerPrivate *priv; - NMIP6Device *device; - g_return_if_fail (NM_IS_IP6_MANAGER (manager)); - g_return_if_fail (iface != NULL); + g_return_if_fail (ifindex > 0); - priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - - device = g_hash_table_lookup (priv->devices_by_iface, iface); - if (device) { - g_hash_table_remove (priv->devices_by_index, GINT_TO_POINTER (device->index)); - g_hash_table_remove (priv->devices_by_iface, iface); - } + g_hash_table_remove (NM_IP6_MANAGER_GET_PRIVATE (manager)->devices, + GINT_TO_POINTER (ifindex)); } NMIP6Config * -nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, - const char *iface) +nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) { NMIP6ManagerPrivate *priv; NMIP6Device *device; @@ -862,20 +847,21 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int i; g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL); - g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (ifindex > 0, NULL); priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - device = (NMIP6Device *) g_hash_table_lookup (priv->devices_by_iface, iface); + device = (NMIP6Device *) g_hash_table_lookup (priv->devices, + GINT_TO_POINTER (ifindex)); if (!device) { - nm_log_warn (LOGD_IP6, "(%s): addrconf not started.", iface); + nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex); return NULL; } config = nm_ip6_config_new (); if (!config) { nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.", - iface); + device->iface); return NULL; } @@ -883,7 +869,7 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, for (rtnladdr = (struct rtnl_addr *)nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *)nl_cache_get_next ((struct nl_object *)rtnladdr)) { - if (rtnl_addr_get_ifindex (rtnladdr) != device->index) + if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); @@ -901,7 +887,7 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, for (rtnlroute = (struct rtnl_route *)nl_cache_get_first (priv->route_cache); rtnlroute; rtnlroute = (struct rtnl_route *)nl_cache_get_next ((struct nl_object *)rtnlroute)) { - if (rtnl_route_get_oif (rtnlroute) != device->index) + if (rtnl_route_get_oif (rtnlroute) != device->ifindex) continue; nldest = rtnl_route_get_dst (rtnlroute); diff --git a/src/ip6-manager/nm-ip6-manager.h b/src/ip6-manager/nm-ip6-manager.h index d0cf4b08a9..db920662b9 100644 --- a/src/ip6-manager/nm-ip6-manager.h +++ b/src/ip6-manager/nm-ip6-manager.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009 - 2010 Red Hat, Inc. */ #ifndef NM_IP6_MANAGER_H @@ -54,7 +54,7 @@ typedef struct { * that the initial configuration is complete. */ void (*addrconf_complete) (NMIP6Manager *manager, - char *iface, + guint32 ifindex, guint dhcp_opts, gboolean success); @@ -63,22 +63,22 @@ typedef struct { * of the interface has changed. */ void (*config_changed) (NMIP6Manager *manager, - char *iface, + guint32 ifindex, guint dhcp_opts); } NMIP6ManagerClass; GType nm_ip6_manager_get_type (void); -NMIP6Manager *nm_ip6_manager_get (void); -void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, - const char *iface, - NMSettingIP6Config *s_ip6); -void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, - const char *iface); -void nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, - const char *iface); +NMIP6Manager *nm_ip6_manager_get (void); +void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, + int ifindex, + NMSettingIP6Config *s_ip6); +void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, + int ifindex); +void nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, + int ifindex); -NMIP6Config * nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, - const char *iface); +NMIP6Config * nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, + int ifindex); #endif /* NM_IP6_MANAGER_H */ diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index 202584b24b..be6d4e2f3c 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -106,7 +106,6 @@ typedef struct { struct ether_addr hw_addr; gboolean carrier; - guint32 ifindex; NMNetlinkMonitor * monitor; gulong link_connected_id; @@ -134,7 +133,6 @@ enum { PROP_HW_ADDRESS, PROP_SPEED, PROP_CARRIER, - PROP_IFINDEX, LAST_PROP }; @@ -247,11 +245,10 @@ carrier_on (NMNetlinkMonitor *monitor, { NMDevice *device = NM_DEVICE (user_data); NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); guint32 caps; /* Make sure signal is for us */ - if (idx == priv->ifindex) { + if (idx == nm_device_get_ifindex (device)) { /* Ignore spurious netlink messages */ caps = nm_device_get_capabilities (device); if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT)) @@ -268,11 +265,10 @@ carrier_off (NMNetlinkMonitor *monitor, { NMDevice *device = NM_DEVICE (user_data); NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); guint32 caps; /* Make sure signal is for us */ - if (idx == priv->ifindex) { + if (idx == nm_device_get_ifindex (device)) { NMDeviceState state; gboolean defer = FALSE; @@ -313,7 +309,8 @@ constructor (GType type, priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d", - nm_device_get_iface (NM_DEVICE (self)), priv->ifindex); + nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_ifindex (NM_DEVICE (self))); caps = nm_device_get_capabilities (self); if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { @@ -332,7 +329,7 @@ constructor (GType type, /* Get initial link state */ if (!nm_netlink_monitor_get_flags_sync (priv->monitor, - priv->ifindex, + nm_device_get_ifindex (NM_DEVICE (self)), &ifflags, &error)) { nm_log_warn (LOGD_HW | LOGD_ETHER, @@ -427,8 +424,7 @@ real_hw_take_down (NMDevice *dev) NMDevice * nm_device_ethernet_new (const char *udi, const char *iface, - const char *driver, - guint32 ifindex) + const char *driver) { g_return_val_if_fail (udi != NULL, NULL); g_return_val_if_fail (iface != NULL, NULL); @@ -438,7 +434,6 @@ nm_device_ethernet_new (const char *udi, NM_DEVICE_INTERFACE_UDI, udi, NM_DEVICE_INTERFACE_IFACE, iface, NM_DEVICE_INTERFACE_DRIVER, driver, - NM_DEVICE_ETHERNET_IFINDEX, ifindex, NM_DEVICE_INTERFACE_TYPE_DESC, "Ethernet", NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, NULL); @@ -460,14 +455,6 @@ nm_device_ethernet_get_address (NMDeviceEthernet *self, struct ether_addr *addr) memcpy (addr, &(NM_DEVICE_ETHERNET_GET_PRIVATE (self)->hw_addr), sizeof (struct ether_addr)); } -guint32 -nm_device_ethernet_get_ifindex (NMDeviceEthernet *self) -{ - g_return_val_if_fail (self != NULL, FALSE); - - return NM_DEVICE_ETHERNET_GET_PRIVATE (self)->ifindex; -} - /* Returns speed in Mb/s */ static guint32 nm_device_ethernet_get_speed (NMDeviceEthernet *self) @@ -1619,7 +1606,7 @@ ip4_match_config (NMDevice *self, NMConnection *connection) int ifindex; AddrData check_data; - ifindex = nm_device_ethernet_get_ifindex (NM_DEVICE_ETHERNET (self)); + ifindex = nm_device_get_ifindex (self); s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); g_assert (s_con); @@ -1791,9 +1778,6 @@ get_property (GObject *object, guint prop_id, case PROP_CARRIER: g_value_set_boolean (value, priv->carrier); break; - case PROP_IFINDEX: - g_value_set_uint (value, priv->ifindex); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1804,13 +1788,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (object); - switch (prop_id) { - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_uint (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1877,14 +1855,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) FALSE, G_PARAM_READABLE)); - g_object_class_install_property - (object_class, PROP_IFINDEX, - g_param_spec_uint (NM_DEVICE_ETHERNET_IFINDEX, - "Ifindex", - "Interface index", - 0, G_MAXUINT32, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); - /* Signals */ signals[PROPERTIES_CHANGED] = nm_properties_changed_signal_new (object_class, diff --git a/src/nm-device-ethernet.h b/src/nm-device-ethernet.h index 643572f700..7bb3db0086 100644 --- a/src/nm-device-ethernet.h +++ b/src/nm-device-ethernet.h @@ -39,7 +39,6 @@ G_BEGIN_DECLS #define NM_DEVICE_ETHERNET_HW_ADDRESS "hw-address" #define NM_DEVICE_ETHERNET_SPEED "speed" #define NM_DEVICE_ETHERNET_CARRIER "carrier" -#define NM_DEVICE_ETHERNET_IFINDEX "ifindex" typedef struct { NMDevice parent; @@ -58,14 +57,11 @@ GType nm_device_ethernet_get_type (void); NMDevice *nm_device_ethernet_new (const char *udi, const char *iface, - const char *driver, - guint32 ifindex); + const char *driver); void nm_device_ethernet_get_address (NMDeviceEthernet *dev, struct ether_addr *addr); -guint32 nm_device_ethernet_get_ifindex (NMDeviceEthernet *dev); - G_END_DECLS #endif /* NM_DEVICE_ETHERNET_H */ diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c index 4040626c2b..85f58d5563 100644 --- a/src/nm-device-interface.c +++ b/src/nm-device-interface.c @@ -16,7 +16,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2008 Red Hat, Inc. + * Copyright (C) 2007 - 2010 Red Hat, Inc. */ #include "nm-marshal.h" @@ -186,6 +186,14 @@ nm_device_interface_init (gpointer g_iface) RFKILL_TYPE_UNKNOWN, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); + g_object_interface_install_property + (g_iface, + g_param_spec_int (NM_DEVICE_INTERFACE_IFINDEX, + "Ifindex", + "Ifindex", + 0, G_MAXINT, 0, + G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT)); + /* Signals */ g_signal_new ("state-changed", iface_type, diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h index adbafcaa25..ec27f6e820 100644 --- a/src/nm-device-interface.h +++ b/src/nm-device-interface.h @@ -57,8 +57,9 @@ typedef enum #define NM_DEVICE_INTERFACE_STATE "state" #define NM_DEVICE_INTERFACE_DEVICE_TYPE "device-type" /* ugh */ #define NM_DEVICE_INTERFACE_MANAGED "managed" -#define NM_DEVICE_INTERFACE_TYPE_DESC "type-desc" /* Internal only */ +#define NM_DEVICE_INTERFACE_TYPE_DESC "type-desc" /* Internal only */ #define NM_DEVICE_INTERFACE_RFKILL_TYPE "rfkill-type" /* Internal only */ +#define NM_DEVICE_INTERFACE_IFINDEX "ifindex" /* Internal only */ typedef enum { NM_DEVICE_INTERFACE_PROP_FIRST = 0x1000, @@ -77,6 +78,7 @@ typedef enum { NM_DEVICE_INTERFACE_PROP_MANAGED, NM_DEVICE_INTERFACE_PROP_TYPE_DESC, NM_DEVICE_INTERFACE_PROP_RFKILL_TYPE, + NM_DEVICE_INTERFACE_PROP_IFINDEX, } NMDeviceInterfaceProp; diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c index 2093a8e887..f73108a793 100644 --- a/src/nm-device-olpc-mesh.c +++ b/src/nm-device-olpc-mesh.c @@ -69,7 +69,6 @@ enum { PROP_HW_ADDRESS, PROP_COMPANION, PROP_ACTIVE_CHANNEL, - PROP_IFINDEX, LAST_PROP }; @@ -98,7 +97,6 @@ struct _NMDeviceOlpcMeshPrivate gboolean dispose_has_run; struct ether_addr hw_addr; - guint32 ifindex; GByteArray * ssid; @@ -263,7 +261,8 @@ constructor (GType type, priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d", - nm_device_get_iface (NM_DEVICE (self)), priv->ifindex); + nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_ifindex (NM_DEVICE (self))); iface = nm_device_get_iface (NM_DEVICE (self)); fd = socket (PF_INET, SOCK_DGRAM, 0); @@ -539,15 +538,6 @@ nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self, const GByteArray * ssid) close (sk); } - -guint32 -nm_device_olpc_mesh_get_ifindex (NMDeviceOlpcMesh *self) -{ - g_return_val_if_fail (self != NULL, FALSE); - - return NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->ifindex; -} - /****************************************************************************/ static void @@ -701,9 +691,6 @@ get_property (GObject *object, guint prop_id, case PROP_ACTIVE_CHANNEL: g_value_set_uint (value, nm_device_olpc_mesh_get_channel (device)); break; - case PROP_IFINDEX: - g_value_set_uint (value, nm_device_olpc_mesh_get_ifindex (device)); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -714,13 +701,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (object); - switch (prop_id) { - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_uint (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -780,13 +761,6 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) 0, G_MAXUINT32, 0, G_PARAM_READABLE)); - g_object_class_install_property (object_class, PROP_IFINDEX, - g_param_spec_uint (NM_DEVICE_OLPC_MESH_IFINDEX, - "Ifindex", - "Interface index", - 0, G_MAXUINT32, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - signals[PROPERTIES_CHANGED] = nm_properties_changed_signal_new (object_class, G_STRUCT_OFFSET (NMDeviceOlpcMeshClass, properties_changed)); @@ -986,8 +960,7 @@ state_changed_cb (NMDevice *device, NMDeviceState state, gpointer user_data) NMDevice * nm_device_olpc_mesh_new (const char *udi, const char *iface, - const char *driver, - guint32 ifindex) + const char *driver) { GObject *obj; @@ -999,7 +972,6 @@ nm_device_olpc_mesh_new (const char *udi, NM_DEVICE_INTERFACE_UDI, udi, NM_DEVICE_INTERFACE_IFACE, iface, NM_DEVICE_INTERFACE_DRIVER, driver, - NM_DEVICE_OLPC_MESH_IFINDEX, ifindex, NM_DEVICE_INTERFACE_TYPE_DESC, "802.11 OLPC Mesh", NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_OLPC_MESH, NULL); diff --git a/src/nm-device-olpc-mesh.h b/src/nm-device-olpc-mesh.h index adf3d2d956..bcc03e57ab 100644 --- a/src/nm-device-olpc-mesh.h +++ b/src/nm-device-olpc-mesh.h @@ -46,7 +46,6 @@ G_BEGIN_DECLS #define NM_DEVICE_OLPC_MESH_COMPANION "companion" #define NM_DEVICE_OLPC_MESH_BITRATE "bitrate" #define NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL "active-channel" -#define NM_DEVICE_OLPC_MESH_IFINDEX "ifindex" #ifndef NM_DEVICE_OLPC_MESH_DEFINED #define NM_DEVICE_OLPC_MESH_DEFINED @@ -75,10 +74,7 @@ GType nm_device_olpc_mesh_get_type (void); NMDevice *nm_device_olpc_mesh_new (const char *udi, const char *iface, - const char *driver, - guint32 ifindex); - -guint32 nm_device_olpc_mesh_get_ifindex (NMDeviceOlpcMesh *self); + const char *driver); G_END_DECLS diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index cccaf1194e..b598f2b675 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -82,7 +82,6 @@ enum { PROP_BITRATE, PROP_ACTIVE_ACCESS_POINT, PROP_CAPABILITIES, - PROP_IFINDEX, PROP_SCANNING, PROP_IPW_RFKILL_STATE, @@ -144,7 +143,6 @@ struct _NMDeviceWifiPrivate { gboolean disposed; struct ether_addr hw_addr; - guint32 ifindex; /* Legacy rfkill for ipw2x00; will be fixed with 2.6.33 kernel */ char * ipw_rfkill_path; @@ -579,7 +577,8 @@ constructor (GType type, priv = NM_DEVICE_WIFI_GET_PRIVATE (self); nm_log_dbg (LOGD_HW | LOGD_WIFI, "(%s): kernel ifindex %d", - nm_device_get_iface (NM_DEVICE (self)), priv->ifindex); + nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_ifindex (NM_DEVICE (self))); memset (&range, 0, sizeof (struct iw_range)); success = wireless_get_range (NM_DEVICE_WIFI (object), &range, &response_len); @@ -3462,14 +3461,6 @@ device_state_changed (NMDevice *device, remove_all_aps (self); } -guint32 -nm_device_wifi_get_ifindex (NMDeviceWifi *self) -{ - g_return_val_if_fail (self != NULL, FALSE); - - return NM_DEVICE_WIFI_GET_PRIVATE (self)->ifindex; -} - NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self) { @@ -3563,8 +3554,7 @@ real_set_enabled (NMDeviceInterface *device, gboolean enabled) NMDevice * nm_device_wifi_new (const char *udi, const char *iface, - const char *driver, - guint32 ifindex) + const char *driver) { g_return_val_if_fail (udi != NULL, NULL); g_return_val_if_fail (iface != NULL, NULL); @@ -3574,7 +3564,6 @@ nm_device_wifi_new (const char *udi, NM_DEVICE_INTERFACE_UDI, udi, NM_DEVICE_INTERFACE_IFACE, iface, NM_DEVICE_INTERFACE_DRIVER, driver, - NM_DEVICE_WIFI_IFINDEX, ifindex, NM_DEVICE_INTERFACE_TYPE_DESC, "802.11 WiFi", NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_WIFI, NM_DEVICE_INTERFACE_RFKILL_TYPE, RFKILL_TYPE_WLAN, @@ -3675,9 +3664,6 @@ get_property (GObject *object, guint prop_id, else g_value_set_boxed (value, "/"); break; - case PROP_IFINDEX: - g_value_set_uint (value, nm_device_wifi_get_ifindex (device)); - break; case PROP_SCANNING: g_value_set_boolean (value, nm_supplicant_interface_get_scanning (priv->supplicant.iface)); break; @@ -3697,10 +3683,6 @@ set_property (GObject *object, guint prop_id, NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object); switch (prop_id) { - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_uint (value); - break; case PROP_IPW_RFKILL_STATE: /* construct only */ priv->ipw_rfkill_state = g_value_get_uint (value); @@ -3788,13 +3770,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) 0, G_MAXUINT32, NM_WIFI_DEVICE_CAP_NONE, G_PARAM_READABLE)); - g_object_class_install_property (object_class, PROP_IFINDEX, - g_param_spec_uint (NM_DEVICE_WIFI_IFINDEX, - "Ifindex", - "Interface index", - 0, G_MAXUINT32, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); - g_object_class_install_property (object_class, PROP_SCANNING, g_param_spec_boolean (NM_DEVICE_WIFI_SCANNING, "Scanning", diff --git a/src/nm-device-wifi.h b/src/nm-device-wifi.h index 45b573a03c..11ac885735 100644 --- a/src/nm-device-wifi.h +++ b/src/nm-device-wifi.h @@ -47,7 +47,6 @@ G_BEGIN_DECLS #define NM_DEVICE_WIFI_BITRATE "bitrate" #define NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT "active-access-point" #define NM_DEVICE_WIFI_CAPABILITIES "wireless-capabilities" -#define NM_DEVICE_WIFI_IFINDEX "ifindex" #define NM_DEVICE_WIFI_SCANNING "scanning" #define NM_DEVICE_WIFI_IPW_RFKILL_STATE "ipw-rfkill-state" @@ -84,8 +83,7 @@ GType nm_device_wifi_get_type (void); NMDevice *nm_device_wifi_new (const char *udi, const char *iface, - const char *driver, - guint32 ifindex); + const char *driver); void nm_device_wifi_get_address (NMDeviceWifi *dev, struct ether_addr *addr); @@ -102,8 +100,6 @@ NM80211Mode nm_device_wifi_get_mode (NMDeviceWifi *self); NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self); -guint32 nm_device_wifi_get_ifindex (NMDeviceWifi *self); - RfKillState nm_device_wifi_get_ipw_rfkill_state (NMDeviceWifi *self); G_END_DECLS diff --git a/src/nm-device.c b/src/nm-device.c index db0ad914a9..b285baaf86 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -83,7 +83,9 @@ typedef struct { char * udi; char * path; char * iface; /* may change, could be renamed by user */ + int ifindex; char * ip_iface; + int ip_ifindex; NMDeviceType type; char * type_desc; guint32 capabilities; @@ -304,6 +306,13 @@ nm_device_get_iface (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->iface; } +int +nm_device_get_ifindex (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, 0); + + return NM_DEVICE_GET_PRIVATE (self)->ifindex; +} const char * nm_device_get_ip_iface (NMDevice *self) @@ -317,14 +326,36 @@ nm_device_get_ip_iface (NMDevice *self) return priv->ip_iface ? priv->ip_iface : priv->iface; } +int +nm_device_get_ip_ifindex (NMDevice *self) +{ + NMDevicePrivate *priv; + + g_return_val_if_fail (self != NULL, 0); + + priv = NM_DEVICE_GET_PRIVATE (self); + /* If it's not set, default to iface */ + return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; +} void nm_device_set_ip_iface (NMDevice *self, const char *iface) { + NMDevicePrivate *priv; + g_return_if_fail (NM_IS_DEVICE (self)); - g_free (NM_DEVICE_GET_PRIVATE (self)->ip_iface); - NM_DEVICE_GET_PRIVATE (self)->ip_iface = iface ? g_strdup (iface) : NULL; + priv = NM_DEVICE_GET_PRIVATE (self); + g_free (priv->ip_iface); + priv->ip_ifindex = 0; + + priv->ip_iface = g_strdup (iface); + if (priv->ip_iface) { + priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface); + if (!priv->ip_ifindex) { + nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", iface); + } + } } @@ -545,7 +576,7 @@ activation_source_schedule (NMDevice *self, GSourceFunc func, int family) static void ip6_addrconf_complete (NMIP6Manager *ip6_manager, - const char *iface, + int ifindex, guint dhcp_opts, gboolean success, gpointer user_data) @@ -558,7 +589,7 @@ ip6_addrconf_complete (NMIP6Manager *ip6_manager, NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; NMDeviceState state; - if (strcmp (nm_device_get_ip_iface (self), iface) != 0) + if (ifindex != nm_device_get_ip_ifindex (self)) return; req = nm_device_get_act_request (self); if (!req) @@ -614,13 +645,13 @@ ip6_addrconf_complete (NMIP6Manager *ip6_manager, static void ip6_config_changed (NMIP6Manager *ip6_manager, - const char *iface, + int ifindex, guint dhcp_opts, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); - if (strcmp (nm_device_get_ip_iface (self), iface) != 0) + if (ifindex != nm_device_get_ip_ifindex (self)) return; if (!nm_device_get_act_request (self)) return; @@ -675,7 +706,9 @@ addrconf6_setup (NMDevice *self) ip_iface = nm_device_get_ip_iface (self); s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); - nm_ip6_manager_prepare_interface (priv->ip6_manager, ip_iface, s_ip6); + nm_ip6_manager_prepare_interface (priv->ip6_manager, + nm_device_get_ip_ifindex (self), + s_ip6); } static void @@ -1481,7 +1514,7 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { priv->ip6_waiting_for_config = TRUE; - nm_ip6_manager_begin_addrconf (priv->ip6_manager, ip_iface); + nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self)); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) ret = dhcp6_start (self, connection, IP6_DHCP_OPT_MANAGED, reason); @@ -1867,7 +1900,8 @@ real_act_stage4_get_ip6_config (NMDevice *self, s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - *config = nm_ip6_manager_get_ip6_config (priv->ip6_manager, ip_iface); + *config = nm_ip6_manager_get_ip6_config (priv->ip6_manager, + nm_device_get_ip_ifindex (self)); if (*config) { /* Merge user-defined overrides into the IP6Config to be applied */ nm_utils_merge_ip6_config (*config, s_ip6); @@ -3089,7 +3123,14 @@ set_property (GObject *object, guint prop_id, break; case NM_DEVICE_INTERFACE_PROP_IFACE: g_free (priv->iface); + priv->ifindex = 0; priv->iface = g_value_dup_string (value); + if (priv->iface) { + priv->ifindex = nm_netlink_iface_to_index (priv->iface); + if (priv->ifindex < 0) { + nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", priv->iface); + } + } break; case NM_DEVICE_INTERFACE_PROP_DRIVER: priv->driver = g_strdup (g_value_get_string (value)); @@ -3137,6 +3178,9 @@ get_property (GObject *object, guint prop_id, case NM_DEVICE_INTERFACE_PROP_IFACE: g_value_set_string (value, priv->iface); break; + case NM_DEVICE_INTERFACE_PROP_IFINDEX: + g_value_set_int (value, priv->ifindex); + break; case NM_DEVICE_INTERFACE_PROP_DRIVER: g_value_set_string (value, priv->driver); break; @@ -3235,6 +3279,10 @@ nm_device_class_init (NMDeviceClass *klass) NM_DEVICE_INTERFACE_PROP_IFACE, NM_DEVICE_INTERFACE_IFACE); + g_object_class_override_property (object_class, + NM_DEVICE_INTERFACE_PROP_IFINDEX, + NM_DEVICE_INTERFACE_IFINDEX); + g_object_class_override_property (object_class, NM_DEVICE_INTERFACE_PROP_DRIVER, NM_DEVICE_INTERFACE_DRIVER); diff --git a/src/nm-device.h b/src/nm-device.h index 5fcde5c338..ffeca42142 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -128,7 +128,9 @@ void nm_device_set_path (NMDevice *dev, const char *path); const char * nm_device_get_udi (NMDevice *dev); const char * nm_device_get_iface (NMDevice *dev); +int nm_device_get_ifindex (NMDevice *dev); const char * nm_device_get_ip_iface (NMDevice *dev); +int nm_device_get_ip_ifindex(NMDevice *dev); const char * nm_device_get_driver (NMDevice *dev); const char * nm_device_get_type_desc (NMDevice *dev); diff --git a/src/nm-manager.c b/src/nm-manager.c index a24606ad99..e42452c9bf 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1523,7 +1523,8 @@ add_device (NMManager *self, NMDevice *device) driver = nm_device_get_driver (device); if (!driver) driver = "unknown"; - nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s')", iface, type_desc, driver); + nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s' ifindex: %d)", + iface, type_desc, driver, nm_device_get_ifindex (device)); path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++); nm_device_set_path (device, path); @@ -1794,20 +1795,11 @@ find_device_by_ifindex (NMManager *self, guint32 ifindex) GSList *iter; for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *device = NM_DEVICE (iter->data); - gint candidate_idx = 0; + NMDevice *candidate = NM_DEVICE (iter->data); - if (NM_IS_DEVICE_ETHERNET (device)) - candidate_idx = nm_device_ethernet_get_ifindex (NM_DEVICE_ETHERNET (device)); - else if (NM_IS_DEVICE_WIFI (device)) - candidate_idx = nm_device_wifi_get_ifindex (NM_DEVICE_WIFI (device)); - else if (NM_IS_DEVICE_OLPC_MESH (device)) - candidate_idx = nm_device_olpc_mesh_get_ifindex (NM_DEVICE_OLPC_MESH (device)); - - if (candidate_idx == ifindex) - return device; + if (ifindex == nm_device_get_ifindex (candidate)) + return candidate; } - return NULL; } diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 6fb13ef3d1..10bf239d5d 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -743,7 +743,8 @@ nm_netlink_index_to_rtnl_link (int idx) NMNetlinkMonitorPrivate *priv; struct rtnl_link *ret = NULL; - g_return_val_if_fail (idx >= 0, NULL); + if (idx <= 0) + return NULL; self = nm_netlink_monitor_get (); priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); diff --git a/src/nm-system.c b/src/nm-system.c index 0d38ea6cf4..2e03c41a8e 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -986,7 +986,7 @@ foreach_route (void (*callback)(struct nl_object *, gpointer), nlh = nm_netlink_get_default_handle (); route_cache = rtnl_route_alloc_cache (nlh); - nl_cache_mngt_provide (route_cache); + g_assert (route_cache); nl_cache_foreach (route_cache, callback, user_data); nl_cache_free (route_cache); } diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c index 0ced962c27..3481d88b40 100644 --- a/src/nm-udev-manager.c +++ b/src/nm-udev-manager.c @@ -384,11 +384,11 @@ device_creator (NMUdevManager *manager, } if (is_olpc_mesh (udev_device)) /* must be before is_wireless */ - device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver, ifindex); + device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver); else if (is_wireless (udev_device)) - device = (GObject *) nm_device_wifi_new (path, ifname, driver, ifindex); + device = (GObject *) nm_device_wifi_new (path, ifname, driver); else - device = (GObject *) nm_device_ethernet_new (path, ifname, driver, ifindex); + device = (GObject *) nm_device_ethernet_new (path, ifname, driver); out: if (grandparent) From 5750529ff58147c6acccaa759ccdf19130273fe0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Apr 2010 15:20:16 -0700 Subject: [PATCH 036/105] ip6: make sure IPv6 addrconf is cleaned up correctly --- src/nm-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nm-device.c b/src/nm-device.c index b285baaf86..c76c9f50ad 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -730,6 +730,7 @@ addrconf6_cleanup (NMDevice *self) priv->ip6_config_changed_sigid = 0; } + nm_ip6_manager_cancel_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self)); g_object_unref (priv->ip6_manager); priv->ip6_manager = NULL; } From 2ce8028e10ab2780dcd7970674ba18dc0772595a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Apr 2010 15:43:34 -0700 Subject: [PATCH 037/105] ip6: fix IPv6 addrconf detection and completion Poll the device's IPv6 flags so we're notified when the RA has been parsed and what the flags are. Only when that's complete and the device's target state has been reached (or Managed mode was indicated by the RA) should we continue with IP configuration. --- src/ip6-manager/nm-ip6-manager.c | 79 ++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 24 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index ddecf07cdc..7767870186 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -55,8 +55,6 @@ typedef enum { NM_IP6_DEVICE_GOT_LINK_LOCAL, NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT, NM_IP6_DEVICE_GOT_ADDRESS, - NM_IP6_DEVICE_WAITING_FOR_DHCP, - NM_IP6_DEVICE_GOT_DHCP, NM_IP6_DEVICE_TIMED_OUT } NMIP6DeviceState; @@ -84,6 +82,8 @@ typedef struct { GArray *rdnss_servers; guint rdnss_timeout_id; + guint ip6flags_poll_id; + guint32 ra_flags; } NMIP6Device; @@ -201,6 +201,8 @@ nm_ip6_device_destroy (NMIP6Device *device) g_array_free (device->rdnss_servers, TRUE); if (device->rdnss_timeout_id) g_source_remove (device->rdnss_timeout_id); + if (device->ip6flags_poll_id) + g_source_remove (device->ip6flags_poll_id); g_free (device->accept_ra_path); g_slice_free (NMIP6Device, device); @@ -235,6 +237,7 @@ nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex) typedef struct { NMIP6Device *device; guint dhcp_opts; + gboolean success; } CallbackInfo; static gboolean @@ -249,16 +252,23 @@ finish_addrconf (gpointer user_data) device->addrconf_complete = TRUE; ifindex = device->ifindex; - if (device->state >= device->target_state) { + /* We're done, stop polling IPv6 flags */ + if (device->ip6flags_poll_id) { + g_source_remove (device->ip6flags_poll_id); + device->ip6flags_poll_id = 0; + } + + /* And tell listeners that addrconf is complete */ + if (info->success) { g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0, - ifindex, info->dhcp_opts, TRUE); + ifindex, info->dhcp_opts, TRUE); } else { nm_log_info (LOGD_IP6, "(%s): IP6 addrconf timed out or failed.", - device->iface); + device->iface); nm_ip6_manager_cancel_addrconf (manager, ifindex); g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0, - ifindex, info->dhcp_opts, FALSE); + ifindex, info->dhcp_opts, FALSE); } return FALSE; @@ -328,14 +338,14 @@ set_rdnss_timeout (NMIP6Device *device) } static CallbackInfo * -callback_info_new (NMIP6Device *device, guint dhcp_opts) +callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success) { CallbackInfo *info; info = g_malloc0 (sizeof (CallbackInfo)); info->device = device; info->dhcp_opts = dhcp_opts; - + info->success = success; return info; } @@ -350,9 +360,10 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) CallbackInfo *info; guint dhcp_opts = IP6_DHCP_OPT_NONE; - for (rtnladdr = (struct rtnl_addr *)nl_cache_get_first (priv->addr_cache); + /* Look for any IPv6 addresses the kernel may have set for the device */ + for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache); rtnladdr; - rtnladdr = (struct rtnl_addr *)nl_cache_get_next ((struct nl_object *)rtnladdr)) { + rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) { if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; @@ -370,27 +381,35 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) } } - if ((device->ra_flags & IF_RA_RCVD) && device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) - device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT; + /* We only care about router advertisements if we want for a real IPv6 address */ + if (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) { + if ( (device->ra_flags & IF_RA_RCVD) + && (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)) + device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT; - if (device->ra_flags & IF_RA_MANAGED) { - dhcp_opts = IP6_DHCP_OPT_MANAGED; - nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6"); - } else if (device->ra_flags & IF_RA_OTHERCONF) { - dhcp_opts = IP6_DHCP_OPT_OTHERCONF; - nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6"); + if (device->ra_flags & IF_RA_MANAGED) { + dhcp_opts = IP6_DHCP_OPT_MANAGED; + nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6"); + } else if (device->ra_flags & IF_RA_OTHERCONF) { + dhcp_opts = IP6_DHCP_OPT_OTHERCONF; + nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6"); + } } if (!device->addrconf_complete) { - if (device->state >= device->target_state || - device->state == NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) { + /* Managed mode (ie DHCP only) short-circuits automatic addrconf, so + * we don't bother waiting for the device's target state to be reached + * when the RA requests managed mode. + */ + if ( (device->state >= device->target_state) + || (dhcp_opts == IP6_DHCP_OPT_MANAGED)) { /* device->finish_addrconf_id may currently be a timeout * rather than an idle, so we remove the existing source. */ if (device->finish_addrconf_id) g_source_remove (device->finish_addrconf_id); - info = callback_info_new (device, dhcp_opts); + info = callback_info_new (device, dhcp_opts, TRUE); device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, finish_addrconf, info, @@ -398,7 +417,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) } } else if (config_changed) { if (!device->config_changed_id) { - info = callback_info_new (device, dhcp_opts); + info = callback_info_new (device, dhcp_opts, TRUE); device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, emit_config_changed, info, @@ -636,6 +655,7 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg) return NULL; device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]); + nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags); return device; } @@ -783,6 +803,13 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager, device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS ? "1\n" : "0\n"); } +static gboolean +poll_ip6_flags (gpointer user_data) +{ + nm_netlink_monitor_request_ip6_info (NM_NETLINK_MONITOR (user_data), NULL); + return TRUE; +} + void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex) { @@ -804,18 +831,22 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex) device->ra_flags = 0; /* Set up a timeout on the transaction to kill it after the timeout */ - info = callback_info_new (device, 0); + info = callback_info_new (device, 0, FALSE); device->finish_addrconf_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, NM_IP6_TIMEOUT, finish_addrconf, info, (GDestroyNotify) g_free); + device->ip6flags_poll_id = g_timeout_add_seconds (1, poll_ip6_flags, priv->monitor); + + /* Kick off the initial IPv6 flags request */ + nm_netlink_monitor_request_ip6_info (priv->monitor, NULL); + /* Sync flags, etc, from netlink; this will also notice if the * device is already fully configured and schedule the * ADDRCONF_COMPLETE signal in that case. */ - nm_netlink_monitor_request_ip6_info (priv->monitor, NULL); nm_ip6_device_sync_from_netlink (device, FALSE); } From 24bd77dc9272bb1f3090d3dc4968a042765d5b76 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 12:55:05 -0700 Subject: [PATCH 038/105] ifcfg-rh: missing IP4 setting means DHCP --- system-settings/plugins/ifcfg-rh/writer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/system-settings/plugins/ifcfg-rh/writer.c b/system-settings/plugins/ifcfg-rh/writer.c index 8085584cca..c4d829fa25 100644 --- a/system-settings/plugins/ifcfg-rh/writer.c +++ b/system-settings/plugins/ifcfg-rh/writer.c @@ -914,7 +914,11 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (s_ip4) method = nm_setting_ip4_config_get_method (s_ip4); - if (!s_ip4 || (method && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED))) { + /* Missing IP4 setting is assumed to be DHCP */ + if (!method) + method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + + if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { int result; /* IPv4 disabled, clear IPv4 related parameters */ From 4a2bb8b6477e6ff7c693a352592cc7f004c37345 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 12:56:33 -0700 Subject: [PATCH 039/105] core: don't even bother running IPv4 or IPv6 when they are disabled --- src/nm-device.c | 14 +++++++++++++- src/nm-device.h | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/nm-device.c b/src/nm-device.c index c76c9f50ad..ba88c6b0e3 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1338,6 +1338,7 @@ dhcp_timeout (NMDHCPClient *client, gpointer user_data) static NMActStageReturn real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; NMSettingConnection *s_con; NMSettingIP4Config *s_ip4; @@ -1367,7 +1368,6 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason) method = nm_setting_ip4_config_get_method (s_ip4); if (!s_ip4 || !method || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); guint8 *anycast = NULL; /* Begin a DHCP transaction on the interface */ @@ -1423,6 +1423,10 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason) *reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED; ret = NM_ACT_STAGE_RETURN_FAILURE; } + } else if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { + /* Nothing to do... */ + priv->ip4_ready = TRUE; + ret = NM_ACT_STAGE_RETURN_STOP; } return ret; @@ -1519,6 +1523,10 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) ret = dhcp6_start (self, connection, IP6_DHCP_OPT_MANAGED, reason); + else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + priv->ip6_ready = TRUE; + ret = NM_ACT_STAGE_RETURN_STOP; + } return ret; } @@ -1551,6 +1559,8 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; + } else if (ret == NM_ACT_STAGE_RETURN_STOP) { + /* Nothing to do */ } else g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); @@ -1560,6 +1570,8 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; + } else if (ret == NM_ACT_STAGE_RETURN_STOP) { + /* Nothing to do */ } else g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); diff --git a/src/nm-device.h b/src/nm-device.h index ffeca42142..202f392413 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -38,7 +38,8 @@ typedef enum NMActStageReturn { NM_ACT_STAGE_RETURN_FAILURE = 0, NM_ACT_STAGE_RETURN_SUCCESS, - NM_ACT_STAGE_RETURN_POSTPONE + NM_ACT_STAGE_RETURN_POSTPONE, + NM_ACT_STAGE_RETURN_STOP /* This activation chain is done */ } NMActStageReturn; From eaa750dda9482bd6f6baa241ed42f95b7be7e944 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 15:30:46 -0700 Subject: [PATCH 040/105] dhcp: add missing DHCPv6 client states --- src/dhcp-manager/nm-dhcp-client.c | 3 +++ src/dhcp-manager/nm-dhcp-client.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 888e7c5402..9f9719473a 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -390,11 +390,14 @@ static DhcState state_table[] = { { DHC_REBIND4, "rebind" }, { DHC_REBIND6, "rebind6" }, { DHC_STOP, "stop" }, + { DHC_STOP6, "stop6" }, { DHC_MEDIUM, "medium" }, { DHC_TIMEOUT, "timeout" }, { DHC_FAIL, "fail" }, { DHC_EXPIRE, "expire" }, + { DHC_EXPIRE6, "expire6" }, { DHC_RELEASE, "release" }, + { DHC_RELEASE6,"release6" }, { DHC_START, "start" }, { DHC_ABEND, "abend" }, { DHC_END, "end" }, diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index 2ebb5a745c..146cf57b3f 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -53,11 +53,14 @@ typedef enum { DHC_REBIND6, /* IPv6 new/different lease */ DHC_DEPREF6, /* IPv6 lease depreferred */ DHC_STOP, /* remove old lease */ + DHC_STOP6, /* remove old lease */ DHC_MEDIUM, /* media selection begun */ DHC_TIMEOUT, /* timed out contacting DHCP server */ DHC_FAIL, /* all attempts to contact server timed out, sleeping */ DHC_EXPIRE, /* lease has expired, renewing */ + DHC_EXPIRE6, /* lease has expired, renewing */ DHC_RELEASE, /* releasing lease */ + DHC_RELEASE6, /* releasing lease */ DHC_START, /* sent when dhclient started OK */ DHC_ABEND, /* dhclient exited abnormally */ DHC_END, /* dhclient exited normally */ From b172519045e5ea4825f85fca81de8395e92600c1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 15:52:09 -0700 Subject: [PATCH 041/105] core: fail connections if IP configuration expires Need to mark these connections invalid too, otherwise they'll just be retried over and over and over. Ran into a problem with DHCPv6 where lease expiration (cached lease really) was *negative*, which caused the lease to expire immediately after being bound. Previously the policy wouldn't mark connections like this as invalid because they hadn't failed during activation. NetworkManager: (eth0): carrier now ON (device state 2) NetworkManager: (eth0): device state change: 2 -> 3 (reason 40) NetworkManager: Activation (eth0) starting connection 'dhcp6 test' NetworkManager: (eth0): device state change: 3 -> 4 (reason 0) NetworkManager: Activation (eth0) Stage 1 of 5 (Device Prepare) scheduled... NetworkManager: Activation (eth0) Stage 1 of 5 (Device Prepare) started... NetworkManager: Activation (eth0) Stage 2 of 5 (Device Configure) scheduled... NetworkManager: Activation (eth0) Stage 1 of 5 (Device Prepare) complete. NetworkManager: Activation (eth0) Stage 2 of 5 (Device Configure) starting... NetworkManager: (eth0): device state change: 4 -> 5 (reason 0) NetworkManager: Activation (eth0) Stage 2 of 5 (Device Configure) successful. NetworkManager: Activation (eth0) Stage 3 of 5 (IP Configure Start) scheduled. NetworkManager: Activation (eth0) Stage 2 of 5 (Device Configure) complete. NetworkManager: Activation (eth0) Stage 3 of 5 (IP Configure Start) started... NetworkManager: (eth0): device state change: 5 -> 7 (reason 0) NetworkManager: Activation (eth0) Beginning DHCPv6 transaction (timeout in 45 seconds) NetworkManager: dhclient started with pid 6639 NetworkManager: Activation (eth0) Stage 3 of 5 (IP Configure Start) complete. Internet Systems Consortium DHCP Client 4.1.1 Copyright 2004-2010 Internet Systems Consortium. All rights reserved. For info, please visit https://www.isc.org/software/dhcp/ NetworkManager: (eth0): DHCPv6 state changed nbi -> preinit6 Bound to *:546 Listening on Socket/eth0 Sending on Socket/eth0 PRC: Confirming active lease (INIT-REBOOT). XMT: Forming Confirm, 0 ms elapsed. XMT: X-- IA_NA 5a:47:1f:71 XMT: | X-- Confirm Address 3ffe:501:ffff::4 XMT: V IA_NA appended. XMT: Confirm on eth0, interval 1090ms. send_packet6: Cannot assign requested address dhc6: sendpacket6() sent -1 of 80 bytes XMT: Forming Confirm, 1090 ms elapsed. XMT: X-- IA_NA 5a:47:1f:71 XMT: | X-- Confirm Address 3ffe:501:ffff::4 XMT: V IA_NA appended. XMT: Confirm on eth0, interval 2120ms. send_packet6: Cannot assign requested address dhc6: sendpacket6() sent -1 of 80 bytes XMT: Forming Confirm, 3210 ms elapsed. XMT: X-- IA_NA 5a:47:1f:71 XMT: | X-- Confirm Address 3ffe:501:ffff::4 XMT: V IA_NA appended. XMT: Confirm on eth0, interval 4320ms. XMT: Forming Confirm, 7530 ms elapsed. XMT: X-- IA_NA 5a:47:1f:71 XMT: | X-- Confirm Address 3ffe:501:ffff::4 XMT: V IA_NA appended. XMT: Confirm on eth0, interval 2470ms. Max retransmission duration exceeded. PRC: Bound to lease 00:01:00:01:12:e1:92:d9:00:14:22:fd:06:e7. PRC: Rebind event scheduled in -8604281 seconds, to run for 110 seconds. PRC: Depreference scheduled in -8604241 seconds. PRC: Expiration scheduled in -8604171 seconds. PRC: Rebinding lease on eth0. PRC: Depreference scheduled in -8604241 seconds. PRC: Expiration scheduled in -8604171 seconds. NetworkManager: (eth0): DHCPv6 state changed preinit6 -> bound6 NetworkManager: Activation (eth0) Stage 4 of 5 (IP6 Configure Get) scheduled... NetworkManager: Activation (eth0) Stage 4 of 5 (IP6 Configure Get) started... NetworkManager: address 3ffe:501:ffff::4 NetworkManager: prefix 64 NetworkManager: nameserver '2000::2' NetworkManager: domain search 'ibm.com.' NetworkManager: Activation (eth0) Stage 5 of 5 (IP Configure Commit) scheduled... NetworkManager: Activation (eth0) Stage 4 of 5 (IP6 Configure Get) complete. NetworkManager: Activation (eth0) Stage 5 of 5 (IP Configure Commit) started... PRC: Address 3ffe:501:ffff::4 depreferred. PRC: Expiration scheduled in -8604171 seconds. PRC: Address 3ffe:501:ffff::4 expired. PRC: Bound lease is devoid of active addresses. Re-initializing. PRC: Soliciting for leases (INIT). XMT: Forming Solicit, 0 ms elapsed. XMT: X-- IA_NA 5a:47:1f:71 XMT: | X-- Request renew in +3600 XMT: | X-- Request rebind in +5400 XMT: Solicit on eth0, interval 1040ms. Stopping nscd: [ OK ] Starting nscd: [ OK ] NetworkManager: (eth0): device state change: 7 -> 8 (reason 0) NetworkManager: Activation (eth0) successful, device activated. NetworkManager: Activation (eth0) Stage 5 of 5 (IP Configure Commit) complete. NetworkManager: (eth0): DHCPv6 state changed bound6 -> depref6 NetworkManager: (eth0): DHCPv6 state changed depref6 -> expire6 --- src/nm-device.c | 16 ++++++++++++++++ src/nm-policy.c | 21 +++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/nm-device.c b/src/nm-device.c index ba88c6b0e3..26b00474dc 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1312,6 +1312,22 @@ dhcp_state_changed (NMDHCPClient *client, else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); break; + case DHC_STOP: + case DHC_STOP6: + case DHC_EXPIRE: + case DHC_EXPIRE6: + if (dev_state == NM_DEVICE_STATE_ACTIVATED) { + if (ipv6) + nm_dhcp6_config_reset (priv->dhcp6_config); + else + nm_dhcp4_config_reset (priv->dhcp4_config); + + /* dhclient quit and can't get/renew a lease; so kill the connection */ + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); + } + break; default: break; } diff --git a/src/nm-policy.c b/src/nm-policy.c index 4fccaf4d11..2591de27b6 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -585,10 +585,23 @@ device_state_changed (NMDevice *device, /* Mark the connection invalid if it failed during activation so that * it doesn't get automatically chosen over and over and over again. */ - if (connection && IS_ACTIVATING_STATE (old_state)) { - g_object_set_data (G_OBJECT (connection), INVALID_TAG, GUINT_TO_POINTER (TRUE)); - nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", get_connection_id (connection)); - nm_connection_clear_secrets (connection); + if (connection) { + gboolean fail = FALSE; + + if (IS_ACTIVATING_STATE (old_state)) { + nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", get_connection_id (connection)); + fail = TRUE; + } else if ( (old_state == NM_DEVICE_STATE_ACTIVATED) + && (reason == NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED)) { + nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid because IP configuration expired.", + get_connection_id (connection)); + fail = TRUE; + } + + if (fail) { + g_object_set_data (G_OBJECT (connection), INVALID_TAG, GUINT_TO_POINTER (TRUE)); + nm_connection_clear_secrets (connection); + } } schedule_activate_check (policy, device, 3); break; From 6b63481d4d47882d15704aa60737f3f777d90ae1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 16:37:45 -0700 Subject: [PATCH 042/105] core: prepare for IPv6 routing and DNS stuff --- src/nm-policy.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index 2591de27b6..8693484b9e 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -55,7 +55,7 @@ struct NMPolicy { gulong vpn_activated_id; gulong vpn_deactivated_id; - NMDevice *default_device; + NMDevice *default_device4; HostnameThread *lookup; @@ -276,7 +276,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) } static void -update_routing_and_dns (NMPolicy *policy, gboolean force_update) +update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update) { NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE; NMDevice *best = NULL; @@ -293,7 +293,7 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) best = get_best_device (policy->manager, &best_req); if (!best) goto out; - if (!force_update && (best == policy->default_device)) + if (!force_update && (best == policy->default_device4)) goto out; /* If a VPN connection is active, it is preferred */ @@ -393,10 +393,16 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update) } out: - /* Update the system hostname */ - update_system_hostname (policy, best); + policy->default_device4 = best; +} - policy->default_device = best; +static void +update_routing_and_dns (NMPolicy *policy, gboolean force_update) +{ + update_ip4_routing_and_dns (policy, force_update); + + /* Update the system hostname */ + update_system_hostname (policy, policy->default_device4); } typedef struct { From aaf10a8edbeb1403a252799a7e6da9e8032be72c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 21:48:16 -0700 Subject: [PATCH 043/105] core: don't pointlessly clear IP6 config on success --- src/nm-device.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/nm-device.c b/src/nm-device.c index 26b00474dc..9c14f5ae30 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1960,10 +1960,8 @@ real_act_stage4_get_ip6_config (NMDevice *self, } else { *reason = NM_DEVICE_STATE_REASON_DHCP_ERROR; } - } else { - *config = NULL; + } else ret = NM_ACT_STAGE_RETURN_SUCCESS; - } out: return ret; From 8d0d80d8dfc580010c9b4257e226bce985e19727 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 21:51:09 -0700 Subject: [PATCH 044/105] core: assure a valid IPv6 config on timeout success --- src/nm-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nm-device.c b/src/nm-device.c index 9c14f5ae30..1a96bd3d27 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -2084,7 +2084,7 @@ nm_device_activate_stage4_ip6_config_timeout (gpointer user_data) goto out; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - /* FIXME g_assert (ip6_config); */ + g_assert (ip6_config); g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), NM_ACT_REQUEST_IP6_CONFIG, ip6_config); From bb936cd46c33759acfdc350559667528ccc67b6f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 21:52:10 -0700 Subject: [PATCH 045/105] core: ensure IP stage failure when stuff actually fails --- src/nm-device.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/nm-device.c b/src/nm-device.c index 1a96bd3d27..9d6ee5f410 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -2292,6 +2292,16 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data) assumed = nm_act_request_get_assumed (priv->act_request); + if (!ip6_config && !ip4_config) { + nm_log_info (LOGD_DEVICE, + "Activation (%s) Stage 5 of 5 (IP Configure Commit) failed (no IP configuration found)", + iface); + nm_device_state_changed (self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + goto out; + } + if (ip4_config && !nm_device_set_ip4_config (self, ip4_config, assumed, &reason)) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; @@ -2301,6 +2311,8 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data) nm_log_info (LOGD_DEVICE | LOGD_IP6, "Activation (%s) Stage 5 of 5 (IP Configure Commit) IPv6 failed", iface); + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + goto out; } connection = nm_act_request_get_connection (nm_device_get_act_request (self)); From 837364726bb127027dfc0425d0f8ac29204052cb Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 22:08:56 -0700 Subject: [PATCH 046/105] dns: handle IPv6 nameservers more like IPv4 ones --- src/named-manager/nm-named-manager.c | 66 +++++++++++++++++++--------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/src/named-manager/nm-named-manager.c b/src/named-manager/nm-named-manager.c index 2963652f06..aed25e8ba3 100644 --- a/src/named-manager/nm-named-manager.c +++ b/src/named-manager/nm-named-manager.c @@ -38,6 +38,7 @@ #include "nm-named-manager.h" #include "nm-ip4-config.h" +#include "nm-ip6-config.h" #include "nm-logging.h" #include "nm-system.h" #include "NetworkManagerUtils.h" @@ -60,8 +61,10 @@ G_DEFINE_TYPE(NMNamedManager, nm_named_manager, G_TYPE_OBJECT) struct NMNamedManagerPrivate { - NMIP4Config *vpn_config; - NMIP4Config *device_config; + NMIP4Config *ip4_vpn_config; + NMIP4Config *ip4_device_config; + NMIP6Config *ip6_vpn_config; + NMIP6Config *ip6_device_config; GSList *configs; }; @@ -487,25 +490,33 @@ rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) rc.domain = NULL; rc.searches = g_ptr_array_new (); - if (priv->vpn_config) - merge_one_ip4_config (&rc, priv->vpn_config); + if (priv->ip4_vpn_config) + merge_one_ip4_config (&rc, priv->ip4_vpn_config); + if (priv->ip4_device_config) + merge_one_ip4_config (&rc, priv->ip4_device_config); - if (priv->device_config) - merge_one_ip4_config (&rc, priv->device_config); + if (priv->ip6_vpn_config) + merge_one_ip6_config (&rc, priv->ip6_vpn_config); + if (priv->ip6_device_config) + merge_one_ip6_config (&rc, priv->ip6_device_config); for (iter = priv->configs; iter; iter = g_slist_next (iter)) { + if ( (iter->data == priv->ip4_vpn_config) + || (iter->data == priv->ip4_device_config) + || (iter->data == priv->ip6_vpn_config) + || (iter->data == priv->ip6_device_config)) + continue; + if (NM_IS_IP4_CONFIG (iter->data)) { NMIP4Config *config = NM_IP4_CONFIG (iter->data); - if ((config == priv->vpn_config) || (config == priv->device_config)) - continue; - merge_one_ip4_config (&rc, config); - } else { + } else if (NM_IS_IP6_CONFIG (iter->data)) { NMIP6Config *config = NM_IP6_CONFIG (iter->data); merge_one_ip6_config (&rc, config); - } + } else + g_assert_not_reached (); } domain = rc.domain; @@ -572,10 +583,10 @@ nm_named_manager_add_ip4_config (NMNamedManager *mgr, switch (cfg_type) { case NM_NAMED_IP_CONFIG_TYPE_VPN: - priv->vpn_config = config; + priv->ip4_vpn_config = config; break; case NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE: - priv->device_config = config; + priv->ip4_device_config = config; break; default: break; @@ -613,11 +624,10 @@ nm_named_manager_remove_ip4_config (NMNamedManager *mgr, priv->configs = g_slist_remove (priv->configs, config); - if (config == priv->vpn_config) - priv->vpn_config = NULL; - - if (config == priv->device_config) - priv->device_config = NULL; + if (config == priv->ip4_vpn_config) + priv->ip4_vpn_config = NULL; + if (config == priv->ip4_device_config) + priv->ip4_device_config = NULL; g_object_unref (config); @@ -643,10 +653,21 @@ nm_named_manager_add_ip6_config (NMNamedManager *mgr, g_return_val_if_fail (iface != NULL, FALSE); g_return_val_if_fail (config != NULL, FALSE); - g_return_val_if_fail (cfg_type == NM_NAMED_IP_CONFIG_TYPE_DEFAULT, FALSE); - priv = NM_NAMED_MANAGER_GET_PRIVATE (mgr); + switch (cfg_type) { + case NM_NAMED_IP_CONFIG_TYPE_VPN: + /* FIXME: not quite yet... */ + g_return_val_if_fail (cfg_type != NM_NAMED_IP_CONFIG_TYPE_VPN, FALSE); + priv->ip6_vpn_config = config; + break; + case NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE: + priv->ip6_device_config = config; + break; + default: + break; + } + /* Don't allow the same zone added twice */ if (!g_slist_find (priv->configs, config)) priv->configs = g_slist_append (priv->configs, g_object_ref (config)); @@ -679,6 +700,11 @@ nm_named_manager_remove_ip6_config (NMNamedManager *mgr, priv->configs = g_slist_remove (priv->configs, config); + if (config == priv->ip6_vpn_config) + priv->ip6_vpn_config = NULL; + if (config == priv->ip6_device_config) + priv->ip6_device_config = NULL; + g_object_unref (config); if (!rewrite_resolv_conf (mgr, iface, &error)) { From e218092d62ef5b5767ee2e79f0c3e49072a00b2f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Apr 2010 22:11:22 -0700 Subject: [PATCH 047/105] core: first pass of IPv6 routing and DNS update on IP config change Mostly the same as the IPv4 bits; dupe them for IPv6. A lot of duplicated code, but it's hard to consolidate. --- src/nm-policy.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++-- src/nm-system.c | 152 ++++++++++++++++++++++++++++++++++ src/nm-system.h | 3 + 3 files changed, 362 insertions(+), 6 deletions(-) diff --git a/src/nm-policy.c b/src/nm-policy.c index 8693484b9e..a7bd96f1bb 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -56,6 +56,7 @@ struct NMPolicy { gulong vpn_deactivated_id; NMDevice *default_device4; + NMDevice *default_device6; HostnameThread *lookup; @@ -78,7 +79,7 @@ get_connection_id (NMConnection *connection) } static NMDevice * -get_best_device (NMManager *manager, NMActRequest **out_req) +get_best_ip4_device (NMManager *manager, NMActRequest **out_req) { GSList *devices, *iter; NMDevice *best = NULL; @@ -150,6 +151,79 @@ get_best_device (NMManager *manager, NMActRequest **out_req) return best; } +static NMDevice * +get_best_ip6_device (NMManager *manager, NMActRequest **out_req) +{ + GSList *devices, *iter; + NMDevice *best = NULL; + int best_prio = G_MAXINT; + + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (NM_IS_MANAGER (manager), NULL); + g_return_val_if_fail (out_req != NULL, NULL); + g_return_val_if_fail (*out_req == NULL, NULL); + + devices = nm_manager_get_devices (manager); + for (iter = devices; iter; iter = g_slist_next (iter)) { + NMDevice *dev = NM_DEVICE (iter->data); + NMActRequest *req; + NMConnection *connection; + NMIP6Config *ip6_config; + NMSettingIP6Config *s_ip6; + int prio; + guint i; + gboolean can_default = FALSE; + const char *method = NULL; + + if (nm_device_get_state (dev) != NM_DEVICE_STATE_ACTIVATED) + continue; + + ip6_config = nm_device_get_ip6_config (dev); + if (!ip6_config) + continue; + + req = nm_device_get_act_request (dev); + g_assert (req); + connection = nm_act_request_get_connection (req); + g_assert (connection); + + /* Never set the default route through an IPv4LL-addressed device */ + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6) + method = nm_setting_ip6_config_get_method (s_ip6); + + if (method && !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) + continue; + + /* Make sure at least one of this device's IP addresses has a gateway */ + for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) { + NMIP6Address *addr; + + addr = nm_ip6_config_get_address (ip6_config, i); + if (nm_ip6_address_get_gateway (addr)) { + can_default = TRUE; + break; + } + } + + if (!can_default && !NM_IS_DEVICE_MODEM (dev)) + continue; + + /* 'never-default' devices can't ever be the default */ + if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6)) + continue; + + prio = nm_device_get_priority (dev); + if (prio > 0 && prio < best_prio) { + best = dev; + best_prio = prio; + *out_req = req; + } + } + + return best; +} + static void _set_hostname (const char *new_hostname, const char *msg) { @@ -215,7 +289,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best) /* Try automatically determined hostname from the best device's IP config */ if (!best) - best = get_best_device (policy->manager, &best_req); + best = get_best_ip4_device (policy->manager, &best_req); if (!best) { /* No best device; fall back to original hostname or if there wasn't @@ -290,7 +364,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update) NMSettingConnection *s_con = NULL; const char *connection_id; - best = get_best_device (policy->manager, &best_req); + best = get_best_ip4_device (policy->manager, &best_req); if (!best) goto out; if (!force_update && (best == policy->default_device4)) @@ -387,19 +461,146 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update) connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL; if (connection_id) { - nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for routing and DNS.", connection_id, ip_iface); + nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv4 routing and DNS.", connection_id, ip_iface); } else { - nm_log_info (LOGD_CORE, "Policy set (%s) as default for routing and DNS.", ip_iface); + nm_log_info (LOGD_CORE, "Policy set (%s) as default for IPv4 routing and DNS.", ip_iface); } out: - policy->default_device4 = best; + policy->default_device4 = best; +} + +static void +update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update) +{ + NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE; + NMDevice *best = NULL; + NMActRequest *best_req = NULL; + NMNamedManager *named_mgr; + GSList *devices = NULL, *iter; +#if NOT_YET + GSList *vpns; +#endif + NMIP6Config *ip6_config = NULL; + NMIP6Address *addr; + const char *ip_iface = NULL; + NMConnection *connection = NULL; + NMSettingConnection *s_con = NULL; + const char *connection_id; + + best = get_best_ip6_device (policy->manager, &best_req); + if (!best) + goto out; + if (!force_update && (best == policy->default_device6)) + goto out; + +#if NOT_YET + /* If a VPN connection is active, it is preferred */ + vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager); + for (iter = vpns; iter; iter = g_slist_next (iter)) { + NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data); + NMConnection *vpn_connection; + NMSettingIP6Config *s_ip6; + gboolean can_default = TRUE; + NMVPNConnectionState vpn_state; + + /* If it's marked 'never-default', don't make it default */ + vpn_connection = nm_vpn_connection_get_connection (candidate); + g_assert (vpn_connection); + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (vpn_connection, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6)) + can_default = FALSE; + + vpn_state = nm_vpn_connection_get_vpn_state (candidate); + if (can_default && (vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED)) { + NMIP6Config *parent_ip6; + NMDevice *parent; + + ip_iface = nm_vpn_connection_get_ip_iface (candidate); + connection = nm_vpn_connection_get_connection (candidate); + ip6_config = nm_vpn_connection_get_ip6_config (candidate); + addr = nm_ip6_config_get_address (ip6_config, 0); + + parent = nm_vpn_connection_get_parent_device (candidate); + parent_ip6 = nm_device_get_ip6_config (parent); + + nm_system_replace_default_ip6_route_vpn (ip_iface, + nm_ip6_address_get_gateway (addr), + nm_vpn_connection_get_ip4_internal_gateway (candidate), + nm_ip6_config_get_mss (ip4_config), + nm_device_get_ip_iface (parent), + nm_ip6_config_get_mss (parent_ip4)); + + dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN; + } + g_object_unref (candidate); + } + g_slist_free (vpns); +#endif + + /* The best device gets the default route if a VPN connection didn't */ + if (!ip_iface || !ip6_config) { + connection = nm_act_request_get_connection (best_req); + ip_iface = nm_device_get_ip_iface (best); + ip6_config = nm_device_get_ip6_config (best); + g_assert (ip6_config); + addr = nm_ip6_config_get_address (ip6_config, 0); + + nm_system_replace_default_ip6_route (ip_iface, nm_ip6_address_get_gateway (addr)); + + dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE; + } + + if (!ip_iface || !ip6_config) { + nm_log_warn (LOGD_CORE, "couldn't determine IP interface (%p) or IPv6 config (%p)!", + ip_iface, ip6_config); + goto out; + } + + /* Update the default active connection. Only mark the new default + * active connection after setting default = FALSE on all other connections + * first. The order is important, we don't want two connections marked + * default at the same time ever. + */ + devices = nm_manager_get_devices (policy->manager); + for (iter = devices; iter; iter = g_slist_next (iter)) { + NMDevice *dev = NM_DEVICE (iter->data); + NMActRequest *req; + + req = nm_device_get_act_request (dev); + if (req && (req != best_req)) + nm_act_request_set_default6 (req, FALSE); + } + + named_mgr = nm_named_manager_get (); + nm_named_manager_add_ip6_config (named_mgr, ip_iface, ip6_config, dns_type); + g_object_unref (named_mgr); + + /* Now set new default active connection _after_ updating DNS info, so that + * if the connection is shared dnsmasq picks up the right stuff. + */ + if (best_req) + nm_act_request_set_default6 (best_req, TRUE); + + if (connection) + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + + connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL; + if (connection_id) { + nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv6 routing and DNS.", connection_id, ip_iface); + } else { + nm_log_info (LOGD_CORE, "Policy set (%s) as default for IPv6 routing and DNS.", ip_iface); + } + +out: + policy->default_device6 = best; } static void update_routing_and_dns (NMPolicy *policy, gboolean force_update) { update_ip4_routing_and_dns (policy, force_update); + update_ip6_routing_and_dns (policy, force_update); /* Update the system hostname */ update_system_hostname (policy, policy->default_device4); diff --git a/src/nm-system.c b/src/nm-system.c index 2e03c41a8e..ccb0a47a19 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -940,6 +940,158 @@ nm_system_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss) return success; } +static struct rtnl_route * +add_ip6_route_to_gateway (const char *iface, const struct in6_addr *gw) +{ + struct nl_handle *nlh; + struct rtnl_route *route = NULL; + struct nl_addr *gw_addr = NULL; + int iface_idx, err; + + nlh = nm_netlink_get_default_handle (); + g_return_val_if_fail (nlh != NULL, NULL); + + iface_idx = nm_netlink_iface_to_index (iface); + if (iface_idx < 0) + return NULL; + + /* Gateway might be over a bridge; try adding a route to gateway first */ + route = rtnl_route_alloc (); + if (route == NULL) + return NULL; + + rtnl_route_set_family (route, AF_INET6); + rtnl_route_set_table (route, RT_TABLE_MAIN); + rtnl_route_set_oif (route, iface_idx); + rtnl_route_set_scope (route, RT_SCOPE_LINK); + + gw_addr = nl_addr_build (AF_INET, (void *) gw, sizeof (*gw)); + if (!gw_addr) + goto error; + nl_addr_set_prefixlen (gw_addr, 128); + rtnl_route_set_dst (route, gw_addr); + nl_addr_put (gw_addr); + + /* Add direct route to the gateway */ + err = rtnl_route_add (nlh, route, 0); + if (err) { + nm_log_err (LOGD_DEVICE | LOGD_IP6, + "(%s): failed to add IPv4 route to gateway (%d)", + iface, err); + goto error; + } + + return route; + +error: + rtnl_route_put (route); + return NULL; +} + +static int +replace_default_ip6_route (const char *iface, const struct in6_addr *gw) +{ + struct rtnl_route *route = NULL; + struct nl_handle *nlh; + struct nl_addr *dst_addr = NULL; + struct nl_addr *gw_addr = NULL; + struct in6_addr dst; + int iface_idx, err = -1; + + g_return_val_if_fail (iface != NULL, -ENODEV); + + nlh = nm_netlink_get_default_handle (); + g_return_val_if_fail (nlh != NULL, -ENOMEM); + + iface_idx = nm_netlink_iface_to_index (iface); + if (iface_idx < 0) + return -ENODEV; + + route = rtnl_route_alloc(); + g_return_val_if_fail (route != NULL, -ENOMEM); + + rtnl_route_set_family (route, AF_INET6); + rtnl_route_set_table (route, RT_TABLE_MAIN); + rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); + rtnl_route_set_oif (route, iface_idx); + + /* Build up the destination address */ + memset (&dst, 0, sizeof (dst)); + dst_addr = nl_addr_build (AF_INET6, &dst, sizeof (dst)); + if (!dst_addr) { + err = -ENOMEM; + goto out; + } + nl_addr_set_prefixlen (dst_addr, 0); + rtnl_route_set_dst (route, dst_addr); + + /* Build up the gateway address */ + gw_addr = nl_addr_build (AF_INET6, (void *) gw, sizeof (*gw)); + if (!gw_addr) { + err = -ENOMEM; + goto out; + } + nl_addr_set_prefixlen (gw_addr, 0); + rtnl_route_set_gateway (route, gw_addr); + + /* Add the new default route */ + err = rtnl_route_add (nlh, route, NLM_F_REPLACE); + +out: + if (dst_addr) + nl_addr_put (dst_addr); + if (gw_addr) + nl_addr_put (gw_addr); + rtnl_route_put (route); + return err; +} + +/* + * nm_system_replace_default_ip6_route + * + * Replace default IPv6 route with one via the given gateway + * + */ +gboolean +nm_system_replace_default_ip6_route (const char *iface, const struct in6_addr *gw) +{ + struct rtnl_route *gw_route = NULL; + struct nl_handle *nlh; + gboolean success = FALSE; + int err; + + nlh = nm_netlink_get_default_handle (); + g_return_val_if_fail (nlh != NULL, FALSE); + + err = replace_default_ip6_route (iface, gw); + if (err == 0) { + return TRUE; + } else if (err != -ESRCH) { + nm_log_err (LOGD_DEVICE | LOGD_IP6, + "(%s): failed to set IPv6 default route: %d", + iface, err); + return FALSE; + } + + /* Try adding a direct route to the gateway first */ + gw_route = add_ip6_route_to_gateway (iface, gw); + if (!gw_route) + return FALSE; + + /* Try adding the original route again */ + err = replace_default_ip6_route (iface, gw); + if (err != 0) { + rtnl_route_del (nlh, gw_route, 0); + nm_log_err (LOGD_DEVICE | LOGD_IP6, + "(%s): failed to set IPv6 default route (pass #2): %d", + iface, err); + } else + success = TRUE; + + rtnl_route_put (gw_route); + return success; +} + static void flush_addresses (const char *iface, gboolean ipv4_only) { int iface_idx; diff --git a/src/nm-system.h b/src/nm-system.h index f2c2693ac1..e48e493c61 100644 --- a/src/nm-system.h +++ b/src/nm-system.h @@ -40,6 +40,9 @@ gboolean nm_system_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss); +gboolean nm_system_replace_default_ip6_route (const char *iface, + const struct in6_addr *gw); + gboolean nm_system_replace_default_ip4_route_vpn (const char *iface, guint32 ext_gw, guint32 int_gw, From 08c33651c7bff1b4635fe5f0170b8eca3a522800 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 26 Apr 2010 13:51:19 -0700 Subject: [PATCH 048/105] test: needs -ldl too for logger code --- src/tests/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 39a994c39b..62612a0e15 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -35,6 +35,7 @@ test_policy_hosts_CPPFLAGS = \ $(GLIB_CFLAGS) test_policy_hosts_LDADD = \ + -ldl \ $(top_builddir)/src/libtest-policy-hosts.la \ $(GLIB_LIBS) From 11a6225aac73d87ab4f4f0102fb0177893608494 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 26 Apr 2010 14:06:58 -0700 Subject: [PATCH 049/105] ip6: correctly handle routes with no gateways For these we don't need to set any gateway at all, and the kernel assumes that it's a default route without a next hop. --- src/nm-system.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/src/nm-system.c b/src/nm-system.c index ccb0a47a19..20d06b83ad 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -460,7 +460,7 @@ nm_system_device_set_ip6_route (const char *iface, g_return_val_if_fail (route != NULL, NULL); /* Destination */ - dest_addr = nl_addr_build (AF_INET6, (struct in6_addr *)ip6_dest, sizeof (*ip6_dest)); + dest_addr = nl_addr_build (AF_INET6, (struct in6_addr *) ip6_dest, sizeof (*ip6_dest)); g_return_val_if_fail (dest_addr != NULL, NULL); nl_addr_set_prefixlen (dest_addr, (int) ip6_prefix); @@ -469,7 +469,7 @@ nm_system_device_set_ip6_route (const char *iface, /* Gateway */ if (ip6_gateway && !IN6_IS_ADDR_UNSPECIFIED (ip6_gateway)) { - gw_addr = nl_addr_build (AF_INET6, (struct in6_addr *)ip6_gateway, sizeof (*ip6_gateway)); + gw_addr = nl_addr_build (AF_INET6, (struct in6_addr *) ip6_gateway, sizeof (*ip6_gateway)); if (gw_addr) { rtnl_route_set_gateway (route, gw_addr); rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); @@ -993,9 +993,7 @@ replace_default_ip6_route (const char *iface, const struct in6_addr *gw) { struct rtnl_route *route = NULL; struct nl_handle *nlh; - struct nl_addr *dst_addr = NULL; struct nl_addr *gw_addr = NULL; - struct in6_addr dst; int iface_idx, err = -1; g_return_val_if_fail (iface != NULL, -ENODEV); @@ -1015,31 +1013,28 @@ replace_default_ip6_route (const char *iface, const struct in6_addr *gw) rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); rtnl_route_set_oif (route, iface_idx); - /* Build up the destination address */ - memset (&dst, 0, sizeof (dst)); - dst_addr = nl_addr_build (AF_INET6, &dst, sizeof (dst)); - if (!dst_addr) { - err = -ENOMEM; - goto out; + if (gw && !IN6_IS_ADDR_UNSPECIFIED (gw)) { + /* Build up the gateway address */ + gw_addr = nl_addr_build (AF_INET6, (void *) gw, sizeof (*gw)); + if (!gw_addr) { + err = -ENOMEM; + goto out; + } + nl_addr_set_prefixlen (gw_addr, -1); + rtnl_route_set_gateway (route, gw_addr); } - nl_addr_set_prefixlen (dst_addr, 0); - rtnl_route_set_dst (route, dst_addr); - - /* Build up the gateway address */ - gw_addr = nl_addr_build (AF_INET6, (void *) gw, sizeof (*gw)); - if (!gw_addr) { - err = -ENOMEM; - goto out; - } - nl_addr_set_prefixlen (gw_addr, 0); - rtnl_route_set_gateway (route, gw_addr); /* Add the new default route */ err = rtnl_route_add (nlh, route, NLM_F_REPLACE); + if (err == -EEXIST) { + /* FIXME: even though we use NLM_F_REPLACE the kernel won't replace + * the route if it's the same. Should try to remove it first, then + * add the new one again here. + */ + err = 0; + } out: - if (dst_addr) - nl_addr_put (dst_addr); if (gw_addr) nl_addr_put (gw_addr); rtnl_route_put (route); From de1a4dcc4b74885cf8f136f00eb30b06f0836646 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 26 Apr 2010 14:08:10 -0700 Subject: [PATCH 050/105] ip6: fix autoconf address and route scraping Two things: 1) we need to bounce IPv6 on the interface because otherwise the kernel won't start listening for new RAs. So code gets added to handle the 'disable_ipv6' /proc/sys/net/ipv6 parameter for each interface. 2) Second, we need to grab a default route (if we find one) before reading addresses, so that we can add it to each address that we get out of the kernel. Most of the time we'll get an -EEXIST error when adding address, but that's OK since we're just trying to add the same route back that the kernel already added from the RA. We also need to make sure the route and address caches are up-to-date otherwise we won't get a complete picture of the routing table. --- src/ip6-manager/nm-ip6-manager.c | 172 +++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 57 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 7767870186..6bf928c1a8 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -30,6 +30,7 @@ #include "NetworkManagerUtils.h" #include "nm-marshal.h" #include "nm-logging.h" +#include "nm-system.h" /* Pre-DHCP addrconf timeout, in seconds */ #define NM_IP6_TIMEOUT 10 @@ -72,6 +73,10 @@ typedef struct { gboolean accept_ra_save_valid; guint32 accept_ra_save; + char *disable_ip6_path; + gboolean disable_ip6_save_valid; + guint32 disable_ip6_save; + guint finish_addrconf_id; guint config_changed_id; @@ -192,6 +197,12 @@ nm_ip6_device_destroy (NMIP6Device *device) device->accept_ra_save ? "1\n" : "0\n"); } + /* reset the saved IPv6 value */ + if (device->disable_ip6_save_valid) { + nm_utils_do_sysctl (device->disable_ip6_path, + device->disable_ip6_save ? "1\n" : "0\n"); + } + if (device->finish_addrconf_id) g_source_remove (device->finish_addrconf_id); if (device->config_changed_id) @@ -699,13 +710,38 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us nm_ip6_device_sync_from_netlink (device, config_changed); } +static gboolean +get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value) +{ + GError *error; + char *contents = NULL; + gboolean success = FALSE; + long int tmp; + + if (!g_file_get_contents (path, &contents, NULL, &error)) { + nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s", + iface, path, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } else { + errno = 0; + tmp = strtol (contents, NULL, 10); + if ((errno == 0) && (tmp == 0 || tmp == 1)) { + *out_value = (guint32) tmp; + success = TRUE; + } + g_free (contents); + } + + return success; +} + static NMIP6Device * nm_ip6_device_new (NMIP6Manager *manager, int ifindex) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); NMIP6Device *device; - GError *error = NULL; - char *contents = NULL; g_return_val_if_fail (ifindex > 0, NULL); @@ -724,15 +760,6 @@ nm_ip6_device_new (NMIP6Manager *manager, int ifindex) goto error; } - device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", - device->iface); - if (!device->accept_ra_path) { - nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 addrconf object " - "property 'accept_ra_path'.", - device->iface); - goto error; - } - device->manager = manager; device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS)); @@ -742,23 +769,20 @@ nm_ip6_device_new (NMIP6Manager *manager, int ifindex) /* Grab the original value of "accept_ra" so we can restore it when the * device is taken down. */ - if (!g_file_get_contents (device->accept_ra_path, &contents, NULL, &error)) { - nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s", - device->iface, device->accept_ra_path, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } else { - long int tmp; + device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", + device->iface); + g_assert (device->accept_ra_path); + device->accept_ra_save_valid = get_proc_sys_net_value (device->accept_ra_path, + device->iface, + &device->accept_ra_save); - errno = 0; - tmp = strtol (contents, NULL, 10); - if ((errno == 0) && (tmp == 0 || tmp == 1)) { - device->accept_ra_save = (guint32) tmp; - device->accept_ra_save_valid = TRUE; - } - g_free (contents); - } + /* and the original value of IPv6 enable/disable */ + device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6", + device->iface); + g_assert (device->disable_ip6_path); + device->disable_ip6_save_valid = get_proc_sys_net_value (device->disable_ip6_path, + device->iface, + &device->disable_ip6_save); return device; @@ -782,25 +806,25 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager, priv = NM_IP6_MANAGER_GET_PRIVATE (manager); device = nm_ip6_device_new (manager, ifindex); + g_return_if_fail (device != NULL); + g_return_if_fail ( strchr (device->iface, '/') == NULL + && strcmp (device->iface, "all") != 0 + && strcmp (device->iface, "default") != 0); if (s_ip6) method = nm_setting_ip6_config_get_method (s_ip6); if (!method) method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; + /* Establish target state and turn router advertisement acceptance on or off */ if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) - || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) + || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL; - else + nm_utils_do_sysctl (device->accept_ra_path, "0\n"); + } else { device->target_state = NM_IP6_DEVICE_GOT_ADDRESS; - - g_return_if_fail ( strchr (device->iface, '/') == NULL - && strcmp (device->iface, "all") != 0 - && strcmp (device->iface, "default") != 0); - - /* Turn router advertisement acceptance on or off... */ - nm_utils_do_sysctl (device->accept_ra_path, - device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS ? "1\n" : "0\n"); + nm_utils_do_sysctl (device->accept_ra_path, "1\n"); + } } static gboolean @@ -838,6 +862,15 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex) info, (GDestroyNotify) g_free); + /* Bounce IPv6 on the interface to ensure the kernel will start looking for + * new RAs; there doesn't seem to be a better way to do this right now. + */ + if (device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS) { + nm_utils_do_sysctl (device->disable_ip6_path, "1\n"); + g_usleep (200); + nm_utils_do_sysctl (device->disable_ip6_path, "0\n"); + } + device->ip6flags_poll_id = g_timeout_add_seconds (1, poll_ip6_flags, priv->monitor); /* Kick off the initial IPv6 flags request */ @@ -860,6 +893,12 @@ nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, int ifindex) GINT_TO_POINTER (ifindex)); } +#define FIRST_ROUTE(m) ((struct rtnl_route *) nl_cache_get_first (m)) +#define NEXT_ROUTE(m) ((struct rtnl_route *) nl_cache_get_next ((struct nl_object *) m)) + +#define FIRST_ADDR(m) ((struct rtnl_addr *) nl_cache_get_first (m)) +#define NEXT_ADDR(m) ((struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) m)) + NMIP6Config * nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) { @@ -873,6 +912,8 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) struct rtnl_route *rtnlroute; struct nl_addr *nldest, *nlgateway; struct in6_addr *dest, *gateway; + gboolean defgw_set = FALSE; + struct in6_addr defgw; uint32_t metric; NMIP6Route *ip6route; int i; @@ -896,30 +937,20 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) return NULL; } - /* Add addresses */ - for (rtnladdr = (struct rtnl_addr *)nl_cache_get_first (priv->addr_cache); - rtnladdr; - rtnladdr = (struct rtnl_addr *)nl_cache_get_next ((struct nl_object *)rtnladdr)) { - if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) - continue; - - nladdr = rtnl_addr_get_local (rtnladdr); - if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) - continue; - - addr = nl_addr_get_binary_addr (nladdr); - ip6addr = nm_ip6_address_new (); - nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr)); - nm_ip6_address_set_address (ip6addr, addr); - nm_ip6_config_take_address (config, ip6addr); - } + /* Make sure we refill the route and address caches, otherwise we won't get + * up-to-date information here since the netlink route/addr change messages + * may be lagging a bit. + */ + nl_cache_refill (priv->nlh, priv->route_cache); + nl_cache_refill (priv->nlh, priv->addr_cache); /* Add routes */ - for (rtnlroute = (struct rtnl_route *)nl_cache_get_first (priv->route_cache); - rtnlroute; - rtnlroute = (struct rtnl_route *)nl_cache_get_next ((struct nl_object *)rtnlroute)) { + for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) { + /* Make sure it's an IPv6 route for this device */ if (rtnl_route_get_oif (rtnlroute) != device->ifindex) continue; + if (rtnl_route_get_family (rtnlroute) != AF_INET6) + continue; nldest = rtnl_route_get_dst (rtnlroute); if (!nldest || nl_addr_get_family (nldest) != AF_INET6) @@ -931,6 +962,15 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) continue; gateway = nl_addr_get_binary_addr (nlgateway); + if (rtnl_route_get_dst_len (rtnlroute) == 0) { + /* Default gateway route; don't add to normal routes but to each address */ + if (!defgw_set) { + memcpy (&defgw, gateway, sizeof (defgw)); + defgw_set = TRUE; + } + continue; + } + ip6route = nm_ip6_route_new (); nm_ip6_route_set_dest (ip6route, dest); nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute)); @@ -941,6 +981,24 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) nm_ip6_config_take_route (config, ip6route); } + /* Add addresses */ + for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) { + if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) + continue; + + nladdr = rtnl_addr_get_local (rtnladdr); + if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) + continue; + + addr = nl_addr_get_binary_addr (nladdr); + ip6addr = nm_ip6_address_new (); + nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr)); + nm_ip6_address_set_address (ip6addr, addr); + nm_ip6_config_take_address (config, ip6addr); + if (defgw_set) + nm_ip6_address_set_gateway (ip6addr, &defgw); + } + /* Add DNS servers */ if (device->rdnss_servers) { NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data); From b127f4aa98d722a5c48272b7a5d1ba8c9e847db9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 26 Apr 2010 15:04:01 -0700 Subject: [PATCH 051/105] ip6: move class boilerplate/setup to the bottom --- src/ip6-manager/nm-ip6-manager.c | 377 ++++++++++++++++--------------- 1 file changed, 190 insertions(+), 187 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 6bf928c1a8..4ea9538d5b 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -51,6 +51,16 @@ typedef struct { #define NM_IP6_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_MANAGER, NMIP6ManagerPrivate)) +G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT) + +enum { + ADDRCONF_COMPLETE, + CONFIG_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + typedef enum { NM_IP6_DEVICE_UNCONFIGURED, NM_IP6_DEVICE_GOT_LINK_LOCAL, @@ -64,6 +74,8 @@ typedef struct { time_t expires; } NMIP6RDNSS; +/******************************************************************/ + typedef struct { NMIP6Manager *manager; char *iface; @@ -92,100 +104,6 @@ typedef struct { guint32 ra_flags; } NMIP6Device; -G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT) - -enum { - ADDRCONF_COMPLETE, - CONFIG_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static NMIP6Manager *nm_ip6_manager_new (void); - -static void netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data); - -static void nm_ip6_device_destroy (NMIP6Device *device); - -NMIP6Manager * -nm_ip6_manager_get (void) -{ - static NMIP6Manager *singleton = NULL; - - if (!singleton) - singleton = nm_ip6_manager_new (); - g_assert (singleton); - - return g_object_ref (singleton); -} - -static void -nm_ip6_manager_init (NMIP6Manager *manager) -{ - NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - - priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, - (GDestroyNotify) nm_ip6_device_destroy); - - priv->monitor = nm_netlink_monitor_get (); - nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL); - nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL); - nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL); - nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL); - - g_signal_connect (priv->monitor, "notification", - G_CALLBACK (netlink_notification), manager); - - priv->nlh = nm_netlink_get_default_handle (); - priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh); - priv->route_cache = rtnl_route_alloc_cache (priv->nlh); -} - -static void -finalize (GObject *object) -{ - NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object); - - g_hash_table_destroy (priv->devices); - g_object_unref (priv->monitor); - nl_cache_free (priv->addr_cache); - nl_cache_free (priv->route_cache); - - G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object); -} - -static void -nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (manager_class); - - g_type_class_add_private (manager_class, sizeof (NMIP6ManagerPrivate)); - - /* virtual methods */ - object_class->finalize = finalize; - - /* signals */ - signals[ADDRCONF_COMPLETE] = - g_signal_new ("addrconf-complete", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete), - NULL, NULL, - _nm_marshal_VOID__INT_UINT_BOOLEAN, - G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN); - - signals[CONFIG_CHANGED] = - g_signal_new ("config-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed), - NULL, NULL, - _nm_marshal_VOID__INT_UINT, - G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT); -} - static void nm_ip6_device_destroy (NMIP6Device *device) { @@ -219,22 +137,85 @@ nm_ip6_device_destroy (NMIP6Device *device) g_slice_free (NMIP6Device, device); } -static NMIP6Manager * -nm_ip6_manager_new (void) +static gboolean +get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value) { - NMIP6Manager *manager; - NMIP6ManagerPrivate *priv; + GError *error; + char *contents = NULL; + gboolean success = FALSE; + long int tmp; - manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL); - priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - - if (!priv->devices) { - nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables"); - g_object_unref (manager); - manager = NULL; + if (!g_file_get_contents (path, &contents, NULL, &error)) { + nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s", + iface, path, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } else { + errno = 0; + tmp = strtol (contents, NULL, 10); + if ((errno == 0) && (tmp == 0 || tmp == 1)) { + *out_value = (guint32) tmp; + success = TRUE; + } + g_free (contents); } - return manager; + return success; +} + +static NMIP6Device * +nm_ip6_device_new (NMIP6Manager *manager, int ifindex) +{ + NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); + NMIP6Device *device; + + g_return_val_if_fail (ifindex > 0, NULL); + + device = g_slice_new0 (NMIP6Device); + if (!device) { + nm_log_err (LOGD_IP6, "(%d): out of memory creating IP6 addrconf object.", + ifindex); + return NULL; + } + + device->ifindex = ifindex; + device->iface = g_strdup (nm_netlink_index_to_iface (ifindex)); + if (!device->iface) { + nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.", + ifindex); + goto error; + } + + device->manager = manager; + + device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS)); + + g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device); + + /* Grab the original value of "accept_ra" so we can restore it when the + * device is taken down. + */ + device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", + device->iface); + g_assert (device->accept_ra_path); + device->accept_ra_save_valid = get_proc_sys_net_value (device->accept_ra_path, + device->iface, + &device->accept_ra_save); + + /* and the original value of IPv6 enable/disable */ + device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6", + device->iface); + g_assert (device->disable_ip6_path); + device->disable_ip6_save_valid = get_proc_sys_net_value (device->disable_ip6_path, + device->iface, + &device->disable_ip6_save); + + return device; + +error: + nm_ip6_device_destroy (device); + return NULL; } static NMIP6Device * @@ -245,6 +226,8 @@ nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex) return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex)); } +/******************************************************************/ + typedef struct { NMIP6Device *device; guint dhcp_opts; @@ -710,87 +693,6 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us nm_ip6_device_sync_from_netlink (device, config_changed); } -static gboolean -get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value) -{ - GError *error; - char *contents = NULL; - gboolean success = FALSE; - long int tmp; - - if (!g_file_get_contents (path, &contents, NULL, &error)) { - nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s", - iface, path, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } else { - errno = 0; - tmp = strtol (contents, NULL, 10); - if ((errno == 0) && (tmp == 0 || tmp == 1)) { - *out_value = (guint32) tmp; - success = TRUE; - } - g_free (contents); - } - - return success; -} - -static NMIP6Device * -nm_ip6_device_new (NMIP6Manager *manager, int ifindex) -{ - NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); - NMIP6Device *device; - - g_return_val_if_fail (ifindex > 0, NULL); - - device = g_slice_new0 (NMIP6Device); - if (!device) { - nm_log_err (LOGD_IP6, "(%d): out of memory creating IP6 addrconf object.", - ifindex); - return NULL; - } - - device->ifindex = ifindex; - device->iface = g_strdup (nm_netlink_index_to_iface (ifindex)); - if (!device->iface) { - nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.", - ifindex); - goto error; - } - - device->manager = manager; - - device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS)); - - g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device); - - /* Grab the original value of "accept_ra" so we can restore it when the - * device is taken down. - */ - device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", - device->iface); - g_assert (device->accept_ra_path); - device->accept_ra_save_valid = get_proc_sys_net_value (device->accept_ra_path, - device->iface, - &device->accept_ra_save); - - /* and the original value of IPv6 enable/disable */ - device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6", - device->iface); - g_assert (device->disable_ip6_path); - device->disable_ip6_save_valid = get_proc_sys_net_value (device->disable_ip6_path, - device->iface, - &device->disable_ip6_save); - - return device; - -error: - nm_ip6_device_destroy (device); - return NULL; -} - void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, int ifindex, @@ -1009,3 +911,104 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) return config; } + +/******************************************************************/ + +static NMIP6Manager * +nm_ip6_manager_new (void) +{ + NMIP6Manager *manager; + NMIP6ManagerPrivate *priv; + + manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL); + priv = NM_IP6_MANAGER_GET_PRIVATE (manager); + + if (!priv->devices) { + nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables"); + g_object_unref (manager); + manager = NULL; + } + + return manager; +} + +NMIP6Manager * +nm_ip6_manager_get (void) +{ + static NMIP6Manager *singleton = NULL; + + if (!singleton) { + singleton = nm_ip6_manager_new (); + g_assert (singleton); + } else + g_object_ref (singleton); + + return singleton; +} + +static void +nm_ip6_manager_init (NMIP6Manager *manager) +{ + NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); + + priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, + (GDestroyNotify) nm_ip6_device_destroy); + + priv->monitor = nm_netlink_monitor_get (); + nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL); + nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL); + nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL); + nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL); + + g_signal_connect (priv->monitor, "notification", + G_CALLBACK (netlink_notification), manager); + + priv->nlh = nm_netlink_get_default_handle (); + priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh); + priv->route_cache = rtnl_route_alloc_cache (priv->nlh); +} + +static void +finalize (GObject *object) +{ + NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object); + + g_hash_table_destroy (priv->devices); + g_object_unref (priv->monitor); + nl_cache_free (priv->addr_cache); + nl_cache_free (priv->route_cache); + + G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object); +} + +static void +nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (manager_class); + + g_type_class_add_private (manager_class, sizeof (NMIP6ManagerPrivate)); + + /* virtual methods */ + object_class->finalize = finalize; + + /* signals */ + signals[ADDRCONF_COMPLETE] = + g_signal_new ("addrconf-complete", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete), + NULL, NULL, + _nm_marshal_VOID__INT_UINT_BOOLEAN, + G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN); + + signals[CONFIG_CHANGED] = + g_signal_new ("config-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed), + NULL, NULL, + _nm_marshal_VOID__INT_UINT, + G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT); +} + From 5331c22adf3335cfd57ddb017fadb0556d37d9bf Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 26 Apr 2010 16:09:25 -0700 Subject: [PATCH 052/105] dns: filter duplicates while constructing resolv.conf --- src/named-manager/nm-named-manager.c | 44 ++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/named-manager/nm-named-manager.c b/src/named-manager/nm-named-manager.c index 2963652f06..0e3310112d 100644 --- a/src/named-manager/nm-named-manager.c +++ b/src/named-manager/nm-named-manager.c @@ -97,6 +97,26 @@ typedef struct { GPtrArray *searches; } NMResolvConfData; +static void +add_string_item (GPtrArray *array, const char *str) +{ + int i; + + g_return_if_fail (array != NULL); + g_return_if_fail (str != NULL); + + /* Check for dupes before adding */ + for (i = 0; i < array->len; i++) { + const char *candidate = g_ptr_array_index (array, i); + + if (candidate && !strcmp (candidate, str)) + return; + } + + /* No dupes, add the new item */ + g_ptr_array_add (array, g_strdup (str)); +} + static void merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src) { @@ -109,19 +129,22 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src) addr.s_addr = nm_ip4_config_get_nameserver (src, i); if (inet_ntop (AF_INET, &addr, buf, INET_ADDRSTRLEN) > 0) - g_ptr_array_add (rc->nameservers, g_strdup (buf)); + add_string_item (rc->nameservers, buf); } num = nm_ip4_config_get_num_domains (src); for (i = 0; i < num; i++) { + const char *domain; + + domain = nm_ip4_config_get_domain (src, i); if (!rc->domain) - rc->domain = nm_ip4_config_get_domain (src, i); - g_ptr_array_add (rc->searches, g_strdup (nm_ip4_config_get_domain (src, i))); + rc->domain = domain; + add_string_item (rc->searches, domain); } num = nm_ip4_config_get_num_searches (src); for (i = 0; i < num; i++) - g_ptr_array_add (rc->searches, g_strdup (nm_ip4_config_get_search (src, i))); + add_string_item (rc->searches, nm_ip4_config_get_search (src, i)); } static void @@ -139,23 +162,26 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src) /* inet_ntop is probably supposed to do this for us, but it doesn't */ if (IN6_IS_ADDR_V4MAPPED (addr)) { if (inet_ntop (AF_INET, &(addr->s6_addr32[3]), buf, INET_ADDRSTRLEN) > 0) - g_ptr_array_add (rc->nameservers, g_strdup (buf)); + add_string_item (rc->nameservers, buf); } else { if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) - g_ptr_array_add (rc->nameservers, g_strdup (buf)); + add_string_item (rc->nameservers, buf); } } num = nm_ip6_config_get_num_domains (src); for (i = 0; i < num; i++) { + const char *domain; + + domain = nm_ip6_config_get_domain (src, i); if (!rc->domain) - rc->domain = nm_ip6_config_get_domain (src, i); - g_ptr_array_add (rc->searches, g_strdup (nm_ip6_config_get_domain (src, i))); + rc->domain = domain; + add_string_item (rc->searches, domain); } num = nm_ip6_config_get_num_searches (src); for (i = 0; i < num; i++) - g_ptr_array_add (rc->searches, g_strdup (nm_ip6_config_get_search (src, i))); + add_string_item (rc->searches, nm_ip6_config_get_search (src, i)); } From 871f9934fa0ea25906e338a74d02bb361f6490bf Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 26 Apr 2010 23:56:01 -0700 Subject: [PATCH 053/105] build: default to pppd-2.4.5 plugin dir People should be using 2.4.5 now anyway, since it's been out for quite a while and includes the fixes for the bogus DNS servers. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index adfe67fe9b..5918c26728 100644 --- a/configure.ac +++ b/configure.ac @@ -296,7 +296,7 @@ AC_ARG_WITH([pppd-plugin-dir], AS_HELP_STRING([--with-pppd-plugin-dir=DIR], [pat if test -n "$with_pppd_plugin_dir" ; then PPPD_PLUGIN_DIR="$with_pppd_plugin_dir" else - PPPD_PLUGIN_DIR="${libdir}/pppd/2.4.4" + PPPD_PLUGIN_DIR="${libdir}/pppd/2.4.5" fi AC_SUBST(PPPD_PLUGIN_DIR) From ea1e6f2f7b5d491085ca94df9830ad94b23cc8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Klime=C5=A1?= Date: Tue, 27 Apr 2010 15:59:46 +0200 Subject: [PATCH 054/105] ip6: fix a crash when /proc/sys/net/ipv6/conf//* files are not present --- src/ip6-manager/nm-ip6-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 4ea9538d5b..d5afcbc048 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -140,7 +140,7 @@ nm_ip6_device_destroy (NMIP6Device *device) static gboolean get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value) { - GError *error; + GError *error = NULL; char *contents = NULL; gboolean success = FALSE; long int tmp; From 17e0749c76a388fd84527bea47eb5c3310ef602a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 27 Apr 2010 17:08:06 -0700 Subject: [PATCH 055/105] ip6: disconnect netlink signal handler on dispose --- src/ip6-manager/nm-ip6-manager.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index d5afcbc048..90a3041a20 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -47,6 +47,8 @@ typedef struct { struct nl_handle *nlh; struct nl_cache *addr_cache, *route_cache; + + guint netlink_id; } NMIP6ManagerPrivate; #define NM_IP6_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_MANAGER, NMIP6ManagerPrivate)) @@ -221,8 +223,12 @@ error: static NMIP6Device * nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex) { - NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); + NMIP6ManagerPrivate *priv; + g_return_val_if_fail (manager != NULL, NULL); + g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL); + + priv = NM_IP6_MANAGER_GET_PRIVATE (manager); return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex)); } @@ -443,6 +449,8 @@ process_addr (NMIP6Manager *manager, struct nl_msg *msg) return NULL; device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr)); + if (!device) + return NULL; old_size = nl_cache_nitems (priv->addr_cache); nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL); @@ -472,6 +480,8 @@ process_route (NMIP6Manager *manager, struct nl_msg *msg) return NULL; device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute)); + if (!device) + return NULL; old_size = nl_cache_nitems (priv->route_cache); nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL); @@ -961,8 +971,8 @@ nm_ip6_manager_init (NMIP6Manager *manager) nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL); - g_signal_connect (priv->monitor, "notification", - G_CALLBACK (netlink_notification), manager); + priv->netlink_id = g_signal_connect (priv->monitor, "notification", + G_CALLBACK (netlink_notification), manager); priv->nlh = nm_netlink_get_default_handle (); priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh); @@ -974,6 +984,8 @@ finalize (GObject *object) { NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object); + g_signal_handler_disconnect (priv->monitor, priv->netlink_id); + g_hash_table_destroy (priv->devices); g_object_unref (priv->monitor); nl_cache_free (priv->addr_cache); From 257b4b34dabecca8bb4810a4c9b845c36e2542ea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 28 Apr 2010 18:39:42 -0700 Subject: [PATCH 056/105] examples: add example for listing connections --- examples/python/Makefile.am | 5 +- examples/python/list-connections.py | 112 ++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 examples/python/list-connections.py diff --git a/examples/python/Makefile.am b/examples/python/Makefile.am index a64727a7fd..fd654cb508 100644 --- a/examples/python/Makefile.am +++ b/examples/python/Makefile.am @@ -1,4 +1,7 @@ EXTRA_DIST = \ nm-state.py \ - add-system-connection.py + add-system-connection.py \ + vpn.py \ + list-connections.py + diff --git a/examples/python/list-connections.py b/examples/python/list-connections.py new file mode 100644 index 0000000000..ad8d9047c4 --- /dev/null +++ b/examples/python/list-connections.py @@ -0,0 +1,112 @@ +#!/bin/env python +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2010 Red Hat, Inc. +# + +import dbus + +# This example asks both the system settings service and the user settings +# service for all configured connections. It also asks for secrets, demonstrating +# the mechanisms each settings service uses to prevent unauthorized access to +# a user's network passwords + +bus = dbus.SystemBus() + +def merge_secrets(proxy, config, setting_name): + try: + # returns a dict of dicts mapping name::setting, where setting is a dict + # mapping key::value. Each member of the 'setting' dict is a secret + secrets = proxy.GetSecrets(setting_name, [], False) + + # Copy the secrets into our connection config + for setting in secrets: + for key in secrets[setting]: + config[setting_name][key] = setting[key] + except Exception, e: + pass + +def dict_to_string(d, indent): + # Try to trivially translate a dictionary's elements into nice string + # formatting. + dstr = "" + for key in d: + val = d[key] + str_val = "" + add_string = True + if type(val) == type(dbus.Array([])): + for elt in val: + if type(elt) == type(dbus.Byte(1)): + str_val += "%s " % int(elt) + elif type(elt) == type(dbus.String("")): + str_val += "%s" % elt + elif type(val) == type(dbus.Dictionary({})): + dstr += dict_to_string(val, indent + " ") + add_string = False + else: + str_val = val + if add_string: + dstr += "%s%s: %s\n" % (indent, key, str_val) + return dstr + +def connection_to_string(config): + # dump a connection configuration to a the console + for setting_name in config: + print " Setting: %s" % setting_name + print dict_to_string(config[setting_name], " ") + print "" + + +def print_one_services_connections(service_name, desc): + # Ask the settings service for the list of connections it provides + proxy = bus.get_object(service_name, "/org/freedesktop/NetworkManagerSettings") + settings = dbus.Interface(proxy, "org.freedesktop.NetworkManagerSettings") + connection_paths = settings.ListConnections() + + print "%s connections --------------------------------------------\n" % desc + + # List each connection's name, UUID, and type + for path in connection_paths: + con_proxy = bus.get_object(service_name, path) + connection = dbus.Interface(con_proxy, "org.freedesktop.NetworkManagerSettings.Connection") + config = connection.GetSettings() + + # Now get secrets too; we grab the secrets for each type of connection + # (since there isn't a "get all secrets" call because most of the time + # you only need 'wifi' secrets or '802.1x' secrets, not everything) and + # merge that into the configuration data + connection_secrets = dbus.Interface(con_proxy, "org.freedesktop.NetworkManagerSettings.Connection.Secrets") + merge_secrets(connection_secrets, config, '802-11-wireless') + merge_secrets(connection_secrets, config, '802-11-wireless-security') + merge_secrets(connection_secrets, config, '802-1x') + merge_secrets(connection_secrets, config, 'gsm') + merge_secrets(connection_secrets, config, 'cdma') + merge_secrets(connection_secrets, config, 'ppp') + + # Get the details of the 'connection' setting + s_con = config['connection'] + print "name: %s" % s_con['id'] + print " uuid: %s" % s_con['uuid'] + print " type: %s" % s_con['type'] + print " ----------------------------" + connection_to_string(config) + + print "" + +# Print out connection information for all connections +print_one_services_connections("org.freedesktop.NetworkManagerSystemSettings", "System") +print_one_services_connections("org.freedesktop.NetworkManagerUserSettings", "User") + From e01039dcd28b6c545715a742d14c116512472011 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 29 Apr 2010 08:26:28 -0700 Subject: [PATCH 057/105] examples: add example printing out all BSSIDs we can see --- examples/python/Makefile.am | 3 +- examples/python/show-bssids.py | 78 ++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 examples/python/show-bssids.py diff --git a/examples/python/Makefile.am b/examples/python/Makefile.am index fd654cb508..179e2f3c9a 100644 --- a/examples/python/Makefile.am +++ b/examples/python/Makefile.am @@ -2,6 +2,7 @@ EXTRA_DIST = \ nm-state.py \ add-system-connection.py \ vpn.py \ - list-connections.py + list-connections.py \ + show-bssids.py diff --git a/examples/python/show-bssids.py b/examples/python/show-bssids.py new file mode 100644 index 0000000000..5d8778c731 --- /dev/null +++ b/examples/python/show-bssids.py @@ -0,0 +1,78 @@ +#!/bin/env python +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2010 Red Hat, Inc. +# + + +# This example prints out all the AP BSSIDs that all WiFi devices on the +# machine can see. Useful for location-based services like Skyhook that +# can geolocate you based on the APs you can see. + +import dbus + +bus = dbus.SystemBus() + +# Get a proxy for the base NetworkManager object +proxy = bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager") +manager = dbus.Interface(proxy, "org.freedesktop.NetworkManager") + +all_aps = [] + +print "Associated APs:" + +# Get all network devices +devices = manager.GetDevices() +for d in devices: + dev_proxy = bus.get_object("org.freedesktop.NetworkManager", d) + prop_iface = dbus.Interface(dev_proxy, "org.freedesktop.DBus.Properties") + + # Make sure the device is enabled before we try to use it + state = prop_iface.Get("org.freedesktop.NetworkManager.Device", "State") + if state <= 2: + continue + + # Get device's type; we only want wifi devices + iface = prop_iface.Get("org.freedesktop.NetworkManager.Device", "Interface") + dtype = prop_iface.Get("org.freedesktop.NetworkManager.Device", "DeviceType") + if dtype == 2: # WiFi + # Get a proxy for the wifi interface + wifi_iface = dbus.Interface(dev_proxy, "org.freedesktop.NetworkManager.Device.Wireless") + wifi_prop_iface = dbus.Interface(dev_proxy, "org.freedesktop.DBus.Properties") + + # Get the associated AP's object path + connected_path = wifi_prop_iface.Get("org.freedesktop.NetworkManager.Device.Wireless", "ActiveAccessPoint") + + # Get all APs the card can see + aps = wifi_iface.GetAccessPoints() + for path in aps: + ap_proxy = bus.get_object("org.freedesktop.NetworkManager", path) + ap_prop_iface = dbus.Interface(ap_proxy, "org.freedesktop.DBus.Properties") + bssid = ap_prop_iface.Get("org.freedesktop.NetworkManager.AccessPoint", "HwAddress") + + # Cache the BSSID + if not bssid in all_aps: + all_aps.append(bssid) + + # Print the current AP's BSSID + if path == connected_path: + print "%s (%s)" % (bssid, iface) + +# and print out all APs the wifi devices can see +print"\nFound APs:" +for bssid in all_aps: + print bssid + From 9830c60d119eb89917ce2572181110030977b99b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 29 Apr 2010 11:31:43 -0700 Subject: [PATCH 058/105] dhcp: fix superclass type of dhcpcd plugin From Mikhail Efremov --- src/dhcp-manager/nm-dhcp-dhcpcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index 56b74810dc..716949324c 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -36,7 +36,7 @@ #include "nm-utils.h" #include "nm-logging.h" -G_DEFINE_TYPE (NMDHCPDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_DHCPCD) +G_DEFINE_TYPE (NMDHCPDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_CLIENT) #define NM_DHCP_DHCPCD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_DHCPCD, NMDHCPDhcpcdPrivate)) From 3d69429a1e6707b5837e79a1d70532e72d0d3324 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 11:18:12 -0700 Subject: [PATCH 059/105] dbus: add Debian D-Bus permission config From Michael Biebl and the debian packages. --- src/NetworkManager.conf | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/NetworkManager.conf b/src/NetworkManager.conf index 87814bec2a..0dea2d65af 100644 --- a/src/NetworkManager.conf +++ b/src/NetworkManager.conf @@ -57,6 +57,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 93d1d819389211df57c5f0584a05d742af59d6ad Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 11:44:56 -0700 Subject: [PATCH 060/105] Revert "dbus: add Debian D-Bus permission config" This reverts commit 3d69429a1e6707b5837e79a1d70532e72d0d3324. Apparently the 'netdev' group rules aren't as widespread anymore and Debian ships with ConsoleKit by default, and thus can use at_console. --- src/NetworkManager.conf | 45 ----------------------------------------- 1 file changed, 45 deletions(-) diff --git a/src/NetworkManager.conf b/src/NetworkManager.conf index 0dea2d65af..87814bec2a 100644 --- a/src/NetworkManager.conf +++ b/src/NetworkManager.conf @@ -57,51 +57,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From cc0c2783b6e4a6dd0a23bffcf13addcd6f0346c6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 15:29:53 -0700 Subject: [PATCH 061/105] libnm-util: fix IPv6 address array -> string transform Only used for debugging, but it's nice to see the actual address instead of a transform error. --- libnm-util/nm-utils.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c index c9c34f1ba6..5a8a8800db 100644 --- a/libnm-util/nm-utils.c +++ b/libnm-util/nm-utils.c @@ -861,10 +861,11 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu g_string_append (printable, "{ "); elements = (GValueArray *) g_ptr_array_index (ptr_array, i++); - if ( (elements->n_values != 2) + if ( (elements->n_values != 3) || (G_VALUE_TYPE (g_value_array_get_nth (elements, 0)) != DBUS_TYPE_G_UCHAR_ARRAY) - || (G_VALUE_TYPE (g_value_array_get_nth (elements, 1)) != G_TYPE_UINT)) { - g_string_append (printable, "invalid"); + || (G_VALUE_TYPE (g_value_array_get_nth (elements, 1)) != G_TYPE_UINT) + || (G_VALUE_TYPE (g_value_array_get_nth (elements, 2)) != DBUS_TYPE_G_UCHAR_ARRAY)) { + g_string_append (printable, "invalid }"); continue; } @@ -872,7 +873,7 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu tmp = g_value_array_get_nth (elements, 0); ba_addr = g_value_get_boxed (tmp); if (ba_addr->len != 16) { - g_string_append (printable, "invalid"); + g_string_append (printable, "invalid }"); continue; } addr = (struct in6_addr *) ba_addr->data; @@ -885,7 +886,7 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu tmp = g_value_array_get_nth (elements, 1); prefix = g_value_get_uint (tmp); if (prefix > 128) { - g_string_append (printable, "invalid"); + g_string_append (printable, "invalid }"); continue; } g_string_append_printf (printable, "px = %u", prefix); @@ -895,7 +896,7 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu tmp = g_value_array_get_nth (elements, 2); ba_addr = g_value_get_boxed (tmp); if (ba_addr->len != 16) { - g_string_append (printable, "invalid"); + g_string_append (printable, "invalid }"); continue; } addr = (struct in6_addr *) ba_addr->data; From 7e980d8be3a5e09739c99b9c4178b8e15f799e6d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 15:49:41 -0700 Subject: [PATCH 062/105] ip6: fix manual IP config application --- src/nm-device.c | 58 ++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/src/nm-device.c b/src/nm-device.c index 9d6ee5f410..ef540204f1 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1520,7 +1520,7 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const char *ip_iface; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMActRequest *req; NMConnection *connection; @@ -1533,7 +1533,8 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) ip_iface = nm_device_get_ip_iface (self); - if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + if ( ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO) + || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { priv->ip6_waiting_for_config = TRUE; nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self)); ret = NM_ACT_STAGE_RETURN_POSTPONE; @@ -1542,7 +1543,10 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { priv->ip6_ready = TRUE; ret = NM_ACT_STAGE_RETURN_STOP; - } + } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + ret = NM_ACT_STAGE_RETURN_SUCCESS; + + /* Other methods (shared) aren't implemented yet */ return ret; } @@ -1911,7 +1915,6 @@ real_act_stage4_get_ip6_config (NMDevice *self, NMDeviceStateReason *reason) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMConnection *connection; NMSettingIP6Config *s_ip6; const char *ip_iface; @@ -1931,40 +1934,45 @@ real_act_stage4_get_ip6_config (NMDevice *self, if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { *config = nm_ip6_manager_get_ip6_config (priv->ip6_manager, nm_device_get_ip_ifindex (self)); - if (*config) { - /* Merge user-defined overrides into the IP6Config to be applied */ - nm_utils_merge_ip6_config (*config, s_ip6); - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else { + if (!*config) { *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; goto out; } + + /* Merge user-defined overrides into the IP6Config to be applied */ + nm_utils_merge_ip6_config (*config, s_ip6); + } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { + *config = nm_ip6_config_new (); + if (!*config) { + *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + goto out; + } + nm_utils_merge_ip6_config (*config, s_ip6); } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) g_assert (priv->dhcp6_client); /* sanity check */ /* Autoconf might have triggered DHCPv6 too */ if (priv->dhcp6_client) { *config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE); - if (*config) { - /* Merge user-defined overrides into the IP4Config to be applied */ - nm_utils_merge_ip6_config (*config, s_ip6); - - nm_dhcp6_config_reset (priv->dhcp6_config); - nm_dhcp_client_foreach_option (priv->dhcp6_client, - dhcp6_add_option_cb, - priv->dhcp6_config); - - /* Notify of new DHCP4 config */ - g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG); - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else { + if (!*config) { *reason = NM_DEVICE_STATE_REASON_DHCP_ERROR; + goto out; } - } else - ret = NM_ACT_STAGE_RETURN_SUCCESS; + + /* Merge user-defined overrides into the IP4Config to be applied */ + nm_utils_merge_ip6_config (*config, s_ip6); + + nm_dhcp6_config_reset (priv->dhcp6_config); + nm_dhcp_client_foreach_option (priv->dhcp6_client, + dhcp6_add_option_cb, + priv->dhcp6_config); + + /* Notify of new DHCP6 config */ + g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG); + } out: - return ret; + return *config ? NM_ACT_STAGE_RETURN_SUCCESS : NM_ACT_STAGE_RETURN_FAILURE; } /* From b24f5c8da9d1ed65378e7101385ee04e52475e63 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 16:09:02 -0700 Subject: [PATCH 063/105] ip6: 'manual' method doesn't use the IP6 manager --- src/ip6-manager/nm-ip6-manager.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 90a3041a20..61cf5be218 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -729,8 +729,7 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager, method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; /* Establish target state and turn router advertisement acceptance on or off */ - if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) - || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { + if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL; nm_utils_do_sysctl (device->accept_ra_path, "0\n"); } else { From a64600d7968a7dd48ade7879871cbdfd15286c55 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 16:09:36 -0700 Subject: [PATCH 064/105] ip6: bump the autoconf RA timeout a bit The RA interval is configurable on the router and we don't want to miss one. 20s is still a lot less than we allow for DHCP so the latency isn't that big of an issue. --- src/ip6-manager/nm-ip6-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 61cf5be218..ca532e3e93 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -33,7 +33,7 @@ #include "nm-system.h" /* Pre-DHCP addrconf timeout, in seconds */ -#define NM_IP6_TIMEOUT 10 +#define NM_IP6_TIMEOUT 20 /* FIXME? Stolen from the kernel sources */ #define IF_RA_OTHERCONF 0x80 From 7b3103b5ebfac1baf46622baa4f6febbe18f1f20 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 16:10:29 -0700 Subject: [PATCH 065/105] ip6: initialize IPv6 address config a bit later Stage 1 gets overridded by most device subclasses and it turns out they don't every chain back up to NMDevice's stage1 implementation. It's a bit complicated to make them all do that, so for now just move the IPv6 address config a bit later. --- src/nm-device.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/nm-device.c b/src/nm-device.c index ef540204f1..ce47bc66f7 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -672,26 +672,19 @@ ip6_method_matches (NMConnection *connection, const char *match) return method && !strcmp (method, match); } -static void +static gboolean addrconf6_setup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; NMConnection *connection; - const char *ip_iface; NMSettingIP6Config *s_ip6; - priv->ip6_waiting_for_config = FALSE; - priv->ip6_dhcp_opt = IP6_DHCP_OPT_NONE; - req = nm_device_get_act_request (self); g_assert (req); connection = nm_act_request_get_connection (req); g_assert (connection); - if (!ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) - return; - if (!priv->ip6_manager) { priv->ip6_manager = nm_ip6_manager_get (); priv->ip6_addrconf_sigid = g_signal_connect (priv->ip6_manager, @@ -704,11 +697,15 @@ addrconf6_setup (NMDevice *self) self); } - ip_iface = nm_device_get_ip_iface (self); + priv->ip6_dhcp_opt = IP6_DHCP_OPT_NONE; + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); nm_ip6_manager_prepare_interface (priv->ip6_manager, nm_device_get_ip_ifindex (self), s_ip6); + priv->ip6_waiting_for_config = TRUE; + + return TRUE; } static void @@ -738,7 +735,6 @@ addrconf6_cleanup (NMDevice *self) static NMActStageReturn real_act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason) { - addrconf6_setup (self); return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -1535,7 +1531,10 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) if ( ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO) || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { - priv->ip6_waiting_for_config = TRUE; + if (!addrconf6_setup (self)) { + *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + goto out; + } nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self)); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) @@ -1548,6 +1547,7 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) /* Other methods (shared) aren't implemented yet */ +out: return ret; } @@ -1931,7 +1931,8 @@ real_act_stage4_get_ip6_config (NMDevice *self, s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); - if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + if ( ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO) + || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { *config = nm_ip6_manager_get_ip6_config (priv->ip6_manager, nm_device_get_ip_ifindex (self)); if (!*config) { From 8a597067128225fbb9fdc16ee9f79099e7e27d35 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 17:30:11 -0700 Subject: [PATCH 066/105] ip6: ensure manager singleton is cleared when disposed --- src/ip6-manager/nm-ip6-manager.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index ca532e3e93..b9b5639ecf 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -941,11 +941,11 @@ nm_ip6_manager_new (void) return manager; } +static NMIP6Manager *singleton = NULL; + NMIP6Manager * nm_ip6_manager_get (void) { - static NMIP6Manager *singleton = NULL; - if (!singleton) { singleton = nm_ip6_manager_new (); g_assert (singleton); @@ -990,6 +990,8 @@ finalize (GObject *object) nl_cache_free (priv->addr_cache); nl_cache_free (priv->route_cache); + singleton = NULL; + G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object); } From 2282f352a42b81d6eed88decbdc5328bc02cdc3a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 17:30:36 -0700 Subject: [PATCH 067/105] ip6: better logging of IPv6 autoconf process --- src/ip6-manager/nm-ip6-manager.c | 133 +++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 17 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index b9b5639ecf..e9a60ee8c4 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -349,6 +349,25 @@ callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success) return info; } +static const char * +state_to_string (NMIP6DeviceState state) +{ + switch (state) { + case NM_IP6_DEVICE_UNCONFIGURED: + return "unconfigured"; + case NM_IP6_DEVICE_GOT_LINK_LOCAL: + return "got-link-local"; + case NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT: + return "got-ra"; + case NM_IP6_DEVICE_GOT_ADDRESS: + return "got-address"; + case NM_IP6_DEVICE_TIMED_OUT: + return "timed-out"; + default: + return "unknown"; + } +} + static void nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) { @@ -359,11 +378,19 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) struct in6_addr *addr; CallbackInfo *info; guint dhcp_opts = IP6_DHCP_OPT_NONE; + gboolean found_linklocal = FALSE; + + nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')", + device->iface, device->ra_flags, + state_to_string (device->state), + state_to_string (device->target_state)); /* Look for any IPv6 addresses the kernel may have set for the device */ for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) { + char buf[INET6_ADDRSTRLEN]; + if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; @@ -372,16 +399,33 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) continue; addr = nl_addr_get_binary_addr (nladdr); + + if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) { + nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s", + device->iface, buf); + } + if (IN6_IS_ADDR_LINKLOCAL (addr)) { if (device->state == NM_IP6_DEVICE_UNCONFIGURED) device->state = NM_IP6_DEVICE_GOT_LINK_LOCAL; + found_linklocal = TRUE; } else { if (device->state < NM_IP6_DEVICE_GOT_ADDRESS) device->state = NM_IP6_DEVICE_GOT_ADDRESS; } } - /* We only care about router advertisements if we want for a real IPv6 address */ + /* There might be a LL address hanging around on the interface from + * before in the initial run, but if it goes away later, make sure we + * regress from GOT_LINK_LOCAL back to UNCONFIGURED. + */ + if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !found_linklocal) + device->state = NM_IP6_DEVICE_UNCONFIGURED; + + nm_log_dbg (LOGD_IP6, "(%s): addresses synced (state %s)", + device->iface, state_to_string (device->state)); + + /* We only care about router advertisements if we want a real IPv6 address */ if (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) { if ( (device->ra_flags & IF_RA_RCVD) && (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)) @@ -409,6 +453,10 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) if (device->finish_addrconf_id) g_source_remove (device->finish_addrconf_id); + nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)", + device->iface, state_to_string (device->state), + dhcp_opts); + info = callback_info_new (device, dhcp_opts, TRUE); device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, finish_addrconf, @@ -443,14 +491,20 @@ process_addr (NMIP6Manager *manager, struct nl_msg *msg) struct rtnl_addr *rtnladdr; int old_size; + nm_log_dbg (LOGD_IP6, "processing netlink new/del address message"); + rtnladdr = NULL; nl_msg_parse (msg, ref_object, &rtnladdr); - if (!rtnladdr) + if (!rtnladdr) { + nm_log_dbg (LOGD_IP6, "error processing netlink new/del address message"); return NULL; + } device = nm_ip6_manager_get_device (manager, rtnl_addr_get_ifindex (rtnladdr)); - if (!device) + if (!device) { + nm_log_dbg (LOGD_IP6, "ignoring message for unknown device"); return NULL; + } old_size = nl_cache_nitems (priv->addr_cache); nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL); @@ -460,8 +514,10 @@ process_addr (NMIP6Manager *manager, struct nl_msg *msg) * every time it gets another router advertisement. We only want * to notify higher levels if we actually changed something. */ - if (nl_cache_nitems (priv->addr_cache) == old_size) + if (nl_cache_nitems (priv->addr_cache) == old_size) { + nm_log_dbg (LOGD_IP6, "(%s): address cache unchanged, ignoring message"); return NULL; + } return device; } @@ -474,22 +530,30 @@ process_route (NMIP6Manager *manager, struct nl_msg *msg) struct rtnl_route *rtnlroute; int old_size; + nm_log_dbg (LOGD_IP6, "processing netlink new/del route message"); + rtnlroute = NULL; nl_msg_parse (msg, ref_object, &rtnlroute); - if (!rtnlroute) + if (!rtnlroute) { + nm_log_dbg (LOGD_IP6, "error processing netlink new/del route message"); return NULL; + } device = nm_ip6_manager_get_device (manager, rtnl_route_get_oif (rtnlroute)); - if (!device) + if (!device) { + nm_log_dbg (LOGD_IP6, "ignoring message for unknown device"); return NULL; + } old_size = nl_cache_nitems (priv->route_cache); nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL); rtnl_route_put (rtnlroute); /* As above in process_addr */ - if (nl_cache_nitems (priv->route_cache) == old_size) + if (nl_cache_nitems (priv->route_cache) == old_size) { + nm_log_dbg (LOGD_IP6, "(%s): route cache unchanged, ignoring message"); return NULL; + } return device; } @@ -506,11 +570,16 @@ process_prefix (NMIP6Manager *manager, struct nl_msg *msg) * way to notice immediately that an RA was received. */ + nm_log_dbg (LOGD_IP6, "processing netlink new prefix message"); + pmsg = (struct prefixmsg *) NLMSG_DATA (nlmsg_hdr (msg)); device = nm_ip6_manager_get_device (manager, pmsg->prefix_ifindex); - if (!device || device->addrconf_complete) + if (!device || device->addrconf_complete) { + nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device", + device ? device->iface : "(none)"); return NULL; + } return device; } @@ -542,16 +611,22 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) NMIP6RDNSS server, *sa, *sb; gboolean changed; + nm_log_dbg (LOGD_IP6, "processing netlink nduseropt message"); + ndmsg = (struct nduseroptmsg *) NLMSG_DATA (nlmsg_hdr (msg)); if (ndmsg->nduseropt_family != AF_INET6 || ndmsg->nduseropt_icmp_type != ND_ROUTER_ADVERT || - ndmsg->nduseropt_icmp_code != 0) + ndmsg->nduseropt_icmp_code != 0) { + nm_log_dbg (LOGD_IP6, "ignoring non-Router Advertisement message"); return NULL; + } device = nm_ip6_manager_get_device (manager, ndmsg->nduseropt_ifindex); - if (!device) + if (!device) { + nm_log_dbg (LOGD_IP6, "ignoring message for unknown device"); return NULL; + } servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS)); @@ -574,6 +649,13 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) server.expires = now + ntohl (rdnss_opt->nd_opt_rdnss_lifetime); for (addr = (struct in6_addr *) (rdnss_opt + 1); nd_opt_len >= 2; addr++, nd_opt_len -= 2) { + char buf[INET6_ADDRSTRLEN]; + + if (inet_ntop (AF_INET6, &addr, buf, INET6_ADDRSTRLEN) > 0) { + nm_log_dbg (LOGD_IP6, "(%s): found RA-provided nameserver %s", + device->iface, buf); + } + server.addr = *addr; g_array_append_val (servers, server); } @@ -599,6 +681,7 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) } if (changed) { + nm_log_dbg (LOGD_IP6, "(%s): RA-provided nameservers changed", device->iface); g_array_free (device->rdnss_servers, TRUE); device->rdnss_servers = servers; } else @@ -632,12 +715,17 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg) int err; ifi = nlmsg_data (hdr); - if (ifi->ifi_family != AF_INET6) + if (ifi->ifi_family != AF_INET6) { + nm_log_dbg (LOGD_IP6, "ignoring netlink message family %d", ifi->ifi_family); return NULL; + } device = nm_ip6_manager_get_device (manager, ifi->ifi_index); - if (!device || device->addrconf_complete) + if (!device || device->addrconf_complete) { + nm_log_dbg (LOGD_IP6, "(%s): ignoring unknown or completed device", + device ? device->iface : "(none)"); return NULL; + } /* FIXME: we have to do this manually for now since libnl doesn't yet * support the IFLA_PROTINFO attribute of NEWLINK messages. When it does, @@ -647,16 +735,24 @@ process_newlink (NMIP6Manager *manager, struct nl_msg *msg) */ err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy); - if (err < 0) + if (err < 0) { + nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO attribute", device->iface); return NULL; - if (!tb[IFLA_PROTINFO]) + } + if (!tb[IFLA_PROTINFO]) { + nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO attribute", device->iface); return NULL; + } err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy); - if (err < 0) + if (err < 0) { + nm_log_dbg (LOGD_IP6, "(%s): error parsing PROTINFO flags", device->iface); return NULL; - if (!pi[IFLA_INET6_FLAGS]) + } + if (!pi[IFLA_INET6_FLAGS]) { + nm_log_dbg (LOGD_IP6, "(%s): message had no PROTINFO flags", device->iface); return NULL; + } device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]); nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags); @@ -673,6 +769,7 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us gboolean config_changed = FALSE; hdr = nlmsg_hdr (msg); + nm_log_dbg (LOGD_HW, "netlink notificate type %d", hdr->nlmsg_type); switch (hdr->nlmsg_type) { case RTM_NEWADDR: case RTM_DELADDR: @@ -699,8 +796,10 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us return; } - if (device) + if (device) { + nm_log_dbg (LOGD_IP6, "(%s): syncing device with netlink changes", device->iface); nm_ip6_device_sync_from_netlink (device, config_changed); + } } void From 9f85d3533ebb50ca4e8a3f6b153308ea7498a3d0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 30 Apr 2010 17:33:44 -0700 Subject: [PATCH 068/105] ip6: fix log message arguments --- src/ip6-manager/nm-ip6-manager.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index e9a60ee8c4..0b7949d974 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -515,7 +515,8 @@ process_addr (NMIP6Manager *manager, struct nl_msg *msg) * to notify higher levels if we actually changed something. */ if (nl_cache_nitems (priv->addr_cache) == old_size) { - nm_log_dbg (LOGD_IP6, "(%s): address cache unchanged, ignoring message"); + nm_log_dbg (LOGD_IP6, "(%s): address cache unchanged, ignoring message", + device->iface); return NULL; } @@ -551,7 +552,8 @@ process_route (NMIP6Manager *manager, struct nl_msg *msg) /* As above in process_addr */ if (nl_cache_nitems (priv->route_cache) == old_size) { - nm_log_dbg (LOGD_IP6, "(%s): route cache unchanged, ignoring message"); + nm_log_dbg (LOGD_IP6, "(%s): route cache unchanged, ignoring message", + device->iface); return NULL; } From 398b41a61d2ed0e9fb29f993b2f5c5256032f8e3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 08:05:39 -0700 Subject: [PATCH 069/105] trivial: IP6Config object cleanups --- src/nm-ip6-config.c | 4 ++-- src/nm-ip6-config.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index e3fe92dbd3..89b8c1a665 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -183,7 +183,7 @@ const struct in6_addr *nm_ip6_config_get_ptp_address (NMIP6Config *config) return &NM_IP6_CONFIG_GET_PRIVATE (config)->ptp_address; } -void nm_ip6_config_set_ptp_address (NMIP6Config *config, struct in6_addr *ptp_addr) +void nm_ip6_config_set_ptp_address (NMIP6Config *config, const struct in6_addr *ptp_addr) { g_return_if_fail (NM_IS_IP6_CONFIG (config)); @@ -197,7 +197,7 @@ void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *n int i; g_return_if_fail (NM_IS_IP6_CONFIG (config)); - g_return_if_fail (nameserver > 0); + g_return_if_fail (nameserver != NULL); priv = NM_IP6_CONFIG_GET_PRIVATE (config); diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 4fd959d531..1e75a121c8 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -60,7 +60,7 @@ NMIP6Address *nm_ip6_config_get_address (NMIP6Config *config, guint32 i) guint32 nm_ip6_config_get_num_addresses (NMIP6Config *config); const struct in6_addr *nm_ip6_config_get_ptp_address (NMIP6Config *config); -void nm_ip6_config_set_ptp_address (NMIP6Config *config, struct in6_addr *ptp_addr); +void nm_ip6_config_set_ptp_address (NMIP6Config *config, const struct in6_addr *ptp_addr); void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver); const struct in6_addr *nm_ip6_config_get_nameserver (NMIP6Config *config, guint i); From e3de3b65ef209e4431ba7c93c474d1805c1b4699 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 08:09:12 -0700 Subject: [PATCH 070/105] logging: print DHCP client pid in warnings --- src/dhcp-manager/nm-dhcp-manager.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index 635fe320b0..c2aacbbbe5 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -235,19 +235,19 @@ nm_dhcp_manager_handle_event (DBusGProxy *proxy, client = get_client_for_pid (manager, (GPid) temp); if (client == NULL) { - nm_log_warn (LOGD_DHCP, "unhandled DHCP event for interface %s", iface); + nm_log_warn (LOGD_DHCP, "(pid %d) unhandled DHCP event for interface %s", temp, iface); goto out; } if (strcmp (iface, nm_dhcp_client_get_iface (client))) { - nm_log_warn (LOGD_DHCP, "received DHCP event from unexpected interface '%s' (expected '%s')", - iface, nm_dhcp_client_get_iface (client)); + nm_log_warn (LOGD_DHCP, "(pid %d) received DHCP event from unexpected interface '%s' (expected '%s')", + temp, iface, nm_dhcp_client_get_iface (client)); goto out; } reason = get_option (options, "reason"); if (reason == NULL) { - nm_log_warn (LOGD_DHCP, "DHCP event didn't have a reason"); + nm_log_warn (LOGD_DHCP, "(pid %d) DHCP event didn't have a reason", temp); goto out; } From d1be3793a159f4e2c2a21b5f67b38704f3900cee Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 08:10:49 -0700 Subject: [PATCH 071/105] dhcp6: info-only requests don't require addresses They aren't actual leases so an info-only request doesn't return an address. --- src/dhcp-manager/nm-dhcp-client.c | 59 +++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 9f9719473a..30d5c7504e 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -44,6 +44,7 @@ typedef struct { guint timeout_id; guint watch_id; GHashTable * options; + gboolean info_only; } NMDHCPClientPrivate; #define NM_DHCP_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_CLIENT, NMDHCPClientPrivate)) @@ -186,6 +187,8 @@ real_stop (NMDHCPClient *self) watch_cleanup (self); stop_process (priv->pid, priv->iface); + + priv->info_only = FALSE; } static gboolean @@ -278,6 +281,8 @@ nm_dhcp_client_start_ip6 (NMDHCPClient *self, g_return_val_if_fail (priv->ipv6 == TRUE, FALSE); g_return_val_if_fail (priv->uuid != NULL, FALSE); + priv->info_only = info_only; + nm_log_info (LOGD_DHCP, "Activation (%s) Beginning DHCPv6 transaction (timeout in %d seconds)", priv->iface, priv->timeout); @@ -894,6 +899,8 @@ ip6_options_to_config (NMDHCPClient *self) struct in6_addr tmp_addr; NMIP6Address *addr = NULL; char *str = NULL; + GHashTableIter iter; + gpointer key, value; g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); @@ -901,6 +908,12 @@ ip6_options_to_config (NMDHCPClient *self) priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->options != NULL, NULL); + g_hash_table_iter_init (&iter, priv->options); + while (g_hash_table_iter_next (&iter, &key, &value)) { + nm_log_dbg (LOGD_DHCP6, "(%s): option '%s'=>'%s'", + priv->iface, (const char *) key, (const char *) value); + } + ip6_config = nm_ip6_config_new (); if (!ip6_config) { nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6Config!", priv->iface); @@ -914,27 +927,43 @@ ip6_options_to_config (NMDHCPClient *self) } str = g_hash_table_lookup (priv->options, "new_ip6_address"); - if (str && (inet_pton (AF_INET6, str, &tmp_addr) > 0)) { + if (str) { + if (!inet_pton (AF_INET6, str, &tmp_addr)) { + nm_log_warn (LOGD_DHCP6, "(%s): DHCP returned invalid address '%s'", + priv->iface); + goto error; + } + nm_ip6_address_set_address (addr, &tmp_addr); nm_log_info (LOGD_DHCP6, " address %s", str); - } else - goto error; - - str = g_hash_table_lookup (priv->options, "new_ip6_prefixlen"); - if (str) { - long unsigned int prefix; - - errno = 0; - prefix = strtoul (str, NULL, 10); - if (errno != 0 || prefix > 128) + } else { + /* No address in managed mode is a hard error */ + if (priv->info_only == FALSE) goto error; - nm_ip6_address_set_prefix (addr, (guint32) prefix); - nm_log_info (LOGD_DHCP6, " prefix %lu", prefix); + /* But "info-only" setups don't necessarily need an address */ + nm_ip6_address_unref (addr); + addr = NULL; } - nm_ip6_config_take_address (ip6_config, addr); - addr = NULL; + /* Only care about prefix if we got an address */ + if (addr) { + str = g_hash_table_lookup (priv->options, "new_ip6_prefixlen"); + if (str) { + long unsigned int prefix; + + errno = 0; + prefix = strtoul (str, NULL, 10); + if (errno != 0 || prefix > 128) + goto error; + + nm_ip6_address_set_prefix (addr, (guint32) prefix); + nm_log_info (LOGD_DHCP6, " prefix %lu", prefix); + } + + nm_ip6_config_take_address (ip6_config, addr); + addr = NULL; + } str = g_hash_table_lookup (priv->options, "new_host_name"); if (str) From 0e546480fac5c663802131ec2acbd6b3d62ee342 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 08:12:25 -0700 Subject: [PATCH 072/105] dhcp6: fix merging of DHCPv6 config into interface config If we're doing autoconf + DHCPv6 info-only, we need to combine the DHCP and IPv6 configuration into the final device configuration. --- src/nm-device.c | 73 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/src/nm-device.c b/src/nm-device.c index ce47bc66f7..01f1d7288f 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1909,6 +1909,42 @@ nm_device_activate_schedule_stage4_ip4_config_timeout (NMDevice *self) nm_device_get_iface (self)); } +static void +merge_dhcp_config_to_master (NMIP6Config *dst, NMIP6Config *src) +{ + guint32 i; + + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); + + /* addresses */ + for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++) + nm_ip6_config_add_address (dst, nm_ip6_config_get_address (src, i)); + + /* ptp address; only replace if src doesn't have one */ + if (!nm_ip6_config_get_ptp_address (dst)) + nm_ip6_config_set_ptp_address (dst, nm_ip6_config_get_ptp_address (src)); + + /* nameservers */ + for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++) + nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i)); + + /* routes */ + for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) + nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i)); + + /* domains */ + for (i = 0; i < nm_ip6_config_get_num_domains (src); i++) + nm_ip6_config_add_domain (dst, nm_ip6_config_get_domain (src, i)); + + /* dns searches */ + for (i = 0; i < nm_ip6_config_get_num_searches (src); i++) + nm_ip6_config_add_search (dst, nm_ip6_config_get_search (src, i)); + + if (!nm_ip6_config_get_mss (dst)) + nm_ip6_config_set_mss (dst, nm_ip6_config_get_mss (src)); +} + static NMActStageReturn real_act_stage4_get_ip6_config (NMDevice *self, NMIP6Config **config, @@ -1929,8 +1965,6 @@ real_act_stage4_get_ip6_config (NMDevice *self, connection = nm_act_request_get_connection (nm_device_get_act_request (self)); g_assert (connection); - s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); - if ( ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO) || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { *config = nm_ip6_manager_get_ip6_config (priv->ip6_manager, @@ -1939,30 +1973,43 @@ real_act_stage4_get_ip6_config (NMDevice *self, *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; goto out; } - - /* Merge user-defined overrides into the IP6Config to be applied */ - nm_utils_merge_ip6_config (*config, s_ip6); } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { *config = nm_ip6_config_new (); if (!*config) { *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; goto out; } - nm_utils_merge_ip6_config (*config, s_ip6); } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) g_assert (priv->dhcp6_client); /* sanity check */ /* Autoconf might have triggered DHCPv6 too */ if (priv->dhcp6_client) { - *config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE); - if (!*config) { + NMIP6Config *dhcp; + + dhcp = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE); + if (!dhcp) { *reason = NM_DEVICE_STATE_REASON_DHCP_ERROR; goto out; } - /* Merge user-defined overrides into the IP4Config to be applied */ - nm_utils_merge_ip6_config (*config, s_ip6); + /* For "managed" and DHCP-only setups, we use only the DHCP-supplied + * IPv6 config. But when autoconf is enabled, we have to merge the + * autoconf config and the DHCP-supplied config, then merge the + * user's overrides from the connection to get the final configuration + * that gets applied to the device. + */ + if (*config) { + /* Merge autoconf and DHCP configs */ + merge_dhcp_config_to_master (*config, dhcp); + g_object_unref (dhcp); + dhcp = NULL; + } else { + *config = dhcp; + } + /* Copy the new DHCPv6 configuration into the DHCP config object that's + * exported over D-Bus to clients. + */ nm_dhcp6_config_reset (priv->dhcp6_config); nm_dhcp_client_foreach_option (priv->dhcp6_client, dhcp6_add_option_cb, @@ -1972,6 +2019,12 @@ real_act_stage4_get_ip6_config (NMDevice *self, g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG); } + /* Merge user-defined overrides into the IP6Config to be applied */ + if (*config) { + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + nm_utils_merge_ip6_config (*config, s_ip6); + } + out: return *config ? NM_ACT_STAGE_RETURN_SUCCESS : NM_ACT_STAGE_RETURN_FAILURE; } From 00bcc42a357beac1dbc5e0ba55dcabfdfe9d9900 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 09:26:57 -0700 Subject: [PATCH 073/105] logging: log DHCP state changes --- src/nm-device.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/nm-device.c b/src/nm-device.c index 01f1d7288f..4da051e21c 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -1267,6 +1267,14 @@ dhcp_state_changed (NMDHCPClient *client, ipv6 = nm_dhcp_client_get_ipv6 (client); dev_state = nm_device_get_state (device); + if (ipv6) { + nm_log_dbg (LOGD_DHCP6, "(%s): new DHCPv6 client state %d", + nm_device_get_iface (device), dev_state); + } else { + nm_log_dbg (LOGD_DHCP4, "(%s): new DHCPv4 client state %d", + nm_device_get_iface (device), dev_state); + } + switch (state) { case DHC_BOUND4: /* lease obtained */ case DHC_BOUND6: From 41f3a670922a63ac5baf13cb1e44b33303f66640 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 09:27:32 -0700 Subject: [PATCH 074/105] dhcp: fix client end state when it exits normally --- src/dhcp-manager/nm-dhcp-client.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 30d5c7504e..cf50efddce 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -212,11 +212,22 @@ daemon_watch_cb (GPid pid, gint status, gpointer user_data) NMDHCPClient *self = NM_DHCP_CLIENT (user_data); NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); + if (priv->ipv6) { + nm_log_info (LOGD_DHCP6, "(%s): DHCPv6 client pid %d exited with status %d", + priv->iface, pid, + WIFEXITED (status) ? WEXITSTATUS (status) : -1); + } else { + nm_log_info (LOGD_DHCP6, "(%s): DHCPv4 client pid %d exited with status %d", + priv->iface, pid, + WIFEXITED (status) ? WEXITSTATUS (status) : -1); + } + if (!WIFEXITED (status)) { priv->state = DHC_ABEND; nm_log_warn (LOGD_DHCP, "DHCP client died abnormally"); - } - priv->pid = 0; + } else + priv->state = DHC_END; + priv->pid = -1; watch_cleanup (self); timeout_cleanup (self); @@ -875,7 +886,7 @@ nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test) priv = NM_DHCP_CLIENT_GET_PRIVATE (self); if (test && !state_is_bound (priv->state)) { - nm_log_warn (LOGD_DHCP4, "(%s): DHCP client didn't bind to a lease.", priv->iface); + nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 client didn't bind to a lease.", priv->iface); return NULL; } @@ -1008,7 +1019,7 @@ nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test) priv = NM_DHCP_CLIENT_GET_PRIVATE (self); if (test && !state_is_bound (priv->state)) { - nm_log_warn (LOGD_DHCP6, "(%s): dhcp client didn't bind to a lease.", priv->iface); + nm_log_warn (LOGD_DHCP6, "(%s): DHCPv6 client didn't bind to a lease.", priv->iface); return NULL; } From 8398ccba592f96518f64bc82491b3f26a41e272f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 09:48:31 -0700 Subject: [PATCH 075/105] dhcp: simplify option iteration Also removes the failure return when the lease isn't bound, because nothing was respecting the return value anyway. --- src/dhcp-manager/nm-dhcp-client.c | 69 +++++++++++++------------------ 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index cf50efddce..22468db5e2 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -553,48 +553,14 @@ nm_dhcp_client_new_options (NMDHCPClient *self, #define NEW_TAG "new_" #define OLD_TAG "old_" -typedef struct { - GHFunc func; - gpointer user_data; -} DhcpForeachInfo; - -static void -iterate_dhcp_config_option (gpointer key, - gpointer value, - gpointer user_data) -{ - DhcpForeachInfo *info = (DhcpForeachInfo *) user_data; - char *tmp_key = NULL; - const char **p; - static const char *filter_options[] = { - "interface", "pid", "reason", "dhcp_message_type", NULL - }; - - /* Filter out stuff that's not actually new DHCP options */ - for (p = filter_options; *p; p++) { - if (!strcmp (*p, (const char *) key)) - return; - if (!strncmp ((const char *) key, OLD_TAG, strlen (OLD_TAG))) - return; - } - - /* Remove the "new_" prefix that dhclient passes back */ - if (!strncmp ((const char *) key, NEW_TAG, strlen (NEW_TAG))) - tmp_key = g_strdup ((const char *) (key + strlen (NEW_TAG))); - else - tmp_key = g_strdup ((const char *) key); - - (*info->func) ((gpointer) tmp_key, value, info->user_data); - g_free (tmp_key); -} - gboolean nm_dhcp_client_foreach_option (NMDHCPClient *self, GHFunc func, gpointer user_data) { NMDHCPClientPrivate *priv; - DhcpForeachInfo info = { NULL, NULL }; + GHashTableIter iter; + gpointer iterkey, itervalue; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); @@ -608,12 +574,35 @@ nm_dhcp_client_foreach_option (NMDHCPClient *self, } else { nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 client didn't bind to a lease.", priv->iface); } - return FALSE; } - info.func = func; - info.user_data = user_data; - g_hash_table_foreach (priv->options, iterate_dhcp_config_option, &info); + g_hash_table_iter_init (&iter, priv->options); + while (g_hash_table_iter_next (&iter, &iterkey, &itervalue)) { + const char *key = iterkey, *value = itervalue; + const char **p; + static const char *filter_options[] = { + "interface", "pid", "reason", "dhcp_message_type", NULL + }; + gboolean ignore = FALSE; + + /* Filter out stuff that's not actually new DHCP options */ + for (p = filter_options; *p; p++) { + if (!strcmp (*p, key) || !strncmp (key, OLD_TAG, strlen (OLD_TAG))) { + ignore = TRUE; + break; + } + } + + if (!ignore) { + const char *tmp_key = value; + + /* Remove the "new_" prefix that dhclient passes back */ + if (!strncmp (key, NEW_TAG, strlen (NEW_TAG))) + tmp_key = key + strlen (NEW_TAG); + + func ((gpointer) tmp_key, (gpointer) value, user_data); + } + } return TRUE; } From 07de58bbeb6dd2daecec32f7d9842ee6751b8df7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 09:53:49 -0700 Subject: [PATCH 076/105] dhcp: clean up client spawn return value --- src/dhcp-manager/nm-dhcp-dhclient.c | 2 +- src/dhcp-manager/nm-dhcp-dhcpcd.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index 37543edc0b..d7a6e32fb3 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -482,7 +482,7 @@ dhclient_start (NMDHCPClient *client, { NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client); GPtrArray *argv = NULL; - GPid pid = 0; + GPid pid = -1; GError *error = NULL; const char *iface, *uuid; char *binary_name, *cmd_str; diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index 716949324c..403431fcb4 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -92,7 +92,7 @@ real_ip4_start (NMDHCPClient *client, { NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client); GPtrArray *argv = NULL; - GPid pid = 0; + GPid pid = -1; GError *error = NULL; char *pid_contents = NULL, *binary_name, *cmd_str; const char *iface, *uuid, *hostname; @@ -147,6 +147,7 @@ real_ip4_start (NMDHCPClient *client, &dhcpcd_child_setup, NULL, &pid, &error)) { nm_log_warn (LOGD_DHCP4, "dhcpcd failed to start. error: '%s'", error->message); g_error_free (error); + pid = -1; } else nm_log_info (LOGD_DHCP4, "dhcpcd started with pid %d", pid); From 39c2797848d6bd335e100dcf3a90ee6a9b51f07e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 10:12:25 -0700 Subject: [PATCH 077/105] dhcp: don't reset pid on client exit Clients in IPv6 info-only mode may exit after getting a response from the server, since there are no leases involved in info-only mode. To ensure that the client's options are received when the event comes in (which could be after we get the child watch callback for the exit) we still need the client's PID. --- src/dhcp-manager/nm-dhcp-client.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 22468db5e2..c2ead0e702 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -227,7 +227,6 @@ daemon_watch_cb (GPid pid, gint status, gpointer user_data) nm_log_warn (LOGD_DHCP, "DHCP client died abnormally"); } else priv->state = DHC_END; - priv->pid = -1; watch_cleanup (self); timeout_cleanup (self); From bec6147e9b1668f9317b190faa4dee069fec3831 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 May 2010 10:16:38 -0700 Subject: [PATCH 078/105] dhcp6: track client mode better and handle info-only early-exit Ignore early exits of the client in info-only mode; since there is no address lease the client doesn't need to stick around after getting DNS/etc options from the server. --- src/nm-device.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/nm-device.c b/src/nm-device.c index 4da051e21c..9fa2523b9f 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -134,9 +134,9 @@ typedef struct { gulong ip6_addrconf_sigid; gulong ip6_config_changed_sigid; gboolean ip6_waiting_for_config; - guint32 ip6_dhcp_opt; NMDHCPClient * dhcp6_client; + guint32 dhcp6_mode; gulong dhcp6_state_sigid; gulong dhcp6_timeout_sigid; NMDHCP6Config * dhcp6_config; @@ -607,10 +607,10 @@ ip6_addrconf_complete (NMIP6Manager *ip6_manager, return; } - priv->ip6_dhcp_opt = dhcp_opts; + priv->dhcp6_mode = dhcp_opts; /* If addrconf is all that's required, we're done */ - if (dhcp_opts == IP6_DHCP_OPT_NONE) { + if (priv->dhcp6_mode == IP6_DHCP_OPT_NONE) { nm_device_activate_schedule_stage4_ip6_config_get (self); return; } @@ -627,7 +627,7 @@ ip6_addrconf_complete (NMIP6Manager *ip6_manager, " as requested by IPv6 router...", priv->iface); - ret = dhcp6_start (self, connection, dhcp_opts, &reason); + ret = dhcp6_start (self, connection, priv->dhcp6_mode, &reason); switch (ret) { case NM_ACT_STAGE_RETURN_SUCCESS: /* Shouldn't get this, but handle it anyway */ @@ -656,6 +656,8 @@ ip6_config_changed (NMIP6Manager *ip6_manager, if (!nm_device_get_act_request (self)) return; + /* FIXME: re-run DHCPv6 here to get any new nameservers or whatever */ + nm_device_activate_schedule_stage4_ip6_config_get (self); } @@ -697,8 +699,6 @@ addrconf6_setup (NMDevice *self) self); } - priv->ip6_dhcp_opt = IP6_DHCP_OPT_NONE; - s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); nm_ip6_manager_prepare_interface (priv->ip6_manager, nm_device_get_ip_ifindex (self), @@ -1302,9 +1302,16 @@ dhcp_state_changed (NMDHCPClient *client, nm_device_activate_schedule_stage4_ip4_config_timeout (device); } break; + case DHC_END: /* dhclient exited normally */ + /* 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 (ipv6 && (priv->dhcp6_mode == IP6_DHCP_OPT_OTHERCONF)) + break; + /* Otherwise, fall through */ case DHC_FAIL: /* all attempts to contact server timed out, sleeping */ case DHC_ABEND: /* dhclient exited abnormally */ - case DHC_END: /* dhclient exited normally */ if (ipv6) nm_dhcp6_config_reset (priv->dhcp6_config); else @@ -1537,6 +1544,8 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) ip_iface = nm_device_get_ip_iface (self); + priv->dhcp6_mode = IP6_DHCP_OPT_NONE; + if ( ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO) || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { if (!addrconf6_setup (self)) { @@ -1545,9 +1554,10 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) } nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self)); ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) - ret = dhcp6_start (self, connection, IP6_DHCP_OPT_MANAGED, reason); - else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + priv->dhcp6_mode = IP6_DHCP_OPT_MANAGED; + ret = dhcp6_start (self, connection, priv->dhcp6_mode, reason); + } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { priv->ip6_ready = TRUE; ret = NM_ACT_STAGE_RETURN_STOP; } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) @@ -2538,6 +2548,8 @@ dhcp6_cleanup (NMDevice *self, gboolean stop) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + priv->dhcp6_mode = IP6_DHCP_OPT_NONE; + if (priv->dhcp6_config) { g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG); g_object_unref (priv->dhcp6_config); From c34cc017ba08a2f80db35a3085e59c059bbc7a9e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 2 May 2010 00:24:40 -0700 Subject: [PATCH 079/105] dhcp: handle client early exit correctly When the client exits it may take a short amount of time for the dhclient hook script to deliver the options to NetworkManager; so we need to keep the client object around a bit (so we know what NMDHCPClient the options getting delivered are for). If we don't, the DHCPManager will dispose of the DHCPClient object and then when the options come in, it can't match up the PID from the options with the PID of an existing NMDHCPClient. So put the clients on a removal timer that keeps them around for a bit before we let the manager dispose of them. Since we're keeping the PID around too instead of zeroing it when the client exits (for the reason above), track whether the client is really dead yet so we don't indiscriminately kill a random process that happens to re-use the PID. --- src/dhcp-manager/nm-dhcp-client.c | 73 +++++++++++++++++++++++++----- src/dhcp-manager/nm-dhcp-client.h | 1 + src/dhcp-manager/nm-dhcp-manager.c | 23 ++-------- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index c2ead0e702..6bf9058976 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -41,10 +41,13 @@ typedef struct { guchar state; GPid pid; + gboolean dead; guint timeout_id; guint watch_id; + guint32 remove_id; GHashTable * options; gboolean info_only; + } NMDHCPClientPrivate; #define NM_DHCP_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_CLIENT, NMDHCPClientPrivate)) @@ -54,6 +57,7 @@ G_DEFINE_TYPE_EXTENDED (NMDHCPClient, nm_dhcp_client, G_TYPE_OBJECT, G_TYPE_FLAG enum { STATE_CHANGED, TIMEOUT, + REMOVE, LAST_SIGNAL }; @@ -206,11 +210,46 @@ daemon_timeout (gpointer user_data) return FALSE; } +static gboolean +signal_remove (gpointer user_data) +{ + NMDHCPClient *self = NM_DHCP_CLIENT (user_data); + + NM_DHCP_CLIENT_GET_PRIVATE (self)->remove_id = 0; + g_signal_emit (G_OBJECT (self), signals[REMOVE], 0); + return FALSE; +} + +static void +dhcp_client_set_state (NMDHCPClient *self, + NMDHCPState state, + gboolean emit_state, + gboolean remove_now) +{ + NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); + + priv->state = state; + + if (emit_state) + g_signal_emit (G_OBJECT (self), signals[STATE_CHANGED], 0, priv->state); + + if (state == DHC_END || state == DHC_ABEND) { + /* Start the remove signal timer */ + if (remove_now) { + g_signal_emit (G_OBJECT (self), signals[REMOVE], 0); + } else { + if (!priv->remove_id) + priv->remove_id = g_timeout_add_seconds (5, signal_remove, self); + } + } +} + static void daemon_watch_cb (GPid pid, gint status, gpointer user_data) { NMDHCPClient *self = NM_DHCP_CLIENT (user_data); NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); + NMDHCPState new_state; if (priv->ipv6) { nm_log_info (LOGD_DHCP6, "(%s): DHCPv6 client pid %d exited with status %d", @@ -223,15 +262,16 @@ daemon_watch_cb (GPid pid, gint status, gpointer user_data) } if (!WIFEXITED (status)) { - priv->state = DHC_ABEND; + new_state = DHC_ABEND; nm_log_warn (LOGD_DHCP, "DHCP client died abnormally"); } else - priv->state = DHC_END; + new_state = DHC_END; watch_cleanup (self); timeout_cleanup (self); + priv->dead = TRUE; - g_signal_emit (G_OBJECT (self), signals[STATE_CHANGED], 0, priv->state); + dhcp_client_set_state (self, new_state, TRUE, FALSE); } static void @@ -349,8 +389,9 @@ nm_dhcp_client_stop (NMDHCPClient *self) priv = NM_DHCP_CLIENT_GET_PRIVATE (self); /* Kill the DHCP client */ - if (priv->pid > 0) { + if (!priv->dead) { NM_DHCP_CLIENT_GET_CLASS (self)->stop (self); + priv->dead = TRUE; nm_log_info (LOGD_DHCP, "(%s): canceled DHCP transaction, DHCP client pid %d", priv->iface, priv->pid); @@ -359,7 +400,7 @@ nm_dhcp_client_stop (NMDHCPClient *self) /* And clean stuff up */ priv->pid = -1; - priv->state = DHC_END; + dhcp_client_set_state (self, DHC_END, FALSE, TRUE); g_hash_table_remove_all (priv->options); @@ -530,23 +571,19 @@ nm_dhcp_client_new_options (NMDHCPClient *self, timeout_cleanup (self); } - priv->state = new_state; if (priv->ipv6) { nm_log_info (LOGD_DHCP6, "(%s): DHCPv6 state changed %s -> %s", priv->iface, state_to_string (old_state), - state_to_string (priv->state)); + state_to_string (new_state)); } else { nm_log_info (LOGD_DHCP4, "(%s): DHCPv4 state changed %s -> %s", priv->iface, state_to_string (old_state), - state_to_string (priv->state)); + state_to_string (new_state)); } - g_signal_emit (G_OBJECT (self), - signals[STATE_CHANGED], - 0, - priv->state); + dhcp_client_set_state (self, new_state, TRUE, FALSE); } #define NEW_TAG "new_" @@ -1089,6 +1126,9 @@ dispose (GObject *object) * the DHCP client. */ + if (priv->remove_id) + g_source_remove (priv->remove_id); + g_hash_table_destroy (priv->options); g_free (priv->iface); @@ -1159,5 +1199,14 @@ nm_dhcp_client_class_init (NMDHCPClientClass *client_class) NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + signals[REMOVE] = + g_signal_new ("remove", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDHCPClientClass, remove), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index 146cf57b3f..92b2b8fe51 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -99,6 +99,7 @@ typedef struct { /* Signals */ void (*state_changed) (NMDHCPClient *self, NMDHCPState state); void (*timeout) (NMDHCPClient *self); + void (*remove) (NMDHCPClient *self); } NMDHCPClientClass; GType nm_dhcp_client_get_type (void); diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index c2aacbbbe5..7b110fb232 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -358,7 +358,7 @@ nm_dhcp_manager_new (const char *client, GError **error) return singleton; } -#define STATE_ID_TAG "state-id" +#define REMOVE_ID_TAG "remove-id" #define TIMEOUT_ID_TAG "timeout-id" static void @@ -367,7 +367,7 @@ remove_client (NMDHCPManager *self, NMDHCPClient *client) NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self); guint id; - id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (client), STATE_ID_TAG)); + id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (client), REMOVE_ID_TAG)); if (id) g_signal_handler_disconnect (client, id); @@ -383,29 +383,16 @@ remove_client (NMDHCPManager *self, NMDHCPClient *client) g_hash_table_remove (priv->clients, client); } -static void -client_state_changed (NMDHCPClient *client, NMDHCPState new_state, gpointer user_data) -{ - if (new_state == DHC_ABEND || new_state == DHC_END) - remove_client (NM_DHCP_MANAGER (user_data), client); -} - -static void -client_timeout (NMDHCPClient *client, gpointer user_data) -{ - remove_client (NM_DHCP_MANAGER (user_data), client); -} - static void add_client (NMDHCPManager *self, NMDHCPClient *client) { NMDHCPManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self); guint id; - id = g_signal_connect (client, "state-changed", G_CALLBACK (client_state_changed), self); - g_object_set_data (G_OBJECT (client), STATE_ID_TAG, GUINT_TO_POINTER (id)); + id = g_signal_connect_swapped (client, "remove", G_CALLBACK (remove_client), self); + g_object_set_data (G_OBJECT (client), REMOVE_ID_TAG, GUINT_TO_POINTER (id)); - id = g_signal_connect (client, "timeout", G_CALLBACK (client_timeout), self); + id = g_signal_connect_swapped (client, "timeout", G_CALLBACK (remove_client), self); g_object_set_data (G_OBJECT (client), TIMEOUT_ID_TAG, GUINT_TO_POINTER (id)); g_hash_table_insert (priv->clients, client, g_object_ref (client)); From 28d2c5592bd36a835fdc8df9949c9a0a61ca6024 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 2 May 2010 00:24:50 -0700 Subject: [PATCH 080/105] dhcp: ensure getting DHCP IP config fails if the client died early If the client never delivered any options to NM, make sure we don't return a valid IP config object to callers when they request one. --- src/dhcp-manager/nm-dhcp-client.c | 10 ++++++++++ src/nm-system.c | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 6bf9058976..5cebaa84ee 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -915,6 +915,11 @@ nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test) return NULL; } + if (!g_hash_table_size (priv->options)) { + /* We never got a response from the DHCP client */ + return NULL; + } + return ip4_options_to_config (self); } @@ -1048,6 +1053,11 @@ nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test) return NULL; } + if (!g_hash_table_size (priv->options)) { + /* We never got a response from the DHCP client */ + return NULL; + } + return ip6_options_to_config (self); } diff --git a/src/nm-system.c b/src/nm-system.c index 20d06b83ad..726da0a825 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -486,18 +486,23 @@ nm_system_device_set_ip6_route (const char *iface, /* Add the route */ err = rtnl_route_add (nlh, route, 0); +g_message ("%s: 1 err %d", __func__, err); if (err == -ESRCH && ip6_gateway) { /* Gateway might be over a bridge; try adding a route to gateway first */ struct rtnl_route *route2; +g_message ("%s: 2", __func__); route2 = create_route (iface_idx, mss); if (route2) { +g_message ("%s: 3", __func__); /* Add route to gateway over bridge */ rtnl_route_set_dst (route2, gw_addr); err = rtnl_route_add (nlh, route2, 0); +g_message ("%s: 4 err %d", __func__, err); if (!err) { /* Try adding the route again */ err = rtnl_route_add (nlh, route, 0); +g_message ("%s: 5 err %d", __func__, err); if (err) rtnl_route_del (nlh, route2, 0); } From 32b255e1281a9962404e3a47b0e0c6c64b91d1af Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 2 May 2010 00:32:26 -0700 Subject: [PATCH 081/105] trivial: remove some debugging leftovers --- src/nm-system.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/nm-system.c b/src/nm-system.c index 726da0a825..20d06b83ad 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -486,23 +486,18 @@ nm_system_device_set_ip6_route (const char *iface, /* Add the route */ err = rtnl_route_add (nlh, route, 0); -g_message ("%s: 1 err %d", __func__, err); if (err == -ESRCH && ip6_gateway) { /* Gateway might be over a bridge; try adding a route to gateway first */ struct rtnl_route *route2; -g_message ("%s: 2", __func__); route2 = create_route (iface_idx, mss); if (route2) { -g_message ("%s: 3", __func__); /* Add route to gateway over bridge */ rtnl_route_set_dst (route2, gw_addr); err = rtnl_route_add (nlh, route2, 0); -g_message ("%s: 4 err %d", __func__, err); if (!err) { /* Try adding the route again */ err = rtnl_route_add (nlh, route, 0); -g_message ("%s: 5 err %d", __func__, err); if (err) rtnl_route_del (nlh, route2, 0); } From 5ca72c78a0ae3ff818c7d47de2738fe776e0c470 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 2 May 2010 00:44:44 -0700 Subject: [PATCH 082/105] ip6: avoid autoconf routes where dest == gateway These return errors when we try to add them via netlink (both internal code and using /sbin/ip) so we'll ignore them for now. --- src/ip6-manager/nm-ip6-manager.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 0b7949d974..cafe9cc430 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -983,6 +983,13 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) continue; } + /* Also ignore routes where the destination and gateway are the same, + * which apparently get added by the kernel but return -EINVAL when + * we try to add them via netlink. + */ + if (gateway && !memcmp (dest, gateway, sizeof (struct in6_addr))) + continue; + ip6route = nm_ip6_route_new (); nm_ip6_route_set_dest (ip6route, dest); nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute)); From 71c7ecba081bad942ca9445fd267a68385ba4cee Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 2 May 2010 13:22:29 -0700 Subject: [PATCH 083/105] libnm-util: more IPv6 address gateway fixes --- libnm-util/nm-setting-ip6-config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libnm-util/nm-setting-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index 3e42216cbd..05f21f037e 100644 --- a/libnm-util/nm-setting-ip6-config.c +++ b/libnm-util/nm-setting-ip6-config.c @@ -834,6 +834,7 @@ nm_ip6_address_dup (NMIP6Address *source) address = nm_ip6_address_new (); address->prefix = source->prefix; memcpy (&address->address, &source->address, sizeof (struct in6_addr)); + memcpy (&address->gateway, &source->gateway, sizeof (struct in6_addr)); return address; } @@ -870,7 +871,8 @@ nm_ip6_address_compare (NMIP6Address *address, NMIP6Address *other) g_return_val_if_fail (other->refcount > 0, FALSE); if ( memcmp (&address->address, &other->address, sizeof (struct in6_addr)) - || address->prefix != other->prefix) + || address->prefix != other->prefix + || memcmp (&address->gateway, &other->gateway, sizeof (struct in6_addr))) return FALSE; return TRUE; } From 806b74db348a16b0a0ed0f0c38105126f8272a7d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 2 May 2010 16:51:26 -0700 Subject: [PATCH 084/105] libnm-util: add 'may-fail' for IPv4 and IPv6 When this property is TRUE, IP configuration can continue as long as at least on IP configuration type succeeds. This allows connections to networks where the user does not necessarily know whether the network supports IPv4 or IPv6 and does not require that both complete succesfully. Since most of the time the user doesn't really care what type of connectivity they have, as long as they have *some* connectivity, this allows better "Just Works" behavior as long as the system settings plugins and connection editors/applets use the right defaults. Suggested defaults for may-fail are: IPv4: no (ie, require IPv4 connectivity) IPv6: yes (ie, do not require IPv6 connectivity) Users who require a specific type of connectivity are probably knowlegable enough to check the box as needed for their network. --- libnm-util/Makefile.am | 2 +- libnm-util/libnm-util.ver | 6 +++-- libnm-util/nm-setting-ip4-config.c | 41 ++++++++++++++++++++++++++++++ libnm-util/nm-setting-ip4-config.h | 3 +++ libnm-util/nm-setting-ip6-config.c | 40 +++++++++++++++++++++++++++++ libnm-util/nm-setting-ip6-config.h | 2 ++ 6 files changed, 91 insertions(+), 3 deletions(-) diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index bb4736f45b..ddc68408ab 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -59,7 +59,7 @@ libnm_util_la_SOURCES= \ libnm_util_la_LIBADD = $(GLIB_LIBS) $(DBUS_LIBS) $(UUID_LIBS) libnm_util_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-util.ver \ - -version-info "4:3:3" + -version-info "4:4:3" if WITH_GNUTLS libnm_util_la_SOURCES += crypto_gnutls.c diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index 1c8446ba2e..ed1d8a484f 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -168,8 +168,7 @@ global: nm_setting_ip4_config_get_dhcp_hostname; nm_setting_ip4_config_get_dhcp_send_hostname; nm_setting_ip4_config_get_never_default; - nm_setting_ip6_config_error_get_type; - nm_setting_ip6_config_error_quark; + nm_setting_ip4_config_get_may_fail; nm_ip6_address_new; nm_ip6_address_dup; nm_ip6_address_ref; @@ -194,6 +193,8 @@ global: nm_ip6_route_set_next_hop; nm_ip6_route_get_metric; nm_ip6_route_set_metric; + nm_setting_ip6_config_error_get_type; + nm_setting_ip6_config_error_quark; nm_setting_ip6_config_get_type; nm_setting_ip6_config_new; nm_setting_ip6_config_get_method; @@ -220,6 +221,7 @@ global: nm_setting_ip6_config_get_ignore_auto_routes; nm_setting_ip6_config_get_ignore_auto_dns; nm_setting_ip6_config_get_never_default; + nm_setting_ip6_config_get_may_fail; nm_setting_need_secrets; nm_setting_ppp_error_get_type; nm_setting_ppp_error_quark; diff --git a/libnm-util/nm-setting-ip4-config.c b/libnm-util/nm-setting-ip4-config.c index c1d7f01c76..a1a9674af7 100644 --- a/libnm-util/nm-setting-ip4-config.c +++ b/libnm-util/nm-setting-ip4-config.c @@ -83,6 +83,7 @@ typedef struct { gboolean dhcp_send_hostname; char *dhcp_hostname; gboolean never_default; + gboolean may_fail; } NMSettingIP4ConfigPrivate; enum { @@ -98,6 +99,7 @@ enum { PROP_DHCP_SEND_HOSTNAME, PROP_DHCP_HOSTNAME, PROP_NEVER_DEFAULT, + PROP_MAY_FAIL, LAST_PROP }; @@ -438,6 +440,14 @@ nm_setting_ip4_config_get_never_default (NMSettingIP4Config *setting) return NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting)->never_default; } +gboolean +nm_setting_ip4_config_get_may_fail (NMSettingIP4Config *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP4_CONFIG (setting), FALSE); + + return NM_SETTING_IP4_CONFIG_GET_PRIVATE (setting)->may_fail; +} + static gboolean verify (NMSetting *setting, GSList *all_settings, GError **error) { @@ -641,6 +651,9 @@ set_property (GObject *object, guint prop_id, case PROP_NEVER_DEFAULT: priv->never_default = g_value_get_boolean (value); break; + case PROP_MAY_FAIL: + priv->may_fail = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -688,6 +701,9 @@ get_property (GObject *object, guint prop_id, case PROP_NEVER_DEFAULT: g_value_set_boolean (value, priv->never_default); break; + case PROP_MAY_FAIL: + g_value_set_boolean (value, priv->may_fail); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -968,6 +984,31 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) "the default route by NetworkManager.", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); + + /** + * NMSettingIP4Config:may-fail: + * + * If TRUE, allow overall network configuration to proceed even if IPv4 + * configuration fails or times out. Note that at least one IP configuration + * must succeed or overall network configuration will still fail. For + * example, in IPv6-only networks, setting this property to TRUE allows + * the overall network configuration to succeed if IPv4 configuration fails + * but IPv6 configuration completes successfully. + **/ + g_object_class_install_property + (object_class, PROP_MAY_FAIL, + g_param_spec_boolean (NM_SETTING_IP4_CONFIG_MAY_FAIL, + "May Fail", + "If TRUE, allow overall network configuration to " + "proceed even if IPv4 configuration fails or times " + "out. Note that at least one IP configuration must " + "succeed or overall network configuration will still " + "fail. For example, in IPv6-only networks, setting " + "this property to TRUE allows the overall network " + "configuration to succeed if IPv4 configuration " + "fails but IPv6 configuration completes successfully.", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); } diff --git a/libnm-util/nm-setting-ip4-config.h b/libnm-util/nm-setting-ip4-config.h index 777f53f126..80ddd4758e 100644 --- a/libnm-util/nm-setting-ip4-config.h +++ b/libnm-util/nm-setting-ip4-config.h @@ -64,6 +64,7 @@ GQuark nm_setting_ip4_config_error_quark (void); #define NM_SETTING_IP4_CONFIG_DHCP_SEND_HOSTNAME "dhcp-send-hostname" #define NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME "dhcp-hostname" #define NM_SETTING_IP4_CONFIG_NEVER_DEFAULT "never-default" +#define NM_SETTING_IP4_CONFIG_MAY_FAIL "may-fail" #define NM_SETTING_IP4_CONFIG_METHOD_AUTO "auto" #define NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL "link-local" @@ -169,6 +170,8 @@ const char * nm_setting_ip4_config_get_dhcp_hostname (NMSettingIP4Config * gboolean nm_setting_ip4_config_get_never_default (NMSettingIP4Config *setting); +gboolean nm_setting_ip4_config_get_may_fail (NMSettingIP4Config *setting); + G_END_DECLS #endif /* NM_SETTING_IP4_CONFIG_H */ diff --git a/libnm-util/nm-setting-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index 05f21f037e..f92595b705 100644 --- a/libnm-util/nm-setting-ip6-config.c +++ b/libnm-util/nm-setting-ip6-config.c @@ -79,6 +79,7 @@ typedef struct { gboolean ignore_auto_routes; gboolean ignore_auto_dns; gboolean never_default; + gboolean may_fail; } NMSettingIP6ConfigPrivate; @@ -92,6 +93,7 @@ enum { PROP_IGNORE_AUTO_ROUTES, PROP_IGNORE_AUTO_DNS, PROP_NEVER_DEFAULT, + PROP_MAY_FAIL, LAST_PROP }; @@ -414,6 +416,14 @@ nm_setting_ip6_config_get_never_default (NMSettingIP6Config *setting) return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->never_default; } +gboolean +nm_setting_ip6_config_get_may_fail (NMSettingIP6Config *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (setting), FALSE); + + return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->may_fail; +} + static gboolean verify (NMSetting *setting, GSList *all_settings, GError **error) { @@ -535,6 +545,9 @@ set_property (GObject *object, guint prop_id, case PROP_NEVER_DEFAULT: priv->never_default = g_value_get_boolean (value); break; + case PROP_MAY_FAIL: + priv->may_fail = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -572,6 +585,9 @@ get_property (GObject *object, guint prop_id, case PROP_NEVER_DEFAULT: g_value_set_boolean (value, priv->never_default); break; + case PROP_MAY_FAIL: + g_value_set_boolean (value, priv->may_fail); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -802,6 +818,30 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class) FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); + /** + * NMSettingIP6Config:may-fail: + * + * If TRUE, allow overall network configuration to proceed even if IPv6 + * configuration fails or times out. Note that at least one IP configuration + * must succeed or overall network configuration will still fail. For + * example, in IPv4-only networks, setting this property to TRUE allows + * the overall network configuration to succeed if IPv6 configuration fails + * but IPv4 configuration completes successfully. + **/ + g_object_class_install_property + (object_class, PROP_MAY_FAIL, + g_param_spec_boolean (NM_SETTING_IP6_CONFIG_MAY_FAIL, + "May Fail", + "If TRUE, allow overall network configuration to " + "proceed even if IPv6 configuration fails or times " + "out. Note that at least one IP configuration must " + "succeed or overall network configuration will still " + "fail. For example, in IPv4-only networks, setting " + "this property to TRUE allows the overall network " + "configuration to succeed if IPv6 configuration " + "fails but IPv4 configuration completes successfully.", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); } /********************************************************************/ diff --git a/libnm-util/nm-setting-ip6-config.h b/libnm-util/nm-setting-ip6-config.h index 78617c4547..e3e286e684 100644 --- a/libnm-util/nm-setting-ip6-config.h +++ b/libnm-util/nm-setting-ip6-config.h @@ -62,6 +62,7 @@ GQuark nm_setting_ip6_config_error_quark (void); #define NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES "ignore-auto-routes" #define NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS "ignore-auto-dns" #define NM_SETTING_IP6_CONFIG_NEVER_DEFAULT "never-default" +#define NM_SETTING_IP6_CONFIG_MAY_FAIL "may-fail" #define NM_SETTING_IP6_CONFIG_METHOD_IGNORE "ignore" #define NM_SETTING_IP6_CONFIG_METHOD_AUTO "auto" @@ -163,6 +164,7 @@ gboolean nm_setting_ip6_config_get_ignore_auto_routes (NMSettingIP gboolean nm_setting_ip6_config_get_ignore_auto_dns (NMSettingIP6Config *setting); gboolean nm_setting_ip6_config_get_never_default (NMSettingIP6Config *setting); +gboolean nm_setting_ip6_config_get_may_fail (NMSettingIP6Config *setting); G_END_DECLS From 7025e054d943ae146f1b9f375d47b6871811bc28 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 00:08:02 -0700 Subject: [PATCH 085/105] libnm-util: clarify may-fail behavior --- libnm-util/nm-setting-ip4-config.c | 6 +++--- libnm-util/nm-setting-ip6-config.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libnm-util/nm-setting-ip4-config.c b/libnm-util/nm-setting-ip4-config.c index a1a9674af7..186e41e243 100644 --- a/libnm-util/nm-setting-ip4-config.c +++ b/libnm-util/nm-setting-ip4-config.c @@ -989,7 +989,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) * NMSettingIP4Config:may-fail: * * If TRUE, allow overall network configuration to proceed even if IPv4 - * configuration fails or times out. Note that at least one IP configuration + * configuration times out. Note that at least one IP configuration * must succeed or overall network configuration will still fail. For * example, in IPv6-only networks, setting this property to TRUE allows * the overall network configuration to succeed if IPv4 configuration fails @@ -1000,8 +1000,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class) g_param_spec_boolean (NM_SETTING_IP4_CONFIG_MAY_FAIL, "May Fail", "If TRUE, allow overall network configuration to " - "proceed even if IPv4 configuration fails or times " - "out. Note that at least one IP configuration must " + "proceed even if IPv4 configuration times out. " + "Note that at least one IP configuration must " "succeed or overall network configuration will still " "fail. For example, in IPv6-only networks, setting " "this property to TRUE allows the overall network " diff --git a/libnm-util/nm-setting-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index f92595b705..e8af058041 100644 --- a/libnm-util/nm-setting-ip6-config.c +++ b/libnm-util/nm-setting-ip6-config.c @@ -822,7 +822,7 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class) * NMSettingIP6Config:may-fail: * * If TRUE, allow overall network configuration to proceed even if IPv6 - * configuration fails or times out. Note that at least one IP configuration + * configuration times out. Note that at least one IP configuration * must succeed or overall network configuration will still fail. For * example, in IPv4-only networks, setting this property to TRUE allows * the overall network configuration to succeed if IPv6 configuration fails @@ -833,8 +833,8 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class) g_param_spec_boolean (NM_SETTING_IP6_CONFIG_MAY_FAIL, "May Fail", "If TRUE, allow overall network configuration to " - "proceed even if IPv6 configuration fails or times " - "out. Note that at least one IP configuration must " + "proceed even if IPv6 configuration times out. " + "Note that at least one IP configuration must " "succeed or overall network configuration will still " "fail. For example, in IPv4-only networks, setting " "this property to TRUE allows the overall network " From 3fb8cdb35fca27cef848f0e2046fd3fa9c2750ee Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 00:59:06 -0700 Subject: [PATCH 086/105] mesh: let parent class handle IP config timeout --- src/nm-device-olpc-mesh.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c index f73108a793..546ecfafe4 100644 --- a/src/nm-device-olpc-mesh.c +++ b/src/nm-device-olpc-mesh.c @@ -637,15 +637,6 @@ real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) return NM_ACT_STAGE_RETURN_SUCCESS; } -static NMActStageReturn -real_act_stage4_ip4_config_timeout (NMDevice *dev, - NMIP4Config **config, - NMDeviceStateReason *reason) -{ - return NM_ACT_STAGE_RETURN_FAILURE; -} - - static void dispose (GObject *object) { @@ -734,7 +725,6 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) parent_class->act_stage1_prepare = real_act_stage1_prepare; parent_class->act_stage2_config = real_act_stage2_config; - parent_class->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout; /* Properties */ g_object_class_install_property From 8aef7ef411a88a43fb79d139b3ecd003e9c1b5d6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 01:19:54 -0700 Subject: [PATCH 087/105] core: allow selective failure of IP configuration (rh #567978) As long as at least one IP config method completes, and as long as methods that the user required to complete do complete, allow the connection to complete. --- src/nm-device-bt.c | 8 ++- src/nm-device-modem.c | 8 ++- src/nm-device-private.h | 2 + src/nm-device-wifi.c | 106 ++++++++++++++++++++++++++++------------ src/nm-device.c | 87 +++++++++++++++++++++++++-------- 5 files changed, 158 insertions(+), 53 deletions(-) diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c index 8cf179e1ed..ef2c98db0e 100644 --- a/src/nm-device-bt.c +++ b/src/nm-device-bt.c @@ -275,10 +275,16 @@ ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) case NM_DEVICE_STATE_PREPARE: case NM_DEVICE_STATE_CONFIG: case NM_DEVICE_STATE_NEED_AUTH: - case NM_DEVICE_STATE_IP_CONFIG: case NM_DEVICE_STATE_ACTIVATED: nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); break; + case NM_DEVICE_STATE_IP_CONFIG: + if (nm_device_ip_config_should_fail (device, FALSE)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } + break; default: break; } diff --git a/src/nm-device-modem.c b/src/nm-device-modem.c index b13ce6c3bb..3ba26ddcdd 100644 --- a/src/nm-device-modem.c +++ b/src/nm-device-modem.c @@ -72,10 +72,16 @@ ppp_failed (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) case NM_DEVICE_STATE_PREPARE: case NM_DEVICE_STATE_CONFIG: case NM_DEVICE_STATE_NEED_AUTH: - case NM_DEVICE_STATE_IP_CONFIG: case NM_DEVICE_STATE_ACTIVATED: nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); break; + case NM_DEVICE_STATE_IP_CONFIG: + if (nm_device_ip_config_should_fail (device, FALSE)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } + break; default: break; } diff --git a/src/nm-device-private.h b/src/nm-device-private.h index 5c71aa1a78..371f17f10d 100644 --- a/src/nm-device-private.h +++ b/src/nm-device-private.h @@ -40,4 +40,6 @@ void nm_device_handle_autoip4_event (NMDevice *self, const char *event, const char *address); +gboolean nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6); + #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index b598f2b675..1fa2937253 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -2676,7 +2676,11 @@ handle_auth_or_fail (NMDeviceWifi *self, NMConnection *connection; g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); + + if (!req) { + req = nm_device_get_act_request (NM_DEVICE (self)); + g_assert (req); + } connection = nm_act_request_get_connection (req); g_assert (connection); @@ -3187,21 +3191,19 @@ real_act_stage4_get_ip4_config (NMDevice *dev, static NMActStageReturn -real_act_stage4_ip4_config_timeout (NMDevice *dev, - NMIP4Config **config, - NMDeviceStateReason *reason) +handle_ip_config_timeout (NMDeviceWifi *self, + NMConnection *connection, + gboolean may_fail, + gboolean *chain_up, + NMDeviceStateReason *reason) { - NMDeviceWifi *self = NM_DEVICE_WIFI (dev); - NMAccessPoint *ap = nm_device_wifi_get_activation_ap (self); + NMAccessPoint *ap; NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMIP4Config *real_config = NULL; - NMActRequest *req = nm_device_get_act_request (dev); - NMConnection *connection; gboolean auth_enforced = FALSE, encrypted = FALSE; - g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); + ap = nm_device_wifi_get_activation_ap (self); g_assert (ap); /* If nothing checks the security authentication information (as in @@ -3209,9 +3211,8 @@ real_act_stage4_ip4_config_timeout (NMDevice *dev, * the encryption key is likely wrong. Ask the user for a new one. * Otherwise the failure likely happened after a successful authentication. */ - connection = nm_act_request_get_connection (req); auth_enforced = ap_auth_enforced (connection, ap, &encrypted); - if (encrypted && !auth_enforced) { + if (encrypted && !auth_enforced && !may_fail) { NMSettingConnection *s_con; s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); @@ -3220,39 +3221,83 @@ real_act_stage4_ip4_config_timeout (NMDevice *dev, nm_log_warn (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): could not get IP configuration for " "connection '%s'.", - nm_device_get_iface (dev), nm_setting_connection_get_id (s_con)); + nm_device_get_iface (NM_DEVICE (self)), + nm_setting_connection_get_id (s_con)); - ret = handle_auth_or_fail (self, req, TRUE); + ret = handle_auth_or_fail (self, NULL, TRUE); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { nm_log_info (LOGD_DEVICE | LOGD_WIFI, "Activation (%s/wireless): asking for new secrets", - nm_device_get_iface (dev)); + nm_device_get_iface (NM_DEVICE (self))); } else { *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; } - } else if (nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) { - NMDeviceWifiClass *klass; - NMDeviceClass * parent_class; - - /* For Ad-Hoc networks, chain up to parent to get a Zeroconf IP */ - klass = NM_DEVICE_WIFI_GET_CLASS (self); - parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); - ret = parent_class->act_stage4_ip4_config_timeout (dev, &real_config, reason); } else { /* Non-encrypted network or authentication is enforced by some - * entity (AP, RADIUS server, etc), but IP configure failed. Alert - * the user. + * entity (AP, RADIUS server, etc), but IP configure failed. Let the + * superclass handle it. */ - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; - ret = NM_ACT_STAGE_RETURN_FAILURE; + *chain_up = TRUE; } - *config = real_config; - return ret; } +static NMActStageReturn +real_act_stage4_ip4_config_timeout (NMDevice *dev, + NMIP4Config **config, + NMDeviceStateReason *reason) +{ + NMActRequest *req; + NMConnection *connection; + NMSettingIP4Config *s_ip4; + gboolean may_fail = FALSE, chain_up = FALSE; + NMActStageReturn ret; + + req = nm_device_get_act_request (dev); + g_assert (req); + connection = nm_act_request_get_connection (req); + g_assert (connection); + + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (s_ip4) + may_fail = nm_setting_ip4_config_get_may_fail (s_ip4); + + ret = handle_ip_config_timeout (NM_DEVICE_WIFI (dev), connection, may_fail, &chain_up, reason); + if (chain_up) + ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip4_config_timeout (dev, config, reason); + + return ret; +} + +static NMActStageReturn +real_act_stage4_ip6_config_timeout (NMDevice *dev, + NMIP6Config **config, + NMDeviceStateReason *reason) +{ + NMActRequest *req; + NMConnection *connection; + NMSettingIP6Config *s_ip6; + gboolean may_fail = FALSE, chain_up = FALSE; + NMActStageReturn ret; + + req = nm_device_get_act_request (dev); + g_assert (req); + connection = nm_act_request_get_connection (req); + g_assert (connection); + + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6) + may_fail = nm_setting_ip6_config_get_may_fail (s_ip6); + + ret = handle_ip_config_timeout (NM_DEVICE_WIFI (dev), connection, may_fail, &chain_up, reason); + if (chain_up) + ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage4_ip6_config_timeout (dev, config, reason); + + return ret; +} + static void activation_success_handler (NMDevice *dev) { @@ -3725,6 +3770,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->act_stage2_config = real_act_stage2_config; parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; parent_class->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout; + parent_class->act_stage4_ip6_config_timeout = real_act_stage4_ip6_config_timeout; parent_class->deactivate = real_deactivate; parent_class->deactivate_quickly = real_deactivate_quickly; parent_class->can_interrupt_activation = real_can_interrupt_activation; diff --git a/src/nm-device.c b/src/nm-device.c index 9fa2523b9f..a09a69218f 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -177,6 +177,11 @@ static NMActStageReturn dhcp6_start (NMDevice *self, guint32 dhcp_opt, NMDeviceStateReason *reason); +static void addrconf6_cleanup (NMDevice *self); +static void dhcp6_cleanup (NMDevice *self, gboolean stop); +static void dhcp4_cleanup (NMDevice *self, gboolean stop); + + static void device_interface_init (NMDeviceInterface *device_interface_class) { @@ -574,6 +579,35 @@ activation_source_schedule (NMDevice *self, GSourceFunc func, int family) } } +gboolean +nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6) +{ + NMActRequest *req; + NMConnection *connection; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + + g_return_val_if_fail (self != NULL, TRUE); + + req = nm_device_get_act_request (self); + g_assert (req); + connection = nm_act_request_get_connection (req); + g_assert (connection); + + /* Fail the connection if the failed IP method is required to complete */ + if (ip6) { + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6 && !nm_setting_ip6_config_get_may_fail (s_ip6)) + return TRUE; + } else { + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (s_ip4 && !nm_setting_ip4_config_get_may_fail (s_ip4)) + return TRUE; + } + + return FALSE; +} + static void ip6_addrconf_complete (NMIP6Manager *ip6_manager, int ifindex, @@ -1318,9 +1352,12 @@ dhcp_state_changed (NMDHCPClient *client, nm_dhcp4_config_reset (priv->dhcp4_config); /* dhclient quit and can't get/renew a lease; so kill the connection */ - if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DHCP_FAILED); - else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) + if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) { + if (ipv6) + nm_device_activate_schedule_stage4_ip6_config_timeout (device); + else + nm_device_activate_schedule_stage4_ip4_config_timeout (device); + } else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); break; case DHC_STOP: @@ -1797,8 +1834,7 @@ nm_device_activate_stage4_ip4_config_get (gpointer user_data) ret = NM_DEVICE_GET_CLASS (self)->act_stage4_get_ip4_config (self, &ip4_config, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) goto out; - else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) - { + else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } @@ -1852,9 +1888,12 @@ real_act_stage4_ip4_config_timeout (NMDevice *self, /* Notify of invalid DHCP4 config object */ g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP4_CONFIG); - /* DHCP failed; connection must fail */ - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; - return NM_ACT_STAGE_RETURN_FAILURE; + if (nm_device_ip_config_should_fail (self, FALSE)) { + *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + return NM_ACT_STAGE_RETURN_FAILURE; + } + + return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -1882,17 +1921,18 @@ nm_device_activate_stage4_ip4_config_timeout (gpointer user_data) iface); ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &ip4_config, &reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) goto out; - } else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) { + else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - g_assert (ip4_config); - g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), - NM_ACT_REQUEST_IP4_CONFIG, ip4_config); + if (ip4_config) { + g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), + NM_ACT_REQUEST_IP4_CONFIG, ip4_config); + } nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET); @@ -2125,11 +2165,15 @@ real_act_stage4_ip6_config_timeout (NMDevice *self, g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE); - /* Notify of invalid DHCP6 config object */ + /* Notify of invalid DHCP4 config object */ g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG); - *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; - return NM_ACT_STAGE_RETURN_FAILURE; + if (nm_device_ip_config_should_fail (self, TRUE)) { + *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + return NM_ACT_STAGE_RETURN_FAILURE; + } + + return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -2157,17 +2201,18 @@ nm_device_activate_stage4_ip6_config_timeout (gpointer user_data) iface); ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &ip6_config, &reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) goto out; - } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - g_assert (ip6_config); - g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), - NM_ACT_REQUEST_IP6_CONFIG, ip6_config); + if (ip6_config) { + g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), + NM_ACT_REQUEST_IP6_CONFIG, ip6_config); + } nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET6); From 13e1aaa423e3ad65a849b55d65f273272b454336 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 01:33:55 -0700 Subject: [PATCH 088/105] ifcfg-rh: add support for non-fatal IP configuration failure --- system-settings/plugins/ifcfg-rh/reader.c | 2 ++ .../tests/network-scripts/ifcfg-test-wired-ipv6-manual | 1 + system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 8 ++++++++ system-settings/plugins/ifcfg-rh/writer.c | 8 ++++++++ 4 files changed, 19 insertions(+) diff --git a/system-settings/plugins/ifcfg-rh/reader.c b/system-settings/plugins/ifcfg-rh/reader.c index c98cf6e272..28244206a9 100644 --- a/system-settings/plugins/ifcfg-rh/reader.c +++ b/system-settings/plugins/ifcfg-rh/reader.c @@ -1233,6 +1233,7 @@ make_ip4_setting (shvarFile *ifcfg, NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "PEERDNS", TRUE), NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "PEERROUTES", TRUE), NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default, + NM_SETTING_IP4_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", TRUE), NULL); /* Handle manual settings */ @@ -1488,6 +1489,7 @@ make_ip6_setting (shvarFile *ifcfg, NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "IPV6_PEERDNS", TRUE), NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "IPV6_PEERROUTES", TRUE), NM_SETTING_IP6_CONFIG_NEVER_DEFAULT, never_default, + NM_SETTING_IP6_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE), NULL); if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-manual b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-manual index 4be4044f18..45db0e4c4b 100644 --- a/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-manual +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-ipv6-manual @@ -16,3 +16,4 @@ IPV6INIT=yes IPV6_AUTOCONF=no IPV6ADDR="1001:abba::1234/56" IPV6ADDR_SECONDARIES="2001:abba::2234/64 3001:abba::3234/96" +IPV6_FAILURE_FATAL=no diff --git a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 9a370be45a..7ca0ecf87c 100644 --- a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -2011,6 +2011,12 @@ test_read_wired_ipv6_manual (void) NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_NEVER_DEFAULT); + ASSERT (nm_setting_ip6_config_get_may_fail (s_ip6) == TRUE, + "wired-ipv6-manual-verify-ip6", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_WIRED_IPV6_MANUAL, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_MAY_FAIL); + /* IP addresses */ ASSERT (nm_setting_ip6_config_get_num_addresses (s_ip6) == 3, "wired-ipv6-manual-verify-ip6", "failed to verify %s: unexpected %s / %s key value", @@ -5157,6 +5163,7 @@ test_write_wired_static (void) g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP4_CONFIG_MAY_FAIL, TRUE, NULL); addr = nm_ip4_address_new (); @@ -5188,6 +5195,7 @@ test_write_wired_static (void) g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, + NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE, NULL); /* Add addresses */ diff --git a/system-settings/plugins/ifcfg-rh/writer.c b/system-settings/plugins/ifcfg-rh/writer.c index d1e1458f73..30ef6e3941 100644 --- a/system-settings/plugins/ifcfg-rh/writer.c +++ b/system-settings/plugins/ifcfg-rh/writer.c @@ -1087,6 +1087,10 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValue (ifcfg, "DHCP_CLIENT_ID", value, FALSE); } + svSetValue (ifcfg, "IPV4_FAILURE_FATAL", + nm_setting_ip4_config_get_may_fail (s_ip4) ? "no" : "yes", + FALSE); + /* Static routes - route- file */ route_path = utils_get_route_path (ifcfg->fileName); if (!route_path) { @@ -1373,6 +1377,10 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) FALSE); } + svSetValue (ifcfg, "IPV6_FAILURE_FATAL", + nm_setting_ip6_config_get_may_fail (s_ip6) ? "no" : "yes", + FALSE); + /* Static routes go to route6- file */ route6_path = utils_get_route6_path (ifcfg->fileName); if (!route6_path) { From dd699c585f125ca512913c2c2d5e7a182749d349 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 02:11:59 -0700 Subject: [PATCH 089/105] core: better logging for interface address syncing --- src/nm-system.c | 61 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/src/nm-system.c b/src/nm-system.c index 20d06b83ad..517460d4fe 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -196,8 +196,10 @@ sync_addresses (const char *iface, int ifindex, int family, struct nl_cache *addr_cache; struct rtnl_addr *filter_addr, *match_addr; struct nl_object *match; + struct nl_addr *nladdr; int i, err; guint32 log_domain = (family == AF_INET) ? LOGD_IP4 : LOGD_IP6; + char buf[INET6_ADDRSTRLEN + 1]; log_domain |= LOGD_DEVICE; @@ -218,20 +220,22 @@ sync_addresses (const char *iface, int ifindex, int family, if (family) rtnl_addr_set_family (filter_addr, family); + nm_log_dbg (log_domain, "(%s): syncing addresses (family %d)", iface, family); + /* Walk through the cache, comparing the addresses already on * the interface to the addresses in addrs. */ for (match = nl_cache_get_first (addr_cache); match; match = nl_cache_get_next (match)) { - match_addr = (struct rtnl_addr *)match; + gboolean buf_valid = FALSE; + match_addr = (struct rtnl_addr *) match; /* Skip addresses not on our interface */ - if (!nl_object_match_filter (match, (struct nl_object *)filter_addr)) + if (!nl_object_match_filter (match, (struct nl_object *) filter_addr)) continue; if (addrs) { for (i = 0; i < num_addrs; i++) { - if (addrs[i] && - nl_object_identical (match, (struct nl_object *)addrs[i])) + if (addrs[i] && nl_object_identical (match, (struct nl_object *) addrs[i])) break; } @@ -245,10 +249,31 @@ sync_addresses (const char *iface, int ifindex, int family, } } + nladdr = rtnl_addr_get_local (match_addr); + /* Don't delete IPv6 link-local addresses; they don't belong to NM */ - if (rtnl_addr_get_family (match_addr) == AF_INET6 && - rtnl_addr_get_scope (match_addr) == RT_SCOPE_LINK) { - continue; + if (rtnl_addr_get_family (match_addr) == AF_INET6) { + struct in6_addr *tmp; + + if (rtnl_addr_get_scope (match_addr) == RT_SCOPE_LINK) { + nm_log_dbg (log_domain, "(%s): ignoring IPv6 link-local address", iface); + continue; + } + + tmp = nl_addr_get_binary_addr (nladdr); + if (inet_ntop (AF_INET6, tmp, buf, sizeof (buf))) + buf_valid = TRUE; + } else if (rtnl_addr_get_family (match_addr) == AF_INET) { + struct in_addr *tmp; + + tmp = nl_addr_get_binary_addr (nladdr); + if (inet_ntop (AF_INET, tmp, buf, sizeof (buf))) + buf_valid = TRUE; + } + + if (buf_valid) { + nm_log_dbg (log_domain, "(%s): removing address '%s/%d'", + iface, buf, nl_addr_get_prefixlen (nladdr)); } /* Otherwise, match_addr should be removed from the interface. */ @@ -264,9 +289,29 @@ sync_addresses (const char *iface, int ifindex, int family, /* Now add the remaining new addresses */ for (i = 0; i < num_addrs; i++) { + struct in6_addr *in6tmp; + struct in_addr *in4tmp; + gboolean buf_valid = FALSE; + if (!addrs[i]) continue; + nladdr = rtnl_addr_get_local (addrs[i]); + if (rtnl_addr_get_family (addrs[i]) == AF_INET6) { + in6tmp = nl_addr_get_binary_addr (nladdr); + if (inet_ntop (AF_INET6, in6tmp, buf, sizeof (buf))) + buf_valid = TRUE; + } else if (rtnl_addr_get_family (addrs[i]) == AF_INET) { + in4tmp = nl_addr_get_binary_addr (nladdr); + if (inet_ntop (AF_INET, in4tmp, buf, sizeof (buf))) + buf_valid = TRUE; + } + + if (buf_valid) { + nm_log_dbg (log_domain, "(%s): adding address '%s/%d'", + iface, buf, nl_addr_get_prefixlen (nladdr)); + } + err = rtnl_addr_add (nlh, addrs[i], 0); if (err < 0) { nm_log_err (log_domain, @@ -1094,7 +1139,7 @@ static void flush_addresses (const char *iface, gboolean ipv4_only) g_return_if_fail (iface != NULL); iface_idx = nm_netlink_iface_to_index (iface); if (iface_idx >= 0) - sync_addresses (iface, iface_idx, ipv4_only ? AF_INET : 0, NULL, 0); + sync_addresses (iface, iface_idx, ipv4_only ? AF_INET : AF_UNSPEC, NULL, 0); } /* From 670de9b5fb7ef6f538136bdeeb8f0d50aeea3d6c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 02:42:48 -0700 Subject: [PATCH 090/105] ip6: tune RDNSS parsing logging --- src/ip6-manager/nm-ip6-manager.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index cafe9cc430..8066d30639 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -294,6 +294,8 @@ rdnss_expired (gpointer user_data) NMIP6Device *device = user_data; CallbackInfo info = { device, IP6_DHCP_OPT_NONE }; + nm_log_dbg (LOGD_IP6, "(%s): IPv6 RDNSS information expired", device->iface); + set_rdnss_timeout (device); emit_config_changed (&info); return FALSE; @@ -322,6 +324,12 @@ set_rdnss_timeout (NMIP6Device *device) * bit. */ if (rdnss->expires <= now + 1) { + char buf[INET6_ADDRSTRLEN + 1]; + + if (inet_ntop (AF_INET6, &(rdnss->addr), buf, sizeof (buf)) > 0) { + nm_log_dbg (LOGD_IP6, "(%s): removing expired RA-provided nameserver %s", + device->iface, buf); + } g_array_remove_index_fast (device->rdnss_servers, i--); continue; } @@ -651,11 +659,12 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) server.expires = now + ntohl (rdnss_opt->nd_opt_rdnss_lifetime); for (addr = (struct in6_addr *) (rdnss_opt + 1); nd_opt_len >= 2; addr++, nd_opt_len -= 2) { - char buf[INET6_ADDRSTRLEN]; + char buf[INET6_ADDRSTRLEN + 1]; - if (inet_ntop (AF_INET6, &addr, buf, INET6_ADDRSTRLEN) > 0) { - nm_log_dbg (LOGD_IP6, "(%s): found RA-provided nameserver %s", - device->iface, buf); + if (inet_ntop (AF_INET6, addr, buf, sizeof (buf))) { + nm_log_dbg (LOGD_IP6, "(%s): found RA-provided nameserver %s (expires in %d seconds)", + device->iface, buf, + ntohl (rdnss_opt->nd_opt_rdnss_lifetime)); } server.addr = *addr; From c21416e9565b9a1274ca605e7baeee8ce2f6f94f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 02:48:18 -0700 Subject: [PATCH 091/105] ip6: don't prematurely remove RDNSS nameservers (rh #588192) --- src/ip6-manager/nm-ip6-manager.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 8066d30639..1b544a2449 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -693,10 +693,13 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) if (changed) { nm_log_dbg (LOGD_IP6, "(%s): RA-provided nameservers changed", device->iface); - g_array_free (device->rdnss_servers, TRUE); - device->rdnss_servers = servers; - } else - g_array_free (servers, TRUE); + } + + /* Always copy in new servers (even if unchanged) to get their updated + * expiration times. + */ + g_array_free (device->rdnss_servers, TRUE); + device->rdnss_servers = servers; /* Timeouts may have changed even if IPs didn't */ set_rdnss_timeout (device); From 10d6bc8d2ecbe996091b0c224ba14b7fdfe9123f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 03:02:57 -0700 Subject: [PATCH 092/105] ip6: fail if the RA-provided address disappears or RDNSS expires --- src/ip6-manager/nm-ip6-manager.c | 27 ++++++++++++++++++++++----- src/ip6-manager/nm-ip6-manager.h | 3 ++- src/nm-device.c | 8 ++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 1b544a2449..5101faf2a8 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -282,7 +282,10 @@ emit_config_changed (gpointer user_data) NMIP6Manager *manager = device->manager; device->config_changed_id = 0; - g_signal_emit (manager, signals[CONFIG_CHANGED], 0, device->ifindex, info->dhcp_opts); + g_signal_emit (manager, signals[CONFIG_CHANGED], 0, + device->ifindex, + info->dhcp_opts, + info->success); return FALSE; } @@ -386,7 +389,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) struct in6_addr *addr; CallbackInfo *info; guint dhcp_opts = IP6_DHCP_OPT_NONE; - gboolean found_linklocal = FALSE; + gboolean found_linklocal = FALSE, found_other = FALSE; nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')", device->iface, device->ra_flags, @@ -420,6 +423,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) } else { if (device->state < NM_IP6_DEVICE_GOT_ADDRESS) device->state = NM_IP6_DEVICE_GOT_ADDRESS; + found_other = TRUE; } } @@ -473,7 +477,20 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) } } else if (config_changed) { if (!device->config_changed_id) { - info = callback_info_new (device, dhcp_opts, TRUE); + gboolean success = TRUE; + + /* If for some reason an RA-provided address disappeared, we need + * to make sure we fail the connection as it's no longer valid. + */ + if ( (device->state == NM_IP6_DEVICE_GOT_ADDRESS) + && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) + && !found_other) { + nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer valid", + device->iface); + success = FALSE; + } + + info = callback_info_new (device, dhcp_opts, success); device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, emit_config_changed, info, @@ -1141,7 +1158,7 @@ nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed), NULL, NULL, - _nm_marshal_VOID__INT_UINT, - G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT); + _nm_marshal_VOID__INT_UINT_BOOLEAN, + G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN); } diff --git a/src/ip6-manager/nm-ip6-manager.h b/src/ip6-manager/nm-ip6-manager.h index db920662b9..7cd0ef70e6 100644 --- a/src/ip6-manager/nm-ip6-manager.h +++ b/src/ip6-manager/nm-ip6-manager.h @@ -64,7 +64,8 @@ typedef struct { */ void (*config_changed) (NMIP6Manager *manager, guint32 ifindex, - guint dhcp_opts); + guint dhcp_opts, + gboolean success); } NMIP6ManagerClass; GType nm_ip6_manager_get_type (void); diff --git a/src/nm-device.c b/src/nm-device.c index a09a69218f..d8f7b64f02 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -681,6 +681,7 @@ static void ip6_config_changed (NMIP6Manager *ip6_manager, int ifindex, guint dhcp_opts, + gboolean success, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); @@ -692,6 +693,13 @@ ip6_config_changed (NMIP6Manager *ip6_manager, /* FIXME: re-run DHCPv6 here to get any new nameservers or whatever */ + if (!success && (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) { + nm_device_state_changed (self, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return; + } + nm_device_activate_schedule_stage4_ip6_config_get (self); } From 7926b3ca95f2c0c611e271f805437cca9dc004ea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 03:42:43 -0700 Subject: [PATCH 093/105] ip6: turn RA acceptance off when RAs shouldn't be used (rh #588163) Make sure we don't inadvertenly let the kernel assign an RA address when connections that don't allow RA are used. --- src/NetworkManagerUtils.c | 29 ++++++++++++++ src/NetworkManagerUtils.h | 4 ++ src/ip6-manager/nm-ip6-manager.c | 63 ++++-------------------------- src/ip6-manager/nm-ip6-manager.h | 3 +- src/nm-device.c | 66 +++++++++++++++++++++++++++++++- 5 files changed, 107 insertions(+), 58 deletions(-) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 4bd57d9944..fe64e1fea7 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -594,3 +594,32 @@ nm_utils_do_sysctl (const char *path, const char *value) return TRUE; } +gboolean +nm_utils_get_proc_sys_net_value (const char *path, + const char *iface, + guint32 *out_value) +{ + GError *error = NULL; + char *contents = NULL; + gboolean success = FALSE; + long int tmp; + + if (!g_file_get_contents (path, &contents, NULL, &error)) { + nm_log_warn (LOGD_DEVICE, "(%s): error reading %s: (%d) %s", + iface, path, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_clear_error (&error); + } else { + errno = 0; + tmp = strtol (contents, NULL, 10); + if ((errno == 0) && (tmp == 0 || tmp == 1)) { + *out_value = (guint32) tmp; + success = TRUE; + } + g_free (contents); + } + + return success; +} + diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index fa8b598db2..e3d1793b4d 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -73,4 +73,8 @@ void value_hash_add_bool (GHashTable *hash, gboolean nm_utils_do_sysctl (const char *path, const char *value); +gboolean nm_utils_get_proc_sys_net_value (const char *path, + const char *iface, + guint32 *out_value); + #endif /* NETWORK_MANAGER_UTILS_H */ diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 5101faf2a8..333638adb3 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -83,10 +83,6 @@ typedef struct { char *iface; int ifindex; - char *accept_ra_path; - gboolean accept_ra_save_valid; - guint32 accept_ra_save; - char *disable_ip6_path; gboolean disable_ip6_save_valid; guint32 disable_ip6_save; @@ -111,12 +107,6 @@ nm_ip6_device_destroy (NMIP6Device *device) { g_return_if_fail (device != NULL); - /* reset the saved RA value */ - if (device->accept_ra_save_valid) { - nm_utils_do_sysctl (device->accept_ra_path, - device->accept_ra_save ? "1\n" : "0\n"); - } - /* reset the saved IPv6 value */ if (device->disable_ip6_save_valid) { nm_utils_do_sysctl (device->disable_ip6_path, @@ -135,37 +125,9 @@ nm_ip6_device_destroy (NMIP6Device *device) if (device->ip6flags_poll_id) g_source_remove (device->ip6flags_poll_id); - g_free (device->accept_ra_path); g_slice_free (NMIP6Device, device); } -static gboolean -get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value) -{ - GError *error = NULL; - char *contents = NULL; - gboolean success = FALSE; - long int tmp; - - if (!g_file_get_contents (path, &contents, NULL, &error)) { - nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s", - iface, path, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } else { - errno = 0; - tmp = strtol (contents, NULL, 10); - if ((errno == 0) && (tmp == 0 || tmp == 1)) { - *out_value = (guint32) tmp; - success = TRUE; - } - g_free (contents); - } - - return success; -} - static NMIP6Device * nm_ip6_device_new (NMIP6Manager *manager, int ifindex) { @@ -195,23 +157,13 @@ nm_ip6_device_new (NMIP6Manager *manager, int ifindex) g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device); - /* Grab the original value of "accept_ra" so we can restore it when the - * device is taken down. - */ - device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", - device->iface); - g_assert (device->accept_ra_path); - device->accept_ra_save_valid = get_proc_sys_net_value (device->accept_ra_path, - device->iface, - &device->accept_ra_save); - /* and the original value of IPv6 enable/disable */ device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6", device->iface); g_assert (device->disable_ip6_path); - device->disable_ip6_save_valid = get_proc_sys_net_value (device->disable_ip6_path, - device->iface, - &device->disable_ip6_save); + device->disable_ip6_save_valid = nm_utils_get_proc_sys_net_value (device->disable_ip6_path, + device->iface, + &device->disable_ip6_save); return device; @@ -835,8 +787,9 @@ netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer us void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, - int ifindex, - NMSettingIP6Config *s_ip6) + int ifindex, + NMSettingIP6Config *s_ip6, + const char *accept_ra_path) { NMIP6ManagerPrivate *priv; NMIP6Device *device; @@ -861,10 +814,10 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager, /* Establish target state and turn router advertisement acceptance on or off */ if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL; - nm_utils_do_sysctl (device->accept_ra_path, "0\n"); + nm_utils_do_sysctl (accept_ra_path, "0\n"); } else { device->target_state = NM_IP6_DEVICE_GOT_ADDRESS; - nm_utils_do_sysctl (device->accept_ra_path, "1\n"); + nm_utils_do_sysctl (accept_ra_path, "1\n"); } } diff --git a/src/ip6-manager/nm-ip6-manager.h b/src/ip6-manager/nm-ip6-manager.h index 7cd0ef70e6..77c1106841 100644 --- a/src/ip6-manager/nm-ip6-manager.h +++ b/src/ip6-manager/nm-ip6-manager.h @@ -73,7 +73,8 @@ GType nm_ip6_manager_get_type (void); NMIP6Manager *nm_ip6_manager_get (void); void nm_ip6_manager_prepare_interface (NMIP6Manager *manager, int ifindex, - NMSettingIP6Config *s_ip6); + NMSettingIP6Config *s_ip6, + const char *accept_ra_path); void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex); void nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, diff --git a/src/nm-device.c b/src/nm-device.c index d8f7b64f02..88c57ba75b 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -135,6 +135,9 @@ typedef struct { gulong ip6_config_changed_sigid; gboolean ip6_waiting_for_config; + char * ip6_accept_ra_path; + guint32 ip6_accept_ra_save; + NMDHCPClient * dhcp6_client; guint32 dhcp6_mode; gulong dhcp6_state_sigid; @@ -207,6 +210,41 @@ nm_device_init (NMDevice *self) priv->rfkill_type = RFKILL_TYPE_UNKNOWN; } +static void +update_accept_ra_save (NMDevice *self) +{ + NMDevicePrivate *priv; + const char *ip_iface; + char *new_path; + + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + ip_iface = nm_device_get_ip_iface (self); + + new_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", ip_iface); + g_assert (new_path); + + if (priv->ip6_accept_ra_path) { + /* If the IP iface is different from before, use the new value */ + if (!strcmp (new_path, priv->ip6_accept_ra_path)) { + g_free (new_path); + return; + } + g_free (priv->ip6_accept_ra_path); + } + + /* Grab the original value of "accept_ra" so we can restore it when NM exits */ + priv->ip6_accept_ra_path = new_path; + if (!nm_utils_get_proc_sys_net_value (priv->ip6_accept_ra_path, + ip_iface, + &priv->ip6_accept_ra_save)) { + g_free (priv->ip6_accept_ra_path); + priv->ip6_accept_ra_path = NULL; + } +} + static GObject* constructor (GType type, guint n_construct_params, @@ -246,6 +284,8 @@ constructor (GType type, priv->dhcp_manager = nm_dhcp_manager_get (); + update_accept_ra_save (dev); + priv->initialized = TRUE; return object; @@ -744,7 +784,8 @@ addrconf6_setup (NMDevice *self) s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); nm_ip6_manager_prepare_interface (priv->ip6_manager, nm_device_get_ip_ifindex (self), - s_ip6); + s_ip6, + priv->ip6_accept_ra_path); priv->ip6_waiting_for_config = TRUE; return TRUE; @@ -1589,6 +1630,8 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) ip_iface = nm_device_get_ip_iface (self); + update_accept_ra_save (self); + priv->dhcp6_mode = IP6_DHCP_OPT_NONE; if ( ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO) @@ -1600,13 +1643,21 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self)); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + /* Router advertisements shouldn't be used in pure DHCP mode */ + if (priv->ip6_accept_ra_path) + nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n"); + priv->dhcp6_mode = IP6_DHCP_OPT_MANAGED; ret = dhcp6_start (self, connection, priv->dhcp6_mode, reason); } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { priv->ip6_ready = TRUE; ret = NM_ACT_STAGE_RETURN_STOP; - } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + } else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { + /* Router advertisements shouldn't be used in manual mode */ + if (priv->ip6_accept_ra_path) + nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n"); ret = NM_ACT_STAGE_RETURN_SUCCESS; + } /* Other methods (shared) aren't implemented yet */ @@ -2676,6 +2727,10 @@ nm_device_deactivate_quickly (NMDevice *self) dnsmasq_cleanup (self); aipd_cleanup (self); + /* Turn off router advertisements until they are needed */ + if (priv->ip6_accept_ra_path) + nm_utils_do_sysctl (priv->ip6_accept_ra_path, "0\n"); + /* Call device type-specific deactivation */ if (NM_DEVICE_GET_CLASS (self)->deactivate_quickly) NM_DEVICE_GET_CLASS (self)->deactivate_quickly (self); @@ -3247,6 +3302,13 @@ dispose (GObject *object) addrconf6_cleanup (self); dnsmasq_cleanup (self); + /* reset the saved RA value */ + if (priv->ip6_accept_ra_path) { + nm_utils_do_sysctl (priv->ip6_accept_ra_path, + priv->ip6_accept_ra_save ? "1\n" : "0\n"); + } + g_free (priv->ip6_accept_ra_path); + /* Take the device itself down and clear its IPv4 configuration */ if (priv->managed && take_down) { NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; From 0ab71998cefd8bcf0c93d45d0f642e596c7ed00c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 04:12:18 -0700 Subject: [PATCH 094/105] ifcfg-rh: test implicit may-fail configuration --- .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 7ca0ecf87c..35cea36cf5 100644 --- a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -560,6 +560,13 @@ test_read_wired_static (const char *file, const char *expected_id) NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_METHOD); + /* Implicit may-fail */ + ASSERT (nm_setting_ip4_config_get_may_fail (s_ip4) == FALSE, + "wired-static-verify-ip6", "failed to verify %s: unexpected %s / %s key value", + file, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_MAY_FAIL); + /* DNS Addresses */ ASSERT (nm_setting_ip4_config_get_num_dns (s_ip4) == 2, "wired-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value", @@ -648,6 +655,13 @@ test_read_wired_static (const char *file, const char *expected_id) NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_METHOD); + /* Implicit may-fail */ + ASSERT (nm_setting_ip6_config_get_may_fail (s_ip6) == TRUE, + "wired-static-verify-ip6", "failed to verify %s: unexpected %s / %s key value", + file, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_MAY_FAIL); + /* DNS Addresses */ ASSERT (nm_setting_ip6_config_get_num_dns (s_ip6) == 2, "wired-static-verify-ip6", "failed to verify %s: unexpected %s / %s key value", From 719738d1335b8c41ebcd20b8eec11804beb70e43 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 04:53:13 -0700 Subject: [PATCH 095/105] keyfile: fix for IPv6 address gateways --- system-settings/plugins/keyfile/io/reader.c | 44 ++- system-settings/plugins/keyfile/io/writer.c | 34 ++- .../keyfile/tests/keyfiles/Makefile.am | 3 +- .../tests/keyfiles/Test_Wired_Connection_IP6 | 20 ++ .../plugins/keyfile/tests/test-keyfile.c | 277 +++++++++++++++++- 5 files changed, 362 insertions(+), 16 deletions(-) create mode 100644 system-settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection_IP6 diff --git a/system-settings/plugins/keyfile/io/reader.c b/system-settings/plugins/keyfile/io/reader.c index 3a4ec42e84..a71c05c577 100644 --- a/system-settings/plugins/keyfile/io/reader.c +++ b/system-settings/plugins/keyfile/io/reader.c @@ -337,13 +337,30 @@ split_prefix (char *addr) return slash; } +static char * +split_gw (char *str) +{ + char *comma; + + g_return_val_if_fail (str != NULL, NULL); + + /* Find the prefix and split the string */ + comma = strchr (str, ','); + if (comma && comma > str) { + comma++; + *(comma - 1) = '\0'; + return comma; + } + return NULL; +} + static GPtrArray * read_ip6_addresses (GKeyFile *file, const char *setting_name, const char *key) { GPtrArray *addresses; - struct in6_addr addr; + struct in6_addr addr, gw; guint32 prefix; int i = 0; @@ -351,10 +368,11 @@ read_ip6_addresses (GKeyFile *file, /* Look for individual addresses */ while (i++ < 1000) { - char *tmp, *key_name, *str_prefix; + char *tmp, *key_name, *str_prefix, *str_gw; int ret; GValueArray *values; GByteArray *address; + GByteArray *gateway; GValue value = { 0 }; key_name = g_strdup_printf ("%s%d", key, i); @@ -377,6 +395,7 @@ read_ip6_addresses (GKeyFile *file, g_value_array_free (values); goto next; } + address = g_byte_array_new (); g_byte_array_append (address, (guint8 *) addr.s6_addr, 16); g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); @@ -401,6 +420,26 @@ read_ip6_addresses (GKeyFile *file, g_value_array_append (values, &value); g_value_unset (&value); + /* Gateway (optional) */ + str_gw = split_gw (str_prefix); + if (str_gw) { + ret = inet_pton (AF_INET6, str_gw, &gw); + if (ret <= 0) { + g_warning ("%s: ignoring invalid IPv6 %s gateway '%s'", __func__, key_name, tmp); + g_value_array_free (values); + goto next; + } + + if (!IN6_IS_ADDR_UNSPECIFIED (&gw)) { + gateway = g_byte_array_new (); + g_byte_array_append (gateway, (guint8 *) gw.s6_addr, 16); + g_value_init (&value, DBUS_TYPE_G_UCHAR_ARRAY); + g_value_take_boxed (&value, gateway); + g_value_array_append (values, &value); + g_value_unset (&value); + } + } + g_ptr_array_add (addresses, values); next: @@ -422,7 +461,6 @@ ip6_addr_parser (NMSetting *setting, const char *key, GKeyFile *keyfile) const char *setting_name = nm_setting_get_name (setting); addresses = read_ip6_addresses (keyfile, setting_name, key); - if (addresses) { g_object_set (setting, key, addresses, NULL); g_ptr_array_foreach (addresses, free_one_ip6_address, NULL); diff --git a/system-settings/plugins/keyfile/io/writer.c b/system-settings/plugins/keyfile/io/writer.c index 2e194072e3..355d624c19 100644 --- a/system-settings/plugins/keyfile/io/writer.c +++ b/system-settings/plugins/keyfile/io/writer.c @@ -226,18 +226,27 @@ ip6_dns_writer (GKeyFile *file, } static gboolean -ip6_array_to_addr (GValueArray *values, guint32 idx, char *buf, size_t buflen) +ip6_array_to_addr (GValueArray *values, + guint32 idx, + char *buf, + size_t buflen, + gboolean *out_is_unspec) { GByteArray *byte_array; GValue *addr_val; + struct in6_addr *addr; g_return_val_if_fail (buflen >= INET6_ADDRSTRLEN, FALSE); - /* address */ addr_val = g_value_array_get_nth (values, idx); byte_array = g_value_get_boxed (addr_val); + addr = (struct in6_addr *) byte_array->data; + + if (out_is_unspec && IN6_IS_ADDR_UNSPECIFIED (addr)) + *out_is_unspec = TRUE; + errno = 0; - if (!inet_ntop (AF_INET6, (struct in6_addr *) byte_array->data, buf, buflen)) { + if (!inet_ntop (AF_INET6, addr, buf, buflen)) { GString *ip6_str = g_string_sized_new (INET6_ADDRSTRLEN + 10); /* error converting the address */ @@ -259,18 +268,24 @@ ip6_array_to_addr_prefix (GValueArray *values) GValue *prefix_val; char *ret = NULL; GString *ip6_str; - char buf[INET6_ADDRSTRLEN]; + char buf[INET6_ADDRSTRLEN + 1]; + gboolean is_unspec = FALSE; /* address */ - if (ip6_array_to_addr (values, 0, buf, sizeof (buf))) { + if (ip6_array_to_addr (values, 0, buf, sizeof (buf), NULL)) { /* Enough space for the address, '/', and the prefix */ - ip6_str = g_string_sized_new (INET6_ADDRSTRLEN + 5); + ip6_str = g_string_sized_new ((INET6_ADDRSTRLEN * 2) + 5); /* prefix */ g_string_append (ip6_str, buf); prefix_val = g_value_array_get_nth (values, 1); g_string_append_printf (ip6_str, "/%u", g_value_get_uint (prefix_val)); + if (ip6_array_to_addr (values, 2, buf, sizeof (buf), &is_unspec)) { + if (!is_unspec) + g_string_append_printf (ip6_str, ",%s", buf); + } + ret = ip6_str->str; g_string_free (ip6_str, FALSE); } @@ -337,7 +352,8 @@ ip6_route_writer (GKeyFile *file, GValueArray *values = g_ptr_array_index (array, i); char *key_name; guint32 int_val; - char buf[INET6_ADDRSTRLEN]; + char buf[INET6_ADDRSTRLEN + 1]; + gboolean is_unspec = FALSE; memset (list, 0, sizeof (list)); @@ -347,7 +363,9 @@ ip6_route_writer (GKeyFile *file, continue; /* Next Hop */ - if (!ip6_array_to_addr (values, 2, buf, sizeof (buf))) + if (!ip6_array_to_addr (values, 2, buf, sizeof (buf), &is_unspec)) + continue; + if (is_unspec) continue; list[1] = g_strdup (buf); diff --git a/system-settings/plugins/keyfile/tests/keyfiles/Makefile.am b/system-settings/plugins/keyfile/tests/keyfiles/Makefile.am index a4ba7bf01d..bf5a5ab060 100644 --- a/system-settings/plugins/keyfile/tests/keyfiles/Makefile.am +++ b/system-settings/plugins/keyfile/tests/keyfiles/Makefile.am @@ -2,7 +2,8 @@ EXTRA_DIST = \ Test_Wired_Connection \ Test_GSM_Connection \ Test_Wireless_Connection \ - Test_Wired_Connection_MAC_Case + Test_Wired_Connection_MAC_Case \ + Test_Wired_Connection_IP6 check-local: @for f in $(EXTRA_DIST); do \ diff --git a/system-settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection_IP6 b/system-settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection_IP6 new file mode 100644 index 0000000000..a42dd5d2a5 --- /dev/null +++ b/system-settings/plugins/keyfile/tests/keyfiles/Test_Wired_Connection_IP6 @@ -0,0 +1,20 @@ + +[connection] +id=Test Wired Connection IP6 +uuid=4e80a56d-c99f-4aad-a6dd-b449bc398c57 +type=802-3-ethernet +autoconnect=true +timestamp=6654332 + +[802-3-ethernet] +auto-negotiate=true +mtu=1400 + +[ipv4] +method=disabled + +[ipv6] +method=manual +addresses1=abcd:1234:ffff::cdde/64,abcd:1234:ffff::cdd1 +dns=1111:dddd::aaaa;1::cafe; + diff --git a/system-settings/plugins/keyfile/tests/test-keyfile.c b/system-settings/plugins/keyfile/tests/test-keyfile.c index 29fe19d2fd..aae823642b 100644 --- a/system-settings/plugins/keyfile/tests/test-keyfile.c +++ b/system-settings/plugins/keyfile/tests/test-keyfile.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2010 Red Hat, Inc. */ #include @@ -510,7 +510,8 @@ add_one_ip4_route (NMSettingIP4Config *s_ip4, static void add_one_ip6_address (NMSettingIP6Config *s_ip6, const char *addr, - guint32 prefix) + guint32 prefix, + const char *gw) { struct in6_addr tmp; NMIP6Address *ip6_addr; @@ -521,6 +522,11 @@ add_one_ip6_address (NMSettingIP6Config *s_ip6, inet_pton (AF_INET6, addr, &tmp); nm_ip6_address_set_address (ip6_addr, &tmp); + if (gw) { + inet_pton (AF_INET6, gw, &tmp); + nm_ip6_address_set_gateway (ip6_addr, &tmp); + } + nm_setting_ip6_config_add_address (s_ip6, ip6_addr); nm_ip6_address_unref (ip6_addr); } @@ -666,8 +672,8 @@ test_write_wired_connection (void) NULL); /* Addresses */ - add_one_ip6_address (s_ip6, address6_1, 64); - add_one_ip6_address (s_ip6, address6_2, 56); + add_one_ip6_address (s_ip6, address6_1, 64, NULL); + add_one_ip6_address (s_ip6, address6_2, 56, NULL); /* Routes */ add_one_ip6_route (s_ip6, route6_1, route6_1_nh, 64, 3); @@ -708,6 +714,266 @@ test_write_wired_connection (void) g_object_unref (connection); } +#define TEST_WIRED_IP6_FILE TEST_KEYFILES_DIR"/Test_Wired_Connection_IP6" + +static void +test_read_ip6_wired_connection (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + GError *error = NULL; + const char *tmp; + const char *expected_id = "Test Wired Connection IP6"; + const char *expected_uuid = "4e80a56d-c99f-4aad-a6dd-b449bc398c57"; + struct in6_addr addr6; + const char *expected6_address1 = "abcd:1234:ffff::cdde"; + const char *expected6_gw1 = "abcd:1234:ffff::cdd1"; + NMIP6Address *ip6_addr; + + connection = connection_from_file (TEST_WIRED_IP6_FILE); + ASSERT (connection != NULL, + "connection-read", "failed to read %s", TEST_WIRED_IP6_FILE); + + ASSERT (nm_connection_verify (connection, &error), + "connection-verify", "failed to verify %s: %s", TEST_WIRED_IP6_FILE, error->message); + + /* ===== CONNECTION SETTING ===== */ + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + ASSERT (s_con != NULL, + "connection-verify-connection", "failed to verify %s: missing %s setting", + TEST_WIRED_IP6_FILE, + NM_SETTING_CONNECTION_SETTING_NAME); + + /* ID */ + tmp = nm_setting_connection_get_id (s_con); + ASSERT (tmp != NULL, + "connection-verify-connection", "failed to verify %s: missing %s / %s key", + TEST_WIRED_IP6_FILE, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + ASSERT (strcmp (tmp, expected_id) == 0, + "connection-verify-connection", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_IP6_FILE, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + + /* UUID */ + tmp = nm_setting_connection_get_uuid (s_con); + ASSERT (tmp != NULL, + "connection-verify-connection", "failed to verify %s: missing %s / %s key", + TEST_WIRED_IP6_FILE, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_UUID); + ASSERT (strcmp (tmp, expected_uuid) == 0, + "connection-verify-connection", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_IP6_FILE, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_UUID); + + /* ===== WIRED SETTING ===== */ + + s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED)); + ASSERT (s_wired != NULL, + "connection-verify-wired", "failed to verify %s: missing %s setting", + TEST_WIRED_IP6_FILE, + NM_SETTING_WIRED_SETTING_NAME); + + /* ===== IPv4 SETTING ===== */ + + s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG)); + ASSERT (s_ip4 != NULL, + "connection-verify-ip4", "failed to verify %s: missing %s setting", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP4_CONFIG_SETTING_NAME); + + /* Method */ + tmp = nm_setting_ip4_config_get_method (s_ip4); + ASSERT (strcmp (tmp, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0, + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_METHOD); + + ASSERT (nm_setting_ip4_config_get_num_addresses (s_ip4) == 0, + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + /* ===== IPv6 SETTING ===== */ + + s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG)); + ASSERT (s_ip6 != NULL, + "connection-verify-ip6", "failed to verify %s: missing %s setting", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME); + + /* Method */ + tmp = nm_setting_ip6_config_get_method (s_ip6); + ASSERT (strcmp (tmp, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) == 0, + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_METHOD); + + ASSERT (nm_setting_ip6_config_get_num_addresses (s_ip6) == 1, + "connection-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_DNS); + + /* Address #1 */ + ip6_addr = nm_setting_ip6_config_get_address (s_ip6, 0); + ASSERT (ip6_addr, + "connection-verify-wired", "failed to verify %s: missing IP6 address #1", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + ASSERT (nm_ip6_address_get_prefix (ip6_addr) == 64, + "connection-verify-wired", "failed to verify %s: unexpected IP6 address #1 prefix", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + ASSERT (inet_pton (AF_INET6, expected6_address1, &addr6) > 0, + "connection-verify-wired", "failed to verify %s: couldn't convert IP address #1", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_address (ip6_addr), &addr6), + "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + ASSERT (inet_pton (AF_INET6, expected6_gw1, &addr6) > 0, + "connection-verify-wired", "failed to verify %s: couldn't convert GW address #1", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + ASSERT (IN6_ARE_ADDR_EQUAL (nm_ip6_address_get_gateway (ip6_addr), &addr6), + "connection-verify-wired", "failed to verify %s: unexpected IP4 address #1", + TEST_WIRED_IP6_FILE, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_ADDRESSES); + + g_object_unref (connection); +} + +static void +test_write_ip6_wired_connection (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIP4Config *s_ip4; + NMSettingIP6Config *s_ip6; + char *uuid; + gboolean success; + NMConnection *reread; + char *testfile = NULL; + GError *error = NULL; + pid_t owner_grp; + uid_t owner_uid; + struct in6_addr addr6; + const char *dns = "1::cafe"; + const char *address = "abcd::beef"; + const char *gw = "dcba::beef"; + + connection = nm_connection_new (); + ASSERT (connection != NULL, + "connection-write", "failed to allocate new connection"); + + /* Connection setting */ + + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + ASSERT (s_con != NULL, + "connection-write", "failed to allocate new %s setting", + NM_SETTING_CONNECTION_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Work Wired IP6", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NULL); + g_free (uuid); + + /* Wired setting */ + + s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); + ASSERT (s_wired != NULL, + "connection-write", "failed to allocate new %s setting", + NM_SETTING_WIRED_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + /* IP4 setting */ + + s_ip4 = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ()); + ASSERT (s_ip4 != NULL, + "connection-write", "failed to allocate new %s setting", + NM_SETTING_IP4_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, + NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + + /* IP6 setting */ + + s_ip6 = NM_SETTING_IP6_CONFIG (nm_setting_ip6_config_new ()); + ASSERT (s_ip6 != NULL, + "connection-write", "failed to allocate new %s setting", + NM_SETTING_IP6_CONFIG_SETTING_NAME); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, + NULL); + + /* Addresses */ + add_one_ip6_address (s_ip6, address, 64, gw); + + /* DNS servers */ + inet_pton (AF_INET6, dns, &addr6); + nm_setting_ip6_config_add_dns (s_ip6, &addr6); + + /* DNS searches */ + nm_setting_ip6_config_add_dns_search (s_ip6, "wallaceandgromit.com"); + + /* Write out the connection */ + owner_uid = geteuid (); + owner_grp = getegid (); + success = write_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); + ASSERT (success == TRUE, + "connection-write", "failed to allocate write keyfile: %s", + error ? error->message : "(none)"); + + ASSERT (testfile != NULL, + "connection-write", "didn't get keyfile name back after writing connection"); + + /* Read the connection back in and compare it to the one we just wrote out */ + reread = connection_from_file (testfile); + ASSERT (reread != NULL, "connection-write", "failed to re-read test connection"); + + ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE, + "connection-write", "written and re-read connection weren't the same"); + + g_clear_error (&error); + unlink (testfile); + g_free (testfile); + + g_object_unref (reread); + g_object_unref (connection); +} + #define TEST_WIRED_MAC_CASE_FILE TEST_KEYFILES_DIR"/Test_Wired_Connection_MAC_Case" static void @@ -1042,6 +1308,9 @@ int main (int argc, char **argv) test_read_valid_wired_connection (); test_write_wired_connection (); + test_read_ip6_wired_connection (); + test_write_ip6_wired_connection (); + test_read_wired_mac_case (); test_read_valid_wireless_connection (); From e1eee774971b99c9281ede14f0a3034b63ea69a6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 May 2010 20:34:22 -0700 Subject: [PATCH 096/105] hostname: return NULL from failed hostname lookup, not zero-length string --- src/nm-policy-hostname.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/nm-policy-hostname.c b/src/nm-policy-hostname.c index 02eb560263..a273a9202f 100644 --- a/src/nm-policy-hostname.c +++ b/src/nm-policy-hostname.c @@ -51,8 +51,12 @@ static gboolean hostname_thread_run_cb (gpointer user_data) { HostnameThread *ht = (HostnameThread *) user_data; + const char *hostname = NULL; - (*ht->callback) (ht, ht->ret, ht->hostname, ht->user_data); + if (strlen (ht->hostname)) + hostname = ht->hostname; + + (*ht->callback) (ht, ht->ret, hostname, ht->user_data); return FALSE; } @@ -148,9 +152,14 @@ nm_policy_set_system_hostname (const char *new_hostname, const char *msg) { char old_hostname[HOST_NAME_MAX + 1]; int ret = 0; - const char *name = new_hostname ? new_hostname : FALLBACK_HOSTNAME; + const char *name; gboolean set_hostname = TRUE, changed = FALSE; + if (new_hostname) + g_warn_if_fail (strlen (new_hostname)); + + name = (new_hostname && strlen (new_hostname)) ? new_hostname : FALLBACK_HOSTNAME; + old_hostname[HOST_NAME_MAX] = '\0'; errno = 0; ret = gethostname (old_hostname, HOST_NAME_MAX); From e99ad944111026abc8b29a379e5aaaceec9f608c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 10:04:55 -0700 Subject: [PATCH 097/105] api: fix SetLogging description typo --- introspection/nm-manager.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/introspection/nm-manager.xml b/introspection/nm-manager.xml index 406b5cfd1e..3adbd9cb2b 100644 --- a/introspection/nm-manager.xml +++ b/introspection/nm-manager.xml @@ -110,7 +110,7 @@ A combination of logging domains separated by commas (','), or "NONE" to disable logging. Each domain enables logging for operations - related to that domain. Available domains are: [NONE, HW, RKILL, + related to that domain. Available domains are: [NONE, HW, RFKILL, ETHER, WIFI, BT, MB, DHCP4, DHCP6, PPP, WIFI_SCAN, IP4, IP6, AUTOIP4, DNS, VPN, SHARING, SUPPLICANT, USER_SET, SYS_SET, SUSPEND, CORE, DEVICE, OLPC] From defaee09e5a95d00bcd3c3cafd107bfc40cd59f8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 12:06:00 -0700 Subject: [PATCH 098/105] logging: correctly print new logging level and domains on changes Previously the input would simply be printed, but if you're not changing either the level or domains (ie sending "") then the unchanged logging domains wouldn't be printed, only "". --- src/logging/nm-logging.c | 30 ++++++++++++++++++++++++++++++ src/logging/nm-logging.h | 3 +++ src/nm-manager.c | 7 ++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c index ac30eb42c6..c82084456b 100644 --- a/src/logging/nm-logging.c +++ b/src/logging/nm-logging.c @@ -179,6 +179,36 @@ nm_logging_setup (const char *level, const char *domains, GError **error) return TRUE; } +const char * +nm_logging_level_to_string (void) +{ + const LogDesc *diter; + + for (diter = &level_descs[0]; diter->name; diter++) { + if (diter->num == log_level) + return diter->name; + } + g_warn_if_reached (); + return ""; +} + +char * +nm_logging_domains_to_string (void) +{ + const LogDesc *diter; + GString *str; + + str = g_string_sized_new (75); + for (diter = &domain_descs[0]; diter->name; diter++) { + if (diter->num & log_domains) { + if (str->len) + g_string_append_c (str, ','); + g_string_append (str, diter->name); + } + } + return g_string_free (str, FALSE); +} + void _nm_log (const char *loc, const char *func, guint32 domain, diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h index 2dc52d1e53..2eedf5ff14 100644 --- a/src/logging/nm-logging.h +++ b/src/logging/nm-logging.h @@ -88,6 +88,9 @@ void _nm_log (const char *loc, const char *func, guint32 domain, guint32 level, const char *fmt, ...); +const char *nm_logging_level_to_string (void); +char *nm_logging_domains_to_string (void); + /* Undefine the nm-utils.h logging stuff to ensure errors */ #undef nm_print_backtrace #undef nm_get_timestamp diff --git a/src/nm-manager.c b/src/nm-manager.c index abe505bba5..f158e50982 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2774,7 +2774,12 @@ impl_manager_set_logging (NMManager *manager, GError **error) { if (nm_logging_setup (level, domains, error)) { - nm_log_info (LOGD_CORE, "logging: level '%s' domains '%s'", level, domains); + char *new_domains = nm_logging_domains_to_string (); + + nm_log_info (LOGD_CORE, "logging: level '%s' domains '%s'", + nm_logging_level_to_string (), + new_domains); + g_free (new_domains); return TRUE; } return FALSE; From 291211ac2ba6a99c8d5a09a6ec1f91f4bc0f0a30 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 12:07:57 -0700 Subject: [PATCH 099/105] dbus: ensure only root can change debug levels --- src/NetworkManager.conf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/NetworkManager.conf b/src/NetworkManager.conf index 87814bec2a..8d08314002 100644 --- a/src/NetworkManager.conf +++ b/src/NetworkManager.conf @@ -56,6 +56,10 @@ + + @@ -64,6 +68,10 @@ + + From 46c5a48ff2d46f60f1cf71ca55408e1aab4211b7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 12:45:36 -0700 Subject: [PATCH 100/105] ip6: use IN6_ARE_ADDR_EQUAL not memcmp --- src/ip6-manager/nm-ip6-manager.c | 10 +++++----- src/nm-ip6-config.c | 7 +++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c index 333638adb3..be22e6465b 100644 --- a/src/ip6-manager/nm-ip6-manager.c +++ b/src/ip6-manager/nm-ip6-manager.c @@ -652,7 +652,7 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg) for (i = 0; i < servers->len; i++) { sa = &(g_array_index (servers, NMIP6RDNSS, i)); sb = &(g_array_index (device->rdnss_servers, NMIP6RDNSS, i)); - if (memcmp (&sa->addr, &sb->addr, sizeof (struct in6_addr)) != 0) { + if (IN6_ARE_ADDR_EQUAL (&sa->addr, &sb->addr) == FALSE) { changed = TRUE; break; } @@ -965,11 +965,11 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex) continue; } - /* Also ignore routes where the destination and gateway are the same, - * which apparently get added by the kernel but return -EINVAL when - * we try to add them via netlink. + /* Also ignore link-local routes where the destination and gateway are + * the same, which apparently get added by the kernel but return -EINVAL + * when we try to add them via netlink. */ - if (gateway && !memcmp (dest, gateway, sizeof (struct in6_addr))) + if (gateway && IN6_ARE_ADDR_EQUAL (dest, gateway)) continue; ip6route = nm_ip6_route_new (); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 89b8c1a665..2fea38f331 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -203,9 +203,8 @@ void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *n /* No dupes */ nameservers = (struct in6_addr *)priv->nameservers->data; - for (i = 0; i < priv->nameservers->len; i++) { - g_return_if_fail (memcmp (nameserver, &nameservers[i], sizeof (struct in6_addr)) != 0); - } + for (i = 0; i < priv->nameservers->len; i++) + g_return_if_fail (IN6_ARE_ADDR_EQUAL (nameserver, &nameservers[i]) == FALSE); g_array_append_val (priv->nameservers, *nameserver); } @@ -572,7 +571,7 @@ addr_array_compare (GArray *a, GArray *b) addrs_b = (struct in6_addr *)b->data; for (i = 0; i < a->len; i++) { for (j = 0, found = FALSE; j < b->len; j++) { - if (memcmp (&addrs_a[i], &addrs_b[j], sizeof (struct in6_addr)) == 0) { + if (IN6_ARE_ADDR_EQUAL (&addrs_a[i], &addrs_b[j])) { found = TRUE; break; } From 79df93ce334b4ff376880cad82233de4589b4a3d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 15:03:59 -0700 Subject: [PATCH 101/105] logging: log PID with syslog messages --- src/logging/nm-logging.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c index c82084456b..9d1905da08 100644 --- a/src/logging/nm-logging.c +++ b/src/logging/nm-logging.c @@ -360,9 +360,9 @@ void nm_logging_start (gboolean become_daemon) { if (become_daemon) - openlog (G_LOG_DOMAIN, 0, LOG_DAEMON); + openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON); else - openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_USER); + openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER); g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, From d9cca4978427ce728a061da1f5b3c157cc40585b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 16:12:52 -0700 Subject: [PATCH 102/105] logging: silence ignorable warning Since the NMDevice's interface isn't always the same as a kernel interface name, we won't always have an entry in /proc/sys/net for it. --- src/NetworkManagerUtils.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index fe64e1fea7..22cf2fa0d8 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -605,10 +605,10 @@ nm_utils_get_proc_sys_net_value (const char *path, long int tmp; if (!g_file_get_contents (path, &contents, NULL, &error)) { - nm_log_warn (LOGD_DEVICE, "(%s): error reading %s: (%d) %s", - iface, path, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); + nm_log_dbg (LOGD_DEVICE, "(%s): error reading %s: (%d) %s", + iface, path, + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); g_clear_error (&error); } else { errno = 0; From ad1017974b68ed107caab8357c41043a0e56f1e7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 16:14:29 -0700 Subject: [PATCH 103/105] core: treat missing IPv6 setting as "ignore" (rh #588814) Caused IPv6 configuration to fail the device even if IPv6 was supposed to be disabled/ignored. --- src/nm-device.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/nm-device.c b/src/nm-device.c index 88c57ba75b..f2bbfc0b63 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -750,8 +750,14 @@ ip6_method_matches (NMConnection *connection, const char *match) const char *method = NULL; s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); - if (s_ip6) + if (s_ip6) { method = nm_setting_ip6_config_get_method (s_ip6); + g_assert (method); + } + + /* Treat missing IP6 setting as IGNORE */ + if (!s_ip6 && !strcmp (match, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) + return TRUE; return method && !strcmp (method, match); } From 1c5236029c255afc6454cc3b8c779482af2244f7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 20:23:09 -0700 Subject: [PATCH 104/105] core: pass ifindex and address family when flushing routes Use the interfaces kernel index when we can to avoid unecessary iface->index lookups; and let callers figure out which address family they really want to flush. --- src/modem-manager/nm-modem.c | 3 ++- src/nm-device.c | 2 +- src/nm-system.c | 36 +++++++++++++++++------------ src/nm-system.h | 4 ++-- src/vpn-manager/nm-vpn-connection.c | 3 ++- 5 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c index d9413edf28..e07b818bbb 100644 --- a/src/modem-manager/nm-modem.c +++ b/src/modem-manager/nm-modem.c @@ -661,7 +661,8 @@ real_deactivate_quickly (NMModem *self, NMDevice *device) case MM_MODEM_IP_METHOD_STATIC: case MM_MODEM_IP_METHOD_DHCP: iface = nm_device_get_ip_iface (device); - nm_system_device_flush_routes_with_iface (iface); + /* FIXME: use AF_UNSPEC here when we have IPv6 support */ + nm_system_device_flush_routes_with_iface (iface, AF_INET); nm_system_device_flush_addresses_with_iface (iface); nm_system_device_set_up_down_with_iface (iface, FALSE, NULL); break; diff --git a/src/nm-device.c b/src/nm-device.c index f2bbfc0b63..30429030ac 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -2767,7 +2767,7 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason) nm_device_deactivate_quickly (self); /* Take out any entries in the routing table and any IP address the device had. */ - nm_system_device_flush_routes (self); + nm_system_device_flush_routes (self, nm_device_get_ip6_config (self) ? AF_UNSPEC : AF_INET); nm_system_device_flush_addresses (self); nm_device_update_ip4_address (self); diff --git a/src/nm-system.c b/src/nm-system.c index 517460d4fe..32be53ff37 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -1211,21 +1211,25 @@ check_one_route (struct nl_object *object, void *user_data) } } -static void flush_routes (const char *iface, gboolean ipv4_only) +static void flush_routes (int ifindex, const char *iface, int family) { - int iface_idx; RouteCheckData check_data; g_return_if_fail (iface != NULL); - iface_idx = nm_netlink_iface_to_index (iface); - if (iface_idx >= 0) { - memset (&check_data, 0, sizeof (check_data)); - check_data.iface = iface; - check_data.iface_idx = iface_idx; - check_data.family = ipv4_only ? AF_INET : 0; - foreach_route (check_one_route, &check_data); + if (ifindex < 0) { + ifindex = nm_netlink_iface_to_index (iface); + if (ifindex < 0) { + nm_log_dbg (LOGD_DEVICE, "(%s) failed to lookup interface index", iface); + return; + } } + + memset (&check_data, 0, sizeof (check_data)); + check_data.iface = iface; + check_data.iface_idx = ifindex; + check_data.family = family; + foreach_route (check_one_route, &check_data); } /* @@ -1234,23 +1238,25 @@ static void flush_routes (const char *iface, gboolean ipv4_only) * Flush all network addresses associated with a network device * */ -void nm_system_device_flush_routes (NMDevice *dev) +void nm_system_device_flush_routes (NMDevice *dev, int family) { g_return_if_fail (dev != NULL); - flush_routes (nm_device_get_ip_iface (dev), - nm_device_get_ip6_config (dev) == NULL); + flush_routes (nm_device_get_ip_ifindex (dev), + nm_device_get_ip_iface (dev), + family); } /* * nm_system_device_flush_routes_with_iface * - * Flush all routes associated with a network device + * Flush all routes associated with a network device. 'family' is an + * address family, either AF_INET, AF_INET6, or AF_UNSPEC. * */ -void nm_system_device_flush_routes_with_iface (const char *iface) +void nm_system_device_flush_routes_with_iface (const char *iface, int family) { - flush_routes (iface, FALSE); + flush_routes (-1, iface, family); } typedef struct { diff --git a/src/nm-system.h b/src/nm-system.h index e48e493c61..2eee01417d 100644 --- a/src/nm-system.h +++ b/src/nm-system.h @@ -33,8 +33,8 @@ * implemented in the backend files in backends/ directory */ -void nm_system_device_flush_routes (NMDevice *dev); -void nm_system_device_flush_routes_with_iface (const char *iface); +void nm_system_device_flush_routes (NMDevice *dev, int family); +void nm_system_device_flush_routes_with_iface (const char *iface, int family); gboolean nm_system_replace_default_ip4_route (const char *iface, guint32 gw, diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index a714e991e8..91c7754265 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -878,7 +878,8 @@ vpn_cleanup (NMVPNConnection *connection) if (priv->tundev) { nm_system_device_set_up_down_with_iface (priv->tundev, FALSE, NULL); - nm_system_device_flush_routes_with_iface (priv->tundev); + /* FIXME: use AF_UNSPEC here when we have IPv6 support */ + nm_system_device_flush_routes_with_iface (priv->tundev, AF_INET); nm_system_device_flush_addresses_with_iface (priv->tundev); } From 17b49b957cb3d92a86ccdce0559e6b753bd7aa98 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 May 2010 20:24:17 -0700 Subject: [PATCH 105/105] ip6: don't flush link-local IPv6 routes (rh #587836) Since a link-local address should pretty much always be assigned to an active interface, avoid flushing the routes that allow link-local communication to work. --- src/nm-system.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/nm-system.c b/src/nm-system.c index 32be53ff37..35aa36a111 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -1203,6 +1203,25 @@ check_one_route (struct nl_object *object, void *user_data) if (data->family && rtnl_route_get_family (route) != data->family) return; + /* We don't want to flush IPv6 link-local routes that may exist on the + * the interface since the LL address and routes should normally stay + * assigned all the time. + */ + if ( (data->family == AF_INET6 || data->family == AF_UNSPEC) + && (rtnl_route_get_family (route) == AF_INET6)) { + struct nl_addr *nl; + struct in6_addr *addr = NULL; + + nl = rtnl_route_get_dst (route); + if (nl) + addr = nl_addr_get_binary_addr (nl); + + if (addr) { + if (IN6_IS_ADDR_LINKLOCAL (addr) || IN6_IS_ADDR_MC_LINKLOCAL (addr)) + return; + } + } + err = rtnl_route_del (nm_netlink_get_default_handle (), route, 0); if (err < 0) { nm_log_err (LOGD_DEVICE,