Merge remote branch 'origin/ip6only'

This commit is contained in:
Dan Williams 2010-04-26 17:33:45 -07:00
commit c3ebe98ae3
64 changed files with 2526 additions and 1895 deletions

View file

@ -17,7 +17,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* (C) Copyright 2009 Red Hat, Inc.
* (C) Copyright 2009 - 2010 Red Hat, Inc.
*/
#include <stdio.h>
@ -86,7 +86,7 @@ static TypeNameElement name_map[] = {
{ "GPtrArray_GArray_guint__", "array of array of uint32" },
{ "GPtrArray_GArray_guchar__", "array of byte array" },
{ "GHashTable_gchararray+gchararray_", "dict of (string::string)" },
{ "GPtrArray_GValueArray_GArray_guchar_+guint__", "array of (byte array, uint32)" },
{ "GPtrArray_GValueArray_GArray_guchar_+guint+GArray_guchar___", "array of (byte array, uint32, byte array)" },
{ "GPtrArray_GValueArray_GArray_guchar_+guint+GArray_guchar_+guint__", "array of (byte array, uint32, byte array, uint32)" },
{ NULL, NULL }
};

View file

@ -34,7 +34,7 @@
#define DBUS_TYPE_G_MAP_OF_STRING (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING))
#define DBUS_TYPE_G_LIST_OF_STRING (dbus_g_type_get_collection ("GSList", G_TYPE_STRING))
#define DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
#define DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_INVALID))
#define DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_IP6_ADDRESS))
#define DBUS_TYPE_G_IP6_ROUTE (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
#define DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_IP6_ROUTE))

View file

@ -18,7 +18,10 @@
<tp:docstring>The state of this active connection.</tp:docstring>
</property>
<property name="Default" type="b" access="read">
<tp:docstring>Whether this active connection is the default connection, i.e. whether it currently owns the default route.</tp:docstring>
<tp:docstring>Whether this active connection is the default IPv4 connection, i.e. whether it currently owns the default IPv4 route.</tp:docstring>
</property>
<property name="Default6" type="b" access="read">
<tp:docstring>Whether this active connection is the default IPv6 connection, i.e. whether it currently owns the default IPv6 route.</tp:docstring>
</property>
<property name="Vpn" type="b" access="read">
<tp:docstring>Whether this active connection is also a VPN connection.</tp:docstring>

View file

@ -2,8 +2,8 @@
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
<interface name="org.freedesktop.NetworkManager.IP6Config">
<property name="Addresses" type="a(ayu)" access="read">
<tp:docstring>Tuples of IPv6 address/prefix.</tp:docstring>
<property name="Addresses" type="a(ayuay)" access="read">
<tp:docstring>Tuples of IPv6 address/prefix/gateway.</tp:docstring>
</property>
<property name="Nameservers" type="aay" access="read">
<tp:docstring>The nameservers in use.</tp:docstring>

View file

@ -132,7 +132,7 @@ libnm_glib_la_LIBADD = \
$(GUDEV_LIBS)
libnm_glib_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-glib.ver \
-version-info "4:1:2"
-version-info "4:2:2"
noinst_PROGRAMS = libnm-glib-test

View file

@ -18,6 +18,7 @@ global:
nm_access_point_new;
nm_active_connection_get_connection;
nm_active_connection_get_default;
nm_active_connection_get_default6;
nm_active_connection_get_devices;
nm_active_connection_get_scope;
nm_active_connection_get_service_name;

View file

@ -17,7 +17,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2008 Red Hat, Inc.
* Copyright (C) 2007 - 2010 Red Hat, Inc.
* Copyright (C) 2008 Novell, Inc.
*/
@ -50,6 +50,7 @@ typedef struct {
GPtrArray *devices;
NMActiveConnectionState state;
gboolean is_default;
gboolean is_default6;
} NMActiveConnectionPrivate;
enum {
@ -60,6 +61,7 @@ enum {
PROP_DEVICES,
PROP_STATE,
PROP_DEFAULT,
PROP_DEFAULT6,
LAST_PROP
};
@ -70,6 +72,7 @@ enum {
#define DBUS_PROP_DEVICES "Devices"
#define DBUS_PROP_STATE "State"
#define DBUS_PROP_DEFAULT "Default"
#define DBUS_PROP_DEFAULT6 "Default6"
/**
* nm_active_connection_new:
@ -263,10 +266,10 @@ nm_active_connection_get_state (NMActiveConnection *connection)
* nm_active_connection_get_default:
* @connection: a #NMActiveConnection
*
* Whether the active connection is the default one (that is, is used for the default route
* and DNS information).
* Whether the active connection is the default IPv4 one (that is, is used for
* the default IPv4 route and DNS information).
*
* Returns: %TRUE if the active connection is the default one
* Returns: %TRUE if the active connection is the default IPv4 connection
**/
gboolean
nm_active_connection_get_default (NMActiveConnection *connection)
@ -278,13 +281,39 @@ nm_active_connection_get_default (NMActiveConnection *connection)
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
if (!priv->is_default) {
priv->is_default = _nm_object_get_boolean_property (NM_OBJECT (connection),
NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
DBUS_PROP_DEFAULT);
NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
DBUS_PROP_DEFAULT);
}
return priv->is_default;
}
/**
* nm_active_connection_get_default6:
* @connection: a #NMActiveConnection
*
* Whether the active connection is the default IPv6 one (that is, is used for
* the default IPv6 route and DNS information).
*
* Returns: %TRUE if the active connection is the default IPv6 connection
**/
gboolean
nm_active_connection_get_default6 (NMActiveConnection *connection)
{
NMActiveConnectionPrivate *priv;
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (connection), FALSE);
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (connection);
if (!priv->is_default6) {
priv->is_default6 = _nm_object_get_boolean_property (NM_OBJECT (connection),
NM_DBUS_INTERFACE_ACTIVE_CONNECTION,
DBUS_PROP_DEFAULT6);
}
return priv->is_default6;
}
static void
nm_active_connection_init (NMActiveConnection *ap)
{
@ -350,6 +379,9 @@ get_property (GObject *object,
case PROP_DEFAULT:
g_value_set_boolean (value, nm_active_connection_get_default (self));
break;
case PROP_DEFAULT6:
g_value_set_boolean (value, nm_active_connection_get_default6 (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -392,6 +424,7 @@ register_for_property_changed (NMActiveConnection *connection)
{ NM_ACTIVE_CONNECTION_DEVICES, demarshal_devices, &priv->devices },
{ NM_ACTIVE_CONNECTION_STATE, _nm_object_demarshal_generic, &priv->state },
{ NM_ACTIVE_CONNECTION_DEFAULT, _nm_object_demarshal_generic, &priv->is_default },
{ NM_ACTIVE_CONNECTION_DEFAULT6, _nm_object_demarshal_generic, &priv->is_default6 },
{ NULL },
};
@ -512,13 +545,26 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class)
/**
* NMActiveConnection:default:
*
* Whether the active connection is the default one.
* Whether the active connection is the default IPv4 one.
**/
g_object_class_install_property
(object_class, PROP_DEFAULT,
g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT,
"Default",
"Is the default active connection",
"Is the default IPv4 active connection",
FALSE,
G_PARAM_READABLE));
/**
* NMActiveConnection:default6:
*
* Whether the active connection is the default IPv6 one.
**/
g_object_class_install_property
(object_class, PROP_DEFAULT6,
g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6,
"Default6",
"Is the default IPv6 active connection",
FALSE,
G_PARAM_READABLE));
}

View file

@ -17,7 +17,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2008 Red Hat, Inc.
* Copyright (C) 2007 - 2010 Red Hat, Inc.
* Copyright (C) 2008 Novell, Inc.
*/
@ -45,6 +45,7 @@ G_BEGIN_DECLS
#define NM_ACTIVE_CONNECTION_DEVICES "devices"
#define NM_ACTIVE_CONNECTION_STATE "state"
#define NM_ACTIVE_CONNECTION_DEFAULT "default"
#define NM_ACTIVE_CONNECTION_DEFAULT6 "default6"
typedef struct {
NMObject parent;
@ -73,6 +74,7 @@ const char * nm_active_connection_get_specific_object (NMActiveConnection *c
const GPtrArray *nm_active_connection_get_devices (NMActiveConnection *connection);
NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *connection);
gboolean nm_active_connection_get_default (NMActiveConnection *connection);
gboolean nm_active_connection_get_default6 (NMActiveConnection *connection);
G_END_DECLS

View file

@ -59,7 +59,7 @@ libnm_util_la_SOURCES= \
libnm_util_la_LIBADD = $(GLIB_LIBS) $(DBUS_LIBS) $(UUID_LIBS)
libnm_util_la_LDFLAGS = -Wl,--version-script=$(srcdir)/libnm-util.ver \
-version-info "4:2:3"
-version-info "4:3:3"
if WITH_GNUTLS
libnm_util_la_SOURCES += crypto_gnutls.c

View file

@ -177,6 +177,8 @@ global:
nm_ip6_address_compare;
nm_ip6_address_get_address;
nm_ip6_address_set_address;
nm_ip6_address_get_gateway;
nm_ip6_address_set_gateway;
nm_ip6_address_get_prefix;
nm_ip6_address_set_prefix;
nm_ip6_route_new;

View file

@ -19,7 +19,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 - 2008 Red Hat, Inc.
* (C) Copyright 2007 - 2010 Red Hat, Inc.
* (C) Copyright 2007 - 2008 Novell, Inc.
*/
@ -377,6 +377,7 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
GValue *tmp_val;
GByteArray *addr1, *addr2;
guint32 prefix1, prefix2;
GByteArray *gw1, *gw2;
gint ret = 0;
int i;
@ -387,8 +388,8 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
/* Since they are NM IPv6 address structures, we expect both
* to contain two elements as specified in nm-dbus-glib-types.h.
*/
g_return_val_if_fail (values1->n_values == 2, 0);
g_return_val_if_fail (values2->n_values == 2, 0);
g_return_val_if_fail (values1->n_values == 3, 0);
g_return_val_if_fail (values2->n_values == 3, 0);
/* First struct IPv6 address */
tmp_val = g_value_array_get_nth (values1, 0);
@ -396,6 +397,9 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
/* First struct IPv6 prefix */
tmp_val = g_value_array_get_nth (values1, 1);
prefix1 = g_value_get_uint (tmp_val);
/* First struct IPv6 gateway */
tmp_val = g_value_array_get_nth (values1, 2);
gw1 = g_value_get_boxed (tmp_val);
/* Second struct IPv6 address */
tmp_val = g_value_array_get_nth (values2, 0);
@ -403,6 +407,9 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
/* Second struct IPv6 prefix */
tmp_val = g_value_array_get_nth (values2, 1);
prefix2 = g_value_get_uint (tmp_val);
/* Second struct IPv6 gateway */
tmp_val = g_value_array_get_nth (values2, 2);
gw2 = g_value_get_boxed (tmp_val);
/* Compare IPv6 addresses */
if (prefix1 != prefix2)
@ -413,6 +420,11 @@ nm_gvalue_ip6_address_compare (const GValue *value1, const GValue *value2)
ret = addr1->data[i] < addr2->data[i] ? -1 : addr1->data[i] > addr2->data[i];
}
if (!IN6_ARE_ADDR_EQUAL ((struct in6_addr *) gw1->data, (struct in6_addr *) gw2->data)) {
for (i = 0; ret == 0 && i < gw1->len; i++)
ret = gw1->data[i] < gw2->data[i] ? -1 : gw1->data[i] > gw2->data[i];
}
return ret;
}

View file

