summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libsystemd-network/dhcp6-protocol.h4
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c47
2 files changed, 48 insertions, 3 deletions
diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h
index 1303a55a8..754e80008 100644
--- a/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libsystemd-network/dhcp6-protocol.h
@@ -54,6 +54,9 @@ enum {
#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC
#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC
#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC
+#define DHCP6_REQ_TIMEOUT 1 * USEC_PER_SEC
+#define DHCP6_REQ_MAX_RT 120 * USEC_PER_SEC
+#define DHCP6_REQ_MAX_RC 10
enum {
DHCP6_DUID_LLT = 1,
@@ -66,6 +69,7 @@ enum DHCP6State {
DHCP6_STATE_STOPPED = 0,
DHCP6_STATE_RS = 1,
DHCP6_STATE_SOLICITATION = 2,
+ DHCP6_STATE_REQUEST = 3,
};
enum {
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 1a59cc286..55dd65c9e 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -213,12 +213,22 @@ static int client_send_message(sd_dhcp6_client *client) {
case DHCP6_STATE_SOLICITATION:
message->type = DHCP6_SOLICIT;
- r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
- sizeof(client->duid), &client->duid);
+ r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
if (r < 0)
return r;
- r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
+ break;
+
+ case DHCP6_STATE_REQUEST:
+ message->type = DHCP6_REQUEST;
+
+ r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID,
+ client->lease->serverid_len,
+ client->lease->serverid);
+ if (r < 0)
+ return r;
+
+ r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
if (r < 0)
return r;
@@ -229,6 +239,11 @@ static int client_send_message(sd_dhcp6_client *client) {
return -EINVAL;
}
+ r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
+ sizeof(client->duid), &client->duid);
+ if (r < 0)
+ return r;
+
r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
len - optlen);
if (r < 0)
@@ -275,6 +290,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
switch (client->state) {
case DHCP6_STATE_SOLICITATION:
+
+ if (client->retransmit_count && client->lease) {
+ client_start(client, DHCP6_STATE_REQUEST);
+ return 0;
+ }
+
init_retransmit_time = DHCP6_SOL_TIMEOUT;
max_retransmit_time = DHCP6_SOL_MAX_RT;
max_retransmit_count = 0;
@@ -282,6 +303,14 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
break;
+ case DHCP6_STATE_REQUEST:
+ init_retransmit_time = DHCP6_REQ_TIMEOUT;
+ max_retransmit_time = DHCP6_REQ_MAX_RT;
+ max_retransmit_count = DHCP6_REQ_MAX_RC;
+ max_retransmit_duration = 0;
+
+ break;
+
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_RS:
return 0;
@@ -537,6 +566,9 @@ static int client_receive_advertise(sd_dhcp6_client *client,
r = 0;
}
+ if (pref_advertise == 255 || client->retransmit_count > 1)
+ r = DHCP6_STATE_REQUEST;
+
return r;
}
@@ -596,8 +628,12 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
case DHCP6_STATE_SOLICITATION:
r = client_receive_advertise(client, message, len);
+ if (r == DHCP6_STATE_REQUEST)
+ client_start(client, r);
+
break;
+ case DHCP6_STATE_REQUEST:
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_RS:
return 0;
@@ -655,6 +691,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
client->state = DHCP6_STATE_SOLICITATION;
break;
+
+ case DHCP6_STATE_REQUEST:
+ client->state = state;
+
+ break;
}
client->transaction_id = random_u32() & htobe32(0x00ffffff);