summaryrefslogtreecommitdiff
path: root/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c')
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c99
1 files changed, 83 insertions, 16 deletions
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
index 375f984940..57dd91f81f 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
@@ -11,6 +11,7 @@
#include "sd-dhcp6-client.h"
#include "alloc-util.h"
+#include "device-util.h"
#include "dhcp-identifier.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
@@ -299,9 +300,8 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
if (client->iaid_set)
return 0;
- r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
+ r = dhcp_identifier_set_iaid(client->dev, &client->hw_addr,
/* legacy_unstable_byteorder = */ true,
- /* use_mac = */ client->test_mode,
&iaid);
if (r < 0)
return r;
@@ -498,6 +498,14 @@ int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable) {
return 0;
}
+int sd_dhcp6_client_set_send_release(sd_dhcp6_client *client, int enable) {
+ assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
+
+ client->send_release = enable;
+ return 0;
+}
+
int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
assert_return(client, -EINVAL);
@@ -586,7 +594,8 @@ static int client_append_common_options_in_managed_mode(
DHCP6_STATE_SOLICITATION,
DHCP6_STATE_REQUEST,
DHCP6_STATE_RENEW,
- DHCP6_STATE_REBIND));
+ DHCP6_STATE_REBIND,
+ DHCP6_STATE_STOPPING));
assert(buf);
assert(*buf);
assert(offset);
@@ -603,9 +612,11 @@ static int client_append_common_options_in_managed_mode(
return r;
}
- r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
- if (r < 0)
- return r;
+ if (client->state != DHCP6_STATE_STOPPING) {
+ r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
+ if (r < 0)
+ return r;
+ }
r = dhcp6_option_append_user_class(buf, offset, client->user_class);
if (r < 0)
@@ -636,6 +647,8 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client)
return DHCP6_MESSAGE_RENEW;
case DHCP6_STATE_REBIND:
return DHCP6_MESSAGE_REBIND;
+ case DHCP6_STATE_STOPPING:
+ return DHCP6_MESSAGE_RELEASE;
default:
assert_not_reached();
}
@@ -679,6 +692,9 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *off
req_opts = p;
break;
+ case DHCP6_STATE_STOPPING:
+ return 0;
+
default:
n = client->n_req_opts;
req_opts = client->req_opts;
@@ -690,6 +706,22 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *off
return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
}
+static int client_append_mudurl(sd_dhcp6_client *client, uint8_t **buf, size_t *offset) {
+ assert(client);
+ assert(buf);
+ assert(*buf);
+ assert(offset);
+
+ if (!client->mudurl)
+ return 0;
+
+ if (client->state == DHCP6_STATE_STOPPING)
+ return 0;
+
+ return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_MUD_URL_V6,
+ strlen(client->mudurl), client->mudurl);
+}
+
int dhcp6_client_send_message(sd_dhcp6_client *client) {
_cleanup_free_ uint8_t *buf = NULL;
struct in6_addr all_servers =
@@ -735,7 +767,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
-
+ case DHCP6_STATE_STOPPING:
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_SERVERID,
client->lease->serverid_len,
client->lease->serverid);
@@ -753,18 +785,15 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
return r;
break;
- case DHCP6_STATE_STOPPED:
case DHCP6_STATE_BOUND:
+ case DHCP6_STATE_STOPPED:
default:
assert_not_reached();
}
- if (client->mudurl) {
- r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_MUD_URL_V6,
- strlen(client->mudurl), client->mudurl);
- if (r < 0)
- return r;
- }
+ r = client_append_mudurl(client, &buf, &offset);
+ if (r < 0)
+ return r;
r = client_append_oro(client, &buf, &offset);
if (r < 0)
@@ -856,6 +885,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
break;
case DHCP6_STATE_STOPPED:
+ case DHCP6_STATE_STOPPING:
case DHCP6_STATE_BOUND:
default:
assert_not_reached();
@@ -911,6 +941,7 @@ static int client_start_transaction(sd_dhcp6_client *client, DHCP6State state) {
assert(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_RENEW));
break;
case DHCP6_STATE_STOPPED:
+ case DHCP6_STATE_STOPPING:
case DHCP6_STATE_BOUND:
default:
assert_not_reached();
@@ -1293,7 +1324,7 @@ static int client_receive_message(
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SO_TIMESTAMP &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
- triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg)));
+ triple_timestamp_from_realtime(&t, timeval_load(CMSG_TYPED_DATA(cmsg, struct timeval)));
}
if (client->transaction_id != (message->transaction_id & htobe32(0x00ffffff)))
@@ -1319,6 +1350,7 @@ static int client_receive_message(
case DHCP6_STATE_BOUND:
case DHCP6_STATE_STOPPED:
+ case DHCP6_STATE_STOPPING:
default:
assert_not_reached();
}
@@ -1326,10 +1358,37 @@ static int client_receive_message(
return 0;
}
+static int client_send_release(sd_dhcp6_client *client) {
+ sd_dhcp6_lease *lease;
+
+ assert(client);
+
+ if (!client->send_release)
+ return 0;
+
+ if (sd_dhcp6_client_get_lease(client, &lease) < 0)
+ return 0;
+
+ if (!lease->ia_na && !lease->ia_pd)
+ return 0;
+
+ client_set_state(client, DHCP6_STATE_STOPPING);
+ return dhcp6_client_send_message(client);
+}
+
int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
+ int r;
+
if (!client)
return 0;
+ /* Intentionally ignoring failure to send DHCP6 release. The DHCPv6 client
+ * engine is about to release its UDP socket unconditionally. */
+ r = client_send_release(client);
+ if (r < 0)
+ log_dhcp6_client_errno(client, r,
+ "Failed to send DHCP6 release message, ignoring: %m");
+
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
client->receive_message = sd_event_source_unref(client->receive_message);
@@ -1446,6 +1505,12 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
return client->event;
}
+int sd_dhcp6_client_attach_device(sd_dhcp6_client *client, sd_device *dev) {
+ assert_return(client, -EINVAL);
+
+ return device_unref_and_replace(client->dev, dev);
+}
+
static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
if (!client)
return NULL;
@@ -1461,6 +1526,8 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
client->fd = safe_close(client->fd);
+ sd_device_unref(client->dev);
+
free(client->req_opts);
free(client->fqdn);
free(client->mudurl);
@@ -1491,7 +1558,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
.ia_pd.type = SD_DHCP6_OPTION_IA_PD,
.ifindex = -1,
.request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD,
- .fd = -1,
+ .fd = -EBADF,
.rapid_commit = true,
};