@ -19,7 +19,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 - 2008 Red Hat, Inc.
* (C) Copyright 2007 - 2010 Red Hat, Inc.
* (C) Copyright 2007 - 2008 Novell, Inc.
*/
@ -462,7 +462,8 @@ verify (NMSetting *setting, GSList *all_settings, GError **error)
return FALSE;
}
} else if ( !strcmp (priv->method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)
|| !strcmp (priv->method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
|| !strcmp (priv->method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)
|| !strcmp (priv->method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
if (priv->dns && priv->dns->len) {
g_set_error (error,
NM_SETTING_IP4_CONFIG_ERROR,
@ -721,7 +722,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
* network access to other computers) then the interface is assigned an
* address in the 10.42.x.1/24 range and a DHCP and forwarding DNS server
* are started, and the interface is NAT-ed to the current default network
* connection. This property must be set.
* connection. 'disabled' means IPv4 will not be used on this connection.
* This property must be set.
**/
g_object_class_install_property
(object_class, PROP_METHOD,
@ -742,7 +744,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
"address in the 10.42.x.1/24 range and a DHCP and "
"forwarding DNS server are started, and the "
"interface is NAT-ed to the current default network "
"connection. This property must be set.",
"connection. 'disabled' means IPv4 will not be "
"used on this connection. This property must be set.",
NULL,
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
@ -751,8 +754,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
*
* List of DNS servers (network byte order). For the 'auto' method, these
* DNS servers are appended to those (if any) returned by automatic
* configuration. DNS servers cannot be used with the 'shared' or
* 'link-local' methods as there is no usptream network. In all other
* configuration. DNS servers cannot be used with the 'shared', 'link-local',
* or 'disabled' methods as there is no usptream network. In all other
* methods, these DNS servers are used as the only DNS servers for this
* connection.
**/
@ -764,10 +767,10 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
"the 'auto' method, these DNS servers are "
"appended to those (if any) returned by automatic "
"configuration. DNS servers cannot be used with "
"the 'shared' or 'link-local' methods as there is "
"no usptream network. In all other methods, "
"these DNS servers are used as the only DNS "
"servers for this connection.",
"the 'shared', 'link-local', or 'disabled' "
"methods as there is no usptream network. In all "
"other methods, these DNS servers are used as the "
"only DNS servers for this connection.",
DBUS_TYPE_G_UINT_ARRAY,
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
@ -776,9 +779,9 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
*
* List of DNS search domains. For the 'auto' method, these search domains
* are appended to those returned by automatic configuration. Search domains
* cannot be used with the 'shared' or 'link-local' methods as there is no
* upstream network. In all other methods, these search domains are used
* as the only search domains for this connection.
* cannot be used with the 'shared', 'link-local', or 'disabled' methods as
* there is no upstream network. In all other methods, these search domains
* are used as the only search domains for this connection.
**/
g_object_class_install_property
(object_class, PROP_DNS_SEARCH,
@ -787,11 +790,11 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
"List of DNS search domains. For the 'auto' "
"method, these search domains are appended to "
"those returned by automatic configuration. "
"Search domains cannot be used with the 'shared' "
"or 'link-local' methods as there is no upstream "
"network. In all other methods, these search "
"domains are used as the only search domains for "
"this connection.",
"Search domains cannot be used with the 'shared', "
"'link-local', or 'disabled' methods as there is "
"no upstream network. In all other methods, these "
"search domains are used as the only search domains "
"for this connection.",
DBUS_TYPE_G_LIST_OF_STRING,
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
@ -804,8 +807,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
* (network byte order). The gateway may be left as 0 if no gateway exists
* for that subnet. For the 'auto' method, given IP addresses are appended
* to those returned by automatic configuration. Addresses cannot be used
* with the 'shared' or 'link-local' methods as the interface is
* automatically assigned an address with these methods.
* with the 'shared', 'link-local', or 'disabled' methods as addressing is
* either automatic or disabled with these methods.
**/
g_object_class_install_property
(object_class, PROP_ADDRESSES,
@ -820,9 +823,9 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
"for that subnet. For the 'auto' method, given "
"IP addresses are appended to those returned by "
"automatic configuration. Addresses cannot be "
"used with the 'shared' or 'link-local' methods "
"as the interface is automatically assigned an "
"address with these methods.",
"used with the 'shared', 'link-local', or "
"'disabled' methods as addressing is either "
"automatic or disabled with these methods.",
DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT,
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
@ -835,8 +838,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
* address prefix (1 - 32), the third being the next-hop (network byte
* order) if any, and the fourth being the route metric. For the 'auto'
* method, given IP routes are appended to those returned by automatic
* configuration. Routes cannot be used with the 'shared' or 'link-local'
* methods because there is no upstream network.
* configuration. Routes cannot be used with the 'shared', 'link-local',
* or 'disabled' methods because there is no upstream network.
**/
g_object_class_install_property
(object_class, PROP_ROUTES,
@ -852,8 +855,8 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *setting_class)
"For the 'auto' method, given IP routes are "
"appended to those returned by automatic "
"configuration. Routes cannot be used with the "
"'shared' or 'link-local' methods as there is no "
"upstream network.",
"'shared', 'link-local', or 'disabled', methods "
"as there is no upstream network.",
DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT,
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));

View file

@ -19,7 +19,7 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* (C) Copyright 2007 - 2008 Red Hat, Inc.
* (C) Copyright 2007 - 2010 Red Hat, Inc.
* (C) Copyright 2007 - 2008 Novell, Inc.
*/
@ -69,6 +69,7 @@ GQuark nm_setting_ip4_config_error_quark (void);
#define NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL "link-local"
#define NM_SETTING_IP4_CONFIG_METHOD_MANUAL "manual"
#define NM_SETTING_IP4_CONFIG_METHOD_SHARED "shared"
#define NM_SETTING_IP4_CONFIG_METHOD_DISABLED "disabled"
typedef struct NMIP4Address NMIP4Address;

View file

@ -684,25 +684,32 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class)
* NMSettingIP6Config:addresses:
*
* Array of IPv6 address structures. Each IPv6 address structure is
* composed of 2 members, the first being a byte array containing the IPv6
* address (network byte order) and the second a 32-bit integer containing
* the IPv6 address prefix. For the 'auto' method, given IP addresses are
* appended to those returned by automatic configuration. Addresses cannot
* be used with the 'shared' or 'link-local' methods as the interface is
* automatically assigned an address with these methods.
* composed of 3 members, the first being a byte array containing the IPv6
* address (network byte order), the second a 32-bit integer containing the
* IPv6 address prefix, and the third a byte array containing the IPv6
* address (network byte order) of the gateway associated with this address,
* if any. If no gateway is given, the third element should be given as
* all zeros. For the 'auto' method, given IP addresses are appended to
* those returned by automatic configuration. Addresses cannot be used with
* the 'shared' or 'link-local' methods as the interface is automatically
* assigned an address with these methods.
**/
g_object_class_install_property
(object_class, PROP_ADDRESSES,
_nm_param_spec_specialized (NM_SETTING_IP6_CONFIG_ADDRESSES,
"Addresses",
"Array of IPv6 address structures. Each IPv6 "
"address structure is composed of 2 members, the "
"address structure is composed of 3 members, the "
"first being a byte array containing the IPv6 "
"address (network byte order) and the second a "
"address (network byte order), the second a "
"32-bit integer containing the IPv6 address "
"prefix. For the 'auto' method, given IP "
"addresses are appended to those returned by "
"automatic configuration. Addresses cannot be "
"prefix, and the third a byte array containing "
"the IPv6 address (network byte order) of the "
"gateway associated with this address, if any. "
"If no gateway is given, the third element should "
"be given as all zeros. For the 'auto' method, "
"given IP addresses are appended to those returned "
"by automatic configuration. Addresses cannot be "
"used with the 'shared' or 'link-local' methods "
"as the interface is automatically assigned an "
"address with these methods.",
@ -797,10 +804,13 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *setting_class)
}
/********************************************************************/
struct NMIP6Address {
guint32 refcount;
struct in6_addr address;
guint32 prefix;
struct in6_addr gateway;
};
NMIP6Address *
@ -902,6 +912,27 @@ nm_ip6_address_set_prefix (NMIP6Address *address, guint32 prefix)
address->prefix = prefix;
}
const struct in6_addr *
nm_ip6_address_get_gateway (NMIP6Address *address)
{
g_return_val_if_fail (address != NULL, 0);
g_return_val_if_fail (address->refcount > 0, 0);
return &address->gateway;
}
void
nm_ip6_address_set_gateway (NMIP6Address *address, const struct in6_addr *gw)
{
g_return_if_fail (address != NULL);
g_return_if_fail (address->refcount > 0);
g_return_if_fail (gw != NULL);
memcpy (&address->gateway, gw, sizeof (struct in6_addr));
}
/********************************************************************/
struct NMIP6Route {
guint32 refcount;

View file

@ -88,6 +88,10 @@ guint32 nm_ip6_address_get_prefix (NMIP6Address *address);
void nm_ip6_address_set_prefix (NMIP6Address *address,
guint32 prefix);
const struct in6_addr *nm_ip6_address_get_gateway (NMIP6Address *address);
void nm_ip6_address_set_gateway (NMIP6Address *address,
const struct in6_addr *gw);
typedef struct NMIP6Route NMIP6Route;
NMIP6Route * nm_ip6_route_new (void);

View file

@ -275,6 +275,8 @@ nm_utils_init (GError **error)
if (!crypto_init (error))
return FALSE;
_nm_utils_register_value_transformations ();
atexit (nm_utils_deinit);
initialized = TRUE;
}
@ -745,7 +747,8 @@ nm_utils_convert_string_hash_to_string (const GValue *src_value, GValue *dest_va
hash = (GHashTable *) g_value_get_boxed (src_value);
printable = g_string_new ("[");
g_hash_table_foreach (hash, convert_one_string_hash_entry, printable);
if (hash)
g_hash_table_foreach (hash, convert_one_string_hash_entry, printable);
g_string_append (printable, " ]");
g_value_take_string (dest_value, printable->str);
@ -886,6 +889,19 @@ nm_utils_convert_ip6_addr_struct_array_to_string (const GValue *src_value, GValu
continue;
}
g_string_append_printf (printable, "px = %u", prefix);
g_string_append (printable, ", ");
/* IPv6 Gateway */
tmp = g_value_array_get_nth (elements, 2);
ba_addr = g_value_get_boxed (tmp);
if (ba_addr->len != 16) {
g_string_append (printable, "invalid");
continue;
}
addr = (struct in6_addr *) ba_addr->data;
memset (buf, 0, sizeof (buf));
nm_utils_inet6_ntop (addr, buf);
g_string_append_printf (printable, "gw = %s", buf);
g_string_append (printable, " }");
}
g_string_append_c (printable, ']');
@ -977,6 +993,58 @@ nm_utils_convert_ip6_route_struct_array_to_string (const GValue *src_value, GVal
g_string_free (printable, FALSE);
}
#define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
#define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS))
static void
nm_utils_convert_old_ip6_addr_array (const GValue *src_value, GValue *dst_value)
{
GPtrArray *src_outer_array;
GPtrArray *dst_outer_array;
guint i;
g_return_if_fail (g_type_is_a (G_VALUE_TYPE (src_value), OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS));
src_outer_array = (GPtrArray *) g_value_get_boxed (src_value);
dst_outer_array = g_ptr_array_new ();
for (i = 0; src_outer_array && (i < src_outer_array->len); i++) {
GValueArray *src_addr_array;
GValueArray *dst_addr_array;
GValue element = {0, };
GValue *src_addr, *src_prefix;
GByteArray *ba;
src_addr_array = (GValueArray *) g_ptr_array_index (src_outer_array, i);
if ( (src_addr_array->n_values != 2)
|| (G_VALUE_TYPE (g_value_array_get_nth (src_addr_array, 0)) != DBUS_TYPE_G_UCHAR_ARRAY)
|| (G_VALUE_TYPE (g_value_array_get_nth (src_addr_array, 1)) != G_TYPE_UINT)) {
g_warning ("%s: invalid old IPv6 address type", __func__);
return;
}
dst_addr_array = g_value_array_new (3);
src_addr = g_value_array_get_nth (src_addr_array, 0);
g_value_array_append (dst_addr_array, src_addr);
src_prefix = g_value_array_get_nth (src_addr_array, 1);
g_value_array_append (dst_addr_array, src_prefix);
/* Blank Gateway */
g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
ba = g_byte_array_new ();
g_byte_array_append (ba, (guint8 *) "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16);
g_value_take_boxed (&element, ba);
g_value_array_append (dst_addr_array, &element);
g_value_unset (&element);
g_ptr_array_add (dst_outer_array, dst_addr_array);
}
g_value_take_boxed (dst_value, dst_outer_array);
}
void
_nm_utils_register_value_transformations (void)
{
@ -1013,6 +1081,9 @@ _nm_utils_register_value_transformations (void)
g_value_register_transform_func (DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE,
G_TYPE_STRING,
nm_utils_convert_ip6_route_struct_array_to_string);
g_value_register_transform_func (OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
nm_utils_convert_old_ip6_addr_array);
registered = TRUE;
}
}
@ -1459,8 +1530,8 @@ nm_utils_ip4_get_default_prefix (guint32 ip)
* @value: gvalue containing a GPtrArray of GValueArrays of (GArray of guchars) and guint32
*
* Utility function to convert a #GPtrArray of #GValueArrays of (#GArray of guchars) and guint32
* representing a list of NetworkManager IPv6 addresses (which is a pair of address
* and prefix), into a GSList of #NMIP6Address objects. The specific format of
* representing a list of NetworkManager IPv6 addresses (which is a tuple of address,
* prefix, and gateway), into a GSList of #NMIP6Address objects. The specific format of
* this serialization is not guaranteed to be stable and the #GValueArray may be
* extended in the future.
*
@ -1479,16 +1550,28 @@ nm_utils_ip6_addresses_from_gvalue (const GValue *value)
GValueArray *elements = (GValueArray *) g_ptr_array_index (addresses, i);
GValue *tmp;
GByteArray *ba_addr;
GByteArray *ba_gw = NULL;
NMIP6Address *addr;
guint32 prefix;
if ( (elements->n_values != 2)
|| (G_VALUE_TYPE (g_value_array_get_nth (elements, 0)) != DBUS_TYPE_G_UCHAR_ARRAY)
if (elements->n_values < 2 || elements->n_values > 3) {
nm_warning ("%s: ignoring invalid IP6 address structure", __func__);
continue;
}
if ( (G_VALUE_TYPE (g_value_array_get_nth (elements, 0)) != DBUS_TYPE_G_UCHAR_ARRAY)
|| (G_VALUE_TYPE (g_value_array_get_nth (elements, 1)) != G_TYPE_UINT)) {
nm_warning ("%s: ignoring invalid IP6 address structure", __func__);
continue;
}
/* Check optional 3rd element (gateway) */
if ( elements->n_values == 3
&& (G_VALUE_TYPE (g_value_array_get_nth (elements, 2)) != DBUS_TYPE_G_UCHAR_ARRAY)) {
nm_warning ("%s: ignoring invalid IP6 address structure", __func__);
continue;
}
tmp = g_value_array_get_nth (elements, 0);
ba_addr = g_value_get_boxed (tmp);
if (ba_addr->len != 16) {
@ -1505,9 +1588,22 @@ nm_utils_ip6_addresses_from_gvalue (const GValue *value)
continue;
}
if (elements->n_values == 3) {
tmp = g_value_array_get_nth (elements, 2);
ba_gw = g_value_get_boxed (tmp);
if (ba_gw->len != 16) {
nm_warning ("%s: ignoring invalid IP6 gateway address of length %d",
__func__, ba_gw->len);
continue;
}
}
addr = nm_ip6_address_new ();
nm_ip6_address_set_prefix (addr, prefix);
nm_ip6_address_set_address (addr, (const struct in6_addr *) ba_addr->data);
if (ba_gw)
nm_ip6_address_set_gateway (addr, (const struct in6_addr *) ba_gw->data);
list = g_slist_prepend (list, addr);
}
@ -1522,10 +1618,10 @@ nm_utils_ip6_addresses_from_gvalue (const GValue *value)
* g_value_unset().
*
* Utility function to convert a #GSList of #NMIP6Address objects into a
* GPtrArray of GValueArrays of (GArray or guchars) and guint32 representing a list
* of NetworkManager IPv6 addresses (which is a pair of address and prefix).
* The specific format of this serialization is not guaranteed to be stable and may be
* extended in the future.
* GPtrArray of GValueArrays representing a list of NetworkManager IPv6 addresses
* (which is a tuple of address, prefix, and gateway). The specific format of
* this serialization is not guaranteed to be stable and may be extended in the
* future.
**/
void
nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value)
@ -1541,8 +1637,9 @@ nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value)
GValue element = {0, };
GByteArray *ba;
array = g_value_array_new (2);
array = g_value_array_new (3);
/* IP address */
g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
ba = g_byte_array_new ();
g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_address (addr), 16);
@ -1550,11 +1647,20 @@ nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value)
g_value_array_append (array, &element);
g_value_unset (&element);
/* Prefix */
g_value_init (&element, G_TYPE_UINT);
g_value_set_uint (&element, nm_ip6_address_get_prefix (addr));
g_value_array_append (array, &element);
g_value_unset (&element);
/* Gateway */
g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
ba = g_byte_array_new ();
g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_gateway (addr), 16);
g_value_take_boxed (&element, ba);
g_value_array_append (array, &element);
g_value_unset (&element);
g_ptr_array_add (addresses, array);
}

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2008 - 2009 Red Hat, Inc.
* Copyright (C) 2008 - 2010 Red Hat, Inc.
*
*/
@ -28,7 +28,8 @@
#include "nm-setting-connection.h"
#include "nm-setting-vpn.h"
#include "nm-setting-ip6-config.h"
#include "nm-dbus-glib-types.h"
static void
vpn_check_func (const char *key, const char *value, gpointer user_data)
@ -128,6 +129,99 @@ test_setting_vpn_items (void)
g_object_unref (s_vpn);
}
#define OLD_DBUS_TYPE_G_IP6_ADDRESS (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
#define OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS (dbus_g_type_get_collection ("GPtrArray", OLD_DBUS_TYPE_G_IP6_ADDRESS))
/* Test that setting the IPv6 setting's 'addresses' property using the old
* IPv6 address format still works, i.e. that the GValue transformation function
* from old->new is working correctly.
*/
static void
test_setting_ip6_config_old_address_array (void)
{
NMSettingIP6Config *s_ip6;
GPtrArray *addresses, *read_addresses;
GValueArray *array, *read_array;
GValue element = {0, }, written_value = {0, }, read_value = {0, };
GByteArray *ba;
const guint8 addr[16] = { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
0x11, 0x22, 0x33, 0x44, 0x66, 0x77, 0x88, 0x99 };
const guint8 gw[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
guint32 prefix = 56;
GValue *read_addr, *read_prefix, *read_gw;
s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
ASSERT (s_ip6 != NULL,
"ip6-old-addr", "error creating IP6 setting");
g_value_init (&written_value, OLD_DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS);
addresses = g_ptr_array_new ();
array = g_value_array_new (3);
/* IP address */
g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
ba = g_byte_array_new ();
g_byte_array_append (ba, &addr[0], sizeof (addr));
g_value_take_boxed (&element, ba);
g_value_array_append (array, &element);
g_value_unset (&element);
/* Prefix */
g_value_init (&element, G_TYPE_UINT);
g_value_set_uint (&element, prefix);
g_value_array_append (array, &element);
g_value_unset (&element);
g_ptr_array_add (addresses, array);
g_value_set_boxed (&written_value, addresses);
/* Set the address array on the object */
g_object_set_property (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_ADDRESSES, &written_value);
/* Get it back so we can compare it */
g_value_init (&read_value, DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS);
g_object_get_property (G_OBJECT (s_ip6), NM_SETTING_IP6_CONFIG_ADDRESSES, &read_value);
ASSERT (G_VALUE_HOLDS (&read_value, DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS),
"ip6-old-addr", "wrong addresses property value type '%s'",
G_VALUE_TYPE_NAME (&read_value));
read_addresses = (GPtrArray *) g_value_get_boxed (&read_value);
ASSERT (read_addresses != NULL,
"ip6-old-addr", "missing addresses on readback");
ASSERT (read_addresses->len == 1,
"ip6-old-addr", "expected one address on readback");
read_array = (GValueArray *) g_ptr_array_index (read_addresses, 0);
read_addr = g_value_array_get_nth (read_array, 0);
ba = g_value_get_boxed (read_addr);
ASSERT (ba->len == sizeof (addr),
"ip6-old-addr", "unexpected address item length %d", ba->len);
ASSERT (memcmp (ba->data, &addr[0], sizeof (addr)) == 0,
"ip6-old-addr", "unexpected failure comparing addresses");
read_prefix = g_value_array_get_nth (read_array, 1);
ASSERT (g_value_get_uint (read_prefix) == prefix,
"ip6-old-addr", "unexpected failure comparing prefix");
/* Ensure the gateway is all zeros, which is how the 2-item to 3-item
* conversion happens.
*/
read_gw = g_value_array_get_nth (read_array, 2);
ba = g_value_get_boxed (read_gw);
ASSERT (ba->len == sizeof (gw),
"ip6-old-addr", "unexpected gateway item length %d", ba->len);
ASSERT (memcmp (ba->data, &gw[0], sizeof (gw)) == 0,
"ip6-old-addr", "unexpected failure comparing gateways");
g_value_unset (&written_value);
g_value_unset (&read_value);
g_object_unref (s_ip6);
}
int main (int argc, char **argv)
{
GError *error = NULL;
@ -142,6 +236,7 @@ int main (int argc, char **argv)
/* The tests */
test_setting_vpn_items ();
test_setting_ip6_config_old_address_array ();
base = g_path_get_basename (argv[0]);
fprintf (stdout, "%s: SUCCESS\n", base);

View file

@ -15,8 +15,8 @@ VOID:POINTER,POINTER
VOID:STRING,STRING,STRING,UINT
VOID:OBJECT,UINT,UINT
VOID:STRING,INT
VOID:STRING,UINT
VOID:STRING,UINT,BOOLEAN
VOID:INT,UINT
VOID:INT,UINT,BOOLEAN
VOID:OBJECT,OBJECT,ENUM
VOID:POINTER,STRING
VOID:STRING,BOXED

View file

@ -14,7 +14,6 @@ src/nm-netlink-monitor.c
src/main.c
src/dhcp-manager/nm-dhcp-dhclient.c
src/dhcp-manager/nm-dhcp-manager.c
src/ip6-manager/nm-netlink-listener.c
src/logging/nm-logging.c
src/named-manager/nm-named-manager.c
src/system-settings/nm-default-wired-connection.c

View file

@ -68,9 +68,11 @@ libtest_policy_hosts_la_SOURCES = \
nm-policy-hosts.h
libtest_policy_hosts_la_CPPFLAGS = \
-DSYSCONFDIR=\"$(sysconfdir)\" \
$(GLIB_CFLAGS)
libtest_policy_hosts_la_LIBADD = \
${top_builddir}/src/logging/libnm-logging.la \
$(GLIB_LIBS)
@ -123,6 +125,8 @@ NetworkManager_SOURCES = \
nm-policy.h \
nm-policy-hosts.c \
nm-policy-hosts.h \
nm-policy-hostname.c \
nm-policy-hostname.h \
NetworkManagerUtils.c \
NetworkManagerUtils.h \
nm-system.c \
@ -137,8 +141,6 @@ NetworkManager_SOURCES = \
nm-properties-changed-signal.h \
wpa.c \
wpa.h \
nm-netlink.c \
nm-netlink.h \
nm-dhcp4-config.c \
nm-dhcp4-config.h \
nm-dhcp6-config.c \
@ -206,9 +208,7 @@ BUILT_SOURCES = \
NetworkManager_CPPFLAGS = \
$(DBUS_CFLAGS) \
$(GLIB_CFLAGS) \
$(HAL_CFLAGS) \
$(GUDEV_CFLAGS) \
$(OPENSSL_CFLAGS) \
$(LIBNL_CFLAGS) \
$(GMODULE_CFLAGS) \
-DG_DISABLE_DEPRECATED \

View file

@ -1,9 +1,5 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* Timothee Lecomte <timothee.lecomte@ens.fr>
*
* Heavily based on NetworkManagerRedhat.c by Dan Williams <dcbw@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,7 +15,8 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2004 Red Hat, Inc.
* (C) Copyright 2004 - 2010 Red Hat, Inc.
* (C) Copyright 2006 Timothee Lecomte <timothee.lecomte@ens.fr>
*/
#ifdef HAVE_CONFIG_H
@ -36,8 +33,8 @@
#include "NetworkManagerGeneric.h"
#include "nm-system.h"
#include "NetworkManagerUtils.h"
#include "nm-netlink.h"
#include "nm-logging.h"
#include "nm-netlink-monitor.h"
/* Because of a bug in libnl, rtnl.h should be included before route.h */
#include <netlink/route/rtnl.h>

View file

@ -390,11 +390,14 @@ static DhcState state_table[] = {
{ DHC_REBIND4, "rebind" },
{ DHC_REBIND6, "rebind6" },
{ DHC_STOP, "stop" },
{ DHC_STOP6, "stop6" },
{ DHC_MEDIUM, "medium" },
{ DHC_TIMEOUT, "timeout" },
{ DHC_FAIL, "fail" },
{ DHC_EXPIRE, "expire" },
{ DHC_EXPIRE6, "expire6" },
{ DHC_RELEASE, "release" },
{ DHC_RELEASE6,"release6" },
{ DHC_START, "start" },
{ DHC_ABEND, "abend" },
{ DHC_END, "end" },

View file

@ -53,11 +53,14 @@ typedef enum {
DHC_REBIND6, /* IPv6 new/different lease */
DHC_DEPREF6, /* IPv6 lease depreferred */
DHC_STOP, /* remove old lease */
DHC_STOP6, /* remove old lease */
DHC_MEDIUM, /* media selection begun */
DHC_TIMEOUT, /* timed out contacting DHCP server */
DHC_FAIL, /* all attempts to contact server timed out, sleeping */
DHC_EXPIRE, /* lease has expired, renewing */
DHC_EXPIRE6, /* lease has expired, renewing */
DHC_RELEASE, /* releasing lease */
DHC_RELEASE6, /* releasing lease */
DHC_START, /* sent when dhclient started OK */
DHC_ABEND, /* dhclient exited abnormally */
DHC_END, /* dhclient exited normally */

View file

@ -482,6 +482,13 @@ nm_dhcp_manager_start_ip4 (NMDHCPManager *self,
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
if (s_ip4) {
const char *method = nm_setting_ip4_config_get_method (s_ip4);
if (method) {
/* Method must be 'auto' */
g_return_val_if_fail (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0, NULL);
}
if ( nm_setting_ip4_config_get_dhcp_send_hostname (s_ip4)
&& (nm_setting_ip4_config_get_dhcp_hostname (s_ip4) == NULL)
&& priv->hostname_provider != NULL) {

View file

@ -11,14 +11,11 @@ noinst_LTLIBRARIES = libip6-manager.la
libip6_manager_la_SOURCES = \
nm-ip6-manager.c \
nm-ip6-manager.h \
nm-netlink-listener.c \
nm-netlink-listener.h
nm-ip6-manager.h
libip6_manager_la_CPPFLAGS = \
$(DBUS_CFLAGS) \
$(GLIB_CFLAGS) \
$(HAL_CFLAGS) \
-DG_DISABLE_DEPRECATED
libip6_manager_la_LIBADD = \

View file

@ -21,14 +21,16 @@
#include <errno.h>
#include <netinet/icmp6.h>
#include <netlink/route/addr.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/route.h>
#include "nm-ip6-manager.h"
#include "nm-netlink-listener.h"
#include "nm-netlink-monitor.h"
#include "NetworkManagerUtils.h"
#include "nm-marshal.h"
#include "nm-logging.h"
#include "nm-system.h"
/* Pre-DHCP addrconf timeout, in seconds */
#define NM_IP6_TIMEOUT 10
@ -40,8 +42,8 @@
#define IF_RS_SENT 0x10
typedef struct {
NMNetlinkListener *netlink;
GHashTable *devices_by_iface, *devices_by_index;
NMNetlinkMonitor *monitor;
GHashTable *devices;
struct nl_handle *nlh;
struct nl_cache *addr_cache, *route_cache;
@ -49,41 +51,6 @@ typedef struct {
#define NM_IP6_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_MANAGER, NMIP6ManagerPrivate))
typedef enum {
NM_IP6_DEVICE_UNCONFIGURED,
NM_IP6_DEVICE_GOT_LINK_LOCAL,
NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT,
NM_IP6_DEVICE_GOT_ADDRESS,
NM_IP6_DEVICE_WAITING_FOR_DHCP,
NM_IP6_DEVICE_GOT_DHCP,
NM_IP6_DEVICE_TIMED_OUT
} NMIP6DeviceState;
typedef struct {
struct in6_addr addr;
time_t expires;
} NMIP6RDNSS;
typedef struct {
NMIP6Manager *manager;
char *iface;
int index;
char *accept_ra_path;
gboolean accept_ra_save_valid;
guint32 accept_ra_save;
guint finish_addrconf_id;
guint config_changed_id;
NMIP6DeviceState state;
NMIP6DeviceState target_state;
gboolean addrconf_complete;
GArray *rdnss_servers;
guint rdnss_timeout_id;
} NMIP6Device;
G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT)
enum {
@ -94,89 +61,48 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
static NMIP6Manager *nm_ip6_manager_new (void);
typedef enum {
NM_IP6_DEVICE_UNCONFIGURED,
NM_IP6_DEVICE_GOT_LINK_LOCAL,
NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT,
NM_IP6_DEVICE_GOT_ADDRESS,
NM_IP6_DEVICE_TIMED_OUT
} NMIP6DeviceState;
static void netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer user_data);
typedef struct {
struct in6_addr addr;
time_t expires;
} NMIP6RDNSS;
static void nm_ip6_device_destroy (NMIP6Device *device);
/******************************************************************/
NMIP6Manager *
nm_ip6_manager_get (void)
{
static NMIP6Manager *singleton = NULL;
typedef struct {
NMIP6Manager *manager;
char *iface;
int ifindex;
if (!singleton)
singleton = nm_ip6_manager_new ();
g_assert (singleton);
char *accept_ra_path;
gboolean accept_ra_save_valid;
guint32 accept_ra_save;
return g_object_ref (singleton);
}
char *disable_ip6_path;
gboolean disable_ip6_save_valid;
guint32 disable_ip6_save;
static void
nm_ip6_manager_init (NMIP6Manager *manager)
{
NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
guint finish_addrconf_id;
guint config_changed_id;
priv->devices_by_iface = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
(GDestroyNotify) nm_ip6_device_destroy);
priv->devices_by_index = g_hash_table_new (NULL, NULL);
NMIP6DeviceState state;
NMIP6DeviceState target_state;
gboolean addrconf_complete;
priv->netlink = nm_netlink_listener_get ();
g_signal_connect (priv->netlink, "notification",
G_CALLBACK (netlink_notification), manager);
nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_IPV6_IFADDR, NULL);
nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_IPV6_PREFIX, NULL);
nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_ND_USEROPT, NULL);
GArray *rdnss_servers;
guint rdnss_timeout_id;
priv->nlh = nm_netlink_get_default_handle ();
priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh);
priv->route_cache = rtnl_route_alloc_cache (priv->nlh);
}
guint ip6flags_poll_id;
static void
finalize (GObject *object)
{
NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object);
g_hash_table_destroy (priv->devices_by_iface);
g_hash_table_destroy (priv->devices_by_index);
g_object_unref (priv->netlink);
nl_cache_free (priv->addr_cache);
nl_cache_free (priv->route_cache);
G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object);
}
static void
nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
g_type_class_add_private (manager_class, sizeof (NMIP6ManagerPrivate));
/* virtual methods */
object_class->finalize = finalize;
/* signals */
signals[ADDRCONF_COMPLETE] =
g_signal_new ("addrconf-complete",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete),
NULL, NULL,
_nm_marshal_VOID__STRING_UINT_BOOLEAN,
G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_BOOLEAN);
signals[CONFIG_CHANGED] =
g_signal_new ("config-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed),
NULL, NULL,
_nm_marshal_VOID__STRING_UINT,
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT);
}
guint32 ra_flags;
} NMIP6Device;
static void
nm_ip6_device_destroy (NMIP6Device *device)
@ -189,6 +115,12 @@ nm_ip6_device_destroy (NMIP6Device *device)
device->accept_ra_save ? "1\n" : "0\n");
}
/* reset the saved IPv6 value */
if (device->disable_ip6_save_valid) {
nm_utils_do_sysctl (device->disable_ip6_path,
device->disable_ip6_save ? "1\n" : "0\n");
}
if (device->finish_addrconf_id)
g_source_remove (device->finish_addrconf_id);
if (device->config_changed_id)
@ -198,27 +130,92 @@ nm_ip6_device_destroy (NMIP6Device *device)
g_array_free (device->rdnss_servers, TRUE);
if (device->rdnss_timeout_id)
g_source_remove (device->rdnss_timeout_id);
if (device->ip6flags_poll_id)
g_source_remove (device->ip6flags_poll_id);
g_free (device->accept_ra_path);
g_slice_free (NMIP6Device, device);
}
static NMIP6Manager *
nm_ip6_manager_new (void)
static gboolean
get_proc_sys_net_value (const char *path, const char *iface, guint32 *out_value)
{
NMIP6Manager *manager;
NMIP6ManagerPrivate *priv;
GError *error;
char *contents = NULL;
gboolean success = FALSE;
long int tmp;
manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL);
priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
if (!priv->devices_by_iface || !priv->devices_by_index) {
nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables");
g_object_unref (manager);
manager = NULL;
if (!g_file_get_contents (path, &contents, NULL, &error)) {
nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s",
iface, path,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
} else {
errno = 0;
tmp = strtol (contents, NULL, 10);
if ((errno == 0) && (tmp == 0 || tmp == 1)) {
*out_value = (guint32) tmp;
success = TRUE;
}
g_free (contents);
}
return manager;
return success;
}
static NMIP6Device *
nm_ip6_device_new (NMIP6Manager *manager, int ifindex)
{
NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
NMIP6Device *device;
g_return_val_if_fail (ifindex > 0, NULL);
device = g_slice_new0 (NMIP6Device);
if (!device) {
nm_log_err (LOGD_IP6, "(%d): out of memory creating IP6 addrconf object.",
ifindex);
return NULL;
}
device->ifindex = ifindex;
device->iface = g_strdup (nm_netlink_index_to_iface (ifindex));
if (!device->iface) {
nm_log_err (LOGD_IP6, "(%d): could not find interface name from index.",
ifindex);
goto error;
}
device->manager = manager;
device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
g_hash_table_replace (priv->devices, GINT_TO_POINTER (device->ifindex), device);
/* Grab the original value of "accept_ra" so we can restore it when the
* device is taken down.
*/
device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra",
device->iface);
g_assert (device->accept_ra_path);
device->accept_ra_save_valid = get_proc_sys_net_value (device->accept_ra_path,
device->iface,
&device->accept_ra_save);
/* and the original value of IPv6 enable/disable */
device->disable_ip6_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
device->iface);
g_assert (device->disable_ip6_path);
device->disable_ip6_save_valid = get_proc_sys_net_value (device->disable_ip6_path,
device->iface,
&device->disable_ip6_save);
return device;
error:
nm_ip6_device_destroy (device);
return NULL;
}
static NMIP6Device *
@ -226,13 +223,15 @@ nm_ip6_manager_get_device (NMIP6Manager *manager, int ifindex)
{
NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
return g_hash_table_lookup (priv->devices_by_index,
GINT_TO_POINTER (ifindex));
return g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
}
/******************************************************************/
typedef struct {
NMIP6Device *device;
guint dhcp_opts;
gboolean success;
} CallbackInfo;
static gboolean
@ -241,25 +240,29 @@ finish_addrconf (gpointer user_data)
CallbackInfo *info = user_data;
NMIP6Device *device = info->device;
NMIP6Manager *manager = device->manager;
char *iface_copy;
int ifindex;
device->finish_addrconf_id = 0;
device->addrconf_complete = TRUE;
ifindex = device->ifindex;
if (device->state >= device->target_state) {
/* We're done, stop polling IPv6 flags */
if (device->ip6flags_poll_id) {
g_source_remove (device->ip6flags_poll_id);
device->ip6flags_poll_id = 0;
}
/* And tell listeners that addrconf is complete */
if (info->success) {
g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
device->iface, info->dhcp_opts, TRUE);
ifindex, info->dhcp_opts, TRUE);
} else {
nm_log_info (LOGD_IP6, "(%s): IP6 addrconf timed out or failed.",
device->iface);
device->iface);
iface_copy = g_strdup (device->iface);
nm_ip6_manager_cancel_addrconf (manager, device->iface);
nm_ip6_manager_cancel_addrconf (manager, ifindex);
g_signal_emit (manager, signals[ADDRCONF_COMPLETE], 0,
iface_copy, info->dhcp_opts, FALSE);
g_free (iface_copy);
ifindex, info->dhcp_opts, FALSE);
}
return FALSE;
@ -273,7 +276,7 @@ emit_config_changed (gpointer user_data)
NMIP6Manager *manager = device->manager;
device->config_changed_id = 0;
g_signal_emit (manager, signals[CONFIG_CHANGED], 0, device->iface, info->dhcp_opts);
g_signal_emit (manager, signals[CONFIG_CHANGED], 0, device->ifindex, info->dhcp_opts);
return FALSE;
}
@ -329,14 +332,14 @@ set_rdnss_timeout (NMIP6Device *device)
}
static CallbackInfo *
callback_info_new (NMIP6Device *device, guint dhcp_opts)
callback_info_new (NMIP6Device *device, guint dhcp_opts, gboolean success)
{
CallbackInfo *info;
info = g_malloc0 (sizeof (CallbackInfo));
info->device = device;
info->dhcp_opts = dhcp_opts;
info->success = success;
return info;
}
@ -348,15 +351,14 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
struct rtnl_addr *rtnladdr;
struct nl_addr *nladdr;
struct in6_addr *addr;
struct rtnl_link *link;
guint flags;
CallbackInfo *info;
guint dhcp_opts = IP6_DHCP_OPT_NONE;
for (rtnladdr = (struct rtnl_addr *)nl_cache_get_first (priv->addr_cache);
/* Look for any IPv6 addresses the kernel may have set for the device */
for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache);
rtnladdr;
rtnladdr = (struct rtnl_addr *)nl_cache_get_next ((struct nl_object *)rtnladdr)) {
if (rtnl_addr_get_ifindex (rtnladdr) != device->index)
rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) {
if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
continue;
nladdr = rtnl_addr_get_local (rtnladdr);
@ -373,32 +375,35 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
}
}
/* Note: we don't want to keep a cache of links, because the
* kernel doesn't send notifications when the flags change, so the
* cached rtnl_links would have out-of-date flags.
*/
link = nm_netlink_index_to_rtnl_link (device->index);
flags = rtnl_link_get_flags (link);
rtnl_link_put (link);
/* We only care about router advertisements if we want for a real IPv6 address */
if (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) {
if ( (device->ra_flags & IF_RA_RCVD)
&& (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT))
device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT;
if ((flags & IF_RA_RCVD) && device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT;
if (flags & IF_RA_MANAGED)
dhcp_opts = IP6_DHCP_OPT_MANAGED;
else if (flags & IF_RA_OTHERCONF)
dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
if (device->ra_flags & IF_RA_MANAGED) {
dhcp_opts = IP6_DHCP_OPT_MANAGED;
nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6");
} else if (device->ra_flags & IF_RA_OTHERCONF) {
dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6");
}
}
if (!device->addrconf_complete) {
if (device->state >= device->target_state ||
device->state == NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) {
/* Managed mode (ie DHCP only) short-circuits automatic addrconf, so
* we don't bother waiting for the device's target state to be reached
* when the RA requests managed mode.
*/
if ( (device->state >= device->target_state)
|| (dhcp_opts == IP6_DHCP_OPT_MANAGED)) {
/* device->finish_addrconf_id may currently be a timeout
* rather than an idle, so we remove the existing source.
*/
if (device->finish_addrconf_id)
g_source_remove (device->finish_addrconf_id);
info = callback_info_new (device, dhcp_opts);
info = callback_info_new (device, dhcp_opts, TRUE);
device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
finish_addrconf,
info,
@ -406,7 +411,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
}
} else if (config_changed) {
if (!device->config_changed_id) {
info = callback_info_new (device, dhcp_opts);
info = callback_info_new (device, dhcp_opts, TRUE);
device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
emit_config_changed,
info,
@ -598,8 +603,59 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg)
return NULL;
}
static struct nla_policy link_policy[IFLA_MAX + 1] = {
[IFLA_PROTINFO] = { .type = NLA_NESTED },
};
static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = {
[IFLA_INET6_FLAGS] = { .type = NLA_U32 },
};
static NMIP6Device *
process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
{
struct nlmsghdr *hdr = nlmsg_hdr (msg);
struct ifinfomsg *ifi;
NMIP6Device *device;
struct nlattr *tb[IFLA_MAX + 1];
struct nlattr *pi[IFLA_INET6_MAX + 1];
int err;
ifi = nlmsg_data (hdr);
if (ifi->ifi_family != AF_INET6)
return NULL;
device = nm_ip6_manager_get_device (manager, ifi->ifi_index);
if (!device || device->addrconf_complete)
return NULL;
/* FIXME: we have to do this manually for now since libnl doesn't yet
* support the IFLA_PROTINFO attribute of NEWLINK messages. When it does,
* we can get rid of this function and just grab IFLA_PROTINFO from
* nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
* the PROTINFO.
*/
err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
if (err < 0)
return NULL;
if (!tb[IFLA_PROTINFO])
return NULL;
err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy);
if (err < 0)
return NULL;
if (!pi[IFLA_INET6_FLAGS])
return NULL;
device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
nm_log_dbg (LOGD_IP6, "(%s): got IPv6 flags 0x%X", device->iface, device->ra_flags);
return device;
}
static void
netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer user_data)
netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data)
{
NMIP6Manager *manager = (NMIP6Manager *) user_data;
NMIP6Device *device;
@ -613,22 +669,22 @@ netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer
device = process_addr (manager, msg);
config_changed = TRUE;
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
device = process_route (manager, msg);
config_changed = TRUE;
break;
case RTM_NEWPREFIX:
device = process_prefix (manager, msg);
break;
case RTM_NEWNDUSEROPT:
device = process_nduseropt (manager, msg);
config_changed = TRUE;
break;
case RTM_NEWLINK:
device = process_newlink (manager, msg);
config_changed = TRUE;
break;
default:
return;
}
@ -637,75 +693,9 @@ netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer
nm_ip6_device_sync_from_netlink (device, config_changed);
}
static NMIP6Device *
nm_ip6_device_new (NMIP6Manager *manager, const char *iface)
{
NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
NMIP6Device *device;
GError *error = NULL;
char *contents = NULL;
device = g_slice_new0 (NMIP6Device);
if (!device) {
nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 addrconf object.", iface);
return NULL;
}
device->iface = g_strdup (iface);
if (!device->iface) {
nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 addrconf object "
"property 'iface'.",
iface);
goto error;
}
device->index = nm_netlink_iface_to_index (iface);
device->accept_ra_path = g_strdup_printf ("/proc/sys/net/ipv6/conf/%s/accept_ra", iface);
if (!device->accept_ra_path) {
nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 addrconf object "
"property 'accept_ra_path'.",
iface);
goto error;
}
device->manager = manager;
device->rdnss_servers = g_array_new (FALSE, FALSE, sizeof (NMIP6RDNSS));
g_hash_table_replace (priv->devices_by_iface, device->iface, device);
g_hash_table_replace (priv->devices_by_index, GINT_TO_POINTER (device->index), device);
/* Grab the original value of "accept_ra" so we can restore it when the
* device is taken down.
*/
if (!g_file_get_contents (device->accept_ra_path, &contents, NULL, &error)) {
nm_log_warn (LOGD_IP6, "(%s): error reading %s: (%d) %s",
iface, device->accept_ra_path,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
} else {
long int tmp;
errno = 0;
tmp = strtol (contents, NULL, 10);
if ((errno == 0) && (tmp == 0 || tmp == 1)) {
device->accept_ra_save = (guint32) tmp;
device->accept_ra_save_valid = TRUE;
}
g_free (contents);
}
return device;
error:
nm_ip6_device_destroy (device);
return NULL;
}
void
nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
const char *iface,
int ifindex,
NMSettingIP6Config *s_ip6)
{
NMIP6ManagerPrivate *priv;
@ -713,60 +703,81 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
const char *method = NULL;
g_return_if_fail (NM_IS_IP6_MANAGER (manager));
g_return_if_fail (iface != NULL);
g_return_if_fail (ifindex > 0);
priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
device = nm_ip6_device_new (manager, iface);
device = nm_ip6_device_new (manager, ifindex);
g_return_if_fail (device != NULL);
g_return_if_fail ( strchr (device->iface, '/') == NULL
&& strcmp (device->iface, "all") != 0
&& strcmp (device->iface, "default") != 0);
if (s_ip6)
method = nm_setting_ip6_config_get_method (s_ip6);
if (!method)
method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
/* Establish target state and turn router advertisement acceptance on or off */
if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)
|| !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL))
|| !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
else
nm_utils_do_sysctl (device->accept_ra_path, "0\n");
} else {
device->target_state = NM_IP6_DEVICE_GOT_ADDRESS;
nm_utils_do_sysctl (device->accept_ra_path, "1\n");
}
}
g_return_if_fail (strchr (iface, '/') == NULL &&
strcmp (iface, "all") != 0 &&
strcmp (iface, "default") != 0);
/* Turn router advertisement acceptance on or off... */
nm_utils_do_sysctl (device->accept_ra_path,
device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS ? "1\n" : "0\n");
static gboolean
poll_ip6_flags (gpointer user_data)
{
nm_netlink_monitor_request_ip6_info (NM_NETLINK_MONITOR (user_data), NULL);
return TRUE;
}
void
nm_ip6_manager_begin_addrconf (NMIP6Manager *manager,
const char *iface)
nm_ip6_manager_begin_addrconf (NMIP6Manager *manager, int ifindex)
{
NMIP6ManagerPrivate *priv;
NMIP6Device *device;
CallbackInfo *info;
g_return_if_fail (NM_IS_IP6_MANAGER (manager));
g_return_if_fail (iface != NULL);
g_return_if_fail (ifindex > 0);
priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
device = (NMIP6Device *) g_hash_table_lookup (priv->devices_by_iface, iface);
device = (NMIP6Device *) g_hash_table_lookup (priv->devices, GINT_TO_POINTER (ifindex));
g_return_if_fail (device != NULL);
nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", iface);
nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", device->iface);
device->addrconf_complete = FALSE;
device->ra_flags = 0;
/* Set up a timeout on the transaction to kill it after the timeout */
info = callback_info_new (device, 0);
info = callback_info_new (device, 0, FALSE);
device->finish_addrconf_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
NM_IP6_TIMEOUT,
finish_addrconf,
info,
(GDestroyNotify) g_free);
/* Bounce IPv6 on the interface to ensure the kernel will start looking for
* new RAs; there doesn't seem to be a better way to do this right now.
*/
if (device->target_state >= NM_IP6_DEVICE_GOT_ADDRESS) {
nm_utils_do_sysctl (device->disable_ip6_path, "1\n");
g_usleep (200);
nm_utils_do_sysctl (device->disable_ip6_path, "0\n");
}
device->ip6flags_poll_id = g_timeout_add_seconds (1, poll_ip6_flags, priv->monitor);
/* Kick off the initial IPv6 flags request */
nm_netlink_monitor_request_ip6_info (priv->monitor, NULL);
/* Sync flags, etc, from netlink; this will also notice if the
* device is already fully configured and schedule the
* ADDRCONF_COMPLETE signal in that case.
@ -775,27 +786,23 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager,
}
void
nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager,
const char *iface)
nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager, int ifindex)
{
NMIP6ManagerPrivate *priv;
NMIP6Device *device;
g_return_if_fail (NM_IS_IP6_MANAGER (manager));
g_return_if_fail (iface != NULL);
g_return_if_fail (ifindex > 0);
priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
device = g_hash_table_lookup (priv->devices_by_iface, iface);
if (device) {
g_hash_table_remove (priv->devices_by_index, GINT_TO_POINTER (device->index));
g_hash_table_remove (priv->devices_by_iface, iface);
}
g_hash_table_remove (NM_IP6_MANAGER_GET_PRIVATE (manager)->devices,
GINT_TO_POINTER (ifindex));
}
#define FIRST_ROUTE(m) ((struct rtnl_route *) nl_cache_get_first (m))
#define NEXT_ROUTE(m) ((struct rtnl_route *) nl_cache_get_next ((struct nl_object *) m))
#define FIRST_ADDR(m) ((struct rtnl_addr *) nl_cache_get_first (m))
#define NEXT_ADDR(m) ((struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) m))
NMIP6Config *
nm_ip6_manager_get_ip6_config (NMIP6Manager *manager,
const char *iface)
nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
{
NMIP6ManagerPrivate *priv;
NMIP6Device *device;
@ -807,51 +814,44 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager,
struct rtnl_route *rtnlroute;
struct nl_addr *nldest, *nlgateway;
struct in6_addr *dest, *gateway;
gboolean defgw_set = FALSE;
struct in6_addr defgw;
uint32_t metric;
NMIP6Route *ip6route;
int i;
g_return_val_if_fail (NM_IS_IP6_MANAGER (manager), NULL);
g_return_val_if_fail (iface != NULL, NULL);
g_return_val_if_fail (ifindex > 0, NULL);
priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
device = (NMIP6Device *) g_hash_table_lookup (priv->devices_by_iface, iface);
device = (NMIP6Device *) g_hash_table_lookup (priv->devices,
GINT_TO_POINTER (ifindex));
if (!device) {
nm_log_warn (LOGD_IP6, "(%s): addrconf not started.", iface);
nm_log_warn (LOGD_IP6, "(%d): addrconf not started.", ifindex);
return NULL;
}
config = nm_ip6_config_new ();
if (!config) {
nm_log_err (LOGD_IP6, "(%s): out of memory creating IP6 config object.",
iface);
device->iface);
return NULL;
}
/* Add addresses */
for (rtnladdr = (struct rtnl_addr *)nl_cache_get_first (priv->addr_cache);
rtnladdr;
rtnladdr = (struct rtnl_addr *)nl_cache_get_next ((struct nl_object *)rtnladdr)) {
if (rtnl_addr_get_ifindex (rtnladdr) != device->index)
continue;
nladdr = rtnl_addr_get_local (rtnladdr);
if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
continue;
addr = nl_addr_get_binary_addr (nladdr);
ip6addr = nm_ip6_address_new ();
nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
nm_ip6_address_set_address (ip6addr, addr);
nm_ip6_config_take_address (config, ip6addr);
}
/* Make sure we refill the route and address caches, otherwise we won't get
* up-to-date information here since the netlink route/addr change messages
* may be lagging a bit.
*/
nl_cache_refill (priv->nlh, priv->route_cache);
nl_cache_refill (priv->nlh, priv->addr_cache);
/* Add routes */
for (rtnlroute = (struct rtnl_route *)nl_cache_get_first (priv->route_cache);
rtnlroute;
rtnlroute = (struct rtnl_route *)nl_cache_get_next ((struct nl_object *)rtnlroute)) {
if (rtnl_route_get_oif (rtnlroute) != device->index)
for (rtnlroute = FIRST_ROUTE (priv->route_cache); rtnlroute; rtnlroute = NEXT_ROUTE (rtnlroute)) {
/* Make sure it's an IPv6 route for this device */
if (rtnl_route_get_oif (rtnlroute) != device->ifindex)
continue;
if (rtnl_route_get_family (rtnlroute) != AF_INET6)
continue;
nldest = rtnl_route_get_dst (rtnlroute);
@ -864,6 +864,15 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager,
continue;
gateway = nl_addr_get_binary_addr (nlgateway);
if (rtnl_route_get_dst_len (rtnlroute) == 0) {
/* Default gateway route; don't add to normal routes but to each address */
if (!defgw_set) {
memcpy (&defgw, gateway, sizeof (defgw));
defgw_set = TRUE;
}
continue;
}
ip6route = nm_ip6_route_new ();
nm_ip6_route_set_dest (ip6route, dest);
nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute));
@ -874,6 +883,24 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager,
nm_ip6_config_take_route (config, ip6route);
}
/* Add addresses */
for (rtnladdr = FIRST_ADDR (priv->addr_cache); rtnladdr; rtnladdr = NEXT_ADDR (rtnladdr)) {
if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex)
continue;
nladdr = rtnl_addr_get_local (rtnladdr);
if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6)
continue;
addr = nl_addr_get_binary_addr (nladdr);
ip6addr = nm_ip6_address_new ();
nm_ip6_address_set_prefix (ip6addr, rtnl_addr_get_prefixlen (rtnladdr));
nm_ip6_address_set_address (ip6addr, addr);
nm_ip6_config_take_address (config, ip6addr);
if (defgw_set)
nm_ip6_address_set_gateway (ip6addr, &defgw);
}
/* Add DNS servers */
if (device->rdnss_servers) {
NMIP6RDNSS *rdnss = (NMIP6RDNSS *)(device->rdnss_servers->data);
@ -884,3 +911,104 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager,
return config;
}
/******************************************************************/
static NMIP6Manager *
nm_ip6_manager_new (void)
{
NMIP6Manager *manager;
NMIP6ManagerPrivate *priv;
manager = g_object_new (NM_TYPE_IP6_MANAGER, NULL);
priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
if (!priv->devices) {
nm_log_err (LOGD_IP6, "not enough memory to initialize IP6 manager tables");
g_object_unref (manager);
manager = NULL;
}
return manager;
}
NMIP6Manager *
nm_ip6_manager_get (void)
{
static NMIP6Manager *singleton = NULL;
if (!singleton) {
singleton = nm_ip6_manager_new ();
g_assert (singleton);
} else
g_object_ref (singleton);
return singleton;
}
static void
nm_ip6_manager_init (NMIP6Manager *manager)
{
NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager);
priv->devices = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL,
(GDestroyNotify) nm_ip6_device_destroy);
priv->monitor = nm_netlink_monitor_get ();
nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL);
nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL);
nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL);
nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);
g_signal_connect (priv->monitor, "notification",
G_CALLBACK (netlink_notification), manager);
priv->nlh = nm_netlink_get_default_handle ();
priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh);
priv->route_cache = rtnl_route_alloc_cache (priv->nlh);
}
static void
finalize (GObject *object)
{
NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (object);
g_hash_table_destroy (priv->devices);
g_object_unref (priv->monitor);
nl_cache_free (priv->addr_cache);
nl_cache_free (priv->route_cache);
G_OBJECT_CLASS (nm_ip6_manager_parent_class)->finalize (object);
}
static void
nm_ip6_manager_class_init (NMIP6ManagerClass *manager_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
g_type_class_add_private (manager_class, sizeof (NMIP6ManagerPrivate));
/* virtual methods */
object_class->finalize = finalize;
/* signals */
signals[ADDRCONF_COMPLETE] =
g_signal_new ("addrconf-complete",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMIP6ManagerClass, addrconf_complete),
NULL, NULL,
_nm_marshal_VOID__INT_UINT_BOOLEAN,
G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_BOOLEAN);
signals[CONFIG_CHANGED] =
g_signal_new ("config-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMIP6ManagerClass, config_changed),
NULL, NULL,
_nm_marshal_VOID__INT_UINT,
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT);
}

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2009 Red Hat, Inc.
* Copyright (C) 2009 - 2010 Red Hat, Inc.
*/
#ifndef NM_IP6_MANAGER_H
@ -54,7 +54,7 @@ typedef struct {
* that the initial configuration is complete.
*/
void (*addrconf_complete) (NMIP6Manager *manager,
char *iface,
guint32 ifindex,
guint dhcp_opts,
gboolean success);
@ -63,22 +63,22 @@ typedef struct {
* of the interface has changed.
*/
void (*config_changed) (NMIP6Manager *manager,
char *iface,
guint32 ifindex,
guint dhcp_opts);
} NMIP6ManagerClass;
GType nm_ip6_manager_get_type (void);
NMIP6Manager *nm_ip6_manager_get (void);
void nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
const char *iface,
NMSettingIP6Config *s_ip6);
void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager,
const char *iface);
void nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager,
const char *iface);
NMIP6Manager *nm_ip6_manager_get (void);
void nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
int ifindex,
NMSettingIP6Config *s_ip6);
void nm_ip6_manager_begin_addrconf (NMIP6Manager *manager,
int ifindex);
void nm_ip6_manager_cancel_addrconf (NMIP6Manager *manager,
int ifindex);
NMIP6Config * nm_ip6_manager_get_ip6_config (NMIP6Manager *manager,
const char *iface);
NMIP6Config * nm_ip6_manager_get_ip6_config (NMIP6Manager *manager,
int ifindex);
#endif /* NM_IP6_MANAGER_H */

