summaryrefslogtreecommitdiff
path: root/src/libsystemd-network/sd-dhcp6-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-network/sd-dhcp6-client.c')
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c79
1 files changed, 77 insertions, 2 deletions
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 8718324c33..15d174beee 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -22,12 +22,17 @@
#include <errno.h>
#include <string.h>
+#include "udev.h"
+#include "udev-util.h"
+#include "virt.h"
#include "siphash24.h"
#include "util.h"
#include "refcnt.h"
+#include "network-internal.h"
#include "sd-dhcp6-client.h"
#include "dhcp6-protocol.h"
+#include "dhcp6-internal.h"
#define SYSTEMD_PEN 43793
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
@@ -40,6 +45,7 @@ struct sd_dhcp6_client {
int event_priority;
int index;
struct ether_addr mac_addr;
+ DHCP6IA ia_na;
sd_dhcp6_client_cb_t cb;
void *userdata;
@@ -98,6 +104,11 @@ static int client_initialize(sd_dhcp6_client *client)
{
assert_return(client, -EINVAL);
+ client->ia_na.timeout_t1 =
+ sd_event_source_unref(client->ia_na.timeout_t1);
+ client->ia_na.timeout_t2 =
+ sd_event_source_unref(client->ia_na.timeout_t2);
+
client->state = DHCP6_STATE_STOPPED;
return 0;
@@ -113,6 +124,65 @@ static sd_dhcp6_client *client_stop(sd_dhcp6_client *client, int error) {
return client;
}
+static int client_ensure_iaid(sd_dhcp6_client *client) {
+ const char *name = NULL;
+ uint64_t id;
+
+ assert(client);
+
+ if (client->ia_na.id)
+ return 0;
+
+ if (detect_container(NULL) <= 0) {
+ /* not in a container, udev will be around */
+ _cleanup_udev_unref_ struct udev *udev;
+ _cleanup_udev_device_unref_ struct udev_device *device;
+ char ifindex_str[2 + DECIMAL_STR_MAX(int)];
+
+ udev = udev_new();
+ if (!udev)
+ return -ENOMEM;
+
+ sprintf(ifindex_str, "n%d", client->index);
+ device = udev_device_new_from_device_id(udev, ifindex_str);
+ if (!device)
+ return -errno;
+
+ if (udev_device_get_is_initialized(device) <= 0)
+ /* not yet ready */
+ return -EBUSY;
+
+ name = net_get_name(device);
+ }
+
+ if (name)
+ siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
+ else
+ /* fall back to mac address if no predictable name available */
+ siphash24((uint8_t*)&id, &client->mac_addr, ETH_ALEN,
+ HASH_KEY.bytes);
+
+ /* fold into 32 bits */
+ client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
+
+ return 0;
+}
+
+static int client_start(sd_dhcp6_client *client)
+{
+ int r;
+
+ assert_return(client, -EINVAL);
+ assert_return(client->event, -EINVAL);
+ assert_return(client->index > 0, -EINVAL);
+
+ r = client_ensure_iaid(client);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
int sd_dhcp6_client_stop(sd_dhcp6_client *client)
{
client_stop(client, DHCP6_EVENT_STOP);
@@ -128,7 +198,11 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client)
assert_return(client->event, -EINVAL);
assert_return(client->index > 0, -EINVAL);
- return r;
+ r = client_initialize(client);
+ if (r < 0)
+ return r;
+
+ return client_start(client);
}
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
@@ -176,7 +250,6 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
if (client && REFCNT_DEC(client->n_ref) <= 0) {
-
client_initialize(client);
sd_dhcp6_client_detach_event(client);
@@ -206,6 +279,8 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
client->n_ref = REFCNT_INIT;
+ client->ia_na.type = DHCP6_OPTION_IA_NA;
+
client->index = -1;
/* initialize DUID */