diff --git a/src/Makefile.am b/src/Makefile.am index 7111ac3e5..db255ca35 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 382b7d4a9..03373d717 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -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) { diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index 8b5804f41..50c49bbc8 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -25,6 +25,7 @@ #include #include #include +#include #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); diff --git a/src/nm-device-interface.c b/src/nm-device-interface.c index 70cce8b62..f0a4fd1c6 100644 --- a/src/nm-device-interface.c +++ b/src/nm-device-interface.c @@ -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, diff --git a/src/nm-device-interface.h b/src/nm-device-interface.h index 0ec5e3da1..306f2dbe6 100644 --- a/src/nm-device-interface.h +++ b/src/nm-device-interface.h @@ -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, diff --git a/src/nm-device.c b/src/nm-device.c index 4f4a43d87..daf3d111c 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -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); diff --git a/src/nm-device.h b/src/nm-device.h index 6300be535..5fcde5c33 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -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);