Merge pull request #9981 from pfl/dhcp6_pd_other_information_quirk
DHCPv6 PD other information quirk
This commit is contained in:
commit
54e6f0a38f
|
@ -1372,6 +1372,22 @@
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>ForceDHCPv6PDOtherInformation=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>A boolean that enforces DHCPv6 stateful mode when the 'Other information' bit is set in
|
||||||
|
Router Advertisement messages. By default setting only the 'O' bit in Router Advertisements
|
||||||
|
makes DHCPv6 request network information in a stateless manner using a two-message Information
|
||||||
|
Request and Information Reply message exchange.
|
||||||
|
<ulink url="https://tools.ietf.org/html/rfc7084">RFC 7084</ulink>, requirement WPD-4, updates
|
||||||
|
this behavior for a Customer Edge router so that stateful DHCPv6 Prefix Delegation is also
|
||||||
|
requested when only the 'O' bit is set in Router Advertisements. This option enables such a CE
|
||||||
|
behavior as it is impossible to automatically distinguish the intention of the 'O' bit otherwise.
|
||||||
|
By default this option is set to 'false', enable it if no prefixes are delegated when the device
|
||||||
|
should be acting as a CE router.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,6 @@ struct DHCP6IA {
|
||||||
struct ia_pd ia_pd;
|
struct ia_pd ia_pd;
|
||||||
struct ia_ta ia_ta;
|
struct ia_ta ia_ta;
|
||||||
};
|
};
|
||||||
sd_event_source *timeout_t1;
|
|
||||||
sd_event_source *timeout_t2;
|
|
||||||
|
|
||||||
LIST_HEAD(DHCP6Address, addresses);
|
LIST_HEAD(DHCP6Address, addresses);
|
||||||
};
|
};
|
||||||
|
|
|
@ -37,7 +37,6 @@ struct sd_dhcp6_lease {
|
||||||
size_t ntp_fqdn_count;
|
size_t ntp_fqdn_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
int dhcp6_lease_clear_timers(DHCP6IA *ia);
|
|
||||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
|
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
|
||||||
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
|
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
|
||||||
|
|
||||||
|
@ -50,6 +49,7 @@ int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease);
|
||||||
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
|
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
|
||||||
|
|
||||||
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||||
|
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||||
|
|
||||||
int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
|
int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
|
||||||
int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
|
int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
|
||||||
|
|
|
@ -27,6 +27,13 @@
|
||||||
|
|
||||||
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
|
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
|
||||||
|
|
||||||
|
/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
|
||||||
|
enum {
|
||||||
|
DHCP6_REQUEST_IA_NA = 1,
|
||||||
|
DHCP6_REQUEST_IA_TA = 2, /* currently not used */
|
||||||
|
DHCP6_REQUEST_IA_PD = 4,
|
||||||
|
};
|
||||||
|
|
||||||
struct sd_dhcp6_client {
|
struct sd_dhcp6_client {
|
||||||
unsigned n_ref;
|
unsigned n_ref;
|
||||||
|
|
||||||
|
@ -40,7 +47,9 @@ struct sd_dhcp6_client {
|
||||||
uint16_t arp_type;
|
uint16_t arp_type;
|
||||||
DHCP6IA ia_na;
|
DHCP6IA ia_na;
|
||||||
DHCP6IA ia_pd;
|
DHCP6IA ia_pd;
|
||||||
bool prefix_delegation;
|
sd_event_source *timeout_t1;
|
||||||
|
sd_event_source *timeout_t2;
|
||||||
|
int request;
|
||||||
be32_t transaction_id;
|
be32_t transaction_id;
|
||||||
usec_t transaction_start;
|
usec_t transaction_start;
|
||||||
struct sd_dhcp6_lease *lease;
|
struct sd_dhcp6_lease *lease;
|
||||||
|
@ -325,10 +334,36 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, bool delegation) {
|
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
|
||||||
|
assert_return(client, -EINVAL);
|
||||||
|
assert_return(delegation, -EINVAL);
|
||||||
|
|
||||||
|
*delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) {
|
||||||
assert_return(client, -EINVAL);
|
assert_return(client, -EINVAL);
|
||||||
|
|
||||||
client->prefix_delegation = delegation;
|
SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
|
||||||
|
assert_return(client, -EINVAL);
|
||||||
|
assert_return(request, -EINVAL);
|
||||||
|
|
||||||
|
*request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
|
||||||
|
assert_return(client, -EINVAL);
|
||||||
|
|
||||||
|
SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -355,12 +390,8 @@ static void client_notify(sd_dhcp6_client *client, int event) {
|
||||||
static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
|
static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
|
||||||
assert(client);
|
assert(client);
|
||||||
|
|
||||||
if (client->lease) {
|
(void) sd_dhcp6_lease_unref(client->lease);
|
||||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
client->lease = sd_dhcp6_lease_ref(lease);
|
||||||
sd_dhcp6_lease_unref(client->lease);
|
|
||||||
}
|
|
||||||
|
|
||||||
client->lease = lease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int client_reset(sd_dhcp6_client *client) {
|
static int client_reset(sd_dhcp6_client *client) {
|
||||||
|
@ -374,11 +405,6 @@ static int client_reset(sd_dhcp6_client *client) {
|
||||||
client->transaction_id = 0;
|
client->transaction_id = 0;
|
||||||
client->transaction_start = 0;
|
client->transaction_start = 0;
|
||||||
|
|
||||||
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->retransmit_time = 0;
|
client->retransmit_time = 0;
|
||||||
client->retransmit_count = 0;
|
client->retransmit_count = 0;
|
||||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
||||||
|
@ -436,9 +462,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
|
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||||
if (r < 0)
|
r = dhcp6_option_append_ia(&opt, &optlen,
|
||||||
return r;
|
&client->ia_na);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->fqdn) {
|
if (client->fqdn) {
|
||||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||||
|
@ -446,7 +475,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->prefix_delegation) {
|
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||||
r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
|
r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -471,9 +500,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||||
if (r < 0)
|
r = dhcp6_option_append_ia(&opt, &optlen,
|
||||||
return r;
|
&client->lease->ia);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->fqdn) {
|
if (client->fqdn) {
|
||||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||||
|
@ -481,7 +513,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->prefix_delegation) {
|
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||||
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
|
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -495,9 +527,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||||
case DHCP6_STATE_REBIND:
|
case DHCP6_STATE_REBIND:
|
||||||
message->type = DHCP6_REBIND;
|
message->type = DHCP6_REBIND;
|
||||||
|
|
||||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||||
if (r < 0)
|
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
||||||
return r;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->fqdn) {
|
if (client->fqdn) {
|
||||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||||
|
@ -505,7 +539,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->prefix_delegation) {
|
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||||
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
|
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -562,8 +596,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
|
||||||
assert(client);
|
assert(client);
|
||||||
assert(client->lease);
|
assert(client->lease);
|
||||||
|
|
||||||
client->lease->ia.timeout_t2 =
|
client->timeout_t2 =
|
||||||
sd_event_source_unref(client->lease->ia.timeout_t2);
|
sd_event_source_unref(client->timeout_t2);
|
||||||
|
|
||||||
log_dhcp6_client(client, "Timeout T2");
|
log_dhcp6_client(client, "Timeout T2");
|
||||||
|
|
||||||
|
@ -579,8 +613,8 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
|
||||||
assert(client);
|
assert(client);
|
||||||
assert(client->lease);
|
assert(client->lease);
|
||||||
|
|
||||||
client->lease->ia.timeout_t1 =
|
client->timeout_t1 =
|
||||||
sd_event_source_unref(client->lease->ia.timeout_t1);
|
sd_event_source_unref(client->timeout_t1);
|
||||||
|
|
||||||
log_dhcp6_client(client, "Timeout T1");
|
log_dhcp6_client(client, "Timeout T1");
|
||||||
|
|
||||||
|
@ -914,7 +948,7 @@ static int client_parse_message(
|
||||||
if (r < 0 && r != -ENOMSG)
|
if (r < 0 && r != -ENOMSG)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dhcp6_lease_get_iaid(lease, &iaid_lease);
|
r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1188,10 +1222,33 @@ static int client_receive_message(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
|
||||||
|
uint32_t *lifetime_t2) {
|
||||||
|
assert_return(client, -EINVAL);
|
||||||
|
assert_return(client->lease, -EINVAL);
|
||||||
|
|
||||||
|
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
|
||||||
|
*lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
|
||||||
|
*lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
|
||||||
|
*lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
|
||||||
|
*lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOMSG;
|
||||||
|
}
|
||||||
|
|
||||||
static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||||
int r;
|
int r;
|
||||||
usec_t timeout, time_now;
|
usec_t timeout, time_now;
|
||||||
char time_string[FORMAT_TIMESPAN_MAX];
|
char time_string[FORMAT_TIMESPAN_MAX];
|
||||||
|
uint32_t lifetime_t1, lifetime_t2;
|
||||||
|
|
||||||
assert_return(client, -EINVAL);
|
assert_return(client, -EINVAL);
|
||||||
assert_return(client->event, -EINVAL);
|
assert_return(client->event, -EINVAL);
|
||||||
|
@ -1251,57 +1308,58 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||||
|
|
||||||
case DHCP6_STATE_BOUND:
|
case DHCP6_STATE_BOUND:
|
||||||
|
|
||||||
if (client->lease->ia.ia_na.lifetime_t1 == 0xffffffff ||
|
r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2);
|
||||||
client->lease->ia.ia_na.lifetime_t2 == 0xffffffff) {
|
if (r < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) {
|
||||||
log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
|
log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
|
||||||
be32toh(client->lease->ia.ia_na.lifetime_t1),
|
lifetime_t1, lifetime_t2);
|
||||||
be32toh(client->lease->ia.ia_na.lifetime_t2));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t1) * USEC_PER_SEC);
|
timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
|
||||||
|
|
||||||
log_dhcp6_client(client, "T1 expires in %s",
|
log_dhcp6_client(client, "T1 expires in %s",
|
||||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||||
|
|
||||||
r = sd_event_add_time(client->event,
|
r = sd_event_add_time(client->event,
|
||||||
&client->lease->ia.timeout_t1,
|
&client->timeout_t1,
|
||||||
clock_boottime_or_monotonic(), time_now + timeout,
|
clock_boottime_or_monotonic(), time_now + timeout,
|
||||||
10 * USEC_PER_SEC, client_timeout_t1,
|
10 * USEC_PER_SEC, client_timeout_t1,
|
||||||
client);
|
client);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
|
r = sd_event_source_set_priority(client->timeout_t1,
|
||||||
client->event_priority);
|
client->event_priority);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
|
r = sd_event_source_set_description(client->timeout_t1, "dhcp6-t1-timeout");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t2) * USEC_PER_SEC);
|
timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
|
||||||
|
|
||||||
log_dhcp6_client(client, "T2 expires in %s",
|
log_dhcp6_client(client, "T2 expires in %s",
|
||||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||||
|
|
||||||
r = sd_event_add_time(client->event,
|
r = sd_event_add_time(client->event,
|
||||||
&client->lease->ia.timeout_t2,
|
&client->timeout_t2,
|
||||||
clock_boottime_or_monotonic(), time_now + timeout,
|
clock_boottime_or_monotonic(), time_now + timeout,
|
||||||
10 * USEC_PER_SEC, client_timeout_t2,
|
10 * USEC_PER_SEC, client_timeout_t2,
|
||||||
client);
|
client);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
|
r = sd_event_source_set_priority(client->timeout_t2,
|
||||||
client->event_priority);
|
client->event_priority);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
|
r = sd_event_source_set_description(client->timeout_t2, "dhcp6-t2-timeout");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -1363,6 +1421,9 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
||||||
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
|
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (!client->information_request && !client->request)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
r = client_reset(client);
|
r = client_reset(client);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -1461,6 +1522,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
||||||
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
|
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
|
||||||
client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
|
client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
|
||||||
client->ifindex = -1;
|
client->ifindex = -1;
|
||||||
|
client->request = DHCP6_REQUEST_IA_NA;
|
||||||
client->fd = -1;
|
client->fd = -1;
|
||||||
|
|
||||||
client->req_opts_len = ELEMENTSOF(default_req_opts);
|
client->req_opts_len = ELEMENTSOF(default_req_opts);
|
||||||
|
|
|
@ -11,15 +11,6 @@
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int dhcp6_lease_clear_timers(DHCP6IA *ia) {
|
|
||||||
assert_return(ia, -EINVAL);
|
|
||||||
|
|
||||||
ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1);
|
|
||||||
ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
|
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
|
||||||
DHCP6Address *addr;
|
DHCP6Address *addr;
|
||||||
uint32_t valid = 0, t;
|
uint32_t valid = 0, t;
|
||||||
|
@ -48,8 +39,6 @@ DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
|
||||||
if (!ia)
|
if (!ia)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
dhcp6_lease_clear_timers(ia);
|
|
||||||
|
|
||||||
while (ia->addresses) {
|
while (ia->addresses) {
|
||||||
address = ia->addresses;
|
address = ia->addresses;
|
||||||
|
|
||||||
|
@ -136,6 +125,15 @@ int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
||||||
|
assert_return(lease, -EINVAL);
|
||||||
|
assert_return(iaid, -EINVAL);
|
||||||
|
|
||||||
|
*iaid = lease->pd.ia_pd.id;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
|
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
|
||||||
uint32_t *lifetime_preferred,
|
uint32_t *lifetime_preferred,
|
||||||
uint32_t *lifetime_valid) {
|
uint32_t *lifetime_valid) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ static uint8_t test_duid[14] = { };
|
||||||
|
|
||||||
static int test_client_basic(sd_event *e) {
|
static int test_client_basic(sd_event *e) {
|
||||||
sd_dhcp6_client *client;
|
sd_dhcp6_client *client;
|
||||||
|
int v;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf("* %s\n", __FUNCTION__);
|
printf("* %s\n", __FUNCTION__);
|
||||||
|
@ -68,6 +69,36 @@ static int test_client_basic(sd_event *e) {
|
||||||
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
|
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
|
||||||
assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
|
assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
|
||||||
|
|
||||||
|
assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0);
|
||||||
|
v = 0;
|
||||||
|
assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0);
|
||||||
|
assert_se(v);
|
||||||
|
assert_se(sd_dhcp6_client_set_information_request(client, 0) >= 0);
|
||||||
|
v = 42;
|
||||||
|
assert_se(sd_dhcp6_client_get_information_request(client, &v) >= 0);
|
||||||
|
assert_se(v == 0);
|
||||||
|
|
||||||
|
v = 0;
|
||||||
|
assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
|
||||||
|
assert_se(v);
|
||||||
|
v = 0;
|
||||||
|
assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
|
||||||
|
assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
|
||||||
|
assert_se(v);
|
||||||
|
v = 42;
|
||||||
|
assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
|
||||||
|
assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
|
||||||
|
assert_se(v);
|
||||||
|
|
||||||
|
assert_se(sd_dhcp6_client_set_address_request(client, 1) >= 0);
|
||||||
|
assert_se(sd_dhcp6_client_set_prefix_delegation(client, 1) >= 0);
|
||||||
|
v = 0;
|
||||||
|
assert_se(sd_dhcp6_client_get_address_request(client, &v) >= 0);
|
||||||
|
assert_se(v);
|
||||||
|
v = 0;
|
||||||
|
assert_se(sd_dhcp6_client_get_prefix_delegation(client, &v) >= 0);
|
||||||
|
assert_se(v);
|
||||||
|
|
||||||
assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
|
assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0);
|
||||||
|
|
||||||
assert_se(sd_dhcp6_client_detach_event(client) >= 0);
|
assert_se(sd_dhcp6_client_detach_event(client) >= 0);
|
||||||
|
@ -862,7 +893,7 @@ static int test_client_solicit(sd_event *e) {
|
||||||
sd_dhcp6_client *client;
|
sd_dhcp6_client *client;
|
||||||
usec_t time_now = now(clock_boottime_or_monotonic());
|
usec_t time_now = now(clock_boottime_or_monotonic());
|
||||||
struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
|
struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } };
|
||||||
int val = true;
|
int val;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf("* %s\n", __FUNCTION__);
|
printf("* %s\n", __FUNCTION__);
|
||||||
|
@ -879,10 +910,10 @@ static int test_client_solicit(sd_event *e) {
|
||||||
assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
|
assert_se(sd_dhcp6_client_set_fqdn(client, "host.lab.intra") == 1);
|
||||||
|
|
||||||
assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
|
assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
|
||||||
assert_se(val == false);
|
assert_se(val == 0);
|
||||||
assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0);
|
assert_se(sd_dhcp6_client_set_information_request(client, 42) >= 0);
|
||||||
assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
|
assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
|
||||||
assert_se(val == true);
|
assert_se(val);
|
||||||
|
|
||||||
assert_se(sd_dhcp6_client_set_callback(client,
|
assert_se(sd_dhcp6_client_set_callback(client,
|
||||||
test_client_information_cb, e) >= 0);
|
test_client_information_cb, e) >= 0);
|
||||||
|
|
|
@ -103,12 +103,77 @@ static int dhcp6_pd_prefix_assign(Link *link, struct in6_addr *prefix,
|
||||||
return sd_radv_start(radv);
|
return sd_radv_start(radv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Network *dhcp6_reset_pd_prefix_network(Link *link) {
|
static int dhcp6_route_remove_cb(sd_netlink *nl, sd_netlink_message *m,
|
||||||
assert(link);
|
void *userdata) {
|
||||||
assert(link->manager);
|
Link *l = userdata;
|
||||||
assert(link->manager->networks);
|
int r;
|
||||||
|
|
||||||
return link->manager->networks;
|
r = sd_netlink_message_get_errno(m);
|
||||||
|
if (r < 0)
|
||||||
|
log_link_debug_errno(l, r, "Received error on unreachable route removal for DHCPv6 delegated subnetl: %m");
|
||||||
|
|
||||||
|
l = link_unref(l);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) {
|
||||||
|
int r;
|
||||||
|
sd_dhcp6_lease *lease;
|
||||||
|
union in_addr_union pd_prefix;
|
||||||
|
uint8_t pd_prefix_len;
|
||||||
|
uint32_t lifetime_preferred, lifetime_valid;
|
||||||
|
|
||||||
|
r = sd_dhcp6_client_get_lease(client, &lease);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
|
||||||
|
|
||||||
|
while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
|
||||||
|
&lifetime_preferred,
|
||||||
|
&lifetime_valid) >= 0) {
|
||||||
|
_cleanup_free_ char *buf = NULL;
|
||||||
|
_cleanup_free_ Route *route;
|
||||||
|
|
||||||
|
if (pd_prefix_len > 64)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||||
|
|
||||||
|
if (pd_prefix_len < 64) {
|
||||||
|
r = route_new(&route);
|
||||||
|
if (r < 0) {
|
||||||
|
log_link_warning_errno(link, r, "Cannot create unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
|
||||||
|
strnull(buf),
|
||||||
|
pd_prefix_len);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
|
||||||
|
0, 0, 0, &route);
|
||||||
|
route_update(route, NULL, 0, NULL, NULL, 0, 0,
|
||||||
|
RTN_UNREACHABLE);
|
||||||
|
|
||||||
|
r = route_remove(route, link, dhcp6_route_remove_cb);
|
||||||
|
if (r < 0) {
|
||||||
|
(void) in_addr_to_string(AF_INET6,
|
||||||
|
&pd_prefix, &buf);
|
||||||
|
|
||||||
|
log_link_warning_errno(link, r, "Cannot delete unreachable route for DHCPv6 delegated subnet %s/%u: %m",
|
||||||
|
strnull(buf),
|
||||||
|
pd_prefix_len);
|
||||||
|
route_free(route);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
link = link_ref(link);
|
||||||
|
|
||||||
|
log_link_debug(link, "Removing unreachable route %s/%u",
|
||||||
|
strnull(buf), pd_prefix_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
|
static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
|
||||||
|
@ -184,39 +249,28 @@ static int dhcp6_pd_prefix_distribute(Link *dhcp6_link, Iterator *i,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n_used < n_prefixes) {
|
return 0;
|
||||||
Route *route;
|
|
||||||
uint64_t n = n_used;
|
|
||||||
|
|
||||||
r = route_new(&route);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
route->family = AF_INET6;
|
|
||||||
|
|
||||||
while (n < n_prefixes) {
|
|
||||||
route_update(route, &prefix, pd_prefix_len, NULL, NULL,
|
|
||||||
0, 0, RTN_UNREACHABLE);
|
|
||||||
|
|
||||||
r = route_configure(route, dhcp6_link, NULL);
|
|
||||||
if (r < 0) {
|
|
||||||
route_free(route);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = in_addr_prefix_next(AF_INET6, &prefix, pd_prefix_len);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n_used;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dhcp6_route_add_cb(sd_netlink *nl, sd_netlink_message *m,
|
||||||
|
void *userdata) {
|
||||||
|
Link *l = userdata;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = sd_netlink_message_get_errno(m);
|
||||||
|
if (r < 0 && r != -EEXIST)
|
||||||
|
log_link_debug_errno(l, r, "Received error when adding unreachable route for DHCPv6 delegated subnet: %m");
|
||||||
|
|
||||||
|
l = link_unref(l);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
sd_dhcp6_lease *lease;
|
sd_dhcp6_lease *lease;
|
||||||
struct in6_addr pd_prefix;
|
union in_addr_union pd_prefix;
|
||||||
uint8_t pd_prefix_len;
|
uint8_t pd_prefix_len;
|
||||||
uint32_t lifetime_preferred, lifetime_valid;
|
uint32_t lifetime_preferred, lifetime_valid;
|
||||||
_cleanup_free_ char *buf = NULL;
|
_cleanup_free_ char *buf = NULL;
|
||||||
|
@ -226,27 +280,62 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
dhcp6_reset_pd_prefix_network(link);
|
|
||||||
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
|
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
|
||||||
|
|
||||||
while (sd_dhcp6_lease_get_pd(lease, &pd_prefix, &pd_prefix_len,
|
while (sd_dhcp6_lease_get_pd(lease, &pd_prefix.in6, &pd_prefix_len,
|
||||||
&lifetime_preferred,
|
&lifetime_preferred,
|
||||||
&lifetime_valid) >= 0) {
|
&lifetime_valid) >= 0) {
|
||||||
|
|
||||||
if (pd_prefix_len > 64) {
|
if (pd_prefix_len > 64) {
|
||||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
|
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||||
log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u",
|
log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u",
|
||||||
strnull(buf), pd_prefix_len);
|
strnull(buf), pd_prefix_len);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pd_prefix_len < 48) {
|
if (pd_prefix_len < 48) {
|
||||||
(void) in_addr_to_string(AF_INET6, (union in_addr_union*) &pd_prefix, &buf);
|
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||||
log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u",
|
log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u",
|
||||||
strnull(buf), pd_prefix_len);
|
strnull(buf), pd_prefix_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix,
|
if (pd_prefix_len < 64) {
|
||||||
|
Route *route = NULL;
|
||||||
|
|
||||||
|
(void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
|
||||||
|
|
||||||
|
r = route_new(&route);
|
||||||
|
if (r < 0) {
|
||||||
|
log_link_warning_errno(link, r, "Cannot create unreachable route for DHCPv6 delegated subnet %s/%u: %m",
|
||||||
|
strnull(buf),
|
||||||
|
pd_prefix_len);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
|
||||||
|
0, 0, 0, &route);
|
||||||
|
route_update(route, NULL, 0, NULL, NULL, 0, 0,
|
||||||
|
RTN_UNREACHABLE);
|
||||||
|
|
||||||
|
r = route_configure(route, link, dhcp6_route_add_cb);
|
||||||
|
if (r < 0) {
|
||||||
|
log_link_warning_errno(link, r, "Cannot configure unreachable route for delegated subnet %s/%u: %m",
|
||||||
|
strnull(buf),
|
||||||
|
pd_prefix_len);
|
||||||
|
route_free(route);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
link = link_ref(link);
|
||||||
|
|
||||||
|
route_free(route);
|
||||||
|
|
||||||
|
log_link_debug(link, "Configuring unreachable route for %s/%u",
|
||||||
|
strnull(buf), pd_prefix_len);
|
||||||
|
|
||||||
|
} else
|
||||||
|
log_link_debug(link, "Not adding a blocking route since distributed prefix is /64");
|
||||||
|
|
||||||
|
r = dhcp6_pd_prefix_distribute(link, &i, &pd_prefix.in6,
|
||||||
pd_prefix_len,
|
pd_prefix_len,
|
||||||
lifetime_preferred,
|
lifetime_preferred,
|
||||||
lifetime_valid);
|
lifetime_valid);
|
||||||
|
@ -364,6 +453,7 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
|
||||||
if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
|
if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
|
||||||
log_link_warning(link, "DHCPv6 lease lost");
|
log_link_warning(link, "DHCPv6 lease lost");
|
||||||
|
|
||||||
|
(void) dhcp6_lease_pd_prefix_lost(client, link);
|
||||||
(void) manager_dhcp6_prefix_remove_all(link->manager, link);
|
(void) manager_dhcp6_prefix_remove_all(link->manager, link);
|
||||||
|
|
||||||
link->dhcp6_configured = false;
|
link->dhcp6_configured = false;
|
||||||
|
@ -403,11 +493,12 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp6_request_address(Link *link, int ir) {
|
int dhcp6_request_address(Link *link, int ir) {
|
||||||
int r, inf_req;
|
int r, inf_req, pd;
|
||||||
bool running;
|
bool running;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(link->dhcp6_client);
|
assert(link->dhcp6_client);
|
||||||
|
assert(link->network);
|
||||||
assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
|
assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0);
|
||||||
|
|
||||||
r = sd_dhcp6_client_is_running(link->dhcp6_client);
|
r = sd_dhcp6_client_is_running(link->dhcp6_client);
|
||||||
|
@ -416,6 +507,21 @@ int dhcp6_request_address(Link *link, int ir) {
|
||||||
else
|
else
|
||||||
running = r;
|
running = r;
|
||||||
|
|
||||||
|
r = sd_dhcp6_client_get_prefix_delegation(link->dhcp6_client, &pd);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (pd && ir && link->network->dhcp6_force_pd_other_information) {
|
||||||
|
log_link_debug(link, "Enabling managed mode to request DHCPv6 PD with 'Other Information' set");
|
||||||
|
|
||||||
|
r = sd_dhcp6_client_set_address_request(link->dhcp6_client,
|
||||||
|
false);
|
||||||
|
if (r < 0 )
|
||||||
|
return r;
|
||||||
|
|
||||||
|
ir = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (running) {
|
if (running) {
|
||||||
r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
|
r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -165,6 +165,7 @@ int dhcp4_set_client_identifier(Link *link);
|
||||||
int dhcp4_set_promote_secondaries(Link *link);
|
int dhcp4_set_promote_secondaries(Link *link);
|
||||||
int dhcp6_configure(Link *link);
|
int dhcp6_configure(Link *link);
|
||||||
int dhcp6_request_address(Link *link, int ir);
|
int dhcp6_request_address(Link *link, int ir);
|
||||||
|
int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);
|
||||||
|
|
||||||
const char* link_state_to_string(LinkState s) _const_;
|
const char* link_state_to_string(LinkState s) _const_;
|
||||||
LinkState link_state_from_string(const char *s) _pure_;
|
LinkState link_state_from_string(const char *s) _pure_;
|
||||||
|
|
|
@ -1240,27 +1240,15 @@ Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
|
static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
Link *l = userdata;
|
Link *l = userdata;
|
||||||
int r;
|
int r;
|
||||||
union in_addr_union prefix;
|
|
||||||
_cleanup_free_ char *buf = NULL;
|
|
||||||
|
|
||||||
r = sd_netlink_message_get_errno(m);
|
r = sd_netlink_message_get_errno(m);
|
||||||
if (r != 0) {
|
if (r < 0 && r != -EEXIST)
|
||||||
log_link_debug_errno(l, r, "Received error adding DHCPv6 Prefix Delegation route: %m");
|
log_link_debug_errno(l, r, "Received error adding DHCPv6 Prefix Delegation route: %m");
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
|
l = link_unref(l);
|
||||||
if (r < 0) {
|
|
||||||
log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while adding route: %m");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) in_addr_to_string(AF_INET6, &prefix, &buf);
|
|
||||||
log_link_debug(l, "Added DHCPv6 Prefix Deleagtion route %s/64",
|
|
||||||
strnull(buf));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1268,6 +1256,7 @@ static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m,
|
||||||
int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
|
int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
Route *route;
|
Route *route;
|
||||||
|
_cleanup_free_ char *buf = NULL;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
assert_return(m, -EINVAL);
|
||||||
assert_return(m->dhcp6_prefixes, -ENODATA);
|
assert_return(m->dhcp6_prefixes, -ENODATA);
|
||||||
|
@ -1282,6 +1271,11 @@ int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
|
||||||
|
log_link_debug(link, "Adding prefix route %s/64", strnull(buf));
|
||||||
|
|
||||||
|
link = link_ref(link);
|
||||||
|
|
||||||
return hashmap_put(m->dhcp6_prefixes, addr, link);
|
return hashmap_put(m->dhcp6_prefixes, addr, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1289,24 +1283,12 @@ static int dhcp6_route_remove_callback(sd_netlink *nl, sd_netlink_message *m,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
Link *l = userdata;
|
Link *l = userdata;
|
||||||
int r;
|
int r;
|
||||||
union in_addr_union prefix;
|
|
||||||
_cleanup_free_ char *buf = NULL;
|
|
||||||
|
|
||||||
r = sd_netlink_message_get_errno(m);
|
r = sd_netlink_message_get_errno(m);
|
||||||
if (r != 0) {
|
if (r < 0)
|
||||||
log_link_debug_errno(l, r, "Received error on DHCPv6 Prefix Delegation route removal: %m");
|
log_link_debug_errno(l, r, "Received error on DHCPv6 Prefix Delegation route removal: %m");
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6);
|
l = link_unref(l);
|
||||||
if (r < 0) {
|
|
||||||
log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while removing route: %m");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) in_addr_to_string(AF_INET6, &prefix, &buf);
|
|
||||||
log_link_debug(l, "Removed DHCPv6 Prefix Delegation route %s/64",
|
|
||||||
strnull(buf));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1315,6 +1297,7 @@ int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
|
||||||
Link *l;
|
Link *l;
|
||||||
int r;
|
int r;
|
||||||
Route *route;
|
Route *route;
|
||||||
|
_cleanup_free_ char *buf = NULL;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
assert_return(m, -EINVAL);
|
||||||
assert_return(m->dhcp6_prefixes, -ENODATA);
|
assert_return(m->dhcp6_prefixes, -ENODATA);
|
||||||
|
@ -1327,8 +1310,17 @@ int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) {
|
||||||
(void) sd_radv_remove_prefix(l->radv, addr, 64);
|
(void) sd_radv_remove_prefix(l->radv, addr, 64);
|
||||||
r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64,
|
r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64,
|
||||||
0, 0, 0, &route);
|
0, 0, 0, &route);
|
||||||
if (r >= 0)
|
if (r < 0)
|
||||||
(void) route_remove(route, l, dhcp6_route_remove_callback);
|
return r;
|
||||||
|
|
||||||
|
r = route_remove(route, l, dhcp6_route_remove_callback);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf);
|
||||||
|
log_link_debug(l, "Removing prefix route %s/64", strnull(buf));
|
||||||
|
|
||||||
|
l = link_ref(l);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1452,11 +1444,18 @@ void manager_free(Manager *m) {
|
||||||
network_free(network);
|
network_free(network);
|
||||||
|
|
||||||
while ((link = hashmap_first(m->dhcp6_prefixes)))
|
while ((link = hashmap_first(m->dhcp6_prefixes)))
|
||||||
link_unref(link);
|
manager_dhcp6_prefix_remove_all(m, link);
|
||||||
hashmap_free(m->dhcp6_prefixes);
|
hashmap_free(m->dhcp6_prefixes);
|
||||||
|
|
||||||
while ((link = hashmap_first(m->links)))
|
while ((link = hashmap_first(m->links))) {
|
||||||
|
if (link->dhcp6_client)
|
||||||
|
(void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client,
|
||||||
|
link);
|
||||||
|
|
||||||
|
hashmap_remove(m->links, INT_TO_PTR(link->ifindex));
|
||||||
|
|
||||||
link_unref(link);
|
link_unref(link);
|
||||||
|
}
|
||||||
hashmap_free(m->links);
|
hashmap_free(m->links);
|
||||||
|
|
||||||
set_free(m->links_requesting_uuid);
|
set_free(m->links_requesting_uuid);
|
||||||
|
|
|
@ -138,6 +138,7 @@ DHCP.UseTimezone, config_parse_bool,
|
||||||
DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
|
DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
|
||||||
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
|
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
|
||||||
DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
|
DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, rapid_commit)
|
||||||
|
DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information)
|
||||||
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
|
IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
|
||||||
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
|
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
|
||||||
IPv6AcceptRA.RouteTable, config_parse_uint32, 0, offsetof(Network, ipv6_accept_ra_route_table)
|
IPv6AcceptRA.RouteTable, config_parse_uint32, 0, offsetof(Network, ipv6_accept_ra_route_table)
|
||||||
|
|
|
@ -171,6 +171,9 @@ struct Network {
|
||||||
struct in6_addr *router_dns;
|
struct in6_addr *router_dns;
|
||||||
unsigned n_router_dns;
|
unsigned n_router_dns;
|
||||||
char **router_search_domains;
|
char **router_search_domains;
|
||||||
|
bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
|
||||||
|
RA flag is set, see RFC 7084,
|
||||||
|
WPD-4 */
|
||||||
|
|
||||||
/* Bridge Support */
|
/* Bridge Support */
|
||||||
int use_bpdu;
|
int use_bpdu;
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <net/ethernet.h>
|
#include <net/ethernet.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "sd-dhcp6-lease.h"
|
#include "sd-dhcp6-lease.h"
|
||||||
|
@ -120,8 +119,14 @@ int sd_dhcp6_client_get_information_request(
|
||||||
int sd_dhcp6_client_set_request_option(
|
int sd_dhcp6_client_set_request_option(
|
||||||
sd_dhcp6_client *client,
|
sd_dhcp6_client *client,
|
||||||
uint16_t option);
|
uint16_t option);
|
||||||
|
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client,
|
||||||
|
int *delegation);
|
||||||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,
|
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,
|
||||||
bool delegation);
|
int delegation);
|
||||||
|
int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client,
|
||||||
|
int *request);
|
||||||
|
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
|
||||||
|
int request);
|
||||||
|
|
||||||
int sd_dhcp6_client_get_lease(
|
int sd_dhcp6_client_get_lease(
|
||||||
sd_dhcp6_client *client,
|
sd_dhcp6_client *client,
|
||||||
|
|
Loading…
Reference in a new issue