X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp6-client.c;h=a432bbfc488d768c803385a02f2375d71a096c34;hb=c1ff5570f4a04bb9aedea444c12dce81679224ec;hp=fa4f9b5dc2c79572cd094d076dcdf1970c08a672;hpb=76253e73f9c9c24fec755e485516f3b55d0707b4;p=elogind.git diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index fa4f9b5dc..a432bbfc4 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -26,8 +26,6 @@ #include "udev.h" #include "udev-util.h" -#include "virt.h" -#include "siphash24.h" #include "util.h" #include "refcnt.h" @@ -36,14 +34,7 @@ #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) - -/* RFC 3315 section 9.1: - * A DUID can be no more than 128 octets long (not including the type code). - */ -#define MAX_DUID_LEN 128 +#include "dhcp-identifier.h" #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN @@ -62,6 +53,7 @@ struct sd_dhcp6_client { usec_t transaction_start; struct sd_dhcp6_lease *lease; int fd; + bool information_request; be16_t *req_opts; size_t req_opts_allocated; size_t req_opts_len; @@ -72,32 +64,7 @@ struct sd_dhcp6_client { sd_event_source *timeout_resend_expire; sd_dhcp6_client_cb_t cb; void *userdata; - union { - struct { - uint16_t type; /* DHCP6_DUID_LLT */ - uint16_t htype; - uint32_t time; - uint8_t haddr[0]; - } _packed_ llt; - struct { - uint16_t type; /* DHCP6_DUID_EN */ - uint32_t pen; - uint8_t id[8]; - } _packed_ en; - struct { - uint16_t type; /* DHCP6_DUID_LL */ - uint16_t htype; - uint8_t haddr[0]; - } _packed_ ll; - struct { - uint16_t type; /* DHCP6_DUID_UUID */ - sd_id128_t uuid; - } _packed_ uuid; - struct { - uint16_t type; - uint8_t data[MAX_DUID_LEN]; - } _packed_ raw; - } duid; + struct duid duid; size_t duid_len; }; @@ -220,9 +187,28 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du break; } - client->duid.raw.type = htobe16(type); + client->duid.type = htobe16(type); memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len; + client->duid_len = duid_len + sizeof(client->duid.type); + + return 0; +} + +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, + bool enabled) { + assert_return(client, -EINVAL); + + client->information_request = enabled; + + return 0; +} + +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, + bool *enabled) { + assert_return(client, -EINVAL); + assert_return(enabled, -EINVAL); + + *enabled = client->information_request; return 0; } @@ -333,6 +319,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { message->transaction_id = client->transaction_id; switch(client->state) { + case DHCP6_STATE_INFORMATION_REQUEST: + message->type = DHCP6_INFORMATION_REQUEST; + + break; + case DHCP6_STATE_SOLICITATION: message->type = DHCP6_SOLICIT; @@ -494,6 +485,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, client->timeout_resend = sd_event_source_unref(client->timeout_resend); switch (client->state) { + case DHCP6_STATE_INFORMATION_REQUEST: + init_retransmit_time = DHCP6_INF_TIMEOUT; + max_retransmit_time = DHCP6_INF_MAX_RT; + + break; + case DHCP6_STATE_SOLICITATION: if (client->retransmit_count && client->lease) { @@ -590,8 +587,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, if (r < 0) goto error; - r = sd_event_source_set_name(client->timeout_resend, - "dhcp6-resend-timer"); + r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer"); if (r < 0) goto error; @@ -614,8 +610,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, if (r < 0) goto error; - r = sd_event_source_set_name(client->timeout_resend_expire, - "dhcp6-resend-expire-timer"); + r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer"); if (r < 0) goto error; } @@ -628,47 +623,16 @@ error: } static int client_ensure_iaid(sd_dhcp6_client *client) { - /* name is a pointer to memory in the udev_device struct, so must - have the same scope */ - _cleanup_udev_device_unref_ struct udev_device *device = NULL; - const char *name = NULL; - uint64_t id; + int r; assert(client); if (client->ia_na.id) return 0; - if (detect_container(NULL) <= 0) { - /* not in a container, udev will be around */ - _cleanup_udev_unref_ struct udev *udev; - char ifindex_str[2 + DECIMAL_STR_MAX(int)]; - - udev = udev_new(); - if (!udev) - return -ENOMEM; - - sprintf(ifindex_str, "n%d", client->index); - device = udev_device_new_from_device_id(udev, ifindex_str); - if (!device) - return -errno; - - if (udev_device_get_is_initialized(device) <= 0) - /* not yet ready */ - return -EBUSY; - - name = net_get_name(device); - } - - if (name) - siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes); - else - /* fall back to mac address if no predictable name available */ - siphash24((uint8_t*)&id, &client->mac_addr, - client->mac_addr_len, HASH_KEY.bytes); - - /* fold into 32 bits */ - client->ia_na.id = (id & 0xffffffff) ^ (id >> 32); + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id); + if (r < 0) + return r; return 0; } @@ -746,6 +710,12 @@ static int client_parse_message(sd_dhcp6_client *client, break; case DHCP6_OPTION_IA_NA: + if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { + log_dhcp6_client(client, "Information request ignoring IA NA option"); + + break; + } + r = dhcp6_option_parse_ia(&optval, &optlen, optcode, &lease->ia); if (r < 0 && r != -ENOMSG) @@ -772,16 +742,21 @@ static int client_parse_message(sd_dhcp6_client *client, } } - if ((r < 0 && r != -ENOMSG) || !clientid) { + if (r == -ENOMSG) + r = 0; + + if (r < 0 || !clientid) { log_dhcp6_client(client, "%s has incomplete options", dhcp6_message_type_to_string(message->type)); return -EINVAL; } - r = dhcp6_lease_get_serverid(lease, &id, &id_len); - if (r < 0) - log_dhcp6_client(client, "%s has no server id", - dhcp6_message_type_to_string(message->type)); + if (client->state != DHCP6_STATE_INFORMATION_REQUEST) { + r = dhcp6_lease_get_serverid(lease, &id, &id_len); + if (r < 0) + log_dhcp6_client(client, "%s has no server id", + dhcp6_message_type_to_string(message->type)); + } return r; } @@ -813,12 +788,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, return 0; } - if (client->lease) + if (client->lease) { dhcp6_lease_clear_timers(&client->lease->ia); + client->lease = sd_dhcp6_lease_unref(client->lease); + } - client->lease = sd_dhcp6_lease_unref(client->lease); - client->lease = lease; - lease = NULL; + if (client->state != DHCP6_STATE_INFORMATION_REQUEST) { + client->lease = lease; + lease = NULL; + } return DHCP6_STATE_BOUND; } @@ -845,7 +823,8 @@ static int client_receive_advertise(sd_dhcp6_client *client, return r; r = dhcp6_lease_get_preference(client->lease, &pref_lease); - if (!client->lease || r < 0 || pref_advertise > pref_lease) { + + if (r < 0 || pref_advertise > pref_lease) { sd_dhcp6_lease_unref(client->lease); client->lease = lease; lease = NULL; @@ -912,6 +891,17 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, return 0; switch (client->state) { + case DHCP6_STATE_INFORMATION_REQUEST: + r = client_receive_reply(client, message, len); + if (r < 0) + return 0; + + client_notify(client, DHCP6_EVENT_INFORMATION_REQUEST); + + client_start(client, DHCP6_STATE_STOPPED); + + break; + case DHCP6_STATE_SOLICITATION: r = client_receive_advertise(client, message, len); @@ -987,38 +977,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) switch (state) { case DHCP6_STATE_STOPPED: - case DHCP6_STATE_SOLICITATION: + if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { + client->state = DHCP6_STATE_STOPPED; - r = client_ensure_iaid(client); - if (r < 0) - return r; - - r = dhcp6_network_bind_udp_socket(client->index, NULL); - if (r < 0) - return r; - - client->fd = r; - - r = sd_event_add_io(client->event, &client->receive_message, - client->fd, EPOLLIN, client_receive_message, - client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->receive_message, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_name(client->receive_message, - "dhcp6-receive-message"); - if (r < 0) - return r; + return 0; + } + /* fall through */ + case DHCP6_STATE_SOLICITATION: client->state = DHCP6_STATE_SOLICITATION; break; + case DHCP6_STATE_INFORMATION_REQUEST: case DHCP6_STATE_REQUEST: case DHCP6_STATE_RENEW: case DHCP6_STATE_REBIND: @@ -1059,8 +1030,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; - r = sd_event_source_set_name(client->lease->ia.timeout_t1, - "dhcp6-t1-timeout"); + r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout"); if (r < 0) return r; @@ -1084,8 +1054,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; - r = sd_event_source_set_name(client->lease->ia.timeout_t2, - "dhcp6-t2-timeout"); + r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout"); if (r < 0) return r; @@ -1108,8 +1077,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; - r = sd_event_source_set_name(client->timeout_resend, - "dhcp6-resend-timeout"); + r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout"); if (r < 0) return r; @@ -1126,6 +1094,7 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client) int sd_dhcp6_client_start(sd_dhcp6_client *client) { int r = 0; + enum DHCP6State state = DHCP6_STATE_SOLICITATION; assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); @@ -1135,7 +1104,44 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) if (r < 0) return r; - return client_start(client, DHCP6_STATE_SOLICITATION); + r = client_ensure_iaid(client); + if (r < 0) + return r; + + r = dhcp6_network_bind_udp_socket(client->index, NULL); + if (r < 0) + return r; + + client->fd = r; + + r = sd_event_add_io(client->event, &client->receive_message, + client->fd, EPOLLIN, client_receive_message, + client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->receive_message, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->receive_message, + "dhcp6-receive-message"); + if (r < 0) + goto error; + + if (client->information_request) + state = DHCP6_STATE_INFORMATION_REQUEST; + + log_dhcp6_client(client, "Started in %s mode", + client->information_request? "Information request": + "Managed"); + + return client_start(client, state); + +error: + client_reset(client); + return r; } int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, @@ -1182,7 +1188,7 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) { } sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { - if (client && REFCNT_DEC(client->n_ref) <= 0) { + if (client && REFCNT_DEC(client->n_ref) == 0) { client_reset(client); sd_dhcp6_client_detach_event(client); @@ -1199,7 +1205,6 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { int sd_dhcp6_client_new(sd_dhcp6_client **ret) { _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL; - sd_id128_t machine_id; int r; size_t t; @@ -1218,18 +1223,10 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) client->fd = -1; /* initialize DUID */ - client->duid.en.type = htobe16(DHCP6_DUID_EN); - client->duid.en.pen = htobe32(SYSTEMD_PEN); - client->duid_len = sizeof(client->duid.en); - - r = sd_id128_get_machine(&machine_id); + r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); if (r < 0) return r; - /* a bit of snake-oil perhaps, but no need to expose the machine-id - directly */ - siphash24(client->duid.en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes); - client->req_opts_len = ELEMENTSOF(default_req_opts); client->req_opts = new0(be16_t, client->req_opts_len);