sd-dhcp6-client.c revision fa94c34b083b5b4019975624453e53d0cbad2a5d
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering/***
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering This file is part of systemd.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Copyright (C) 2014 Intel Corporation. All rights reserved.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is free software; you can redistribute it and/or modify it
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering under the terms of the GNU Lesser General Public License as published by
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering (at your option) any later version.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering systemd is distributed in the hope that it will be useful, but
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering Lesser General Public License for more details.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering You should have received a copy of the GNU Lesser General Public License
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering***/
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <errno.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <string.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include <sys/ioctl.h>
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "udev.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "udev-util.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "virt.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "siphash24.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "util.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "refcnt.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "network-internal.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "sd-dhcp6-client.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "dhcp6-protocol.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "dhcp6-internal.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#include "dhcp6-lease-internal.h"
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#define SYSTEMD_PEN 43793
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekstruct sd_dhcp6_client {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering RefCount n_ref;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering enum DHCP6State state;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_event *event;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int event_priority;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int index;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering struct ether_addr mac_addr;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering DHCP6IA ia_na;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering be32_t transaction_id;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering struct sd_dhcp6_lease *lease;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int fd;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering be16_t *req_opts;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering size_t req_opts_allocated;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering size_t req_opts_len;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_event_source *receive_message;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering usec_t retransmit_time;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uint8_t retransmit_count;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_event_source *timeout_resend;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_event_source *timeout_resend_expire;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering sd_dhcp6_client_cb_t cb;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering void *userdata;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt struct duid_en {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uint16_t type; /* DHCP6_DUID_EN */
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering uint32_t pen;
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering uint8_t id[8];
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering } _packed_ duid;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering};
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poetteringstatic const uint16_t default_req_opts[] = {
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering DHCP6_OPTION_DNS_SERVERS,
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering DHCP6_OPTION_DOMAIN_LIST,
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering DHCP6_OPTION_NTP_SERVER,
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering};
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poetteringconst char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering [DHCP6_SOLICIT] = "SOLICIT",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_ADVERTISE] = "ADVERTISE",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_REQUEST] = "REQUEST",
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt [DHCP6_CONFIRM] = "CONFIRM",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_RENEW] = "RENEW",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_REBIND] = "REBIND",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_REPLY] = "REPLY",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_RELEASE] = "RELEASE",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_DECLINE] = "DECLINE",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_RECONFIGURE] = "RECONFIGURE",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_RELAY_FORW] = "RELAY-FORW",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_RELAY_REPL] = "RELAY-REPL",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering};
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidtconst char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt [DHCP6_STATUS_SUCCESS] = "Success",
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt [DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_STATUS_NOT_ON_LINK] = "Not on link",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering [DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering};
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringDEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#define _cleanup_dhcp6_client_unref_ _cleanup_(sd_dhcp6_client_unrefp)
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering#define DHCP6_CLIENT_DONT_DESTROY(client) \
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_dhcp6_client_unref_ _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int client_start(sd_dhcp6_client *client, enum DHCP6State state);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringint sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_dhcp6_client_cb_t cb, void *userdata)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering{
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(client, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->cb = cb;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->userdata = userdata;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmekint sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index)
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek{
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert_return(client, -EINVAL);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering assert_return(interface_index >= -1, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->index = interface_index;
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek return 0;
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmekint sd_dhcp6_client_set_mac(sd_dhcp6_client *client,
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek const struct ether_addr *mac_addr)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering{
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek assert_return(client, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (mac_addr)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering memcpy(&client->mac_addr, mac_addr, sizeof(client->mac_addr));
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek else
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek memset(&client->mac_addr, 0x00, sizeof(client->mac_addr));
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return 0;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek}
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmekint sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek uint16_t option) {
4b8268f843b0da1cfe1995d93a0b1f95faccc454Zbigniew Jędrzejewski-Szmek size_t t;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek assert_return(client, -EINVAL);
4b8268f843b0da1cfe1995d93a0b1f95faccc454Zbigniew Jędrzejewski-Szmek assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek switch(option) {
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek case DHCP6_OPTION_DNS_SERVERS:
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek case DHCP6_OPTION_DOMAIN_LIST:
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek case DHCP6_OPTION_SNTP_SERVERS:
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek case DHCP6_OPTION_NTP_SERVER:
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek break;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek default:
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return -EINVAL;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek }
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek for (t = 0; t < client->req_opts_len; t++)
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek if (client->req_opts[t] == htobe16(option))
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek return -EEXIST;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek client->req_opts_len + 1))
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek return -ENOMEM;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek client->req_opts[client->req_opts_len++] = htobe16(option);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek return 0;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek}
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmekint sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek assert_return(client, -EINVAL);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek assert_return(ret, -EINVAL);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek if (!client->lease)
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek return -ENOMSG;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek *ret = sd_dhcp6_lease_ref(client->lease);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek return 0;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek}
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmekstatic void client_notify(sd_dhcp6_client *client, int event) {
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek if (client->cb)
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek client->cb(client, event, client->userdata);
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int client_reset(sd_dhcp6_client *client) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(client, -EINVAL);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->receive_message =
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek sd_event_source_unref(client->receive_message);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->fd = safe_close(client->fd);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->transaction_id = 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->ia_na.timeout_t1 =
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_event_source_unref(client->ia_na.timeout_t1);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->ia_na.timeout_t2 =
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt sd_event_source_unref(client->ia_na.timeout_t2);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->retransmit_time = 0;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek client->retransmit_count = 0;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek client->timeout_resend = sd_event_source_unref(client->timeout_resend);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt client->timeout_resend_expire =
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek sd_event_source_unref(client->timeout_resend_expire);
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek client->state = DHCP6_STATE_STOPPED;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic void client_stop(sd_dhcp6_client *client, int error) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering DHCP6_CLIENT_DONT_DESTROY(client);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(client);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt client_notify(client, error);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client_reset(client);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int client_send_message(sd_dhcp6_client *client) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_free_ DHCP6Message *message = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering struct in6_addr all_servers =
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering size_t len, optlen = 512;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uint8_t *opt;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d3b6d0c21ea5a0d15ec6dbd8b8d179138b7463bcZbigniew Jędrzejewski-Szmek len = sizeof(DHCP6Message) + optlen;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering message = malloc0(len);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!message)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENOMEM;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering opt = (uint8_t *)(message + 1);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek message->transaction_id = client->transaction_id;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering switch(client->state) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_STATE_SOLICITATION:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering message->type = DHCP6_SOLICIT;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_option_append(&opt, &optlen,
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek case DHCP6_STATE_REQUEST:
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek case DHCP6_STATE_RENEW:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (client->state == DHCP6_STATE_REQUEST)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering message->type = DHCP6_REQUEST;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering message->type = DHCP6_RENEW;
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID,
baf167ee0a2953f98e4e7d4c35752ef737832674Zbigniew Jędrzejewski-Szmek client->lease->serverid_len,
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek client->lease->serverid);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_STATE_REBIND:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering message->type = DHCP6_REBIND;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_STATE_STOPPED:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_STATE_BOUND:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->req_opts_len * sizeof(be16_t),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->req_opts);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sizeof(client->duid), &client->duid);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering len - optlen);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_dhcp6_client(client, "Sent %s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering dhcp6_message_type_to_string(message->type));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
c7332b0844e28d9b70c3c763b929f105c1056fe8Zbigniew Jędrzejewski-Szmek return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int client_timeout_t2(sd_event_source *s, uint64_t usec,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering void *userdata) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_dhcp6_client *client = userdata;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert_return(s, -EINVAL);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert_return(client, -EINVAL);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert_return(client->lease, -EINVAL);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek client->lease->ia.timeout_t2 =
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek sd_event_source_unref(client->lease->ia.timeout_t2);
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek log_dhcp6_client(client, "Timeout T2");
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek client_start(client, DHCP6_STATE_REBIND);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidtstatic int client_timeout_t1(sd_event_source *s, uint64_t usec,
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt void *userdata) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek sd_dhcp6_client *client = userdata;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt assert_return(s, -EINVAL);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt assert_return(client, -EINVAL);
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt assert_return(client->lease, -EINVAL);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek client->lease->ia.timeout_t1 =
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek sd_event_source_unref(client->lease->ia.timeout_t1);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek log_dhcp6_client(client, "Timeout T1");
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek client_start(client, DHCP6_STATE_RENEW);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekstatic int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek void *userdata) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek sd_dhcp6_client *client = userdata;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek DHCP6_CLIENT_DONT_DESTROY(client);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek enum DHCP6State state;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(s);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(client);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek assert(client->event);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek state = client->state;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek client_stop(client, DHCP6_EVENT_RESEND_EXPIRE);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek /* RFC 3315, section 18.1.4., says that "...the client may choose to
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek use a Solicit message to locate a new DHCP server..." */
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering if (state == DHCP6_STATE_REBIND)
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering client_start(client, DHCP6_STATE_SOLICITATION);
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekstatic usec_t client_timeout_compute_random(usec_t val) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return val - val / 10 +
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering}
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmekstatic int client_timeout_resend(sd_event_source *s, uint64_t usec,
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek void *userdata) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek int r = 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek sd_dhcp6_client *client = userdata;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering usec_t max_retransmit_duration = 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek uint8_t max_retransmit_count = 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek char time_string[FORMAT_TIMESPAN_MAX];
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek uint32_t expire = 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(s);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(client);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(client->event);
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->timeout_resend = sd_event_source_unref(client->timeout_resend);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering switch (client->state) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_STATE_SOLICITATION:
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (client->retransmit_count && client->lease) {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt client_start(client, DHCP6_STATE_REQUEST);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek }
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering init_retransmit_time = DHCP6_SOL_TIMEOUT;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering max_retransmit_time = DHCP6_SOL_MAX_RT;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_STATE_REQUEST:
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt init_retransmit_time = DHCP6_REQ_TIMEOUT;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering max_retransmit_time = DHCP6_REQ_MAX_RT;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering max_retransmit_count = DHCP6_REQ_MAX_RC;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek case DHCP6_STATE_RENEW:
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek init_retransmit_time = DHCP6_REN_TIMEOUT;
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek max_retransmit_time = DHCP6_REN_MAX_RT;
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek /* RFC 3315, section 18.1.3. says max retransmit duration will
e3b9d9c8027a7c4c55cf1614e0fe9423fad69e8fZbigniew Jędrzejewski-Szmek be the remaining time until T2. Instead of setting MRD,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering wait for T2 to trigger with the same end result */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_STATE_REBIND:
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek init_retransmit_time = DHCP6_REB_TIMEOUT;
80343dc19a9bcd703275ad2ad88f43e5310559d6Zbigniew Jędrzejewski-Szmek max_retransmit_time = DHCP6_REB_MAX_RT;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!client->timeout_resend_expire) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering &expire);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client_stop(client, r);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering max_retransmit_duration = expire * USEC_PER_SEC;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek break;
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek
18cd5fe99f70a55a2d6f2303d6ee0624942695b1Zbigniew Jędrzejewski-Szmek case DHCP6_STATE_STOPPED:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_STATE_BOUND:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
7ff7394d9e4e9189c30fd018235e6b1728c6f2d0Zbigniew Jędrzejewski-Szmek if (max_retransmit_count &&
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->retransmit_count >= max_retransmit_count) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek client_stop(client, DHCP6_EVENT_RETRANS_MAX);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek return 0;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt }
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek r = client_send_message(client);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (r >= 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->retransmit_count++;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek goto error;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!client->retransmit_time) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek client->retransmit_time =
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client_timeout_compute_random(init_retransmit_time);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (client->state == DHCP6_STATE_SOLICITATION)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->retransmit_time += init_retransmit_time / 10;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering } else {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (max_retransmit_time &&
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->retransmit_time > max_retransmit_time / 2)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_dhcp6_client(client, "Next retransmission in %s",
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering format_timespan(time_string, FORMAT_TIMESPAN_MAX,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->retransmit_time, 0));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_event_add_time(client->event, &client->timeout_resend,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering clock_boottime_or_monotonic(),
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering time_now + client->retransmit_time,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering 10 * USEC_PER_MSEC, client_timeout_resend,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering goto error;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering r = sd_event_source_set_priority(client->timeout_resend,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->event_priority);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering goto error;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (max_retransmit_duration && !client->timeout_resend_expire) {
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering max_retransmit_duration / USEC_PER_SEC);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering r = sd_event_add_time(client->event,
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering &client->timeout_resend_expire,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering clock_boottime_or_monotonic(),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering time_now + max_retransmit_duration,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering USEC_PER_SEC,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client_timeout_resend_expire, client);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering goto error;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = sd_event_source_set_priority(client->timeout_resend_expire,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->event_priority);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering goto error;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringerror:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client_stop(client, r);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int client_ensure_iaid(sd_dhcp6_client *client) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* name is a pointer to memory in the udev_device struct, so must
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering have the same scope */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_udev_device_unref_ struct udev_device *device = NULL;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering const char *name = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uint64_t id;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering assert(client);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (client->ia_na.id)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (detect_container(NULL) <= 0) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* not in a container, udev will be around */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering _cleanup_udev_unref_ struct udev *udev;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering char ifindex_str[2 + DECIMAL_STR_MAX(int)];
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering udev = udev_new();
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering if (!udev)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -ENOMEM;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sprintf(ifindex_str, "n%d", client->index);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering device = udev_device_new_from_device_id(udev, ifindex_str);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (!device)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -errno;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering if (udev_device_get_is_initialized(device) <= 0)
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering /* not yet ready */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EBUSY;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek name = net_get_name(device);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
a7f7d1bde43fc825c49afea3f946f5b4b3d563e0Harald Hoyer if (name)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering else
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering /* fall back to mac address if no predictable name available */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering siphash24((uint8_t*)&id, &client->mac_addr, ETH_ALEN,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering HASH_KEY.bytes);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek /* fold into 32 bits */
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return 0;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering}
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poetteringstatic int client_parse_message(sd_dhcp6_client *client,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering DHCP6Message *message, size_t len,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering sd_dhcp6_lease *lease) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering int r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uint8_t *optval, *option = (uint8_t *)(message + 1), *id = NULL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering uint16_t optcode, status;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering size_t optlen, id_len;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering bool clientid = false;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering be32_t iaid_lease;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen,
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering &optval)) >= 0) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering switch (optcode) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_OPTION_CLIENTID:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (clientid) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_dhcp6_client(client, "%s contains multiple clientids",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering dhcp6_message_type_to_string(message->type));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (optlen != sizeof(client->duid) ||
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering memcmp(&client->duid, optval, optlen) != 0) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_dhcp6_client(client, "%s DUID does not match",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering dhcp6_message_type_to_string(message->type));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering clientid = true;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_OPTION_SERVERID:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_lease_get_serverid(lease, &id, &id_len);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r >= 0 && id) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_dhcp6_client(client, "%s contains multiple serverids",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering dhcp6_message_type_to_string(message->type));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_lease_set_serverid(lease, optval, optlen);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek case DHCP6_OPTION_PREFERENCE:
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (optlen != 1)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return -EINVAL;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = dhcp6_lease_set_preference(lease, *optval);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return r;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek break;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek case DHCP6_OPTION_STATUS_CODE:
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (optlen < 2)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return -EINVAL;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek status = optval[0] << 8 | optval[1];
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek if (status) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_dhcp6_client(client, "%s Status %s",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering dhcp6_message_type_to_string(message->type),
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering dhcp6_message_status_to_string(status));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_OPTION_IA_NA:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek &lease->ia);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0 && r != -ENOMSG)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_lease_get_iaid(lease, &iaid_lease);
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
83f6936a018b08880670838756e0f4e9ea98b4a7Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (client->ia_na.id != iaid_lease) {
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering log_dhcp6_client(client, "%s has wrong IAID",
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering dhcp6_message_type_to_string(message->type));
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return -EINVAL;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering case DHCP6_OPTION_RAPID_COMMIT:
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering r = dhcp6_lease_set_rapid_commit(lease);
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering if (r < 0)
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering return r;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering break;
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering }
d4205751d4643c272059a3728045929dd0e5e800Lennart Poettering
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if ((r < 0 && r != -ENOMSG) || !clientid) {
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek log_dhcp6_client(client, "%s has incomplete options",
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek dhcp6_message_type_to_string(message->type));
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return -EINVAL;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek }
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = dhcp6_lease_get_serverid(lease, &id, &id_len);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0)
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer log_dhcp6_client(client, "%s has no server id",
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek dhcp6_message_type_to_string(message->type));
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return r;
c33b329709ebe2755181980a050d02ec7c81ed87Michal Schmidt}
c33b329709ebe2755181980a050d02ec7c81ed87Michal Schmidt
464264ac5a35b655065c5d95b8d8ffbbc7ff3bcfLukas Nykrynstatic int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek size_t len)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek{
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek int r;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
844ec79b3c2f246114ea316ebe1f36044bdb688eZbigniew Jędrzejewski-Szmek bool rapid_commit;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (reply->type != DHCP6_REPLY)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return 0;
2e8fb7026d3c560194cfe9f83935ce0b16263da0Lukas Nykryn
464264ac5a35b655065c5d95b8d8ffbbc7ff3bcfLukas Nykryn r = dhcp6_lease_new(&lease);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return -ENOMEM;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = client_parse_message(client, reply, len, lease);
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (r < 0)
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek return r;
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek if (client->state == DHCP6_STATE_SOLICITATION) {
54b7254c1fa629937f92fd6fa34bdf127b696a00Zbigniew Jędrzejewski-Szmek r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit);
if (r < 0)
return r;
if (!rapid_commit)
return 0;
}
if (client->lease)
dhcp6_lease_clear_timers(&client->lease->ia);
client->lease = sd_dhcp6_lease_unref(client->lease);
client->lease = lease;
lease = NULL;
return DHCP6_STATE_BOUND;
}
static int client_receive_advertise(sd_dhcp6_client *client,
DHCP6Message *advertise, size_t len) {
int r;
_cleanup_dhcp6_lease_free_ 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 (!client->lease || r < 0 || pref_advertise > pref_lease) {
sd_dhcp6_lease_unref(client->lease);
client->lease = 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;
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;
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;
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:
r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
return r;
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;
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;
client->state = state;
return 0;
}
client->transaction_id = random_u32() & htobe32(0x00ffffff);
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;
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.type = htobe16(DHCP6_DUID_EN);
client->duid.pen = htobe32(SYSTEMD_PEN);
r = sd_id128_get_machine(&machine_id);
if (r < 0)
return r;
/* a bit of snake-oil perhaps, but no need to expose the machine-id
directly */
siphash24(client->duid.id, &machine_id, sizeof(machine_id),
HASH_KEY.bytes);
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;
}