sd-dhcp6-client.c revision 2c1ab8ca9b5dec48c66eb25dd8af71731e70e517
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering/***
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering This file is part of systemd.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering systemd is free software; you can redistribute it and/or modify it
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering under the terms of the GNU Lesser General Public License as published by
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering (at your option) any later version.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering systemd is distributed in the hope that it will be useful, but
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering Lesser General Public License for more details.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering You should have received a copy of the GNU Lesser General Public License
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering***/
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <errno.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <string.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <sys/ioctl.h>
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include <linux/if_infiniband.h>
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "sd-dhcp6-client.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "alloc-util.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "dhcp-identifier.h"
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmek#include "dhcp6-internal.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "dhcp6-lease-internal.h"
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering#include "dhcp6-protocol.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "fd-util.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "in-addr-util.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "network-internal.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "random-util.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "string-table.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#include "util.h"
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstruct sd_dhcp6_client {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering unsigned n_ref;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering enum DHCP6State state;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event *event;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int event_priority;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int index;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct in6_addr local_address;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering uint8_t mac_addr[MAX_MAC_ADDR_LEN];
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t mac_addr_len;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering uint16_t arp_type;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering DHCP6IA ia_na;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering be32_t transaction_id;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering usec_t transaction_start;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct sd_dhcp6_lease *lease;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int fd;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering bool information_request;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering be16_t *req_opts;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t req_opts_allocated;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t req_opts_len;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source *receive_message;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering usec_t retransmit_time;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering uint8_t retransmit_count;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source *timeout_resend;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source *timeout_resend_expire;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_dhcp6_client_cb_t cb;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering void *userdata;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct duid duid;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t duid_len;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering};
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic const uint16_t default_req_opts[] = {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering SD_DHCP6_OPTION_DNS_SERVERS,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering SD_DHCP6_OPTION_DOMAIN_LIST,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering SD_DHCP6_OPTION_NTP_SERVER,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering SD_DHCP6_OPTION_SNTP_SERVERS,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering};
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringconst char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_SOLICIT] = "SOLICIT",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_ADVERTISE] = "ADVERTISE",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_REQUEST] = "REQUEST",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_CONFIRM] = "CONFIRM",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_RENEW] = "RENEW",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_REBIND] = "REBIND",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_REPLY] = "REPLY",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_RELEASE] = "RELEASE",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_DECLINE] = "DECLINE",
f5f6d0e25574dd63fb605b81fa7767dd71c454dbDaniel Buch [DHCP6_RECONFIGURE] = "RECONFIGURE",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_RELAY_FORW] = "RELAY-FORW",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_RELAY_REPL] = "RELAY-REPL",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering};
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringconst char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_STATUS_SUCCESS] = "Success",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_STATUS_NOT_ON_LINK] = "Not on link",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering};
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering#define DHCP6_CLIENT_DONT_DESTROY(client) \
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
e9f600f2fb4b0df55c7a8fb4b4d09f9979997223Lennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int client_start(sd_dhcp6_client *client, enum DHCP6State state);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->cb = cb;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->userdata = userdata;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(interface_index >= -1, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->index = interface_index;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(local_address, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->local_address = *local_address;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_set_mac(
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_dhcp6_client *client,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering const uint8_t *addr, size_t addr_len,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering uint16_t arp_type) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(addr, -EINVAL);
507f22bd0172bff5e5d98145b1419bd472a2c57fZbigniew Jędrzejewski-Szmek assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
507f22bd0172bff5e5d98145b1419bd472a2c57fZbigniew Jędrzejewski-Szmek assert_return(arp_type > 0, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (arp_type == ARPHRD_ETHER)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(addr_len == ETH_ALEN, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering else if (arp_type == ARPHRD_INFINIBAND)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering else
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -EINVAL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (client->mac_addr_len == addr_len &&
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering memcmp(&client->mac_addr, addr, addr_len) == 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering memcpy(&client->mac_addr, addr, addr_len);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->mac_addr_len = addr_len;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->arp_type = arp_type;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
e9f600f2fb4b0df55c7a8fb4b4d09f9979997223Lennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int client_ensure_duid(sd_dhcp6_client *client) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (client->duid_len != 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_set_duid(
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_dhcp6_client *client,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering uint16_t type,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering uint8_t *duid, size_t duid_len) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(duid, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering switch (type) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_DUID_LLT:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (duid_len <= sizeof(client->duid.llt))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -EINVAL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_DUID_EN:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (duid_len != sizeof(client->duid.en))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -EINVAL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_DUID_LL:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (duid_len <= sizeof(client->duid.ll))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -EINVAL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_DUID_UUID:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (duid_len != sizeof(client->duid.uuid))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -EINVAL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering default:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering /* accept unknown type in order to be forward compatible */
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->duid.type = htobe16(type);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering memcpy(&client->duid.raw.data, duid, duid_len);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->duid_len = duid_len + sizeof(client->duid.type);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->information_request = enabled;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(enabled, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering *enabled = client->information_request;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t t;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering switch(option) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case SD_DHCP6_OPTION_DNS_SERVERS:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case SD_DHCP6_OPTION_DOMAIN_LIST:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case SD_DHCP6_OPTION_SNTP_SERVERS:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case SD_DHCP6_OPTION_NTP_SERVER:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering default:
4b94f3b8f7693f076e5c85bc2c02cf028192d8deZbigniew Jędrzejewski-Szmek return -EINVAL;
4b94f3b8f7693f076e5c85bc2c02cf028192d8deZbigniew Jędrzejewski-Szmek }
4b94f3b8f7693f076e5c85bc2c02cf028192d8deZbigniew Jędrzejewski-Szmek
4b94f3b8f7693f076e5c85bc2c02cf028192d8deZbigniew Jędrzejewski-Szmek for (t = 0; t < client->req_opts_len; t++)
4b94f3b8f7693f076e5c85bc2c02cf028192d8deZbigniew Jędrzejewski-Szmek if (client->req_opts[t] == htobe16(option))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -EEXIST;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->req_opts_len + 1))
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -ENOMEM;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->req_opts[client->req_opts_len++] = htobe16(option);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
e9f600f2fb4b0df55c7a8fb4b4d09f9979997223Lennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringint sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!client->lease)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -ENOMSG;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (ret)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering *ret = client->lease;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic void client_notify(sd_dhcp6_client *client, int event) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (client->cb)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->cb(client, event, client->userdata);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (client->lease) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering dhcp6_lease_clear_timers(&client->lease->ia);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_dhcp6_lease_unref(client->lease);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->lease = lease;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int client_reset(sd_dhcp6_client *client) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client_set_lease(client, NULL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->receive_message =
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source_unref(client->receive_message);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->fd = safe_close(client->fd);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->transaction_id = 0;
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek client->transaction_start = 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->ia_na.timeout_t1 =
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source_unref(client->ia_na.timeout_t1);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->ia_na.timeout_t2 =
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source_unref(client->ia_na.timeout_t2);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->retransmit_time = 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->retransmit_count = 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->timeout_resend = sd_event_source_unref(client->timeout_resend);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->timeout_resend_expire =
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source_unref(client->timeout_resend_expire);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->state = DHCP6_STATE_STOPPED;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic void client_stop(sd_dhcp6_client *client, int error) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering DHCP6_CLIENT_DONT_DESTROY(client);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert(client);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client_notify(client, error);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client_reset(client);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering _cleanup_free_ DHCP6Message *message = NULL;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering struct in6_addr all_servers =
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering size_t len, optlen = 512;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering uint8_t *opt;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering int r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering usec_t elapsed_usec;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering be16_t elapsed_time;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering len = sizeof(DHCP6Message) + optlen;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering message = malloc0(len);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (!message)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return -ENOMEM;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering opt = (uint8_t *)(message + 1);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering message->transaction_id = client->transaction_id;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering switch(client->state) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_STATE_INFORMATION_REQUEST:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering message->type = DHCP6_INFORMATION_REQUEST;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_STATE_SOLICITATION:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering message->type = DHCP6_SOLICIT;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
2b43f939a4b3ad5aeb2650868b0234ff42ec0045Lennart Poettering r = dhcp6_option_append(&opt, &optlen,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (r < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (r < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return r;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_STATE_REQUEST:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_STATE_RENEW:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering if (client->state == DHCP6_STATE_REQUEST)
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering message->type = DHCP6_REQUEST;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering else
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering message->type = DHCP6_RENEW;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID,
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering client->lease->serverid_len,
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering client->lease->serverid);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering if (r < 0)
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering return r;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering if (r < 0)
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering return r;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering case DHCP6_STATE_REBIND:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering message->type = DHCP6_REBIND;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering if (r < 0)
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return r;
445ea9be520b9549aee45d0b6427cf48b446987fLennart Poettering
445ea9be520b9549aee45d0b6427cf48b446987fLennart Poettering break;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_STATE_STOPPED:
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering case DHCP6_STATE_BOUND:
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering return -EINVAL;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering }
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->req_opts_len * sizeof(be16_t),
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering client->req_opts);
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering if (r < 0)
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering return r;
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert (client->duid_len);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_CLIENTID,
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering client->duid_len, &client->duid);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering if (r < 0)
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering return r;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering elapsed_usec = time_now - client->transaction_start;
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering else
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering elapsed_time = 0xffff;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sizeof(elapsed_time), &elapsed_time);
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering if (r < 0)
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering return r;
a69f4254a82765cd0c7f155d5dc86e0768ea0ef3Lennart Poettering
a69f4254a82765cd0c7f155d5dc86e0768ea0ef3Lennart Poettering r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
a69f4254a82765cd0c7f155d5dc86e0768ea0ef3Lennart Poettering len - optlen);
a69f4254a82765cd0c7f155d5dc86e0768ea0ef3Lennart Poettering if (r < 0)
a69f4254a82765cd0c7f155d5dc86e0768ea0ef3Lennart Poettering return r;
a69f4254a82765cd0c7f155d5dc86e0768ea0ef3Lennart Poettering
a69f4254a82765cd0c7f155d5dc86e0768ea0ef3Lennart Poettering log_dhcp6_client(client, "Sent %s",
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering dhcp6_message_type_to_string(message->type));
c0f71f469fef3f3a0822e0021085e6d165df2b46Lennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int client_timeout_t2(sd_event_source *s, uint64_t usec,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering void *userdata) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_dhcp6_client *client = userdata;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(s, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client->lease, -EINVAL);
b2e6df73aa508cc09b1b536a2fb9f90f152b89faZbigniew Jędrzejewski-Szmek
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->lease->ia.timeout_t2 =
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source_unref(client->lease->ia.timeout_t2);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_dhcp6_client(client, "Timeout T2");
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client_start(client, DHCP6_STATE_REBIND);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering return 0;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering}
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poetteringstatic int client_timeout_t1(sd_event_source *s, uint64_t usec,
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering void *userdata) {
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_dhcp6_client *client = userdata;
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(s, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering assert_return(client->lease, -EINVAL);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client->lease->ia.timeout_t1 =
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering sd_event_source_unref(client->lease->ia.timeout_t1);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering log_dhcp6_client(client, "Timeout T1");
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering client_start(client, DHCP6_STATE_RENEW);
ef63833d532dd86bdba63211e6a1363cbb3ef61dLennart Poettering
return 0;
}
static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
void *userdata) {
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
enum DHCP6State state;
assert(s);
assert(client);
assert(client->event);
state = client->state;
client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
/* RFC 3315, section 18.1.4., says that "...the client may choose to
use a Solicit message to locate a new DHCP server..." */
if (state == DHCP6_STATE_REBIND)
client_start(client, DHCP6_STATE_SOLICITATION);
return 0;
}
static usec_t client_timeout_compute_random(usec_t val) {
return val - val / 10 +
(random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
}
static int client_timeout_resend(sd_event_source *s, uint64_t usec,
void *userdata) {
int r = 0;
sd_dhcp6_client *client = userdata;
usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
usec_t max_retransmit_duration = 0;
uint8_t max_retransmit_count = 0;
char time_string[FORMAT_TIMESPAN_MAX];
uint32_t expire = 0;
assert(s);
assert(client);
assert(client->event);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
switch (client->state) {
case DHCP6_STATE_INFORMATION_REQUEST:
init_retransmit_time = DHCP6_INF_TIMEOUT;
max_retransmit_time = DHCP6_INF_MAX_RT;
break;
case DHCP6_STATE_SOLICITATION:
if (client->retransmit_count && client->lease) {
client_start(client, DHCP6_STATE_REQUEST);
return 0;
}
init_retransmit_time = DHCP6_SOL_TIMEOUT;
max_retransmit_time = DHCP6_SOL_MAX_RT;
break;
case DHCP6_STATE_REQUEST:
init_retransmit_time = DHCP6_REQ_TIMEOUT;
max_retransmit_time = DHCP6_REQ_MAX_RT;
max_retransmit_count = DHCP6_REQ_MAX_RC;
break;
case DHCP6_STATE_RENEW:
init_retransmit_time = DHCP6_REN_TIMEOUT;
max_retransmit_time = DHCP6_REN_MAX_RT;
/* RFC 3315, section 18.1.3. says max retransmit duration will
be the remaining time until T2. Instead of setting MRD,
wait for T2 to trigger with the same end result */
break;
case DHCP6_STATE_REBIND:
init_retransmit_time = DHCP6_REB_TIMEOUT;
max_retransmit_time = DHCP6_REB_MAX_RT;
if (!client->timeout_resend_expire) {
r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
&expire);
if (r < 0) {
client_stop(client, r);
return 0;
}
max_retransmit_duration = expire * USEC_PER_SEC;
}
break;
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_BOUND:
return 0;
}
if (max_retransmit_count &&
client->retransmit_count >= max_retransmit_count) {
client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
return 0;
}
r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
goto error;
r = client_send_message(client, time_now);
if (r >= 0)
client->retransmit_count++;
if (!client->retransmit_time) {
client->retransmit_time =
client_timeout_compute_random(init_retransmit_time);
if (client->state == DHCP6_STATE_SOLICITATION)
client->retransmit_time += init_retransmit_time / 10;
} else {
if (max_retransmit_time &&
client->retransmit_time > max_retransmit_time / 2)
client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
else
client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
}
log_dhcp6_client(client, "Next retransmission in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
r = sd_event_add_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
time_now + client->retransmit_time,
10 * USEC_PER_MSEC, client_timeout_resend,
client);
if (r < 0)
goto error;
r = sd_event_source_set_priority(client->timeout_resend,
client->event_priority);
if (r < 0)
goto error;
r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer");
if (r < 0)
goto error;
if (max_retransmit_duration && !client->timeout_resend_expire) {
log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
max_retransmit_duration / USEC_PER_SEC);
r = sd_event_add_time(client->event,
&client->timeout_resend_expire,
clock_boottime_or_monotonic(),
time_now + max_retransmit_duration,
USEC_PER_SEC,
client_timeout_resend_expire, client);
if (r < 0)
goto error;
r = sd_event_source_set_priority(client->timeout_resend_expire,
client->event_priority);
if (r < 0)
goto error;
r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer");
if (r < 0)
goto error;
}
error:
if (r < 0)
client_stop(client, r);
return 0;
}
static int client_ensure_iaid(sd_dhcp6_client *client) {
int r;
assert(client);
if (client->ia_na.id)
return 0;
r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id);
if (r < 0)
return r;
return 0;
}
static int client_parse_message(sd_dhcp6_client *client,
DHCP6Message *message, size_t len,
sd_dhcp6_lease *lease) {
int r;
uint8_t *optval, *option, *id = NULL;
uint16_t optcode, status;
size_t optlen, id_len;
bool clientid = false;
be32_t iaid_lease;
option = (uint8_t *)message + sizeof(DHCP6Message);
len -= sizeof(DHCP6Message);
while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen,
&optval)) >= 0) {
switch (optcode) {
case SD_DHCP6_OPTION_CLIENTID:
if (clientid) {
log_dhcp6_client(client, "%s contains multiple clientids",
dhcp6_message_type_to_string(message->type));
return -EINVAL;
}
if (optlen != client->duid_len ||
memcmp(&client->duid, optval, optlen) != 0) {
log_dhcp6_client(client, "%s DUID does not match",
dhcp6_message_type_to_string(message->type));
return -EINVAL;
}
clientid = true;
break;
case SD_DHCP6_OPTION_SERVERID:
r = dhcp6_lease_get_serverid(lease, &id, &id_len);
if (r >= 0 && id) {
log_dhcp6_client(client, "%s contains multiple serverids",
dhcp6_message_type_to_string(message->type));
return -EINVAL;
}
r = dhcp6_lease_set_serverid(lease, optval, optlen);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_PREFERENCE:
if (optlen != 1)
return -EINVAL;
r = dhcp6_lease_set_preference(lease, *optval);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_STATUS_CODE:
if (optlen < 2)
return -EINVAL;
status = optval[0] << 8 | optval[1];
if (status) {
log_dhcp6_client(client, "%s Status %s",
dhcp6_message_type_to_string(message->type),
dhcp6_message_status_to_string(status));
return -EINVAL;
}
break;
case SD_DHCP6_OPTION_IA_NA:
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
log_dhcp6_client(client, "Information request ignoring IA NA option");
break;
}
r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
&lease->ia);
if (r < 0 && r != -ENOMSG)
return r;
r = dhcp6_lease_get_iaid(lease, &iaid_lease);
if (r < 0)
return r;
if (client->ia_na.id != iaid_lease) {
log_dhcp6_client(client, "%s has wrong IAID",
dhcp6_message_type_to_string(message->type));
return -EINVAL;
}
break;
case SD_DHCP6_OPTION_RAPID_COMMIT:
r = dhcp6_lease_set_rapid_commit(lease);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_DNS_SERVERS:
r = dhcp6_lease_set_dns(lease, optval, optlen);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_DOMAIN_LIST:
r = dhcp6_lease_set_domains(lease, optval, optlen);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_NTP_SERVER:
r = dhcp6_lease_set_ntp(lease, optval, optlen);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_SNTP_SERVERS:
r = dhcp6_lease_set_sntp(lease, optval, optlen);
if (r < 0)
return r;
break;
}
}
if (r == -ENOMSG)
r = 0;
if (r < 0 || !clientid) {
log_dhcp6_client(client, "%s has incomplete options",
dhcp6_message_type_to_string(message->type));
return -EINVAL;
}
if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
r = dhcp6_lease_get_serverid(lease, &id, &id_len);
if (r < 0)
log_dhcp6_client(client, "%s has no server id",
dhcp6_message_type_to_string(message->type));
}
return r;
}
static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
int r;
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
bool rapid_commit;
if (reply->type != DHCP6_REPLY)
return 0;
r = dhcp6_lease_new(&lease);
if (r < 0)
return -ENOMEM;
r = client_parse_message(client, reply, len, lease);
if (r < 0)
return r;
if (client->state == DHCP6_STATE_SOLICITATION) {
r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
if (r < 0)
return r;
if (!rapid_commit)
return 0;
}
client_set_lease(client, lease);
lease = NULL;
return DHCP6_STATE_BOUND;
}
static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
int r;
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
uint8_t pref_advertise = 0, pref_lease = 0;
if (advertise->type != DHCP6_ADVERTISE)
return 0;
r = dhcp6_lease_new(&lease);
if (r < 0)
return r;
r = client_parse_message(client, advertise, len, lease);
if (r < 0)
return r;
r = dhcp6_lease_get_preference(lease, &pref_advertise);
if (r < 0)
return r;
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
if (r < 0 || pref_advertise > pref_lease) {
client_set_lease(client, lease);
lease = NULL;
r = 0;
}
if (pref_advertise == 255 || client->retransmit_count > 1)
r = DHCP6_STATE_REQUEST;
return r;
}
static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
_cleanup_free_ DHCP6Message *message = NULL;
int r, buflen, len;
assert(s);
assert(client);
assert(client->event);
r = ioctl(fd, FIONREAD, &buflen);
if (r < 0)
return -errno;
else if (buflen < 0)
/* This really should not happen */
return -EIO;
message = malloc(buflen);
if (!message)
return -ENOMEM;
len = read(fd, message, buflen);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
log_dhcp6_client(client, "Could not receive message from UDP socket: %m");
return -errno;
} else if ((size_t)len < sizeof(DHCP6Message))
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_INFORMATION_REQUEST:
r = client_receive_reply(client, message, len);
if (r < 0)
return 0;
client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
client_start(client, DHCP6_STATE_STOPPED);
break;
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, SD_DHCP6_CLIENT_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;
r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
return r;
switch (state) {
case DHCP6_STATE_STOPPED:
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
client->state = DHCP6_STATE_STOPPED;
return 0;
}
/* fall through */
case DHCP6_STATE_SOLICITATION:
client->state = DHCP6_STATE_SOLICITATION;
break;
case DHCP6_STATE_INFORMATION_REQUEST:
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
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, USEC_PER_SEC));
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_description(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, USEC_PER_SEC));
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_description(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_description(client->timeout_resend, "dhcp6-resend-timeout");
if (r < 0)
return r;
return 0;
}
int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
return 0;
}
int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
return client->state != DHCP6_STATE_STOPPED;
}
int sd_dhcp6_client_start(sd_dhcp6_client *client) {
int r = 0;
enum DHCP6State state = DHCP6_STATE_SOLICITATION;
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
assert_return(client->index > 0, -EINVAL);
assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
return -EBUSY;
r = client_reset(client);
if (r < 0)
return r;
r = client_ensure_iaid(client);
if (r < 0)
return r;
r = client_ensure_duid(client);
if (r < 0)
return r;
r = dhcp6_network_bind_udp_socket(client->index, &client->local_address);
if (r < 0)
return r;
client->fd = r;
r = sd_event_add_io(client->event, &client->receive_message,
client->fd, EPOLLIN, client_receive_message,
client);
if (r < 0)
goto error;
r = sd_event_source_set_priority(client->receive_message,
client->event_priority);
if (r < 0)
goto error;
r = sd_event_source_set_description(client->receive_message,
"dhcp6-receive-message");
if (r < 0)
goto error;
if (client->information_request)
state = DHCP6_STATE_INFORMATION_REQUEST;
log_dhcp6_client(client, "Started in %s mode",
client->information_request? "Information request":
"Managed");
return client_start(client, state);
error:
client_reset(client);
return r;
}
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, 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)
return NULL;
assert(client->n_ref >= 1);
client->n_ref++;
return client;
}
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
if (!client)
return NULL;
assert(client->n_ref >= 1);
client->n_ref--;
if (client->n_ref > 0)
return NULL;
client_reset(client);
sd_dhcp6_client_detach_event(client);
free(client->req_opts);
free(client);
return NULL;
}
int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
size_t t;
assert_return(ret, -EINVAL);
client = new0(sd_dhcp6_client, 1);
if (!client)
return -ENOMEM;
client->n_ref = 1;
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
client->index = -1;
client->fd = -1;
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;
}