From e7caf09032d97c9e1f20e02f1b0d7100e0377a15 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 28 Jul 2009 10:07:52 -0400 Subject: [PATCH 01/19] dbus: fix formatting of dbus permissions file --- src/NetworkManager.conf | 70 ++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/NetworkManager.conf b/src/NetworkManager.conf index a5eee46e88..87814bec2a 100644 --- a/src/NetworkManager.conf +++ b/src/NetworkManager.conf @@ -4,10 +4,10 @@ - + - + @@ -15,58 +15,58 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + 512 From f1d80330441f19d414a7944197a3ba3ba6bea37e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 28 Jul 2009 10:12:27 -0400 Subject: [PATCH 02/19] build: add BT introspection to dist tarball --- introspection/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/introspection/Makefile.am b/introspection/Makefile.am index a77dba1a70..e284d0c0ed 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 \ From 18788a26d3fef955cf6dab4b3ae60bcd951852ed Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 28 Jul 2009 10:14:21 -0400 Subject: [PATCH 03/19] build: remove duplicate automake bits --- policy/Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/policy/Makefile.am b/policy/Makefile.am index 9ce677b188..c5d24764ee 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 : "; \ From e5347169f6df8db878c1d7a0b5ca5b18cad55625 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 29 Jul 2009 14:08:54 -0400 Subject: [PATCH 04/19] peap: add GTC as a recognized phase2 method (bgo #565065) (rh #451027) (lp #284211) --- libnm-util/nm-setting-8021x.c | 2 +- system-settings/plugins/ifcfg-rh/reader.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libnm-util/nm-setting-8021x.c b/libnm-util/nm-setting-8021x.c index 1c7a8bc708..68efff391f 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/system-settings/plugins/ifcfg-rh/reader.c b/system-settings/plugins/ifcfg-rh/reader.c index e41de7d563..61f3d68791 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); From e324f783e27144b92866f92976bc8a14cfc7ff0a Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 28 Jul 2009 13:28:24 -0400 Subject: [PATCH 05/19] Fix crash when nm-applet exits --- src/nm-manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 731589c40a..07be3e3071 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -638,8 +638,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); From 90bd1ad5cd6b3ddf00749a61f8f959f274ee41d8 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 11 Jun 2009 15:52:11 -0400 Subject: [PATCH 06/19] Install and fix up libnm-util IPv6 config stuff --- include/nm-dbus-glib-types.h | 4 +- libnm-util/Makefile.am | 3 +- libnm-util/libnm-util.ver | 54 ++++++++ libnm-util/nm-connection.c | 5 + libnm-util/nm-setting-ip6-config.c | 205 +++++++++-------------------- libnm-util/nm-setting-ip6-config.h | 89 ++++++------- libnm-util/nm-utils.c | 158 ++++++++++++++++------ libnm-util/nm-utils.h | 9 ++ 8 files changed, 297 insertions(+), 230 deletions(-) diff --git a/include/nm-dbus-glib-types.h b/include/nm-dbus-glib-types.h index be52614cfd..cfb08274c6 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/libnm-util/Makefile.am b/libnm-util/Makefile.am index bc7befb060..1a5a94eb3f 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 4d372a7437..92228f5257 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 e0160232cd..810032ae54 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-ip6-config.c b/libnm-util/nm-setting-ip6-config.c index 66defb38c6..d9da92fa8f 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 879d82e0cb..4e39940231 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 f9a56f4702..a034121405 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 629bc59fee..810c6e7e9d 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); From b67b1afb1aad64a56003bc772455b992c2f8103d Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 29 Jul 2009 21:34:52 -0400 Subject: [PATCH 07/19] Backend IP6 config --- introspection/nm-ip6-config.xml | 19 + src/Makefile.am | 6 + src/nm-ip6-config.c | 726 ++++++++++++++++++++++++++++++++ src/nm-ip6-config.h | 120 ++++++ 4 files changed, 871 insertions(+) create mode 100644 introspection/nm-ip6-config.xml create mode 100644 src/nm-ip6-config.c create mode 100644 src/nm-ip6-config.h diff --git a/introspection/nm-ip6-config.xml b/introspection/nm-ip6-config.xml new file mode 100644 index 0000000000..d1349b0c21 --- /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/src/Makefile.am b/src/Makefile.am index 79c2a2e64b..d8878e05df 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/nm-ip6-config.c b/src/nm-ip6-config.c new file mode 100644 index 0000000000..990ba3df32 --- /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 0000000000..4fd959d531 --- /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 */ From db2748b545ad7b0054d32dcc4c50653f9f37db90 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 21 Jul 2009 13:59:37 -0400 Subject: [PATCH 08/19] Add IP6 support to NMNamedManager --- src/named-manager/nm-named-manager.c | 279 +++++++++++++++++---------- src/named-manager/nm-named-manager.h | 16 +- 2 files changed, 185 insertions(+), 110 deletions(-) diff --git a/src/named-manager/nm-named-manager.c b/src/named-manager/nm-named-manager.c index cab06abf49..b89c80118c 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 2b5b647579..47c8e7115d 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 From fc8e609784ec7e46ed64fef604431596cb431105 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 29 Jul 2009 12:12:41 -0400 Subject: [PATCH 09/19] Initial IPv6 support (only handles "manual" and "ignore" currently) --- src/NetworkManagerSystem.c | 291 ++++++++++++--- src/NetworkManagerSystem.h | 13 +- src/NetworkManagerUtils.c | 135 +++++++ src/NetworkManagerUtils.h | 4 + src/modem-manager/nm-modem.c | 14 +- src/nm-device-bt.c | 8 +- src/nm-device-ethernet.c | 2 +- src/nm-device-interface.c | 8 + src/nm-device-interface.h | 2 + src/nm-device-wifi.c | 10 +- src/nm-device.c | 548 +++++++++++++++++++++++----- src/nm-device.h | 23 +- src/vpn-manager/nm-vpn-connection.c | 4 +- 13 files changed, 896 insertions(+), 166 deletions(-) diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index 508e0fe931..9f62d7fb00 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 b83a663d00..f2c2693ac1 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 a030a3867b..4934d465c6 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 a987d21b4e..05f3b837a3 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 3826dce150..48f9296edf 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/nm-device-bt.c b/src/nm-device-bt.c index 2517c797bf..06a4d8d0f9 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 759a183ea9..14b23c6a26 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -1255,7 +1255,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 5647adb425..5514ac1a04 100644 --- a/src/nm-device-interface.c +++ b/src/nm-device-interface.c @@ -123,6 +123,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, diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h index 760cccacc7..d6cb03374b 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 0fbff7424d..0d67c652c2 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; diff --git a/src/nm-device.c b/src/nm-device.c index 6f7423b385..18e6a9f523 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, @@ -123,7 +132,7 @@ static gboolean nm_device_activate (NMDeviceInterface *device, static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason); static gboolean nm_device_spec_match_list (NMDeviceInterface *device, const GSList *specs); -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); @@ -131,6 +140,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) @@ -150,7 +160,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; } @@ -439,24 +448,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 @@ -464,13 +493,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 * @@ -481,17 +548,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; @@ -525,7 +597,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)); @@ -562,7 +634,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); @@ -612,7 +684,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)); @@ -772,7 +844,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; @@ -837,7 +909,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; } @@ -902,7 +974,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; @@ -976,39 +1048,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); @@ -1031,7 +1118,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)); @@ -1172,15 +1259,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; @@ -1189,10 +1275,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) @@ -1207,22 +1293,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; @@ -1231,17 +1317,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); @@ -1256,13 +1342,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; @@ -1271,12 +1357,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)) { @@ -1289,22 +1375,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; @@ -1313,9 +1399,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)); } @@ -1330,31 +1599,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++) { @@ -1464,6 +1723,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; @@ -1472,9 +1732,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...", @@ -1485,6 +1748,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) @@ -1504,8 +1772,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; } @@ -1517,7 +1786,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; @@ -1526,7 +1795,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)); @@ -1581,7 +1858,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); @@ -1641,10 +1919,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 */ @@ -1873,7 +2152,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; @@ -1881,7 +2160,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 */ @@ -1913,7 +2192,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 @@ -2049,7 +2328,6 @@ nm_device_set_ip4_config (NMDevice *self, return success; } - /* * nm_device_get_ip4_address * @@ -2090,6 +2368,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) { @@ -2229,7 +2570,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); nm_device_set_use_dhcp (self, FALSE); @@ -2349,6 +2691,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; @@ -2386,9 +2737,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 */ @@ -2420,6 +2774,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 31c58fb547..dff95ac224 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); @@ -128,7 +137,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, @@ -136,6 +144,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); @@ -149,8 +158,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/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 6657aa7870..a4521e0e13 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) { From e4d03e1f9d83d4304a30b889f0de8a3be8223e79 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 30 Jul 2009 09:27:21 -0400 Subject: [PATCH 10/19] manager: fix crash when applets exit Due to bad refcounting of D-Bus proxies of the connections applets expose. --- src/nm-manager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 731589c40a..22a563edb3 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -638,8 +638,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); From a77655df0616c34af2638731c0e31bde26a69d9c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 30 Jul 2009 10:39:57 -0400 Subject: [PATCH 11/19] core: don't send properties-changed events for internal properties --- src/nm-device-interface.c | 3 ++- src/nm-device-wifi.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c index 5647adb425..1d5962ef38 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" @@ -152,7 +153,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-wifi.c b/src/nm-device-wifi.c index 0fbff7424d..ce5d08b35f 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -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] = From f2eb3dea659d66437d6564abef49fe4eb8964a38 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 3 Aug 2009 17:15:03 -0400 Subject: [PATCH 12/19] core: base infrastructure for connection assumption Figure out what connections can be assumed when a device is added, and on shutdown don't blow away connections that can be assumed on NM restart. --- src/dhcp-manager/nm-dhcp-dhclient.c | 204 ++++++++++++++++++++++++++++ src/dhcp-manager/nm-dhcp-dhcpcd.c | 5 + src/dhcp-manager/nm-dhcp-manager.c | 13 ++ src/dhcp-manager/nm-dhcp-manager.h | 7 + src/nm-device-ethernet.c | 196 +++++++++++++++++++++++++- src/nm-device-interface.c | 21 +++ src/nm-device-interface.h | 7 + src/nm-device.c | 57 ++++++-- src/nm-device.h | 2 + src/nm-manager.c | 43 ++++-- 10 files changed, 532 insertions(+), 23 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index f35465976b..ac7d9f58ab 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -18,6 +18,10 @@ * Copyright (C) 2005 - 2008 Red Hat, Inc. */ +#define _XOPEN_SOURCE +#include +#undef _XOPEN_SOURCE + #include #include #include @@ -74,6 +78,206 @@ get_leasefile_for_iface (const char * iface, const char *uuid) NM_DHCP_MANAGER_LEASE_FILE_EXT); } +static void +add_lease_option (GHashTable *hash, char *line) +{ + char *spc; + + spc = strchr (line, ' '); + if (!spc) { + g_warning ("%s: line '%s' did not contain a space", __func__, line); + return; + } + + /* If it's an 'option' line, split at second space */ + if (g_str_has_prefix (line, "option ")) { + spc = strchr (spc + 1, ' '); + if (!spc) { + g_warning ("%s: option line '%s' did not contain a second space", + __func__, line); + return; + } + } + + /* Split the line at the space */ + *spc = '\0'; + spc++; + + /* Kill the ';' at the end of the line, if any */ + if (*(spc + strlen (spc) - 1) == ';') + *(spc + strlen (spc) - 1) = '\0'; + + /* Treat 'interface' specially */ + if (g_str_has_prefix (line, "interface")) { + if (*(spc) == '"') + spc++; /* Jump past the " */ + if (*(spc + strlen (spc) - 1) == '"') + *(spc + strlen (spc) - 1) = '\0'; /* Kill trailing " */ + } + + g_hash_table_insert (hash, g_strdup (line), g_strdup (spc)); +} + +GSList * +nm_dhcp_client_get_lease_ip4_config (const char *iface, const char *uuid) +{ + GSList *parsed = NULL, *iter, *leases = NULL; + char *contents = NULL; + char *leasefile; + char **line, **split = NULL; + GHashTable *hash = NULL; + + leasefile = get_leasefile_for_iface (iface, uuid); + if (!leasefile) + return NULL; + + if (!g_file_test (leasefile, G_FILE_TEST_EXISTS)) + goto out; + + if (!g_file_get_contents (leasefile, &contents, NULL, NULL)) + goto out; + + split = g_strsplit_set (contents, "\n\r", -1); + g_free (contents); + if (!split) + goto out; + + for (line = split; line && *line; line++) { + *line = g_strstrip (*line); + + if (!strcmp (*line, "}")) { + /* Lease ends */ + parsed = g_slist_append (parsed, hash); + hash = NULL; + } else if (!strcmp (*line, "lease {")) { + /* Beginning of a new lease */ + if (hash) { + g_warning ("%s: lease file %s malformed; new lease started " + "without ending previous lease", + __func__, leasefile); + g_hash_table_destroy (hash); + } + + hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + } else if (strlen (*line)) + add_lease_option (hash, *line); + } + g_strfreev (split); + + /* Check if the last lease in the file was properly ended */ + if (hash) { + g_warning ("%s: lease file %s malformed; new lease started " + "without ending previous lease", + __func__, leasefile); + g_hash_table_destroy (hash); + hash = NULL; + } + + for (iter = parsed; iter; iter = g_slist_next (iter)) { + NMIP4Config *ip4; + NMIP4Address *addr; + const char *data; + struct in_addr tmp; + guint32 prefix; + struct tm expire; + + hash = iter->data; + + /* Make sure this lease is for the interface we want */ + data = g_hash_table_lookup (hash, "interface"); + if (!data || strcmp (data, iface)) + continue; + + data = g_hash_table_lookup (hash, "expire"); + if (data) { + time_t now_tt; + struct tm *now; + + /* Read lease expiration (in UTC) */ + if (!strptime (data, "%w %Y/%m/%d %H:%M:%S", &expire)) { + g_warning ("%s: couldn't parse expire time '%s'", + __func__, data); + continue; + } + + now_tt = time (NULL); + now = gmtime(&now_tt); + + /* Ignore this lease if it's already expired */ + if (expire.tm_year < now->tm_year) + continue; + else if (expire.tm_year == now->tm_year) { + if (expire.tm_mon < now->tm_mon) + continue; + else if (expire.tm_mon == now->tm_mon) { + if (expire.tm_mday < now->tm_mday) + continue; + else if (expire.tm_mday == now->tm_mday) { + if (expire.tm_hour < now->tm_hour) + continue; + else if (expire.tm_hour == now->tm_hour) { + if (expire.tm_min < now->tm_min) + continue; + else if (expire.tm_min == now->tm_min) { + if (expire.tm_sec <= now->tm_sec) + continue; + } + } + } + } + } + /* If we get this far, the lease hasn't expired */ + } + + data = g_hash_table_lookup (hash, "fixed-address"); + if (!data) + continue; + + ip4 = nm_ip4_config_new (); + addr = nm_ip4_address_new (); + + /* IP4 address */ + if (!inet_pton (AF_INET, data, &tmp)) { + g_warning ("%s: couldn't parse IP4 address '%s'", __func__, data); + goto error; + } + nm_ip4_address_set_address (addr, tmp.s_addr); + + /* Netmask */ + data = g_hash_table_lookup (hash, "option subnet-mask"); + if (!data) + data = "255.255.255.0"; /* FIXME: assume class C? */ + if (!inet_pton (AF_INET, data, &tmp)) { + g_warning ("%s: couldn't parse IP4 subnet mask '%s'", __func__, data); + goto error; + } + prefix = nm_utils_ip4_netmask_to_prefix (tmp.s_addr); + nm_ip4_address_set_prefix (addr, prefix); + + /* Gateway */ + data = g_hash_table_lookup (hash, "option routers"); + if (data) { + if (!inet_pton (AF_INET, data, &tmp)) { + g_warning ("%s: couldn't parse IP4 gateway '%s'", __func__, data); + goto error; + } + nm_ip4_address_set_gateway (addr, tmp.s_addr); + } + + nm_ip4_config_take_address (ip4, addr); + leases = g_slist_append (leases, ip4); + continue; + + error: + nm_ip4_address_unref (addr); + g_object_unref (ip4); + } + +out: + g_slist_foreach (parsed, (GFunc) g_hash_table_destroy, NULL); + g_free (leasefile); + return leases; +} #define DHCP_CLIENT_ID_TAG "send dhcp-client-identifier" diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index a6ce8d21e6..a8d929a528 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -49,6 +49,11 @@ get_pidfile_for_iface (const char * iface) NM_DHCP_MANAGER_PID_FILE_EXT); } +GSList * +nm_dhcp_client_get_lease_ip4_config (const char *iface, const char *uuid) +{ + return NULL; +} static void dhcpcd_child_setup (gpointer user_data G_GNUC_UNUSED) diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index bdd2695b2a..f099ea289c 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -1121,3 +1121,16 @@ nm_dhcp_manager_set_hostname_provider (NMDHCPManager *manager, g_object_weak_ref (G_OBJECT (provider), hostname_provider_destroyed, manager); } } + +GSList * +nm_dhcp_manager_get_lease_ip4_config (NMDHCPManager *self, + const char *iface, + const char *uuid) +{ + g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (uuid != NULL, NULL); + + return nm_dhcp_client_get_lease_ip4_config (iface, uuid); +} + diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index 6880a2336c..124008493a 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -107,6 +107,10 @@ gboolean nm_dhcp_manager_foreach_dhcp4_option (NMDHCPManager *self, GHFunc func, gpointer user_data); +GSList * nm_dhcp_manager_get_lease_ip4_config (NMDHCPManager *self, + const char *iface, + const char *uuid); + /* The following are implemented by the DHCP client backends */ GPid nm_dhcp_client_start (NMDHCPDevice *device, const char *uuid, @@ -118,6 +122,9 @@ gboolean nm_dhcp_client_process_classless_routes (GHashTable *options, NMIP4Config *ip4_config, guint32 *gwaddr); +GSList * nm_dhcp_client_get_lease_ip4_config (const char *iface, + const char *uuid); + /* Test functions */ NMIP4Config *nm_dhcp_manager_options_to_ip4_config (const char *iface, GHashTable *options); diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index 759a183ea9..2c68f790d1 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -53,6 +53,7 @@ #include "ppp-manager/nm-ppp-manager.h" #include "nm-utils.h" #include "nm-properties-changed-signal.h" +#include "nm-dhcp-manager.h" #include "nm-device-ethernet-glue.h" @@ -280,8 +281,8 @@ constructor (GType type, guint32 caps; object = G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructor (type, - n_construct_params, - construct_params); + n_construct_params, + construct_params); if (!object) return NULL; @@ -1472,6 +1473,196 @@ spec_match_list (NMDevice *device, const GSList *specs) return matched; } +static gboolean +wired_match_config (NMDevice *self, NMConnection *connection) +{ + NMSettingWired *s_wired; + struct ether_addr ether; + const GByteArray *s_ether; + + s_wired = (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); + if (!s_wired) + return FALSE; + + /* MAC address check */ + s_ether = nm_setting_wired_get_mac_address (s_wired); + if (s_ether) { + nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (self), ðer); + + if (memcmp (s_ether->data, ether.ether_addr_octet, ETH_ALEN)) + return FALSE; + } + + return TRUE; +} + +typedef struct { + int ifindex; + NMIP4Address *addr; + gboolean found; +} AddrData; + +static void +check_one_address (struct nl_object *object, void *user_data) +{ + AddrData *data = user_data; + struct rtnl_addr *addr = (struct rtnl_addr *) object; + struct nl_addr *local; + struct in_addr tmp; + + if (rtnl_addr_get_ifindex (addr) != data->ifindex) + return; + if (rtnl_addr_get_family (addr) != AF_INET) + return; + + if (nm_ip4_address_get_prefix (data->addr) != rtnl_addr_get_prefixlen (addr)) + return; + + local = rtnl_addr_get_local (addr); + if (nl_addr_get_family (local) != AF_INET) + return; + if (nl_addr_get_len (local) != sizeof (struct in_addr)) + return; + if (!nl_addr_get_binary_addr (local)) + return; + + memcpy (&tmp, nl_addr_get_binary_addr (local), nl_addr_get_len (local)); + if (tmp.s_addr != nm_ip4_address_get_address (data->addr)) + return; + + /* Yay, found it */ + data->found = TRUE; +} + +static gboolean +ip4_match_config (NMDevice *self, NMConnection *connection) +{ + NMSettingIP4Config *s_ip4; + NMSettingConnection *s_con; + struct nl_handle *nlh = NULL; + struct nl_cache *addr_cache = NULL; + int i, num; + GSList *leases, *iter; + NMDHCPManager *dhcp_mgr; + const char *method; + int ifindex; + AddrData check_data; + + ifindex = nm_device_ethernet_get_ifindex (NM_DEVICE_ETHERNET (self)); + + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + g_assert (nm_setting_connection_get_uuid (s_con)); + + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (!s_ip4) + return FALSE; + + /* Read all the device's IP addresses */ + 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); + + /* Get any saved leases that apply to this connection */ + dhcp_mgr = nm_dhcp_manager_get (); + leases = nm_dhcp_manager_get_lease_ip4_config (dhcp_mgr, + nm_device_get_iface (self), + nm_setting_connection_get_uuid (s_con)); + g_object_unref (dhcp_mgr); + + method = nm_setting_ip4_config_get_method (s_ip4); + if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + gboolean found = FALSE; + + /* Find at least one lease's address on the device */ + for (iter = leases; iter; iter = g_slist_next (iter)) { + NMIP4Config *addr = iter->data; + + memset (&check_data, 0, sizeof (check_data)); + check_data.ifindex = ifindex; + check_data.found = FALSE; + check_data.addr = nm_ip4_config_get_address (addr, 0); + + nl_cache_foreach (addr_cache, check_one_address, &check_data); + if (check_data.found) { + found = TRUE; /* Yay, device has same address as a lease */ + break; + } + } + g_slist_foreach (leases, (GFunc) g_object_unref, NULL); + g_slist_free (leases); + return found; + } else { + /* Maybe the connection used to be DHCP and there are stale leases; ignore them */ + g_slist_foreach (leases, (GFunc) g_object_unref, NULL); + g_slist_free (leases); + } + + /* 'shared' and 'link-local' aren't supported methods because 'shared' + * requires too much iptables and dnsmasq state to be reclaimed, and + * avahi-autoipd isn't smart enough to allow the link-local address to be + * determined at any point other than when it was first assigned. + */ + if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + return FALSE; + + /* Everything below for static addressing */ + + /* Find all IP4 addresses of this connection in the device's address list */ + num = nm_setting_ip4_config_get_num_addresses (s_ip4); + for (i = 0; i < num; i++) { + memset (&check_data, 0, sizeof (check_data)); + check_data.ifindex = ifindex; + check_data.found = FALSE; + check_data.addr = nm_setting_ip4_config_get_address (s_ip4, i); + + nl_cache_foreach (addr_cache, check_one_address, &check_data); + if (!check_data.found) + return FALSE; + } + + /* Success; all the connection's static IP addresses are assigned to the device */ + return TRUE; +} + +static NMConnection * +connection_match_config (NMDevice *self, const GSList *connections) +{ + GSList *iter; + NMSettingConnection *s_con; + + for (iter = (GSList *) connections; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = NM_CONNECTION (iter->data); + + s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRED_SETTING_NAME)) + continue; + + /* Can't assume 802.1x or PPPoE connections; they have too much state + * that's impossible to get on-the-fly from PPPoE or the supplicant. + */ + if ( nm_connection_get_setting (candidate, NM_TYPE_SETTING_802_1X) + || nm_connection_get_setting (candidate, NM_TYPE_SETTING_PPPOE)) + continue; + + if (!wired_match_config (self, candidate)) + continue; + + if (!ip4_match_config (self, candidate)) + continue; + + return candidate; + } + + return NULL; +} + static void dispose (GObject *object) { @@ -1587,6 +1778,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; parent_class->deactivate_quickly = real_deactivate_quickly; parent_class->spec_match_list = spec_match_list; + parent_class->connection_match_config = connection_match_config; /* properties */ g_object_class_install_property diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c index 5647adb425..7f287a8696 100644 --- a/src/nm-device-interface.c +++ b/src/nm-device-interface.c @@ -282,8 +282,29 @@ gboolean nm_device_interface_spec_match_list (NMDeviceInterface *device, const GSList *specs) { + g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE); + if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->spec_match_list) return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->spec_match_list (device, specs); return FALSE; } +NMConnection * +nm_device_interface_connection_match_config (NMDeviceInterface *device, + const GSList *connections) +{ + g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), NULL); + + if (NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config) + return NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config (device, connections); + return NULL; +} + +gboolean +nm_device_interface_can_assume_connection (NMDeviceInterface *device) +{ + g_return_val_if_fail (NM_IS_DEVICE_INTERFACE (device), FALSE); + + return !!NM_DEVICE_INTERFACE_GET_INTERFACE (device)->connection_match_config; +} + diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h index 760cccacc7..97a95da479 100644 --- a/src/nm-device-interface.h +++ b/src/nm-device-interface.h @@ -88,6 +88,8 @@ struct _NMDeviceInterface { gboolean (*spec_match_list) (NMDeviceInterface *device, const GSList *specs); + NMConnection * (*connection_match_config) (NMDeviceInterface *device, const GSList *specs); + /* Signals */ void (*state_changed) (NMDeviceInterface *device, NMDeviceState new_state, @@ -115,4 +117,9 @@ NMDeviceState nm_device_interface_get_state (NMDeviceInterface *device); gboolean nm_device_interface_spec_match_list (NMDeviceInterface *device, const GSList *specs); +NMConnection * nm_device_interface_connection_match_config (NMDeviceInterface *device, + const GSList *connections); + +gboolean nm_device_interface_can_assume_connection (NMDeviceInterface *device); + #endif /* NM_DEVICE_INTERFACE_H */ diff --git a/src/nm-device.c b/src/nm-device.c index 6f7423b385..56634ef8fc 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -121,7 +121,8 @@ static gboolean nm_device_activate (NMDeviceInterface *device, NMActRequest *req, GError **error); static void nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason); -static gboolean nm_device_spec_match_list (NMDeviceInterface *device, const GSList *specs); +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); @@ -139,7 +140,8 @@ device_interface_init (NMDeviceInterface *device_interface_class) device_interface_class->check_connection_compatible = check_connection_compatible; device_interface_class->activate = nm_device_activate; device_interface_class->deactivate = nm_device_deactivate; - device_interface_class->spec_match_list = nm_device_spec_match_list; + device_interface_class->spec_match_list = spec_match_list; + device_interface_class->connection_match_config = connection_match_config; } @@ -2202,25 +2204,45 @@ dispose (GObject *object) { NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean take_down = TRUE; if (priv->disposed || !priv->initialized) goto out; priv->disposed = TRUE; + /* Don't down can-assume-connection capable devices that are activated with + * a connection that can be assumed. + */ + if (nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (self)) + && (nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED)) { + NMConnection *connection; + NMSettingIP4Config *s_ip4; + const char *method = NULL; + + /* Only system connections can be left up */ + connection = nm_act_request_get_connection (priv->act_request); + if ( connection + && (nm_connection_get_scope (connection) == NM_CONNECTION_SCOPE_SYSTEM)) { + + /* Only static or DHCP connections can be left up */ + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); + g_assert (s_ip4); + + method = nm_setting_ip4_config_get_method (s_ip4); + if ( !method + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + take_down = FALSE; + } + } + if (priv->failed_to_disconnected_id) { g_source_remove (priv->failed_to_disconnected_id); priv->failed_to_disconnected_id = 0; } - /* - * In dispose, you are supposed to free all types referenced from this - * object which might themselves hold a reference to self. Generally, - * the most simple solution is to unref all members on which you own a - * reference. - */ - - if (priv->managed) { + if (priv->managed && take_down) { NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; nm_device_take_down (self, FALSE, NM_DEVICE_STATE_REASON_REMOVED); @@ -2231,7 +2253,8 @@ dispose (GObject *object) activation_source_clear (self, TRUE); - nm_device_set_use_dhcp (self, FALSE); + if (!take_down) + nm_device_set_use_dhcp (self, FALSE); if (priv->dnsmasq_manager) { if (priv->dnsmasq_state_id) { @@ -2577,7 +2600,7 @@ nm_device_set_managed (NMDevice *device, } static gboolean -nm_device_spec_match_list (NMDeviceInterface *device, const GSList *specs) +spec_match_list (NMDeviceInterface *device, const GSList *specs) { NMDevice *self; @@ -2590,6 +2613,16 @@ nm_device_spec_match_list (NMDeviceInterface *device, const GSList *specs) return FALSE; } +static NMConnection * +connection_match_config (NMDeviceInterface *device, const GSList *connections) +{ + g_return_val_if_fail (device != NULL, FALSE); + + if (NM_DEVICE_GET_CLASS (device)->connection_match_config) + return NM_DEVICE_GET_CLASS (device)->connection_match_config (NM_DEVICE (device), connections); + return NULL; +} + void nm_device_set_dhcp_timeout (NMDevice *device, guint32 timeout) { diff --git a/src/nm-device.h b/src/nm-device.h index 31c58fb547..f3d63235e4 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -106,6 +106,8 @@ typedef struct { gboolean (* can_interrupt_activation) (NMDevice *self); gboolean (* spec_match_list) (NMDevice *self, const GSList *specs); + + NMConnection * (* connection_match_config) (NMDevice *self, const GSList *connections); } NMDeviceClass; diff --git a/src/nm-manager.c b/src/nm-manager.c index 731589c40a..87338a10d5 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -348,12 +348,24 @@ manager_device_state_changed (NMDevice *device, /* Removes a device from a device list; returns the start of the new device list */ static GSList * -remove_one_device (NMManager *manager, GSList *list, NMDevice *device) +remove_one_device (NMManager *manager, + GSList *list, + NMDevice *device, + gboolean quitting) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - if (nm_device_get_managed (device)) - nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED); + if (nm_device_get_managed (device)) { + gboolean unmanage = !quitting; + + /* Don't unmanage active assume-connection-capable devices at shutdown */ + if ( nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device)) + && nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) + unmanage = FALSE; + + if (unmanage) + nm_device_set_managed (device, FALSE, NM_DEVICE_STATE_REASON_REMOVED); + } g_signal_handlers_disconnect_by_func (device, manager_device_state_changed, manager); @@ -372,7 +384,7 @@ modem_removed (NMModemManager *modem_manager, NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - priv->devices = remove_one_device (self, priv->devices, modem); + priv->devices = remove_one_device (self, priv->devices, modem, FALSE); } static void @@ -1153,6 +1165,10 @@ add_device (NMManager *self, NMDevice *device) char *path; static guint32 devcount = 0; const GSList *unmanaged_specs; + GSList *connections = NULL; + NMConnection *existing; + GHashTableIter iter; + gpointer value; priv->devices = g_slist_append (priv->devices, device); @@ -1189,6 +1205,16 @@ add_device (NMManager *self, NMDevice *device) nm_info ("(%s): exported as %s", iface, path); g_free (path); + /* Check if we should assume the device's active connection by matching its + * config with an existing system connection. + */ + g_hash_table_iter_init (&iter, priv->system_connections); + while (g_hash_table_iter_next (&iter, NULL, &value)) + connections = g_slist_append (connections, value); + existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device), + (const GSList *) connections); + g_slist_free (connections); + /* Start the device if it's supposed to be managed */ unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings); if (!priv->sleeping && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) @@ -1302,7 +1328,7 @@ bluez_manager_resync_devices (NMManager *self) priv->devices = keep; while (g_slist_length (gone)) - gone = remove_one_device (self, gone, NM_DEVICE (gone->data)); + gone = remove_one_device (self, gone, NM_DEVICE (gone->data), FALSE); } else { g_slist_free (keep); g_slist_free (gone); @@ -1372,7 +1398,7 @@ bluez_manager_bdaddr_removed_cb (NMBluezManager *bluez_mgr, NMDevice *device = NM_DEVICE (iter->data); if (!strcmp (nm_device_get_udi (device), object_path)) { - priv->devices = remove_one_device (self, priv->devices, device); + priv->devices = remove_one_device (self, priv->devices, device, FALSE); break; } } @@ -1433,8 +1459,7 @@ udev_device_removed_cb (NMUdevManager *manager, ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); device = find_device_by_ifindex (self, ifindex); if (device) - priv->devices = remove_one_device (self, priv->devices, device); - + priv->devices = remove_one_device (self, priv->devices, device, FALSE); } static void @@ -2522,7 +2547,7 @@ dispose (GObject *object) while (g_slist_length (priv->devices)) { NMDevice *device = NM_DEVICE (priv->devices->data); - priv->devices = remove_one_device (manager, priv->devices, device); + priv->devices = remove_one_device (manager, priv->devices, device, TRUE); } user_destroy_connections (manager); From 4bab33405be01fd263373e530d712f3eb8d01d0d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 4 Aug 2009 14:55:22 -0400 Subject: [PATCH 13/19] ipv6: fix missing introspection file in distcheck --- introspection/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/introspection/Makefile.am b/introspection/Makefile.am index e284d0c0ed..eee9eb1891 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -12,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 \ From ff88cf12c2de43081f1a7c93a2565658119b7894 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 5 Aug 2009 16:34:02 -0400 Subject: [PATCH 14/19] olpc: add mesh device logic and config setting --- Makefile.am | 2 +- callouts/77-nm-olpc-mesh.rules | 6 + callouts/Makefile.am | 4 + configure.ac | 8 + include/NetworkManager.h | 3 +- introspection/Makefile.am | 1 + introspection/nm-device-olpc-mesh.xml | 32 + libnm-util/Makefile.am | 2 + libnm-util/libnm-util.ver | 4 + libnm-util/nm-connection.c | 6 + libnm-util/nm-setting-olpc-mesh.c | 265 +++++++ libnm-util/nm-setting-olpc-mesh.h | 52 ++ src/Makefile.am | 6 + src/nm-device-olpc-mesh.c | 979 ++++++++++++++++++++++++++ src/nm-device-olpc-mesh.h | 85 +++ src/nm-manager.c | 3 + src/nm-udev-manager.c | 12 +- 17 files changed, 1467 insertions(+), 3 deletions(-) create mode 100644 callouts/77-nm-olpc-mesh.rules create mode 100644 introspection/nm-device-olpc-mesh.xml create mode 100644 libnm-util/nm-setting-olpc-mesh.c create mode 100644 libnm-util/nm-setting-olpc-mesh.h create mode 100644 src/nm-device-olpc-mesh.c create mode 100644 src/nm-device-olpc-mesh.h diff --git a/Makefile.am b/Makefile.am index a61200f2db..3e2fec99f4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,7 +27,7 @@ EXTRA_DIST = \ intltool-merge.in \ intltool-update.in -DISTCHECK_CONFIGURE_FLAGS = --with-tests=yes --with-docs=yes +DISTCHECK_CONFIGURE_FLAGS = --with-tests=yes --with-docs=yes --with-udev-dir=$$dc_install_base/lib/udev DISTCLEANFILES = intltool-extract intltool-merge intltool-update diff --git a/callouts/77-nm-olpc-mesh.rules b/callouts/77-nm-olpc-mesh.rules new file mode 100644 index 0000000000..a1a1554c2b --- /dev/null +++ b/callouts/77-nm-olpc-mesh.rules @@ -0,0 +1,6 @@ +# do not edit this file, it will be overwritten on update + +# The fact that this device is driven by libertas is not currently exposed +# in the sysfs tree..? +KERNEL=="msh*", SUBSYSTEM=="net", DRIVERS=="usb", ATTRS{idVendor}=="1286", ATTRS{idProduct}=="2001", ENV{ID_NM_OLPC_MESH}="1" + diff --git a/callouts/Makefile.am b/callouts/Makefile.am index d77fea5880..385537ef62 100644 --- a/callouts/Makefile.am +++ b/callouts/Makefile.am @@ -62,6 +62,9 @@ nm_dispatcher_action_LDADD = \ nm-dispatcher-glue.h: nm-dispatcher.xml dbus-binding-tool --prefix=nm_dispatcher --mode=glib-server --output=$@ $< +udevrulesdir = $(UDEV_BASE_DIR)/rules.d +udevrules_DATA = 77-nm-olpc-mesh.rules + dbusactivationdir = $(datadir)/dbus-1/system-services dbusactivation_in_files = org.freedesktop.nm_dispatcher.service.in dbusactivation_DATA = $(dbusactivation_in_files:.service.in=.service) @@ -85,6 +88,7 @@ CLEANFILES = $(BUILT_SOURCES) $(dbusactivation_DATA) EXTRA_DIST = \ $(dbusservice_DATA) \ + $(udevrules_DATA) \ $(dbusactivation_in_files) \ nm-dispatcher.xml diff --git a/configure.ac b/configure.ac index adaf2e040f..320f51a6a6 100644 --- a/configure.ac +++ b/configure.ac @@ -193,6 +193,14 @@ PKG_CHECK_MODULES(GUDEV, gudev-1.0) AC_SUBST(GUDEV_CFLAGS) AC_SUBST(GUDEV_LIBS) +AC_ARG_WITH(udev-dir, AS_HELP_STRING([--with-udev-dir=DIR], [where the udev base directory is])) +if test -n "$with_udev_dir" ; then + UDEV_BASE_DIR="$with_udev_dir" +else + UDEV_BASE_DIR="/lib/udev" +fi +AC_SUBST(UDEV_BASE_DIR) + PKG_CHECK_EXISTS(gio-2.0,[have_gio=yes],[have_gio=no]) if test x"$have_gio" = "xno"; then AC_DEFINE([NO_GIO],[1],[Define if you don't have GIO]) diff --git a/include/NetworkManager.h b/include/NetworkManager.h index fcef15bc7f..d48552bc07 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -77,7 +77,8 @@ typedef enum NMDeviceType NM_DEVICE_TYPE_WIFI, NM_DEVICE_TYPE_GSM, NM_DEVICE_TYPE_CDMA, - NM_DEVICE_TYPE_BT /* Bluetooth */ + NM_DEVICE_TYPE_BT, /* Bluetooth */ + NM_DEVICE_TYPE_OLPC_MESH } NMDeviceType; /* DEPRECATED TYPE NAMES */ diff --git a/introspection/Makefile.am b/introspection/Makefile.am index eee9eb1891..0dc286a9cd 100644 --- a/introspection/Makefile.am +++ b/introspection/Makefile.am @@ -6,6 +6,7 @@ EXTRA_DIST = \ nm-access-point.xml \ nm-device-bt.xml \ nm-device-wifi.xml \ + nm-device-olpc-mesh.xml \ nm-device-ethernet.xml \ nm-device-cdma.xml \ nm-device-gsm.xml \ diff --git a/introspection/nm-device-olpc-mesh.xml b/introspection/nm-device-olpc-mesh.xml new file mode 100644 index 0000000000..7d326b6b95 --- /dev/null +++ b/introspection/nm-device-olpc-mesh.xml @@ -0,0 +1,32 @@ + + + + + + + The hardware address of the device. + + + + + The object path of the companion device. + + + + + The currently active channel. + + + + + + + A dictionary containing the FIXME: check changed parameters. + + + + Emitted when the wireless device's properties changed. + + + + diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am index 1a5a94eb3f..cbf6de36cb 100644 --- a/libnm-util/Makefile.am +++ b/libnm-util/Makefile.am @@ -23,6 +23,7 @@ libnm_util_include_HEADERS = \ nm-setting-serial.h \ nm-setting-gsm.h \ nm-setting-cdma.h \ + nm-setting-olpc-mesh.h \ nm-setting-wired.h \ nm-setting-wireless.h \ nm-setting-wireless-security.h \ @@ -46,6 +47,7 @@ libnm_util_la_SOURCES= \ nm-setting-serial.c \ nm-setting-gsm.c \ nm-setting-cdma.c \ + nm-setting-olpc-mesh.c \ nm-setting-wired.c \ nm-setting-wireless.c \ nm-setting-wireless-security.c \ diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver index 92228f5257..5a89a71581 100644 --- a/libnm-util/libnm-util.ver +++ b/libnm-util/libnm-util.ver @@ -303,6 +303,10 @@ global: nm_setting_wireless_security_remove_pairwise; nm_setting_wireless_security_remove_proto; nm_setting_wireless_security_set_wep_key; + nm_setting_olpc_mesh_get_type; + nm_setting_olpc_mesh_get_ssid; + nm_setting_olpc_mesh_get_channel; + nm_setting_olpc_mesh_get_dhcp_anycast_address; nm_utils_deinit; nm_utils_escape_ssid; nm_utils_gvalue_hash_dup; diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c index 810032ae54..1d186a6e91 100644 --- a/libnm-util/nm-connection.c +++ b/libnm-util/nm-connection.c @@ -41,6 +41,7 @@ #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" #include "nm-setting-vpn.h" +#include "nm-setting-olpc-mesh.h" #include "nm-setting-serial.h" #include "nm-setting-gsm.h" @@ -216,6 +217,11 @@ register_default_settings (void) NM_SETTING_WIRELESS_ERROR, 1); + register_one_setting (NM_SETTING_OLPC_MESH_SETTING_NAME, + NM_TYPE_SETTING_OLPC_MESH, + NM_SETTING_OLPC_MESH_ERROR, + 1); + register_one_setting (NM_SETTING_GSM_SETTING_NAME, NM_TYPE_SETTING_GSM, NM_SETTING_GSM_ERROR, diff --git a/libnm-util/nm-setting-olpc-mesh.c b/libnm-util/nm-setting-olpc-mesh.c new file mode 100644 index 0000000000..dd0e1d64ce --- /dev/null +++ b/libnm-util/nm-setting-olpc-mesh.c @@ -0,0 +1,265 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +/* + * Dan Williams + * Tambet Ingo + * Sjoerd Simons + * Daniel Drake + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2007 - 2008 Red Hat, Inc. + * (C) Copyright 2007 - 2008 Novell, Inc. + * (C) Copyright 2009 One Laptop per Child + */ + +#include +#include +#include + +#include "NetworkManager.h" +#include "nm-setting-olpc-mesh.h" +#include "nm-param-spec-specialized.h" +#include "nm-utils.h" +#include "nm-dbus-glib-types.h" +#include "nm-utils-private.h" + +GQuark +nm_setting_olpc_mesh_error_quark (void) +{ + static GQuark quark; + + if (G_UNLIKELY (!quark)) + quark = g_quark_from_static_string ("nm-setting-wireless-mesh-error-quark"); + return quark; +} + +/* This should really be standard. */ +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +GType +nm_setting_olpc_mesh_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + /* Unknown error. */ + ENUM_ENTRY (NM_SETTING_OLPC_MESH_ERROR_UNKNOWN, "UnknownError"), + /* The specified property was invalid. */ + ENUM_ENTRY (NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY, "InvalidProperty"), + /* The specified property was missing and is required. */ + ENUM_ENTRY (NM_SETTING_OLPC_MESH_ERROR_MISSING_PROPERTY, "MissingProperty"), + { 0, 0, 0 } + }; + etype = g_enum_register_static ("NMSettingWirelessError", values); + } + return etype; +} + +static void nm_setting_olpc_mesh_init (NMSettingOlpcMesh *setting); + +G_DEFINE_TYPE (NMSettingOlpcMesh, nm_setting_olpc_mesh, NM_TYPE_SETTING) + +#define NM_SETTING_OLPC_MESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMeshPrivate)) + +typedef struct { + GByteArray *ssid; + guint32 channel; + GByteArray *dhcp_anycast_addr; +} NMSettingOlpcMeshPrivate; + +enum { + PROP_0, + PROP_SSID, + PROP_CHANNEL, + PROP_DHCP_ANYCAST_ADDRESS, + + LAST_PROP +}; + +static void +nm_setting_olpc_mesh_init (NMSettingOlpcMesh *setting) +{ + g_object_set (setting, NM_SETTING_NAME, NM_SETTING_OLPC_MESH_SETTING_NAME, NULL); +} + +const GByteArray * +nm_setting_olpc_mesh_get_ssid (NMSettingOlpcMesh *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (setting), NULL); + + return NM_SETTING_OLPC_MESH_GET_PRIVATE (setting)->ssid; +} + +guint32 +nm_setting_olpc_mesh_get_channel (NMSettingOlpcMesh *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (setting), 0); + + return NM_SETTING_OLPC_MESH_GET_PRIVATE (setting)->channel; +} + +const GByteArray * +nm_setting_olpc_mesh_get_dhcp_anycast_address (NMSettingOlpcMesh *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (setting), NULL); + + return NM_SETTING_OLPC_MESH_GET_PRIVATE (setting)->dhcp_anycast_addr; +} + +static gboolean +verify (NMSetting *setting, GSList *all_settings, GError **error) +{ + NMSettingOlpcMeshPrivate *priv = NM_SETTING_OLPC_MESH_GET_PRIVATE (setting); + + if (!priv->ssid) { + g_set_error (error, + NM_SETTING_OLPC_MESH_ERROR, + NM_SETTING_OLPC_MESH_ERROR_MISSING_PROPERTY, + NM_SETTING_OLPC_MESH_SSID); + return FALSE; + } + + if (!priv->ssid->len || priv->ssid->len > 32) { + g_set_error (error, + NM_SETTING_OLPC_MESH_ERROR, + NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY, + NM_SETTING_OLPC_MESH_SSID); + return FALSE; + } + + if (priv->channel == 0 || priv->channel > 13) { + g_set_error (error, + NM_SETTING_OLPC_MESH_ERROR, + NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY, + NM_SETTING_OLPC_MESH_CHANNEL); + return FALSE; + } + + if (priv->dhcp_anycast_addr && priv->dhcp_anycast_addr->len != ETH_ALEN) { + g_set_error (error, + NM_SETTING_OLPC_MESH_ERROR, + NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY, + NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS); + return FALSE; + } + + return TRUE; +} + +static void +finalize (GObject *object) +{ + NMSettingOlpcMeshPrivate *priv = NM_SETTING_OLPC_MESH_GET_PRIVATE (object); + + if (priv->ssid) + g_byte_array_free (priv->ssid, TRUE); + if (priv->dhcp_anycast_addr) + g_byte_array_free (priv->dhcp_anycast_addr, TRUE); + + G_OBJECT_CLASS (nm_setting_olpc_mesh_parent_class)->finalize (object); +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingOlpcMeshPrivate *priv = NM_SETTING_OLPC_MESH_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_SSID: + if (priv->ssid) + g_byte_array_free (priv->ssid, TRUE); + priv->ssid = g_value_dup_boxed (value); + break; + case PROP_CHANNEL: + priv->channel = g_value_get_uint (value); + break; + case PROP_DHCP_ANYCAST_ADDRESS: + if (priv->dhcp_anycast_addr) + g_byte_array_free (priv->dhcp_anycast_addr, TRUE); + priv->dhcp_anycast_addr = g_value_dup_boxed (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingOlpcMesh *setting = NM_SETTING_OLPC_MESH (object); + + switch (prop_id) { + case PROP_SSID: + g_value_set_boxed (value, nm_setting_olpc_mesh_get_ssid (setting)); + break; + case PROP_CHANNEL: + g_value_set_uint (value, nm_setting_olpc_mesh_get_channel (setting)); + break; + case PROP_DHCP_ANYCAST_ADDRESS: + g_value_set_boxed (value, nm_setting_olpc_mesh_get_dhcp_anycast_address (setting)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_setting_olpc_mesh_class_init (NMSettingOlpcMeshClass *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 (NMSettingOlpcMeshPrivate)); + + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + parent_class->verify = verify; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_SSID, + _nm_param_spec_specialized (NM_SETTING_OLPC_MESH_SSID, + "SSID", + "SSID", + DBUS_TYPE_G_UCHAR_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + + g_object_class_install_property + (object_class, PROP_CHANNEL, + g_param_spec_uint (NM_SETTING_OLPC_MESH_CHANNEL, + "Channel", + "Channel", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE)); + + + g_object_class_install_property + (object_class, PROP_DHCP_ANYCAST_ADDRESS, + _nm_param_spec_specialized (NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, + "Anycast DHCP MAC address", + "Anycast DHCP MAC address", + DBUS_TYPE_G_UCHAR_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE)); + +} diff --git a/libnm-util/nm-setting-olpc-mesh.h b/libnm-util/nm-setting-olpc-mesh.h new file mode 100644 index 0000000000..173853d3f7 --- /dev/null +++ b/libnm-util/nm-setting-olpc-mesh.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ + +#ifndef NM_SETTING_OLPC_MESH_H +#define NM_SETTING_OLPC_MESH_H + +#include + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_OLPC_MESH (nm_setting_olpc_mesh_get_type ()) +#define NM_SETTING_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMesh)) +#define NM_SETTING_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMeshClass)) +#define NM_IS_SETTING_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_OLPC_MESH)) +#define NM_IS_SETTING_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SETTING_OLPC_MESH)) +#define NM_SETTING_OLPC_MESH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMeshClass)) + +#define NM_SETTING_OLPC_MESH_SETTING_NAME "802-11-olpc-mesh" + +typedef enum +{ + NM_SETTING_OLPC_MESH_ERROR_UNKNOWN = 0, + NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY, + NM_SETTING_OLPC_MESH_ERROR_MISSING_PROPERTY +} NMSettingOlpcMeshError; + +#define NM_TYPE_SETTING_OLPC_MESH_ERROR (nm_setting_olpc_mesh_error_get_type ()) +GType nm_setting_olpc_mesh_error_get_type (void); + +#define NM_SETTING_OLPC_MESH_ERROR nm_setting_olpc_mesh_error_quark () +GQuark nm_setting_olpc_mesh_error_quark (void); + +#define NM_SETTING_OLPC_MESH_SSID "ssid" +#define NM_SETTING_OLPC_MESH_CHANNEL "channel" +#define NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS "dhcp-anycast-address" + +typedef struct { + NMSetting parent; +} NMSettingOlpcMesh; + +typedef struct { + NMSettingClass parent; +} NMSettingOlpcMeshClass; + +GType nm_setting_olpc_mesh_get_type (void); + +const GByteArray *nm_setting_olpc_mesh_get_ssid (NMSettingOlpcMesh *setting); +guint32 nm_setting_olpc_mesh_get_channel (NMSettingOlpcMesh *setting); +const GByteArray *nm_setting_olpc_mesh_get_dhcp_anycast_address (NMSettingOlpcMesh *setting); + +G_END_DECLS + +#endif /* NM_SETTING_OLPC_MESH_H */ diff --git a/src/Makefile.am b/src/Makefile.am index d8878e05df..915e972daa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -68,6 +68,8 @@ NetworkManager_SOURCES = \ nm-device-ethernet.h \ nm-device-wifi.c \ nm-device-wifi.h \ + nm-device-olpc-mesh.c \ + nm-device-olpc-mesh.h \ nm-device-bt.c \ nm-device-bt.h \ NetworkManagerAP.c \ @@ -128,6 +130,9 @@ nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml dbus-binding-tool --prefix=nm_device_bt --mode=glib-server --output=$@ $< +nm-device-olpc-mesh-glue.h: $(top_srcdir)/introspection/nm-device-olpc-mesh.xml + dbus-binding-tool --prefix=nm_device_olpc_mesh --mode=glib-server --output=$@ $< + nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $< @@ -146,6 +151,7 @@ BUILT_SOURCES = \ nm-device-interface-glue.h \ nm-device-ethernet-glue.h \ nm-device-wifi-glue.h \ + nm-device-olpc-mesh-glue.h \ nm-device-bt-glue.h \ nm-ip4-config-glue.h \ nm-ip6-config-glue.h \ diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c new file mode 100644 index 0000000000..743f47cdf7 --- /dev/null +++ b/src/nm-device-olpc-mesh.c @@ -0,0 +1,979 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * Dan Williams + * Sjoerd Simons + * Daniel Drake + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 - 2008 Red Hat, Inc. + * (C) Copyright 2008 Collabora Ltd. + * (C) Copyright 2009 One Laptop per Child + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nm-device.h" +#include "nm-device-wifi.h" +#include "nm-device-olpc-mesh.h" +#include "nm-device-interface.h" +#include "nm-device-private.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" +#include "NetworkManagerPolicy.h" +#include "nm-activation-request.h" +#include "nm-properties-changed-signal.h" +#include "nm-setting-connection.h" +#include "nm-setting-olpc-mesh.h" +#include "NetworkManagerSystem.h" +#include "nm-manager.h" + +#include "nm-device-olpc-mesh-glue.h" + +static void nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self, const GByteArray * ssid); + +G_DEFINE_TYPE (NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE) + +#define NM_DEVICE_OLPC_MESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshPrivate)) + + +enum { + PROP_0, + PROP_HW_ADDRESS, + PROP_COMPANION, + PROP_ACTIVE_CHANNEL, + PROP_IFINDEX, + + LAST_PROP +}; + +enum { + PROPERTIES_CHANGED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef enum +{ + NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH = 0, + NM_OLPC_MESH_ERROR_CONNECTION_INVALID, + NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE, +} NMOlpcMeshError; + +#define NM_OLPC_MESH_ERROR (nm_olpc_mesh_error_quark ()) +#define NM_TYPE_OLPC_MESH_ERROR (nm_olpc_mesh_error_get_type ()) + + +struct _NMDeviceOlpcMeshPrivate +{ + gboolean dispose_has_run; + + struct ether_addr hw_addr; + guint32 ifindex; + + GByteArray * ssid; + + gint8 num_freqs; + guint32 freqs[IW_MAX_FREQUENCIES]; + + guint8 we_version; + gboolean up; + + NMDevice * companion; + gboolean stage1_waiting; + guint device_added_cb; +}; + +static GQuark +nm_olpc_mesh_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("nm-mesh-error"); + return quark; +} + +/* This should really be standard. */ +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +static GType +nm_olpc_mesh_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + /* Connection was not a wireless connection. */ + ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH, "ConnectionNotMesh"), + /* Connection was not a valid wireless connection. */ + ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_INVALID, "ConnectionInvalid"), + /* Connection does not apply to this device. */ + ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"), + { 0, 0, 0 } + }; + etype = g_enum_register_static ("NMOlpcMeshError", values); + } + return etype; +} + +static guint32 +real_get_generic_capabilities (NMDevice *dev) +{ + int fd; + guint32 caps = NM_DEVICE_CAP_NONE; + struct iw_range range; + struct iwreq wrq; + const char *iface = nm_device_get_iface (dev); + + /* Check for Wireless Extensions support >= 16 for wireless devices */ + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + nm_warning ("couldn't open control socket."); + goto out; + } + + memset (&wrq, 0, sizeof (struct iwreq)); + memset (&range, 0, sizeof (struct iw_range)); + strncpy (wrq.ifr_name, iface, IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) ⦥ + wrq.u.data.length = sizeof (struct iw_range); + + if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0) { + nm_warning ("couldn't get driver range information."); + goto out; + } + + if ((wrq.u.data.length < 300) || (range.we_version_compiled < 16)) { + nm_warning ("%s: driver's Wireless Extensions version (%d) is too old.", + iface, range.we_version_compiled); + goto out; + } else { + caps |= NM_DEVICE_CAP_NM_SUPPORTED; + } + +out: + if (fd >= 0) + close (fd); + return caps; +} + +static void +nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + + priv->dispose_has_run = FALSE; + priv->we_version = 0; + priv->companion = NULL; + priv->stage1_waiting = FALSE; + + memset (&(priv->hw_addr), 0, sizeof (struct ether_addr)); +} + +static guint32 iw_freq_to_uint32 (struct iw_freq *freq) +{ + if (freq->e == 0) { + /* Some drivers report channel not frequency. Convert to a + * frequency; but this assumes that the device is in b/g mode. + */ + if ((freq->m >= 1) && (freq->m <= 13)) + return 2407 + (5 * freq->m); + else if (freq->m == 14) + return 2484; + } + + return (guint32) (((double) freq->m) * pow (10, freq->e) / 1000000); +} + + +/* Until a new wireless-tools comes out that has the defs and the structure, + * need to copy them here. + */ +/* Scan capability flags - in (struct iw_range *)->scan_capa */ +#define NM_IW_SCAN_CAPA_NONE 0x00 +#define NM_IW_SCAN_CAPA_ESSID 0x01 + +struct iw_range_with_scan_capa +{ + guint32 throughput; + guint32 min_nwid; + guint32 max_nwid; + guint16 old_num_channels; + guint8 old_num_frequency; + + guint8 scan_capa; +/* don't need the rest... */ +}; + + + + +static GObject* +constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) +{ + GObject *object; + GObjectClass *klass; + NMDeviceOlpcMesh *self; + NMDeviceOlpcMeshPrivate *priv; + const char *iface; + int fd; + struct iw_range range; + struct iwreq wrq; + int i; + + klass = G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class); + object = klass->constructor (type, n_construct_params, construct_params); + if (!object) + return NULL; + + self = NM_DEVICE_OLPC_MESH (object); + priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + + iface = nm_device_get_iface (NM_DEVICE (self)); + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) + goto error; + + memset (&wrq, 0, sizeof (struct iwreq)); + memset (&range, 0, sizeof (struct iw_range)); + strncpy (wrq.ifr_name, iface, IFNAMSIZ); + wrq.u.data.pointer = (caddr_t) ⦥ + wrq.u.data.length = sizeof (struct iw_range); + + if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0) + goto error; + + priv->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES); + for (i = 0; i < priv->num_freqs; i++) + priv->freqs[i] = iw_freq_to_uint32 (&range.freq[i]); + + priv->we_version = range.we_version_compiled; + + close (fd); + + /* shorter timeout for mesh connectivity */ + nm_device_set_dhcp_timeout (NM_DEVICE (self), 20); + return object; + +error: + if (fd >= 0) + close (fd); + g_object_unref (object); + return NULL; +} + +static gboolean +real_hw_is_up (NMDevice *device) +{ + return nm_system_device_is_up (device); +} + +static gboolean +real_hw_bring_up (NMDevice *dev, gboolean *no_firmware) +{ + return nm_system_device_set_up_down (dev, TRUE, no_firmware); +} + +static void +real_hw_take_down (NMDevice *dev) +{ + nm_system_device_set_up_down (dev, FALSE, NULL); +} + +static gboolean +real_is_up (NMDevice *device) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + + return priv->up; +} + +static gboolean +real_bring_up (NMDevice *dev) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + + priv->up = TRUE; + return TRUE; +} + +static void +device_cleanup (NMDeviceOlpcMesh *self) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + + if (priv->ssid) { + g_byte_array_free (priv->ssid, TRUE); + priv->ssid = NULL; + } + priv->up = FALSE; +} + +static void +real_take_down (NMDevice *dev) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev); + + device_cleanup (self); +} + +static gboolean +real_check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error) +{ + NMSettingConnection *s_con; + NMSettingOlpcMesh *s_mesh; + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + g_assert (s_con); + + if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) { + g_set_error (error, + NM_OLPC_MESH_ERROR, NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH, + "The connection was not a Mesh connection."); + return FALSE; + } + + s_mesh = NM_SETTING_OLPC_MESH (nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH)); + if (!s_mesh) { + g_set_error (error, + NM_OLPC_MESH_ERROR, NM_OLPC_MESH_ERROR_CONNECTION_INVALID, + "The connection was not a valid Mesh connection."); + return FALSE; + } + + return TRUE; +} + +/* + * nm_device_olpc_mesh_get_address + * + * Get a device's hardware address + * + */ +static void +nm_device_olpc_mesh_get_address (NMDeviceOlpcMesh *self, + struct ether_addr *addr) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + g_return_if_fail (self != NULL); + g_return_if_fail (addr != NULL); + + memcpy (addr, &(priv->hw_addr), sizeof (struct ether_addr)); +} + +static int +create_socket_with_request (NMDevice *self, struct iwreq *req) +{ + int sk; + const char * iface; + + g_return_val_if_fail (self != NULL, -1); + + sk = socket (AF_INET, SOCK_DGRAM, 0); + if (!sk) { + nm_error ("Couldn't create socket: %d.", errno); + return -1; + } + + memset (req, 0, sizeof (struct iwreq)); + iface = nm_device_get_iface (NM_DEVICE (self)); + strncpy (req->ifr_name, iface, IFNAMSIZ); + + return sk; +} + +static guint32 +nm_device_olpc_mesh_get_channel (NMDeviceOlpcMesh *self) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + int sk; + struct iwreq req; + int ret = 0; + int i; + guint32 freq; + + sk = create_socket_with_request (NM_DEVICE (self), &req); + if (sk == -1) + return 0; + + if ((ioctl (sk, SIOCGIWFREQ, &req)) != 0) { + nm_warning ("%s: failed to get channel (errno: %d))", + nm_device_get_iface (NM_DEVICE (self)), errno); + goto out; + } + + freq = iw_freq_to_uint32 (&req.u.freq); + + for (i = 0 ; i < priv->num_freqs; i++) { + if (freq == priv->freqs[i]) + break; + } + if (i < priv->num_freqs) + ret = i + 1; + +out: + if (sk >= 0) + close (sk); + return ret; +} + +static void +nm_device_olpc_mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel) +{ + int sk; + struct iwreq req; + + if (nm_device_olpc_mesh_get_channel (self) == channel) + return; + + sk = create_socket_with_request (NM_DEVICE (self), &req); + if (sk < 0) + return; + + if (channel > 0) { + req.u.freq.flags = IW_FREQ_FIXED; + req.u.freq.e = 0; + req.u.freq.m = channel; + } + + if (ioctl (sk, SIOCSIWFREQ, &req) != 0) + nm_warning ("%s: failed to set to channel %d (errno: %d))", + nm_device_get_iface (NM_DEVICE (self)), channel, errno); + else + g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL); + + close (sk); +} + +static void +nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self, const GByteArray * ssid) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + int sk; + struct iwreq wrq; + const char * iface; + guint32 len = 0; + char buf[IW_ESSID_MAX_SIZE + 1]; + + g_return_if_fail (self != NULL); + + sk = socket (AF_INET, SOCK_DGRAM, 0); + if (!sk) { + nm_error ("Couldn't create socket: %d.", errno); + return; + } + + iface = nm_device_get_iface (NM_DEVICE (self)); + + memset (buf, 0, sizeof (buf)); + if (ssid) { + len = ssid->len; + memcpy (buf, ssid->data, MIN (sizeof (buf) - 1, len)); + } + wrq.u.essid.pointer = (caddr_t) buf; + + if (priv->we_version < 21) { + /* For historic reasons, set SSID length to include one extra + * character, C string nul termination, even though SSID is + * really an octet string that should not be presented as a C + * string. Some Linux drivers decrement the length by one and + * can thus end up missing the last octet of the SSID if the + * length is not incremented here. WE-21 changes this to + * explicitly require the length _not_ to include nul + * termination. */ + if (len) + len++; + } + wrq.u.essid.length = len; + wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */ + + strncpy (wrq.ifr_name, iface, IFNAMSIZ); + + if (ioctl (sk, SIOCSIWESSID, &wrq) < 0) { + if (errno != ENODEV) { + nm_warning ("error setting SSID to '%s' for device %s: %s", + ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(null)", + iface, strerror (errno)); + } + } + + close (sk); +} + + +guint32 +nm_device_olpc_mesh_get_ifindex (NMDeviceOlpcMesh *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->ifindex; +} + +/****************************************************************************/ + +static void +real_update_hw_address (NMDevice *dev) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + struct ifreq req; + int ret, fd; + + fd = socket (PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + g_warning ("could not open control socket."); + return; + } + + memset (&req, 0, sizeof (struct ifreq)); + strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ); + ret = ioctl (fd, SIOCGIFHWADDR, &req); + if (ret) { + nm_warning ("%s: (%s) error getting hardware address: %d", + __func__, nm_device_get_iface (dev), errno); + goto out; + } + + if (memcmp (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr))) { + memcpy (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr)); + g_object_notify (G_OBJECT (dev), NM_DEVICE_OLPC_MESH_HW_ADDRESS); + } + +out: + close (fd); +} + + +static NMActStageReturn +real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (dev); + gboolean scanning; + + /* disconnect companion device, if it is connected */ + if (nm_device_get_act_request (NM_DEVICE (priv->companion))) { + nm_warning ("disconnecting companion device"); + nm_device_state_changed (NM_DEVICE (priv->companion), + NM_DEVICE_STATE_DISCONNECTED, + NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED); + nm_warning ("companion disconnected"); + } + + + /* wait with continuing configuration untill the companion device is done + * scanning */ + g_object_get (priv->companion, "scanning", &scanning, NULL); + if (scanning) { + priv->stage1_waiting = TRUE; + return NM_ACT_STAGE_RETURN_POSTPONE; + } + + return NM_ACT_STAGE_RETURN_SUCCESS; +} + +static NMActStageReturn +real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev); + NMConnection *connection; + NMSettingOlpcMesh *s_mesh; + NMActRequest *req; + guint32 channel; + const GByteArray *anycast_addr_array; + guint8 *anycast_addr = NULL; + + req = nm_device_get_act_request (dev); + g_assert (req); + + connection = nm_act_request_get_connection (req); + g_assert (connection); + + s_mesh = NM_SETTING_OLPC_MESH (nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH)); + g_assert (s_mesh); + + channel = nm_setting_olpc_mesh_get_channel (s_mesh); + if (channel != 0) + nm_device_olpc_mesh_set_channel (self, channel); + nm_device_olpc_mesh_set_ssid (self, nm_setting_olpc_mesh_get_ssid (s_mesh)); + + anycast_addr_array = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh); + if (anycast_addr_array) + anycast_addr = anycast_addr_array->data; + + nm_device_set_dhcp_anycast_address (dev, anycast_addr); + return NM_ACT_STAGE_RETURN_SUCCESS; +} + +static NMActStageReturn +real_act_stage4_ip4_config_timeout (NMDevice *dev, + NMIP4Config **config, + NMDeviceStateReason *reason) +{ + return NM_ACT_STAGE_RETURN_FAILURE; +} + + +static void +nm_device_olpc_mesh_dispose (GObject *object) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + + if (priv->dispose_has_run) { + G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); + return; + } + + priv->dispose_has_run = TRUE; + + device_cleanup (self); + + if (priv->device_added_cb != 0) + g_source_remove (priv->device_added_cb); + + priv->device_added_cb = 0; + + G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceOlpcMesh *device = NM_DEVICE_OLPC_MESH (object); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device); + struct ether_addr hw_addr; + + switch (prop_id) { + case PROP_HW_ADDRESS: + nm_device_olpc_mesh_get_address (device, &hw_addr); + g_value_take_string (value, nm_ether_ntop (&hw_addr)); + break; + case PROP_COMPANION: + g_value_set_string (value, nm_device_get_path (priv->companion)); + break; + case PROP_ACTIVE_CHANNEL: + g_value_set_uint (value, nm_device_olpc_mesh_get_channel (device)); + break; + case PROP_IFINDEX: + g_value_set_uint (value, nm_device_olpc_mesh_get_ifindex (device)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_IFINDEX: + /* construct-only */ + priv->ifindex = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMDeviceOlpcMeshPrivate)); + + object_class->constructor = constructor; + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->dispose = nm_device_olpc_mesh_dispose; + + parent_class->get_type_capabilities = NULL; + parent_class->get_generic_capabilities = real_get_generic_capabilities; + parent_class->hw_is_up = real_hw_is_up; + parent_class->hw_bring_up = real_hw_bring_up; + parent_class->hw_take_down = real_hw_take_down; + parent_class->is_up = real_is_up; + parent_class->bring_up = real_bring_up; + parent_class->take_down = real_take_down; + parent_class->update_hw_address = real_update_hw_address; + parent_class->check_connection_compatible = real_check_connection_compatible; + + parent_class->act_stage1_prepare = real_act_stage1_prepare; + parent_class->act_stage2_config = real_act_stage2_config; + parent_class->act_stage4_ip4_config_timeout = real_act_stage4_ip4_config_timeout; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_HW_ADDRESS, + g_param_spec_string (NM_DEVICE_OLPC_MESH_HW_ADDRESS, + "MAC Address", + "Hardware MAC address", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property + (object_class, PROP_COMPANION, + g_param_spec_string (NM_DEVICE_OLPC_MESH_COMPANION, + "Companion device", + "Companion device object path", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property + (object_class, PROP_ACTIVE_CHANNEL, + g_param_spec_uint (NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL, + "Active channel", + "Active channel", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, PROP_IFINDEX, + g_param_spec_uint (NM_DEVICE_OLPC_MESH_IFINDEX, + "Ifindex", + "Interface index", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + signals[PROPERTIES_CHANGED] = + nm_properties_changed_signal_new (object_class, + G_STRUCT_OFFSET (NMDeviceOlpcMeshClass, properties_changed)); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), &dbus_glib_nm_device_olpc_mesh_object_info); + + dbus_g_error_domain_register (NM_OLPC_MESH_ERROR, NULL, + NM_TYPE_OLPC_MESH_ERROR); +} + +static void +companion_notify_cb (NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_data) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + gboolean scanning; + + if (!priv->stage1_waiting) + return; + + g_object_get (companion, "scanning", &scanning, NULL); + + if (!scanning) { + priv->stage1_waiting = FALSE; + nm_device_activate_schedule_stage2_device_config (NM_DEVICE (self)); + } +} + +/* disconnect from mesh if someone starts using the companion */ +static void +companion_state_changed_cb (NMDeviceWifi *companion, NMDeviceState state, NMDeviceState old_state, NMDeviceStateReason reason, gpointer user_data) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); + NMDeviceState self_state = nm_device_get_state (NM_DEVICE (self)); + + if ( self_state < NM_DEVICE_STATE_PREPARE + || self_state > NM_DEVICE_STATE_ACTIVATED + || state < NM_DEVICE_STATE_PREPARE + || state > NM_DEVICE_STATE_ACTIVATED) + return; + + nm_debug ("disconnecting mesh due to companion connectivity"); + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_DISCONNECTED, + NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED); +} + +static gboolean +companion_scan_allowed_cb (NMDeviceWifi *companion, gpointer user_data) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); + NMDeviceState state; + + g_object_get (G_OBJECT (self), NM_DEVICE_INTERFACE_STATE, &state, NULL); + + /* Don't allow the companion to scan while configure the mesh interface */ + return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_IP_CONFIG); +} + +static gboolean +companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); + NMDeviceState state; + + g_object_get (G_OBJECT (self), NM_DEVICE_INTERFACE_STATE, &state, NULL); + + /* Don't allow the companion to autoconnect while a mesh connection is + * active */ + return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_ACTIVATED); +} + +static gboolean +is_companion (NMDeviceOlpcMesh *self, NMDevice *other) +{ + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + struct ether_addr their_addr; + + if (!NM_IS_DEVICE_WIFI (other)) + return FALSE; + + nm_device_wifi_get_address (NM_DEVICE_WIFI (other), &their_addr); + + if (memcmp (priv->hw_addr.ether_addr_octet, + their_addr.ether_addr_octet, ETH_ALEN) != 0) { + return FALSE; + } + + /* FIXME detect when our companion leaves */ + priv->companion = other; + + g_source_remove (priv->device_added_cb); + priv->device_added_cb = 0; + + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + + nm_debug ("Found companion device: %s", nm_device_get_iface (other)); + + g_signal_connect (G_OBJECT (other), "state-changed", + G_CALLBACK (companion_state_changed_cb), self); + g_signal_connect (G_OBJECT (other), "notify::scanning", + G_CALLBACK (companion_notify_cb), self); + g_signal_connect (G_OBJECT (other), "scanning-allowed", + G_CALLBACK (companion_scan_allowed_cb), self); + g_signal_connect (G_OBJECT (other), "autoconnect-allowed", + G_CALLBACK (companion_autoconnect_allowed_cb), self); + + return TRUE; +} + +static void +device_added_cb (NMDevice *other, gpointer user_data) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); + + is_companion (self, other); +} + +static gboolean +check_companion_cb (gpointer user_data) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); + NMManager *manager; + GSList *list; + + if (priv->companion != NULL) { + nm_device_state_changed (NM_DEVICE (user_data), + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_NONE); + return FALSE; + } + + if (priv->device_added_cb != 0) + return FALSE; + + manager = nm_manager_get (NULL, NULL, NULL); + + priv->device_added_cb = g_signal_connect (manager, "device-added", + G_CALLBACK (device_added_cb), self); + + list = nm_manager_get_devices (manager); + for (; list != NULL ; list = list->next) + if (is_companion (self, NM_DEVICE (list->data))) + break; + + g_object_unref (manager); + + return FALSE; +} + +static void +state_changed_cb (NMDevice *device, NMDeviceState state, gpointer user_data) +{ + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); + + switch (state) { + case NM_DEVICE_STATE_UNMANAGED: + break; + case NM_DEVICE_STATE_UNAVAILABLE: + /* If transitioning to UNAVAILBLE and the companion device is known then + * transition to DISCONNECTED otherwise wait for our companion. + */ + g_idle_add (check_companion_cb, self); + break; + case NM_DEVICE_STATE_ACTIVATED: + break; + case NM_DEVICE_STATE_FAILED: + break; + case NM_DEVICE_STATE_DISCONNECTED: + break; + default: + break; + } +} + + +NMDevice * +nm_device_olpc_mesh_new (const char *udi, + const char *iface, + const char *driver, + guint32 ifindex) +{ + GObject *obj; + + g_return_val_if_fail (udi != NULL, NULL); + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (driver != NULL, NULL); + + obj = g_object_new (NM_TYPE_DEVICE_OLPC_MESH, + NM_DEVICE_INTERFACE_UDI, udi, + NM_DEVICE_INTERFACE_IFACE, iface, + NM_DEVICE_INTERFACE_DRIVER, driver, + NM_DEVICE_OLPC_MESH_IFINDEX, ifindex, + NM_DEVICE_INTERFACE_TYPE_DESC, "802.11 OLPC Mesh", + NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_OLPC_MESH, + NULL); + if (obj == NULL) + return NULL; + + g_signal_connect (obj, "state-changed", G_CALLBACK (state_changed_cb), NULL); + + return NM_DEVICE (obj); +} diff --git a/src/nm-device-olpc-mesh.h b/src/nm-device-olpc-mesh.h new file mode 100644 index 0000000000..9ec051f468 --- /dev/null +++ b/src/nm-device-olpc-mesh.h @@ -0,0 +1,85 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* NetworkManager -- Network link manager + * + * Dan Williams + * Sjoerd Simons + * Daniel Drake + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * (C) Copyright 2005 Red Hat, Inc. + * (C) Copyright 2008 Collabora Ltd. + * (C) Copyright 2009 One Laptop per Child + */ + +#ifndef NM_DEVICE_OLPC_MESH_H +#define NM_DEVICE_OLPC_MESH_H + +#include +#include + +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_OLPC_MESH (nm_device_olpc_mesh_get_type ()) +#define NM_DEVICE_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMesh)) +#define NM_DEVICE_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass)) +#define NM_IS_DEVICE_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_OLPC_MESH)) +#define NM_IS_DEVICE_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_OLPC_MESH)) +#define NM_DEVICE_OLPC_MESH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass)) + +#define NM_DEVICE_OLPC_MESH_HW_ADDRESS "hw-address" +#define NM_DEVICE_OLPC_MESH_COMPANION "companion" +#define NM_DEVICE_OLPC_MESH_BITRATE "bitrate" +#define NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL "active-channel" +#define NM_DEVICE_OLPC_MESH_IFINDEX "ifindex" + +#ifndef NM_DEVICE_OLPC_MESH_DEFINED +#define NM_DEVICE_OLPC_MESH_DEFINED +typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; +#endif + +typedef struct _NMDeviceOlpcMeshClass NMDeviceOlpcMeshClass; +typedef struct _NMDeviceOlpcMeshPrivate NMDeviceOlpcMeshPrivate; + +struct _NMDeviceOlpcMesh +{ + NMDevice parent; +}; + +struct _NMDeviceOlpcMeshClass +{ + NMDeviceClass parent; + + /* Signals */ + void (*properties_changed) (NMDeviceOlpcMesh *device, + GHashTable *properties); +}; + + +GType nm_device_olpc_mesh_get_type (void); + +NMDevice *nm_device_olpc_mesh_new (const char *udi, + const char *iface, + const char *driver, + guint32 ifindex); + +guint32 nm_device_olpc_mesh_get_ifindex (NMDeviceOlpcMesh *self); + +G_END_DECLS + +#endif /* NM_DEVICE_OLPC_MESH_H */ diff --git a/src/nm-manager.c b/src/nm-manager.c index 07be3e3071..cdab19fb77 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -35,6 +35,7 @@ #include "nm-device-private.h" #include "nm-device-ethernet.h" #include "nm-device-wifi.h" +#include "nm-device-olpc-mesh.h" #include "NetworkManagerSystem.h" #include "nm-properties-changed-signal.h" #include "nm-setting-bluetooth.h" @@ -1392,6 +1393,8 @@ find_device_by_ifindex (NMManager *self, guint32 ifindex) candidate_idx = nm_device_ethernet_get_ifindex (NM_DEVICE_ETHERNET (device)); else if (NM_IS_DEVICE_WIFI (device)) candidate_idx = nm_device_wifi_get_ifindex (NM_DEVICE_WIFI (device)); + else if (NM_IS_DEVICE_OLPC_MESH (device)) + candidate_idx = nm_device_olpc_mesh_get_ifindex (NM_DEVICE_OLPC_MESH (device)); if (candidate_idx == ifindex) return device; diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c index c9a184d8f6..191ba4f145 100644 --- a/src/nm-udev-manager.c +++ b/src/nm-udev-manager.c @@ -36,6 +36,7 @@ #include "nm-utils.h" #include "NetworkManagerUtils.h" #include "nm-device-wifi.h" +#include "nm-device-olpc-mesh.h" #include "nm-device-ethernet.h" typedef struct { @@ -271,6 +272,13 @@ is_wireless (GUdevDevice *device) return is_wifi; } +static gboolean +is_olpc_mesh (GUdevDevice *device) +{ + const gchar *prop = g_udev_device_get_property (device, "ID_NM_OLPC_MESH"); + return (prop != NULL); +} + static GObject * device_creator (NMUdevManager *manager, GUdevDevice *udev_device, @@ -311,7 +319,9 @@ device_creator (NMUdevManager *manager, return NULL; } - if (is_wireless (udev_device)) + if (is_olpc_mesh (udev_device)) /* must be before is_wireless */ + device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver, ifindex); + else if (is_wireless (udev_device)) device = (GObject *) nm_device_wifi_new (path, ifname, driver, ifindex); else device = (GObject *) nm_device_ethernet_new (path, ifname, driver, ifindex); From 78bb1c01b7e00275c27f20fbbac5ba507102c2fe Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 5 Aug 2009 18:03:09 -0400 Subject: [PATCH 15/19] core: implement connection assumption Mark activation requests that contain connections to be assumed, and use that to short-circuit various parts of the activation process by not touching various device attributes, since they are already set up. Also ensure the device is not deactivated when it initially becomes managed, because that would kill the connection we are about to assume. --- include/NetworkManager.h | 3 ++ introspection/nm-device.xml | 5 +++ src/nm-activation-request.c | 12 +++++ src/nm-activation-request.h | 3 ++ src/nm-device.c | 87 +++++++++++++++++++++++++++---------- src/nm-manager.c | 56 +++++++++++++++++++----- 6 files changed, 132 insertions(+), 34 deletions(-) diff --git a/include/NetworkManager.h b/include/NetworkManager.h index fcef15bc7f..f755a4e4ca 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -357,6 +357,9 @@ typedef enum { /* Carrier/link changed */ NM_DEVICE_STATE_REASON_CARRIER, + /* The device's existing connection was assumed */ + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED, + /* Unused */ NM_DEVICE_STATE_REASON_LAST = 0xFFFF } NMDeviceStateReason; diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml index 952f1cf1ac..c743f831b2 100644 --- a/introspection/nm-device.xml +++ b/introspection/nm-device.xml @@ -370,6 +370,11 @@ The device's carrier/link changed. + + + + The device's existing connection was assumed. + diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index c919c5e710..45851d9938 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -76,6 +76,8 @@ typedef struct { GSList *share_rules; char *ac_path; + + gboolean assumed; } NMActRequestPrivate; enum { @@ -136,6 +138,7 @@ NMActRequest * nm_act_request_new (NMConnection *connection, const char *specific_object, gboolean user_requested, + gboolean assumed, gpointer *device) { GObject *object; @@ -160,6 +163,7 @@ nm_act_request_new (NMConnection *connection, NM_ACT_REQUEST (object)); priv->user_requested = user_requested; + priv->assumed = assumed; return NM_ACT_REQUEST (object); } @@ -643,3 +647,11 @@ nm_act_request_get_device (NMActRequest *req) return G_OBJECT (NM_ACT_REQUEST_GET_PRIVATE (req)->device); } +gboolean +nm_act_request_get_assumed (NMActRequest *req) +{ + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + + return NM_ACT_REQUEST_GET_PRIVATE (req)->assumed; +} + diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index 18760925f2..a3c0d97446 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -59,6 +59,7 @@ GType nm_act_request_get_type (void); NMActRequest *nm_act_request_new (NMConnection *connection, const char *specific_object, gboolean user_requested, + gboolean assumed, gpointer *device); /* An NMDevice */ NMConnection *nm_act_request_get_connection (NMActRequest *req); @@ -85,6 +86,8 @@ void nm_act_request_add_share_rule (NMActRequest *req, GObject * nm_act_request_get_device (NMActRequest *req); +gboolean nm_act_request_get_assumed (NMActRequest *req); + gboolean nm_act_request_get_secrets (NMActRequest *req, const char *setting_name, gboolean request_new, diff --git a/src/nm-device.c b/src/nm-device.c index 53e18f21ce..18a85160c7 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -140,8 +140,14 @@ static void nm_device_take_down (NMDevice *dev, gboolean wait, NMDeviceStateReas static gboolean nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware); 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 gboolean nm_device_set_ip4_config (NMDevice *dev, + NMIP4Config *config, + gboolean assumed, + NMDeviceStateReason *reason); +static gboolean nm_device_set_ip6_config (NMDevice *dev, + NMIP6Config *config, + gboolean assumed, + NMDeviceStateReason *reason); static void device_interface_init (NMDeviceInterface *device_interface_class) @@ -774,7 +780,7 @@ handle_autoip_change (NMDevice *self, NMDeviceStateReason *reason) g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config); - if (!nm_device_set_ip4_config (self, config, reason)) { + if (!nm_device_set_ip4_config (self, config, FALSE, reason)) { nm_warning ("(%s): failed to update IP4 config in response to autoip event.", nm_device_get_iface (self)); return FALSE; @@ -1724,19 +1730,20 @@ static gboolean nm_device_activate_stage5_ip_config_commit (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMIP4Config *ip4_config = NULL; NMIP6Config *ip6_config = NULL; const char *iface, *method = NULL; NMConnection *connection; NMSettingIP4Config *s_ip4; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + gboolean assumed; 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, 0); @@ -1745,12 +1752,14 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data) nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) started...", iface); - if (!nm_device_set_ip4_config (self, ip4_config, &reason)) { + assumed = nm_act_request_get_assumed (priv->act_request); + + if (!nm_device_set_ip4_config (self, ip4_config, assumed, &reason)) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); goto out; } - if (!nm_device_set_ip6_config (self, ip6_config, &reason)) { + if (ip6_config && !nm_device_set_ip6_config (self, ip6_config, assumed, &reason)) { nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) IPv6 failed", iface); } @@ -1776,7 +1785,8 @@ out: /* Balance IP config creation; device takes ownership in set_ip*_config() */ g_object_unref (ip4_config); - g_object_unref (ip6_config); + if (ip6_config) + g_object_unref (ip6_config); return FALSE; } @@ -1920,8 +1930,8 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason) nm_device_deactivate_quickly (self); /* Clean up nameservers and addresses */ - nm_device_set_ip4_config (self, NULL, &ignored); - nm_device_set_ip6_config (self, NULL, &ignored); + nm_device_set_ip4_config (self, NULL, FALSE, &ignored); + nm_device_set_ip6_config (self, NULL, FALSE, &ignored); /* Take out any entries in the routing table and any IP address the device had. */ nm_system_device_flush_routes (self); @@ -2022,13 +2032,22 @@ nm_device_activate (NMDeviceInterface *device, G_CALLBACK (connection_secrets_failed_cb), device); - /* HACK: update the state a bit early to avoid a race between the - * scheduled stage1 handler and nm_policy_device_change_check() thinking - * that the activation request isn't deferred because the deferred bit - * gets cleared a bit too early, when the connection becomes valid. - */ - nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); - nm_device_activate_schedule_stage1_device_prepare (self); + if (!nm_act_request_get_assumed (req)) { + /* HACK: update the state a bit early to avoid a race between the + * scheduled stage1 handler and nm_policy_device_change_check() thinking + * that the activation request isn't deferred because the deferred bit + * gets cleared a bit too early, when the connection becomes valid. + */ + nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); + nm_device_activate_schedule_stage1_device_prepare (self); + } else { + /* If it's an assumed connection, let the device subclass short-circuit + * the normal connection process and just copy its IP configs from the + * interface. + */ + nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); + nm_device_activate_schedule_stage3_ip_config_start (self); + } return TRUE; } @@ -2093,6 +2112,7 @@ handle_dhcp_lease_change (NMDevice *device) NMActRequest *req; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; const char *ip_iface; + gboolean assumed; if (!nm_device_get_use_dhcp (device)) { nm_warning ("got DHCP rebind for device that wasn't using DHCP."); @@ -2118,7 +2138,8 @@ handle_dhcp_lease_change (NMDevice *device) g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config); - if (nm_device_set_ip4_config (device, config, &reason)) { + assumed = nm_act_request_get_assumed (req); + if (nm_device_set_ip4_config (device, config, assumed, &reason)) { nm_dhcp4_config_reset (priv->dhcp4_config); nm_dhcp_manager_foreach_dhcp4_option (priv->dhcp_manager, ip_iface, @@ -2276,6 +2297,7 @@ nm_device_get_ip4_config (NMDevice *self) static gboolean nm_device_set_ip4_config (NMDevice *self, NMIP4Config *new_config, + gboolean assumed, NMDeviceStateReason *reason) { NMDevicePrivate *priv; @@ -2311,8 +2333,13 @@ nm_device_set_ip4_config (NMDevice *self, if (new_config) { priv->ip4_config = g_object_ref (new_config); - success = nm_system_apply_ip4_config (ip_iface, new_config, nm_device_get_priority (self), diff); - if (success) { + /* Don't touch the device's actual IP config if the connection is + * assumed when NM starts. + */ + if (!assumed) + success = nm_system_apply_ip4_config (ip_iface, new_config, nm_device_get_priority (self), diff); + + if (success || assumed) { /* Export over D-Bus */ if (!nm_ip4_config_get_dbus_path (new_config)) nm_ip4_config_export (new_config); @@ -2373,6 +2400,7 @@ nm_device_update_ip4_address (NMDevice *self) static gboolean nm_device_set_ip6_config (NMDevice *self, NMIP6Config *new_config, + gboolean assumed, NMDeviceStateReason *reason) { NMDevicePrivate *priv; @@ -2408,8 +2436,13 @@ nm_device_set_ip6_config (NMDevice *self, 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) { + /* Don't touch the device's actual IP config if the connection is + * assumed when NM starts. + */ + if (!assumed) + success = nm_system_apply_ip6_config (ip_iface, new_config, nm_device_get_priority (self), diff); + + if (success || assumed) { /* Export over D-Bus */ if (!nm_ip6_config_get_dbus_path (new_config)) nm_ip6_config_export (new_config); @@ -2587,7 +2620,7 @@ dispose (GObject *object) NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; nm_device_take_down (self, FALSE, NM_DEVICE_STATE_REASON_REMOVED); - nm_device_set_ip4_config (self, NULL, &ignored); + nm_device_set_ip4_config (self, NULL, FALSE, &ignored); } clear_act_request (self); @@ -2880,8 +2913,14 @@ nm_device_state_changed (NMDevice *device, if (!nm_device_bring_up (device, TRUE, &no_firmware) && no_firmware) nm_warning ("%s: firmware may be missing.", nm_device_get_iface (device)); } - /* Fall through, so when the device needs to be deactivated due to - * eg carrier changes we actually deactivate it */ + /* Ensure the device gets deactivated in response to stuff like + * carrier changes or rfkill. But don't deactivate devices that are + * about to assume a connection since that defeats the purpose of + * assuming the device's existing connection. + */ + if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) + nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device), reason); + break; case NM_DEVICE_STATE_DISCONNECTED: if (old_state != NM_DEVICE_STATE_UNAVAILABLE) nm_device_interface_deactivate (NM_DEVICE_INTERFACE (device), reason); diff --git a/src/nm-manager.c b/src/nm-manager.c index 5ad0ff58cf..dc9da810e4 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -113,6 +113,14 @@ static void add_device (NMManager *self, NMDevice *device); static void hostname_provider_init (NMHostnameProvider *provider_class); +static const char *internal_activate_device (NMManager *manager, + NMDevice *device, + NMConnection *connection, + const char *specific_object, + gboolean user_requested, + gboolean assumed, + GError **error); + #define SSD_POKE_INTERVAL 120 #define ORIGDEV_TAG "originating-device" @@ -1165,7 +1173,6 @@ add_device (NMManager *self, NMDevice *device) char *path; static guint32 devcount = 0; const GSList *unmanaged_specs; - GSList *connections = NULL; NMConnection *existing; GHashTableIter iter; gpointer value; @@ -1208,20 +1215,47 @@ add_device (NMManager *self, NMDevice *device) /* Check if we should assume the device's active connection by matching its * config with an existing system connection. */ - g_hash_table_iter_init (&iter, priv->system_connections); - while (g_hash_table_iter_next (&iter, NULL, &value)) - connections = g_slist_append (connections, value); - existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device), - (const GSList *) connections); - g_slist_free (connections); + if (nm_device_interface_can_assume_connection (NM_DEVICE_INTERFACE (device))) { + GSList *connections = NULL; + + g_hash_table_iter_init (&iter, priv->system_connections); + while (g_hash_table_iter_next (&iter, NULL, &value)) + connections = g_slist_append (connections, value); + existing = nm_device_interface_connection_match_config (NM_DEVICE_INTERFACE (device), + (const GSList *) connections); + g_slist_free (connections); + } /* Start the device if it's supposed to be managed */ unmanaged_specs = nm_sysconfig_settings_get_unmanaged_specs (priv->sys_settings); - if (!priv->sleeping && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) - nm_device_set_managed (device, TRUE, NM_DEVICE_STATE_REASON_NOW_MANAGED); + if ( !priv->sleeping + && !nm_device_interface_spec_match_list (NM_DEVICE_INTERFACE (device), unmanaged_specs)) { + nm_device_set_managed (device, + TRUE, + existing ? NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED : + NM_DEVICE_STATE_REASON_NOW_MANAGED); + } nm_sysconfig_settings_device_added (priv->sys_settings, device); g_signal_emit (self, signals[DEVICE_ADDED], 0, device); + + /* If the device has a connection it can assume, do that now */ + if (existing) { + const char *ac_path; + GError *error = NULL; + + ac_path = internal_activate_device (self, device, existing, NULL, FALSE, TRUE, &error); + if (ac_path) + g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); + else { + nm_warning ("Assumed connection (%d) %s failed to activate: (%d) %s", + nm_connection_get_scope (existing), + nm_connection_get_path (existing), + error ? error->code : -1, + error && error->message ? error->message : "(unknown)"); + g_error_free (error); + } + } } static gboolean @@ -1826,6 +1860,7 @@ internal_activate_device (NMManager *manager, NMConnection *connection, const char *specific_object, gboolean user_requested, + gboolean assumed, GError **error) { NMActRequest *req; @@ -1849,7 +1884,7 @@ internal_activate_device (NMManager *manager, NM_DEVICE_STATE_REASON_NONE); } - req = nm_act_request_new (connection, specific_object, user_requested, (gpointer) device); + req = nm_act_request_new (connection, specific_object, user_requested, assumed, (gpointer) device); g_signal_connect (req, "manager-get-secrets", G_CALLBACK (provider_get_secrets), manager); g_signal_connect (req, "manager-cancel-secrets", G_CALLBACK (provider_cancel_secrets), manager); success = nm_device_interface_activate (dev_iface, req, error); @@ -1961,6 +1996,7 @@ nm_manager_activate_connection (NMManager *manager, connection, specific_object, user_requested, + FALSE, error); } From 869e57524cc283150a6d885e75e25f50b3b02fb6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 6 Aug 2009 15:15:46 -0400 Subject: [PATCH 16/19] core: fix uninitialized variable usage --- src/nm-manager.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index dc9da810e4..7e4155139d 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1173,7 +1173,7 @@ add_device (NMManager *self, NMDevice *device) char *path; static guint32 devcount = 0; const GSList *unmanaged_specs; - NMConnection *existing; + NMConnection *existing = NULL; GHashTableIter iter; gpointer value; From 1d5a68db74a1e86155be9879a62fb1cbb86291ea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 7 Aug 2009 12:13:54 -0500 Subject: [PATCH 17/19] ifcfg-rh: read iBFT config and convert to NM IPv4 config --- system-settings/plugins/ifcfg-rh/Makefile.am | 3 +- .../plugins/ifcfg-rh/nm-ifcfg-connection.c | 2 +- system-settings/plugins/ifcfg-rh/reader.c | 353 +++++++++++++-- system-settings/plugins/ifcfg-rh/reader.h | 5 +- .../plugins/ifcfg-rh/tests/Makefile.am | 9 + .../ifcfg-rh/tests/iscsiadm-test-bad-dns1 | 21 + .../ifcfg-rh/tests/iscsiadm-test-bad-dns2 | 21 + .../ifcfg-rh/tests/iscsiadm-test-bad-entry | 35 ++ .../ifcfg-rh/tests/iscsiadm-test-bad-gateway | 21 + .../ifcfg-rh/tests/iscsiadm-test-bad-ipaddr | 21 + .../ifcfg-rh/tests/iscsiadm-test-bad-record | 18 + .../plugins/ifcfg-rh/tests/iscsiadm-test-dhcp | 33 ++ .../ifcfg-rh/tests/iscsiadm-test-static | 35 ++ .../tests/network-scripts/Makefile.am | 4 +- .../network-scripts/ifcfg-test-ibft-dhcp | 4 + .../network-scripts/ifcfg-test-ibft-static | 4 + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 415 +++++++++++++++++- 17 files changed, 958 insertions(+), 46 deletions(-) create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns1 create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns2 create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-entry create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-gateway create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-ipaddr create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-record create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-dhcp create mode 100755 system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-static create mode 100644 system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-dhcp create mode 100644 system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-static diff --git a/system-settings/plugins/ifcfg-rh/Makefile.am b/system-settings/plugins/ifcfg-rh/Makefile.am index 1635e39484..e2b0a83c99 100644 --- a/system-settings/plugins/ifcfg-rh/Makefile.am +++ b/system-settings/plugins/ifcfg-rh/Makefile.am @@ -32,7 +32,8 @@ libifcfg_rh_io_la_CPPFLAGS = \ $(DBUS_CFLAGS) \ $(NSS_CFLAGS) \ -DG_DISABLE_DEPRECATED \ - -DSYSCONFDIR=\"$(sysconfdir)\" + -DSYSCONFDIR=\"$(sysconfdir)\" \ + -DSBINDIR=\"$(sbindir)\" libifcfg_rh_io_la_LIBADD = $(GLIB_LIBS) $(NSS_LIBS) diff --git a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c index 4767b5183c..5561df37ff 100644 --- a/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c +++ b/system-settings/plugins/ifcfg-rh/nm-ifcfg-connection.c @@ -104,7 +104,7 @@ nm_ifcfg_connection_new (const char *filename, g_return_val_if_fail (filename != NULL, NULL); - wrapped = connection_from_file (filename, NULL, NULL, &unmanaged, &keyfile, error, ignore_error); + wrapped = connection_from_file (filename, NULL, NULL, NULL, &unmanaged, &keyfile, error, ignore_error); if (!wrapped) return NULL; diff --git a/system-settings/plugins/ifcfg-rh/reader.c b/system-settings/plugins/ifcfg-rh/reader.c index 61f3d68791..8d6b311d4c 100644 --- a/system-settings/plugins/ifcfg-rh/reader.c +++ b/system-settings/plugins/ifcfg-rh/reader.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -183,6 +184,284 @@ make_connection_setting (const char *file, return NM_SETTING (s_con); } +static gboolean +read_mac_address (shvarFile *ifcfg, GByteArray **array, GError **error) +{ + char *value = NULL; + struct ether_addr *mac; + + g_return_val_if_fail (ifcfg != NULL, FALSE); + g_return_val_if_fail (array != NULL, FALSE); + g_return_val_if_fail (*array == NULL, FALSE); + g_return_val_if_fail (error != NULL, FALSE); + g_return_val_if_fail (*error == NULL, FALSE); + + value = svGetValue (ifcfg, "HWADDR", FALSE); + if (!value || !strlen (value)) { + g_free (value); + return TRUE; + } + + mac = ether_aton (value); + if (!mac) { + g_free (value); + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "The MAC address '%s' was invalid.", value); + return FALSE; + } + + g_free (value); + *array = g_byte_array_sized_new (ETH_ALEN); + g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN); + return TRUE; +} + +static void +iscsiadm_child_setup (gpointer user_data G_GNUC_UNUSED) +{ + /* We are in the child process here; set a different process group to + * ensure signal isolation between child and parent. + */ + pid_t pid = getpid (); + setpgid (pid, pid); +} + +static char * +match_iscsiadm_tag (const char *line, const char *tag, gboolean *skip) +{ + char *p; + + if (g_ascii_strncasecmp (line, tag, strlen (tag))) + return NULL; + + p = strchr (line, '='); + if (!p) { + g_warning ("%s: malformed iscsiadm record: no = in '%s'.", + __func__, line); + *skip = TRUE; + return NULL; + } + + p++; /* advance past = */ + return g_strstrip (p); +} + +#define ISCSI_HWADDR_TAG "iface.hwaddress" +#define ISCSI_BOOTPROTO_TAG "iface.bootproto" +#define ISCSI_IPADDR_TAG "iface.ipaddress" +#define ISCSI_SUBNET_TAG "iface.subnet_mask" +#define ISCSI_GATEWAY_TAG "iface.gateway" +#define ISCSI_DNS1_TAG "iface.primary_dns" +#define ISCSI_DNS2_TAG "iface.secondary_dns" + +static gboolean +fill_ip4_setting_from_ibft (shvarFile *ifcfg, + NMSettingIP4Config *s_ip4, + const char *iscsiadm_path, + GError **error) +{ + const char *argv[4] = { iscsiadm_path, "-m", "fw", NULL }; + const char *envp[1] = { NULL }; + gboolean success = FALSE, in_record = FALSE, hwaddr_matched = FALSE, skip = FALSE; + char *out = NULL, *err = NULL; + gint status = 0; + GByteArray *ifcfg_mac = NULL; + char **lines = NULL, **iter; + const char *method = NULL; + struct in_addr ipaddr; + struct in_addr gateway; + struct in_addr dns1; + struct in_addr dns2; + guint32 prefix = 0; + + g_return_val_if_fail (s_ip4 != NULL, FALSE); + g_return_val_if_fail (iscsiadm_path != NULL, FALSE); + + if (!g_spawn_sync ("/", (char **) argv, (char **) envp, 0, + iscsiadm_child_setup, NULL, &out, &err, &status, error)) + return FALSE; + + if (!WIFEXITED (status)) { + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "%s exited abnormally.", iscsiadm_path); + goto done; + } + + if (WEXITSTATUS (status) != 0) { + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "%s exited with error %d. Message: '%s'", + iscsiadm_path, WEXITSTATUS (status), err ? err : "(none)"); + goto done; + } + + if (!read_mac_address (ifcfg, &ifcfg_mac, error)) + goto done; + /* Ensure we got a MAC */ + if (!ifcfg_mac) { + g_set_error (error, ifcfg_plugin_error_quark (), 0, + "Missing device MAC address (no HWADDR tag present)."); + goto done; + } + + memset (&ipaddr, 0, sizeof (ipaddr)); + memset (&gateway, 0, sizeof (gateway)); + memset (&dns1, 0, sizeof (dns1)); + memset (&dns2, 0, sizeof (dns2)); + + /* Success, lets parse the output */ + lines = g_strsplit_set (out, "\n\r", -1); + for (iter = lines; iter && *iter; iter++) { + char *p; + + if (!g_ascii_strcasecmp (*iter, "# BEGIN RECORD")) { + if (in_record) { + g_warning ("%s: malformed iscsiadm record: already parsing record.", __func__); + skip = TRUE; + } + } else if (!g_ascii_strcasecmp (*iter, "# END RECORD")) { + if (!skip && hwaddr_matched) { + /* Record is good; fill IP4 config with its info */ + if (!method) { + g_warning ("%s: malformed iscsiadm record: missing BOOTPROTO.", __func__); + return FALSE; + } + + g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, method, NULL); + + if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + NMIP4Address *addr; + + if (!ipaddr.s_addr || !prefix) { + g_warning ("%s: malformed iscsiadm record: BOOTPROTO=static " + "but missing IP address or prefix.", __func__); + return FALSE; + } + + addr = nm_ip4_address_new (); + nm_ip4_address_set_address (addr, ipaddr.s_addr); + nm_ip4_address_set_prefix (addr, prefix); + nm_ip4_address_set_gateway (addr, gateway.s_addr); + nm_setting_ip4_config_add_address (s_ip4, addr); + nm_ip4_address_unref (addr); + + if (dns1.s_addr) + nm_setting_ip4_config_add_dns (s_ip4, dns1.s_addr); + if (dns2.s_addr) + nm_setting_ip4_config_add_dns (s_ip4, dns2.s_addr); + + // FIXME: DNS search domains? + } + return TRUE; + } + skip = FALSE; + hwaddr_matched = FALSE; + memset (&ipaddr, 0, sizeof (ipaddr)); + memset (&gateway, 0, sizeof (gateway)); + memset (&dns1, 0, sizeof (dns1)); + memset (&dns2, 0, sizeof (dns2)); + prefix = 0; + method = NULL; + } + + if (skip) + continue; + + /* HWADDR */ + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_HWADDR_TAG, &skip))) { + struct ether_addr *ibft_mac; + + ibft_mac = ether_aton (p); + if (!ibft_mac) { + g_warning ("%s: malformed iscsiadm record: invalid hwaddress.", __func__); + skip = TRUE; + continue; + } + + if (memcmp (ifcfg_mac->data, (guint8 *) ibft_mac->ether_addr_octet, ETH_ALEN)) { + /* This record isn't for the current device, ignore it */ + skip = TRUE; + continue; + } + + /* Success, this record is for this device */ + hwaddr_matched = TRUE; + } + + /* BOOTPROTO */ + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_BOOTPROTO_TAG, &skip))) { + if (!g_ascii_strcasecmp (p, "dhcp")) + method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + else if (!g_ascii_strcasecmp (p, "static")) + method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; + else { + g_warning ("%s: malformed iscsiadm record: unknown BOOTPROTO '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_IPADDR_TAG, &skip))) { + if (inet_pton (AF_INET, p, &ipaddr) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid IP address '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_SUBNET_TAG, &skip))) { + struct in_addr mask; + + if (inet_pton (AF_INET, p, &mask) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid subnet mask '%s'.", + __func__, p); + skip = TRUE; + continue; + } + + prefix = nm_utils_ip4_netmask_to_prefix (mask.s_addr); + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_GATEWAY_TAG, &skip))) { + if (inet_pton (AF_INET, p, &gateway) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid IP gateway '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS1_TAG, &skip))) { + if (inet_pton (AF_INET, p, &dns1) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid DNS1 address '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + + if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS2_TAG, &skip))) { + if (inet_pton (AF_INET, p, &dns2) < 1) { + g_warning ("%s: malformed iscsiadm record: invalid DNS2 address '%s'.", + __func__, p); + skip = TRUE; + continue; + } + } + } + + success = TRUE; + +done: + if (ifcfg_mac) + g_byte_array_free (ifcfg_mac, TRUE); + g_strfreev (lines); + g_free (out); + g_free (err); + return success; +} + static gboolean read_ip4_address (shvarFile *ifcfg, const char *tag, @@ -325,7 +604,10 @@ error: } static NMSetting * -make_ip4_setting (shvarFile *ifcfg, const char *network_file, GError **error) +make_ip4_setting (shvarFile *ifcfg, + const char *network_file, + const char *iscsiadm_path, + GError **error) { NMSettingIP4Config *s_ip4 = NULL; char *value = NULL; @@ -364,7 +646,15 @@ make_ip4_setting (shvarFile *ifcfg, const char *network_file, GError **error) if (value) { if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; - else if (!g_ascii_strcasecmp (value, "autoip")) { + else if (!g_ascii_strcasecmp (value, "ibft")) { + /* iSCSI Boot Firmware Table: need to read values from the iSCSI + * firmware for this device and create the IP4 setting using those. + */ + if (fill_ip4_setting_from_ibft (ifcfg, s_ip4, iscsiadm_path, error)) + return NM_SETTING (s_ip4); + g_object_unref (s_ip4); + return NULL; + } else if (!g_ascii_strcasecmp (value, "autoip")) { g_free (value); g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, @@ -498,38 +788,6 @@ error: return NULL; } -static gboolean -read_mac_address (shvarFile *ifcfg, GByteArray **array, GError **error) -{ - char *value = NULL; - struct ether_addr *mac; - - g_return_val_if_fail (ifcfg != NULL, FALSE); - g_return_val_if_fail (array != NULL, FALSE); - g_return_val_if_fail (*array == NULL, FALSE); - g_return_val_if_fail (error != NULL, FALSE); - g_return_val_if_fail (*error == NULL, FALSE); - - value = svGetValue (ifcfg, "HWADDR", FALSE); - if (!value || !strlen (value)) { - g_free (value); - return TRUE; - } - - mac = ether_aton (value); - if (!mac) { - g_free (value); - g_set_error (error, ifcfg_plugin_error_quark (), 0, - "The MAC address '%s' was invalid.", value); - return FALSE; - } - - g_free (value); - *array = g_byte_array_sized_new (ETH_ALEN); - g_byte_array_append (*array, (guint8 *) mac->ether_addr_octet, ETH_ALEN); - return TRUE; -} - static gboolean add_one_wep_key (shvarFile *ifcfg, const char *shvar_key, @@ -2032,8 +2290,9 @@ is_wireless_device (const char *iface) NMConnection * connection_from_file (const char *filename, - const char *network_file, - const char *test_type, /* for unit tests only */ + const char *network_file, /* for unit tests only */ + const char *test_type, /* for unit tests only */ + const char *iscsiadm_path, /* for unit tests only */ char **unmanaged, char **keyfile, GError **error, @@ -2041,7 +2300,7 @@ connection_from_file (const char *filename, { NMConnection *connection = NULL; shvarFile *parsed; - char *type, *nmc = NULL; + char *type, *nmc = NULL, *bootproto; NMSetting *s_ip4; char *ifcfg_name = NULL; gboolean nm_controlled = TRUE; @@ -2056,6 +2315,9 @@ connection_from_file (const char *filename, if (!network_file) network_file = SYSCONFDIR "/sysconfig/network"; + if (!iscsiadm_path) + iscsiadm_path = SBINDIR "/iscsiadm"; + ifcfg_name = utils_get_ifcfg_name (filename); if (!ifcfg_name) { g_set_error (error, ifcfg_plugin_error_quark (), 0, @@ -2142,7 +2404,7 @@ connection_from_file (const char *filename, if (!connection || *unmanaged) goto done; - s_ip4 = make_ip4_setting (parsed, network_file, error); + s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, error); if (*error) { g_object_unref (connection); connection = NULL; @@ -2151,6 +2413,21 @@ connection_from_file (const char *filename, nm_connection_add_setting (connection, s_ip4); } + /* iSCSI / ibft connections are read-only since their settings are + * stored in NVRAM and can only be changed in BIOS. + */ + bootproto = svGetValue (parsed, "BOOTPROTO", FALSE); + if ( bootproto + && connection + && !g_ascii_strcasecmp (bootproto, "ibft")) { + NMSettingConnection *s_con; + + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + + g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_READ_ONLY, TRUE, NULL); + } + if (!nm_connection_verify (connection, error)) { g_object_unref (connection); connection = NULL; diff --git a/system-settings/plugins/ifcfg-rh/reader.h b/system-settings/plugins/ifcfg-rh/reader.h index 458223fce8..f453045571 100644 --- a/system-settings/plugins/ifcfg-rh/reader.h +++ b/system-settings/plugins/ifcfg-rh/reader.h @@ -27,8 +27,9 @@ #include "shvar.h" NMConnection *connection_from_file (const char *filename, - const char *network_file, - const char *test_type, + const char *network_file, /* for unit tests only */ + const char *test_type, /* for unit tests only */ + const char *iscsiadm_path, /* for unit tests only */ char **unmanaged, char **keyfile, GError **error, diff --git a/system-settings/plugins/ifcfg-rh/tests/Makefile.am b/system-settings/plugins/ifcfg-rh/tests/Makefile.am index d898cc5ab2..195ab1fc8d 100644 --- a/system-settings/plugins/ifcfg-rh/tests/Makefile.am +++ b/system-settings/plugins/ifcfg-rh/tests/Makefile.am @@ -30,3 +30,12 @@ check-local: test-ifcfg-rh endif +EXTRA_DIST = \ + iscsiadm-test-dhcp \ + iscsiadm-test-static \ + iscsiadm-test-malformed \ + iscsiadm-test-bad-ipaddr \ + iscsiadm-test-bad-gateway \ + iscsiadm-test-bad-dns1 \ + iscsiadm-test-bad-dns2 + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns1 b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns1 new file mode 100755 index 0000000000..4a6a93822e --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns1 @@ -0,0 +1,21 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10000.500.250.1 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns2 b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns2 new file mode 100755 index 0000000000..9bd5839bd3 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-dns2 @@ -0,0 +1,21 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = blah.foo.bar.baz +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-entry b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-entry new file mode 100755 index 0000000000..eba0ec6730 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-entry @@ -0,0 +1,35 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f1 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth1 +node.name = iqn.1.2008-11.com.blahblah:iscsi1 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-gateway b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-gateway new file mode 100755 index 0000000000..b3dc74478b --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-gateway @@ -0,0 +1,21 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = aa.bb.cc.dd +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-ipaddr b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-ipaddr new file mode 100755 index 0000000000..92f44777b4 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-ipaddr @@ -0,0 +1,21 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = bb.cc.dd.ee +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-record b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-record new file mode 100755 index 0000000000..a2d215fe24 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-bad-record @@ -0,0 +1,18 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-dhcp b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-dhcp new file mode 100755 index 0000000000..6de0637cb1 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-dhcp @@ -0,0 +1,33 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f1 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth1 +node.name = iqn.1.2008-11.com.blahblah:iscsi1 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-static b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-static new file mode 100755 index 0000000000..99a6e7c173 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/iscsiadm-test-static @@ -0,0 +1,35 @@ +#!/bin/bash + +cat << EOF +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f0 +iface.bootproto = STATIC +iface.ipaddress = 192.168.32.72 +iface.subnet_mask = 255.255.252.0 +iface.gateway = 192.168.35.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth0 +node.name = iqn.0.2008-11.com.blahblah:iscsi0 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +# BEGIN RECORD +iface.initiatorname = iqn.pjones6 +iface.hwaddress = 00:33:21:98:b9:f1 +iface.bootproto = DHCP +iface.gateway = 10.16.52.254 +iface.primary_dns = 10.16.255.2 +iface.secondary_dns = 10.16.255.3 +iface.vlan = 0 +iface.net_ifacename = eth1 +node.name = iqn.1.2008-11.com.blahblah:iscsi1 +node.conn[0].address = 10.16.52.16 +node.conn[0].port = 3260 +node.boot_lun = 00000000 +# END RECORD +EOF + diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am index 01532b7c5b..206b206e15 100644 --- a/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am @@ -35,7 +35,9 @@ EXTRA_DIST = \ ifcfg-test-wifi-wpa-eap-ttls-tls \ keys-test-wifi-wpa-eap-ttls-tls \ test_ca_cert.pem \ - test1_key_and_cert.pem + test1_key_and_cert.pem \ + ifcfg-test-ibft-dhcp \ + ifcfg-test-ibft-static check-local: @for f in $(EXTRA_DIST); do \ diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-dhcp b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-dhcp new file mode 100644 index 0000000000..abfcd6e4ce --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-dhcp @@ -0,0 +1,4 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +DEVICE=eth0 +HWADDR=00:33:21:98:b9:f1 +BOOTPROTO=ibft diff --git a/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-static b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-static new file mode 100644 index 0000000000..99b02e42b1 --- /dev/null +++ b/system-settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ibft-static @@ -0,0 +1,4 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +DEVICE=eth0 +HWADDR=00:33:21:98:b9:f0 +BOOTPROTO=ibft diff --git a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 213aeab148..2afb147b9b 100644 --- a/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -176,6 +176,7 @@ test_read_minimal (void) connection = connection_from_file (TEST_IFCFG_MINIMAL, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -299,6 +300,7 @@ test_read_unmanaged (void) connection = connection_from_file (TEST_IFCFG_UNMANAGED, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -417,6 +419,7 @@ test_read_wired_static (void) connection = connection_from_file (TEST_IFCFG_WIRED_STATIC, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -557,7 +560,7 @@ test_read_wired_static (void) NM_SETTING_IP4_CONFIG_ADDRESSES); ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 24, - "wired-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1 gateway", + "wired-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1 prefix", TEST_IFCFG_WIRED_STATIC, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES); @@ -612,6 +615,7 @@ test_read_wired_dhcp (void) connection = connection_from_file (TEST_IFCFG_WIRED_DHCP, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -777,6 +781,7 @@ test_read_wired_global_gateway (void) connection = connection_from_file (TEST_IFCFG_WIRED_GLOBAL_GATEWAY, TEST_NETWORK_WIRED_GLOBAL_GATEWAY, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -844,7 +849,7 @@ test_read_wired_global_gateway (void) NM_SETTING_IP4_CONFIG_ADDRESSES); ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 24, - "wired-global-gateway-verify-ip4", "failed to verify %s: unexpected IP4 address #1 gateway", + "wired-global-gateway-verify-ip4", "failed to verify %s: unexpected IP4 address #1 prefix", TEST_IFCFG_WIRED_GLOBAL_GATEWAY, NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_SETTING_IP4_CONFIG_ADDRESSES); @@ -894,6 +899,7 @@ test_read_wired_never_default (void) connection = connection_from_file (TEST_IFCFG_WIRED_NEVER_DEFAULT, TEST_NETWORK_WIRED_NEVER_DEFAULT, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -983,6 +989,7 @@ test_read_onboot_no (void) connection = connection_from_file (TEST_IFCFG_ONBOOT_NO, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -1039,6 +1046,7 @@ test_read_wired_8021x_peap_mschapv2 (void) connection = connection_from_file (TEST_IFCFG_WIRED_8021x_PEAP_MSCHAPV2, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -1226,6 +1234,7 @@ test_read_wifi_open (void) connection = connection_from_file (TEST_IFCFG_WIFI_OPEN, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -1394,6 +1403,7 @@ test_read_wifi_open_ssid_hex (void) connection = connection_from_file (TEST_IFCFG_WIFI_OPEN_SSID_HEX, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -1463,7 +1473,14 @@ test_read_wifi_open_ssid_bad (const char *file, const char *test) gboolean ignore_error = FALSE; GError *error = NULL; - connection = connection_from_file (file, NULL, TYPE_WIRELESS, &unmanaged, &keyfile, &error, &ignore_error); + connection = connection_from_file (file, + NULL, + TYPE_WIRELESS, + NULL, + &unmanaged, + &keyfile, + &error, + &ignore_error); ASSERT (connection == NULL, test, "unexpected success reading %s", file); g_clear_error (&error); } @@ -1488,6 +1505,7 @@ test_read_wifi_open_ssid_quoted (void) connection = connection_from_file (TEST_IFCFG_WIFI_OPEN_SSID_QUOTED, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -1575,6 +1593,7 @@ test_read_wifi_wep (void) connection = connection_from_file (TEST_IFCFG_WIFI_WEP, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -1835,6 +1854,7 @@ test_read_wifi_wep_adhoc (void) connection = connection_from_file (TEST_IFCFG_WIFI_WEP_ADHOC, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2088,6 +2108,7 @@ test_read_wifi_leap (void) connection = connection_from_file (TEST_IFCFG_WIFI_LEAP, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2235,6 +2256,7 @@ test_read_wifi_wpa_psk (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2533,6 +2555,7 @@ test_read_wifi_wpa_psk_adhoc (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_ADHOC, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2715,6 +2738,7 @@ test_read_wifi_wpa_psk_hex (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_PSK_HEX, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -2861,6 +2885,7 @@ test_read_wifi_wpa_eap_tls (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_EAP_TLS, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -2995,6 +3020,7 @@ test_read_wifi_wpa_eap_ttls_tls (void) connection = connection_from_file (TEST_IFCFG_WIFI_WPA_EAP_TTLS_TLS, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -3152,6 +3178,7 @@ test_read_wifi_wep_eap_ttls_chap (void) connection = connection_from_file (TEST_IFCFG_WIFI_WEP_EAP_TTLS_CHAP, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -3402,6 +3429,7 @@ test_write_wired_static (void) reread = connection_from_file (testfile, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -3500,6 +3528,7 @@ test_write_wired_dhcp (void) reread = connection_from_file (testfile, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -3618,6 +3647,7 @@ test_write_wired_dhcp_8021x_peap_mschapv2 (void) reread = connection_from_file (testfile, NULL, TYPE_ETHERNET, + NULL, &unmanaged, &keyfile, &error, @@ -3742,6 +3772,7 @@ test_write_wifi_open (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -3846,6 +3877,7 @@ test_write_wifi_open_hex_ssid (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -3970,6 +4002,7 @@ test_write_wifi_wep (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4114,6 +4147,7 @@ test_write_wifi_wep_adhoc (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4263,6 +4297,7 @@ test_write_wifi_wpa_psk (const char *name, reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4407,6 +4442,7 @@ test_write_wifi_wpa_psk_adhoc (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4566,6 +4602,7 @@ test_write_wifi_wpa_eap_tls (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4742,6 +4779,7 @@ test_write_wifi_wpa_eap_ttls_tls (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4893,6 +4931,7 @@ test_write_wifi_wpa_eap_ttls_mschapv2 (void) reread = connection_from_file (testfile, NULL, TYPE_WIRELESS, + NULL, &unmanaged, &keyfile, &error, @@ -4917,6 +4956,366 @@ test_write_wifi_wpa_eap_ttls_mschapv2 (void) g_object_unref (reread); } +#define TEST_IFCFG_IBFT_DHCP TEST_IFCFG_DIR"/network-scripts/ifcfg-test-ibft-dhcp" + +static void +test_read_ibft_dhcp (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIP4Config *s_ip4; + char *unmanaged = NULL; + char *keyfile = NULL; + gboolean ignore_error = FALSE; + GError *error = NULL; + const char *tmp; + const GByteArray *array; + char expected_mac_address[ETH_ALEN] = { 0x00, 0x33, 0x21, 0x98, 0xb9, 0xf1 }; + const char *expected_id = "System test-ibft-dhcp"; + guint64 expected_timestamp = 0; + + connection = connection_from_file (TEST_IFCFG_IBFT_DHCP, + NULL, + TYPE_ETHERNET, + TEST_IFCFG_DIR "/iscsiadm-test-dhcp", + &unmanaged, + &keyfile, + &error, + &ignore_error); + ASSERT (connection != NULL, + "ibft-dhcp-read", "failed to read %s: %s", TEST_IFCFG_IBFT_DHCP, error->message); + + ASSERT (nm_connection_verify (connection, &error), + "ibft-dhcp-verify", "failed to verify %s: %s", TEST_IFCFG_IBFT_DHCP, error->message); + + /* ===== CONNECTION SETTING ===== */ + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + ASSERT (s_con != NULL, + "ibft-dhcp-verify-connection", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME); + + /* ID */ + tmp = nm_setting_connection_get_id (s_con); + ASSERT (tmp != NULL, + "ibft-dhcp-verify-connection", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + ASSERT (strcmp (tmp, expected_id) == 0, + "ibft-dhcp-verify-connection", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + + /* UUID can't be tested if the ifcfg does not contain the UUID key, because + * the UUID is generated on the full path of the ifcfg file, which can change + * depending on where the tests are run. + */ + + /* Timestamp */ + ASSERT (nm_setting_connection_get_timestamp (s_con) == expected_timestamp, + "ibft-dhcp-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_TIMESTAMP); + + /* Autoconnect */ + ASSERT (nm_setting_connection_get_autoconnect (s_con) == TRUE, + "ibft-dhcp-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_AUTOCONNECT); + + /* Read-only */ + ASSERT (nm_setting_connection_get_read_only (s_con) == TRUE, + "ibft-dhcp-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_READ_ONLY); + + /* ===== WIRED SETTING ===== */ + + s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED)); + ASSERT (s_wired != NULL, + "ibft-dhcp-verify-wired", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME); + + /* MAC address */ + array = nm_setting_wired_get_mac_address (s_wired); + ASSERT (array != NULL, + "ibft-dhcp-verify-wired", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + ASSERT (array->len == ETH_ALEN, + "ibft-dhcp-verify-wired", "failed to verify %s: unexpected %s / %s key value length", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + ASSERT (memcmp (array->data, &expected_mac_address[0], sizeof (expected_mac_address)) == 0, + "ibft-dhcp-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + + ASSERT (nm_setting_wired_get_mtu (s_wired) == 0, + "ibft-dhcp-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MTU); + + /* ===== IPv4 SETTING ===== */ + + s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG)); + ASSERT (s_ip4 != NULL, + "ibft-dhcp-verify-ip4", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_IP4_CONFIG_SETTING_NAME); + + /* Method */ + tmp = nm_setting_ip4_config_get_method (s_ip4); + ASSERT (strcmp (tmp, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0, + "ibft-dhcp-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_DHCP, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_METHOD); + + g_object_unref (connection); +} + +#define TEST_IFCFG_IBFT_STATIC TEST_IFCFG_DIR"/network-scripts/ifcfg-test-ibft-static" + +static void +test_read_ibft_static (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIP4Config *s_ip4; + char *unmanaged = NULL; + char *keyfile = NULL; + gboolean ignore_error = FALSE; + GError *error = NULL; + const char *tmp; + const GByteArray *array; + char expected_mac_address[ETH_ALEN] = { 0x00, 0x33, 0x21, 0x98, 0xb9, 0xf0 }; + const char *expected_id = "System test-ibft-static"; + guint64 expected_timestamp = 0; + const char *expected_dns1 = "10.16.255.2"; + const char *expected_dns2 = "10.16.255.3"; + struct in_addr addr; + const char *expected_address1 = "192.168.32.72"; + const char *expected_address1_gw = "192.168.35.254"; + NMIP4Address *ip4_addr; + + connection = connection_from_file (TEST_IFCFG_IBFT_STATIC, + NULL, + TYPE_ETHERNET, + TEST_IFCFG_DIR "/iscsiadm-test-static", + &unmanaged, + &keyfile, + &error, + &ignore_error); + ASSERT (connection != NULL, + "ibft-static-read", "failed to read %s: %s", TEST_IFCFG_IBFT_STATIC, error->message); + + ASSERT (nm_connection_verify (connection, &error), + "ibft-static-verify", "failed to verify %s: %s", TEST_IFCFG_IBFT_STATIC, error->message); + + /* ===== CONNECTION SETTING ===== */ + + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION)); + ASSERT (s_con != NULL, + "ibft-static-verify-connection", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME); + + /* ID */ + tmp = nm_setting_connection_get_id (s_con); + ASSERT (tmp != NULL, + "ibft-static-verify-connection", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + ASSERT (strcmp (tmp, expected_id) == 0, + "ibft-static-verify-connection", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_ID); + + /* UUID can't be tested if the ifcfg does not contain the UUID key, because + * the UUID is generated on the full path of the ifcfg file, which can change + * depending on where the tests are run. + */ + + /* Timestamp */ + ASSERT (nm_setting_connection_get_timestamp (s_con) == expected_timestamp, + "ibft-static-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_TIMESTAMP); + + /* Autoconnect */ + ASSERT (nm_setting_connection_get_autoconnect (s_con) == TRUE, + "ibft-static-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_AUTOCONNECT); + + /* Read-only */ + ASSERT (nm_setting_connection_get_read_only (s_con) == TRUE, + "ibft-static-verify-connection", "failed to verify %s: unexpected %s /%s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_READ_ONLY); + + /* ===== WIRED SETTING ===== */ + + s_wired = NM_SETTING_WIRED (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED)); + ASSERT (s_wired != NULL, + "ibft-static-verify-wired", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME); + + /* MAC address */ + array = nm_setting_wired_get_mac_address (s_wired); + ASSERT (array != NULL, + "ibft-static-verify-wired", "failed to verify %s: missing %s / %s key", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + ASSERT (array->len == ETH_ALEN, + "ibft-static-verify-wired", "failed to verify %s: unexpected %s / %s key value length", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + ASSERT (memcmp (array->data, &expected_mac_address[0], sizeof (expected_mac_address)) == 0, + "ibft-static-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MAC_ADDRESS); + + ASSERT (nm_setting_wired_get_mtu (s_wired) == 0, + "ibft-static-verify-wired", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_WIRED_MTU); + + /* ===== IPv4 SETTING ===== */ + + s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG)); + ASSERT (s_ip4 != NULL, + "ibft-static-verify-ip4", "failed to verify %s: missing %s setting", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME); + + /* Method */ + tmp = nm_setting_ip4_config_get_method (s_ip4); + ASSERT (strcmp (tmp, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_METHOD); + + /* DNS Addresses */ + ASSERT (nm_setting_ip4_config_get_num_dns (s_ip4) == 2, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + ASSERT (inet_pton (AF_INET, expected_dns1, &addr) > 0, + "ibft-static-verify-ip4", "failed to verify %s: couldn't convert DNS IP address #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + ASSERT (nm_setting_ip4_config_get_dns (s_ip4, 0) == addr.s_addr, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + ASSERT (inet_pton (AF_INET, expected_dns2, &addr) > 0, + "ibft-static-verify-ip4", "failed to verify %s: couldn't convert DNS IP address #2", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + ASSERT (nm_setting_ip4_config_get_dns (s_ip4, 1) == addr.s_addr, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value #2", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + ASSERT (nm_setting_ip4_config_get_num_addresses (s_ip4) == 1, + "ibft-static-verify-ip4", "failed to verify %s: unexpected %s / %s key value", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + + /* Address #1 */ + ip4_addr = nm_setting_ip4_config_get_address (s_ip4, 0); + ASSERT (ip4_addr, + "ibft-static-verify-ip4", "failed to verify %s: missing IP4 address #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + + ASSERT (nm_ip4_address_get_prefix (ip4_addr) == 22, + "ibft-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1 prefix", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + + ASSERT (inet_pton (AF_INET, expected_address1, &addr) > 0, + "ibft-static-verify-ip4", "failed to verify %s: couldn't convert IP address #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_DNS); + ASSERT (nm_ip4_address_get_address (ip4_addr) == addr.s_addr, + "ibft-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + + ASSERT (inet_pton (AF_INET, expected_address1_gw, &addr) > 0, + "ibft-static-verify-ip4", "failed to verify %s: couldn't convert IP address #1 gateway", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + ASSERT (nm_ip4_address_get_gateway (ip4_addr) == addr.s_addr, + "ibft-static-verify-ip4", "failed to verify %s: unexpected IP4 address #1 gateway", + TEST_IFCFG_IBFT_STATIC, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_ADDRESSES); + + g_object_unref (connection); +} + +static void +test_read_ibft_malformed (const char *name, const char *iscsiadm_path) +{ + NMConnection *connection; + char *unmanaged = NULL; + char *keyfile = NULL; + gboolean ignore_error = FALSE; + GError *error = NULL; + + connection = connection_from_file (TEST_IFCFG_IBFT_STATIC, + NULL, + TYPE_ETHERNET, + iscsiadm_path, + &unmanaged, + &keyfile, + &error, + &ignore_error); + ASSERT (connection == NULL, + name, "unexpectedly able to read %s", TEST_IFCFG_IBFT_STATIC); +} + static void test_write_wired_pppoe (void) { @@ -5236,6 +5635,16 @@ int main (int argc, char **argv) test_write_wifi_wpa_eap_ttls_tls (); test_write_wifi_wpa_eap_ttls_mschapv2 (); + /* iSCSI / ibft */ + test_read_ibft_dhcp (); + test_read_ibft_static (); + test_read_ibft_malformed ("ibft-bad-record-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-record"); + test_read_ibft_malformed ("ibft-bad-entry-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-entry"); + test_read_ibft_malformed ("ibft-bad-ipaddr-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-ipaddr"); + test_read_ibft_malformed ("ibft-bad-gateway-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-gateway"); + test_read_ibft_malformed ("ibft-bad-dns1-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns1"); + test_read_ibft_malformed ("ibft-bad-dns2-read", TEST_IFCFG_DIR "/iscsiadm-test-bad-dns2"); + /* Stuff we expect to fail for now */ test_write_wired_pppoe (); test_write_vpn (); From 39feeeb0653a81b1324cf8791aba751d546b0dd1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Aug 2009 11:50:26 -0500 Subject: [PATCH 18/19] introspection: add a few missing files --- introspection/all.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/introspection/all.xml b/introspection/all.xml index 82af93d8c8..370f76742e 100644 --- a/introspection/all.xml +++ b/introspection/all.xml @@ -34,7 +34,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + From 0993ea398951df26eb961e7ca0ac386ed374022d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Aug 2009 15:21:16 -0500 Subject: [PATCH 19/19] libnm-util: fix DEFAULT_MAP_SIZE; broken by ff88cf12c2de43 --- libnm-util/nm-connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c index 1d186a6e91..7dcb310e96 100644 --- a/libnm-util/nm-connection.c +++ b/libnm-util/nm-connection.c @@ -141,7 +141,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; static GHashTable *registered_settings = NULL; -#define DEFAULT_MAP_SIZE 14 +#define DEFAULT_MAP_SIZE 15 static struct SettingInfo { const char *name;