summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/devices/nm-device.c3
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c43
-rw-r--r--src/dhcp-manager/nm-dhcp-client.h7
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient.c14
-rw-r--r--src/dhcp-manager/nm-dhcp-dhcpcd.c3
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.c12
-rw-r--r--src/dhcp-manager/nm-dhcp-manager.h3
-rw-r--r--src/dhcp-manager/nm-dhcp-systemd.c10
-rw-r--r--src/dhcp-manager/nm-dhcp-utils.c48
-rw-r--r--src/dhcp-manager/nm-dhcp-utils.h2
10 files changed, 117 insertions, 28 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 2c4d4421b5..4269bc8ada 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -5992,7 +5992,8 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
priv->dhcp_timeout,
priv->dhcp_anycast_address,
(priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE,
- nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)));
+ nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)),
+ 0);
if (tmp)
g_byte_array_free (tmp, TRUE);
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 15eb7a9f09..ec981e0ead 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -41,6 +41,7 @@
enum {
SIGNAL_STATE_CHANGED,
+ SIGNAL_PREFIX_DELEGATED,
LAST_SIGNAL
};
@@ -511,7 +512,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
const struct in6_addr *ll_addr,
const char *hostname,
gboolean info_only,
- NMSettingIP6ConfigPrivacy privacy)
+ NMSettingIP6ConfigPrivacy privacy,
+ guint needed_prefixes)
{
NMDhcpClientPrivate *priv;
gs_free char *str = NULL;
@@ -544,7 +546,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self,
ll_addr,
info_only,
privacy,
- priv->duid);
+ priv->duid,
+ needed_prefixes);
}
void
@@ -709,6 +712,7 @@ nm_dhcp_client_handle_event (gpointer unused,
guint32 new_state;
GHashTable *str_options = NULL;
GObject *ip_config = NULL;
+ NMPlatformIP6Address prefix = { 0, };
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE);
g_return_val_if_fail (iface != NULL, FALSE);
@@ -754,6 +758,7 @@ nm_dhcp_client_handle_event (gpointer unused,
g_warn_if_fail (g_hash_table_size (str_options));
if (g_hash_table_size (str_options)) {
if (priv->ipv6) {
+ prefix = nm_dhcp_utils_ip6_prefix_from_options (str_options);
ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (priv->ifindex,
priv->iface,
str_options,
@@ -765,17 +770,26 @@ nm_dhcp_client_handle_event (gpointer unused,
str_options,
priv->priority);
}
-
- /* Fail if no valid IP config was received */
- if (ip_config == NULL) {
- _LOGW ("client bound but IP config not received");
- new_state = NM_DHCP_STATE_FAIL;
- g_clear_pointer (&str_options, g_hash_table_unref);
- }
}
}
- nm_dhcp_client_set_state (self, new_state, ip_config, str_options);
+ if (!IN6_IS_ADDR_UNSPECIFIED (&prefix.address)) {
+ /* If we got an IPv6 prefix to delegate, we don't change the state
+ * of the DHCP client instance. Instead, we just signal the prefix
+ * to the device. */
+ g_signal_emit (G_OBJECT (self),
+ signals[SIGNAL_PREFIX_DELEGATED], 0,
+ &prefix);
+ } else {
+ /* Fail if no valid IP config was received */
+ if (new_state == NM_DHCP_STATE_BOUND && ip_config == NULL) {
+ _LOGW ("client bound but IP config not received");
+ new_state = NM_DHCP_STATE_FAIL;
+ g_clear_pointer (&str_options, g_hash_table_unref);
+ }
+
+ nm_dhcp_client_set_state (self, new_state, ip_config, str_options);
+ }
if (str_options)
g_hash_table_destroy (str_options);
@@ -972,5 +986,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
G_STRUCT_OFFSET (NMDhcpClientClass, state_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_HASH_TABLE, G_TYPE_STRING);
-}
+ signals[SIGNAL_PREFIX_DELEGATED] =
+ g_signal_new (NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMDhcpClientClass, state_changed),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+}
diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h
index 9a2d21f713..7a083ae7a3 100644
--- a/src/dhcp-manager/nm-dhcp-client.h
+++ b/src/dhcp-manager/nm-dhcp-client.h
@@ -40,6 +40,7 @@
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed"
+#define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated"
typedef enum {
NM_DHCP_STATE_UNKNOWN = 0,
@@ -73,7 +74,8 @@ typedef struct {
const struct in6_addr *ll_addr,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
- const GByteArray *duid);
+ const GByteArray *duid,
+ guint needed_prefixes);
void (*stop) (NMDhcpClient *self,
gboolean release,
@@ -133,7 +135,8 @@ gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self,
const struct in6_addr *ll_addr,
const char *hostname,
gboolean info_only,
- NMSettingIP6ConfigPrivacy privacy);
+ NMSettingIP6ConfigPrivacy privacy,
+ guint needed_prefixes);
void nm_dhcp_client_stop (NMDhcpClient *self, gboolean release);
diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c
index a055e54179..64d93744f2 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient.c
@@ -330,7 +330,8 @@ dhclient_start (NMDhcpClient *client,
const char *mode_opt,
const GByteArray *duid,
gboolean release,
- pid_t *out_pid)
+ pid_t *out_pid,
+ int prefixes)
{
NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client);
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
@@ -424,6 +425,8 @@ dhclient_start (NMDhcpClient *client,
g_ptr_array_add (argv, (gpointer) "-6");
if (mode_opt)
g_ptr_array_add (argv, (gpointer) mode_opt);
+ while (prefixes--)
+ g_ptr_array_add (argv, (gpointer) "-P");
}
g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */
g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path);
@@ -503,7 +506,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last
if (priv->conf_file) {
if (new_client_id)
nm_dhcp_client_set_client_id (client, new_client_id);
- success = dhclient_start (client, NULL, NULL, FALSE, NULL);
+ success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0);
} else
_LOGW ("error creating dhclient configuration file");
@@ -516,7 +519,8 @@ ip6_start (NMDhcpClient *client,
const struct in6_addr *ll_addr,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
- const GByteArray *duid)
+ const GByteArray *duid,
+ guint needed_prefixes)
{
NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client);
NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self);
@@ -532,7 +536,7 @@ ip6_start (NMDhcpClient *client,
return FALSE;
}
- return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL);
+ return dhclient_start (client, info_only ? "-S" : "-N", duid, FALSE, NULL, needed_prefixes);
}
static void
@@ -557,7 +561,7 @@ stop (NMDhcpClient *client, gboolean release, const GByteArray *duid)
if (release) {
pid_t rpid = -1;
- if (dhclient_start (client, NULL, duid, TRUE, &rpid)) {
+ if (dhclient_start (client, NULL, duid, TRUE, &rpid, 0)) {
/* Wait a few seconds for the release to happen */
nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client));
}
diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c
index 6b7fe38bbf..c8643881fc 100644
--- a/src/dhcp-manager/nm-dhcp-dhcpcd.c
+++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c
@@ -185,7 +185,8 @@ ip6_start (NMDhcpClient *client,
const struct in6_addr *ll_addr,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
- const GByteArray *duid)
+ const GByteArray *duid,
+ guint needed_prefixes)
{
NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client);
diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c
index dee4039a5c..6cb5c105b9 100644
--- a/src/dhcp-manager/nm-dhcp-manager.c
+++ b/src/dhcp-manager/nm-dhcp-manager.c
@@ -166,7 +166,8 @@ client_start (NMDhcpManager *self,
const char *fqdn,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
- const char *last_ip4_address)
+ const char *last_ip4_address,
+ guint needed_prefixes)
{
NMDhcpManagerPrivate *priv;
NMDhcpClient *client;
@@ -206,7 +207,7 @@ client_start (NMDhcpManager *self,
g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self);
if (ipv6)
- success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy);
+ success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy, needed_prefixes);
else
success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, fqdn, last_ip4_address);
@@ -254,7 +255,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
}
return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL,
dhcp_client_id, timeout, dhcp_anycast_addr, hostname,
- fqdn, FALSE, 0, last_ip_address);
+ fqdn, FALSE, 0, last_ip_address, 0);
}
/* Caller owns a reference to the NMDhcpClient on return */
@@ -271,7 +272,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
guint32 timeout,
const char *dhcp_anycast_addr,
gboolean info_only,
- NMSettingIP6ConfigPrivacy privacy)
+ NMSettingIP6ConfigPrivacy privacy,
+ guint needed_prefixes)
{
const char *hostname = NULL;
@@ -281,7 +283,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
hostname = get_send_hostname (self, dhcp_hostname);
return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE,
ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, NULL, info_only,
- privacy, NULL);
+ privacy, NULL, needed_prefixes);
}
void
diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h
index e525180d43..a948b60970 100644
--- a/src/dhcp-manager/nm-dhcp-manager.h
+++ b/src/dhcp-manager/nm-dhcp-manager.h
@@ -69,7 +69,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
guint32 timeout,
const char *dhcp_anycast_addr,
gboolean info_only,
- NMSettingIP6ConfigPrivacy privacy);
+ NMSettingIP6ConfigPrivacy privacy,
+ guint needed_prefixes);
GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self,
const char *iface,
diff --git a/src/dhcp-manager/nm-dhcp-systemd.c b/src/dhcp-manager/nm-dhcp-systemd.c
index 4e3f85deb9..b6c9e27c17 100644
--- a/src/dhcp-manager/nm-dhcp-systemd.c
+++ b/src/dhcp-manager/nm-dhcp-systemd.c
@@ -894,7 +894,8 @@ ip6_start (NMDhcpClient *client,
const struct in6_addr *ll_addr,
gboolean info_only,
NMSettingIP6ConfigPrivacy privacy,
- const GByteArray *duid)
+ const GByteArray *duid,
+ guint needed_prefixes)
{
NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client);
NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
@@ -916,7 +917,12 @@ ip6_start (NMDhcpClient *client,
return FALSE;
}
- _LOGT ("dhcp-client6: set %p", priv->client4);
+ if (needed_prefixes > 0) {
+ _LOGW ("dhcp-client6: prefix delegation not yet supported, won't supply %d prefixes\n",
+ needed_prefixes);
+ }
+
+ _LOGT ("dhcp-client6: set %p", priv->client6);
if (info_only)
sd_dhcp6_client_set_information_request (priv->client6, 1);
diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c
index 0fdc31a46d..4205d021b7 100644
--- a/src/dhcp-manager/nm-dhcp-utils.c
+++ b/src/dhcp-manager/nm-dhcp-utils.c
@@ -604,6 +604,54 @@ ip6_add_domain_search (gpointer data, gpointer user_data)
nm_ip6_config_add_search (NM_IP6_CONFIG (user_data), (const char *) data);
}
+NMPlatformIP6Address
+nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options)
+{
+ gs_strfreev gchar **split_addr = NULL;
+ NMPlatformIP6Address address = { 0, };
+ struct in6_addr tmp_addr;
+ char *str = NULL;
+ int prefix;
+
+ g_return_val_if_fail (options != NULL, address);
+
+ str = g_hash_table_lookup (options, "ip6_prefix");
+ if (!str)
+ return address;
+
+ split_addr = g_strsplit (str, "/", 2);
+ if (split_addr[0] == NULL && split_addr[1] == NULL) {
+ nm_log_warn (LOGD_DHCP6, "DHCP returned prefix without length '%s'", str);
+ return address;
+ }
+
+ if (!inet_pton (AF_INET6, split_addr[0], &tmp_addr)) {
+ nm_log_warn (LOGD_DHCP6, "DHCP returned invalid prefix '%s'", str);
+ return address;
+ }
+
+ prefix = _nm_utils_ascii_str_to_int64 (split_addr[1], 10, 0, 128, -1);
+ if (prefix < 0) {
+ nm_log_warn (LOGD_DHCP6, "DHCP returned prefix with invalid length '%s'", str);
+ return address;
+ }
+
+ address.address = tmp_addr;
+ address.addr_source = NM_IP_CONFIG_SOURCE_DHCP;
+ address.plen = prefix;
+ address.timestamp = nm_utils_get_monotonic_timestamp_s ();
+
+ str = g_hash_table_lookup (options, "max_life");
+ if (str)
+ address.lifetime = strtoul (str, NULL, 10);
+
+ str = g_hash_table_lookup (options, "preferred_life");
+ if (str)
+ address.preferred = strtoul (str, NULL, 10);
+
+ return address;
+}
+
NMIP6Config *
nm_dhcp_utils_ip6_config_from_options (int ifindex,
const char *iface,
diff --git a/src/dhcp-manager/nm-dhcp-utils.h b/src/dhcp-manager/nm-dhcp-utils.h
index 6540b1ff80..b45c5e89a2 100644
--- a/src/dhcp-manager/nm-dhcp-utils.h
+++ b/src/dhcp-manager/nm-dhcp-utils.h
@@ -35,6 +35,8 @@ NMIP6Config *nm_dhcp_utils_ip6_config_from_options (int ifindex,
guint priority,
gboolean info_only);
+NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options);
+
char * nm_dhcp_utils_duid_to_string (const GByteArray *duid);
GBytes * nm_dhcp_utils_client_id_string_to_bytes (const char *client_id);