diff --git a/include/nm-dbus-glib-types.h b/include/nm-dbus-glib-types.h index be52614cf..cfb08274c 100644 --- a/include/nm-dbus-glib-types.h +++ b/include/nm-dbus-glib-types.h @@ -34,8 +34,10 @@ #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, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_INVALID)) +#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_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)) #endif /* DBUS_GLIB_TYPES_H */ diff --git a/introspection/Makefile.am b/introspection/Makefile.am index a77dba1a7..eee9eb189 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -4,6 +4,7 @@ EXTRA_DIST = \ errors.xml \ vpn-errors.xml \ nm-access-point.xml \ + nm-device-bt.xml \ nm-device-wifi.xml \ nm-device-ethernet.xml \ nm-device-cdma.xml \ @@ -11,6 +12,7 @@ EXTRA_DIST = \ nm-device-serial.xml \ nm-device.xml \ nm-ip4-config.xml \ + nm-ip6-config.xml \ nm-manager.xml \ nm-manager-client.xml \ nm-settings.xml \ diff --git a/introspection/nm-ip6-config.xml b/introspection/nm-ip6-config.xml new file mode 100644 index 000000000..d1349b0c2 --- /dev/null +++ b/introspection/nm-ip6-config.xml @@ -0,0 +1,19 @@ + + + + + + Tuples of IPv6 address/prefix. + + + The nameservers in use. + + + A list of domains this address belongs to. + + + Tuples of IPv6 route/prefix/next-hop/metric. + + + + diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index bc7befb06..1a5a94eb3 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -17,6 +17,7 @@ libnm_util_include_HEADERS = \ nm-setting-bluetooth.h \ nm-setting-connection.h \ nm-setting-ip4-config.h \ + nm-setting-ip6-config.h \ nm-setting-ppp.h \ nm-setting-pppoe.h \ nm-setting-serial.h \ @@ -106,5 +107,5 @@ pkgconfig_DATA = libnm-util.pc DISTCLEANFILES = libnm-util.pc -EXTRA_DIST = libnm-util.pc.in libnm-util.ver nm-setting-ip6-config.h +EXTRA_DIST = libnm-util.pc.in libnm-util.ver diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index 4d372a743..92228f525 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -140,6 +140,56 @@ global: nm_setting_ip4_config_get_dhcp_hostname; nm_setting_ip4_config_get_dhcp_send_hostname; nm_setting_ip4_config_get_never_default; + nm_setting_ip6_config_error_get_type; + nm_setting_ip6_config_error_quark; + nm_ip6_address_new; + nm_ip6_address_dup; + nm_ip6_address_ref; + nm_ip6_address_unref; + nm_ip6_address_compare; + nm_ip6_address_get_address; + nm_ip6_address_set_address; + nm_ip6_address_get_prefix; + nm_ip6_address_set_prefix; + nm_ip6_route_new; + nm_ip6_route_dup; + nm_ip6_route_ref; + nm_ip6_route_unref; + nm_ip6_route_compare; + nm_ip6_route_get_dest; + nm_ip6_route_set_dest; + nm_ip6_route_get_prefix; + nm_ip6_route_set_prefix; + nm_ip6_route_get_next_hop; + nm_ip6_route_set_next_hop; + nm_ip6_route_get_metric; + nm_ip6_route_set_metric; + nm_setting_ip6_config_get_type; + nm_setting_ip6_config_new; + nm_setting_ip6_config_get_method; + nm_setting_ip6_config_get_num_dns; + nm_setting_ip6_config_get_dns; + nm_setting_ip6_config_add_dns; + nm_setting_ip6_config_remove_dns; + nm_setting_ip6_config_clear_dns; + nm_setting_ip6_config_get_num_dns_searches; + nm_setting_ip6_config_get_dns_search; + nm_setting_ip6_config_add_dns_search; + nm_setting_ip6_config_remove_dns_search; + nm_setting_ip6_config_clear_dns_searches; + nm_setting_ip6_config_get_num_addresses; + nm_setting_ip6_config_get_address; + nm_setting_ip6_config_add_address; + nm_setting_ip6_config_remove_address; + nm_setting_ip6_config_clear_addresses; + nm_setting_ip6_config_get_num_routes; + nm_setting_ip6_config_get_route; + nm_setting_ip6_config_add_route; + nm_setting_ip6_config_remove_route; + nm_setting_ip6_config_clear_routes; + nm_setting_ip6_config_get_ignore_auto_routes; + nm_setting_ip6_config_get_ignore_auto_dns; + nm_setting_ip6_config_get_never_default; nm_setting_need_secrets; nm_setting_ppp_error_get_type; nm_setting_ppp_error_quark; @@ -263,6 +313,10 @@ global: nm_utils_ip4_prefix_to_netmask; nm_utils_ip4_routes_from_gvalue; nm_utils_ip4_routes_to_gvalue; + nm_utils_ip6_addresses_from_gvalue; + nm_utils_ip6_addresses_to_gvalue; + nm_utils_ip6_routes_from_gvalue; + nm_utils_ip6_routes_to_gvalue; nm_utils_is_empty_ssid; nm_utils_same_ssid; nm_utils_security_valid; diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c index e0160232c..810032ae5 100644 --- a/libnm-util/nm-connection.c +++ b/libnm-util/nm-connection.c @@ -266,6 +266,11 @@ register_default_settings (void) NM_SETTING_IP4_CONFIG_ERROR, 6); + register_one_setting (NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_TYPE_SETTING_IP6_CONFIG, + NM_SETTING_IP6_CONFIG_ERROR, + 6); + /* Be sure to update DEFAULT_MAP_SIZE if you add another setting!! */ } diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c index 1c7a8bc70..68efff391 100644 --- a/libnm-util/nm-setting-8021x.c +++ b/libnm-util/nm-setting-8021x.c @@ -947,7 +947,7 @@ static EAPMethodsTable eap_methods_table[] = { { "peap", need_secrets_phase2, verify_ttls }, { "ttls", need_secrets_phase2, verify_ttls }, { "sim", need_secrets_sim, NULL }, - { "gtc", NULL, NULL }, // FIXME: implement + { "gtc", need_secrets_password, verify_identity }, { "otp", NULL, NULL }, // FIXME: implement { NULL, NULL, NULL } }; diff --git a/libnm-util/nm-setting-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index 66defb38c..d9da92fa8 100644 --- a/libnm-util/nm-setting-ip6-config.c +++ b/libnm-util/nm-setting-ip6-config.c @@ -30,13 +30,6 @@ #include "nm-utils.h" #include "nm-dbus-glib-types.h" -GSList *nm_utils_ip6_addresses_from_gvalue (const GValue *value); -void nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value); - -GSList *nm_utils_ip6_dns_from_gvalue (const GValue *value); -void nm_utils_ip6_dns_to_gvalue (GSList *list, GValue *value); - - GQuark nm_setting_ip6_config_error_quark (void) { @@ -83,9 +76,9 @@ typedef struct { GSList *dns_search; /* list of strings */ GSList *addresses; /* array of NMIP6Address */ GSList *routes; /* array of NMIP6Route */ + gboolean ignore_auto_routes; gboolean ignore_auto_dns; - gboolean ignore_ra; - char *dhcp_mode; + gboolean never_default; } NMSettingIP6ConfigPrivate; @@ -96,9 +89,9 @@ enum { PROP_DNS_SEARCH, PROP_ADDRESSES, PROP_ROUTES, + PROP_IGNORE_AUTO_ROUTES, PROP_IGNORE_AUTO_DNS, - PROP_IGNORE_ROUTER_ADV, - PROP_DHCP_MODE, + PROP_NEVER_DEFAULT, LAST_PROP }; @@ -397,6 +390,14 @@ nm_setting_ip6_config_clear_routes (NMSettingIP6Config *setting) priv->routes = NULL; } +gboolean +nm_setting_ip6_config_get_ignore_auto_routes (NMSettingIP6Config *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (setting), FALSE); + + return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->ignore_auto_routes; +} + gboolean nm_setting_ip6_config_get_ignore_auto_dns (NMSettingIP6Config *setting) { @@ -406,19 +407,11 @@ nm_setting_ip6_config_get_ignore_auto_dns (NMSettingIP6Config *setting) } gboolean -nm_setting_ip6_config_get_ignore_router_adv (NMSettingIP6Config *setting) +nm_setting_ip6_config_get_never_default (NMSettingIP6Config *setting) { g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (setting), FALSE); - return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->ignore_ra; -} - -const char * -nm_setting_ip6_config_get_dhcp_mode (NMSettingIP6Config *setting) -{ - g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (setting), FALSE); - - return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->dhcp_mode; + return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->never_default; } static gboolean @@ -443,6 +436,7 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) return FALSE; } } else if ( !strcmp (priv->method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) + || !strcmp (priv->method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) || !strcmp (priv->method, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { if (!priv->ignore_auto_dns) { if (priv->dns && g_slist_length (priv->dns)) { @@ -469,17 +463,6 @@ verify (NMSetting *setting, GSList *all_settings, GError **error) NM_SETTING_IP6_CONFIG_ADDRESSES); return FALSE; } - - /* if router advertisement autoconf is disabled, dhcpv6 mode must - * be SOMETHING as long as the user has selected the auto method - */ - if (priv->ignore_ra && (priv->dhcp_mode == NULL)) { - g_set_error (error, - NM_SETTING_IP6_CONFIG_ERROR, - NM_SETTING_IP6_CONFIG_ERROR_INVALID_PROPERTY, - NM_SETTING_IP6_CONFIG_DHCP_MODE); - return FALSE; - } } else { g_set_error (error, NM_SETTING_IP6_CONFIG_ERROR, @@ -540,17 +523,16 @@ set_property (GObject *object, guint prop_id, break; case PROP_ROUTES: nm_utils_slist_free (priv->routes, g_free); - priv->routes = nm_utils_ip6_addresses_from_gvalue (value); + priv->routes = nm_utils_ip6_routes_from_gvalue (value); + break; + case PROP_IGNORE_AUTO_ROUTES: + priv->ignore_auto_routes = g_value_get_boolean (value); break; case PROP_IGNORE_AUTO_DNS: priv->ignore_auto_dns = g_value_get_boolean (value); break; - case PROP_IGNORE_ROUTER_ADV: - priv->ignore_ra = g_value_get_boolean (value); - break; - case PROP_DHCP_MODE: - g_free (priv->dhcp_mode); - priv->dhcp_mode = g_value_dup_string (value); + case PROP_NEVER_DEFAULT: + priv->never_default = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -578,16 +560,16 @@ get_property (GObject *object, guint prop_id, nm_utils_ip6_addresses_to_gvalue (priv->addresses, value); break; case PROP_ROUTES: - nm_utils_ip6_addresses_to_gvalue (priv->routes, value); + nm_utils_ip6_routes_to_gvalue (priv->routes, value); + break; + case PROP_IGNORE_AUTO_ROUTES: + g_value_set_boolean (value, priv->ignore_auto_routes); break; case PROP_IGNORE_AUTO_DNS: g_value_set_boolean (value, priv->ignore_auto_dns); break; - case PROP_IGNORE_ROUTER_ADV: - g_value_set_boolean (value, priv->ignore_ra); - break; - case PROP_DHCP_MODE: - g_value_set_string (value, priv->dhcp_mode); + case PROP_NEVER_DEFAULT: + g_value_set_boolean (value, priv->never_default); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -601,6 +583,8 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class) GObjectClass *object_class = G_OBJECT_CLASS (setting_class); NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + g_type_class_add_private (setting_class, sizeof (NMSettingIP6ConfigPrivate)); + /* virtual methods */ object_class->set_property = set_property; object_class->get_property = get_property; @@ -645,39 +629,39 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class) _nm_param_spec_specialized (NM_SETTING_IP6_CONFIG_ROUTES, "Routes", "List of NMSettingIP6Addresses", - DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS, + DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE, G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + g_object_class_install_property + (object_class, PROP_IGNORE_AUTO_ROUTES, + g_param_spec_boolean (NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, + "Ignore automatic routes", + "Ignore automatic routes", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); + g_object_class_install_property (object_class, PROP_IGNORE_AUTO_DNS, g_param_spec_boolean (NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, - "Ignore DHCPv6 DNS", - "Ignore DHCPv6 DNS", + "Ignore DHCPv6/RDNSS DNS", + "Ignore DHCPv6/RDNSS DNS", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); g_object_class_install_property - (object_class, PROP_IGNORE_ROUTER_ADV, - g_param_spec_boolean (NM_SETTING_IP6_CONFIG_IGNORE_ROUTER_ADV, - "Ignore Router Advertisements", - "Ignore Router Advertisements", + (object_class, PROP_NEVER_DEFAULT, + g_param_spec_boolean (NM_SETTING_IP6_CONFIG_NEVER_DEFAULT, + "Never default", + "Never make this connection the default IPv6 connection", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); - g_object_class_install_property - (object_class, PROP_DHCP_MODE, - g_param_spec_string (NM_SETTING_IP6_CONFIG_DHCP_MODE, - "DHCPv6 Client Mode", - "DHCPv6 Client Mode", - NULL, - G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); } struct NMIP6Address { guint32 refcount; - struct in6_addr *address; /* network byte order */ + struct in6_addr address; guint32 prefix; - struct in6_addr *gateway; /* network byte order */ }; NMIP6Address * @@ -700,16 +684,7 @@ nm_ip6_address_dup (NMIP6Address *source) address = nm_ip6_address_new (); address->prefix = source->prefix; - - if (source->address) { - address->address = g_malloc0 (sizeof (struct in6_addr)); - memcpy (address->address, source->address, sizeof (struct in6_addr)); - } - - if (source->gateway) { - address->gateway = g_malloc0 (sizeof (struct in6_addr)); - memcpy (address->gateway, source->gateway, sizeof (struct in6_addr)); - } + memcpy (&address->address, &source->address, sizeof (struct in6_addr)); return address; } @@ -731,8 +706,6 @@ nm_ip6_address_unref (NMIP6Address *address) address->refcount--; if (address->refcount == 0) { - g_free (address->address); - g_free (address->gateway); memset (address, 0, sizeof (NMIP6Address)); g_free (address); } @@ -747,9 +720,8 @@ nm_ip6_address_compare (NMIP6Address *address, NMIP6Address *other) g_return_val_if_fail (other != NULL, FALSE); g_return_val_if_fail (other->refcount > 0, FALSE); - if ( memcmp (address->address, other->address, sizeof (struct in6_addr)) - || address->prefix != other->prefix - || memcmp (address->gateway, other->gateway, sizeof (struct in6_addr))) + if ( memcmp (&address->address, &other->address, sizeof (struct in6_addr)) + || address->prefix != other->prefix) return FALSE; return TRUE; } @@ -760,7 +732,7 @@ nm_ip6_address_get_address (NMIP6Address *address) g_return_val_if_fail (address != NULL, 0); g_return_val_if_fail (address->refcount > 0, 0); - return address->address; + return &address->address; } void @@ -768,14 +740,9 @@ nm_ip6_address_set_address (NMIP6Address *address, const struct in6_addr *addr) { g_return_if_fail (address != NULL); g_return_if_fail (address->refcount > 0); + g_return_if_fail (addr != NULL); - g_free (address->address); - address->address = NULL; - - if (addr) { - address->address = g_malloc0 (sizeof (struct in6_addr)); - memcpy (address->address, addr, sizeof (struct in6_addr)); - } + memcpy (&address->address, addr, sizeof (struct in6_addr)); } guint32 @@ -796,37 +763,12 @@ 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 *gateway) -{ - g_return_if_fail (address != NULL); - g_return_if_fail (address->refcount > 0); - - g_free (address->gateway); - address->gateway = NULL; - - if (gateway) { - address->gateway = g_malloc0 (sizeof (struct in6_addr)); - memcpy (address->gateway, gateway, sizeof (struct in6_addr)); - } -} - - struct NMIP6Route { guint32 refcount; - struct in6_addr *dest; /* network byte order */ + struct in6_addr dest; guint32 prefix; - struct in6_addr *next_hop; /* network byte order */ + struct in6_addr next_hop; guint32 metric; /* lower metric == more preferred */ }; @@ -851,16 +793,8 @@ nm_ip6_route_dup (NMIP6Route *source) route = nm_ip6_route_new (); route->prefix = source->prefix; route->metric = source->metric; - - if (source->dest) { - route->dest = g_malloc0 (sizeof (struct in6_addr)); - memcpy (route->dest, source->dest, sizeof (struct in6_addr)); - } - - if (source->next_hop) { - route->next_hop = g_malloc0 (sizeof (struct in6_addr)); - memcpy (route->next_hop, source->next_hop, sizeof (struct in6_addr)); - } + memcpy (&route->dest, &source->dest, sizeof (struct in6_addr)); + memcpy (&route->next_hop, &source->next_hop, sizeof (struct in6_addr)); return route; } @@ -882,8 +816,6 @@ nm_ip6_route_unref (NMIP6Route *route) route->refcount--; if (route->refcount == 0) { - g_free (route->dest); - g_free (route->next_hop); memset (route, 0, sizeof (NMIP6Route)); g_free (route); } @@ -898,9 +830,9 @@ nm_ip6_route_compare (NMIP6Route *route, NMIP6Route *other) g_return_val_if_fail (other != NULL, FALSE); g_return_val_if_fail (other->refcount > 0, FALSE); - if ( memcmp (route->dest, other->dest, sizeof (struct in6_addr)) + if ( memcmp (&route->dest, &other->dest, sizeof (struct in6_addr)) || route->prefix != other->prefix - || memcmp (route->next_hop, other->next_hop, sizeof (struct in6_addr)) + || memcmp (&route->next_hop, &other->next_hop, sizeof (struct in6_addr)) || route->metric != other->metric) return FALSE; return TRUE; @@ -912,7 +844,7 @@ nm_ip6_route_get_dest (NMIP6Route *route) g_return_val_if_fail (route != NULL, 0); g_return_val_if_fail (route->refcount > 0, 0); - return route->dest; + return &route->dest; } void @@ -920,14 +852,9 @@ nm_ip6_route_set_dest (NMIP6Route *route, const struct in6_addr *dest) { g_return_if_fail (route != NULL); g_return_if_fail (route->refcount > 0); + g_return_if_fail (dest != NULL); - g_free (route->dest); - route->dest = NULL; - - if (dest) { - route->dest = g_malloc0 (sizeof (struct in6_addr)); - memcpy (route->dest, dest, sizeof (struct in6_addr)); - } + memcpy (&route->dest, dest, sizeof (struct in6_addr)); } guint32 @@ -954,7 +881,7 @@ nm_ip6_route_get_next_hop (NMIP6Route *route) g_return_val_if_fail (route != NULL, 0); g_return_val_if_fail (route->refcount > 0, 0); - return route->next_hop; + return &route->next_hop; } void @@ -962,14 +889,9 @@ nm_ip6_route_set_next_hop (NMIP6Route *route, const struct in6_addr *next_hop) { g_return_if_fail (route != NULL); g_return_if_fail (route->refcount > 0); + g_return_if_fail (next_hop != NULL); - g_free (route->next_hop); - route->next_hop = NULL; - - if (next_hop) { - route->next_hop = g_malloc0 (sizeof (struct in6_addr)); - memcpy (route->next_hop, next_hop, sizeof (struct in6_addr)); - } + memcpy (&route->next_hop, next_hop, sizeof (struct in6_addr)); } guint32 @@ -989,4 +911,3 @@ nm_ip6_route_set_metric (NMIP6Route *route, guint32 metric) route->metric = metric; } - diff --git a/libnm-util/nm-setting-ip6-config.h b/libnm-util/nm-setting-ip6-config.h index 879d82e0c..4e3994023 100644 --- a/libnm-util/nm-setting-ip6-config.h +++ b/libnm-util/nm-setting-ip6-config.h @@ -54,21 +54,20 @@ GType nm_setting_ip6_config_error_get_type (void); #define NM_SETTING_IP6_CONFIG_ERROR nm_setting_ip6_config_error_quark () GQuark nm_setting_ip6_config_error_quark (void); -#define NM_SETTING_IP6_CONFIG_METHOD "method" -#define NM_SETTING_IP6_CONFIG_DNS "dns" -#define NM_SETTING_IP6_CONFIG_DNS_SEARCH "dns-search" -#define NM_SETTING_IP6_CONFIG_ADDRESSES "addresses" -#define NM_SETTING_IP6_CONFIG_ROUTES "routes" -#define NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS "ignore-auto-dns" -#define NM_SETTING_IP6_CONFIG_IGNORE_ROUTER_ADV "ignore-router-adv" -#define NM_SETTING_IP6_CONFIG_DHCP_MODE "dhcp-mode" +#define NM_SETTING_IP6_CONFIG_METHOD "method" +#define NM_SETTING_IP6_CONFIG_DNS "dns" +#define NM_SETTING_IP6_CONFIG_DNS_SEARCH "dns-search" +#define NM_SETTING_IP6_CONFIG_ADDRESSES "addresses" +#define NM_SETTING_IP6_CONFIG_ROUTES "routes" +#define NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES "ignore-auto-routes" +#define NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS "ignore-auto-dns" +#define NM_SETTING_IP6_CONFIG_NEVER_DEFAULT "never-default" -#define NM_SETTING_IP6_CONFIG_METHOD_AUTO "auto" -#define NM_SETTING_IP6_CONFIG_METHOD_MANUAL "manual" -#define NM_SETTING_IP6_CONFIG_METHOD_SHARED "shared" - -#define NM_SETTING_IP6_CONFIG_DHCPV6_MODE_INFO "info" -#define NM_SETTING_IP6_CONFIG_DHCPV6_MODE_REQUEST "request" +#define NM_SETTING_IP6_CONFIG_METHOD_IGNORE "ignore" +#define NM_SETTING_IP6_CONFIG_METHOD_AUTO "auto" +#define NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL "link-local" +#define NM_SETTING_IP6_CONFIG_METHOD_MANUAL "manual" +#define NM_SETTING_IP6_CONFIG_METHOD_SHARED "shared" typedef struct NMIP6Address NMIP6Address; @@ -82,16 +81,12 @@ gboolean nm_ip6_address_compare (NMIP6Address *address, NMIP6A const struct in6_addr *nm_ip6_address_get_address (NMIP6Address *address); void nm_ip6_address_set_address (NMIP6Address *address, - const struct in6_addr *addr); /* network byte order */ + const struct in6_addr *addr); 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 *addr); /* network byte order */ - typedef struct NMIP6Route NMIP6Route; NMIP6Route * nm_ip6_route_new (void); @@ -103,7 +98,7 @@ gboolean nm_ip6_route_compare (NMIP6Route *route, NMIP6Route const struct in6_addr *nm_ip6_route_get_dest (NMIP6Route *route); void nm_ip6_route_set_dest (NMIP6Route *route, - const struct in6_addr *dest); /* network byte order */ + const struct in6_addr *dest); guint32 nm_ip6_route_get_prefix (NMIP6Route *route); void nm_ip6_route_set_prefix (NMIP6Route *route, @@ -111,7 +106,7 @@ void nm_ip6_route_set_prefix (NMIP6Route *route, const struct in6_addr *nm_ip6_route_get_next_hop (NMIP6Route *route); void nm_ip6_route_set_next_hop (NMIP6Route *route, - const struct in6_addr *next_hop); /* network byte order */ + const struct in6_addr *next_hop); guint32 nm_ip6_route_get_metric (NMIP6Route *route); void nm_ip6_route_set_metric (NMIP6Route *route, @@ -125,40 +120,38 @@ typedef struct { NMSettingClass parent; } NMSettingIP6ConfigClass; -/* IPv6 support is currently incomplete. Do not use. */ - GType nm_setting_ip6_config_get_type (void); -NMSetting * nm_setting_ip6_config_new (void); -const char * nm_setting_ip6_config_get_method (NMSettingIP6Config *setting); +NMSetting * nm_setting_ip6_config_new (void); +const char * nm_setting_ip6_config_get_method (NMSettingIP6Config *setting); -guint32 nm_setting_ip6_config_get_num_dns (NMSettingIP6Config *setting); -const struct in6_addr *nm_setting_ip6_config_get_dns (NMSettingIP6Config *setting, guint32 i); -gboolean nm_setting_ip6_config_add_dns (NMSettingIP6Config *setting, const struct in6_addr *dns); -void nm_setting_ip6_config_remove_dns (NMSettingIP6Config *setting, guint32 i); -void nm_setting_ip6_config_clear_dns (NMSettingIP6Config *setting); +guint32 nm_setting_ip6_config_get_num_dns (NMSettingIP6Config *setting); +const struct in6_addr *nm_setting_ip6_config_get_dns (NMSettingIP6Config *setting, guint32 i); +gboolean nm_setting_ip6_config_add_dns (NMSettingIP6Config *setting, const struct in6_addr *dns); +void nm_setting_ip6_config_remove_dns (NMSettingIP6Config *setting, guint32 i); +void nm_setting_ip6_config_clear_dns (NMSettingIP6Config *setting); -guint32 nm_setting_ip6_config_get_num_dns_searches (NMSettingIP6Config *setting); -const char * nm_setting_ip6_config_get_dns_search (NMSettingIP6Config *setting, guint32 i); -gboolean nm_setting_ip6_config_add_dns_search (NMSettingIP6Config *setting, const char *dns_search); -void nm_setting_ip6_config_remove_dns_search (NMSettingIP6Config *setting, guint32 i); -void nm_setting_ip6_config_clear_dns_searches (NMSettingIP6Config *setting); +guint32 nm_setting_ip6_config_get_num_dns_searches (NMSettingIP6Config *setting); +const char * nm_setting_ip6_config_get_dns_search (NMSettingIP6Config *setting, guint32 i); +gboolean nm_setting_ip6_config_add_dns_search (NMSettingIP6Config *setting, const char *dns_search); +void nm_setting_ip6_config_remove_dns_search (NMSettingIP6Config *setting, guint32 i); +void nm_setting_ip6_config_clear_dns_searches (NMSettingIP6Config *setting); -guint32 nm_setting_ip6_config_get_num_addresses (NMSettingIP6Config *setting); -NMIP6Address * nm_setting_ip6_config_get_address (NMSettingIP6Config *setting, guint32 i); -gboolean nm_setting_ip6_config_add_address (NMSettingIP6Config *setting, NMIP6Address *address); -void nm_setting_ip6_config_remove_address (NMSettingIP6Config *setting, guint32 i); -void nm_setting_ip6_config_clear_addresses (NMSettingIP6Config *setting); +guint32 nm_setting_ip6_config_get_num_addresses (NMSettingIP6Config *setting); +NMIP6Address * nm_setting_ip6_config_get_address (NMSettingIP6Config *setting, guint32 i); +gboolean nm_setting_ip6_config_add_address (NMSettingIP6Config *setting, NMIP6Address *address); +void nm_setting_ip6_config_remove_address (NMSettingIP6Config *setting, guint32 i); +void nm_setting_ip6_config_clear_addresses (NMSettingIP6Config *setting); -guint32 nm_setting_ip6_config_get_num_routes (NMSettingIP6Config *setting); -NMIP6Route * nm_setting_ip6_config_get_route (NMSettingIP6Config *setting, guint32 i); -gboolean nm_setting_ip6_config_add_route (NMSettingIP6Config *setting, NMIP6Route *route); -void nm_setting_ip6_config_remove_route (NMSettingIP6Config *setting, guint32 i); -void nm_setting_ip6_config_clear_routes (NMSettingIP6Config *setting); +guint32 nm_setting_ip6_config_get_num_routes (NMSettingIP6Config *setting); +NMIP6Route * nm_setting_ip6_config_get_route (NMSettingIP6Config *setting, guint32 i); +gboolean nm_setting_ip6_config_add_route (NMSettingIP6Config *setting, NMIP6Route *route); +void nm_setting_ip6_config_remove_route (NMSettingIP6Config *setting, guint32 i); +void nm_setting_ip6_config_clear_routes (NMSettingIP6Config *setting); +gboolean nm_setting_ip6_config_get_ignore_auto_routes (NMSettingIP6Config *setting); -gboolean nm_setting_ip6_config_get_ignore_auto_dns (NMSettingIP6Config *setting); -gboolean nm_setting_ip6_config_get_ignore_router_adv (NMSettingIP6Config *setting); -const char * nm_setting_ip6_config_get_dhcp_mode (NMSettingIP6Config *setting); +gboolean nm_setting_ip6_config_get_ignore_auto_dns (NMSettingIP6Config *setting); +gboolean nm_setting_ip6_config_get_never_default (NMSettingIP6Config *setting); G_END_DECLS diff --git a/libnm-util/nm-utils.c b/libnm-util/nm-utils.c index f9a56f470..a03412140 100644 --- a/libnm-util/nm-utils.c +++ b/libnm-util/nm-utils.c @@ -54,14 +54,6 @@ * access points and devices, among other things. */ -/* IP6 currently incomplete */ -GSList *nm_utils_ip6_addresses_from_gvalue (const GValue *value); -void nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value); - -GSList *nm_utils_ip6_dns_from_gvalue (const GValue *value); -void nm_utils_ip6_dns_to_gvalue (GSList *list, GValue *value); - - struct EncodingTriplet { const char *encoding1; @@ -1228,14 +1220,13 @@ nm_utils_ip6_addresses_from_gvalue (const GValue *value) for (i = 0; addresses && (i < addresses->len); i++) { GValueArray *elements = (GValueArray *) g_ptr_array_index (addresses, i); GValue *tmp; - GByteArray *ba_addr, *ba_gw; + GByteArray *ba_addr; NMIP6Address *addr; guint32 prefix; - if ( (elements->n_values != 3) + if ( (elements->n_values != 2) || (G_VALUE_TYPE (g_value_array_get_nth (elements, 0)) != DBUS_TYPE_G_UCHAR_ARRAY) - || (G_VALUE_TYPE (g_value_array_get_nth (elements, 1)) != G_TYPE_UINT) - || (G_VALUE_TYPE (g_value_array_get_nth (elements, 2)) != 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; } @@ -1256,18 +1247,9 @@ nm_utils_ip6_addresses_from_gvalue (const GValue *value) continue; } - 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 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); - nm_ip6_address_set_gateway (addr, (const struct in6_addr *) ba_gw->data); list = g_slist_prepend (list, addr); } @@ -1284,31 +1266,131 @@ nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value) for (iter = list; iter; iter = iter->next) { NMIP6Address *addr = (NMIP6Address *) iter->data; - GValue element = { 0, }; - GByteArray *ba_addr, *ba_gw; + GValueArray *array; + GValue element = {0, }; + GByteArray *ba; - g_value_init (&element, DBUS_TYPE_G_IP6_ADDRESS); - g_value_take_boxed (&element, dbus_g_type_specialized_construct (DBUS_TYPE_G_IP6_ADDRESS)); + array = g_value_array_new (2); - ba_addr = g_byte_array_sized_new (16); - g_byte_array_append (ba_addr, (guint8 *) nm_ip6_address_get_address (addr), 16); - - ba_gw = g_byte_array_sized_new (16); - g_byte_array_append (ba_gw, (guint8 *) nm_ip6_address_get_gateway (addr), 16); - - dbus_g_type_struct_set (&element, - 0, ba_addr, - 1, nm_ip6_address_get_prefix (addr), - 2, ba_gw, - G_MAXUINT); - - g_ptr_array_add (addresses, g_value_get_boxed (&element)); + 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); + g_value_take_boxed (&element, ba); + g_value_array_append (array, &element); g_value_unset (&element); + + 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); + + g_ptr_array_add (addresses, array); } g_value_take_boxed (value, addresses); } +GSList * +nm_utils_ip6_routes_from_gvalue (const GValue *value) +{ + GPtrArray *routes; + int i; + GSList *list = NULL; + + routes = (GPtrArray *) g_value_get_boxed (value); + for (i = 0; routes && (i < routes->len); i++) { + GValueArray *route_values = (GValueArray *) g_ptr_array_index (routes, i); + GByteArray *dest, *next_hop; + guint prefix, metric; + NMIP6Route *route; + + if ( (route_values->n_values != 4) + || (G_VALUE_TYPE (g_value_array_get_nth (route_values, 0)) != DBUS_TYPE_G_UCHAR_ARRAY) + || (G_VALUE_TYPE (g_value_array_get_nth (route_values, 1)) != G_TYPE_UINT) + || (G_VALUE_TYPE (g_value_array_get_nth (route_values, 2)) != DBUS_TYPE_G_UCHAR_ARRAY) + || (G_VALUE_TYPE (g_value_array_get_nth (route_values, 3)) != G_TYPE_UINT)) { + nm_warning ("Ignoring invalid IP6 route"); + continue; + } + + dest = g_value_get_boxed (g_value_array_get_nth (route_values, 0)); + if (dest->len != 16) { + nm_warning ("%s: ignoring invalid IP6 dest address of length %d", + __func__, dest->len); + continue; + } + + prefix = g_value_get_uint (g_value_array_get_nth (route_values, 1)); + + next_hop = g_value_get_boxed (g_value_array_get_nth (route_values, 2)); + if (next_hop->len != 16) { + nm_warning ("%s: ignoring invalid IP6 next_hop address of length %d", + __func__, next_hop->len); + continue; + } + + metric = g_value_get_uint (g_value_array_get_nth (route_values, 3)); + + route = nm_ip6_route_new (); + nm_ip6_route_set_dest (route, (struct in6_addr *)dest->data); + nm_ip6_route_set_prefix (route, prefix); + nm_ip6_route_set_next_hop (route, (struct in6_addr *)next_hop->data); + nm_ip6_route_set_metric (route, metric); + list = g_slist_prepend (list, route); + } + + return g_slist_reverse (list); +} + +void +nm_utils_ip6_routes_to_gvalue (GSList *list, GValue *value) +{ + GPtrArray *routes; + GSList *iter; + + routes = g_ptr_array_new (); + + for (iter = list; iter; iter = iter->next) { + NMIP6Route *route = (NMIP6Route *) iter->data; + GValueArray *array; + const struct in6_addr *addr; + GByteArray *ba; + GValue element = {0, }; + + array = g_value_array_new (4); + + g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); + addr = nm_ip6_route_get_dest (route); + ba = g_byte_array_new (); + g_byte_array_append (ba, (guchar *)addr, sizeof (*addr)); + g_value_take_boxed (&element, ba); + g_value_array_append (array, &element); + g_value_unset (&element); + + g_value_init (&element, G_TYPE_UINT); + g_value_set_uint (&element, nm_ip6_route_get_prefix (route)); + g_value_array_append (array, &element); + g_value_unset (&element); + + g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); + addr = nm_ip6_route_get_next_hop (route); + ba = g_byte_array_new (); + g_byte_array_append (ba, (guchar *)addr, sizeof (*addr)); + g_value_take_boxed (&element, ba); + g_value_array_append (array, &element); + g_value_unset (&element); + + g_value_init (&element, G_TYPE_UINT); + g_value_set_uint (&element, nm_ip6_route_get_metric (route)); + g_value_array_append (array, &element); + g_value_unset (&element); + + g_ptr_array_add (routes, array); + } + + g_value_take_boxed (value, routes); +} + GSList * nm_utils_ip6_dns_from_gvalue (const GValue *value) { diff --git a/libnm-util/nm-utils.h b/libnm-util/nm-utils.h index 629bc59fe..810c6e7e9 100644 --- a/libnm-util/nm-utils.h +++ b/libnm-util/nm-utils.h @@ -193,6 +193,15 @@ void nm_utils_ip4_routes_to_gvalue (GSList *list, GValue *value); guint32 nm_utils_ip4_netmask_to_prefix (guint32 netmask); guint32 nm_utils_ip4_prefix_to_netmask (guint32 prefix); +GSList *nm_utils_ip6_addresses_from_gvalue (const GValue *value); +void nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value); + +GSList *nm_utils_ip6_routes_from_gvalue (const GValue *value); +void nm_utils_ip6_routes_to_gvalue (GSList *list, GValue *value); + +GSList *nm_utils_ip6_dns_from_gvalue (const GValue *value); +void nm_utils_ip6_dns_to_gvalue (GSList *list, GValue *value); + char *nm_utils_uuid_generate (void); char *nm_utils_uuid_generate_from_string (const char *s); diff --git a/policy/Makefile.am b/policy/Makefile.am index 9ce677b18..c5d24764e 100644 --- a/policy/Makefile.am +++ b/policy/Makefile.am @@ -5,8 +5,6 @@ dist_polkit_policy_DATA = $(dist_polkit_policy_in_files:.policy.in=.policy) @INTLTOOL_POLICY_RULE@ -EXTRA_DIST = $(dist_polkit_policy_in_files) - check: @for f in $(dist_polkit_policy_DATA); do \ echo -n "Validate PolicyKit policy in $$f : "; \ diff --git a/src/Makefile.am b/src/Makefile.am index 79c2a2e64..d8878e05d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,8 @@ NetworkManager_SOURCES = \ nm-hostname-provider.h \ nm-ip4-config.c \ nm-ip4-config.h \ + nm-ip6-config.c \ + nm-ip6-config.h \ nm-secrets-provider-interface.c \ nm-secrets-provider-interface.h \ nm-active-connection.h \ @@ -129,6 +131,9 @@ nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $< +nm-ip6-config-glue.h: $(top_srcdir)/introspection/nm-ip6-config.xml + dbus-binding-tool --prefix=nm_ip6_config --mode=glib-server --output=$@ $< + nm-active-connection-glue.h: $(top_srcdir)/introspection/nm-active-connection.xml dbus-binding-tool --prefix=nm_active_connection --mode=glib-server --output=$@ $< @@ -143,6 +148,7 @@ BUILT_SOURCES = \ nm-device-wifi-glue.h \ nm-device-bt-glue.h \ nm-ip4-config-glue.h \ + nm-ip6-config-glue.h \ nm-active-connection-glue.h \ nm-dhcp4-config-glue.h diff --git a/src/NetworkManager.conf b/src/NetworkManager.conf index a5eee46e8..87814bec2 100644 --- a/src/NetworkManager.conf +++ b/src/NetworkManager.conf @@ -4,10 +4,10 @@ - + - + @@ -15,58 +15,58 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + 512 diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index 508e0fe93..9f62d7fb0 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -198,14 +198,19 @@ check_one_address (struct nl_object *object, void *user_data) struct rtnl_addr *addr = (struct rtnl_addr *) object; int err; - if (rtnl_addr_get_ifindex (addr) == data->ifindex) { - if (rtnl_addr_get_family (addr) == data->family) { - err = rtnl_addr_delete (data->nlh, addr, 0); - if (err < 0) { - nm_warning ("(%s) error %d returned from rtnl_addr_delete(): %s", - data->iface, err, nl_geterror()); - } - } + if (rtnl_addr_get_ifindex (addr) != data->ifindex) + return; + + if (data->family && rtnl_addr_get_family (addr) != data->family) + return; + if (data->family == AF_INET6 && + rtnl_addr_get_scope (addr) == rtnl_str2scope ("link")) + return; + + err = rtnl_addr_delete (data->nlh, addr, 0); + if (err < 0) { + nm_warning ("(%s) error %d returned from rtnl_addr_delete(): %s", + data->iface, err, nl_geterror()); } } @@ -386,6 +391,194 @@ nm_system_apply_ip4_config (const char *iface, return TRUE; } +static struct rtnl_route * +nm_system_device_set_ip6_route (const char *iface, + const struct in6_addr *ip6_dest, + guint32 ip6_prefix, + const struct in6_addr *ip6_gateway, + guint32 metric, + int mss) +{ + struct nl_handle *nlh; + struct rtnl_route *route; + struct nl_addr *dest_addr; + struct nl_addr *gw_addr = NULL; + int err, iface_idx; + + nlh = nm_netlink_get_default_handle (); + g_return_val_if_fail (nlh != NULL, NULL); + + iface_idx = nm_netlink_iface_to_index (iface); + g_return_val_if_fail (iface_idx >= 0, NULL); + + route = create_route (iface_idx, mss); + g_return_val_if_fail (route != NULL, NULL); + + /* Destination */ + 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); + + rtnl_route_set_dst (route, dest_addr); + nl_addr_put (dest_addr); + + /* 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)); + if (gw_addr) { + rtnl_route_set_gateway (route, gw_addr); + rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE); + } else { + nm_warning ("Invalid gateway"); + rtnl_route_put (route); + return NULL; + } + } + + /* Metric */ + if (metric) + rtnl_route_set_prio (route, metric); + + /* Add the route */ + err = rtnl_route_add (nlh, route, 0); + if (err == -ESRCH && ip6_gateway) { + /* Gateway might be over a bridge; try adding a route to gateway first */ + struct rtnl_route *route2; + + route2 = create_route (iface_idx, mss); + if (route2) { + /* Add route to gateway over bridge */ + rtnl_route_set_dst (route2, gw_addr); + err = rtnl_route_add (nlh, route2, 0); + if (!err) { + /* Try adding the route again */ + err = rtnl_route_add (nlh, route, 0); + if (err) + rtnl_route_del (nlh, route2, 0); + } + rtnl_route_put (route2); + } + } + + if (gw_addr) + nl_addr_put (gw_addr); + + if (err) { + nm_warning ("Failed to set IPv6 route on '%s': %s", iface, nl_geterror ()); + rtnl_route_put (route); + route = NULL; + } + + return route; +} + +static gboolean +add_ip6_addresses (NMIP6Config *config, const char *iface) +{ + struct nl_handle *nlh = NULL; + struct nl_cache *addr_cache = NULL; + int i, iface_idx, err; + AddrCheckData check_data; + guint32 flags = 0; + + nlh = nm_netlink_get_default_handle (); + if (!nlh) + return FALSE; + + addr_cache = rtnl_addr_alloc_cache (nlh); + if (!addr_cache) + return FALSE; + nl_cache_mngt_provide (addr_cache); + + iface_idx = nm_netlink_iface_to_index (iface); + + memset (&check_data, 0, sizeof (check_data)); + check_data.iface = iface; + check_data.nlh = nlh; + check_data.ifindex = iface_idx; + check_data.family = AF_INET6; + + /* Remove all existing IPv6 addresses */ + nl_cache_foreach (addr_cache, check_one_address, &check_data); + + for (i = 0; i < nm_ip6_config_get_num_addresses (config); i++) { + NMIP6Address *addr; + struct rtnl_addr *nl_addr = NULL; + + addr = nm_ip6_config_get_address (config, i); + g_assert (addr); + + flags = NM_RTNL_ADDR_DEFAULT; + + nl_addr = nm_ip6_config_to_rtnl_addr (config, i, flags); + if (!nl_addr) { + nm_warning ("couldn't create rtnl address!\n"); + continue; + } + rtnl_addr_set_ifindex (nl_addr, iface_idx); + + if ((err = rtnl_addr_add (nlh, nl_addr, 0)) < 0) + nm_warning ("(%s) error %d returned from rtnl_addr_add():\n%s", iface, err, nl_geterror()); + + rtnl_addr_put (nl_addr); + } + + nl_cache_free (addr_cache); + return TRUE; +} + +/* + * nm_system_apply_ip6_config + * + * Set IPv6 configuration of the device from an NMIP6Config object. + * + */ +gboolean +nm_system_apply_ip6_config (const char *iface, + NMIP6Config *config, + int priority, + NMIP6ConfigCompareFlags flags) +{ + int i; + + g_return_val_if_fail (iface != NULL, FALSE); + g_return_val_if_fail (config != NULL, FALSE); + + if (flags & NM_IP6_COMPARE_FLAG_ADDRESSES) { + if (!add_ip6_addresses (config, iface)) + return FALSE; + sleep (1); // FIXME? + } + + if (flags & NM_IP6_COMPARE_FLAG_ROUTES) { + for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) { + NMIP6Route *route = nm_ip6_config_get_route (config, i); + struct rtnl_route *tmp; + + /* Don't add the route if it doesn't have a gateway and the connection + * is never supposed to be the default connection. + */ + if ( nm_ip6_config_get_never_default (config) + && IN6_IS_ADDR_UNSPECIFIED(nm_ip6_route_get_dest (route))) + continue; + + tmp = nm_system_device_set_ip6_route (iface, + nm_ip6_route_get_dest (route), + nm_ip6_route_get_prefix (route), + nm_ip6_route_get_next_hop (route), + nm_ip6_route_get_metric (route), + nm_ip6_config_get_mss (config)); + rtnl_route_put (tmp); + } + } + +// FIXME +// if (priority > 0) +// nm_system_device_set_priority (iface, config, priority); + + return TRUE; +} + /* * nm_system_device_set_up_down * @@ -719,27 +912,7 @@ nm_system_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss) return success; } -/* - * nm_system_device_flush_ip4_addresses - * - * Flush all network addresses associated with a network device - * - */ -void nm_system_device_flush_ip4_addresses (NMDevice *dev) -{ - g_return_if_fail (dev != NULL); - - nm_system_device_flush_ip4_addresses_with_iface (nm_device_get_ip_iface (dev)); -} - - -/* - * nm_system_device_flush_ip4_addresses_with_iface - * - * Flush all network addresses associated with a network device - * - */ -void nm_system_device_flush_ip4_addresses_with_iface (const char *iface) +static void flush_addresses (const char *iface, gboolean ipv4_only) { struct nl_handle *nlh = NULL; struct nl_cache *addr_cache = NULL; @@ -756,7 +929,7 @@ void nm_system_device_flush_ip4_addresses_with_iface (const char *iface) memset (&check_data, 0, sizeof (check_data)); check_data.iface = iface; check_data.nlh = nlh; - check_data.family = AF_INET; + check_data.family = ipv4_only ? AF_INET : 0; check_data.ifindex = nm_netlink_iface_to_index (iface); addr_cache = rtnl_addr_alloc_cache (nlh); @@ -771,16 +944,29 @@ void nm_system_device_flush_ip4_addresses_with_iface (const char *iface) } /* - * nm_system_device_flush_ip4_routes + * nm_system_device_flush_addresses * * Flush all network addresses associated with a network device * */ -void nm_system_device_flush_ip4_routes (NMDevice *dev) +void nm_system_device_flush_addresses (NMDevice *dev) { g_return_if_fail (dev != NULL); - nm_system_device_flush_ip4_routes_with_iface (nm_device_get_ip_iface (dev)); + flush_addresses (nm_device_get_ip_iface (dev), + nm_device_get_ip6_config (dev) == NULL); +} + + +/* + * nm_system_device_flush_addresses_with_iface + * + * Flush all network addresses associated with a network device + * + */ +void nm_system_device_flush_addresses_with_iface (const char *iface) +{ + flush_addresses (iface, FALSE); } @@ -802,6 +988,7 @@ foreach_route (void (*callback)(struct nl_object *, gpointer), typedef struct { const char *iface; int iface_idx; + int family; } RouteCheckData; static void @@ -811,10 +998,10 @@ check_one_route (struct nl_object *object, void *user_data) struct rtnl_route *route = (struct rtnl_route *) object; int err; - /* Delete all IPv4 routes from this interface */ + /* Delete all routes from this interface */ if (rtnl_route_get_oif (route) != data->iface_idx) return; - if (rtnl_route_get_family (route) != AF_INET) + if (data->family && rtnl_route_get_family (route) != data->family) return; err = rtnl_route_del (nm_netlink_get_default_handle (), route, 0); @@ -824,13 +1011,7 @@ check_one_route (struct nl_object *object, void *user_data) } } -/* - * nm_system_device_flush_ip4_routes_with_iface - * - * Flush all routes associated with a network device - * - */ -void nm_system_device_flush_ip4_routes_with_iface (const char *iface) +static void flush_routes (const char *iface, gboolean ipv4_only) { int iface_idx; RouteCheckData check_data; @@ -842,10 +1023,36 @@ void nm_system_device_flush_ip4_routes_with_iface (const char *iface) memset (&check_data, 0, sizeof (check_data)); check_data.iface = iface; check_data.iface_idx = iface_idx; + check_data.family = ipv4_only ? AF_INET : 0; foreach_route (check_one_route, &check_data); } +/* + * nm_system_device_flush_routes + * + * Flush all network addresses associated with a network device + * + */ +void nm_system_device_flush_routes (NMDevice *dev) +{ + g_return_if_fail (dev != NULL); + + flush_routes (nm_device_get_ip_iface (dev), + nm_device_get_ip6_config (dev) == NULL); +} + +/* + * nm_system_device_flush_routes_with_iface + * + * Flush all routes associated with a network device + * + */ +void nm_system_device_flush_routes_with_iface (const char *iface) +{ + flush_routes (iface, FALSE); +} + typedef struct { struct rtnl_route *route; NMIP4Config *config; diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index b83a663d0..f2c2693ac 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -33,8 +33,8 @@ * implemented in the backend files in backends/ directory */ -void nm_system_device_flush_ip4_routes (NMDevice *dev); -void nm_system_device_flush_ip4_routes_with_iface (const char *iface); +void nm_system_device_flush_routes (NMDevice *dev); +void nm_system_device_flush_routes_with_iface (const char *iface); gboolean nm_system_replace_default_ip4_route (const char *iface, guint32 gw, @@ -50,8 +50,8 @@ gboolean nm_system_replace_default_ip4_route_vpn (const char *iface, struct rtnl_route *nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_config); -void nm_system_device_flush_ip4_addresses (NMDevice *dev); -void nm_system_device_flush_ip4_addresses_with_iface (const char *iface); +void nm_system_device_flush_addresses (NMDevice *dev); +void nm_system_device_flush_addresses_with_iface (const char *iface); void nm_system_enable_loopback (void); void nm_system_update_dns (void); @@ -61,6 +61,11 @@ gboolean nm_system_apply_ip4_config (const char *iface, int priority, NMIP4ConfigCompareFlags flags); +gboolean nm_system_apply_ip6_config (const char *iface, + NMIP6Config *config, + int priority, + NMIP6ConfigCompareFlags flags); + gboolean nm_system_device_set_up_down (NMDevice *dev, gboolean up, gboolean *no_firmware); diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index a030a3867..4934d465c 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -20,8 +20,11 @@ */ #include +#include +#include #include #include +#include #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -259,6 +262,112 @@ nm_utils_merge_ip4_config (NMIP4Config *ip4_config, NMSettingIP4Config *setting) nm_ip4_config_set_never_default (ip4_config, TRUE); } +static inline gboolean +ip6_addresses_equal (const struct in6_addr *a, const struct in6_addr *b) +{ + return memcmp (a, b, sizeof (struct in6_addr)) == 0; +} + +/* This is exactly identical to nm_utils_merge_ip4_config, with s/4/6/, + * except that we can't compare addresses with ==. + */ +void +nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *setting) +{ + int i, j; + + if (!setting) + return; /* Defaults are just fine */ + + if (nm_setting_ip6_config_get_ignore_auto_dns (setting)) { + nm_ip6_config_reset_nameservers (ip6_config); + nm_ip6_config_reset_domains (ip6_config); + nm_ip6_config_reset_searches (ip6_config); + } + + if (nm_setting_ip6_config_get_ignore_auto_routes (setting)) + nm_ip6_config_reset_routes (ip6_config); + + for (i = 0; i < nm_setting_ip6_config_get_num_dns (setting); i++) { + const struct in6_addr *ns; + gboolean found = FALSE; + + /* Avoid dupes */ + ns = nm_setting_ip6_config_get_dns (setting, i); + for (j = 0; j < nm_ip6_config_get_num_nameservers (ip6_config); j++) { + if (ip6_addresses_equal (nm_ip6_config_get_nameserver (ip6_config, j), ns)) { + found = TRUE; + break; + } + } + + if (!found) + nm_ip6_config_add_nameserver (ip6_config, ns); + } + + /* DNS search domains */ + for (i = 0; i < nm_setting_ip6_config_get_num_dns_searches (setting); i++) { + const char *search = nm_setting_ip6_config_get_dns_search (setting, i); + gboolean found = FALSE; + + /* Avoid dupes */ + for (j = 0; j < nm_ip6_config_get_num_searches (ip6_config); j++) { + if (!strcmp (search, nm_ip6_config_get_search (ip6_config, j))) { + found = TRUE; + break; + } + } + + if (!found) + nm_ip6_config_add_search (ip6_config, search); + } + + /* IPv6 addresses */ + for (i = 0; i < nm_setting_ip6_config_get_num_addresses (setting); i++) { + NMIP6Address *setting_addr = nm_setting_ip6_config_get_address (setting, i); + guint32 num; + + num = nm_ip6_config_get_num_addresses (ip6_config); + for (j = 0; j < num; j++) { + NMIP6Address *cfg_addr = nm_ip6_config_get_address (ip6_config, j); + + /* Dupe, override with user-specified address */ + if (ip6_addresses_equal (nm_ip6_address_get_address (cfg_addr), nm_ip6_address_get_address (setting_addr))) { + nm_ip6_config_replace_address (ip6_config, j, setting_addr); + break; + } + } + + if (j == num) + nm_ip6_config_add_address (ip6_config, setting_addr); + } + + /* IPv6 routes */ + for (i = 0; i < nm_setting_ip6_config_get_num_routes (setting); i++) { + NMIP6Route *setting_route = nm_setting_ip6_config_get_route (setting, i); + guint32 num; + + num = nm_ip6_config_get_num_routes (ip6_config); + for (j = 0; j < num; j++) { + NMIP6Route *cfg_route = nm_ip6_config_get_route (ip6_config, j); + + /* Dupe, override with user-specified route */ + if ( ip6_addresses_equal (nm_ip6_route_get_dest (cfg_route), nm_ip6_route_get_dest (setting_route)) + && (nm_ip6_route_get_prefix (cfg_route) == nm_ip6_route_get_prefix (setting_route)) + && ip6_addresses_equal (nm_ip6_route_get_next_hop (cfg_route), nm_ip6_route_get_next_hop (setting_route))) { + nm_ip6_config_replace_route (ip6_config, j, setting_route); + break; + } + } + + if (j == num) + nm_ip6_config_add_route (ip6_config, setting_route); + } + + if (nm_setting_ip6_config_get_never_default (setting)) + nm_ip6_config_set_never_default (ip6_config, TRUE); +} + void nm_utils_call_dispatcher (const char *action, NMConnection *connection, @@ -444,3 +553,29 @@ value_hash_add_uint (GHashTable *hash, value_hash_add (hash, key, value); } +gboolean +nm_utils_do_sysctl (const char *path, const char *value) +{ + int fd, len, nwrote, total; + + fd = open (path, O_WRONLY | O_TRUNC); + if (fd == -1) + return FALSE; + + len = strlen (value); + total = 0; + do { + nwrote = write (fd, value + total, len - total); + if (nwrote == -1) { + if (errno == EINTR) + continue; + close (fd); + return FALSE; + } + total += nwrote; + } while (total < len); + + close (fd); + return TRUE; +} + diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index a987d21b4..05f3b837a 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -29,6 +29,8 @@ #include "nm-device.h" #include "nm-ip4-config.h" #include "nm-setting-ip4-config.h" +#include "nm-ip6-config.h" +#include "nm-setting-ip6-config.h" #include "nm-connection.h" gboolean nm_ethernet_address_is_valid (const struct ether_addr *test_addr); @@ -38,6 +40,7 @@ int nm_spawn_process (const char *args); char *nm_ether_ntop (const struct ether_addr *mac); void nm_utils_merge_ip4_config (NMIP4Config *ip4_config, NMSettingIP4Config *setting); +void nm_utils_merge_ip6_config (NMIP6Config *ip6_config, NMSettingIP6Config *setting); void nm_utils_call_dispatcher (const char *action, NMConnection *connection, @@ -64,5 +67,6 @@ void value_hash_add_uint (GHashTable *hash, const char *key, guint32 val); +gboolean nm_utils_do_sysctl (const char *path, const char *value); #endif /* NETWORK_MANAGER_UTILS_H */ diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c index 3826dce15..48f9296ed 100644 --- a/src/modem-manager/nm-modem.c +++ b/src/modem-manager/nm-modem.c @@ -131,7 +131,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, nm_device_set_ip_iface (device, iface); NM_MODEM_GET_PRIVATE (device)->pending_ip4_config = g_object_ref (config); - nm_device_activate_schedule_stage4_ip_config_get (device); + nm_device_activate_schedule_stage4_ip4_config_get (device); } static void @@ -235,7 +235,7 @@ static_stage3_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_da g_value_get_uint (g_value_array_get_nth (ret_array, i))); g_value_array_free (ret_array); - nm_device_activate_schedule_stage4_ip_config_get (device); + nm_device_activate_schedule_stage4_ip4_config_get (device); } else { nm_warning ("Retrieving IP4 configuration failed: %s", error->message); g_error_free (error); @@ -303,7 +303,7 @@ real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) } static NMActStageReturn -real_act_stage3_ip_config_start (NMDevice *device, NMDeviceStateReason *reason) +real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) { NMActStageReturn ret; @@ -315,7 +315,7 @@ real_act_stage3_ip_config_start (NMDevice *device, NMDeviceStateReason *reason) ret = static_stage3_config (device, reason); break; case MM_MODEM_IP_METHOD_DHCP: - ret = NM_DEVICE_CLASS (nm_modem_parent_class)->act_stage3_ip_config_start (device, reason); + ret = NM_DEVICE_CLASS (nm_modem_parent_class)->act_stage3_ip4_config_start (device, reason); break; default: g_warning ("Invalid IP method"); @@ -376,8 +376,8 @@ real_deactivate_quickly (NMDevice *device) case MM_MODEM_IP_METHOD_DHCP: iface = nm_device_get_iface (device); - nm_system_device_flush_ip4_routes_with_iface (iface); - nm_system_device_flush_ip4_addresses_with_iface (iface); + nm_system_device_flush_routes_with_iface (iface); + nm_system_device_flush_addresses_with_iface (iface); nm_system_device_set_up_down_with_iface (iface, FALSE, NULL); break; default: @@ -611,7 +611,7 @@ nm_modem_class_init (NMModemClass *klass) device_class->get_generic_capabilities = real_get_generic_capabilities; device_class->act_stage2_config = real_act_stage2_config; - device_class->act_stage3_ip_config_start = real_act_stage3_ip_config_start; + device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start; device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; device_class->deactivate_quickly = real_deactivate_quickly; device_class->hw_is_up = real_hw_is_up; diff --git a/src/named-manager/nm-named-manager.c b/src/named-manager/nm-named-manager.c index cab06abf4..b89c80118 100644 --- a/src/named-manager/nm-named-manager.c +++ b/src/named-manager/nm-named-manager.c @@ -63,8 +63,6 @@ struct NMNamedManagerPrivate { NMIP4Config * vpn_config; NMIP4Config * device_config; GSList * configs; - - gboolean disposed; }; @@ -94,29 +92,71 @@ nm_named_manager_error_quark (void) return quark; } +typedef struct { + GPtrArray *nameservers; + const char *domain; + GPtrArray *searches; +} NMResolvConfData; + static void -merge_one_ip4_config (NMIP4Config *dst, NMIP4Config *src) +merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src) { - guint32 num, num_domains, i; + guint32 num, i; num = nm_ip4_config_get_num_nameservers (src); - for (i = 0; i < num; i++) - nm_ip4_config_add_nameserver (dst, nm_ip4_config_get_nameserver (src, i)); + for (i = 0; i < num; i++) { + struct in_addr addr; + char buf[INET_ADDRSTRLEN]; - num_domains = nm_ip4_config_get_num_domains (src); - for (i = 0; i < num_domains; i++) - nm_ip4_config_add_domain (dst, nm_ip4_config_get_domain (src, i)); + addr.s_addr = nm_ip4_config_get_nameserver (src, i); + if (inet_ntop (AF_INET, &addr, buf, INET_ADDRSTRLEN) > 0) + g_ptr_array_add (rc->nameservers, g_strdup (buf)); + } + + num = nm_ip4_config_get_num_domains (src); + for (i = 0; i < num; i++) { + if (!rc->domain) + rc->domain = nm_ip4_config_get_domain (src, i); + g_ptr_array_add (rc->searches, g_strdup (nm_ip4_config_get_domain (src, i))); + } num = nm_ip4_config_get_num_searches (src); for (i = 0; i < num; i++) - nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i)); + g_ptr_array_add (rc->searches, g_strdup (nm_ip4_config_get_search (src, i))); +} - /* Add the 'domain' list to searches as well since overloading the - * 'domain_name' DHCP field used to be the way you got searches - * into resolv.conf. - */ - for (i = 0; i < num_domains; i++) - nm_ip4_config_add_search (dst, nm_ip4_config_get_domain (src, i)); +static void +merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src) +{ + guint32 num, i; + + num = nm_ip6_config_get_num_nameservers (src); + for (i = 0; i < num; i++) { + const struct in6_addr *addr; + char buf[INET6_ADDRSTRLEN]; + + addr = nm_ip6_config_get_nameserver (src, i); + + /* inet_ntop is probably supposed to do this for us, but it doesn't */ + if (IN6_IS_ADDR_V4MAPPED (addr)) { + if (inet_ntop (AF_INET, &(addr->s6_addr32[3]), buf, INET_ADDRSTRLEN) > 0) + g_ptr_array_add (rc->nameservers, g_strdup (buf)); + } else { + if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) + g_ptr_array_add (rc->nameservers, g_strdup (buf)); + } + } + + num = nm_ip6_config_get_num_domains (src); + for (i = 0; i < num; i++) { + if (!rc->domain) + rc->domain = nm_ip6_config_get_domain (src, i); + g_ptr_array_add (rc->searches, g_strdup (nm_ip6_config_get_domain (src, i))); + } + + num = nm_ip6_config_get_num_searches (src); + for (i = 0; i < num; i++) + g_ptr_array_add (rc->searches, g_strdup (nm_ip6_config_get_search (src, i))); } @@ -183,6 +223,15 @@ dispatch_netconfig (const char *domain, if (pid < 0) return FALSE; + // FIXME: this is wrong. We are not writing out the iface-specific + // resolv.conf data, we are writing out an already-fully-merged + // resolv.conf. Assuming netconfig works in the obvious way, then + // there are various failure modes, such as, eg, bringing up a VPN on + // eth0, then bringing up wlan0, then bringing down the VPN. Because + // NMNamedManager would have claimed that the VPN DNS server was also + // part of the wlan0 config, it will remain in resolv.conf after the + // VPN goes down, even though it is presumably no longer reachable + // at that point. write_to_netconfig (fd, "INTERFACE", iface); if (searches) { @@ -391,50 +440,16 @@ update_resolv_conf (const char *domain, return *error ? FALSE : TRUE; } -static char ** -compute_searches (guint32 num, NMIP4Config *config, gboolean searches) -{ - GPtrArray *array; - size_t len, elem_len; - const char *elem; - int i; - - /* Search list is limited to 6 domains total per 'man resolv.conf' */ - if (num > 6) - num = 6; - - array = g_ptr_array_sized_new (num + 1); - for (i = 0, len = 0; i < num; i++) { - elem = searches ? nm_ip4_config_get_search (config, i) - : nm_ip4_config_get_domain (config, i); - elem_len = strlen (elem); - - /* The search list is limited to 256 characters per 'man resolv.conf' */ - if (len + elem_len > 255) - break; - - g_ptr_array_add (array, g_strdup (elem)); - len += elem_len + 1; /* +1 for spaces */ - } - - g_ptr_array_add (array, NULL); - return (char **) g_ptr_array_free (array, FALSE); -} - static gboolean rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) { NMNamedManagerPrivate *priv; - NMIP4Config *composite; + NMResolvConfData rc; GSList *iter; - GPtrArray *array; const char *domain = NULL; char **searches = NULL; char **nameservers = NULL; - int num_domains; - int num_searches; - int num_nameservers; - int i; + int num, i, len; gboolean success = FALSE; g_return_val_if_fail (error != NULL, FALSE); @@ -442,66 +457,54 @@ rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) priv = NM_NAMED_MANAGER_GET_PRIVATE (mgr); - /* Construct the composite config from all the currently active IP4Configs */ - composite = nm_ip4_config_new (); + rc.nameservers = g_ptr_array_new (); + rc.domain = NULL; + rc.searches = g_ptr_array_new (); if (priv->vpn_config) - merge_one_ip4_config (composite, priv->vpn_config); + merge_one_ip4_config (&rc, priv->vpn_config); if (priv->device_config) - merge_one_ip4_config (composite, priv->device_config); + merge_one_ip4_config (&rc, priv->device_config); for (iter = priv->configs; iter; iter = g_slist_next (iter)) { - NMIP4Config *config = NM_IP4_CONFIG (iter->data); + 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 (composite, config); - } - - /* Some DHCP servers like to put multiple search paths into the domain - * option as the domain-search option wasn't around in the first RFC. - * We should try and support these old servers as best we can. */ - - num_domains = nm_ip4_config_get_num_domains (composite); - num_searches = nm_ip4_config_get_num_searches (composite); - - /* Domain */ - if (num_domains > 0) - domain = nm_ip4_config_get_domain (composite, 0); - - /* Searches */ - if (num_searches > 0) - searches = compute_searches (num_searches, composite, TRUE); - else if (num_domains > 0) - searches = compute_searches (num_searches, composite, FALSE); - - /* Name servers */ - num_nameservers = nm_ip4_config_get_num_nameservers (composite); - if (num_nameservers > 0) { - array = g_ptr_array_sized_new (num_nameservers + 1); - for (i = 0; i < num_nameservers; i++) { - struct in_addr addr; - char *buf; - - addr.s_addr = nm_ip4_config_get_nameserver (composite, i); - buf = g_malloc0 (ADDR_BUF_LEN); - if (!buf) + if ((config == priv->vpn_config) || (config == priv->device_config)) continue; - if (inet_ntop (AF_INET, &addr, buf, ADDR_BUF_LEN)) - g_ptr_array_add (array, buf); - else - nm_warning ("%s: error converting IP4 address 0x%X", - __func__, ntohl (addr.s_addr)); - } + merge_one_ip4_config (&rc, config); + } else { + NMIP6Config *config = NM_IP6_CONFIG (iter->data); - g_ptr_array_add (array, NULL); - nameservers = (char **) g_ptr_array_free (array, FALSE); + merge_one_ip6_config (&rc, config); + } } - g_object_unref (composite); + domain = rc.domain; + + /* Per 'man resolv.conf', the search list is limited to 6 domains + * totalling 256 characters. + */ + num = MIN (rc.searches->len, 6); + for (i = 0, len = 0; i < num; i++) { + len += strlen (rc.searches->pdata[i]) + 1; /* +1 for spaces */ + if (len > 256) + break; + } + g_ptr_array_set_size (rc.searches, i); + if (rc.searches->len) { + g_ptr_array_add (rc.searches, NULL); + searches = (char **) g_ptr_array_free (rc.searches, FALSE); + } else + g_ptr_array_free (rc.searches, TRUE); + + if (rc.nameservers->len) { + g_ptr_array_add (rc.nameservers, NULL); + nameservers = (char **) g_ptr_array_free (rc.nameservers, FALSE); + } else + g_ptr_array_free (rc.nameservers, TRUE); #ifdef RESOLVCONF_PATH success = dispatch_resolvconf (domain, searches, nameservers, iface, error); @@ -518,17 +521,19 @@ rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error) if (success) nm_system_update_dns (); - g_strfreev (searches); - g_strfreev (nameservers); + if (searches) + g_strfreev (searches); + if (nameservers) + g_strfreev (nameservers); return success; } gboolean nm_named_manager_add_ip4_config (NMNamedManager *mgr, - const char *iface, - NMIP4Config *config, - NMNamedIPConfigType cfg_type) + const char *iface, + NMIP4Config *config, + NMNamedIPConfigType cfg_type) { NMNamedManagerPrivate *priv; GError *error = NULL; @@ -564,8 +569,8 @@ nm_named_manager_add_ip4_config (NMNamedManager *mgr, gboolean nm_named_manager_remove_ip4_config (NMNamedManager *mgr, - const char *iface, - NMIP4Config *config) + const char *iface, + NMIP4Config *config) { NMNamedManagerPrivate *priv; GError *error = NULL; @@ -588,6 +593,66 @@ nm_named_manager_remove_ip4_config (NMNamedManager *mgr, if (config == priv->device_config) priv->device_config = NULL; + g_object_unref (config); + + if (!rewrite_resolv_conf (mgr, iface, &error)) { + nm_warning ("Could not commit DNS changes. Error: '%s'", error ? error->message : "(none)"); + if (error) + g_error_free (error); + } + + return TRUE; +} + +gboolean +nm_named_manager_add_ip6_config (NMNamedManager *mgr, + const char *iface, + NMIP6Config *config, + NMNamedIPConfigType cfg_type) +{ + NMNamedManagerPrivate *priv; + GError *error = NULL; + + g_return_val_if_fail (mgr != NULL, FALSE); + 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); + + /* 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)); + + if (!rewrite_resolv_conf (mgr, iface, &error)) { + nm_warning ("Could not commit DNS changes. Error: '%s'", error ? error->message : "(none)"); + g_error_free (error); + } + + return TRUE; +} + +gboolean +nm_named_manager_remove_ip6_config (NMNamedManager *mgr, + const char *iface, + NMIP6Config *config) +{ + NMNamedManagerPrivate *priv; + GError *error = NULL; + + g_return_val_if_fail (mgr != NULL, FALSE); + g_return_val_if_fail (iface != NULL, FALSE); + g_return_val_if_fail (config != NULL, FALSE); + + priv = NM_NAMED_MANAGER_GET_PRIVATE (mgr); + + /* Can't remove it if it wasn't in the list to begin with */ + if (!g_slist_find (priv->configs, config)) + return FALSE; + + priv->configs = g_slist_remove (priv->configs, config); + g_object_unref (config); if (!rewrite_resolv_conf (mgr, iface, &error)) { diff --git a/src/named-manager/nm-named-manager.h b/src/named-manager/nm-named-manager.h index 2b5b64757..47c8e7115 100644 --- a/src/named-manager/nm-named-manager.h +++ b/src/named-manager/nm-named-manager.h @@ -28,6 +28,7 @@ #include #include #include "nm-ip4-config.h" +#include "nm-ip6-config.h" typedef enum { NM_NAMED_MANAGER_ERROR_SYSTEM, @@ -69,13 +70,22 @@ GType nm_named_manager_get_type (void); NMNamedManager * nm_named_manager_get (void); gboolean nm_named_manager_add_ip4_config (NMNamedManager *mgr, - const char *iface, + const char *iface, NMIP4Config *config, NMNamedIPConfigType cfg_type); gboolean nm_named_manager_remove_ip4_config (NMNamedManager *mgr, - const char *iface, - NMIP4Config *config); + const char *iface, + NMIP4Config *config); + +gboolean nm_named_manager_add_ip6_config (NMNamedManager *mgr, + const char *iface, + NMIP6Config *config, + NMNamedIPConfigType cfg_type); + +gboolean nm_named_manager_remove_ip6_config (NMNamedManager *mgr, + const char *iface, + NMIP6Config *config); G_END_DECLS diff --git a/src/nm-device-bt.c b/src/nm-device-bt.c index 2517c797b..06a4d8d0f 100644 --- a/src/nm-device-bt.c +++ b/src/nm-device-bt.c @@ -313,7 +313,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, nm_device_set_ip_iface (device, iface); NM_DEVICE_BT_GET_PRIVATE (device)->pending_ip4_config = g_object_ref (config); - nm_device_activate_schedule_stage4_ip_config_get (device); + nm_device_activate_schedule_stage4_ip4_config_get (device); } static void @@ -626,7 +626,7 @@ real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) } static NMActStageReturn -real_act_stage3_ip_config_start (NMDevice *device, NMDeviceStateReason *reason) +real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); NMActStageReturn ret; @@ -634,7 +634,7 @@ real_act_stage3_ip_config_start (NMDevice *device, NMDeviceStateReason *reason) if (priv->bt_type == NM_BT_CAPABILITY_DUN) ret = ppp_stage3_start (device, reason); else - ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip_config_start (device, reason); + ret = NM_DEVICE_CLASS (nm_device_bt_parent_class)->act_stage3_ip4_config_start (device, reason); return ret; } @@ -841,7 +841,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) device_class->connection_secrets_updated = real_connection_secrets_updated; device_class->deactivate_quickly = real_deactivate_quickly; device_class->act_stage2_config = real_act_stage2_config; - device_class->act_stage3_ip_config_start = real_act_stage3_ip_config_start; + device_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start; device_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; device_class->check_connection_compatible = real_check_connection_compatible; diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index 2c68f790d..bdb740ed9 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -1256,7 +1256,7 @@ ppp_ip4_config (NMPPPManager *ppp_manager, nm_device_set_ip_iface (device, iface); NM_DEVICE_ETHERNET_GET_PRIVATE (device)->pending_ip4_config = g_object_ref (config); - nm_device_activate_schedule_stage4_ip_config_get (device); + nm_device_activate_schedule_stage4_ip4_config_get (device); } static NMActStageReturn diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c index 7f287a869..5e72afab9 100644 --- a/src/nm-device-interface.c +++ b/src/nm-device-interface.c @@ -23,6 +23,7 @@ #include "nm-setting-connection.h" #include "nm-device-interface.h" #include "nm-utils.h" +#include "nm-properties-changed-signal.h" #include "nm-device-interface-glue.h" @@ -123,6 +124,14 @@ nm_device_interface_init (gpointer g_iface) DBUS_TYPE_G_OBJECT_PATH, G_PARAM_READWRITE)); + g_object_interface_install_property + (g_iface, + g_param_spec_boxed (NM_DEVICE_INTERFACE_IP6_CONFIG, + "IP6 Config", + "IP6 Config", + DBUS_TYPE_G_OBJECT_PATH, + G_PARAM_READWRITE)); + g_object_interface_install_property (g_iface, g_param_spec_uint (NM_DEVICE_INTERFACE_STATE, @@ -152,7 +161,7 @@ nm_device_interface_init (gpointer g_iface) "Type Description", "Device type description", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT)); /* Signals */ g_signal_new ("state-changed", diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h index 97a95da47..0273c750d 100644 --- a/src/nm-device-interface.h +++ b/src/nm-device-interface.h @@ -48,6 +48,7 @@ typedef enum #define NM_DEVICE_INTERFACE_IP4_ADDRESS "ip4-address" #define NM_DEVICE_INTERFACE_IP4_CONFIG "ip4-config" #define NM_DEVICE_INTERFACE_DHCP4_CONFIG "dhcp4-config" +#define NM_DEVICE_INTERFACE_IP6_CONFIG "ip6-config" #define NM_DEVICE_INTERFACE_STATE "state" #define NM_DEVICE_INTERFACE_DEVICE_TYPE "device-type" /* ugh */ #define NM_DEVICE_INTERFACE_MANAGED "managed" @@ -63,6 +64,7 @@ typedef enum { NM_DEVICE_INTERFACE_PROP_IP4_ADDRESS, NM_DEVICE_INTERFACE_PROP_IP4_CONFIG, NM_DEVICE_INTERFACE_PROP_DHCP4_CONFIG, + NM_DEVICE_INTERFACE_PROP_IP6_CONFIG, NM_DEVICE_INTERFACE_PROP_STATE, NM_DEVICE_INTERFACE_PROP_DEVICE_TYPE, NM_DEVICE_INTERFACE_PROP_MANAGED, diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index 0fbff7424..eefb1366a 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -3022,9 +3022,9 @@ real_act_stage4_get_ip4_config (NMDevice *dev, static NMActStageReturn -real_act_stage4_ip_config_timeout (NMDevice *dev, - NMIP4Config **config, - NMDeviceStateReason *reason) +real_act_stage4_ip4_config_timeout (NMDevice *dev, + NMIP4Config **config, + NMDeviceStateReason *reason) { NMDeviceWifi *self = NM_DEVICE_WIFI (dev); NMAccessPoint *ap = nm_device_wifi_get_activation_ap (self); @@ -3070,7 +3070,7 @@ real_act_stage4_ip_config_timeout (NMDevice *dev, /* For Ad-Hoc networks, chain up to parent to get a Zeroconf IP */ klass = NM_DEVICE_WIFI_GET_CLASS (self); parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); - ret = parent_class->act_stage4_ip_config_timeout (dev, &real_config, reason); + ret = parent_class->act_stage4_ip4_config_timeout (dev, &real_config, reason); } else { /* Non-encrypted network or authentication is enforced by some * entity (AP, RADIUS server, etc), but IP configure failed. Alert @@ -3555,7 +3555,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->act_stage1_prepare = real_act_stage1_prepare; parent_class->act_stage2_config = real_act_stage2_config; parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; - parent_class->act_stage4_ip_config_timeout = real_act_stage4_ip_config_timeout; + parent_class->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout; parent_class->deactivate = real_deactivate; parent_class->deactivate_quickly = real_deactivate_quickly; parent_class->can_interrupt_activation = real_can_interrupt_activation; @@ -3610,7 +3610,8 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) g_param_spec_boolean (NM_DEVICE_WIFI_SCANNING, "Scanning", "Scanning", - 0, G_PARAM_READABLE)); + FALSE, + G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT)); /* Signals */ signals[ACCESS_POINT_ADDED] = diff --git a/src/nm-device.c b/src/nm-device.c index 56634ef8f..53e18f21c 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -47,12 +47,14 @@ #include "nm-utils.h" #include "nm-netlink.h" #include "nm-setting-ip4-config.h" +#include "nm-setting-ip6-config.h" #include "nm-setting-connection.h" #include "nm-dnsmasq-manager.h" #include "nm-dhcp4-config.h" #include "nm-marshal.h" #define NM_ACT_REQUEST_IP4_CONFIG "nm-act-request-ip4-config" +#define NM_ACT_REQUEST_IP6_CONFIG "nm-act-request-ip6-config" static void device_interface_init (NMDeviceInterface *device_interface_class); @@ -86,15 +88,19 @@ typedef struct { gboolean managed; /* whether managed by NM or not */ guint32 ip4_address; - struct in6_addr ip6_address; NMActRequest * act_request; guint act_source_id; gpointer act_source_func; + guint act_source6_id; + gpointer act_source6_func; gulong secrets_updated_id; gulong secrets_failed_id; - /* IP configuration info */ + gboolean ip4_ready; + gboolean ip6_ready; + + /* IP4 configuration info */ NMIP4Config * ip4_config; /* Config from DHCP, PPP, or system config files */ NMDHCPManager * dhcp_manager; guint32 dhcp_timeout; @@ -112,6 +118,9 @@ typedef struct { guint aipd_watch; guint aipd_timeout; guint32 aipd_addr; + + /* IP6 configuration info */ + NMIP6Config *ip6_config; } NMDevicePrivate; static gboolean check_connection_compatible (NMDeviceInterface *device, @@ -124,7 +133,7 @@ static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason static gboolean spec_match_list (NMDeviceInterface *device, const GSList *specs); static NMConnection *connection_match_config (NMDeviceInterface *device, const GSList *connections); -static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self); +static void nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family); static void nm_device_take_down (NMDevice *dev, gboolean wait, NMDeviceStateReason reason); @@ -132,6 +141,7 @@ static gboolean nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no static gboolean nm_device_is_up (NMDevice *self); static gboolean nm_device_set_ip4_config (NMDevice *dev, NMIP4Config *config, NMDeviceStateReason *reason); +static gboolean nm_device_set_ip6_config (NMDevice *dev, NMIP6Config *config, NMDeviceStateReason *reason); static void device_interface_init (NMDeviceInterface *device_interface_class) @@ -152,7 +162,6 @@ nm_device_init (NMDevice *self) priv->type = NM_DEVICE_TYPE_UNKNOWN; priv->capabilities = NM_DEVICE_CAP_NONE; - memset (&priv->ip6_address, 0, sizeof (struct in6_addr)); priv->state = NM_DEVICE_STATE_UNMANAGED; priv->dhcp_timeout = 0; } @@ -441,24 +450,44 @@ dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer us } static void -activation_source_clear (NMDevice *self, gboolean remove_source) +activation_source_clear (NMDevice *self, gboolean remove_source, int family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + guint *act_source_id; + gpointer *act_source_func; - if (priv->act_source_id) { + if (family == AF_INET6) { + act_source_id = &priv->act_source6_id; + act_source_func = &priv->act_source6_func; + } else { + act_source_id = &priv->act_source_id; + act_source_func = &priv->act_source_func; + } + + if (*act_source_id) { if (remove_source) - g_source_remove (priv->act_source_id); - priv->act_source_id = 0; - priv->act_source_func = NULL; + g_source_remove (*act_source_id); + *act_source_id = 0; + *act_source_func = NULL; } } static void -activation_source_schedule (NMDevice *self, GSourceFunc func) +activation_source_schedule (NMDevice *self, GSourceFunc func, int family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + guint *act_source_id; + gpointer *act_source_func; - if (priv->act_source_id) + if (family == AF_INET6) { + act_source_id = &priv->act_source6_id; + act_source_func = &priv->act_source6_func; + } else { + act_source_id = &priv->act_source_id; + act_source_func = &priv->act_source_func; + } + + if (*act_source_id) nm_warning ("activation stage already scheduled"); /* Don't bother rescheduling the same function that's about to @@ -466,13 +495,51 @@ activation_source_schedule (NMDevice *self, GSourceFunc func) * streams of associate events before NM has had a chance to process * the first one. */ - if (!priv->act_source_id || (priv->act_source_func != func)) { - activation_source_clear (self, TRUE); - priv->act_source_id = g_idle_add (func, self); - priv->act_source_func = func; + if (!*act_source_id || (*act_source_func != func)) { + activation_source_clear (self, TRUE, family); + *act_source_id = g_idle_add (func, self); + *act_source_func = func; } } +static void +configure_ip6_router_advertisements (NMDevice *dev) +{ + NMActRequest *req; + NMConnection *connection; + const char *iface, *method = NULL; + NMSettingIP6Config *s_ip6; + gboolean accept_ra = TRUE; + char *sysctl_path; + + req = nm_device_get_act_request (dev); + if (!req) + return; + connection = nm_act_request_get_connection (req); + if (!connection) + return; + + 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_IGNORE)) + return; + + if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) + || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) + accept_ra = FALSE; + + iface = nm_device_get_iface (dev); + g_return_if_fail (strchr (iface, '/') == NULL && + strcmp (iface, "all") != 0 && + strcmp (iface, "default") != 0); + + sysctl_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", iface); + nm_utils_do_sysctl (sysctl_path, accept_ra ? "1\n" : "0\n"); + g_free (sysctl_path); +} + /* * nm_device_activate_stage1_device_prepare * @@ -483,17 +550,22 @@ static gboolean nm_device_activate_stage1_device_prepare (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); - const char * iface; + const char *iface; NMActStageReturn ret; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE); + activation_source_clear (self, FALSE, 0); iface = nm_device_get_iface (self); nm_info ("Activation (%s) Stage 1 of 5 (Device Prepare) started...", iface); nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); + /* Ensure that IPv6 Router Advertisement handling is properly + * enabled/disabled before bringing up the interface. + */ + configure_ip6_router_advertisements (self); + ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { goto out; @@ -527,7 +599,7 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_stage1_device_prepare); + activation_source_schedule (self, nm_device_activate_stage1_device_prepare, 0); nm_info ("Activation (%s) Stage 1 of 5 (Device Prepare) scheduled...", nm_device_get_iface (self)); @@ -564,7 +636,7 @@ nm_device_activate_stage2_device_config (gpointer user_data) gboolean no_firmware = FALSE; /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE); + activation_source_clear (self, FALSE, 0); iface = nm_device_get_iface (self); nm_info ("Activation (%s) Stage 2 of 5 (Device Configure) starting...", iface); @@ -614,7 +686,7 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_stage2_device_config); + activation_source_schedule (self, nm_device_activate_stage2_device_config, 0); nm_info ("Activation (%s) Stage 2 of 5 (Device Configure) scheduled...", nm_device_get_iface (self)); @@ -774,7 +846,7 @@ nm_device_handle_autoip4_event (NMDevice *self, priv->aipd_addr = ip.s_addr; aipd_timeout_remove (self); - nm_device_activate_schedule_stage4_ip_config_get (self); + nm_device_activate_schedule_stage4_ip4_config_get (self); break; case NM_DEVICE_STATE_ACTIVATED: priv->aipd_addr = ip.s_addr; @@ -839,7 +911,7 @@ aipd_timeout_cb (gpointer user_data) aipd_cleanup (self); if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG) - nm_device_activate_schedule_stage4_ip_config_timeout (self); + nm_device_activate_schedule_stage4_ip4_config_timeout (self); return FALSE; } @@ -904,7 +976,7 @@ aipd_exec (NMDevice *self, GError **error) } static NMActStageReturn -real_act_stage3_ip_config_start (NMDevice *self, NMDeviceStateReason *reason) +real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason) { NMConnection *connection; NMSettingConnection *s_con; @@ -978,39 +1050,54 @@ real_act_stage3_ip_config_start (NMDevice *self, NMDeviceStateReason *reason) return ret; } +static NMActStageReturn +real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason) +{ + return NM_ACT_STAGE_RETURN_SUCCESS; +} + /* * nm_device_activate_stage3_ip_config_start * - * Begin IP configuration with either DHCP or static IP. + * Begin automatic/manual IP configuration * */ static gboolean nm_device_activate_stage3_ip_config_start (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const char *iface; NMActStageReturn ret; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE); + activation_source_clear (self, FALSE, 0); + + priv->ip4_ready = priv->ip6_ready = FALSE; iface = nm_device_get_iface (self); nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) started...", iface); nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); - ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip_config_start (self, &reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - goto out; - else if (ret == NM_ACT_STAGE_RETURN_FAILURE) - { + ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &reason); + if (ret == NM_ACT_STAGE_RETURN_SUCCESS) + nm_device_activate_schedule_stage4_ip4_config_get (self); + else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; - } - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + } else + g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); - nm_device_activate_schedule_stage4_ip_config_get (self); + ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &reason); + if (ret == NM_ACT_STAGE_RETURN_SUCCESS) + nm_device_activate_schedule_stage4_ip6_config_get (self); + else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + goto out; + } else + g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); out: nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) complete.", iface); @@ -1033,7 +1120,7 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_stage3_ip_config_start); + activation_source_schedule (self, nm_device_activate_stage3_ip_config_start, 0); nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) scheduled.", nm_device_get_iface (self)); @@ -1174,15 +1261,14 @@ real_act_stage4_get_ip4_config (NMDevice *self, return ret; } - /* - * nm_device_activate_stage4_ip_config_get + * nm_device_activate_stage4_ip4_config_get * - * Retrieve the correct IP config. + * Retrieve the correct IPv4 config. * */ static gboolean -nm_device_activate_stage4_ip_config_get (gpointer user_data) +nm_device_activate_stage4_ip4_config_get (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMIP4Config *ip4_config = NULL; @@ -1191,10 +1277,10 @@ nm_device_activate_stage4_ip_config_get (gpointer user_data) NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE); + activation_source_clear (self, FALSE, AF_INET); iface = nm_device_get_iface (self); - nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Get) started...", iface); + nm_info ("Activation (%s) Stage 4 of 5 (IP4 Configure Get) started...", iface); ret = NM_DEVICE_GET_CLASS (self)->act_stage4_get_ip4_config (self, &ip4_config, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) @@ -1209,22 +1295,22 @@ nm_device_activate_stage4_ip_config_get (gpointer user_data) g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), NM_ACT_REQUEST_IP4_CONFIG, ip4_config); - nm_device_activate_schedule_stage5_ip_config_commit (self); + nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET); out: - nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Get) complete.", iface); + nm_info ("Activation (%s) Stage 4 of 5 (IP4 Configure Get) complete.", iface); return FALSE; } /* - * nm_device_activate_schedule_stage4_ip_config_get + * nm_device_activate_schedule_stage4_ip4_config_get * - * Schedule creation of the IP config + * Schedule creation of the IPv4 config * */ void -nm_device_activate_schedule_stage4_ip_config_get (NMDevice *self) +nm_device_activate_schedule_stage4_ip4_config_get (NMDevice *self) { NMDevicePrivate *priv; @@ -1233,17 +1319,17 @@ nm_device_activate_schedule_stage4_ip_config_get (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_stage4_ip_config_get); + activation_source_schedule (self, nm_device_activate_stage4_ip4_config_get, AF_INET); - nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Get) scheduled...", + nm_info ("Activation (%s) Stage 4 of 5 (IP4 Configure Get) scheduled...", nm_device_get_iface (self)); } static NMActStageReturn -real_act_stage4_ip_config_timeout (NMDevice *self, - NMIP4Config **config, - NMDeviceStateReason *reason) +real_act_stage4_ip4_config_timeout (NMDevice *self, + NMIP4Config **config, + NMDeviceStateReason *reason) { g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE); @@ -1258,13 +1344,13 @@ real_act_stage4_ip_config_timeout (NMDevice *self, /* - * nm_device_activate_stage4_ip_config_timeout + * nm_device_activate_stage4_ip4_config_timeout * - * Retrieve the correct IP config. + * Time out on retrieving the IPv4 config. * */ static gboolean -nm_device_activate_stage4_ip_config_timeout (gpointer user_data) +nm_device_activate_stage4_ip4_config_timeout (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMIP4Config *ip4_config = NULL; @@ -1273,12 +1359,12 @@ nm_device_activate_stage4_ip_config_timeout (gpointer user_data) NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE); + activation_source_clear (self, FALSE, AF_INET); iface = nm_device_get_iface (self); - nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Timeout) started...", iface); + nm_info ("Activation (%s) Stage 4 of 5 (IP4 Configure Timeout) started...", iface); - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip_config_timeout (self, &ip4_config, &reason); + ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &ip4_config, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { goto out; } else if (!ip4_config || (ret == NM_ACT_STAGE_RETURN_FAILURE)) { @@ -1291,22 +1377,22 @@ nm_device_activate_stage4_ip_config_timeout (gpointer user_data) g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), NM_ACT_REQUEST_IP4_CONFIG, ip4_config); - nm_device_activate_schedule_stage5_ip_config_commit (self); + nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET); out: - nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Timeout) complete.", iface); + nm_info ("Activation (%s) Stage 4 of 5 (IP4 Configure Timeout) complete.", iface); return FALSE; } /* - * nm_device_activate_schedule_stage4_ip_config_timeout + * nm_device_activate_schedule_stage4_ip4_config_timeout * - * Deal with a timeout of the IP configuration + * Deal with a timeout of the IPv4 configuration * */ void -nm_device_activate_schedule_stage4_ip_config_timeout (NMDevice *self) +nm_device_activate_schedule_stage4_ip4_config_timeout (NMDevice *self) { NMDevicePrivate *priv; @@ -1315,9 +1401,192 @@ nm_device_activate_schedule_stage4_ip_config_timeout (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_stage4_ip_config_timeout); + activation_source_schedule (self, nm_device_activate_stage4_ip4_config_timeout, AF_INET); - nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Timeout) scheduled...", + nm_info ("Activation (%s) Stage 4 of 5 (IP4 Configure Timeout) scheduled...", + nm_device_get_iface (self)); +} + +static NMActStageReturn +real_act_stage4_get_ip6_config (NMDevice *self, + NMIP6Config **config, + NMDeviceStateReason *reason) +{ + NMConnection *connection; + NMSettingIP6Config *s_ip6; + const char *ip_iface; + const char *method = NULL; + + g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + /* Use the IP interface (not the control interface) for IP stuff */ + ip_iface = nm_device_get_ip_iface (self); + + connection = nm_act_request_get_connection (nm_device_get_act_request (self)); + g_assert (connection); + + s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6) + method = nm_setting_ip6_config_get_method (s_ip6); + + if (!method || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + *config = NULL; + return NM_ACT_STAGE_RETURN_SUCCESS; + } + + *config = nm_ip6_config_new (); + if (!*config) { + *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + return NM_ACT_STAGE_RETURN_FAILURE; + } + + if (!strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + nm_utils_merge_ip6_config (*config, s_ip6); + + return NM_ACT_STAGE_RETURN_SUCCESS; +} + +/* + * nm_device_activate_stage4_ip6_config_get + * + * Retrieve the correct IPv6 config. + * + */ +static gboolean +nm_device_activate_stage4_ip6_config_get (gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + NMIP6Config *ip6_config = NULL; + NMActStageReturn ret; + const char *iface = NULL; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + + /* Clear the activation source ID now that this stage has run */ + activation_source_clear (self, FALSE, AF_INET6); + + iface = nm_device_get_iface (self); + nm_info ("Activation (%s) Stage 4 of 5 (IP6 Configure Get) started...", iface); + + ret = NM_DEVICE_GET_CLASS (self)->act_stage4_get_ip6_config (self, &ip6_config, &reason); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) + goto out; + else if (ret == NM_ACT_STAGE_RETURN_FAILURE) + { + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + goto out; + } + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + + g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), + NM_ACT_REQUEST_IP6_CONFIG, ip6_config); + + nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET6); + +out: + nm_info ("Activation (%s) Stage 4 of 5 (IP6 Configure Get) complete.", iface); + return FALSE; +} + + +/* + * nm_device_activate_schedule_stage4_ip6_config_get + * + * Schedule creation of the IPv6 config + * + */ +void +nm_device_activate_schedule_stage4_ip6_config_get (NMDevice *self) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + g_return_if_fail (priv->act_request); + + activation_source_schedule (self, nm_device_activate_stage4_ip6_config_get, AF_INET6); + + nm_info ("Activation (%s) Stage 4 of 5 (IP6 Configure Get) scheduled...", + nm_device_get_iface (self)); +} + + +static NMActStageReturn +real_act_stage4_ip6_config_timeout (NMDevice *self, + NMIP6Config **config, + NMDeviceStateReason *reason) +{ + g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE); + + *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; + return NM_ACT_STAGE_RETURN_FAILURE; +} + + +/* + * nm_device_activate_stage4_ip6_config_timeout + * + * Time out on retrieving the IPv6 config. + * + */ +static gboolean +nm_device_activate_stage4_ip6_config_timeout (gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + NMIP6Config *ip6_config = NULL; + const char *iface; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + + /* Clear the activation source ID now that this stage has run */ + activation_source_clear (self, FALSE, AF_INET6); + + iface = nm_device_get_iface (self); + nm_info ("Activation (%s) Stage 4 of 5 (IP6 Configure Timeout) started...", iface); + + ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &ip6_config, &reason); + if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { + goto out; + } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + goto out; + } + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + /* FIXME g_assert (ip6_config); */ + + g_object_set_data (G_OBJECT (nm_device_get_act_request (self)), + NM_ACT_REQUEST_IP6_CONFIG, ip6_config); + + nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET6); + +out: + nm_info ("Activation (%s) Stage 4 of 5 (IP6 Configure Timeout) complete.", iface); + return FALSE; +} + + +/* + * nm_device_activate_schedule_stage4_ip6_config_timeout + * + * Deal with a timeout of the IPv6 configuration + * + */ +void +nm_device_activate_schedule_stage4_ip6_config_timeout (NMDevice *self) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + g_return_if_fail (priv->act_request); + + activation_source_schedule (self, nm_device_activate_stage4_ip6_config_timeout, AF_INET6); + + nm_info ("Activation (%s) Stage 4 of 5 (IP6 Configure Timeout) scheduled...", nm_device_get_iface (self)); } @@ -1332,31 +1601,21 @@ share_child_setup (gpointer user_data G_GNUC_UNUSED) static gboolean share_init (void) { - int fd, count, status; + int status; char *modules[] = { "ip_tables", "iptable_nat", "nf_nat_ftp", "nf_nat_irc", "nf_nat_sip", "nf_nat_tftp", "nf_nat_pptp", "nf_nat_h323", NULL }; char **iter; - fd = open ("/proc/sys/net/ipv4/ip_forward", O_WRONLY | O_TRUNC); - if (fd) { - count = write (fd, "1\n", 2); - if (count != 2) { - nm_warning ("%s: Error starting IP forwarding: (%d) %s", - __func__, errno, strerror (errno)); - return FALSE; - } - close (fd); + if (!nm_utils_do_sysctl ("/proc/sys/net/ipv4/ip_forward", "1\n")) { + nm_warning ("%s: Error starting IP forwarding: (%d) %s", + __func__, errno, strerror (errno)); + return FALSE; } - fd = open ("/proc/sys/net/ipv4/ip_dynaddr", O_WRONLY | O_TRUNC); - if (fd) { - count = write (fd, "1\n", 2); - if (count != 2) { - nm_warning ("%s: Error starting IP forwarding: (%d) %s", - __func__, errno, strerror (errno)); - } - close (fd); + if (!nm_utils_do_sysctl ("/proc/sys/net/ipv4/ip_dynaddr", "1\n")) { + nm_warning ("%s: Error starting IP forwarding: (%d) %s", + __func__, errno, strerror (errno)); } for (iter = modules; *iter; iter++) { @@ -1466,6 +1725,7 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMIP4Config *ip4_config = NULL; + NMIP6Config *ip6_config = NULL; const char *iface, *method = NULL; NMConnection *connection; NMSettingIP4Config *s_ip4; @@ -1474,9 +1734,12 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data) ip4_config = g_object_get_data (G_OBJECT (nm_device_get_act_request (self)), NM_ACT_REQUEST_IP4_CONFIG); g_assert (ip4_config); + ip6_config = g_object_get_data (G_OBJECT (nm_device_get_act_request (self)), + NM_ACT_REQUEST_IP6_CONFIG); + /* FIXME g_assert (ip6_config); */ /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE); + activation_source_clear (self, FALSE, 0); iface = nm_device_get_iface (self); nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) started...", @@ -1487,6 +1750,11 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data) goto out; } + if (!nm_device_set_ip6_config (self, ip6_config, &reason)) { + nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) IPv6 failed", + iface); + } + connection = nm_act_request_get_connection (nm_device_get_act_request (self)); s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); if (s_ip4) @@ -1506,8 +1774,9 @@ out: nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) complete.", iface); - /* Balance IP4Config creation; device takes ownership in set_ip4_config() */ + /* Balance IP config creation; device takes ownership in set_ip*_config() */ g_object_unref (ip4_config); + g_object_unref (ip6_config); return FALSE; } @@ -1519,7 +1788,7 @@ out: * Schedule commit of the IP config */ static void -nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self) +nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family) { NMDevicePrivate *priv; @@ -1528,7 +1797,15 @@ nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_stage5_ip_config_commit); + if (family == AF_INET) + priv->ip4_ready = TRUE; + else if (family == AF_INET6) + priv->ip6_ready = TRUE; + + if (!priv->ip4_ready || !priv->ip6_ready) + return; + + activation_source_schedule (self, nm_device_activate_stage5_ip_config_commit, 0); nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) scheduled...", nm_device_get_iface (self)); @@ -1583,7 +1860,8 @@ nm_device_deactivate_quickly (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); /* Break the activation chain */ - activation_source_clear (self, TRUE); + activation_source_clear (self, TRUE, AF_INET); + activation_source_clear (self, TRUE, AF_INET6); if (priv->failed_to_disconnected_id) { g_source_remove (priv->failed_to_disconnected_id); @@ -1643,10 +1921,11 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason) /* Clean up nameservers and addresses */ nm_device_set_ip4_config (self, NULL, &ignored); + nm_device_set_ip6_config (self, NULL, &ignored); /* Take out any entries in the routing table and any IP address the device had. */ - nm_system_device_flush_ip4_routes (self); - nm_system_device_flush_ip4_addresses (self); + nm_system_device_flush_routes (self); + nm_system_device_flush_addresses (self); nm_device_update_ip4_address (self); /* Call device type-specific deactivation */ @@ -1875,7 +2154,7 @@ dhcp_state_changed (NMDHCPManager *dhcp_manager, case DHC_REBOOT: /* have valid lease, but now obtained a different one */ case DHC_REBIND: /* new, different lease */ if (dev_state == NM_DEVICE_STATE_IP_CONFIG) - nm_device_activate_schedule_stage4_ip_config_get (device); + nm_device_activate_schedule_stage4_ip4_config_get (device); else if (dev_state == NM_DEVICE_STATE_ACTIVATED) handle_dhcp_lease_change (device); break; @@ -1883,7 +2162,7 @@ dhcp_state_changed (NMDHCPManager *dhcp_manager, nm_dhcp4_config_reset (priv->dhcp4_config); if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) - nm_device_activate_schedule_stage4_ip_config_timeout (device); + nm_device_activate_schedule_stage4_ip4_config_timeout (device); break; case DHC_FAIL: /* all attempts to contact server timed out, sleeping */ case DHC_ABEND: /* dhclient exited abnormally */ @@ -1915,7 +2194,7 @@ dhcp_timeout (NMDHCPManager *dhcp_manager, return; if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) - nm_device_activate_schedule_stage4_ip_config_timeout (device); + nm_device_activate_schedule_stage4_ip4_config_timeout (device); } gboolean @@ -2051,7 +2330,6 @@ nm_device_set_ip4_config (NMDevice *self, return success; } - /* * nm_device_get_ip4_address * @@ -2092,6 +2370,69 @@ nm_device_update_ip4_address (NMDevice *self) close (fd); } +static gboolean +nm_device_set_ip6_config (NMDevice *self, + NMIP6Config *new_config, + NMDeviceStateReason *reason) +{ + NMDevicePrivate *priv; + const char *ip_iface; + NMIP6Config *old_config = NULL; + gboolean success = TRUE; + NMIP6ConfigCompareFlags diff = NM_IP6_COMPARE_FLAG_ALL; + NMNamedManager *named_mgr; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (reason != NULL, FALSE); + + priv = NM_DEVICE_GET_PRIVATE (self); + ip_iface = nm_device_get_ip_iface (self); + + old_config = priv->ip6_config; + + if (new_config && old_config) + diff = nm_ip6_config_diff (new_config, old_config); + + /* No actual change, do nothing */ + if (diff == NM_IP6_COMPARE_FLAG_NONE) + return TRUE; + + named_mgr = nm_named_manager_get (); + if (old_config) { + /* Remove any previous IP6 Config from the named manager */ + nm_named_manager_remove_ip6_config (named_mgr, ip_iface, old_config); + g_object_unref (old_config); + priv->ip6_config = NULL; + } + + if (new_config) { + priv->ip6_config = g_object_ref (new_config); + + success = nm_system_apply_ip6_config (ip_iface, new_config, nm_device_get_priority (self), diff); + if (success) { + /* Export over D-Bus */ + if (!nm_ip6_config_get_dbus_path (new_config)) + nm_ip6_config_export (new_config); + + /* Add the DNS information to the named manager */ + nm_named_manager_add_ip6_config (named_mgr, ip_iface, new_config, NM_NAMED_IP_CONFIG_TYPE_DEFAULT); + } + } + g_object_unref (named_mgr); + + g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_IP6_CONFIG); + + return success; +} + +NMIP6Config * +nm_device_get_ip6_config (NMDevice *self) +{ + g_return_val_if_fail (self != NULL, NULL); + + return NM_DEVICE_GET_PRIVATE (self)->ip6_config; +} + static gboolean nm_device_is_up (NMDevice *self) { @@ -2251,7 +2592,8 @@ dispose (GObject *object) clear_act_request (self); - activation_source_clear (self, TRUE); + activation_source_clear (self, TRUE, AF_INET); + activation_source_clear (self, TRUE, AF_INET6); if (!take_down) nm_device_set_use_dhcp (self, FALSE); @@ -2372,6 +2714,15 @@ get_property (GObject *object, guint prop_id, else g_value_set_boxed (value, "/"); break; + case NM_DEVICE_INTERFACE_PROP_IP6_CONFIG: + if ((state == NM_DEVICE_STATE_ACTIVATED) || (state == NM_DEVICE_STATE_IP_CONFIG)) { + if (priv->ip6_config) { + g_value_set_boxed (value, nm_ip6_config_get_dbus_path (priv->ip6_config)); + break; + } + } + g_value_set_boxed (value, "/"); + break; case NM_DEVICE_INTERFACE_PROP_STATE: g_value_set_uint (value, priv->state); break; @@ -2409,9 +2760,12 @@ nm_device_class_init (NMDeviceClass *klass) klass->get_generic_capabilities = real_get_generic_capabilities; klass->act_stage1_prepare = real_act_stage1_prepare; klass->act_stage2_config = real_act_stage2_config; - klass->act_stage3_ip_config_start = real_act_stage3_ip_config_start; + klass->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start; + klass->act_stage3_ip6_config_start = real_act_stage3_ip6_config_start; klass->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; - klass->act_stage4_ip_config_timeout = real_act_stage4_ip_config_timeout; + klass->act_stage4_get_ip6_config = real_act_stage4_get_ip6_config; + klass->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout; + klass->act_stage4_ip6_config_timeout = real_act_stage4_ip6_config_timeout; /* Properties */ @@ -2443,6 +2797,10 @@ nm_device_class_init (NMDeviceClass *klass) NM_DEVICE_INTERFACE_PROP_DHCP4_CONFIG, NM_DEVICE_INTERFACE_DHCP4_CONFIG); + g_object_class_override_property (object_class, + NM_DEVICE_INTERFACE_PROP_IP6_CONFIG, + NM_DEVICE_INTERFACE_IP6_CONFIG); + g_object_class_override_property (object_class, NM_DEVICE_INTERFACE_PROP_STATE, NM_DEVICE_INTERFACE_STATE); diff --git a/src/nm-device.h b/src/nm-device.h index f3d63235e..d06375cc6 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -29,6 +29,7 @@ #include "NetworkManager.h" #include "nm-activation-request.h" #include "nm-ip4-config.h" +#include "nm-ip6-config.h" #include "nm-dhcp4-config.h" #include "nm-connection.h" @@ -92,14 +93,22 @@ typedef struct { NMDeviceStateReason *reason); NMActStageReturn (* act_stage2_config) (NMDevice *self, NMDeviceStateReason *reason); - NMActStageReturn (* act_stage3_ip_config_start) (NMDevice *self, - NMDeviceStateReason *reason); + NMActStageReturn (* act_stage3_ip4_config_start) (NMDevice *self, + NMDeviceStateReason *reason); + NMActStageReturn (* act_stage3_ip6_config_start) (NMDevice *self, + NMDeviceStateReason *reason); NMActStageReturn (* act_stage4_get_ip4_config) (NMDevice *self, NMIP4Config **config, NMDeviceStateReason *reason); - NMActStageReturn (* act_stage4_ip_config_timeout) (NMDevice *self, + NMActStageReturn (* act_stage4_get_ip6_config) (NMDevice *self, + NMIP6Config **config, + NMDeviceStateReason *reason); + NMActStageReturn (* act_stage4_ip4_config_timeout) (NMDevice *self, NMIP4Config **config, NMDeviceStateReason *reason); + NMActStageReturn (* act_stage4_ip6_config_timeout) (NMDevice *self, + NMIP6Config **config, + NMDeviceStateReason *reason); void (* deactivate) (NMDevice *self); void (* deactivate_quickly) (NMDevice *self); @@ -130,7 +139,6 @@ int nm_device_get_priority (NMDevice *dev); guint32 nm_device_get_ip4_address (NMDevice *dev); void nm_device_update_ip4_address (NMDevice *dev); -struct in6_addr * nm_device_get_ip6_address (NMDevice *dev); gboolean nm_device_get_use_dhcp (NMDevice *dev); void nm_device_set_use_dhcp (NMDevice *dev, @@ -138,6 +146,7 @@ void nm_device_set_use_dhcp (NMDevice *dev, NMDHCP4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMIP4Config * nm_device_get_ip4_config (NMDevice *dev); +NMIP6Config * nm_device_get_ip6_config (NMDevice *dev); void * nm_device_get_system_config_data (NMDevice *dev); @@ -151,8 +160,10 @@ NMConnection * nm_device_get_best_auto_connection (NMDevice *dev, void nm_device_activate_schedule_stage1_device_prepare (NMDevice *device); void nm_device_activate_schedule_stage2_device_config (NMDevice *device); -void nm_device_activate_schedule_stage4_ip_config_get (NMDevice *device); -void nm_device_activate_schedule_stage4_ip_config_timeout (NMDevice *device); +void nm_device_activate_schedule_stage4_ip4_config_get (NMDevice *device); +void nm_device_activate_schedule_stage4_ip4_config_timeout (NMDevice *device); +void nm_device_activate_schedule_stage4_ip6_config_get (NMDevice *device); +void nm_device_activate_schedule_stage4_ip6_config_timeout (NMDevice *device); gboolean nm_device_deactivate_quickly (NMDevice *dev); gboolean nm_device_is_activating (NMDevice *dev); gboolean nm_device_can_interrupt_activation (NMDevice *self); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c new file mode 100644 index 000000000..990ba3df3 --- /dev/null +++ b/src/nm-ip6-config.c @@ -0,0 +1,726 @@ +/* -*- 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 - 2008 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#include +#include +#include +#include "nm-ip6-config.h" +#include "nm-dbus-manager.h" +#include "NetworkManager.h" +#include "NetworkManagerUtils.h" +#include "nm-setting-ip6-config.h" +#include "nm-utils.h" + +#include +#include +#include + +#include "nm-ip6-config-glue.h" +#include "nm-dbus-glib-types.h" + + +G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, G_TYPE_OBJECT) + +#define NM_IP6_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_CONFIG, NMIP6ConfigPrivate)) + +typedef struct { + char *path; + + GSList *addresses; + struct in6_addr ptp_address; + + guint32 mss; /* Maximum Segment Size of the route */ + + GArray *nameservers; + GPtrArray *domains; + GPtrArray *searches; + + GSList *routes; + + gboolean never_default; +} NMIP6ConfigPrivate; + + +enum { + PROP_0, + PROP_ADDRESSES, + PROP_NAMESERVERS, + PROP_DOMAINS, + PROP_ROUTES, + + LAST_PROP +}; + + +static struct nl_addr * +nm_utils_ip6_addr_to_nl_addr (const struct in6_addr *ip6_addr) +{ + struct nl_addr * nla = NULL; + + if (!(nla = nl_addr_alloc (sizeof (struct in6_addr)))) + return NULL; + nl_addr_set_family (nla, AF_INET6); + nl_addr_set_binary_addr (nla, (struct in6_addr *)ip6_addr, sizeof (struct in6_addr)); + + return nla; +} + + +NMIP6Config * +nm_ip6_config_new (void) +{ + return (NMIP6Config *) g_object_new (NM_TYPE_IP6_CONFIG, NULL); +} + +void +nm_ip6_config_export (NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv; + NMDBusManager *dbus_mgr; + DBusGConnection *connection; + static guint32 counter = 0; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + g_return_if_fail (priv->path == NULL); + + dbus_mgr = nm_dbus_manager_get (); + connection = nm_dbus_manager_get_connection (dbus_mgr); + priv->path = g_strdup_printf (NM_DBUS_PATH "/IP6Config/%d", counter++); + + dbus_g_connection_register_g_object (connection, priv->path, G_OBJECT (config)); + g_object_unref (dbus_mgr); +} + +const char * +nm_ip6_config_get_dbus_path (NMIP6Config *config) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), FALSE); + + return NM_IP6_CONFIG_GET_PRIVATE (config)->path; +} + +void +nm_ip6_config_take_address (NMIP6Config *config, NMIP6Address *address) +{ + NMIP6ConfigPrivate *priv; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + g_return_if_fail (address != NULL); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + priv->addresses = g_slist_append (priv->addresses, address); +} + +void +nm_ip6_config_add_address (NMIP6Config *config, + NMIP6Address *address) +{ + NMIP6ConfigPrivate *priv; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + g_return_if_fail (address != NULL); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + priv->addresses = g_slist_append (priv->addresses, nm_ip6_address_dup (address)); +} + +void +nm_ip6_config_replace_address (NMIP6Config *config, + guint i, + NMIP6Address *new_address) +{ + NMIP6ConfigPrivate *priv; + GSList *old; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + old = g_slist_nth (priv->addresses, i); + g_return_if_fail (old != NULL); + nm_ip6_address_unref ((NMIP6Address *) old->data); + + old->data = nm_ip6_address_dup (new_address); +} + +NMIP6Address *nm_ip6_config_get_address (NMIP6Config *config, guint i) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL); + + return (NMIP6Address *) g_slist_nth_data (NM_IP6_CONFIG_GET_PRIVATE (config)->addresses, i); +} + +guint32 nm_ip6_config_get_num_addresses (NMIP6Config *config) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0); + + return g_slist_length (NM_IP6_CONFIG_GET_PRIVATE (config)->addresses); +} + +const struct in6_addr *nm_ip6_config_get_ptp_address (NMIP6Config *config) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0); + + return &NM_IP6_CONFIG_GET_PRIVATE (config)->ptp_address; +} + +void nm_ip6_config_set_ptp_address (NMIP6Config *config, struct in6_addr *ptp_addr) +{ + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + NM_IP6_CONFIG_GET_PRIVATE (config)->ptp_address = *ptp_addr; +} + +void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver) +{ + NMIP6ConfigPrivate *priv; + struct in6_addr *nameservers; + int i; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + g_return_if_fail (nameserver > 0); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + /* No dupes */ + nameservers = (struct in6_addr *)priv->nameservers->data; + for (i = 0; i < priv->nameservers->len; i++) { + g_return_if_fail (memcmp (nameserver, &nameservers[i], sizeof (struct in6_addr)) == 0); + } + + g_array_append_val (priv->nameservers, *nameserver); +} + +const struct in6_addr *nm_ip6_config_get_nameserver (NMIP6Config *config, guint i) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0); + + return &g_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->nameservers, struct in6_addr, i); +} + +guint32 nm_ip6_config_get_num_nameservers (NMIP6Config *config) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0); + + return NM_IP6_CONFIG_GET_PRIVATE (config)->nameservers->len; +} + +void nm_ip6_config_reset_nameservers (NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + if (priv->nameservers->len) + g_array_remove_range (priv->nameservers, 0, priv->nameservers->len); +} + +void +nm_ip6_config_take_route (NMIP6Config *config, NMIP6Route *route) +{ + NMIP6ConfigPrivate *priv; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + g_return_if_fail (route != NULL); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + priv->routes = g_slist_append (priv->routes, route); +} + +void +nm_ip6_config_add_route (NMIP6Config *config, NMIP6Route *route) +{ + NMIP6ConfigPrivate *priv; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + g_return_if_fail (route != NULL); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + priv->routes = g_slist_append (priv->routes, nm_ip6_route_dup (route)); +} + +void +nm_ip6_config_replace_route (NMIP6Config *config, + guint i, + NMIP6Route *new_route) +{ + NMIP6ConfigPrivate *priv; + GSList *old; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + old = g_slist_nth (priv->routes, i); + g_return_if_fail (old != NULL); + nm_ip6_route_unref ((NMIP6Route *) old->data); + + old->data = nm_ip6_route_dup (new_route); +} + +NMIP6Route * +nm_ip6_config_get_route (NMIP6Config *config, guint i) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL); + + return (NMIP6Route *) g_slist_nth_data (NM_IP6_CONFIG_GET_PRIVATE (config)->routes, i); +} + +guint32 nm_ip6_config_get_num_routes (NMIP6Config *config) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0); + + return g_slist_length (NM_IP6_CONFIG_GET_PRIVATE (config)->routes); +} + +void nm_ip6_config_reset_routes (NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + g_slist_foreach (priv->routes, (GFunc) g_free, NULL); + priv->routes = NULL; +} + +void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain) +{ + NMIP6ConfigPrivate *priv; + int i; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + g_return_if_fail (domain != NULL); + g_return_if_fail (strlen (domain) > 0); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + for (i = 0; i < priv->domains->len; i++) { + if (!strcmp (g_ptr_array_index (priv->domains, i), domain)) + return; + } + + g_ptr_array_add (priv->domains, g_strdup (domain)); +} + +const char *nm_ip6_config_get_domain (NMIP6Config *config, guint i) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL); + + return (const char *) g_ptr_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->domains, i); +} + +guint32 nm_ip6_config_get_num_domains (NMIP6Config *config) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0); + + return NM_IP6_CONFIG_GET_PRIVATE (config)->domains->len; +} + +void nm_ip6_config_reset_domains (NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv; + int i; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + for (i = 0; i < priv->domains->len; i++) + g_free (g_ptr_array_index (priv->domains, i)); + g_ptr_array_free (priv->domains, TRUE); + priv->domains = g_ptr_array_sized_new (3); +} + +void nm_ip6_config_add_search (NMIP6Config *config, const char *search) +{ + NMIP6ConfigPrivate *priv; + int i; + + g_return_if_fail (config != NULL); + g_return_if_fail (search != NULL); + g_return_if_fail (strlen (search) > 0); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + for (i = 0; i < priv->searches->len; i++) { + if (!strcmp (g_ptr_array_index (priv->searches, i), search)) + return; + } + + g_ptr_array_add (priv->searches, g_strdup (search)); +} + +const char *nm_ip6_config_get_search (NMIP6Config *config, guint i) +{ + g_return_val_if_fail (config != NULL, NULL); + + return (const char *) g_ptr_array_index (NM_IP6_CONFIG_GET_PRIVATE (config)->searches, i); +} + +guint32 nm_ip6_config_get_num_searches (NMIP6Config *config) +{ + g_return_val_if_fail (config != NULL, 0); + + return NM_IP6_CONFIG_GET_PRIVATE (config)->searches->len; +} + +void nm_ip6_config_reset_searches (NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv; + int i; + + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + priv = NM_IP6_CONFIG_GET_PRIVATE (config); + for (i = 0; i < priv->searches->len; i++) + g_free (g_ptr_array_index (priv->searches, i)); + g_ptr_array_free (priv->searches, TRUE); + priv->searches = g_ptr_array_sized_new (3); +} + +guint32 nm_ip6_config_get_mss (NMIP6Config *config) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), 0); + + return NM_IP6_CONFIG_GET_PRIVATE (config)->mss; +} + +void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss) +{ + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + NM_IP6_CONFIG_GET_PRIVATE (config)->mss = mss; +} + +gboolean +nm_ip6_config_get_never_default (NMIP6Config *config) +{ + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), FALSE); + + return NM_IP6_CONFIG_GET_PRIVATE (config)->never_default; +} + +void +nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default) +{ + g_return_if_fail (NM_IS_IP6_CONFIG (config)); + + NM_IP6_CONFIG_GET_PRIVATE (config)->never_default = never_default; +} + +/* libnl convenience/conversion functions */ + +static int ip6_addr_to_rtnl_local (const struct in6_addr *ip6_address, struct rtnl_addr *addr) +{ + struct nl_addr * local = NULL; + int err = 0; + + g_return_val_if_fail (addr != NULL, -1); + + local = nm_utils_ip6_addr_to_nl_addr (ip6_address); + err = rtnl_addr_set_local (addr, local); + nl_addr_put (local); + + return err; +} + +static int ip6_addr_to_rtnl_peer (const struct in6_addr *ip6_address, struct rtnl_addr *addr) +{ + struct nl_addr * peer = NULL; + int err = 0; + + g_return_val_if_fail (addr != NULL, -1); + + peer = nm_utils_ip6_addr_to_nl_addr (ip6_address); + err = rtnl_addr_set_peer (addr, peer); + nl_addr_put (peer); + + return err; +} + +struct rtnl_addr * +nm_ip6_config_to_rtnl_addr (NMIP6Config *config, guint32 i, guint32 flags) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6Address *config_addr; + struct rtnl_addr *addr; + gboolean success = TRUE; + + g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL); + + config_addr = nm_ip6_config_get_address (config, i); + g_return_val_if_fail (config_addr != NULL, NULL); + + if (!(addr = rtnl_addr_alloc())) + return NULL; + + if (flags & NM_RTNL_ADDR_ADDR) + success = (ip6_addr_to_rtnl_local (nm_ip6_address_get_address (config_addr), addr) >= 0); + + if (flags & NM_RTNL_ADDR_PTP_ADDR) + success = (ip6_addr_to_rtnl_peer (&priv->ptp_address, addr) >= 0); + + if (flags & NM_RTNL_ADDR_PREFIX) + rtnl_addr_set_prefixlen (addr, nm_ip6_address_get_prefix (config_addr)); + + if (!success) { + rtnl_addr_put (addr); + addr = NULL; + } + + return addr; +} + +static gboolean +addr_slist_compare (GSList *a, GSList *b) +{ + GSList *iter_a, *iter_b; + gboolean found = FALSE; + + for (iter_a = a; iter_a; iter_a = g_slist_next (iter_a)) { + NMIP6Address *addr_a = (NMIP6Address *) iter_a->data; + + for (iter_b = b, found = FALSE; iter_b; iter_b = g_slist_next (iter_b)) { + NMIP6Address *addr_b = (NMIP6Address *) iter_b->data; + + if (nm_ip6_address_compare (addr_a, addr_b)) { + found = TRUE; + break; + } + } + + if (!found) + return FALSE; + } + return TRUE; +} + +static gboolean +route_slist_compare (GSList *a, GSList *b) +{ + GSList *iter_a, *iter_b; + gboolean found = FALSE; + + for (iter_a = a; iter_a; iter_a = g_slist_next (iter_a)) { + NMIP6Route *route_a = (NMIP6Route *) iter_a->data; + + for (iter_b = b, found = FALSE; iter_b; iter_b = g_slist_next (iter_b)) { + NMIP6Route *route_b = (NMIP6Route *) iter_b->data; + + if (nm_ip6_route_compare (route_a, route_b)) { + found = TRUE; + break; + } + } + + if (!found) + return FALSE; + } + return TRUE; +} + +static gboolean +string_array_compare (GPtrArray *a, GPtrArray *b) +{ + int i, j; + gboolean found = FALSE; + + for (i = 0; i < a->len; i++) { + for (j = 0, found = FALSE; j < b->len; j++) { + const char *item_a = g_ptr_array_index (a, i); + const char *item_b = g_ptr_array_index (b, j); + + if ((!item_a && !item_b) || (item_a && item_b && !strcmp (item_a, item_b))) { + found = TRUE; + break; + } + } + + if (!found) + return FALSE; + } + return TRUE; +} + +static gboolean +addr_array_compare (GArray *a, GArray *b) +{ + struct in6_addr *addrs_a, *addrs_b; + int i, j; + gboolean found = FALSE; + + addrs_a = (struct in6_addr *)a->data; + addrs_b = (struct in6_addr *)b->data; + for (i = 0; i < a->len; i++) { + for (j = 0, found = FALSE; j < b->len; j++) { + if (memcmp (&addrs_a[i], &addrs_b[j], sizeof (struct in6_addr)) == 0) { + found = TRUE; + break; + } + } + + if (!found) + return FALSE; + } + return TRUE; +} + +NMIP6ConfigCompareFlags +nm_ip6_config_diff (NMIP6Config *a, NMIP6Config *b) +{ + NMIP6ConfigPrivate *a_priv; + NMIP6ConfigPrivate *b_priv; + NMIP6ConfigCompareFlags flags = NM_IP6_COMPARE_FLAG_NONE; + + if ((a && !b) || (b && !a)) + return 0xFFFFFFFF; + if (!a && !b) + return NM_IP6_COMPARE_FLAG_NONE; + + a_priv = NM_IP6_CONFIG_GET_PRIVATE (a); + b_priv = NM_IP6_CONFIG_GET_PRIVATE (b); + + if ( !addr_slist_compare (a_priv->addresses, b_priv->addresses) + || !addr_slist_compare (b_priv->addresses, a_priv->addresses)) + flags |= NM_IP6_COMPARE_FLAG_ADDRESSES; + + if (memcmp (&a_priv->ptp_address, &b_priv->ptp_address, sizeof (struct in6_addr)) != 0) + flags |= NM_IP6_COMPARE_FLAG_PTP_ADDRESS; + + if ( (a_priv->nameservers->len != b_priv->nameservers->len) + || !addr_array_compare (a_priv->nameservers, b_priv->nameservers) + || !addr_array_compare (b_priv->nameservers, a_priv->nameservers)) + flags |= NM_IP6_COMPARE_FLAG_NAMESERVERS; + + if ( !route_slist_compare (a_priv->routes, b_priv->routes) + || !route_slist_compare (b_priv->routes, a_priv->routes)) + flags |= NM_IP6_COMPARE_FLAG_ROUTES; + + if ( (a_priv->domains->len != b_priv->domains->len) + || !string_array_compare (a_priv->domains, b_priv->domains) + || !string_array_compare (b_priv->domains, a_priv->domains)) + flags |= NM_IP6_COMPARE_FLAG_DOMAINS; + + if ( (a_priv->searches->len != b_priv->searches->len) + || !string_array_compare (a_priv->searches, b_priv->searches) + || !string_array_compare (b_priv->searches, a_priv->searches)) + flags |= NM_IP6_COMPARE_FLAG_SEARCHES; + + if (a_priv->mss != b_priv->mss) + flags |= NM_IP6_COMPARE_FLAG_MSS; + + return flags; +} + +static void +nm_ip6_config_init (NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr)); + priv->domains = g_ptr_array_sized_new (3); + priv->searches = g_ptr_array_sized_new (3); +} + +static void +finalize (GObject *object) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object); + + nm_utils_slist_free (priv->addresses, (GDestroyNotify) nm_ip6_address_unref); + nm_utils_slist_free (priv->routes, (GDestroyNotify) nm_ip6_route_unref); + g_array_free (priv->nameservers, TRUE); + g_ptr_array_free (priv->domains, TRUE); + g_ptr_array_free (priv->searches, TRUE); + + G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_ADDRESSES: + nm_utils_ip6_addresses_to_gvalue (priv->addresses, value); + break; + case PROP_NAMESERVERS: + g_value_set_boxed (value, priv->nameservers); + break; + case PROP_DOMAINS: + g_value_set_boxed (value, priv->domains); + break; + case PROP_ROUTES: + nm_utils_ip6_routes_to_gvalue (priv->routes, value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_ip6_config_class_init (NMIP6ConfigClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + g_type_class_add_private (config_class, sizeof (NMIP6ConfigPrivate)); + + /* virtual methods */ + object_class->get_property = get_property; + 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_ARRAY_OF_UINT, + 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)); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (config_class), + &dbus_glib_nm_ip6_config_object_info); +} diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h new file mode 100644 index 000000000..4fd959d53 --- /dev/null +++ b/src/nm-ip6-config.h @@ -0,0 +1,120 @@ +/* -*- 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) 2008 Red Hat, Inc. + */ + +#ifndef NM_IP6_CONFIG_H +#define NM_IP6_CONFIG_H + +#include +#include + +#include "nm-setting-ip6-config.h" + +#define NM_TYPE_IP6_CONFIG (nm_ip6_config_get_type ()) +#define NM_IP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IP6_CONFIG, NMIP6Config)) +#define NM_IP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IP6_CONFIG, NMIP6ConfigClass)) +#define NM_IS_IP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_IP6_CONFIG)) +#define NM_IS_IP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_IP6_CONFIG)) +#define NM_IP6_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IP6_CONFIG, NMIP6ConfigClass)) + +typedef struct { + GObject parent; +} NMIP6Config; + +typedef struct { + GObjectClass parent; +} NMIP6ConfigClass; + +#define NM_IP6_CONFIG_ADDRESSES "addresses" +#define NM_IP6_CONFIG_NAMESERVERS "nameservers" +#define NM_IP6_CONFIG_DOMAINS "domains" +#define NM_IP6_CONFIG_ROUTES "routes" + +GType nm_ip6_config_get_type (void); + + +NMIP6Config * nm_ip6_config_new (void); +void nm_ip6_config_export (NMIP6Config *config); +const char * nm_ip6_config_get_dbus_path (NMIP6Config *config); + +void nm_ip6_config_take_address (NMIP6Config *config, NMIP6Address *address); +void nm_ip6_config_add_address (NMIP6Config *config, NMIP6Address *address); +void nm_ip6_config_replace_address (NMIP6Config *config, guint32 i, NMIP6Address *new_address); +NMIP6Address *nm_ip6_config_get_address (NMIP6Config *config, guint32 i); +guint32 nm_ip6_config_get_num_addresses (NMIP6Config *config); + +const struct in6_addr *nm_ip6_config_get_ptp_address (NMIP6Config *config); +void nm_ip6_config_set_ptp_address (NMIP6Config *config, struct in6_addr *ptp_addr); + +void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver); +const struct in6_addr *nm_ip6_config_get_nameserver (NMIP6Config *config, guint i); +guint32 nm_ip6_config_get_num_nameservers (NMIP6Config *config); +void nm_ip6_config_reset_nameservers (NMIP6Config *config); + +void nm_ip6_config_take_route (NMIP6Config *config, NMIP6Route *route); +void nm_ip6_config_add_route (NMIP6Config *config, NMIP6Route *route); +void nm_ip6_config_replace_route (NMIP6Config *config, guint32 i, NMIP6Route *new_route); +NMIP6Route * nm_ip6_config_get_route (NMIP6Config *config, guint32 i); +guint32 nm_ip6_config_get_num_routes (NMIP6Config *config); +void nm_ip6_config_reset_routes (NMIP6Config *config); + +void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain); +const char * nm_ip6_config_get_domain (NMIP6Config *config, guint i); +guint32 nm_ip6_config_get_num_domains (NMIP6Config *config); +void nm_ip6_config_reset_domains (NMIP6Config *config); + +void nm_ip6_config_add_search (NMIP6Config *config, const char *search); +const char * nm_ip6_config_get_search (NMIP6Config *config, guint i); +guint32 nm_ip6_config_get_num_searches (NMIP6Config *config); +void nm_ip6_config_reset_searches (NMIP6Config *config); + +guint32 nm_ip6_config_get_mss (NMIP6Config *config); +void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss); + +gboolean nm_ip6_config_get_never_default (NMIP6Config *config); +void nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default); + +/* Flags for nm_ip6_config_to_rtnl_addr() */ +#define NM_RTNL_ADDR_NONE 0x0000 +#define NM_RTNL_ADDR_ADDR 0x0001 +#define NM_RTNL_ADDR_PTP_ADDR 0x0002 +#define NM_RTNL_ADDR_PREFIX 0x0004 +#define NM_RTNL_ADDR_BROADCAST 0x0008 + +#define NM_RTNL_ADDR_DEFAULT (NM_RTNL_ADDR_ADDR | NM_RTNL_ADDR_PREFIX | NM_RTNL_ADDR_BROADCAST) +#define NM_RTNL_ADDR_PTP_DEFAULT (NM_RTNL_ADDR_ADDR | NM_RTNL_ADDR_PREFIX | NM_RTNL_ADDR_PTP_ADDR) + +struct rtnl_addr *nm_ip6_config_to_rtnl_addr (NMIP6Config *config, guint32 i, guint32 flags); + +typedef enum { + NM_IP6_COMPARE_FLAG_NONE = 0x00000000, /* match nothing, kinda pointless */ + NM_IP6_COMPARE_FLAG_ADDRESSES = 0x00000001, + NM_IP6_COMPARE_FLAG_PTP_ADDRESS = 0x00000002, + NM_IP6_COMPARE_FLAG_NAMESERVERS = 0x00000004, + NM_IP6_COMPARE_FLAG_ROUTES = 0x00000008, + NM_IP6_COMPARE_FLAG_DOMAINS = 0x00000010, + NM_IP6_COMPARE_FLAG_SEARCHES = 0x00000020, + NM_IP6_COMPARE_FLAG_MSS = 0x00000080, + NM_IP6_COMPARE_FLAG_ALL = 0xFFFFFFFF /* match everything */ +} NMIP6ConfigCompareFlags; + +/* Returns a bitfield representing how the two IP6 configs differ */ +NMIP6ConfigCompareFlags nm_ip6_config_diff (NMIP6Config *a, NMIP6Config *b); + +#endif /* NM_IP6_CONFIG_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index 87338a10d..5ad0ff58c 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -650,8 +650,8 @@ user_connection_get_settings_cb (DBusGProxy *proxy, */ g_object_set_data_full (G_OBJECT (connection), "proxy", - info->proxy, - g_object_ref (info->proxy)); + g_object_ref (info->proxy), + g_object_unref); } else g_object_unref (connection); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 6657aa787..a4521e0e1 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -851,8 +851,8 @@ vpn_cleanup (NMVPNConnection *connection) if (priv->tundev) { nm_system_device_set_up_down_with_iface (priv->tundev, FALSE, NULL); - nm_system_device_flush_ip4_routes_with_iface (priv->tundev); - nm_system_device_flush_ip4_addresses_with_iface (priv->tundev); + nm_system_device_flush_routes_with_iface (priv->tundev); + nm_system_device_flush_addresses_with_iface (priv->tundev); } if (priv->ip4_config) { diff --git a/system-settings/plugins/ifcfg-rh/reader.c b/system-settings/plugins/ifcfg-rh/reader.c index e41de7d56..61f3d6879 100644 --- a/system-settings/plugins/ifcfg-rh/reader.c +++ b/system-settings/plugins/ifcfg-rh/reader.c @@ -1204,7 +1204,9 @@ eap_peap_reader (const char *eap_method, if (!strlen (*iter)) continue; - if (!strcmp (*iter, "MSCHAPV2") || !strcmp (*iter, "MD5")) { + if ( !strcmp (*iter, "MSCHAPV2") + || !strcmp (*iter, "MD5") + || !strcmp (*iter, "GTC")) { if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) goto done; } else if (!strcmp (*iter, "TLS")) { @@ -1217,7 +1219,6 @@ eap_peap_reader (const char *eap_method, goto done; } - // FIXME: OTP & GTC too lower = g_ascii_strdown (*iter, -1); g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL); g_free (lower);