1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-03-08 20:58:20 +03:00

dhcp6: gracefully handle NoBinding error

When we receive NoBinding status code, the requesting binding (address or
any other information) does not exist anymore in the server. Hence,
resending the request is meaningless. Let's restart the transaction from
the beginning in that case.

(cherry picked from commit 1929c1fcb2f305206c01a6fc79cd038d6d9615f5)
This commit is contained in:
Yu Watanabe 2022-08-13 04:47:54 +09:00 committed by Zbigniew Jędrzejewski-Szmek
parent c67a388aef
commit 97474b03e7
5 changed files with 39 additions and 7 deletions

View File

@ -82,3 +82,14 @@ static const char * const dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, DHCP6Status);
int dhcp6_message_status_to_errno(DHCP6Status s) {
switch (s) {
case DHCP6_STATUS_SUCCESS:
return 0;
case DHCP6_STATUS_NO_BINDING:
return -EADDRNOTAVAIL;
default:
return -EINVAL;
}
}

View File

@ -154,3 +154,4 @@ const char *dhcp6_message_type_to_string(DHCP6MessageType s) _const_;
DHCP6MessageType dhcp6_message_type_from_string(const char *s) _pure_;
const char *dhcp6_message_status_to_string(DHCP6Status s) _const_;
DHCP6Status dhcp6_message_status_from_string(const char *s) _pure_;
int dhcp6_message_status_to_errno(DHCP6Status s);

View File

@ -48,7 +48,7 @@ static void fuzz_client(sd_dhcp6_client *client, const uint8_t *data, size_t siz
assert_se(IN_SET(client->state, DHCP6_STATE_REQUEST, DHCP6_STATE_BOUND));
break;
case DHCP6_STATE_REQUEST:
assert_se(client->state == DHCP6_STATE_BOUND);
assert_se(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_SOLICITATION));
break;
default:
assert_not_reached();

View File

@ -536,13 +536,9 @@ static void client_notify(sd_dhcp6_client *client, int event) {
client->callback(client, event, client->userdata);
}
static void client_stop(sd_dhcp6_client *client, int error) {
DHCP6_CLIENT_DONT_DESTROY(client);
static void client_cleanup(sd_dhcp6_client *client) {
assert(client);
client_notify(client, error);
client->lease = sd_dhcp6_lease_unref(client->lease);
/* Reset IRT here. Otherwise, we cannot restart the client in the information requesting mode,
@ -559,6 +555,16 @@ static void client_stop(sd_dhcp6_client *client, int error) {
client_set_state(client, DHCP6_STATE_STOPPED);
}
static void client_stop(sd_dhcp6_client *client, int error) {
DHCP6_CLIENT_DONT_DESTROY(client);
assert(client);
client_notify(client, error);
client_cleanup(client);
}
static int client_append_common_options_in_managed_mode(
sd_dhcp6_client *client,
uint8_t **opt,
@ -1124,6 +1130,20 @@ static int client_process_reply(
return log_invalid_message_type(client, message);
r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
if (r == -EADDRNOTAVAIL) {
/* If NoBinding status code is received, we cannot request the address anymore.
* Let's restart transaction from the beginning. */
if (client->state == DHCP6_STATE_REQUEST)
/* The lease is not acquired yet, hence it is not necessary to notify the restart. */
client_cleanup(client);
else
/* We need to notify the previous lease was expired. */
client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
return client_start_transaction(client, DHCP6_STATE_SOLICITATION);
}
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");

View File

@ -512,7 +512,7 @@ static int dhcp6_lease_parse_message(
return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
return log_dhcp6_client_errno(client, dhcp6_message_status_to_errno(r),
"Received %s message with non-zero status: %s%s%s",
dhcp6_message_type_to_string(message->type),
strempty(msg), isempty(msg) ? "" : ": ",