View file

@ -1,406 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2005 - 2009 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
* Copyright (C) 2005 Ray Strode
*
* Some code borrowed from HAL:
*
* Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
* Copyright (C) 2004 Novell, Inc.
*/
/* FIXME: this should be merged with src/nm-netlink-monitor.c */
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/unistd.h>
#include <unistd.h>
#include <stdio.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "NetworkManager.h"
#include "nm-system.h"
#include "nm-netlink-listener.h"
#include "nm-marshal.h"
#include "nm-netlink.h"
#define NM_NETLINK_LISTENER_EVENT_CONDITIONS \
((GIOCondition) (G_IO_IN | G_IO_PRI))
#define NM_NETLINK_LISTENER_ERROR_CONDITIONS \
((GIOCondition) (G_IO_ERR | G_IO_NVAL))
#define NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS \
((GIOCondition) (G_IO_HUP))
#define NM_NETLINK_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
NM_TYPE_NETLINK_LISTENER, \
NMNetlinkListenerPrivate))
typedef struct {
struct nl_handle *nlh;
struct nl_cb * nlh_cb;
struct nl_cache * nlh_link_cache;
GIOChannel * io_channel;
guint event_id;
guint request_status_id;
} NMNetlinkListenerPrivate;
static gboolean nm_netlink_listener_event_handler (GIOChannel *channel,
GIOCondition io_condition,
gpointer user_data);
static gboolean nm_netlink_listener_error_handler (GIOChannel *channel,
GIOCondition io_condition,
NMNetlinkListener *listener);
static gboolean nm_netlink_listener_disconnect_handler (GIOChannel *channel,
GIOCondition io_condition,
NMNetlinkListener *listener);
static void close_connection (NMNetlinkListener *listener);
enum {
NOTIFICATION = 0,
ERROR,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (NMNetlinkListener, nm_netlink_listener, G_TYPE_OBJECT);
NMNetlinkListener *
nm_netlink_listener_get (void)
{
static NMNetlinkListener *singleton = NULL;
if (!singleton)
singleton = NM_NETLINK_LISTENER (g_object_new (NM_TYPE_NETLINK_LISTENER, NULL));
else
g_object_ref (singleton);
return singleton;
}
static void
nm_netlink_listener_init (NMNetlinkListener *listener)
{
}
static void
finalize (GObject *object)
{
NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (object);
if (priv->request_status_id)
g_source_remove (priv->request_status_id);
if (priv->io_channel)
close_connection (NM_NETLINK_LISTENER (object));
if (priv->nlh) {
nl_handle_destroy (priv->nlh);
priv->nlh = NULL;
}
if (priv->nlh_cb) {
nl_cb_put (priv->nlh_cb);
priv->nlh_cb = NULL;
}
G_OBJECT_CLASS (nm_netlink_listener_parent_class)->finalize (object);
}
static void
nm_netlink_listener_class_init (NMNetlinkListenerClass *listener_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (listener_class);
g_type_class_add_private (listener_class, sizeof (NMNetlinkListenerPrivate));
/* Virtual methods */
object_class->finalize = finalize;
/* Signals */
signals[NOTIFICATION] =
g_signal_new ("notification",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMNetlinkListenerClass, notification),
NULL, NULL, g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
signals[ERROR] =
g_signal_new ("error",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMNetlinkListenerClass, error),
NULL, NULL, _nm_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
}
static int
netlink_event_input (struct nl_msg *msg, void *listener)
{
struct nlmsghdr *hdr = nlmsg_hdr (msg);
if (hdr->nlmsg_pid != 0)
return NL_STOP;
g_signal_emit (listener, signals[NOTIFICATION], 0, msg);
/* Stop processing messages */
return NL_STOP;
}
static gboolean
open_connection (NMNetlinkListener *listener, GError **error)
{
NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
int fd;
GError *channel_error = NULL;
GIOFlags channel_flags;
g_return_val_if_fail (priv->io_channel == NULL, FALSE);
priv->nlh_cb = nl_cb_alloc (NL_CB_DEFAULT);
priv->nlh = nl_handle_alloc_cb (priv->nlh_cb);
if (!priv->nlh) {
g_set_error (error, NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_HANDLE,
_("unable to allocate netlink handle: %s"),
nl_geterror ());
goto error;
}
nl_disable_sequence_check (priv->nlh);
nl_socket_modify_cb (priv->nlh, NL_CB_VALID, NL_CB_CUSTOM, netlink_event_input, listener);
if (nl_connect (priv->nlh, NETLINK_ROUTE) < 0) {
g_set_error (error, NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_NETLINK_CONNECT,
_("unable to connect to netlink: %s"),
nl_geterror ());
goto error;
}
fd = nl_socket_get_fd (priv->nlh);
priv->io_channel = g_io_channel_unix_new (fd);
g_io_channel_set_encoding (priv->io_channel, NULL, &channel_error);
/* Encoding is NULL, so no conversion error can possibly occur */
g_assert (channel_error == NULL);
g_io_channel_set_close_on_unref (priv->io_channel, TRUE);
channel_flags = g_io_channel_get_flags (priv->io_channel);
channel_error = NULL;
g_io_channel_set_flags (priv->io_channel,
channel_flags | G_IO_FLAG_NONBLOCK,
&channel_error);
if (channel_error != NULL) {
g_propagate_error (error, channel_error);
goto error;
}
priv->event_id = g_io_add_watch (priv->io_channel,
(NM_NETLINK_LISTENER_EVENT_CONDITIONS |
NM_NETLINK_LISTENER_ERROR_CONDITIONS |
NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS),
nm_netlink_listener_event_handler,
listener);
return TRUE;
error:
if (priv->io_channel)
close_connection (listener);
if (priv->nlh) {
nl_handle_destroy (priv->nlh);
priv->nlh = NULL;
}
if (priv->nlh_cb) {
nl_cb_put (priv->nlh_cb);
priv->nlh_cb = NULL;
}
return FALSE;
}
static void
close_connection (NMNetlinkListener *listener)
{
NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
g_return_if_fail (priv->io_channel != NULL);
if (priv->event_id) {
g_source_remove (priv->event_id);
priv->event_id = 0;
}
g_io_channel_shutdown (priv->io_channel,
TRUE /* flush pending data */,
NULL);
g_io_channel_unref (priv->io_channel);
priv->io_channel = NULL;
}
GQuark
nm_netlink_listener_error_quark (void)
{
static GQuark error_quark = 0;
if (error_quark == 0)
error_quark = g_quark_from_static_string ("nm-netlink-listener-error-quark");
return error_quark;
}
gboolean
nm_netlink_listener_subscribe (NMNetlinkListener *listener,
int group,
GError **error)
{
NMNetlinkListenerPrivate *priv;
g_return_val_if_fail (NM_IS_NETLINK_LISTENER (listener), FALSE);
priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
if (!priv->nlh) {
if (!open_connection (listener, error))
return FALSE;
}
if (nl_socket_add_membership (priv->nlh, group) < 0) {
g_set_error (error, NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_NETLINK_JOIN_GROUP,
_("unable to join netlink group: %s"),
nl_geterror ());
return FALSE;
}
return TRUE;
}
void
nm_netlink_listener_unsubscribe (NMNetlinkListener *listener, int group)
{
NMNetlinkListenerPrivate *priv;
g_return_if_fail (NM_IS_NETLINK_LISTENER (listener));
priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
g_return_if_fail (priv->nlh != NULL);
nl_socket_drop_membership (priv->nlh, group);
}
static gboolean
nm_netlink_listener_event_handler (GIOChannel *channel,
GIOCondition io_condition,
gpointer user_data)
{
NMNetlinkListener *listener = (NMNetlinkListener *) user_data;
NMNetlinkListenerPrivate *priv;
GError *error = NULL;
g_return_val_if_fail (NM_IS_NETLINK_LISTENER (listener), TRUE);
priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
g_return_val_if_fail (priv->event_id > 0, TRUE);
if (io_condition & NM_NETLINK_LISTENER_ERROR_CONDITIONS)
return nm_netlink_listener_error_handler (channel, io_condition, listener);
else if (io_condition & NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS)
return nm_netlink_listener_disconnect_handler (channel, io_condition, listener);
g_return_val_if_fail (!(io_condition & ~(NM_NETLINK_LISTENER_EVENT_CONDITIONS)), FALSE);
if (nl_recvmsgs_default (priv->nlh) < 0) {
error = g_error_new (NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_PROCESSING_MESSAGE,
_("error processing netlink message: %s"),
nl_geterror ());
g_signal_emit (G_OBJECT (listener),
signals[ERROR],
0, error);
g_error_free (error);
}
return TRUE;
}
static gboolean
nm_netlink_listener_error_handler (GIOChannel *channel,
GIOCondition io_condition,
NMNetlinkListener *listener)
{
GError *socket_error;
const char *err_msg;
int err_code;
socklen_t err_len;
g_return_val_if_fail (io_condition & NM_NETLINK_LISTENER_ERROR_CONDITIONS, FALSE);
err_code = 0;
err_len = sizeof (err_code);
if (getsockopt (g_io_channel_unix_get_fd (channel),
SOL_SOCKET, SO_ERROR, (void *) &err_code, &err_len))
err_msg = strerror (err_code);
else
err_msg = _("error occurred while waiting for data on socket");
socket_error = g_error_new (NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_WAITING_FOR_SOCKET_DATA,
"%s",
err_msg);
g_signal_emit (G_OBJECT (listener),
signals[ERROR],
0, socket_error);
g_error_free (socket_error);
return TRUE;
}
static gboolean
nm_netlink_listener_disconnect_handler (GIOChannel *channel,
GIOCondition io_condition,
NMNetlinkListener *listener)
{
g_return_val_if_fail (!(io_condition & ~(NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS)), FALSE);
return FALSE;
}

View file

@ -1,78 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Netlink socket listener
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2005 - 2009 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
* Copyright (C) 2005 Ray Strode
*/
#ifndef NM_NETLINK_LISTENER_H
#define NM_NETLINK_LISTENER_H
#include <glib.h>
#include <glib-object.h>
#include "nm-netlink.h"
G_BEGIN_DECLS
#define NM_TYPE_NETLINK_LISTENER (nm_netlink_listener_get_type ())
#define NM_NETLINK_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETLINK_LISTENER, NMNetlinkListener))
#define NM_NETLINK_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NETLINK_LISTENER, NMNetlinkListenerClass))
#define NM_IS_NETLINK_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETLINK_LISTENER))
#define NM_IS_NETLINK_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_NETLINK_LISTENER))
#define NM_NETLINK_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_NETLINK_LISTENER, NMNetlinkListenerClass))
#define NM_NETLINK_LISTENER_ERROR (nm_netlink_listener_error_quark ())
typedef enum {
NM_NETLINK_LISTENER_ERROR_GENERIC = 0,
NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_HANDLE,
NM_NETLINK_LISTENER_ERROR_NETLINK_CONNECT,
NM_NETLINK_LISTENER_ERROR_NETLINK_JOIN_GROUP,
NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_LINK_CACHE,
NM_NETLINK_LISTENER_ERROR_PROCESSING_MESSAGE,
NM_NETLINK_LISTENER_ERROR_BAD_ALLOC,
NM_NETLINK_LISTENER_ERROR_WAITING_FOR_SOCKET_DATA,
NM_NETLINK_LISTENER_ERROR_LINK_CACHE_UPDATE
} NMNetlinkListenerError;
typedef struct {
GObject parent;
} NMNetlinkListener;
typedef struct {
GObjectClass parent_class;
/* Signals */
void (*notification) (NMNetlinkListener *listener, struct nl_msg *msg);
void (*error) (NMNetlinkListener *listener, GError *error);
} NMNetlinkListenerClass;
GType nm_netlink_listener_get_type (void) G_GNUC_CONST;
GQuark nm_netlink_listener_error_quark (void) G_GNUC_CONST;
NMNetlinkListener *nm_netlink_listener_get (void);
gboolean nm_netlink_listener_subscribe (NMNetlinkListener *listener,
int group,
GError **error);
void nm_netlink_listener_unsubscribe (NMNetlinkListener *listener,
int group);
G_END_DECLS
#endif /* NM_NETLINK_LISTENER_H */

View file

@ -10,5 +10,6 @@ libnm_logging_la_CPPFLAGS = \
-DG_DISABLE_DEPRECATED
libnm_logging_la_LIBADD = \
-ldl \
$(GLIB_LIBS)

View file

@ -38,6 +38,7 @@
#include "nm-named-manager.h"
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
#include "nm-logging.h"
#include "nm-system.h"
#include "NetworkManagerUtils.h"
@ -60,8 +61,10 @@ G_DEFINE_TYPE(NMNamedManager, nm_named_manager, G_TYPE_OBJECT)
struct NMNamedManagerPrivate {
NMIP4Config *vpn_config;
NMIP4Config *device_config;
NMIP4Config *ip4_vpn_config;
NMIP4Config *ip4_device_config;
NMIP6Config *ip6_vpn_config;
NMIP6Config *ip6_device_config;
GSList *configs;
};
@ -513,25 +516,33 @@ rewrite_resolv_conf (NMNamedManager *mgr, const char *iface, GError **error)
rc.domain = NULL;
rc.searches = g_ptr_array_new ();
if (priv->vpn_config)
merge_one_ip4_config (&rc, priv->vpn_config);
if (priv->ip4_vpn_config)
merge_one_ip4_config (&rc, priv->ip4_vpn_config);
if (priv->ip4_device_config)
merge_one_ip4_config (&rc, priv->ip4_device_config);
if (priv->device_config)
merge_one_ip4_config (&rc, priv->device_config);
if (priv->ip6_vpn_config)
merge_one_ip6_config (&rc, priv->ip6_vpn_config);
if (priv->ip6_device_config)
merge_one_ip6_config (&rc, priv->ip6_device_config);
for (iter = priv->configs; iter; iter = g_slist_next (iter)) {
if ( (iter->data == priv->ip4_vpn_config)
|| (iter->data == priv->ip4_device_config)
|| (iter->data == priv->ip6_vpn_config)
|| (iter->data == priv->ip6_device_config))
continue;
if (NM_IS_IP4_CONFIG (iter->data)) {
NMIP4Config *config = NM_IP4_CONFIG (iter->data);
if ((config == priv->vpn_config) || (config == priv->device_config))
continue;
merge_one_ip4_config (&rc, config);
} else {
} else if (NM_IS_IP6_CONFIG (iter->data)) {
NMIP6Config *config = NM_IP6_CONFIG (iter->data);
merge_one_ip6_config (&rc, config);
}
} else
g_assert_not_reached ();
}
domain = rc.domain;
@ -598,10 +609,10 @@ nm_named_manager_add_ip4_config (NMNamedManager *mgr,
switch (cfg_type) {
case NM_NAMED_IP_CONFIG_TYPE_VPN:
priv->vpn_config = config;
priv->ip4_vpn_config = config;
break;
case NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE:
priv->device_config = config;
priv->ip4_device_config = config;
break;
default:
break;
@ -639,11 +650,10 @@ nm_named_manager_remove_ip4_config (NMNamedManager *mgr,
priv->configs = g_slist_remove (priv->configs, config);
if (config == priv->vpn_config)
priv->vpn_config = NULL;
if (config == priv->device_config)
priv->device_config = NULL;
if (config == priv->ip4_vpn_config)
priv->ip4_vpn_config = NULL;
if (config == priv->ip4_device_config)
priv->ip4_device_config = NULL;
g_object_unref (config);
@ -669,10 +679,21 @@ nm_named_manager_add_ip6_config (NMNamedManager *mgr,
g_return_val_if_fail (iface != NULL, FALSE);
g_return_val_if_fail (config != NULL, FALSE);
g_return_val_if_fail (cfg_type == NM_NAMED_IP_CONFIG_TYPE_DEFAULT, FALSE);
priv = NM_NAMED_MANAGER_GET_PRIVATE (mgr);
switch (cfg_type) {
case NM_NAMED_IP_CONFIG_TYPE_VPN:
/* FIXME: not quite yet... */
g_return_val_if_fail (cfg_type != NM_NAMED_IP_CONFIG_TYPE_VPN, FALSE);
priv->ip6_vpn_config = config;
break;
case NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE:
priv->ip6_device_config = config;
break;
default:
break;
}
/* Don't allow the same zone added twice */
if (!g_slist_find (priv->configs, config))
priv->configs = g_slist_append (priv->configs, g_object_ref (config));
@ -705,6 +726,11 @@ nm_named_manager_remove_ip6_config (NMNamedManager *mgr,
priv->configs = g_slist_remove (priv->configs, config);
if (config == priv->ip6_vpn_config)
priv->ip6_vpn_config = NULL;
if (config == priv->ip6_device_config)
priv->ip6_device_config = NULL;
g_object_unref (config);
if (!rewrite_resolv_conf (mgr, iface, &error)) {

View file

@ -72,6 +72,7 @@ typedef struct {
NMActiveConnectionState state;
gboolean is_default;
gboolean is_default6;
gboolean shared;
GSList *share_rules;
@ -88,6 +89,7 @@ enum {
PROP_DEVICES,
PROP_STATE,
PROP_DEFAULT,
PROP_DEFAULT6,
PROP_VPN,
LAST_PROP
@ -104,7 +106,7 @@ device_state_changed (NMDevice *device,
NMActRequest *self = NM_ACT_REQUEST (user_data);
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
NMActiveConnectionState new_ac_state;
gboolean new_default = FALSE;
gboolean new_default = FALSE, new_default6 = FALSE;
/* Set NMActiveConnection state based on the device's state */
switch (new_state) {
@ -117,6 +119,7 @@ device_state_changed (NMDevice *device,
case NM_DEVICE_STATE_ACTIVATED:
new_ac_state = NM_ACTIVE_CONNECTION_STATE_ACTIVATED;
new_default = priv->is_default;
new_default6 = priv->is_default6;
break;
default:
new_ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
@ -132,6 +135,11 @@ device_state_changed (NMDevice *device,
priv->is_default = new_default;
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT);
}
if (new_default6 != priv->is_default6) {
priv->is_default6 = new_default6;
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEFAULT6);
}
}
NMActRequest *
@ -271,6 +279,9 @@ get_property (GObject *object, guint prop_id,
case PROP_DEFAULT:
g_value_set_boolean (value, priv->is_default);
break;
case PROP_DEFAULT6:
g_value_set_boolean (value, priv->is_default6);
break;
case PROP_VPN:
g_value_set_boolean (value, FALSE);
break;
@ -334,7 +345,14 @@ nm_act_request_class_init (NMActRequestClass *req_class)
(object_class, PROP_DEFAULT,
g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT,
"Default",
"Is the default active connection",
"Is the default IPv4 active connection",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_DEFAULT6,
g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6,
"Default6",
"Is the default IPv6 active connection",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property
@ -548,6 +566,29 @@ nm_act_request_get_default (NMActRequest *req)
return NM_ACT_REQUEST_GET_PRIVATE (req)->is_default;
}
void
nm_act_request_set_default6 (NMActRequest *req, gboolean is_default6)
{
NMActRequestPrivate *priv;
g_return_if_fail (NM_IS_ACT_REQUEST (req));
priv = NM_ACT_REQUEST_GET_PRIVATE (req);
if (priv->is_default6 == is_default6)
return;
priv->is_default6 = is_default6;
g_object_notify (G_OBJECT (req), NM_ACTIVE_CONNECTION_DEFAULT6);
}
gboolean
nm_act_request_get_default6 (NMActRequest *req)
{
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
return NM_ACT_REQUEST_GET_PRIVATE (req)->is_default6;
}
static void
share_child_setup (gpointer user_data G_GNUC_UNUSED)
{

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2005 - 2008 Red Hat, Inc.
* (C) Copyright 2005 - 2010 Red Hat, Inc.
*/
#ifndef NM_ACTIVATION_REQUEST_H
@ -76,6 +76,10 @@ void nm_act_request_set_default (NMActRequest *req, gboolean is_default
gboolean nm_act_request_get_default (NMActRequest *req);
void nm_act_request_set_default6 (NMActRequest *req, gboolean is_default6);
gboolean nm_act_request_get_default6 (NMActRequest *req);
gboolean nm_act_request_get_shared (NMActRequest *req);
void nm_act_request_set_shared (NMActRequest *req, gboolean shared);

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2008 Red Hat, Inc.
* Copyright (C) 2008 - 2010 Red Hat, Inc.
*/
#ifndef NM_ACTIVE_CONNECTION_H
@ -30,6 +30,7 @@
#define NM_ACTIVE_CONNECTION_DEVICES "devices"
#define NM_ACTIVE_CONNECTION_STATE "state"
#define NM_ACTIVE_CONNECTION_DEFAULT "default"
#define NM_ACTIVE_CONNECTION_DEFAULT6 "default6"
#define NM_ACTIVE_CONNECTION_VPN "vpn"
char *nm_active_connection_get_next_object_path (void);

View file

@ -34,6 +34,8 @@
#include <linux/if.h>
#include <errno.h>
#include <netlink/route/addr.h>
#include "nm-glib-compat.h"
#include "nm-device-ethernet.h"
#include "nm-device-interface.h"
@ -43,7 +45,6 @@
#include "nm-supplicant-manager.h"
#include "nm-supplicant-interface.h"
#include "nm-supplicant-config.h"
#include "nm-netlink.h"
#include "nm-netlink-monitor.h"
#include "nm-system.h"
#include "nm-setting-connection.h"
@ -105,7 +106,6 @@ typedef struct {
struct ether_addr hw_addr;
gboolean carrier;
guint32 ifindex;
NMNetlinkMonitor * monitor;
gulong link_connected_id;
@ -133,7 +133,6 @@ enum {
PROP_HW_ADDRESS,
PROP_SPEED,
PROP_CARRIER,
PROP_IFINDEX,
LAST_PROP
};
@ -246,11 +245,10 @@ carrier_on (NMNetlinkMonitor *monitor,
{
NMDevice *device = NM_DEVICE (user_data);
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
guint32 caps;
/* Make sure signal is for us */
if (idx == priv->ifindex) {
if (idx == nm_device_get_ifindex (device)) {
/* Ignore spurious netlink messages */
caps = nm_device_get_capabilities (device);
if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT))
@ -267,11 +265,10 @@ carrier_off (NMNetlinkMonitor *monitor,
{
NMDevice *device = NM_DEVICE (user_data);
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
guint32 caps;
/* Make sure signal is for us */
if (idx == priv->ifindex) {
if (idx == nm_device_get_ifindex (device)) {
NMDeviceState state;
gboolean defer = FALSE;
@ -312,7 +309,8 @@ constructor (GType type,
priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d",
nm_device_get_iface (NM_DEVICE (self)), priv->ifindex);
nm_device_get_iface (NM_DEVICE (self)),
nm_device_get_ifindex (NM_DEVICE (self)));
caps = nm_device_get_capabilities (self);
if (caps & NM_DEVICE_CAP_CARRIER_DETECT) {
@ -331,7 +329,7 @@ constructor (GType type,
/* Get initial link state */
if (!nm_netlink_monitor_get_flags_sync (priv->monitor,
priv->ifindex,
nm_device_get_ifindex (NM_DEVICE (self)),
&ifflags,
&error)) {
nm_log_warn (LOGD_HW | LOGD_ETHER,
@ -426,8 +424,7 @@ real_hw_take_down (NMDevice *dev)
NMDevice *
nm_device_ethernet_new (const char *udi,
const char *iface,
const char *driver,
guint32 ifindex)
const char *driver)
{
g_return_val_if_fail (udi != NULL, NULL);
g_return_val_if_fail (iface != NULL, NULL);
@ -437,7 +434,6 @@ nm_device_ethernet_new (const char *udi,
NM_DEVICE_INTERFACE_UDI, udi,
NM_DEVICE_INTERFACE_IFACE, iface,
NM_DEVICE_INTERFACE_DRIVER, driver,
NM_DEVICE_ETHERNET_IFINDEX, ifindex,
NM_DEVICE_INTERFACE_TYPE_DESC, "Ethernet",
NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
NULL);
@ -459,14 +455,6 @@ nm_device_ethernet_get_address (NMDeviceEthernet *self, struct ether_addr *addr)
memcpy (addr, &(NM_DEVICE_ETHERNET_GET_PRIVATE (self)->hw_addr), sizeof (struct ether_addr));
}
guint32
nm_device_ethernet_get_ifindex (NMDeviceEthernet *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return NM_DEVICE_ETHERNET_GET_PRIVATE (self)->ifindex;
}
/* Returns speed in Mb/s */
static guint32
nm_device_ethernet_get_speed (NMDeviceEthernet *self)
@ -1618,7 +1606,7 @@ ip4_match_config (NMDevice *self, NMConnection *connection)
int ifindex;
AddrData check_data;
ifindex = nm_device_ethernet_get_ifindex (NM_DEVICE_ETHERNET (self));
ifindex = nm_device_get_ifindex (self);
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
@ -1790,9 +1778,6 @@ get_property (GObject *object, guint prop_id,
case PROP_CARRIER:
g_value_set_boolean (value, priv->carrier);
break;
case PROP_IFINDEX:
g_value_set_uint (value, priv->ifindex);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1803,13 +1788,7 @@ static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (object);
switch (prop_id) {
case PROP_IFINDEX:
/* construct-only */
priv->ifindex = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1876,14 +1855,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
FALSE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_IFINDEX,
g_param_spec_uint (NM_DEVICE_ETHERNET_IFINDEX,
"Ifindex",
"Interface index",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
/* Signals */
signals[PROPERTIES_CHANGED] =
nm_properties_changed_signal_new (object_class,

View file

@ -39,7 +39,6 @@ G_BEGIN_DECLS
#define NM_DEVICE_ETHERNET_HW_ADDRESS "hw-address"
#define NM_DEVICE_ETHERNET_SPEED "speed"
#define NM_DEVICE_ETHERNET_CARRIER "carrier"
#define NM_DEVICE_ETHERNET_IFINDEX "ifindex"
typedef struct {
NMDevice parent;
@ -58,14 +57,11 @@ GType nm_device_ethernet_get_type (void);
NMDevice *nm_device_ethernet_new (const char *udi,
const char *iface,
const char *driver,
guint32 ifindex);
const char *driver);
void nm_device_ethernet_get_address (NMDeviceEthernet *dev,
struct ether_addr *addr);
guint32 nm_device_ethernet_get_ifindex (NMDeviceEthernet *dev);
G_END_DECLS
#endif /* NM_DEVICE_ETHERNET_H */

View file

@ -16,7 +16,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2008 Novell, Inc.
* Copyright (C) 2007 - 2008 Red Hat, Inc.
* Copyright (C) 2007 - 2010 Red Hat, Inc.
*/
#include "nm-marshal.h"
@ -186,6 +186,14 @@ nm_device_interface_init (gpointer g_iface)
RFKILL_TYPE_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
g_object_interface_install_property
(g_iface,
g_param_spec_int (NM_DEVICE_INTERFACE_IFINDEX,
"Ifindex",
"Ifindex",
0, G_MAXINT, 0,
G_PARAM_READABLE | NM_PROPERTY_PARAM_NO_EXPORT));
/* Signals */
g_signal_new ("state-changed",
iface_type,

View file

@ -57,8 +57,9 @@ typedef enum
#define NM_DEVICE_INTERFACE_STATE "state"
#define NM_DEVICE_INTERFACE_DEVICE_TYPE "device-type" /* ugh */
#define NM_DEVICE_INTERFACE_MANAGED "managed"
#define NM_DEVICE_INTERFACE_TYPE_DESC "type-desc" /* Internal only */
#define NM_DEVICE_INTERFACE_TYPE_DESC "type-desc" /* Internal only */
#define NM_DEVICE_INTERFACE_RFKILL_TYPE "rfkill-type" /* Internal only */
#define NM_DEVICE_INTERFACE_IFINDEX "ifindex" /* Internal only */
typedef enum {
NM_DEVICE_INTERFACE_PROP_FIRST = 0x1000,
@ -77,6 +78,7 @@ typedef enum {
NM_DEVICE_INTERFACE_PROP_MANAGED,
NM_DEVICE_INTERFACE_PROP_TYPE_DESC,
NM_DEVICE_INTERFACE_PROP_RFKILL_TYPE,
NM_DEVICE_INTERFACE_PROP_IFINDEX,
} NMDeviceInterfaceProp;

View file

@ -69,7 +69,6 @@ enum {
PROP_HW_ADDRESS,
PROP_COMPANION,
PROP_ACTIVE_CHANNEL,
PROP_IFINDEX,
LAST_PROP
};
@ -98,7 +97,6 @@ struct _NMDeviceOlpcMeshPrivate
gboolean dispose_has_run;
struct ether_addr hw_addr;
guint32 ifindex;
GByteArray * ssid;
@ -263,7 +261,8 @@ constructor (GType type,
priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d",
nm_device_get_iface (NM_DEVICE (self)), priv->ifindex);
nm_device_get_iface (NM_DEVICE (self)),
nm_device_get_ifindex (NM_DEVICE (self)));
iface = nm_device_get_iface (NM_DEVICE (self));
fd = socket (PF_INET, SOCK_DGRAM, 0);
@ -539,15 +538,6 @@ nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self, const GByteArray * ssid)
close (sk);
}
guint32
nm_device_olpc_mesh_get_ifindex (NMDeviceOlpcMesh *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->ifindex;
}
/****************************************************************************/
static void
@ -701,9 +691,6 @@ get_property (GObject *object, guint prop_id,
case PROP_ACTIVE_CHANNEL:
g_value_set_uint (value, nm_device_olpc_mesh_get_channel (device));
break;
case PROP_IFINDEX:
g_value_set_uint (value, nm_device_olpc_mesh_get_ifindex (device));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -714,13 +701,7 @@ static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (object);
switch (prop_id) {
case PROP_IFINDEX:
/* construct-only */
priv->ifindex = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -780,13 +761,6 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass)
0, G_MAXUINT32, 0,
G_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_IFINDEX,
g_param_spec_uint (NM_DEVICE_OLPC_MESH_IFINDEX,
"Ifindex",
"Interface index",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
signals[PROPERTIES_CHANGED] =
nm_properties_changed_signal_new (object_class,
G_STRUCT_OFFSET (NMDeviceOlpcMeshClass, properties_changed));
@ -986,8 +960,7 @@ state_changed_cb (NMDevice *device, NMDeviceState state, gpointer user_data)
NMDevice *
nm_device_olpc_mesh_new (const char *udi,
const char *iface,
const char *driver,
guint32 ifindex)
const char *driver)
{
GObject *obj;
@ -999,7 +972,6 @@ nm_device_olpc_mesh_new (const char *udi,
NM_DEVICE_INTERFACE_UDI, udi,
NM_DEVICE_INTERFACE_IFACE, iface,
NM_DEVICE_INTERFACE_DRIVER, driver,
NM_DEVICE_OLPC_MESH_IFINDEX, ifindex,
NM_DEVICE_INTERFACE_TYPE_DESC, "802.11 OLPC Mesh",
NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_OLPC_MESH,
NULL);

View file

@ -46,7 +46,6 @@ G_BEGIN_DECLS
#define NM_DEVICE_OLPC_MESH_COMPANION "companion"
#define NM_DEVICE_OLPC_MESH_BITRATE "bitrate"
#define NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL "active-channel"
#define NM_DEVICE_OLPC_MESH_IFINDEX "ifindex"
#ifndef NM_DEVICE_OLPC_MESH_DEFINED
#define NM_DEVICE_OLPC_MESH_DEFINED
@ -75,10 +74,7 @@ GType nm_device_olpc_mesh_get_type (void);
NMDevice *nm_device_olpc_mesh_new (const char *udi,
const char *iface,
const char *driver,
guint32 ifindex);
guint32 nm_device_olpc_mesh_get_ifindex (NMDeviceOlpcMesh *self);
const char *driver);
G_END_DECLS

View file

@ -82,7 +82,6 @@ enum {
PROP_BITRATE,
PROP_ACTIVE_ACCESS_POINT,
PROP_CAPABILITIES,
PROP_IFINDEX,
PROP_SCANNING,
PROP_IPW_RFKILL_STATE,
@ -144,7 +143,6 @@ struct _NMDeviceWifiPrivate {
gboolean disposed;
struct ether_addr hw_addr;
guint32 ifindex;
/* Legacy rfkill for ipw2x00; will be fixed with 2.6.33 kernel */
char * ipw_rfkill_path;
@ -579,7 +577,8 @@ constructor (GType type,
priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
nm_log_dbg (LOGD_HW | LOGD_WIFI, "(%s): kernel ifindex %d",
nm_device_get_iface (NM_DEVICE (self)), priv->ifindex);
nm_device_get_iface (NM_DEVICE (self)),
nm_device_get_ifindex (NM_DEVICE (self)));
memset (&range, 0, sizeof (struct iw_range));
success = wireless_get_range (NM_DEVICE_WIFI (object), &range, &response_len);
@ -3462,14 +3461,6 @@ device_state_changed (NMDevice *device,
remove_all_aps (self);
}
guint32
nm_device_wifi_get_ifindex (NMDeviceWifi *self)
{
g_return_val_if_fail (self != NULL, FALSE);
return NM_DEVICE_WIFI_GET_PRIVATE (self)->ifindex;
}
NMAccessPoint *
nm_device_wifi_get_activation_ap (NMDeviceWifi *self)
{
@ -3563,8 +3554,7 @@ real_set_enabled (NMDeviceInterface *device, gboolean enabled)
NMDevice *
nm_device_wifi_new (const char *udi,
const char *iface,
const char *driver,
guint32 ifindex)
const char *driver)
{
g_return_val_if_fail (udi != NULL, NULL);
g_return_val_if_fail (iface != NULL, NULL);
@ -3574,7 +3564,6 @@ nm_device_wifi_new (const char *udi,
NM_DEVICE_INTERFACE_UDI, udi,
NM_DEVICE_INTERFACE_IFACE, iface,
NM_DEVICE_INTERFACE_DRIVER, driver,
NM_DEVICE_WIFI_IFINDEX, ifindex,
NM_DEVICE_INTERFACE_TYPE_DESC, "802.11 WiFi",
NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_WIFI,
NM_DEVICE_INTERFACE_RFKILL_TYPE, RFKILL_TYPE_WLAN,
@ -3675,9 +3664,6 @@ get_property (GObject *object, guint prop_id,
else
g_value_set_boxed (value, "/");
break;
case PROP_IFINDEX:
g_value_set_uint (value, nm_device_wifi_get_ifindex (device));
break;
case PROP_SCANNING:
g_value_set_boolean (value, nm_supplicant_interface_get_scanning (priv->supplicant.iface));
break;
@ -3697,10 +3683,6 @@ set_property (GObject *object, guint prop_id,
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (object);
switch (prop_id) {
case PROP_IFINDEX:
/* construct-only */
priv->ifindex = g_value_get_uint (value);
break;
case PROP_IPW_RFKILL_STATE:
/* construct only */
priv->ipw_rfkill_state = g_value_get_uint (value);
@ -3788,13 +3770,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
0, G_MAXUINT32, NM_WIFI_DEVICE_CAP_NONE,
G_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_IFINDEX,
g_param_spec_uint (NM_DEVICE_WIFI_IFINDEX,
"Ifindex",
"Interface index",
0, G_MAXUINT32, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
g_object_class_install_property (object_class, PROP_SCANNING,
g_param_spec_boolean (NM_DEVICE_WIFI_SCANNING,
"Scanning",

View file

@ -47,7 +47,6 @@ G_BEGIN_DECLS
#define NM_DEVICE_WIFI_BITRATE "bitrate"
#define NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT "active-access-point"
#define NM_DEVICE_WIFI_CAPABILITIES "wireless-capabilities"
#define NM_DEVICE_WIFI_IFINDEX "ifindex"
#define NM_DEVICE_WIFI_SCANNING "scanning"
#define NM_DEVICE_WIFI_IPW_RFKILL_STATE "ipw-rfkill-state"
@ -84,8 +83,7 @@ GType nm_device_wifi_get_type (void);
NMDevice *nm_device_wifi_new (const char *udi,
const char *iface,
const char *driver,
guint32 ifindex);
const char *driver);
void nm_device_wifi_get_address (NMDeviceWifi *dev,
struct ether_addr *addr);
@ -102,8 +100,6 @@ NM80211Mode nm_device_wifi_get_mode (NMDeviceWifi *self);
NMAccessPoint * nm_device_wifi_get_activation_ap (NMDeviceWifi *self);
guint32 nm_device_wifi_get_ifindex (NMDeviceWifi *self);
RfKillState nm_device_wifi_get_ipw_rfkill_state (NMDeviceWifi *self);
G_END_DECLS

View file

@ -45,7 +45,7 @@
#include "nm-named-manager.h"
#include "nm-utils.h"
#include "nm-logging.h"
#include "nm-netlink.h"
#include "nm-netlink-monitor.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
#include "nm-setting-connection.h"
@ -83,7 +83,9 @@ typedef struct {
char * udi;
char * path;
char * iface; /* may change, could be renamed by user */
int ifindex;
char * ip_iface;
int ip_ifindex;
NMDeviceType type;
char * type_desc;
guint32 capabilities;
@ -304,6 +306,13 @@ nm_device_get_iface (NMDevice *self)
return NM_DEVICE_GET_PRIVATE (self)->iface;
}
int
nm_device_get_ifindex (NMDevice *self)
{
g_return_val_if_fail (self != NULL, 0);
return NM_DEVICE_GET_PRIVATE (self)->ifindex;
}
const char *
nm_device_get_ip_iface (NMDevice *self)
@ -317,14 +326,36 @@ nm_device_get_ip_iface (NMDevice *self)
return priv->ip_iface ? priv->ip_iface : priv->iface;
}
int
nm_device_get_ip_ifindex (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_val_if_fail (self != NULL, 0);
priv = NM_DEVICE_GET_PRIVATE (self);
/* If it's not set, default to iface */
return priv->ip_iface ? priv->ip_ifindex : priv->ifindex;
}
void
nm_device_set_ip_iface (NMDevice *self, const char *iface)
{
NMDevicePrivate *priv;
g_return_if_fail (NM_IS_DEVICE (self));
g_free (NM_DEVICE_GET_PRIVATE (self)->ip_iface);
NM_DEVICE_GET_PRIVATE (self)->ip_iface = iface ? g_strdup (iface) : NULL;
priv = NM_DEVICE_GET_PRIVATE (self);
g_free (priv->ip_iface);
priv->ip_ifindex = 0;
priv->ip_iface = g_strdup (iface);
if (priv->ip_iface) {
priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
if (!priv->ip_ifindex) {
nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", iface);
}
}
}
@ -545,7 +576,7 @@ activation_source_schedule (NMDevice *self, GSourceFunc func, int family)
static void
ip6_addrconf_complete (NMIP6Manager *ip6_manager,
const char *iface,
int ifindex,
guint dhcp_opts,
gboolean success,
gpointer user_data)
@ -558,7 +589,7 @@ ip6_addrconf_complete (NMIP6Manager *ip6_manager,
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
NMDeviceState state;
if (strcmp (nm_device_get_ip_iface (self), iface) != 0)
if (ifindex != nm_device_get_ip_ifindex (self))
return;
req = nm_device_get_act_request (self);
if (!req)
@ -614,13 +645,13 @@ ip6_addrconf_complete (NMIP6Manager *ip6_manager,
static void
ip6_config_changed (NMIP6Manager *ip6_manager,
const char *iface,
int ifindex,
guint dhcp_opts,
gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
if (strcmp (nm_device_get_ip_iface (self), iface) != 0)
if (ifindex != nm_device_get_ip_ifindex (self))
return;
if (!nm_device_get_act_request (self))
return;
@ -675,7 +706,9 @@ addrconf6_setup (NMDevice *self)
ip_iface = nm_device_get_ip_iface (self);
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
nm_ip6_manager_prepare_interface (priv->ip6_manager, ip_iface, s_ip6);
nm_ip6_manager_prepare_interface (priv->ip6_manager,
nm_device_get_ip_ifindex (self),
s_ip6);
}
static void
@ -697,6 +730,7 @@ addrconf6_cleanup (NMDevice *self)
priv->ip6_config_changed_sigid = 0;
}
nm_ip6_manager_cancel_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
g_object_unref (priv->ip6_manager);
priv->ip6_manager = NULL;
}
@ -1278,6 +1312,22 @@ dhcp_state_changed (NMDHCPClient *client,
else if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
break;
case DHC_STOP:
case DHC_STOP6:
case DHC_EXPIRE:
case DHC_EXPIRE6:
if (dev_state == NM_DEVICE_STATE_ACTIVATED) {
if (ipv6)
nm_dhcp6_config_reset (priv->dhcp6_config);
else
nm_dhcp4_config_reset (priv->dhcp4_config);
/* dhclient quit and can't get/renew a lease; so kill the connection */
nm_device_state_changed (device,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
}
break;
default:
break;
}
@ -1304,6 +1354,7 @@ dhcp_timeout (NMDHCPClient *client, gpointer user_data)
static NMActStageReturn
real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingIP4Config *s_ip4;
@ -1333,7 +1384,6 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
method = nm_setting_ip4_config_get_method (s_ip4);
if (!s_ip4 || !method || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint8 *anycast = NULL;
/* Begin a DHCP transaction on the interface */
@ -1389,6 +1439,10 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
*reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED;
ret = NM_ACT_STAGE_RETURN_FAILURE;
}
} else if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
/* Nothing to do... */
priv->ip4_ready = TRUE;
ret = NM_ACT_STAGE_RETURN_STOP;
}
return ret;
@ -1481,10 +1535,14 @@ real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason)
if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
priv->ip6_waiting_for_config = TRUE;
nm_ip6_manager_begin_addrconf (priv->ip6_manager, ip_iface);
nm_ip6_manager_begin_addrconf (priv->ip6_manager, nm_device_get_ip_ifindex (self));
ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP))
ret = dhcp6_start (self, connection, IP6_DHCP_OPT_MANAGED, reason);
else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
priv->ip6_ready = TRUE;
ret = NM_ACT_STAGE_RETURN_STOP;
}
return ret;
}
@ -1517,6 +1575,8 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
goto out;
} else if (ret == NM_ACT_STAGE_RETURN_STOP) {
/* Nothing to do */
} else
g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE);
@ -1526,6 +1586,8 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
else if (ret == NM_ACT_STAGE_RETURN_FAILURE) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
goto out;
} else if (ret == NM_ACT_STAGE_RETURN_STOP) {
/* Nothing to do */
} else
g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE);
@ -1674,7 +1736,8 @@ real_act_stage4_get_ip4_config (NMDevice *self,
*config = nm_device_new_ip4_shared_config (self, reason);
if (*config)
priv->dnsmasq_manager = nm_dnsmasq_manager_new (ip_iface);
}
} else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED))
ret = NM_ACT_STAGE_RETURN_SUCCESS;
}
if (!*config) {
@ -1866,7 +1929,8 @@ real_act_stage4_get_ip6_config (NMDevice *self,
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
*config = nm_ip6_manager_get_ip6_config (priv->ip6_manager, ip_iface);
*config = nm_ip6_manager_get_ip6_config (priv->ip6_manager,
nm_device_get_ip_ifindex (self));
if (*config) {
/* Merge user-defined overrides into the IP6Config to be applied */
nm_utils_merge_ip6_config (*config, s_ip6);
@ -1896,10 +1960,8 @@ real_act_stage4_get_ip6_config (NMDevice *self,
} else {
*reason = NM_DEVICE_STATE_REASON_DHCP_ERROR;
}
} else {
*config = NULL;
} else
ret = NM_ACT_STAGE_RETURN_SUCCESS;
}
out:
return ret;
@ -2022,7 +2084,7 @@ nm_device_activate_stage4_ip6_config_timeout (gpointer user_data)
goto out;
}
g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS);
/* FIXME g_assert (ip6_config); */
g_assert (ip6_config);
g_object_set_data (G_OBJECT (nm_device_get_act_request (self)),
NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
@ -2230,6 +2292,16 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data)
assumed = nm_act_request_get_assumed (priv->act_request);
if (!ip6_config && !ip4_config) {
nm_log_info (LOGD_DEVICE,
"Activation (%s) Stage 5 of 5 (IP Configure Commit) failed (no IP configuration found)",
iface);
nm_device_state_changed (self,
NM_DEVICE_STATE_FAILED,
NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
goto out;
}
if (ip4_config && !nm_device_set_ip4_config (self, ip4_config, assumed, &reason)) {
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
goto out;
@ -2239,6 +2311,8 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data)
nm_log_info (LOGD_DEVICE | LOGD_IP6,
"Activation (%s) Stage 5 of 5 (IP Configure Commit) IPv6 failed",
iface);
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason);
goto out;
}
connection = nm_act_request_get_connection (nm_device_get_act_request (self));
@ -2248,7 +2322,7 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data)
if (s_ip4)
method = nm_setting_ip4_config_get_method (s_ip4);
if (s_ip4 && !strcmp (method, "shared")) {
if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) {
if (!start_sharing (self)) {
nm_log_warn (LOGD_SHARING, "Activation (%s) Stage 5 of 5 (IP Configure Commit) start sharing failed.", iface);
nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED);
@ -3088,7 +3162,14 @@ set_property (GObject *object, guint prop_id,
break;
case NM_DEVICE_INTERFACE_PROP_IFACE:
g_free (priv->iface);
priv->ifindex = 0;
priv->iface = g_value_dup_string (value);
if (priv->iface) {
priv->ifindex = nm_netlink_iface_to_index (priv->iface);
if (priv->ifindex < 0) {
nm_log_warn (LOGD_HW, "(%s): failed to look up interface index", priv->iface);
}
}
break;
case NM_DEVICE_INTERFACE_PROP_DRIVER:
priv->driver = g_strdup (g_value_get_string (value));
@ -3136,6 +3217,9 @@ get_property (GObject *object, guint prop_id,
case NM_DEVICE_INTERFACE_PROP_IFACE:
g_value_set_string (value, priv->iface);
break;
case NM_DEVICE_INTERFACE_PROP_IFINDEX:
g_value_set_int (value, priv->ifindex);
break;
case NM_DEVICE_INTERFACE_PROP_DRIVER:
g_value_set_string (value, priv->driver);
break;
@ -3234,6 +3318,10 @@ nm_device_class_init (NMDeviceClass *klass)
NM_DEVICE_INTERFACE_PROP_IFACE,
NM_DEVICE_INTERFACE_IFACE);
g_object_class_override_property (object_class,
NM_DEVICE_INTERFACE_PROP_IFINDEX,
NM_DEVICE_INTERFACE_IFINDEX);
g_object_class_override_property (object_class,
NM_DEVICE_INTERFACE_PROP_DRIVER,
NM_DEVICE_INTERFACE_DRIVER);

View file

@ -38,7 +38,8 @@ typedef enum NMActStageReturn
{
NM_ACT_STAGE_RETURN_FAILURE = 0,
NM_ACT_STAGE_RETURN_SUCCESS,
NM_ACT_STAGE_RETURN_POSTPONE
NM_ACT_STAGE_RETURN_POSTPONE,
NM_ACT_STAGE_RETURN_STOP /* This activation chain is done */
} NMActStageReturn;
@ -128,7 +129,9 @@ void nm_device_set_path (NMDevice *dev, const char *path);
const char * nm_device_get_udi (NMDevice *dev);
const char * nm_device_get_iface (NMDevice *dev);
int nm_device_get_ifindex (NMDevice *dev);
const char * nm_device_get_ip_iface (NMDevice *dev);
int nm_device_get_ip_ifindex(NMDevice *dev);
const char * nm_device_get_driver (NMDevice *dev);
const char * nm_device_get_type_desc (NMDevice *dev);

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2005 - 2008 Red Hat, Inc.
* Copyright (C) 2005 - 2010 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
@ -692,34 +692,33 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
object_class->finalize = finalize;
/* properties */
g_object_class_install_property
(object_class, PROP_ADDRESSES,
g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES,
"Addresses",
"IP6 addresses",
DBUS_TYPE_G_ARRAY_OF_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));
g_object_class_install_property (object_class, PROP_ADDRESSES,
g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES,
"Addresses",
"IP6 addresses",
DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS,
G_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_NAMESERVERS,
g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS,
"Nameservers",
"DNS list",
DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR,
G_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_DOMAINS,
g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS,
"Domains",
"Domains",
DBUS_TYPE_G_ARRAY_OF_STRING,
G_PARAM_READABLE));
g_object_class_install_property (object_class, PROP_ROUTES,
g_param_spec_boxed (NM_IP6_CONFIG_ROUTES,
"Routes",
"Routes",
DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE,
G_PARAM_READABLE));
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (config_class),
&dbus_glib_nm_ip6_config_object_info);

View file

@ -1523,7 +1523,8 @@ add_device (NMManager *self, NMDevice *device)
driver = nm_device_get_driver (device);
if (!driver)
driver = "unknown";
nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s')", iface, type_desc, driver);
nm_log_info (LOGD_HW, "(%s): new %s device (driver: '%s' ifindex: %d)",
iface, type_desc, driver, nm_device_get_ifindex (device));
path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++);
nm_device_set_path (device, path);
@ -1794,20 +1795,11 @@ find_device_by_ifindex (NMManager *self, guint32 ifindex)
GSList *iter;
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMDevice *device = NM_DEVICE (iter->data);
gint candidate_idx = 0;
NMDevice *candidate = NM_DEVICE (iter->data);
if (NM_IS_DEVICE_ETHERNET (device))
candidate_idx = nm_device_ethernet_get_ifindex (NM_DEVICE_ETHERNET (device));
else if (NM_IS_DEVICE_WIFI (device))
candidate_idx = nm_device_wifi_get_ifindex (NM_DEVICE_WIFI (device));
else if (NM_IS_DEVICE_OLPC_MESH (device))
candidate_idx = nm_device_olpc_mesh_get_ifindex (NM_DEVICE_OLPC_MESH (device));
if (candidate_idx == ifindex)
return device;
if (ifindex == nm_device_get_ifindex (candidate))
return candidate;
}
return NULL;
}

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2005 - 2008 Red Hat, Inc.
* Copyright (C) 2005 - 2010 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
* Copyright (C) 2005 Ray Strode
*/
@ -25,16 +25,15 @@
#include <glib.h>
#include <glib-object.h>
#include <netlink/netlink.h>
#include <netlink/route/link.h>
G_BEGIN_DECLS
#define NM_TYPE_NETLINK_MONITOR (nm_netlink_monitor_get_type ())
#define NM_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitor))
#define NM_TYPE_NETLINK_MONITOR (nm_netlink_monitor_get_type ())
#define NM_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitor))
#define NM_NETLINK_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitorClass))
#define NM_IS_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETLINK_MONITOR))
#define NM_IS_NETLINK_MONITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETLINK_MONITOR))
#define NM_IS_NETLINK_MONITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_NETLINK_MONITOR))
#define NM_NETLINK_MONITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_NETLINK_MONITOR, NMNetlinkMonitorClass))
#define NM_NETLINK_MONITOR_ERROR (nm_netlink_monitor_error_quark ())
typedef enum {
NM_NETLINK_MONITOR_ERROR_GENERIC = 0,
@ -56,29 +55,45 @@ typedef struct {
GObjectClass parent_class;
/* Signals */
void (*carrier_on) (NMNetlinkMonitor *monitor, int index);
void (*carrier_off) (NMNetlinkMonitor *monitor, int index);
void (*error) (NMNetlinkMonitor *monitor, GError *error);
void (*notification) (NMNetlinkMonitor *monitor, struct nl_msg *msg);
void (*carrier_on) (NMNetlinkMonitor *monitor, int index);
void (*carrier_off) (NMNetlinkMonitor *monitor, int index);
void (*error) (NMNetlinkMonitor *monitor, GError *error);
} NMNetlinkMonitorClass;
GType nm_netlink_monitor_get_type (void) G_GNUC_CONST;
GQuark nm_netlink_monitor_error_quark (void) G_GNUC_CONST;
#define NM_NETLINK_MONITOR_ERROR (nm_netlink_monitor_error_quark ())
GType nm_netlink_monitor_get_type (void) G_GNUC_CONST;
GQuark nm_netlink_monitor_error_quark (void) G_GNUC_CONST;
NMNetlinkMonitor *nm_netlink_monitor_get (void);
gboolean nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor,
GError **error);
gboolean nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor,
GError **error);
void nm_netlink_monitor_close_connection (NMNetlinkMonitor *monitor);
void nm_netlink_monitor_attach (NMNetlinkMonitor *monitor);
void nm_netlink_monitor_detach (NMNetlinkMonitor *monitor);
void nm_netlink_monitor_attach (NMNetlinkMonitor *monitor);
void nm_netlink_monitor_detach (NMNetlinkMonitor *monitor);
gboolean nm_netlink_monitor_subscribe (NMNetlinkMonitor *monitor,
int group,
GError **error);
void nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *monitor,
int group);
gboolean nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *monitor,
GError **error);
gboolean nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor,
GError **error);
GError **error);
gboolean nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *monitor,
guint32 ifindex,
guint32 *ifflags,
GError **error);
G_END_DECLS
/* Generic utility functions */
int nm_netlink_iface_to_index (const char *iface);
char * nm_netlink_index_to_iface (int idx);
struct rtnl_link *nm_netlink_index_to_rtnl_link (int idx);
struct nl_handle *nm_netlink_get_default_handle (void);
#endif /* NM_NETLINK_MONITOR_H */

View file

@ -1,149 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2008 Red Hat, Inc.
*/
#include "config.h"
#include "nm-netlink.h"
#include "nm-logging.h"
#include <glib.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <netlink/object-api.h>
static struct nl_cache * link_cache = NULL;
static struct nl_handle * def_nl_handle = NULL;
static struct nl_cache *
get_link_cache (void)
{
struct nl_handle * nlh;
nlh = nm_netlink_get_default_handle ();
if (G_UNLIKELY (!nlh)) {
nm_log_err (LOGD_HW, "couldn't allocate netlink handle.");
return NULL;
}
if (G_UNLIKELY (!link_cache))
link_cache = rtnl_link_alloc_cache (nlh);
if (G_UNLIKELY (!link_cache)) {
nm_log_err (LOGD_HW, "couldn't allocate netlink link cache: %s", nl_geterror ());
return NULL;
}
nl_cache_update (nlh, link_cache);
return link_cache;
}
struct nl_handle *
nm_netlink_get_default_handle (void)
{
struct nl_cb *cb;
#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
struct nl_cache *addr_cache;
#endif
if (def_nl_handle)
return def_nl_handle;
cb = nl_cb_alloc(NL_CB_VERBOSE);
def_nl_handle = nl_handle_alloc_cb (cb);
if (!def_nl_handle) {
nm_log_err (LOGD_HW, "couldn't allocate netlink handle.");
return NULL;
}
if (nl_connect (def_nl_handle, NETLINK_ROUTE) < 0) {
nm_log_err (LOGD_HW, "couldn't connect to netlink: %s", nl_geterror ());
return NULL;
}
#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
/* Work around apparent libnl bug; rtnl_addr requires that all
* addresses have the "peer" attribute set in order to be compared
* for equality, but this attribute is not normally set. As a
* result, most addresses will not compare as equal even to
* themselves, busting caching.
*/
addr_cache = rtnl_addr_alloc_cache (def_nl_handle);
nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80;
nl_cache_free (addr_cache);
#endif
return def_nl_handle;
}
int
nm_netlink_iface_to_index (const char *iface)
{
struct nl_cache * cache;
g_return_val_if_fail (iface != NULL, -1);
cache = get_link_cache ();
if (!cache)
return RTNL_LINK_NOT_FOUND;
return rtnl_link_name2i (cache, iface);
}
#define MAX_IFACE_LEN 33
char *
nm_netlink_index_to_iface (int idx)
{
struct nl_cache * cache;
char * buf = NULL;
cache = get_link_cache ();
if (!cache)
return NULL;
buf = g_malloc0 (MAX_IFACE_LEN);
if (buf == NULL) {
nm_log_warn (LOGD_HW, "Not enough memory to allocate interface name buffer.");
return NULL;
}
if (rtnl_link_i2name (cache, idx, buf, MAX_IFACE_LEN - 1) == NULL) {
g_free (buf);
buf = NULL;
}
return buf;
}
struct rtnl_link *
nm_netlink_index_to_rtnl_link (int idx)
{
struct nl_cache *cache;
cache = get_link_cache ();
if (!cache)
return NULL;
return rtnl_link_get (cache, idx);
}

View file

@ -1,36 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2008 Red Hat, Inc.
*/
#ifndef NM_NETLINK_H
#define NM_NETLINK_H
#include <asm/types.h>
#include <netlink/route/addr.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/link.h>
int nm_netlink_iface_to_index (const char *iface);
char * nm_netlink_index_to_iface (int idx);
struct rtnl_link * nm_netlink_index_to_rtnl_link (int idx);
struct nl_handle * nm_netlink_get_default_handle (void);
#endif /* NM_NETLINK_H */

196
src/nm-policy-hostname.c Normal file
View file

@ -0,0 +1,196 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2004 - 2010 Red Hat, Inc.
* Copyright (C) 2007 - 2008 Novell, Inc.
*/
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <ctype.h>
#include <glib.h>
#include "nm-logging.h"
#include "nm-policy-hostname.h"
#include "nm-policy-hosts.h"
/************************************************************************/
struct HostnameThread {
GThread *thread;
GMutex *lock;
gboolean dead;
int ret;
guint32 ip4_addr;
char hostname[NI_MAXHOST + 1];
HostnameThreadCallback callback;
gpointer user_data;
};
static gboolean
hostname_thread_run_cb (gpointer user_data)
{
HostnameThread *ht = (HostnameThread *) user_data;
(*ht->callback) (ht, ht->ret, ht->hostname, ht->user_data);
return FALSE;
}
static gpointer
hostname_thread_worker (gpointer data)
{
HostnameThread *ht = (HostnameThread *) data;
struct sockaddr_in addr;
int i;
g_mutex_lock (ht->lock);
if (ht->dead) {
g_mutex_unlock (ht->lock);
return (gpointer) NULL;
}
g_mutex_unlock (ht->lock);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ht->ip4_addr;
ht->ret = getnameinfo ((struct sockaddr *) &addr, sizeof (struct sockaddr_in),
ht->hostname, NI_MAXHOST, NULL, 0,
NI_NAMEREQD);
if (ht->ret == 0) {
for (i = 0; i < strlen (ht->hostname); i++)
ht->hostname[i] = tolower (ht->hostname[i]);
}
/* Don't track the idle handler ID because by the time the g_idle_add()
* returns the ID, the handler may already have run and freed the
* HostnameThread.
*/
g_idle_add (hostname_thread_run_cb, ht);
return (gpointer) TRUE;
}
void
hostname_thread_free (HostnameThread *ht)
{
g_return_if_fail (ht != NULL);
g_mutex_free (ht->lock);
memset (ht, 0, sizeof (HostnameThread));
g_free (ht);
}
HostnameThread *
hostname_thread_new (guint32 ip4_addr, HostnameThreadCallback callback, gpointer user_data)
{
HostnameThread *ht;
ht = g_malloc0 (sizeof (HostnameThread));
g_assert (ht);
ht->lock = g_mutex_new ();
ht->callback = callback;
ht->user_data = user_data;
ht->ip4_addr = ip4_addr;
ht->thread = g_thread_create (hostname_thread_worker, ht, FALSE, NULL);
if (!ht->thread) {
hostname_thread_free (ht);
ht = NULL;
}
return ht;
}
void
hostname_thread_kill (HostnameThread *ht)
{
g_return_if_fail (ht != NULL);
g_mutex_lock (ht->lock);
ht->dead = TRUE;
g_mutex_unlock (ht->lock);
}
gboolean
hostname_thread_is_dead (HostnameThread *ht)
{
g_return_val_if_fail (ht != NULL, TRUE);
return ht->dead;
}
/************************************************************************/
#define FALLBACK_HOSTNAME "localhost.localdomain"
gboolean
nm_policy_set_system_hostname (const char *new_hostname, const char *msg)
{
char old_hostname[HOST_NAME_MAX + 1];
int ret = 0;
const char *name = new_hostname ? new_hostname : FALLBACK_HOSTNAME;
gboolean set_hostname = TRUE, changed = FALSE;
old_hostname[HOST_NAME_MAX] = '\0';
errno = 0;
ret = gethostname (old_hostname, HOST_NAME_MAX);
if (ret != 0) {
nm_log_warn (LOGD_DNS, "couldn't get the system hostname: (%d) %s",
errno, strerror (errno));
} else {
/* Don't set the hostname if it isn't actually changing */
if ( (new_hostname && !strcmp (old_hostname, new_hostname))
|| (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME)))
set_hostname = FALSE;
}
if (set_hostname) {
nm_log_info (LOGD_DNS, "Setting system hostname to '%s' (%s)", name, msg);
ret = sethostname (name, strlen (name));
if (ret != 0) {
nm_log_warn (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s",
name, errno, strerror (errno));
return FALSE;
}
}
/* But even if the hostname isn't changing, always try updating /etc/hosts
* just in case the hostname changed while NM wasn't running; we need to
* make sure that /etc/hosts has valid mappings for '127.0.0.1' and the
* current system hostname. If those exist,
* nm_policy_hosts_update_etc_hosts() will just return and won't touch
* /etc/hosts at all.
*/
if (!nm_policy_hosts_update_etc_hosts (name, FALLBACK_HOSTNAME, &changed)) {
/* error updating /etc/hosts; fallback to localhost.localdomain */
nm_log_info (LOGD_DNS, "Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)");
ret = sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME));
if (ret != 0) {
nm_log_warn (LOGD_DNS, "couldn't set the fallback system hostname (%s): (%d) %s",
FALLBACK_HOSTNAME, errno, strerror (errno));
}
}
return changed;
}

47
src/nm-policy-hostname.h Normal file
View file

@ -0,0 +1,47 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2004 - 2010 Red Hat, Inc.
* Copyright (C) 2007 - 2008 Novell, Inc.
*/
#ifndef NM_POLICY_HOSTNAME_H
#define NM_POLICY_HOSTNAME_H
#include <glib.h>
gboolean nm_policy_set_system_hostname (const char *new_hostname, const char *msg);
typedef struct HostnameThread HostnameThread;
typedef void (*HostnameThreadCallback) (HostnameThread *ht,
int error,
const char *hostname,
gpointer user_data);
HostnameThread * hostname_thread_new (guint32 ip4_addr,
HostnameThreadCallback callback,
gpointer user_data);
void hostname_thread_free (HostnameThread *ht);
gboolean hostname_thread_is_dead (HostnameThread *ht);
void hostname_thread_kill (HostnameThread *ht);
#endif /* NM_POLICY_HOSTNAME_H */

View file

@ -25,6 +25,7 @@
#include <ctype.h>
#include "nm-policy-hosts.h"
#include "nm-logging.h"
gboolean
nm_policy_hosts_find_token (const char *line, const char *token)
@ -171,3 +172,64 @@ nm_policy_get_etc_hosts (const char **lines,
return contents;
}
gboolean
nm_policy_hosts_update_etc_hosts (const char *hostname,
const char *fallback_hostname,
gboolean *out_changed)
{
char *contents = NULL;
char **lines = NULL;
GError *error = NULL;
GString *new_contents = NULL;
gsize contents_len = 0;
gboolean success = FALSE;
g_return_val_if_fail (hostname != NULL, FALSE);
g_return_val_if_fail (out_changed != NULL, FALSE);
if (!g_file_get_contents (SYSCONFDIR "/hosts", &contents, &contents_len, &error)) {
nm_log_warn (LOGD_DNS, "couldn't read " SYSCONFDIR "/hosts: (%d) %s",
error ? error->code : 0,
(error && error->message) ? error->message : "(unknown)");
g_clear_error (&error);
return FALSE;
}
/* Get the new /etc/hosts contents */
lines = g_strsplit_set (contents, "\n\r", 0);
new_contents = nm_policy_get_etc_hosts ((const char **) lines,
contents_len,
hostname,
fallback_hostname,
&error);
g_strfreev (lines);
g_free (contents);
if (new_contents) {
nm_log_info (LOGD_DNS, "Updating /etc/hosts with new system hostname");
g_clear_error (&error);
/* And actually update /etc/hosts */
if (!g_file_set_contents (SYSCONFDIR "/hosts", new_contents->str, -1, &error)) {
nm_log_warn (LOGD_DNS, "couldn't update " SYSCONFDIR "/hosts: (%d) %s",
error ? error->code : 0,
(error && error->message) ? error->message : "(unknown)");
g_clear_error (&error);
} else {
success = TRUE;
*out_changed = TRUE;
}
g_string_free (new_contents, TRUE);
} else if (!error) {
/* No change required */
success = TRUE;
} else {
nm_log_warn (LOGD_DNS, "couldn't read " SYSCONFDIR "/hosts: (%d) %s",
error->code, error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
return success;
}

View file

@ -23,14 +23,18 @@
#include <glib.h>
gboolean nm_policy_hosts_update_etc_hosts (const char *hostname,
const char *fallback_hostname,
gboolean *out_changed);
/* Only for testcases; don't use outside of nm-policy-hosts.c */
gboolean nm_policy_hosts_find_token (const char *line, const char *token);
GString *nm_policy_get_etc_hosts (const char **lines,
gsize existing_len,
const char *hostname,
const char *fallback_hostname,
GError **error);
/* Only for testcases; don't use outside of nm-policy-hosts.c */
gboolean nm_policy_hosts_find_token (const char *line, const char *token);
#endif /* NM_POLICY_HOSTS_H */

View file

@ -42,24 +42,7 @@
#include "nm-named-manager.h"
#include "nm-vpn-manager.h"
#include "nm-policy-hosts.h"
typedef struct LookupThread LookupThread;
typedef void (*LookupCallback) (LookupThread *thread, gpointer user_data);
struct LookupThread {
GThread *thread;
GMutex *lock;
gboolean die;
int ret;
guint32 ip4_addr;
char hostname[NI_MAXHOST + 1];
LookupCallback callback;
gpointer user_data;
};
#include "nm-policy-hostname.h"
struct NMPolicy {
NMManager *manager;
@ -72,99 +55,14 @@ struct NMPolicy {
gulong vpn_activated_id;
gulong vpn_deactivated_id;
NMDevice *default_device;
NMDevice *default_device4;
NMDevice *default_device6;
LookupThread *lookup;
HostnameThread *lookup;
char *orig_hostname; /* hostname at NM start time */
};
static gboolean
lookup_thread_run_cb (gpointer user_data)
{
LookupThread *thread = (LookupThread *) user_data;
(*thread->callback) (thread, thread->user_data);
return FALSE;
}
static gpointer
lookup_thread_worker (gpointer data)
{
LookupThread *thread = (LookupThread *) data;
struct sockaddr_in addr;
g_mutex_lock (thread->lock);
if (thread->die) {
g_mutex_unlock (thread->lock);
return (gpointer) NULL;
}
g_mutex_unlock (thread->lock);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = thread->ip4_addr;
thread->ret = getnameinfo ((struct sockaddr *) &addr, sizeof (struct sockaddr_in),
thread->hostname, NI_MAXHOST, NULL, 0,
NI_NAMEREQD);
if (thread->ret == 0) {
int i;
for (i = 0; i < strlen (thread->hostname); i++)
thread->hostname[i] = tolower (thread->hostname[i]);
}
/* Don't track the idle handler ID because by the time the g_idle_add()
* returns the ID, the handler may already have run and freed the
* LookupThread.
*/
g_idle_add (lookup_thread_run_cb, thread);
return (gpointer) TRUE;
}
static void
lookup_thread_free (LookupThread *thread)
{
g_return_if_fail (thread != NULL);
g_mutex_free (thread->lock);
memset (thread, 0, sizeof (LookupThread));
g_free (thread);
}
static LookupThread *
lookup_thread_new (guint32 ip4_addr, LookupCallback callback, gpointer user_data)
{
LookupThread *thread;
thread = g_malloc0 (sizeof (LookupThread));
if (!thread)
return NULL;
thread->lock = g_mutex_new ();
thread->callback = callback;
thread->user_data = user_data;
thread->ip4_addr = ip4_addr;
thread->thread = g_thread_create (lookup_thread_worker, thread, FALSE, NULL);
if (!thread->thread) {
lookup_thread_free (thread);
return NULL;
}
return thread;
}
static void
lookup_thread_die (LookupThread *thread)
{
g_return_if_fail (thread != NULL);
g_mutex_lock (thread->lock);
thread->die = TRUE;
g_mutex_unlock (thread->lock);
}
#define INVALID_TAG "invalid"
static const char *
@ -181,7 +79,7 @@ get_connection_id (NMConnection *connection)
}
static NMDevice *
get_best_device (NMManager *manager, NMActRequest **out_req)
get_best_ip4_device (NMManager *manager, NMActRequest **out_req)
{
GSList *devices, *iter;
NMDevice *best = NULL;
@ -253,142 +151,107 @@ get_best_device (NMManager *manager, NMActRequest **out_req)
return best;
}
#define FALLBACK_HOSTNAME "localhost.localdomain"
static gboolean
update_etc_hosts (const char *hostname, gboolean *out_changed)
static NMDevice *
get_best_ip6_device (NMManager *manager, NMActRequest **out_req)
{
char *contents = NULL;
char **lines = NULL;
GError *error = NULL;
GString *new_contents = NULL;
gsize contents_len = 0;
gboolean success = FALSE;
GSList *devices, *iter;
NMDevice *best = NULL;
int best_prio = G_MAXINT;
g_return_val_if_fail (hostname != NULL, FALSE);
g_return_val_if_fail (out_changed != NULL, FALSE);
g_return_val_if_fail (manager != NULL, NULL);
g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
g_return_val_if_fail (out_req != NULL, NULL);
g_return_val_if_fail (*out_req == NULL, NULL);
if (!g_file_get_contents (SYSCONFDIR "/hosts", &contents, &contents_len, &error)) {
nm_log_warn (LOGD_DNS, "couldn't read " SYSCONFDIR "/hosts: (%d) %s",
error ? error->code : 0,
(error && error->message) ? error->message : "(unknown)");
g_clear_error (&error);
return FALSE;
}
devices = nm_manager_get_devices (manager);
for (iter = devices; iter; iter = g_slist_next (iter)) {
NMDevice *dev = NM_DEVICE (iter->data);
NMActRequest *req;
NMConnection *connection;
NMIP6Config *ip6_config;
NMSettingIP6Config *s_ip6;
int prio;
guint i;
gboolean can_default = FALSE;
const char *method = NULL;
/* Get the new /etc/hosts contents */
lines = g_strsplit_set (contents, "\n\r", 0);
new_contents = nm_policy_get_etc_hosts ((const char **) lines,
contents_len,
hostname,
FALLBACK_HOSTNAME,
&error);
g_strfreev (lines);
g_free (contents);
if (nm_device_get_state (dev) != NM_DEVICE_STATE_ACTIVATED)
continue;
if (new_contents) {
nm_log_info (LOGD_DNS, "Updating /etc/hosts with new system hostname");
ip6_config = nm_device_get_ip6_config (dev);
if (!ip6_config)
continue;
g_clear_error (&error);
/* And actually update /etc/hosts */
if (!g_file_set_contents (SYSCONFDIR "/hosts", new_contents->str, -1, &error)) {
nm_log_warn (LOGD_DNS, "couldn't update " SYSCONFDIR "/hosts: (%d) %s",
error ? error->code : 0,
(error && error->message) ? error->message : "(unknown)");
g_clear_error (&error);
} else {
success = TRUE;
*out_changed = TRUE;
req = nm_device_get_act_request (dev);
g_assert (req);
connection = nm_act_request_get_connection (req);
g_assert (connection);
/* Never set the default route through an IPv4LL-addressed device */
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
if (s_ip6)
method = nm_setting_ip6_config_get_method (s_ip6);
if (method && !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL))
continue;
/* Make sure at least one of this device's IP addresses has a gateway */
for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) {
NMIP6Address *addr;
addr = nm_ip6_config_get_address (ip6_config, i);
if (nm_ip6_address_get_gateway (addr)) {
can_default = TRUE;
break;
}
}
g_string_free (new_contents, TRUE);
} else if (!error) {
/* No change required */
success = TRUE;
} else {
nm_log_warn (LOGD_DNS, "couldn't read " SYSCONFDIR "/hosts: (%d) %s",
error->code, error->message ? error->message : "(unknown)");
g_clear_error (&error);
if (!can_default && !NM_IS_DEVICE_MODEM (dev))
continue;
/* 'never-default' devices can't ever be the default */
if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6))
continue;
prio = nm_device_get_priority (dev);
if (prio > 0 && prio < best_prio) {
best = dev;
best_prio = prio;
*out_req = req;
}
}
return success;
return best;
}
static void
set_system_hostname (const char *new_hostname, const char *msg)
_set_hostname (const char *new_hostname, const char *msg)
{
char old_hostname[HOST_NAME_MAX + 1];
int ret = 0;
const char *name = new_hostname ? new_hostname : FALLBACK_HOSTNAME;
gboolean set_hostname = TRUE, changed = FALSE;
old_hostname[HOST_NAME_MAX] = '\0';
errno = 0;
ret = gethostname (old_hostname, HOST_NAME_MAX);
if (ret != 0) {
nm_log_warn (LOGD_DNS, "couldn't get the system hostname: (%d) %s",
errno, strerror (errno));
} else {
/* Don't set the hostname if it isn't actually changing */
if ( (new_hostname && !strcmp (old_hostname, new_hostname))
|| (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME)))
set_hostname = FALSE;
}
if (set_hostname) {
nm_log_info (LOGD_DNS, "Setting system hostname to '%s' (%s)", name, msg);
ret = sethostname (name, strlen (name));
if (ret != 0) {
nm_log_warn (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s",
name, errno, strerror (errno));
return;
}
}
/* But still always try updating /etc/hosts just in case the hostname
* changed while NM wasn't running; we need to make sure that /etc/hosts
* has valid mappings for '127.0.0.1' and the current system hostname. If
* those exist, update_etc_hosts() will just return and won't touch
* /etc/hosts at all.
*/
if (!update_etc_hosts (name, &changed)) {
/* error updating /etc/hosts; fallback to localhost.localdomain */
nm_log_info (LOGD_DNS, "Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)");
ret = sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME));
if (ret != 0) {
nm_log_warn (LOGD_DNS, "couldn't set the fallback system hostname (%s): (%d) %s",
FALLBACK_HOSTNAME, errno, strerror (errno));
}
}
if (changed)
if (nm_policy_set_system_hostname (new_hostname, msg))
nm_utils_call_dispatcher ("hostname", NULL, NULL, NULL);
}
static void
lookup_callback (LookupThread *thread, gpointer user_data)
lookup_callback (HostnameThread *thread,
int result,
const char *hostname,
gpointer user_data)
{
NMPolicy *policy = (NMPolicy *) user_data;
char *msg;
/* If the thread was told to die or it's not the current in-progress
* hostname lookup, nothing to do.
*/
if (thread->die || (thread != policy->lookup))
goto done;
policy->lookup = NULL;
if (!strlen (thread->hostname)) {
char *msg;
/* No valid IP4 config (!!); fall back to localhost.localdomain */
msg = g_strdup_printf ("address lookup failed: %d", thread->ret);
set_system_hostname (NULL, msg);
g_free (msg);
} else
set_system_hostname (thread->hostname, "from address lookup");
done:
lookup_thread_free (thread);
/* Update the hostname if the calling lookup thread is the in-progress one */
if (!hostname_thread_is_dead (thread) && (thread == policy->lookup)) {
policy->lookup = NULL;
if (!hostname) {
/* No valid IP4 config (!!); fall back to localhost.localdomain */
msg = g_strdup_printf ("address lookup failed: %d", result);
_set_hostname (NULL, msg);
g_free (msg);
} else
_set_hostname (hostname, "from address lookup");
}
hostname_thread_free (thread);
}
static void
@ -403,7 +266,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
g_return_if_fail (policy != NULL);
if (policy->lookup) {
lookup_thread_die (policy->lookup);
hostname_thread_kill (policy->lookup);
policy->lookup = NULL;
}
@ -419,20 +282,20 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
/* Try a persistent hostname first */
g_object_get (G_OBJECT (policy->manager), NM_MANAGER_HOSTNAME, &configured_hostname, NULL);
if (configured_hostname) {
set_system_hostname (configured_hostname, "from system configuration");
_set_hostname (configured_hostname, "from system configuration");
g_free (configured_hostname);
return;
}
/* Try automatically determined hostname from the best device's IP config */
if (!best)
best = get_best_device (policy->manager, &best_req);
best = get_best_ip4_device (policy->manager, &best_req);
if (!best) {
/* No best device; fall back to original hostname or if there wasn't
* one, 'localhost.localdomain'
*/
set_system_hostname (policy->orig_hostname, "no default device");
_set_hostname (policy->orig_hostname, "no default device");
return;
}
@ -446,7 +309,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
/* Sanity check */
while (*p) {
if (!isblank (*p++)) {
set_system_hostname (dhcp4_hostname, "from DHCP");
_set_hostname (dhcp4_hostname, "from DHCP");
return;
}
}
@ -459,7 +322,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
* when NM started up.
*/
if (policy->orig_hostname) {
set_system_hostname (policy->orig_hostname, "from system startup");
_set_hostname (policy->orig_hostname, "from system startup");
return;
}
@ -471,7 +334,7 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
|| (nm_ip4_config_get_num_nameservers (ip4_config) == 0)
|| (nm_ip4_config_get_num_addresses (ip4_config) == 0)) {
/* No valid IP4 config (!!); fall back to localhost.localdomain */
set_system_hostname (NULL, "no IPv4 config");
_set_hostname (NULL, "no IPv4 config");
return;
}
@ -479,15 +342,15 @@ update_system_hostname (NMPolicy *policy, NMDevice *best)
g_assert (addr); /* checked for > 1 address above */
/* Start the hostname lookup thread */
policy->lookup = lookup_thread_new (nm_ip4_address_get_address (addr), lookup_callback, policy);
policy->lookup = hostname_thread_new (nm_ip4_address_get_address (addr), lookup_callback, policy);
if (!policy->lookup) {
/* Fall back to 'localhost.localdomain' */
set_system_hostname (NULL, "error starting hostname thread");
_set_hostname (NULL, "error starting hostname thread");
}
}
static void
update_routing_and_dns (NMPolicy *policy, gboolean force_update)
update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
{
NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
NMDevice *best = NULL;
@ -501,10 +364,10 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
NMSettingConnection *s_con = NULL;
const char *connection_id;
best = get_best_device (policy->manager, &best_req);
best = get_best_ip4_device (policy->manager, &best_req);
if (!best)
goto out;
if (!force_update && (best == policy->default_device))
if (!force_update && (best == policy->default_device4))
goto out;
/* If a VPN connection is active, it is preferred */
@ -598,16 +461,149 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
if (connection_id) {
nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for routing and DNS.", connection_id, ip_iface);
nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv4 routing and DNS.", connection_id, ip_iface);
} else {
nm_log_info (LOGD_CORE, "Policy set (%s) as default for routing and DNS.", ip_iface);
nm_log_info (LOGD_CORE, "Policy set (%s) as default for IPv4 routing and DNS.", ip_iface);
}
out:
/* Update the system hostname */
update_system_hostname (policy, best);
policy->default_device4 = best;
}
policy->default_device = best;
static void
update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
{
NMNamedIPConfigType dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
NMDevice *best = NULL;
NMActRequest *best_req = NULL;
NMNamedManager *named_mgr;
GSList *devices = NULL, *iter;
#if NOT_YET
GSList *vpns;
#endif
NMIP6Config *ip6_config = NULL;
NMIP6Address *addr;
const char *ip_iface = NULL;
NMConnection *connection = NULL;
NMSettingConnection *s_con = NULL;
const char *connection_id;
best = get_best_ip6_device (policy->manager, &best_req);
if (!best)
goto out;
if (!force_update && (best == policy->default_device6))
goto out;
#if NOT_YET
/* If a VPN connection is active, it is preferred */
vpns = nm_vpn_manager_get_active_connections (policy->vpn_manager);
for (iter = vpns; iter; iter = g_slist_next (iter)) {
NMVPNConnection *candidate = NM_VPN_CONNECTION (iter->data);
NMConnection *vpn_connection;
NMSettingIP6Config *s_ip6;
gboolean can_default = TRUE;
NMVPNConnectionState vpn_state;
/* If it's marked 'never-default', don't make it default */
vpn_connection = nm_vpn_connection_get_connection (candidate);
g_assert (vpn_connection);
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (vpn_connection, NM_TYPE_SETTING_IP6_CONFIG);
if (s_ip6 && nm_setting_ip6_config_get_never_default (s_ip6))
can_default = FALSE;
vpn_state = nm_vpn_connection_get_vpn_state (candidate);
if (can_default && (vpn_state == NM_VPN_CONNECTION_STATE_ACTIVATED)) {
NMIP6Config *parent_ip6;
NMDevice *parent;
ip_iface = nm_vpn_connection_get_ip_iface (candidate);
connection = nm_vpn_connection_get_connection (candidate);
ip6_config = nm_vpn_connection_get_ip6_config (candidate);
addr = nm_ip6_config_get_address (ip6_config, 0);
parent = nm_vpn_connection_get_parent_device (candidate);
parent_ip6 = nm_device_get_ip6_config (parent);
nm_system_replace_default_ip6_route_vpn (ip_iface,
nm_ip6_address_get_gateway (addr),
nm_vpn_connection_get_ip4_internal_gateway (candidate),
nm_ip6_config_get_mss (ip4_config),
nm_device_get_ip_iface (parent),
nm_ip6_config_get_mss (parent_ip4));
dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN;
}
g_object_unref (candidate);
}
g_slist_free (vpns);
#endif
/* The best device gets the default route if a VPN connection didn't */
if (!ip_iface || !ip6_config) {
connection = nm_act_request_get_connection (best_req);
ip_iface = nm_device_get_ip_iface (best);
ip6_config = nm_device_get_ip6_config (best);
g_assert (ip6_config);
addr = nm_ip6_config_get_address (ip6_config, 0);
nm_system_replace_default_ip6_route (ip_iface, nm_ip6_address_get_gateway (addr));
dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
}
if (!ip_iface || !ip6_config) {
nm_log_warn (LOGD_CORE, "couldn't determine IP interface (%p) or IPv6 config (%p)!",
ip_iface, ip6_config);
goto out;
}
/* Update the default active connection. Only mark the new default
* active connection after setting default = FALSE on all other connections
* first. The order is important, we don't want two connections marked
* default at the same time ever.
*/
devices = nm_manager_get_devices (policy->manager);
for (iter = devices; iter; iter = g_slist_next (iter)) {
NMDevice *dev = NM_DEVICE (iter->data);
NMActRequest *req;
req = nm_device_get_act_request (dev);
if (req && (req != best_req))
nm_act_request_set_default6 (req, FALSE);
}
named_mgr = nm_named_manager_get ();
nm_named_manager_add_ip6_config (named_mgr, ip_iface, ip6_config, dns_type);
g_object_unref (named_mgr);
/* Now set new default active connection _after_ updating DNS info, so that
* if the connection is shared dnsmasq picks up the right stuff.
*/
if (best_req)
nm_act_request_set_default6 (best_req, TRUE);
if (connection)
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
connection_id = s_con ? nm_setting_connection_get_id (s_con) : NULL;
if (connection_id) {
nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv6 routing and DNS.", connection_id, ip_iface);
} else {
nm_log_info (LOGD_CORE, "Policy set (%s) as default for IPv6 routing and DNS.", ip_iface);
}
out:
policy->default_device6 = best;
}
static void
update_routing_and_dns (NMPolicy *policy, gboolean force_update)
{
update_ip4_routing_and_dns (policy, force_update);
update_ip6_routing_and_dns (policy, force_update);
/* Update the system hostname */
update_system_hostname (policy, policy->default_device4);
}
typedef struct {
@ -796,10 +792,23 @@ device_state_changed (NMDevice *device,
/* Mark the connection invalid if it failed during activation so that
* it doesn't get automatically chosen over and over and over again.
*/
if (connection && IS_ACTIVATING_STATE (old_state)) {
g_object_set_data (G_OBJECT (connection), INVALID_TAG, GUINT_TO_POINTER (TRUE));
nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", get_connection_id (connection));
nm_connection_clear_secrets (connection);
if (connection) {
gboolean fail = FALSE;
if (IS_ACTIVATING_STATE (old_state)) {
nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid.", get_connection_id (connection));
fail = TRUE;
} else if ( (old_state == NM_DEVICE_STATE_ACTIVATED)
&& (reason == NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED)) {
nm_log_info (LOGD_DEVICE, "Marking connection '%s' invalid because IP configuration expired.",
get_connection_id (connection));
fail = TRUE;
}
if (fail) {
g_object_set_data (G_OBJECT (connection), INVALID_TAG, GUINT_TO_POINTER (TRUE));
nm_connection_clear_secrets (connection);
}
}
schedule_activate_check (policy, device, 3);
break;
@ -828,9 +837,9 @@ device_state_changed (NMDevice *device,
}
static void
device_ip4_config_changed (NMDevice *device,
GParamSpec *pspec,
gpointer user_data)
device_ip_config_changed (NMDevice *device,
GParamSpec *pspec,
gpointer user_data)
{
update_routing_and_dns ((NMPolicy *) user_data, TRUE);
}
@ -872,7 +881,12 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data)
policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device);
id = g_signal_connect (device, "notify::" NM_DEVICE_INTERFACE_IP4_CONFIG,
G_CALLBACK (device_ip4_config_changed),
G_CALLBACK (device_ip_config_changed),
policy);
policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device);
id = g_signal_connect (device, "notify::" NM_DEVICE_INTERFACE_IP6_CONFIG,
G_CALLBACK (device_ip_config_changed),
policy);
policy->dev_signal_ids = add_device_signal_id (policy->dev_signal_ids, id, device);
@ -1083,7 +1097,7 @@ nm_policy_destroy (NMPolicy *policy)
* by the lookup thread callback.
*/
if (policy->lookup) {
lookup_thread_die (policy->lookup);
hostname_thread_kill (policy->lookup);
policy->lookup = NULL;
}

