The caller may have an existing DUID that it wants to use, and may want to use some other DUID generation scheme than systemd's default DUID-EN. --- src/libsystemd-network/sd-dhcp6-client.c | 52 +++++++++++++++++++----------- src/libsystemd-network/test-dhcp6-client.c | 4 +-- src/network/networkd-link.c | 2 +- src/systemd/sd-dhcp6-client.h | 2 +- 4 files changed, 38 insertions(+), 22 deletions(-)
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index c6c82eb..8123dc8 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -35,14 +35,16 @@ #include "dhcp6-protocol.h" #include "dhcp6-internal.h" #include "dhcp6-lease-internal.h" #define SYSTEMD_PEN 43793 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +#define MAX_DUID_LEN 32 + struct sd_dhcp6_client { RefCount n_ref; enum DHCP6State state; sd_event *event; int event_priority; int index; @@ -57,20 +59,16 @@ struct sd_dhcp6_client { sd_event_source *receive_message; usec_t retransmit_time; uint8_t retransmit_count; sd_event_source *timeout_resend; sd_event_source *timeout_resend_expire; sd_dhcp6_client_cb_t cb; void *userdata; - - struct duid_en { - uint16_t type; /* DHCP6_DUID_EN */ - uint32_t pen; - uint8_t id[8]; - } _packed_ duid; + uint8_t duid[MAX_DUID_LEN]; + size_t duid_len; }; static const uint16_t default_req_opts[] = { DHCP6_OPTION_DNS_SERVERS, DHCP6_OPTION_DOMAIN_LIST, DHCP6_OPTION_NTP_SERVER, }; @@ -300,15 +298,15 @@ static int client_send_message(sd_dhcp6_client *client) { r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO, client->req_opts_len * sizeof(be16_t), client->req_opts); if (r < 0) return r; r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID, - sizeof(client->duid), &client->duid); + client->duid_len, &client->duid); if (r < 0) return r; r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message, len - optlen); if (r < 0) return r; @@ -585,15 +583,15 @@ static int client_parse_message(sd_dhcp6_client *client, case DHCP6_OPTION_CLIENTID: if (clientid) { log_dhcp6_client(client, "%s contains multiple clientids", dhcp6_message_type_to_string(message->type)); return -EINVAL; } - if (optlen != sizeof(client->duid) || + if (optlen != client->duid_len || memcmp(&client->duid, optval, optlen) != 0) { log_dhcp6_client(client, "%s DUID does not match", dhcp6_message_type_to_string(message->type)); return -EINVAL; } clientid = true; @@ -1059,47 +1057,65 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { return NULL; } return client; } -int sd_dhcp6_client_new(sd_dhcp6_client **ret) +struct duid_en { + uint16_t type; /* DHCP6_DUID_EN */ + uint32_t pen; + uint8_t id[8]; +} _packed_; + +int sd_dhcp6_client_new(sd_dhcp6_client **ret, uint8_t *duid, size_t duid_len) { _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL; sd_id128_t machine_id; int r; size_t t; assert_return(ret, -EINVAL); + if (duid) + assert_return(duid_len > 0 && duid_len < MAX_DUID_LEN, -EINVAL); + else + assert_return(duid_len == 0, -EINVAL); client = new0(sd_dhcp6_client, 1); if (!client) return -ENOMEM; client->n_ref = REFCNT_INIT; client->ia_na.type = DHCP6_OPTION_IA_NA; client->index = -1; client->fd = -1; /* initialize DUID */ - client->duid.type = htobe16(DHCP6_DUID_EN); - client->duid.pen = htobe32(SYSTEMD_PEN); + if (duid) { + memcpy(&client->duid, duid, duid_len); + client->duid_len = duid_len; + } else { + struct duid_en *en = (struct duid_en *) &client->duid; - r = sd_id128_get_machine(&machine_id); - if (r < 0) - return r; + en->type = htobe16(DHCP6_DUID_EN); + en->pen = htobe32(SYSTEMD_PEN); - /* a bit of snake-oil perhaps, but no need to expose the machine-id - directly */ - siphash24(client->duid.id, &machine_id, sizeof(machine_id), - HASH_KEY.bytes); + r = sd_id128_get_machine(&machine_id); + if (r < 0) + return r; + + /* a bit of snake-oil perhaps, but no need to expose the + machine-id directly */ + siphash24(en->id, &machine_id, sizeof(machine_id), + HASH_KEY.bytes); + client->duid_len = sizeof (*en); + } client->req_opts_len = ELEMENTSOF(default_req_opts); client->req_opts = new0(be16_t, client->req_opts_len); if (!client->req_opts) return -ENOMEM; diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 96c68e1..3545935 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -52,15 +52,15 @@ static uint8_t test_duid[14] = { }; static int test_client_basic(sd_event *e) { sd_dhcp6_client *client; if (verbose) printf("* %s\n", __FUNCTION__); - assert_se(sd_dhcp6_client_new(&client) >= 0); + assert_se(sd_dhcp6_client_new(&client, NULL, 0) >= 0); assert_se(client); assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); assert_se(sd_dhcp6_client_set_index(client, 15) == 0); assert_se(sd_dhcp6_client_set_index(client, -42) == -EINVAL); assert_se(sd_dhcp6_client_set_index(client, -1) == 0); @@ -538,15 +538,15 @@ static void test_client_solicit_cb(sd_dhcp6_client *client, int event, static int test_client_solicit(sd_event *e) { sd_dhcp6_client *client; usec_t time_now = now(clock_boottime_or_monotonic()); if (verbose) printf("* %s\n", __FUNCTION__); - assert_se(sd_dhcp6_client_new(&client) >= 0); + assert_se(sd_dhcp6_client_new(&client, NULL, 0) >= 0); assert_se(client); assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0); assert_se(sd_dhcp6_client_set_index(client, test_index) == 0); assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index accb42b..eff14ca 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1367,15 +1367,15 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) { return; } if (link->dhcp6_client) return; - r = sd_dhcp6_client_new(&link->dhcp6_client); + r = sd_dhcp6_client_new(&link->dhcp6_client, NULL, 0); if (r < 0) return; r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0); if (r < 0) { link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); return; diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 93edcc4..b3ec82f 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -54,10 +54,10 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client); int sd_dhcp6_client_start(sd_dhcp6_client *client); int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority); int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client); -int sd_dhcp6_client_new(sd_dhcp6_client **ret); +int sd_dhcp6_client_new(sd_dhcp6_client **ret, uint8_t *duid, size_t duid_len); #endif -- 1.9.3 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel