dh-dhcp{,6}-client: change the semantics of DUID setting

Both versions of the code are changed to allow the caller to override
DUID using simple rules: duid type and value may be specified, in
which case the caller is responsible to providing the contents,
or just duid type may be specified as DUID_TYPE_EN, in which case we
we fill in the values. In the future more support for other types may
be added, e.g. DUID_TYPE_LLT.

There still remains and ugly discrepancy between dhcp4 and dhcp6 code:
dhcp6 has sd_dhcp6_client_set_duid and sd_dhcp6_client_set_iaid and
requires client->state to be DHCP6_STATE_STOPPED, while dhcp4 has
sd_dhcp_client_set_iaid_duid and will reconfigure the client if it
is not stopped. This commit doesn't touch that part.

This addresses #3127 § 2.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2016-04-29 21:18:11 -04:00
parent 3b6a4e97ea
commit d7df2fd317
3 changed files with 43 additions and 19 deletions

View file

@ -318,6 +318,11 @@ int sd_dhcp_client_set_client_id(
return 0; return 0;
} }
/**
* Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
* without further modification. Otherwise, if duid_type is supported, DUID
* is set based on that type. Otherwise, an error is returned.
*/
int sd_dhcp_client_set_iaid_duid( int sd_dhcp_client_set_iaid_duid(
sd_dhcp_client *client, sd_dhcp_client *client,
uint32_t iaid, uint32_t iaid,
@ -327,9 +332,18 @@ int sd_dhcp_client_set_iaid_duid(
DHCP_CLIENT_DONT_DESTROY(client); DHCP_CLIENT_DONT_DESTROY(client);
int r; int r;
assert_return(client, -EINVAL); size_t len;
zero(client->client_id);
assert_return(client, -EINVAL);
assert_return(duid_len == 0 || duid != NULL, -EINVAL);
if (duid != NULL) {
r = dhcp_validate_duid_len(duid_type, duid_len);
if (r < 0)
return r;
}
zero(client->client_id);
client->client_id.type = 255; client->client_id.type = 255;
/* If IAID is not configured, generate it. */ /* If IAID is not configured, generate it. */
@ -342,22 +356,18 @@ int sd_dhcp_client_set_iaid_duid(
} else } else
client->client_id.ns.iaid = htobe32(iaid); client->client_id.ns.iaid = htobe32(iaid);
/* If DUID is not configured, generate DUID-EN. */ if (duid != NULL) {
if (duid_len == 0) {
r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid,
&duid_len);
if (r < 0)
return r;
} else {
r = dhcp_validate_duid_len(client->client_id.type, duid_len);
if (r < 0)
return r;
client->client_id.ns.duid.type = htobe16(duid_type); client->client_id.ns.duid.type = htobe16(duid_type);
memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
duid_len += sizeof(client->client_id.ns.duid.type); len = sizeof(client->client_id.ns.duid.type) + duid_len;
} } else if (duid_type == DUID_TYPE_EN) {
r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
if (r < 0)
return r;
} else
return -EOPNOTSUPP;
client->client_id_len = sizeof(client->client_id.type) + duid_len + client->client_id_len = sizeof(client->client_id.type) + len +
sizeof(client->client_id.ns.iaid); sizeof(client->client_id.ns.iaid);
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {

View file

@ -186,6 +186,11 @@ static int client_ensure_duid(sd_dhcp6_client *client) {
return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
} }
/**
* Sets DUID. If duid is non-null, the DUID is set to duid_type + duid
* without further modification. Otherwise, if duid_type is supported, DUID
* is set based on that type. Otherwise, an error is returned.
*/
int sd_dhcp6_client_set_duid( int sd_dhcp6_client_set_duid(
sd_dhcp6_client *client, sd_dhcp6_client *client,
uint16_t duid_type, uint16_t duid_type,
@ -194,16 +199,25 @@ int sd_dhcp6_client_set_duid(
int r; int r;
assert_return(client, -EINVAL); assert_return(client, -EINVAL);
assert_return(duid_len == 0 || duid != NULL, -EINVAL);
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
if (duid_len > 0) { if (duid != NULL) {
r = dhcp_validate_duid_len(duid_type, duid_len); r = dhcp_validate_duid_len(duid_type, duid_len);
if (r < 0) if (r < 0)
return r; return r;
}
if (duid != NULL) {
client->duid.type = htobe16(duid_type); client->duid.type = htobe16(duid_type);
memcpy(&client->duid.raw.data, duid, duid_len); memcpy(&client->duid.raw.data, duid, duid_len);
client->duid_len = duid_len + sizeof(client->duid.type); client->duid_len = sizeof(client->duid.type) + duid_len;
} } else if (duid_type == DUID_TYPE_EN) {
r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
if (r < 0)
return r;
} else
return -EOPNOTSUPP;
return 0; return 0;
} }

View file

@ -1037,7 +1037,7 @@ int manager_new(Manager **ret) {
if (r < 0) if (r < 0)
return r; return r;
m->duid_type = _DUID_TYPE_INVALID; m->duid_type = DUID_TYPE_EN;
*ret = m; *ret = m;
m = NULL; m = NULL;