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.c144
1 files changed, 109 insertions, 35 deletions
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index cc5b74416f..940a606d09 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -62,6 +62,7 @@ struct sd_dhcp6_client {
usec_t transaction_start;
struct sd_dhcp6_lease *lease;
int fd;
+ bool information_request;
be16_t *req_opts;
size_t req_opts_allocated;
size_t req_opts_len;
@@ -227,6 +228,25 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du
return 0;
}
+int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
+ bool enabled) {
+ assert_return(client, -EINVAL);
+
+ client->information_request = enabled;
+
+ return 0;
+}
+
+int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
+ bool *enabled) {
+ assert_return(client, -EINVAL);
+ assert_return(enabled, -EINVAL);
+
+ *enabled = client->information_request;
+
+ return 0;
+}
+
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
uint16_t option) {
size_t t;
@@ -333,6 +353,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
message->transaction_id = client->transaction_id;
switch(client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ message->type = DHCP6_INFORMATION_REQUEST;
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
message->type = DHCP6_SOLICIT;
@@ -494,6 +519,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
switch (client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ init_retransmit_time = DHCP6_INF_TIMEOUT;
+ max_retransmit_time = DHCP6_INF_MAX_RT;
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
if (client->retransmit_count && client->lease) {
@@ -744,6 +775,12 @@ static int client_parse_message(sd_dhcp6_client *client,
break;
case DHCP6_OPTION_IA_NA:
+ if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
+ log_dhcp6_client(client, "Information request ignoring IA NA option");
+
+ break;
+ }
+
r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
&lease->ia);
if (r < 0 && r != -ENOMSG)
@@ -779,10 +816,12 @@ static int client_parse_message(sd_dhcp6_client *client,
return -EINVAL;
}
- r = dhcp6_lease_get_serverid(lease, &id, &id_len);
- if (r < 0)
- log_dhcp6_client(client, "%s has no server id",
- dhcp6_message_type_to_string(message->type));
+ if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
+ r = dhcp6_lease_get_serverid(lease, &id, &id_len);
+ if (r < 0)
+ log_dhcp6_client(client, "%s has no server id",
+ dhcp6_message_type_to_string(message->type));
+ }
return r;
}
@@ -814,12 +853,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
return 0;
}
- if (client->lease)
+ if (client->lease) {
dhcp6_lease_clear_timers(&client->lease->ia);
+ client->lease = sd_dhcp6_lease_unref(client->lease);
+ }
- client->lease = sd_dhcp6_lease_unref(client->lease);
- client->lease = lease;
- lease = NULL;
+ if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
+ client->lease = lease;
+ lease = NULL;
+ }
return DHCP6_STATE_BOUND;
}
@@ -846,7 +888,8 @@ static int client_receive_advertise(sd_dhcp6_client *client,
return r;
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
- if (!client->lease || r < 0 || pref_advertise > pref_lease) {
+
+ if (r < 0 || pref_advertise > pref_lease) {
sd_dhcp6_lease_unref(client->lease);
client->lease = lease;
lease = NULL;
@@ -913,6 +956,17 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
return 0;
switch (client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ r = client_receive_reply(client, message, len);
+ if (r < 0)
+ return 0;
+
+ client_notify(client, DHCP6_EVENT_INFORMATION_REQUEST);
+
+ client_start(client, DHCP6_STATE_STOPPED);
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
r = client_receive_advertise(client, message, len);
@@ -988,37 +1042,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
switch (state) {
case DHCP6_STATE_STOPPED:
- case DHCP6_STATE_SOLICITATION:
+ if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
+ client->state = DHCP6_STATE_STOPPED;
- r = client_ensure_iaid(client);
- if (r < 0)
- return r;
-
- r = dhcp6_network_bind_udp_socket(client->index, NULL);
- if (r < 0)
- return r;
-
- client->fd = r;
-
- r = sd_event_add_io(client->event, &client->receive_message,
- client->fd, EPOLLIN, client_receive_message,
- client);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(client->receive_message,
- client->event_priority);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_description(client->receive_message, "dhcp6-receive-message");
- if (r < 0)
- return r;
+ return 0;
+ }
+ /* fall through */
+ case DHCP6_STATE_SOLICITATION:
client->state = DHCP6_STATE_SOLICITATION;
break;
+ case DHCP6_STATE_INFORMATION_REQUEST:
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
@@ -1123,6 +1159,7 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client)
int sd_dhcp6_client_start(sd_dhcp6_client *client)
{
int r = 0;
+ enum DHCP6State state = DHCP6_STATE_SOLICITATION;
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
@@ -1132,7 +1169,44 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client)
if (r < 0)
return r;
- return client_start(client, DHCP6_STATE_SOLICITATION);
+ r = client_ensure_iaid(client);
+ if (r < 0)
+ return r;
+
+ r = dhcp6_network_bind_udp_socket(client->index, NULL);
+ if (r < 0)
+ return r;
+
+ client->fd = r;
+
+ r = sd_event_add_io(client->event, &client->receive_message,
+ client->fd, EPOLLIN, client_receive_message,
+ client);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_priority(client->receive_message,
+ client->event_priority);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_description(client->receive_message,
+ "dhcp6-receive-message");
+ if (r < 0)
+ goto error;
+
+ if (client->information_request)
+ state = DHCP6_STATE_INFORMATION_REQUEST;
+
+ log_dhcp6_client(client, "Started in %s mode",
+ client->information_request? "Information request":
+ "Managed");
+
+ return client_start(client, state);
+
+error:
+ client_reset(client);
+ return r;
}
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,