dhcp: add initial DHCPv6 support (managed mode only)

This commit is contained in:
Dan Williams
2010-01-14 00:45:10 -08:00
parent f094e0ad9d
commit a9e32f3c3b
7 changed files with 462 additions and 157 deletions

View File

@@ -37,6 +37,7 @@ noinst_LTLIBRARIES = libtest-dhcp.la
libtest_dhcp_la_SOURCES = \
nm-ip4-config.c \
nm-ip6-config.c \
nm-hostname-provider.c \
nm-dbus-manager.c

View File

@@ -375,6 +375,7 @@ typedef struct {
static DhcState state_table[] = {
{ DHC_NBI, "nbi" },
{ DHC_PREINIT, "preinit" },
{ DHC_PREINIT6,"preinit6" },
{ DHC_BOUND4, "bound" },
{ DHC_BOUND6, "bound6" },
{ DHC_IPV4LL, "ipv4ll" },
@@ -507,7 +508,8 @@ nm_dhcp_client_new_options (NMDHCPClient *self,
}
priv->state = new_state;
g_message ("DHCP: device %s state changed %s -> %s",
g_message ("DHCPv%c: device %s state changed %s -> %s",
priv->ipv6 ? '6' : '4',
priv->iface,
state_to_string (old_state),
state_to_string (priv->state));
@@ -524,14 +526,14 @@ nm_dhcp_client_new_options (NMDHCPClient *self,
typedef struct {
GHFunc func;
gpointer user_data;
} Dhcp4ForeachInfo;
} DhcpForeachInfo;
static void
iterate_dhcp4_config_option (gpointer key,
gpointer value,
gpointer user_data)
iterate_dhcp_config_option (gpointer key,
gpointer value,
gpointer user_data)
{
Dhcp4ForeachInfo *info = (Dhcp4ForeachInfo *) user_data;
DhcpForeachInfo *info = (DhcpForeachInfo *) user_data;
char *tmp_key = NULL;
const char **p;
static const char *filter_options[] = {
@@ -557,12 +559,12 @@ iterate_dhcp4_config_option (gpointer key,
}
gboolean
nm_dhcp_client_foreach_dhcp4_option (NMDHCPClient *self,
GHFunc func,
gpointer user_data)
nm_dhcp_client_foreach_option (NMDHCPClient *self,
GHFunc func,
gpointer user_data)
{
NMDHCPClientPrivate *priv;
Dhcp4ForeachInfo info = { NULL, NULL };
DhcpForeachInfo info = { NULL, NULL };
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
@@ -577,7 +579,7 @@ nm_dhcp_client_foreach_dhcp4_option (NMDHCPClient *self,
info.func = func;
info.user_data = user_data;
g_hash_table_foreach (priv->options, iterate_dhcp4_config_option, &info);
g_hash_table_foreach (priv->options, iterate_dhcp_config_option, &info);
return TRUE;
}
@@ -629,14 +631,14 @@ out:
}
static void
process_domain_search (NMIP4Config *ip4_config, const char *str)
process_domain_search (const char *str, GFunc add_func, gpointer user_data)
{
char **searches, **s;
char *unescaped, *p;
int i;
g_return_if_fail (str != NULL);
g_return_if_fail (ip4_config != NULL);
g_return_if_fail (add_func != NULL);
p = unescaped = g_strdup (str);
do {
@@ -658,7 +660,7 @@ process_domain_search (NMIP4Config *ip4_config, const char *str)
for (s = searches; *s; s++) {
if (strlen (*s)) {
g_message (" domain search '%s'", *s);
nm_ip4_config_add_search (ip4_config, *s);
add_func (*s, user_data);
}
}
g_strfreev (searches);
@@ -667,6 +669,12 @@ out:
g_free (unescaped);
}
static void
ip4_add_domain_search (gpointer data, gpointer user_data)
{
nm_ip4_config_add_search (NM_IP4_CONFIG (user_data), (const char *) data);
}
/* Given a table of DHCP options from the client, convert into an IP4Config */
static NMIP4Config *
ip4_options_to_config (NMDHCPClient *self)
@@ -789,7 +797,7 @@ ip4_options_to_config (NMDHCPClient *self)
str = g_hash_table_lookup (priv->options, "new_domain_search");
if (str)
process_domain_search (ip4_config, str);
process_domain_search (str, ip4_add_domain_search, ip4_config);
str = g_hash_table_lookup (priv->options, "new_netbios_name_servers");
if (str) {
@@ -848,6 +856,115 @@ nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test)
/********************************************/
static void
ip6_add_domain_search (gpointer data, gpointer user_data)
{
nm_ip6_config_add_search (NM_IP6_CONFIG (user_data), (const char *) data);
}
/* Given a table of DHCP options from the client, convert into an IP6Config */
static NMIP6Config *
ip6_options_to_config (NMDHCPClient *self)
{
NMDHCPClientPrivate *priv;
NMIP6Config *ip6_config = NULL;
struct in6_addr tmp_addr;
NMIP6Address *addr = NULL;
char *str = NULL;
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
g_return_val_if_fail (priv->options != NULL, NULL);
ip6_config = nm_ip6_config_new ();
if (!ip6_config) {
g_warning ("%s: couldn't allocate memory for an IP6Config!", priv->iface);
return NULL;
}
addr = nm_ip6_address_new ();
if (!addr) {
g_warning ("%s: couldn't allocate memory for an IP6 Address!", priv->iface);
goto error;
}
str = g_hash_table_lookup (priv->options, "new_ip6_address");
if (str && (inet_pton (AF_INET6, str, &tmp_addr) > 0)) {
nm_ip6_address_set_address (addr, &tmp_addr);
g_message (" address %s", str);
} else
goto error;
str = g_hash_table_lookup (priv->options, "new_ip6_prefixlen");
if (str) {
long unsigned int prefix;
errno = 0;
prefix = strtoul (str, NULL, 10);
if (errno != 0 || prefix > 128)
goto error;
nm_ip6_address_set_prefix (addr, (guint32) prefix);
g_message (" prefix %lu", prefix);
}
nm_ip6_config_take_address (ip6_config, addr);
addr = NULL;
str = g_hash_table_lookup (priv->options, "new_host_name");
if (str)
g_message (" hostname '%s'", str);
str = g_hash_table_lookup (priv->options, "new_dhcp6_name_servers");
if (str) {
char **searches = g_strsplit (str, " ", 0);
char **s;
for (s = searches; *s; s++) {
if (inet_pton (AF_INET6, *s, &tmp_addr) > 0) {
nm_ip6_config_add_nameserver (ip6_config, &tmp_addr);
g_message (" nameserver '%s'", *s);
} else
g_warning ("Ignoring invalid nameserver '%s'", *s);
}
g_strfreev (searches);
}
str = g_hash_table_lookup (priv->options, "new_dhcp6_domain_search");
if (str)
process_domain_search (str, ip6_add_domain_search, ip6_config);
return ip6_config;
error:
if (addr)
nm_ip6_address_unref (addr);
g_object_unref (ip6_config);
return NULL;
}
NMIP6Config *
nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test)
{
NMDHCPClientPrivate *priv;
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
priv = NM_DHCP_CLIENT_GET_PRIVATE (self);
if (test && !state_is_bound (priv->state)) {
g_warning ("%s: dhcp client didn't bind to a lease.", priv->iface);
return NULL;
}
return ip6_options_to_config (self);
}
/********************************************/
static void
nm_dhcp_client_init (NMDHCPClient *self)
{

View File

@@ -25,6 +25,7 @@
#include <nm-setting-ip4-config.h>
#include <nm-setting-ip6-config.h>
#include <nm-ip4-config.h>
#include <nm-ip6-config.h>
#define NM_TYPE_DHCP_CLIENT (nm_dhcp_client_get_type ())
#define NM_DHCP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_CLIENT, NMDHCPClient))
@@ -41,6 +42,7 @@
typedef enum {
DHC_NBI = 0, /* no broadcast interfaces found */
DHC_PREINIT, /* configuration started */
DHC_PREINIT6, /* configuration started */
DHC_BOUND4, /* IPv4 lease obtained */
DHC_BOUND6, /* IPv6 lease obtained */
DHC_IPV4LL, /* IPv4LL address obtained */
@@ -119,12 +121,14 @@ void nm_dhcp_client_new_options (NMDHCPClient *self,
GHashTable *options,
const char *reason);
gboolean nm_dhcp_client_foreach_dhcp4_option (NMDHCPClient *self,
GHFunc func,
gpointer user_data);
gboolean nm_dhcp_client_foreach_option (NMDHCPClient *self,
GHFunc func,
gpointer user_data);
NMIP4Config *nm_dhcp_client_get_ip4_config (NMDHCPClient *self, gboolean test);
NMIP6Config *nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test);
/* Backend helpers */
void nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name);

View File

@@ -137,6 +137,14 @@ nm_device_interface_init (gpointer g_iface)
DBUS_TYPE_G_OBJECT_PATH,
G_PARAM_READWRITE));
g_object_interface_install_property
(g_iface,
g_param_spec_boxed (NM_DEVICE_INTERFACE_DHCP6_CONFIG,
"DHCP6 Config",
"DHCP6 Config",
DBUS_TYPE_G_OBJECT_PATH,
G_PARAM_READWRITE));
g_object_interface_install_property
(g_iface,
g_param_spec_uint (NM_DEVICE_INTERFACE_STATE,

View File

@@ -53,6 +53,7 @@ typedef enum
#define NM_DEVICE_INTERFACE_IP4_CONFIG "ip4-config"
#define NM_DEVICE_INTERFACE_DHCP4_CONFIG "dhcp4-config"
#define NM_DEVICE_INTERFACE_IP6_CONFIG "ip6-config"
#define NM_DEVICE_INTERFACE_DHCP6_CONFIG "dhcp6-config"
#define NM_DEVICE_INTERFACE_STATE "state"
#define NM_DEVICE_INTERFACE_DEVICE_TYPE "device-type" /* ugh */
#define NM_DEVICE_INTERFACE_MANAGED "managed"
@@ -69,6 +70,7 @@ typedef enum {
NM_DEVICE_INTERFACE_PROP_IP4_CONFIG,
NM_DEVICE_INTERFACE_PROP_DHCP4_CONFIG,
NM_DEVICE_INTERFACE_PROP_IP6_CONFIG,
NM_DEVICE_INTERFACE_PROP_DHCP6_CONFIG,
NM_DEVICE_INTERFACE_PROP_STATE,
NM_DEVICE_INTERFACE_PROP_DEVICE_TYPE,
NM_DEVICE_INTERFACE_PROP_MANAGED,

View File

@@ -131,6 +131,11 @@ typedef struct {
gulong ip6_config_changed_sigid;
gboolean ip6_waiting_for_config;
NMDHCPClient * dhcp6_client;
gulong dhcp6_state_sigid;
gulong dhcp6_timeout_sigid;
NMDHCP6Config * dhcp6_config;
/* inhibit autoconnect feature */
gboolean autoconnect_inhibit;
} NMDevicePrivate;
@@ -566,49 +571,57 @@ ip6_config_changed (NMIP6Manager *ip6_manager,
nm_device_activate_schedule_stage4_ip6_config_get (self);
}
static void
nm_device_setup_ip6 (NMDevice *self)
static gboolean
ip6_method_matches (NMConnection *connection, const char *match)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActRequest *req;
NMConnection *connection;
const char *ip_iface, *method = NULL;
NMSettingIP6Config *s_ip6;
req = nm_device_get_act_request (self);
if (!req)
return;
connection = nm_act_request_get_connection (req);
if (!connection)
return;
const char *method = NULL;
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
if (s_ip6)
method = nm_setting_ip6_config_get_method (s_ip6);
if (!method || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE))
return method && !strcmp (method, match);
}
static void
addrconf6_setup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActRequest *req;
NMConnection *connection;
const char *ip_iface;
NMSettingIP6Config *s_ip6;
priv->ip6_waiting_for_config = FALSE;
req = nm_device_get_act_request (self);
g_assert (req);
connection = nm_act_request_get_connection (req);
g_assert (connection);
if (!ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO))
return;
if (!priv->ip6_manager) {
priv->ip6_manager = nm_ip6_manager_get ();
priv->ip6_addrconf_sigid = g_signal_connect (priv->ip6_manager,
"addrconf-complete",
G_CALLBACK (ip6_addrconf_complete),
self);
"addrconf-complete",
G_CALLBACK (ip6_addrconf_complete),
self);
priv->ip6_config_changed_sigid = g_signal_connect (priv->ip6_manager,
"config-changed",
G_CALLBACK (ip6_config_changed),
self);
"config-changed",
G_CALLBACK (ip6_config_changed),
self);
}
priv->ip6_waiting_for_config = FALSE;
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);
}
static void
nm_device_cleanup_ip6 (NMDevice *self)
addrconf6_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
@@ -630,6 +643,13 @@ nm_device_cleanup_ip6 (NMDevice *self)
priv->ip6_manager = NULL;
}
static NMActStageReturn
real_act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason)
{
addrconf6_setup (self);
return NM_ACT_STAGE_RETURN_SUCCESS;
}
/*
* nm_device_activate_stage1_device_prepare
*
@@ -651,8 +671,6 @@ nm_device_activate_stage1_device_prepare (gpointer user_data)
nm_info ("Activation (%s) Stage 1 of 5 (Device Prepare) started...", iface);
nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
nm_device_setup_ip6 (self);
ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, &reason);
if (ret == NM_ACT_STAGE_RETURN_POSTPONE) {
goto out;
@@ -692,13 +710,6 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self)
nm_device_get_iface (self));
}
static NMActStageReturn
real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
/* Nothing to do */
return NM_ACT_STAGE_RETURN_SUCCESS;
}
static NMActStageReturn
real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason)
{
@@ -1071,42 +1082,76 @@ dhcp4_add_option_cb (gpointer key, gpointer value, gpointer user_data)
}
static void
handle_dhcp_lease_change (NMDevice *device)
dhcp6_add_option_cb (gpointer key, gpointer value, gpointer user_data)
{
nm_dhcp6_config_add_option (NM_DHCP6_CONFIG (user_data),
(const char *) key,
(const char *) value);
}
static void
handle_dhcp_lease_change (NMDevice *device, gboolean ipv6)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
NMIP4Config *config;
NMIP4Config *ip4_config;
NMSettingIP4Config *s_ip4;
NMIP6Config *ip6_config;
NMSettingIP6Config *s_ip6;
NMConnection *connection;
NMActRequest *req;
NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
gboolean assumed;
config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
if (!config) {
nm_warning ("failed to get DHCP config for rebind");
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
return;
}
req = nm_device_get_act_request (device);
g_assert (req);
connection = nm_act_request_get_connection (req);
g_assert (connection);
s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
nm_utils_merge_ip4_config (config, s_ip4);
g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, config);
assumed = nm_act_request_get_assumed (req);
if (nm_device_set_ip4_config (device, config, assumed, &reason)) {
nm_dhcp4_config_reset (priv->dhcp4_config);
nm_dhcp_client_foreach_dhcp4_option (priv->dhcp4_client,
dhcp4_add_option_cb,
priv->dhcp4_config);
if (ipv6) {
ip6_config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
if (!ip6_config) {
nm_warning ("failed to get DHCPv6 config for rebind");
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
return;
}
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
nm_utils_merge_ip6_config (ip6_config, s_ip6);
g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
if (nm_device_set_ip6_config (device, ip6_config, assumed, &reason)) {
nm_dhcp6_config_reset (priv->dhcp6_config);
nm_dhcp_client_foreach_option (priv->dhcp6_client,
dhcp6_add_option_cb,
priv->dhcp6_config);
} else {
nm_warning ("Failed to update IPv6 config in response to DHCP event.");
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
}
} else {
nm_warning ("Failed to update IP4 config in response to DHCP event.");
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
ip4_config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
if (!ip4_config) {
nm_warning ("failed to get DHCPv4 config for rebind");
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
return;
}
s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG));
nm_utils_merge_ip4_config (ip4_config, s_ip4);
g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP4_CONFIG, ip4_config);
if (nm_device_set_ip4_config (device, ip4_config, assumed, &reason)) {
nm_dhcp4_config_reset (priv->dhcp4_config);
nm_dhcp_client_foreach_option (priv->dhcp4_client,
dhcp4_add_option_cb,
priv->dhcp4_config);
} else {
nm_warning ("Failed to update IPv4 config in response to DHCP event.");
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
}
}
}
@@ -1118,32 +1163,45 @@ dhcp_state_changed (NMDHCPClient *client,
NMDevice *device = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
NMDeviceState dev_state;
gboolean ipv6;
if (!nm_device_get_act_request (device))
return;
ipv6 = nm_dhcp_client_get_ipv6 (client);
dev_state = nm_device_get_state (device);
switch (state) {
case DHC_BOUND4: /* lease obtained */
case DHC_BOUND6:
case DHC_RENEW4: /* lease renewed */
case DHC_RENEW6: /* lease renewed */
case DHC_REBOOT: /* have valid lease, but now obtained a different one */
case DHC_REBIND4: /* new, different lease */
if (dev_state == NM_DEVICE_STATE_IP_CONFIG)
nm_device_activate_schedule_stage4_ip4_config_get (device);
else if (dev_state == NM_DEVICE_STATE_ACTIVATED)
handle_dhcp_lease_change (device);
case DHC_REBIND6: /* new, different lease */
if (dev_state == NM_DEVICE_STATE_IP_CONFIG) {
if (ipv6)
nm_device_activate_schedule_stage4_ip6_config_get (device);
else
nm_device_activate_schedule_stage4_ip4_config_get (device);
} else if (dev_state == NM_DEVICE_STATE_ACTIVATED)
handle_dhcp_lease_change (device, ipv6);
break;
case DHC_TIMEOUT: /* timed out contacting DHCP server */
nm_dhcp4_config_reset (priv->dhcp4_config);
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
nm_device_activate_schedule_stage4_ip4_config_timeout (device);
if (ipv6) {
nm_dhcp6_config_reset (priv->dhcp6_config);
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
nm_device_activate_schedule_stage4_ip6_config_timeout (device);
} else {
nm_dhcp4_config_reset (priv->dhcp4_config);
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
nm_device_activate_schedule_stage4_ip4_config_timeout (device);
}
break;
case DHC_FAIL: /* all attempts to contact server timed out, sleeping */
case DHC_ABEND: /* dhclient exited abnormally */
case DHC_END: /* dhclient exited normally */
nm_dhcp4_config_reset (priv->dhcp4_config);
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 */
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
@@ -1164,8 +1222,12 @@ dhcp_timeout (NMDHCPClient *client, gpointer user_data)
if (!nm_device_get_act_request (device))
return;
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG)
nm_device_activate_schedule_stage4_ip4_config_timeout (device);
if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
if (nm_dhcp_client_get_ipv6 (client))
nm_device_activate_schedule_stage4_ip6_config_timeout (device);
else
nm_device_activate_schedule_stage4_ip4_config_timeout (device);
}
}
static NMActStageReturn
@@ -1213,8 +1275,6 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
g_object_unref (priv->dhcp4_config);
priv->dhcp4_config = nm_dhcp4_config_new ();
/* DHCP manager will cancel any transaction already in progress and we do not
want to cancel this activation if we get "down" state from that. */
priv->dhcp4_client = nm_dhcp_manager_start_ip4 (priv->dhcp_manager,
ip_iface,
uuid,
@@ -1265,20 +1325,70 @@ static NMActStageReturn
real_act_stage3_ip6_config_start (NMDevice *self, NMDeviceStateReason *reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *ip_iface = nm_device_get_ip_iface (self);
const char *ip_iface, *uuid;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
NMActRequest *req;
NMConnection *connection;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
/* If we are ignoring IPv6 on this interface then we can go right
* to stage 4.
*/
if (!priv->ip6_manager)
return NM_ACT_STAGE_RETURN_SUCCESS;
req = nm_device_get_act_request (self);
g_assert (req);
connection = nm_act_request_get_connection (req);
g_assert (connection);
priv->ip6_waiting_for_config = TRUE;
nm_ip6_manager_begin_addrconf (priv->ip6_manager, ip_iface);
ip_iface = nm_device_get_ip_iface (self);
return NM_ACT_STAGE_RETURN_POSTPONE;
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);
ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
guint8 *anycast = NULL;
NMSettingIP6Config *s_ip6;
NMSettingConnection *s_con;
/* Begin a DHCP transaction on the interface */
if (priv->dhcp_anycast_address)
anycast = priv->dhcp_anycast_address->data;
/* Clear old exported DHCP options */
if (priv->dhcp6_config)
g_object_unref (priv->dhcp6_config);
priv->dhcp6_config = nm_dhcp6_config_new ();
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
uuid = nm_setting_connection_get_uuid (s_con);
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
priv->dhcp6_client = nm_dhcp_manager_start_ip6 (priv->dhcp_manager,
ip_iface,
uuid,
s_ip6,
priv->dhcp_timeout,
anycast);
if (priv->dhcp6_client) {
priv->dhcp6_state_sigid = g_signal_connect (priv->dhcp6_client,
"state-changed",
G_CALLBACK (dhcp_state_changed),
self);
priv->dhcp6_timeout_sigid = g_signal_connect (priv->dhcp6_client,
"timeout",
G_CALLBACK (dhcp_timeout),
self);
/* DHCP devices will be notified by the DHCP manager when stuff happens */
ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else {
*reason = NM_DEVICE_STATE_REASON_DHCP_START_FAILED;
ret = NM_ACT_STAGE_RETURN_FAILURE;
}
}
return ret;
}
@@ -1439,9 +1549,9 @@ real_act_stage4_get_ip4_config (NMDevice *self,
nm_utils_merge_ip4_config (*config, s_ip4);
nm_dhcp4_config_reset (priv->dhcp4_config);
nm_dhcp_client_foreach_dhcp4_option (priv->dhcp4_client,
dhcp4_add_option_cb,
priv->dhcp4_config);
nm_dhcp_client_foreach_option (priv->dhcp4_client,
dhcp4_add_option_cb,
priv->dhcp4_config);
/* Notify of new DHCP4 config */
g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP4_CONFIG);
@@ -1632,11 +1742,11 @@ real_act_stage4_get_ip6_config (NMDevice *self,
NMIP6Config **config,
NMDeviceStateReason *reason)
{
NMDevicePrivate *priv;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
NMConnection *connection;
NMSettingIP6Config *s_ip6;
const char *ip_iface;
const char *method = NULL;
g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
@@ -1649,25 +1759,41 @@ real_act_stage4_get_ip6_config (NMDevice *self,
g_assert (connection);
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
if (s_ip6)
method = nm_setting_ip6_config_get_method (s_ip6);
if (!method || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) {
*config = nm_ip6_manager_get_ip6_config (priv->ip6_manager, ip_iface);
if (*config) {
/* Merge user-defined overrides into the IP6Config to be applied */
nm_utils_merge_ip6_config (*config, s_ip6);
ret = NM_ACT_STAGE_RETURN_SUCCESS;
} else {
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
}
} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
g_assert (priv->dhcp6_client);
*config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
if (*config) {
/* Merge user-defined overrides into the IP4Config to be applied */
nm_utils_merge_ip6_config (*config, s_ip6);
nm_dhcp6_config_reset (priv->dhcp6_config);
nm_dhcp_client_foreach_option (priv->dhcp6_client,
dhcp6_add_option_cb,
priv->dhcp6_config);
/* Notify of new DHCP4 config */
g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG);
ret = NM_ACT_STAGE_RETURN_SUCCESS;
} else {
*reason = NM_DEVICE_STATE_REASON_DHCP_ERROR;
}
} else {
*config = NULL;
return NM_ACT_STAGE_RETURN_SUCCESS;
ret = NM_ACT_STAGE_RETURN_SUCCESS;
}
priv = NM_DEVICE_GET_PRIVATE (self);
*config = nm_ip6_manager_get_ip6_config (priv->ip6_manager, ip_iface);
if (!*config) {
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
return NM_ACT_STAGE_RETURN_FAILURE;
}
/* Merge user-defined overrides into the IP6Config to be applied */
nm_utils_merge_ip6_config (*config, s_ip6);
return NM_ACT_STAGE_RETURN_SUCCESS;
return ret;
}
/*
@@ -1743,6 +1869,9 @@ real_act_stage4_ip6_config_timeout (NMDevice *self,
g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
/* Notify of invalid DHCP6 config object */
g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG);
*reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE;
return NM_ACT_STAGE_RETURN_FAILURE;
}
@@ -2135,6 +2264,54 @@ dhcp4_cleanup (NMDevice *self, gboolean stop)
}
}
static void
dhcp6_cleanup (NMDevice *self, gboolean stop)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->dhcp6_config) {
g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG);
g_object_unref (priv->dhcp6_config);
priv->dhcp6_config = NULL;
}
if (priv->dhcp6_client) {
if (priv->dhcp6_state_sigid) {
g_signal_handler_disconnect (priv->dhcp6_client, priv->dhcp6_state_sigid);
priv->dhcp6_state_sigid = 0;
}
if (priv->dhcp6_timeout_sigid) {
g_signal_handler_disconnect (priv->dhcp6_client, priv->dhcp6_timeout_sigid);
priv->dhcp6_timeout_sigid = 0;
}
if (stop)
nm_dhcp_client_stop (priv->dhcp6_client);
g_object_unref (priv->dhcp6_client);
priv->dhcp6_client = NULL;
}
}
static void
dnsmasq_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
if (!priv->dnsmasq_manager)
return;
if (priv->dnsmasq_state_id) {
g_signal_handler_disconnect (priv->dnsmasq_manager, priv->dnsmasq_state_id);
priv->dnsmasq_state_id = 0;
}
nm_dnsmasq_manager_stop (priv->dnsmasq_manager);
g_object_unref (priv->dnsmasq_manager);
priv->dnsmasq_manager = NULL;
}
/*
* nm_device_deactivate_quickly
*
@@ -2159,24 +2336,11 @@ nm_device_deactivate_quickly (NMDevice *self)
/* Clear any delayed transitions */
delayed_transitions_clear (self);
if (nm_device_get_act_request (self)) {
dhcp4_cleanup (self, TRUE);
if (priv->dnsmasq_manager) {
/* Or any shared connection */
if (priv->dnsmasq_state_id) {
g_signal_handler_disconnect (priv->dnsmasq_manager, priv->dnsmasq_state_id);
priv->dnsmasq_state_id = 0;
}
nm_dnsmasq_manager_stop (priv->dnsmasq_manager);
g_object_unref (priv->dnsmasq_manager);
priv->dnsmasq_manager = NULL;
}
}
dhcp4_cleanup (self, TRUE);
dhcp6_cleanup (self, TRUE);
addrconf6_cleanup (self);
dnsmasq_cleanup (self);
aipd_cleanup (self);
nm_device_cleanup_ip6 (self);
/* Call device type-specific deactivation */
if (NM_DEVICE_GET_CLASS (self)->deactivate_quickly)
@@ -2395,21 +2559,17 @@ nm_device_can_interrupt_activation (NMDevice *self)
NMDHCP4Config *
nm_device_get_dhcp4_config (NMDevice *self)
{
NMDevicePrivate *priv;
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
if (priv->dhcp_manager)
return priv->dhcp4_config;
return NULL;
return NM_DEVICE_GET_PRIVATE (self)->dhcp4_config;
}
NMIP4Config *
nm_device_get_ip4_config (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->ip4_config;
}
@@ -2579,10 +2739,20 @@ nm_device_set_ip6_config (NMDevice *self,
return success;
}
NMDHCP6Config *
nm_device_get_dhcp6_config (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->dhcp6_config;
}
NMIP6Config *
nm_device_get_ip6_config (NMDevice *self)
{
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
return NM_DEVICE_GET_PRIVATE (self)->ip6_config;
}
@@ -2740,8 +2910,11 @@ dispose (GObject *object)
/* Clean up and stop DHCP */
dhcp4_cleanup (self, take_down);
dhcp6_cleanup (self, take_down);
addrconf6_cleanup (self);
dnsmasq_cleanup (self);
/* Take the device itself down and clear it's IPv4 configuration */
/* Take the device itself down and clear its IPv4 configuration */
if (priv->managed && take_down) {
NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
@@ -2749,23 +2922,10 @@ dispose (GObject *object)
nm_device_set_ip4_config (self, NULL, FALSE, &ignored);
}
clear_act_request (self);
activation_source_clear (self, TRUE, AF_INET);
activation_source_clear (self, TRUE, AF_INET6);
nm_device_cleanup_ip6 (self);
if (priv->dnsmasq_manager) {
if (priv->dnsmasq_state_id) {
g_signal_handler_disconnect (priv->dnsmasq_manager, priv->dnsmasq_state_id);
priv->dnsmasq_state_id = 0;
}
nm_dnsmasq_manager_stop (priv->dnsmasq_manager);
g_object_unref (priv->dnsmasq_manager);
priv->dnsmasq_manager = NULL;
}
clear_act_request (self);
out:
G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
@@ -2883,6 +3043,13 @@ get_property (GObject *object, guint prop_id,
}
g_value_set_boxed (value, "/");
break;
case NM_DEVICE_INTERFACE_PROP_DHCP6_CONFIG:
if ( ((state == NM_DEVICE_STATE_ACTIVATED) || (state == NM_DEVICE_STATE_IP_CONFIG))
&& priv->dhcp6_client)
g_value_set_boxed (value, nm_dhcp6_config_get_dbus_path (priv->dhcp6_config));
else
g_value_set_boxed (value, "/");
break;
case NM_DEVICE_INTERFACE_PROP_STATE:
g_value_set_uint (value, priv->state);
break;
@@ -2961,6 +3128,10 @@ nm_device_class_init (NMDeviceClass *klass)
NM_DEVICE_INTERFACE_PROP_IP6_CONFIG,
NM_DEVICE_INTERFACE_IP6_CONFIG);
g_object_class_override_property (object_class,
NM_DEVICE_INTERFACE_PROP_DHCP6_CONFIG,
NM_DEVICE_INTERFACE_DHCP6_CONFIG);
g_object_class_override_property (object_class,
NM_DEVICE_INTERFACE_PROP_STATE,
NM_DEVICE_INTERFACE_STATE);

View File

@@ -31,6 +31,7 @@
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
#include "nm-dhcp4-config.h"
#include "nm-dhcp6-config.h"
#include "nm-connection.h"
typedef enum NMActStageReturn
@@ -141,6 +142,7 @@ guint32 nm_device_get_ip4_address (NMDevice *dev);
void nm_device_update_ip4_address (NMDevice *dev);
NMDHCP4Config * nm_device_get_dhcp4_config (NMDevice *dev);
NMDHCP6Config * nm_device_get_dhcp6_config (NMDevice *dev);
NMIP4Config * nm_device_get_ip4_config (NMDevice *dev);
NMIP6Config * nm_device_get_ip6_config (NMDevice *dev);