From fb6c929d887f652967d4fb978d50e9104788ad24 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Apr 2010 14:51:47 -0700 Subject: [PATCH 01/51] 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 02/51] 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 03/51] 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 04/51] 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 05/51] 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 06/51] 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 07/51] 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 08/51] 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 09/51] 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 10/51] 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 11/51] 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 12/51] 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 13/51] 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 14/51] 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 15/51] 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 16/51] 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 17/51] 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 18/51] 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 19/51] 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 20/51] 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 21/51] 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 22/51] 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 23/51] 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 24/51] 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 25/51] 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 26/51] 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 27/51] 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 28/51] 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 29/51] 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 30/51] 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 31/51] 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 32/51] 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 33/51] 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 34/51] 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 35/51] 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 36/51] 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 37/51] 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 38/51] 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 39/51] 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 40/51] 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 41/51] 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 42/51] 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 43/51] 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 44/51] 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 45/51] 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 46/51] 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 47/51] 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 48/51] 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 49/51] 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 50/51] 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 51/51] 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); +} +