sd-dhcp6-client.c revision 513a6fa8679510ea1b55967bdb482dd5f8a39f21
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/***
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright (C) 2014 Intel Corporation. All rights reserved.
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering***/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <errno.h>
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include <string.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <sys/ioctl.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "udev.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "udev-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "virt.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "siphash24.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "refcnt.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "network-internal.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "sd-dhcp6-client.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "dhcp6-protocol.h"
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers#include "dhcp6-internal.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "dhcp6-lease-internal.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define SYSTEMD_PEN 43793
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstruct sd_dhcp6_client {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering RefCount n_ref;
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering enum DHCP6State state;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event *event;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int event_priority;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers int index;
7085053a437456ab87d726f3697002dd811fdf7aDaniel Wallace struct ether_addr mac_addr;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering DHCP6IA ia_na;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering be32_t transaction_id;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct sd_dhcp6_lease *lease;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int fd;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source *receive_message;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering usec_t retransmit_time;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint8_t retransmit_count;
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer sd_event_source *timeout_resend;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source *timeout_resend_expire;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_dhcp6_client_cb_t cb;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering void *userdata;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct duid_en {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint16_t type; /* DHCP6_DUID_EN */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint32_t pen;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint8_t id[8];
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering } _packed_ duid;
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering};
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringconst char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_SOLICIT] = "SOLICIT",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_ADVERTISE] = "ADVERTISE",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_REQUEST] = "REQUEST",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_CONFIRM] = "CONFIRM",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_RENEW] = "RENEW",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_REBIND] = "REBIND",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_REPLY] = "REPLY",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_RELEASE] = "RELEASE",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_DECLINE] = "DECLINE",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_RECONFIGURE] = "RECONFIGURE",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_RELAY_FORW] = "RELAY-FORW",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_RELAY_REPL] = "RELAY-REPL",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering};
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringconst char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_STATUS_SUCCESS] = "Success",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_STATUS_NOT_ON_LINK] = "Not on link",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering};
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int client_start(sd_dhcp6_client *client, enum DHCP6State state);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_dhcp6_client_cb_t cb, void *userdata)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering{
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->cb = cb;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->userdata = userdata;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return 0;
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek}
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversint sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers{
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers assert_return(client, -EINVAL);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers assert_return(interface_index >= -1, -EINVAL);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers client->index = interface_index;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 0;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers}
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieversint sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const struct ether_addr *mac_addr)
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers{
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client, -EINVAL);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers if (mac_addr)
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers memcpy(&client->mac_addr, mac_addr, sizeof(client->mac_addr));
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers else
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers memset(&client->mac_addr, 0x00, sizeof(client->mac_addr));
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sieversint sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers assert_return(client, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(ret, -EINVAL);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!client->lease)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMSG;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers *ret = sd_dhcp6_lease_ref(client->lease);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic sd_dhcp6_client *client_notify(sd_dhcp6_client *client, int event) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (client->cb) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client = sd_dhcp6_client_ref(client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->cb(client, event, client->userdata);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client = sd_dhcp6_client_unref(client);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return client;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sieversstatic int client_reset(sd_dhcp6_client *client) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers assert_return(client, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers client->receive_message =
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers sd_event_source_unref(client->receive_message);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->fd = safe_close(client->fd);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->transaction_id = 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->ia_na.timeout_t1 =
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers sd_event_source_unref(client->ia_na.timeout_t1);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers client->ia_na.timeout_t2 =
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering sd_event_source_unref(client->ia_na.timeout_t2);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_time = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_count = 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers client->timeout_resend = sd_event_source_unref(client->timeout_resend);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->timeout_resend_expire =
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(client->timeout_resend_expire);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->state = DHCP6_STATE_STOPPED;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic sd_dhcp6_client *client_stop(sd_dhcp6_client *client, int error) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client, NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client = client_notify(client, error);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (client)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client_reset(client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return client;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int client_send_message(sd_dhcp6_client *client) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ DHCP6Message *message = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering struct in6_addr all_servers =
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size_t len, optlen = 512;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint8_t *opt;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering len = sizeof(DHCP6Message) + optlen;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering message = malloc0(len);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!message)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering opt = (uint8_t *)(message + 1);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering message->transaction_id = client->transaction_id;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch(client->state) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_SOLICITATION:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering message->type = DHCP6_SOLICIT;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_REQUEST:
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna message->type = DHCP6_REQUEST;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->lease->serverid_len,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->lease->serverid);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_STOPPED:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_RS:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_BOUND:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sizeof(client->duid), &client->duid);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering len - optlen);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "Sent %s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dhcp6_message_type_to_string(message->type));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int client_timeout_t2(sd_event_source *s, uint64_t usec,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering void *userdata) {
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar sd_dhcp6_client *client = userdata;
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(s, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client->lease, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->lease->ia.timeout_t2 =
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(client->lease->ia.timeout_t2);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "Timeout T2");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering return 0;
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering}
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int client_timeout_t1(sd_event_source *s, uint64_t usec,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering void *userdata) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_dhcp6_client *client = userdata;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(s, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client, -EINVAL);
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek assert_return(client->lease, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->lease->ia.timeout_t1 =
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(client->lease->ia.timeout_t1);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "Timeout T1");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna}
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnastatic int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna void *userdata) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna sd_dhcp6_client *client = userdata;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna assert(s);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna assert(client);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna assert(client->event);
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna client_stop(client, DHCP6_EVENT_RESEND_EXPIRE);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna}
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnastatic usec_t client_timeout_compute_random(usec_t val) {
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek return val - val / 10 +
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna}
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnastatic int client_timeout_resend(sd_event_source *s, uint64_t usec,
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna void *userdata) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna int r = 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna sd_dhcp6_client *client = userdata;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna usec_t time_now, init_retransmit_time, max_retransmit_time;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna usec_t max_retransmit_duration;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna uint8_t max_retransmit_count = 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna char time_string[FORMAT_TIMESPAN_MAX];
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna assert(s);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek assert(client);
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek assert(client->event);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek client->timeout_resend = sd_event_source_unref(client->timeout_resend);
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek switch (client->state) {
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek case DHCP6_STATE_SOLICITATION:
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (client->retransmit_count && client->lease) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna client_start(client, DHCP6_STATE_REQUEST);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna }
8333c77edf8fd1654cd96f3f6ee0f078dd64b58bZbigniew Jędrzejewski-Szmek
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna init_retransmit_time = DHCP6_SOL_TIMEOUT;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek max_retransmit_time = DHCP6_SOL_MAX_RT;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna max_retransmit_count = 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna max_retransmit_duration = 0;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna break;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers case DHCP6_STATE_REQUEST:
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek init_retransmit_time = DHCP6_REQ_TIMEOUT;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna max_retransmit_time = DHCP6_REQ_MAX_RT;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna max_retransmit_count = DHCP6_REQ_MAX_RC;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna max_retransmit_duration = 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna break;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna case DHCP6_STATE_STOPPED:
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna case DHCP6_STATE_RS:
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna case DHCP6_STATE_BOUND:
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek return 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna }
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (max_retransmit_count &&
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek client->retransmit_count >= max_retransmit_count) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna client_stop(client, DHCP6_EVENT_RETRANS_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek }
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = client_send_message(client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r >= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_count++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek goto error;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!client->retransmit_time) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers client->retransmit_time =
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers client_timeout_compute_random(init_retransmit_time);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (client->state == DHCP6_STATE_SOLICITATION)
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering client->retransmit_time += init_retransmit_time / 10;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (max_retransmit_time &&
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_time > max_retransmit_time / 2)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "Next retransmission in %s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format_timespan(time_string, FORMAT_TIMESPAN_MAX,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_time, 0));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_time(client->event, &client->timeout_resend,
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering CLOCK_MONOTONIC,
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering time_now + client->retransmit_time,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering 10 * USEC_PER_MSEC, client_timeout_resend,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto error;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_source_set_priority(client->timeout_resend,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers client->event_priority);
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering if (r < 0)
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering goto error;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering if (max_retransmit_duration && !client->timeout_resend_expire) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering max_retransmit_duration / USEC_PER_SEC);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_time(client->event,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &client->timeout_resend_expire,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering CLOCK_MONOTONIC,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering time_now + max_retransmit_duration,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering USEC_PER_SEC,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client_timeout_resend_expire, client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto error;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_source_set_priority(client->timeout_resend_expire,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->event_priority);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering goto error;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringerror:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client_stop(client, r);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic int client_ensure_iaid(sd_dhcp6_client *client) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *name = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint64_t id;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek if (client->ia_na.id)
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (detect_container(NULL) <= 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* not in a container, udev will be around */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_udev_unref_ struct udev *udev;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_udev_device_unref_ struct udev_device *device = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char ifindex_str[2 + DECIMAL_STR_MAX(int)];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers udev = udev_new();
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer if (!udev)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sprintf(ifindex_str, "n%d", client->index);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering device = udev_device_new_from_device_id(udev, ifindex_str);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!device)
4a9e80b3b5d0d3c0cabac01c35db18d95f27c9c1Michał Górny return -errno;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (udev_device_get_is_initialized(device) <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* not yet ready */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EBUSY;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering name = net_get_name(device);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (name)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* fall back to mac address if no predictable name available */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering siphash24((uint8_t*)&id, &client->mac_addr, ETH_ALEN,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering HASH_KEY.bytes);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* fold into 32 bits */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersenstatic int client_parse_message(sd_dhcp6_client *client,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering DHCP6Message *message, size_t len,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_dhcp6_lease *lease) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint8_t *optval, *option = (uint8_t *)(message + 1), *id = NULL;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers uint16_t optcode, status;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers size_t optlen, id_len;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers bool clientid = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering be32_t iaid_lease;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &optval)) >= 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (optcode) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_OPTION_CLIENTID:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (clientid) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "%s contains multiple clientids",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dhcp6_message_type_to_string(message->type));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (optlen != sizeof(client->duid) ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering memcmp(&client->duid, optval, optlen) != 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "%s DUID does not match",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dhcp6_message_type_to_string(message->type));
6b2b6f30e38d67b032d6bdc6b47ae05e143e96c5Michal Schmidt
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering }
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering clientid = true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_OPTION_SERVERID:
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers r = dhcp6_lease_get_serverid(lease, &id, &id_len);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r >= 0 && id) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers log_dhcp6_client(client, "%s contains multiple serverids",
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers dhcp6_message_type_to_string(message->type));
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering return -EINVAL;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering }
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering r = dhcp6_lease_set_serverid(lease, optval, optlen);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering break;
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering case DHCP6_OPTION_PREFERENCE:
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (optlen != 1)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EINVAL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dhcp6_lease_set_preference(lease, *optval);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering break;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering case DHCP6_OPTION_STATUS_CODE:
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (optlen < 2)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EINVAL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering status = optval[0] << 8 | optval[1];
c62e11ce3966c55d23520b9f0785c7e839cf7f37Lennart Poettering if (status) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_dhcp6_client(client, "%s Status %s",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dhcp6_message_type_to_string(message->type),
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dhcp6_message_status_to_string(status));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EINVAL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering break;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering case DHCP6_OPTION_IA_NA:
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering &lease->ia);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0 && r != -ENOMSG)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dhcp6_lease_get_iaid(lease, &iaid_lease);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (client->ia_na.id != iaid_lease) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_dhcp6_client(client, "%s has wrong IAID",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dhcp6_message_type_to_string(message->type));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EINVAL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering break;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if ((r < 0 && r != -ENOMSG) || !clientid) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_dhcp6_client(client, "%s has incomplete options",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dhcp6_message_type_to_string(message->type));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EINVAL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dhcp6_lease_get_serverid(lease, &id, &id_len);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering log_dhcp6_client(client, "%s has no server id",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dhcp6_message_type_to_string(message->type));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering size_t len)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering{
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (reply->type != DHCP6_REPLY)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EINVAL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dhcp6_lease_new(&lease);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -ENOMEM;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = client_parse_message(client, reply, len, lease);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dhcp6_lease_clear_timers(&client->lease->ia);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering client->lease = sd_dhcp6_lease_unref(client->lease);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering client->lease = lease;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering lease = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return DHCP6_STATE_BOUND;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int client_receive_advertise(sd_dhcp6_client *client,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering DHCP6Message *advertise, size_t len) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering uint8_t pref_advertise = 0, pref_lease = 0;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (advertise->type != DHCP6_ADVERTISE)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return -EINVAL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dhcp6_lease_new(&lease);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = client_parse_message(client, advertise, len, lease);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dhcp6_lease_get_preference(lease, &pref_advertise);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
82c1d8f4eb74ddd9be2c9b9b56d9dc564c599effLennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dhcp6_lease_get_preference(client->lease, &pref_lease);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (!client->lease || r < 0 || pref_advertise > pref_lease) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering sd_dhcp6_lease_unref(client->lease);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering client->lease = lease;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers lease = NULL;
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering r = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (pref_advertise == 255 || client->retransmit_count > 1)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = DHCP6_STATE_REQUEST;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering void *userdata) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering sd_dhcp6_client *client = userdata;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering _cleanup_free_ DHCP6Message *message;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r, buflen, len;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(s);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(client->event);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = ioctl(fd, FIONREAD, &buflen);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0 || buflen <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering buflen = DHCP6_MIN_OPTIONS_SIZE;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering message = malloc0(buflen);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!message)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering len = read(fd, message, buflen);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if ((size_t)len < sizeof(DHCP6Message)) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers log_dhcp6_client(client, "could not receive message from UDP socket: %s", strerror(errno));
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers }
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers switch(message->type) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers case DHCP6_SOLICIT:
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers case DHCP6_REQUEST:
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering case DHCP6_CONFIRM:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_RENEW:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_REBIND:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_RELEASE:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_DECLINE:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_INFORMATION_REQUEST:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_RELAY_FORW:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_RELAY_REPL:
4b4bec19582c3ad2b7d25116f3c22c783274feadThomas Hindoe Paaboel Andersen return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_ADVERTISE:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_REPLY:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_RECONFIGURE:
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering default:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "unknown message type %d",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering message->type);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (client->transaction_id != (message->transaction_id &
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering htobe32(0x00ffffff)))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (client->state) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_SOLICITATION:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = client_receive_advertise(client, message, len);
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen if (r == DHCP6_STATE_REQUEST)
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen client_start(client, r);
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers break;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers case DHCP6_STATE_REQUEST:
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers r = client_receive_reply(client, message, len);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r < 0)
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r == DHCP6_STATE_BOUND) {
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers r = client_start(client, DHCP6_STATE_BOUND);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client_stop(client, r);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client = client_notify(client, DHCP6_EVENT_IP_ACQUIRE);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!client)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_BOUND:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_STOPPED:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_RS:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r >= 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "Recv %s",
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering dhcp6_message_type_to_string(message->type));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return 0;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringstatic int client_start(sd_dhcp6_client *client, enum DHCP6State state)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering{
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering usec_t timeout, time_now;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char time_string[FORMAT_TIMESPAN_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client->event, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client->index > 0, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert_return(client->state != state, -EINVAL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->timeout_resend_expire =
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sd_event_source_unref(client->timeout_resend_expire);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->timeout_resend = sd_event_source_unref(client->timeout_resend);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_time = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->retransmit_count = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering switch (state) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_STOPPED:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_RS:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_SOLICITATION:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = client_ensure_iaid(client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dhcp6_network_bind_udp_socket(client->index, NULL);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->fd = r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_io(client->event, &client->receive_message,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->fd, EPOLLIN, client_receive_message,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_source_set_priority(client->receive_message,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->event_priority);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->state = DHCP6_STATE_SOLICITATION;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_REQUEST:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->state = state;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering case DHCP6_STATE_BOUND:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_now(client->event, CLOCK_MONOTONIC, &time_now);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (client->lease->ia.lifetime_t1 == 0xffffffff ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->lease->ia.lifetime_t2 == 0xffffffff) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering be32toh(client->lease->ia.lifetime_t1),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering be32toh(client->lease->ia.lifetime_t2));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers return 0;
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers }
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering log_dhcp6_client(client, "T1 expires in %s",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering format_timespan(time_string,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering FORMAT_TIMESPAN_MAX,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering timeout, 0));
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = sd_event_add_time(client->event,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering &client->lease->ia.timeout_t1,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers CLOCK_MONOTONIC, time_now + timeout,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers 10 * USEC_PER_SEC, client_timeout_t1,
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers client);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering client->event_priority);
4d7859d173282e16bb75254c2b4ec14a915ef30bKay Sievers if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
log_dhcp6_client(client, "T2 expires in %s",
format_timespan(time_string,
FORMAT_TIMESPAN_MAX,
timeout, 0));
r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t2,
CLOCK_MONOTONIC, time_now + timeout,
10 * USEC_PER_SEC, client_timeout_t2,
client);
if (r < 0)
return r;
r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
client->event_priority);
if (r < 0)
return r;
return 0;
}
client->transaction_id = random_u32() & htobe32(0x00ffffff);
r = sd_event_add_time(client->event, &client->timeout_resend,
CLOCK_MONOTONIC, 0, 0, client_timeout_resend,
client);
if (r < 0)
return r;
r = sd_event_source_set_priority(client->timeout_resend,
client->event_priority);
if (r < 0)
return r;
return 0;
}
int sd_dhcp6_client_stop(sd_dhcp6_client *client)
{
client_stop(client, DHCP6_EVENT_STOP);
return 0;
}
int sd_dhcp6_client_start(sd_dhcp6_client *client)
{
int r = 0;
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
assert_return(client->index > 0, -EINVAL);
r = client_reset(client);
if (r < 0)
return r;
return client_start(client, DHCP6_STATE_SOLICITATION);
}
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
int priority)
{
int r;
assert_return(client, -EINVAL);
assert_return(!client->event, -EBUSY);
if (event)
client->event = sd_event_ref(event);
else {
r = sd_event_default(&client->event);
if (r < 0)
return 0;
}
client->event_priority = priority;
return 0;
}
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
client->event = sd_event_unref(client->event);
return 0;
}
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
if (!client)
return NULL;
return client->event;
}
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
if (client)
assert_se(REFCNT_INC(client->n_ref) >= 2);
return client;
}
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
if (client && REFCNT_DEC(client->n_ref) <= 0) {
client_reset(client);
sd_dhcp6_client_detach_event(client);
free(client);
return NULL;
}
return client;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref);
#define _cleanup_dhcp6_client_free_ _cleanup_(sd_dhcp6_client_unrefp)
int sd_dhcp6_client_new(sd_dhcp6_client **ret)
{
_cleanup_dhcp6_client_free_ sd_dhcp6_client *client = NULL;
sd_id128_t machine_id;
int r;
assert_return(ret, -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);
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(client->duid.id, &machine_id, sizeof(machine_id),
HASH_KEY.bytes);
*ret = client;
client = NULL;
return 0;
}