sd-dhcp6-client.c revision 76253e73f9c9c24fec755e485516f3b55d0707b4
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/***
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer This file is part of systemd.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Copyright (C) 2014 Intel Corporation. All rights reserved.
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer systemd is free software; you can redistribute it and/or modify it
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer under the terms of the GNU Lesser General Public License as published by
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer the Free Software Foundation; either version 2.1 of the License, or
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer (at your option) any later version.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer systemd is distributed in the hope that it will be useful, but
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer WITHOUT ANY WARRANTY; without even the implied warranty of
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer Lesser General Public License for more details.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer You should have received a copy of the GNU Lesser General Public License
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer along with systemd; If not, see <http://www.gnu.org/licenses/>.
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer***/
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include <errno.h>
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include <string.h>
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include <sys/ioctl.h>
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include <linux/if_infiniband.h>
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "udev.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "udev-util.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "virt.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "siphash24.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "util.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "refcnt.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "network-internal.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "sd-dhcp6-client.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "dhcp6-protocol.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "dhcp6-internal.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#include "dhcp6-lease-internal.h"
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#define SYSTEMD_PEN 43793
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer/* RFC 3315 section 9.1:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer * A DUID can be no more than 128 octets long (not including the type code).
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#define MAX_DUID_LEN 128
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstruct sd_dhcp6_client {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer RefCount n_ref;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer enum DHCP6State state;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event *event;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int event_priority;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int index;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t mac_addr[MAX_MAC_ADDR_LEN];
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t mac_addr_len;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t arp_type;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6IA ia_na;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer be32_t transaction_id;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer usec_t transaction_start;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct sd_dhcp6_lease *lease;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int fd;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer be16_t *req_opts;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t req_opts_allocated;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t req_opts_len;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source *receive_message;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer usec_t retransmit_time;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t retransmit_count;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source *timeout_resend;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source *timeout_resend_expire;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_dhcp6_client_cb_t cb;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *userdata;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer union {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t type; /* DHCP6_DUID_LLT */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t htype;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint32_t time;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t haddr[0];
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } _packed_ llt;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t type; /* DHCP6_DUID_EN */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint32_t pen;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t id[8];
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } _packed_ en;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t type; /* DHCP6_DUID_LL */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t htype;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t haddr[0];
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } _packed_ ll;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t type; /* DHCP6_DUID_UUID */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_id128_t uuid;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } _packed_ uuid;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t type;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t data[MAX_DUID_LEN];
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } _packed_ raw;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer } duid;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t duid_len;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer};
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic const uint16_t default_req_opts[] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6_OPTION_DNS_SERVERS,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6_OPTION_DOMAIN_LIST,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6_OPTION_NTP_SERVER,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer};
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerconst char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_SOLICIT] = "SOLICIT",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_ADVERTISE] = "ADVERTISE",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_REQUEST] = "REQUEST",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_CONFIRM] = "CONFIRM",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_RENEW] = "RENEW",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_REBIND] = "REBIND",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_REPLY] = "REPLY",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_RELEASE] = "RELEASE",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_DECLINE] = "DECLINE",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_RECONFIGURE] = "RECONFIGURE",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_RELAY_FORW] = "RELAY-FORW",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_RELAY_REPL] = "RELAY-REPL",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer};
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald HoyerDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerconst char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_STATUS_SUCCESS] = "Success",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_STATUS_NOT_ON_LINK] = "Not on link",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer};
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald HoyerDEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#define _cleanup_dhcp6_client_unref_ _cleanup_(sd_dhcp6_client_unrefp)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer#define DHCP6_CLIENT_DONT_DESTROY(client) \
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer _cleanup_dhcp6_client_unref_ _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_start(sd_dhcp6_client *client, enum DHCP6State state);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_dhcp6_client_cb_t cb, void *userdata)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer{
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->cb = cb;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->userdata = userdata;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer{
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(interface_index >= -1, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->index = interface_index;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t addr_len, uint16_t arp_type)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer{
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(addr, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(arp_type > 0, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (arp_type == ARPHRD_ETHER)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(addr_len == ETH_ALEN, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else if (arp_type == ARPHRD_INFINIBAND)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EINVAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (client->mac_addr_len == addr_len &&
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer memcmp(&client->mac_addr, addr, addr_len) == 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer memcpy(&client->mac_addr, addr, addr_len);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->mac_addr_len = addr_len;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->arp_type = arp_type;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t duid_len)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer{
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(duid, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer switch (type) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_DUID_LLT:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (duid_len <= sizeof(client->duid.llt))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EINVAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_DUID_EN:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (duid_len != sizeof(client->duid.en))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EINVAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_DUID_LL:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (duid_len <= sizeof(client->duid.ll))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EINVAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_DUID_UUID:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (duid_len != sizeof(client->duid.uuid))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EINVAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer default:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* accept unknown type in order to be forward compatible */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->duid.raw.type = htobe16(type);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer memcpy(&client->duid.raw.data, duid, duid_len);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->duid_len = duid_len;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint16_t option) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t t;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer switch(option) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_OPTION_DNS_SERVERS:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_OPTION_DOMAIN_LIST:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_OPTION_SNTP_SERVERS:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_OPTION_NTP_SERVER:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer default:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EINVAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer for (t = 0; t < client->req_opts_len; t++)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (client->req_opts[t] == htobe16(option))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EEXIST;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->req_opts_len + 1))
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -ENOMEM;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->req_opts[client->req_opts_len++] = htobe16(option);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerint sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(ret, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!client->lease)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -ENOMSG;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer *ret = sd_dhcp6_lease_ref(client->lease);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void client_notify(sd_dhcp6_client *client, int event) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (client->cb)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->cb(client, event, client->userdata);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_reset(sd_dhcp6_client *client) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->receive_message =
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(client->receive_message);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->fd = safe_close(client->fd);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->transaction_id = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->transaction_start = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->ia_na.timeout_t1 =
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(client->ia_na.timeout_t1);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->ia_na.timeout_t2 =
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(client->ia_na.timeout_t2);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->retransmit_time = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->retransmit_count = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->timeout_resend = sd_event_source_unref(client->timeout_resend);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->timeout_resend_expire =
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(client->timeout_resend_expire);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->state = DHCP6_STATE_STOPPED;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic void client_stop(sd_dhcp6_client *client, int error) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6_CLIENT_DONT_DESTROY(client);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(client);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client_notify(client, error);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client_reset(client);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer _cleanup_free_ DHCP6Message *message = NULL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer struct in6_addr all_servers =
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t len, optlen = 512;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t *opt;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer usec_t elapsed_usec;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer be16_t elapsed_time;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer len = sizeof(DHCP6Message) + optlen;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer message = malloc0(len);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!message)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -ENOMEM;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer opt = (uint8_t *)(message + 1);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer message->transaction_id = client->transaction_id;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer switch(client->state) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_SOLICITATION:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer message->type = DHCP6_SOLICIT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_option_append(&opt, &optlen,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_REQUEST:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_RENEW:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (client->state == DHCP6_STATE_REQUEST)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer message->type = DHCP6_REQUEST;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer message->type = DHCP6_RENEW;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->lease->serverid_len,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->lease->serverid);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_REBIND:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer message->type = DHCP6_REBIND;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_STOPPED:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_BOUND:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EINVAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->req_opts_len * sizeof(be16_t),
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->req_opts);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->duid_len, &client->duid);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer elapsed_usec = time_now - client->transaction_start;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer else
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer elapsed_time = 0xffff;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ELAPSED_TIME,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sizeof(elapsed_time), &elapsed_time);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer len - optlen);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_dhcp6_client(client, "Sent %s",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dhcp6_message_type_to_string(message->type));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_timeout_t2(sd_event_source *s, uint64_t usec,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *userdata) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_dhcp6_client *client = userdata;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(s, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client->lease, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->lease->ia.timeout_t2 =
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(client->lease->ia.timeout_t2);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_dhcp6_client(client, "Timeout T2");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client_start(client, DHCP6_STATE_REBIND);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_timeout_t1(sd_event_source *s, uint64_t usec,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *userdata) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_dhcp6_client *client = userdata;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(s, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert_return(client->lease, -EINVAL);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->lease->ia.timeout_t1 =
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_event_source_unref(client->lease->ia.timeout_t1);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_dhcp6_client(client, "Timeout T1");
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client_start(client, DHCP6_STATE_RENEW);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *userdata) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_dhcp6_client *client = userdata;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6_CLIENT_DONT_DESTROY(client);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer enum DHCP6State state;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(s);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(client);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(client->event);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer state = client->state;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client_stop(client, DHCP6_EVENT_RESEND_EXPIRE);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* RFC 3315, section 18.1.4., says that "...the client may choose to
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer use a Solicit message to locate a new DHCP server..." */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (state == DHCP6_STATE_REBIND)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client_start(client, DHCP6_STATE_SOLICITATION);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic usec_t client_timeout_compute_random(usec_t val) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return val - val / 10 +
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_timeout_resend(sd_event_source *s, uint64_t usec,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *userdata) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_dhcp6_client *client = userdata;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer usec_t max_retransmit_duration = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t max_retransmit_count = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer char time_string[FORMAT_TIMESPAN_MAX];
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint32_t expire = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(s);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(client);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer assert(client->event);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->timeout_resend = sd_event_source_unref(client->timeout_resend);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer switch (client->state) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_SOLICITATION:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (client->retransmit_count && client->lease) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client_start(client, DHCP6_STATE_REQUEST);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer init_retransmit_time = DHCP6_SOL_TIMEOUT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer max_retransmit_time = DHCP6_SOL_MAX_RT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_REQUEST:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer init_retransmit_time = DHCP6_REQ_TIMEOUT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer max_retransmit_time = DHCP6_REQ_MAX_RT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer max_retransmit_count = DHCP6_REQ_MAX_RC;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_RENEW:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer init_retransmit_time = DHCP6_REN_TIMEOUT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer max_retransmit_time = DHCP6_REN_MAX_RT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer /* RFC 3315, section 18.1.3. says max retransmit duration will
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer be the remaining time until T2. Instead of setting MRD,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer wait for T2 to trigger with the same end result */
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_REBIND:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer init_retransmit_time = DHCP6_REB_TIMEOUT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer max_retransmit_time = DHCP6_REB_MAX_RT;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!client->timeout_resend_expire) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer &expire);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client_stop(client, r);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer max_retransmit_duration = expire * USEC_PER_SEC;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_STOPPED:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_STATE_BOUND:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (max_retransmit_count &&
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->retransmit_count >= max_retransmit_count) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client_stop(client, DHCP6_EVENT_RETRANS_MAX);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto error;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = client_send_message(client, time_now);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r >= 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->retransmit_count++;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!client->retransmit_time) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->retransmit_time =
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client_timeout_compute_random(init_retransmit_time);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (client->state == DHCP6_STATE_SOLICITATION)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->retransmit_time += init_retransmit_time / 10;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer } else {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (max_retransmit_time &&
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->retransmit_time > max_retransmit_time / 2)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer else
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_dhcp6_client(client, "Next retransmission in %s",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer format_timespan(time_string, FORMAT_TIMESPAN_MAX,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->retransmit_time, 0));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = sd_event_add_time(client->event, &client->timeout_resend,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer clock_boottime_or_monotonic(),
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer time_now + client->retransmit_time,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer 10 * USEC_PER_MSEC, client_timeout_resend,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto error;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = sd_event_source_set_priority(client->timeout_resend,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->event_priority);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto error;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = sd_event_source_set_name(client->timeout_resend,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer "dhcp6-resend-timer");
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto error;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (max_retransmit_duration && !client->timeout_resend_expire) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer max_retransmit_duration / USEC_PER_SEC);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = sd_event_add_time(client->event,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer &client->timeout_resend_expire,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer clock_boottime_or_monotonic(),
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer time_now + max_retransmit_duration,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer USEC_PER_SEC,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client_timeout_resend_expire, client);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto error;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = sd_event_source_set_priority(client->timeout_resend_expire,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->event_priority);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto error;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = sd_event_source_set_name(client->timeout_resend_expire,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer "dhcp6-resend-expire-timer");
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer goto error;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
c53158818d8cdaf46b3f1b5299b9bda118a1043fThomas Hindoe Paaboel Andersenerror:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client_stop(client, r);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerstatic int client_ensure_iaid(sd_dhcp6_client *client) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* name is a pointer to memory in the udev_device struct, so must
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer have the same scope */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer _cleanup_udev_device_unref_ struct udev_device *device = NULL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer const char *name = NULL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint64_t id;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer assert(client);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (client->ia_na.id)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (detect_container(NULL) <= 0) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* not in a container, udev will be around */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer _cleanup_udev_unref_ struct udev *udev;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer char ifindex_str[2 + DECIMAL_STR_MAX(int)];
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer udev = udev_new();
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!udev)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -ENOMEM;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer sprintf(ifindex_str, "n%d", client->index);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer device = udev_device_new_from_device_id(udev, ifindex_str);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (!device)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -errno;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (udev_device_get_is_initialized(device) <= 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* not yet ready */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EBUSY;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer name = net_get_name(device);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (name)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer else
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* fall back to mac address if no predictable name available */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer siphash24((uint8_t*)&id, &client->mac_addr,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->mac_addr_len, HASH_KEY.bytes);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer /* fold into 32 bits */
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return 0;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer}
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyerstatic int client_parse_message(sd_dhcp6_client *client,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer DHCP6Message *message, size_t len,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer sd_dhcp6_lease *lease) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer int r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint8_t *optval, *option, *id = NULL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer uint16_t optcode, status;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer size_t optlen, id_len;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer bool clientid = false;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer be32_t iaid_lease;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer option = (uint8_t *)message + sizeof(DHCP6Message);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer len -= sizeof(DHCP6Message);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer &optval)) >= 0) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer switch (optcode) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer case DHCP6_OPTION_CLIENTID:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (clientid) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_dhcp6_client(client, "%s contains multiple clientids",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dhcp6_message_type_to_string(message->type));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (optlen != client->duid_len ||
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer memcmp(&client->duid, optval, optlen) != 0) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_dhcp6_client(client, "%s DUID does not match",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dhcp6_message_type_to_string(message->type));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer clientid = true;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer break;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer case DHCP6_OPTION_SERVERID:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = dhcp6_lease_get_serverid(lease, &id, &id_len);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r >= 0 && id) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_dhcp6_client(client, "%s contains multiple serverids",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dhcp6_message_type_to_string(message->type));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = dhcp6_lease_set_serverid(lease, optval, optlen);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer break;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer case DHCP6_OPTION_PREFERENCE:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (optlen != 1)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = dhcp6_lease_set_preference(lease, *optval);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer break;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer case DHCP6_OPTION_STATUS_CODE:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (optlen < 2)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer status = optval[0] << 8 | optval[1];
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (status) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_dhcp6_client(client, "%s Status %s",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dhcp6_message_type_to_string(message->type),
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dhcp6_message_status_to_string(status));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer break;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer case DHCP6_OPTION_IA_NA:
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer &lease->ia);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0 && r != -ENOMSG)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer r = dhcp6_lease_get_iaid(lease, &iaid_lease);
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (r < 0)
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return r;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer if (client->ia_na.id != iaid_lease) {
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer log_dhcp6_client(client, "%s has wrong IAID",
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer dhcp6_message_type_to_string(message->type));
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer return -EINVAL;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer }
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer break;
0d6e798a784ef0ba6b95512e4453067b2f84a91aHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer case DHCP6_OPTION_RAPID_COMMIT:
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_lease_set_rapid_commit(lease);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer break;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if ((r < 0 && r != -ENOMSG) || !clientid) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_dhcp6_client(client, "%s has incomplete options",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dhcp6_message_type_to_string(message->type));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return -EINVAL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_lease_get_serverid(lease, &id, &id_len);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer log_dhcp6_client(client, "%s has no server id",
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dhcp6_message_type_to_string(message->type));
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer size_t len)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer{
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer bool rapid_commit;
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer if (reply->type != DHCP6_REPLY)
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer return 0;
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer r = dhcp6_lease_new(&lease);
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer if (r < 0)
1ecf6a2b4960229ad1d06c591b4776ddf065e834Harald Hoyer return -ENOMEM;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer r = client_parse_message(client, reply, len, lease);
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer if (r < 0)
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer return r;
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer
33a5e20ffaa2cbb2853f14265566bac66a7f9026Harald Hoyer if (client->state == DHCP6_STATE_SOLICITATION) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!rapid_commit)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (client->lease)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer dhcp6_lease_clear_timers(&client->lease->ia);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->lease = sd_dhcp6_lease_unref(client->lease);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->lease = lease;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer lease = NULL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return DHCP6_STATE_BOUND;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_receive_advertise(sd_dhcp6_client *client,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6Message *advertise, size_t len) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer int r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer uint8_t pref_advertise = 0, pref_lease = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (advertise->type != DHCP6_ADVERTISE)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_lease_new(&lease);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = client_parse_message(client, advertise, len, lease);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_lease_get_preference(lease, &pref_advertise);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (r < 0)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = dhcp6_lease_get_preference(client->lease, &pref_lease);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (!client->lease || r < 0 || pref_advertise > pref_lease) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_dhcp6_lease_unref(client->lease);
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer client->lease = lease;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer lease = NULL;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = 0;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer }
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer if (pref_advertise == 255 || client->retransmit_count > 1)
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer r = DHCP6_STATE_REQUEST;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer return r;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer}
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyerstatic int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer void *userdata) {
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer sd_dhcp6_client *client = userdata;
898720b7e9cf3bdf7a93e435cbed5dd6942ecf9bHarald Hoyer DHCP6_CLIENT_DONT_DESTROY(client);
_cleanup_free_ DHCP6Message *message;
int r, buflen, len;
assert(s);
assert(client);
assert(client->event);
r = ioctl(fd, FIONREAD, &buflen);
if (r < 0 || buflen <= 0)
buflen = DHCP6_MIN_OPTIONS_SIZE;
message = malloc0(buflen);
if (!message)
return -ENOMEM;
len = read(fd, message, buflen);
if ((size_t)len < sizeof(DHCP6Message)) {
log_dhcp6_client(client, "could not receive message from UDP socket: %m");
return 0;
}
switch(message->type) {
case DHCP6_SOLICIT:
case DHCP6_REQUEST:
case DHCP6_CONFIRM:
case DHCP6_RENEW:
case DHCP6_REBIND:
case DHCP6_RELEASE:
case DHCP6_DECLINE:
case DHCP6_INFORMATION_REQUEST:
case DHCP6_RELAY_FORW:
case DHCP6_RELAY_REPL:
return 0;
case DHCP6_ADVERTISE:
case DHCP6_REPLY:
case DHCP6_RECONFIGURE:
break;
default:
log_dhcp6_client(client, "unknown message type %d",
message->type);
return 0;
}
if (client->transaction_id != (message->transaction_id &
htobe32(0x00ffffff)))
return 0;
switch (client->state) {
case DHCP6_STATE_SOLICITATION:
r = client_receive_advertise(client, message, len);
if (r == DHCP6_STATE_REQUEST) {
client_start(client, r);
break;
}
/* fall through for Soliciation Rapid Commit option check */
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
r = client_receive_reply(client, message, len);
if (r < 0)
return 0;
if (r == DHCP6_STATE_BOUND) {
r = client_start(client, DHCP6_STATE_BOUND);
if (r < 0) {
client_stop(client, r);
return 0;
}
client_notify(client, DHCP6_EVENT_IP_ACQUIRE);
}
break;
case DHCP6_STATE_BOUND:
break;
case DHCP6_STATE_STOPPED:
return 0;
}
if (r >= 0) {
log_dhcp6_client(client, "Recv %s",
dhcp6_message_type_to_string(message->type));
}
return 0;
}
static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
{
int r;
usec_t timeout, time_now;
char time_string[FORMAT_TIMESPAN_MAX];
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
assert_return(client->index > 0, -EINVAL);
assert_return(client->state != state, -EINVAL);
client->timeout_resend_expire =
sd_event_source_unref(client->timeout_resend_expire);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
client->retransmit_time = 0;
client->retransmit_count = 0;
if (client->state == DHCP6_STATE_STOPPED) {
time_now = now(clock_boottime_or_monotonic());
} else {
r = sd_event_now(client->event, clock_boottime_or_monotonic(),
&time_now);
if (r < 0)
return r;
}
switch (state) {
case DHCP6_STATE_STOPPED:
case 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)
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;
client->state = DHCP6_STATE_SOLICITATION;
break;
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
client->state = state;
break;
case DHCP6_STATE_BOUND:
if (client->lease->ia.lifetime_t1 == 0xffffffff ||
client->lease->ia.lifetime_t2 == 0xffffffff) {
log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x",
be32toh(client->lease->ia.lifetime_t1),
be32toh(client->lease->ia.lifetime_t2));
return 0;
}
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
log_dhcp6_client(client, "T1 expires in %s",
format_timespan(time_string,
FORMAT_TIMESPAN_MAX,
timeout, 0));
r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t1,
clock_boottime_or_monotonic(), time_now + timeout,
10 * USEC_PER_SEC, client_timeout_t1,
client);
if (r < 0)
return r;
r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
client->event_priority);
if (r < 0)
return r;
r = sd_event_source_set_name(client->lease->ia.timeout_t1,
"dhcp6-t1-timeout");
if (r < 0)
return r;
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
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_boottime_or_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;
r = sd_event_source_set_name(client->lease->ia.timeout_t2,
"dhcp6-t2-timeout");
if (r < 0)
return r;
client->state = state;
return 0;
}
client->transaction_id = random_u32() & htobe32(0x00ffffff);
client->transaction_start = time_now;
r = sd_event_add_time(client->event, &client->timeout_resend,
clock_boottime_or_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;
r = sd_event_source_set_name(client->timeout_resend,
"dhcp6-resend-timeout");
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->req_opts);
free(client);
return NULL;
}
return 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;
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.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);
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);
if (!client->req_opts)
return -ENOMEM;
for (t = 0; t < client->req_opts_len; t++)
client->req_opts[t] = htobe16(default_req_opts[t]);
*ret = client;
client = NULL;
return 0;
}