View file

@ -48,7 +48,7 @@
#include "NetworkManagerUtils.h"
#include "nm-utils.h"
#include "nm-logging.h"
#include "nm-netlink.h"
#include "nm-netlink-monitor.h"
/* Because of a bug in libnl, rtnl.h should be included before route.h */
#include <netlink/route/rtnl.h>
@ -460,7 +460,7 @@ nm_system_device_set_ip6_route (const char *iface,
g_return_val_if_fail (route != NULL, NULL);
/* Destination */
dest_addr = nl_addr_build (AF_INET6, (struct in6_addr *)ip6_dest, sizeof (*ip6_dest));
dest_addr = nl_addr_build (AF_INET6, (struct in6_addr *) ip6_dest, sizeof (*ip6_dest));
g_return_val_if_fail (dest_addr != NULL, NULL);
nl_addr_set_prefixlen (dest_addr, (int) ip6_prefix);
@ -469,7 +469,7 @@ nm_system_device_set_ip6_route (const char *iface,
/* Gateway */
if (ip6_gateway && !IN6_IS_ADDR_UNSPECIFIED (ip6_gateway)) {
gw_addr = nl_addr_build (AF_INET6, (struct in6_addr *)ip6_gateway, sizeof (*ip6_gateway));
gw_addr = nl_addr_build (AF_INET6, (struct in6_addr *) ip6_gateway, sizeof (*ip6_gateway));
if (gw_addr) {
rtnl_route_set_gateway (route, gw_addr);
rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
@ -940,6 +940,153 @@ nm_system_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
return success;
}
static struct rtnl_route *
add_ip6_route_to_gateway (const char *iface, const struct in6_addr *gw)
{
struct nl_handle *nlh;
struct rtnl_route *route = NULL;
struct nl_addr *gw_addr = NULL;
int iface_idx, err;
nlh = nm_netlink_get_default_handle ();
g_return_val_if_fail (nlh != NULL, NULL);
iface_idx = nm_netlink_iface_to_index (iface);
if (iface_idx < 0)
return NULL;
/* Gateway might be over a bridge; try adding a route to gateway first */
route = rtnl_route_alloc ();
if (route == NULL)
return NULL;
rtnl_route_set_family (route, AF_INET6);
rtnl_route_set_table (route, RT_TABLE_MAIN);
rtnl_route_set_oif (route, iface_idx);
rtnl_route_set_scope (route, RT_SCOPE_LINK);
gw_addr = nl_addr_build (AF_INET, (void *) gw, sizeof (*gw));
if (!gw_addr)
goto error;
nl_addr_set_prefixlen (gw_addr, 128);
rtnl_route_set_dst (route, gw_addr);
nl_addr_put (gw_addr);
/* Add direct route to the gateway */
err = rtnl_route_add (nlh, route, 0);
if (err) {
nm_log_err (LOGD_DEVICE | LOGD_IP6,
"(%s): failed to add IPv4 route to gateway (%d)",
iface, err);
goto error;
}
return route;
error:
rtnl_route_put (route);
return NULL;
}
static int
replace_default_ip6_route (const char *iface, const struct in6_addr *gw)
{
struct rtnl_route *route = NULL;
struct nl_handle *nlh;
struct nl_addr *gw_addr = NULL;
int iface_idx, err = -1;
g_return_val_if_fail (iface != NULL, -ENODEV);
nlh = nm_netlink_get_default_handle ();
g_return_val_if_fail (nlh != NULL, -ENOMEM);
iface_idx = nm_netlink_iface_to_index (iface);
if (iface_idx < 0)
return -ENODEV;
route = rtnl_route_alloc();
g_return_val_if_fail (route != NULL, -ENOMEM);
rtnl_route_set_family (route, AF_INET6);
rtnl_route_set_table (route, RT_TABLE_MAIN);
rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
rtnl_route_set_oif (route, iface_idx);
if (gw && !IN6_IS_ADDR_UNSPECIFIED (gw)) {
/* Build up the gateway address */
gw_addr = nl_addr_build (AF_INET6, (void *) gw, sizeof (*gw));
if (!gw_addr) {
err = -ENOMEM;
goto out;
}
nl_addr_set_prefixlen (gw_addr, -1);
rtnl_route_set_gateway (route, gw_addr);
}
/* Add the new default route */
err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
if (err == -EEXIST) {
/* FIXME: even though we use NLM_F_REPLACE the kernel won't replace
* the route if it's the same. Should try to remove it first, then
* add the new one again here.
*/
err = 0;
}
out:
if (gw_addr)
nl_addr_put (gw_addr);
rtnl_route_put (route);
return err;
}
/*
* nm_system_replace_default_ip6_route
*
* Replace default IPv6 route with one via the given gateway
*
*/
gboolean
nm_system_replace_default_ip6_route (const char *iface, const struct in6_addr *gw)
{
struct rtnl_route *gw_route = NULL;
struct nl_handle *nlh;
gboolean success = FALSE;
int err;
nlh = nm_netlink_get_default_handle ();
g_return_val_if_fail (nlh != NULL, FALSE);
err = replace_default_ip6_route (iface, gw);
if (err == 0) {
return TRUE;
} else if (err != -ESRCH) {
nm_log_err (LOGD_DEVICE | LOGD_IP6,
"(%s): failed to set IPv6 default route: %d",
iface, err);
return FALSE;
}
/* Try adding a direct route to the gateway first */
gw_route = add_ip6_route_to_gateway (iface, gw);
if (!gw_route)
return FALSE;
/* Try adding the original route again */
err = replace_default_ip6_route (iface, gw);
if (err != 0) {
rtnl_route_del (nlh, gw_route, 0);
nm_log_err (LOGD_DEVICE | LOGD_IP6,
"(%s): failed to set IPv6 default route (pass #2): %d",
iface, err);
} else
success = TRUE;
rtnl_route_put (gw_route);
return success;
}
static void flush_addresses (const char *iface, gboolean ipv4_only)
{
int iface_idx;
@ -986,7 +1133,7 @@ foreach_route (void (*callback)(struct nl_object *, gpointer),
nlh = nm_netlink_get_default_handle ();
route_cache = rtnl_route_alloc_cache (nlh);
nl_cache_mngt_provide (route_cache);
g_assert (route_cache);
nl_cache_foreach (route_cache, callback, user_data);
nl_cache_free (route_cache);
}

View file

@ -40,6 +40,9 @@ gboolean nm_system_replace_default_ip4_route (const char *iface,
guint32 gw,
guint32 mss);
gboolean nm_system_replace_default_ip6_route (const char *iface,
const struct in6_addr *gw);
gboolean nm_system_replace_default_ip4_route_vpn (const char *iface,
guint32 ext_gw,
guint32 int_gw,

View file

@ -384,11 +384,11 @@ device_creator (NMUdevManager *manager,
}
if (is_olpc_mesh (udev_device)) /* must be before is_wireless */
device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver, ifindex);
device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver);
else if (is_wireless (udev_device))
device = (GObject *) nm_device_wifi_new (path, ifname, driver, ifindex);
device = (GObject *) nm_device_wifi_new (path, ifname, driver);
else
device = (GObject *) nm_device_ethernet_new (path, ifname, driver, ifindex);
device = (GObject *) nm_device_ethernet_new (path, ifname, driver);
out:
if (grandparent)

View file

@ -35,6 +35,7 @@ test_policy_hosts_CPPFLAGS = \
$(GLIB_CFLAGS)
test_policy_hosts_LDADD = \
-ldl \
$(top_builddir)/src/libtest-policy-hosts.la \
$(GLIB_LIBS)

View file

@ -45,7 +45,7 @@
#include "nm-dbus-glib-types.h"
#include "NetworkManagerUtils.h"
#include "nm-named-manager.h"
#include "nm-netlink.h"
#include "nm-netlink-monitor.h"
#include "nm-glib-compat.h"
#include "nm-vpn-connection-glue.h"
@ -69,6 +69,7 @@ typedef struct {
gulong device_ip4;
gboolean is_default;
gboolean is_default6;
NMActiveConnectionState state;
NMVPNConnectionState vpn_state;
@ -102,6 +103,7 @@ enum {
PROP_DEVICES,
PROP_STATE,
PROP_DEFAULT,
PROP_DEFAULT6,
PROP_VPN,
PROP_VPN_STATE,
PROP_BANNER,
@ -1052,6 +1054,9 @@ get_property (GObject *object, guint prop_id,
case PROP_DEFAULT:
g_value_set_boolean (value, priv->is_default);
break;
case PROP_DEFAULT6:
g_value_set_boolean (value, priv->is_default6);
break;
case PROP_VPN:
g_value_set_boolean (value, TRUE);
break;
@ -1122,7 +1127,14 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
(object_class, PROP_DEFAULT,
g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT,
"Default",
"Is the default active connection",
"Is the default IPv4 active connection",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_DEFAULT6,
g_param_spec_boolean (NM_ACTIVE_CONNECTION_DEFAULT6,
"Default6",
"Is the default IPv6 active connection",
FALSE,
G_PARAM_READABLE));
g_object_class_install_property

View file

@ -1215,7 +1215,10 @@ make_ip4_setting (shvarFile *ifcfg,
if (!tmp_ip4 && !tmp_prefix && !tmp_netmask) {
if (valid_ip6_config) {
/* Nope, no IPv4 */
goto done;
g_object_set (s_ip4,
NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
NULL);
return NM_SETTING (s_ip4);
}
method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;

View file

@ -2165,6 +2165,7 @@ test_read_wired_ipv6_only (void)
const char *expected_dns1 = "1:2:3:4::a";
NMIP6Address *ip6_addr;
struct in6_addr addr;
const char *method;
connection = connection_from_file (TEST_IFCFG_WIRED_IPV6_ONLY,
NULL,
@ -2217,11 +2218,18 @@ test_read_wired_ipv6_only (void)
/* ===== IPv4 SETTING ===== */
s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
ASSERT (s_ip4 == NULL,
"wired-ipv6-only-verify-ip4", "failed to verify %s: unexpected %s setting",
ASSERT (s_ip4 != NULL,
"wired-ipv6-only-verify-ip4", "failed to verify %s: missing %s setting",
TEST_IFCFG_WIRED_IPV6_MANUAL,
NM_SETTING_IP4_CONFIG_SETTING_NAME);
method = nm_setting_ip4_config_get_method (s_ip4);
ASSERT (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0,
"wired-ipv6-only-verify-ip4", "failed to verify %s: unexpected %s / %s key value",
TEST_IFCFG_WIRED_IPV6_MANUAL,
NM_SETTING_IP4_CONFIG_SETTING_NAME,
NM_SETTING_IP4_CONFIG_METHOD);
/* ===== IPv6 SETTING ===== */
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
@ -5408,6 +5416,7 @@ test_write_wired_static_ip6_only (void)
NMConnection *reread;
NMSettingConnection *s_con;
NMSettingWired *s_wired;
NMSettingIP4Config *s_ip4;
NMSettingIP6Config *s_ip6;
static unsigned char tmpmac[] = { 0x31, 0x33, 0x33, 0x37, 0xbe, 0xcd };
GByteArray *mac;
@ -5461,6 +5470,17 @@ test_write_wired_static_ip6_only (void)
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
g_byte_array_free (mac, TRUE);
/* IP4 setting */
s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
ASSERT (s_ip4 != NULL,
"wired-static-ip6-only-write", "failed to allocate new %s setting",
NM_SETTING_IP4_CONFIG_SETTING_NAME);
nm_connection_add_setting (connection, NM_SETTING (s_ip4));
g_object_set (s_ip4,
NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED,
NULL);
/* IP6 setting */
s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
ASSERT (s_ip6 != NULL,
@ -5517,9 +5537,6 @@ test_write_wired_static_ip6_only (void)
ASSERT (nm_connection_verify (reread, &error),
"wired-static-ip6-only-write-reread-verify", "failed to verify %s: %s", testfile, error->message);
ASSERT (nm_connection_get_setting (reread, NM_TYPE_SETTING_IP4_CONFIG) == NULL,
"wired-static-ip6-only-write-reread-verify", "unexpected IPv4 setting");
ASSERT (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT) == TRUE,
"wired-static-ip6-only-write", "written and re-read connection weren't the same.");

View file

@ -934,9 +934,17 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
guint32 i, num;
GString *searches;
gboolean success = FALSE;
const char *method = NULL;
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
if (!s_ip4) {
if (s_ip4)
method = nm_setting_ip4_config_get_method (s_ip4);
/* Missing IP4 setting is assumed to be DHCP */
if (!method)
method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
int result;
/* IPv4 disabled, clear IPv4 related parameters */

View file

@ -298,9 +298,9 @@ ip6_addr_writer (GKeyFile *file,
GValueArray *values = g_ptr_array_index (array, i);
char *key_name, *ip6_addr;
if (values->n_values % 2) {
nm_warning ("%s: error writing IP6 address %d; address array length"
" %d is not a multiple of 2.",
if (values->n_values != 3) {
nm_warning ("%s: error writing IP6 address %d (address array length "
"%d is not 3)",
__func__, i, values->n_values);
continue;
}