sd-dhcp6-client.c revision 3dc34fcc97b41f8b7b019027225b121dfbb9871d
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright (C) 2014 Intel Corporation. All rights reserved.
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <string.h>
#include "udev.h"
#include "udev-util.h"
#include "virt.h"
#include "siphash24.h"
#include "util.h"
#include "refcnt.h"
#include "network-internal.h"
#include "sd-dhcp6-client.h"
#include "dhcp6-protocol.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
#define SYSTEMD_PEN 43793
struct sd_dhcp6_client {
enum DHCP6State state;
int event_priority;
int index;
struct ether_addr mac_addr;
struct sd_dhcp6_lease *lease;
int fd;
void *userdata;
struct duid_en {
};
static const uint16_t default_req_opts[] = {
};
const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
[DHCP6_SOLICIT] = "SOLICIT",
[DHCP6_ADVERTISE] = "ADVERTISE",
[DHCP6_REQUEST] = "REQUEST",
[DHCP6_CONFIRM] = "CONFIRM",
[DHCP6_RENEW] = "RENEW",
[DHCP6_REBIND] = "REBIND",
[DHCP6_REPLY] = "REPLY",
[DHCP6_RELEASE] = "RELEASE",
[DHCP6_DECLINE] = "DECLINE",
[DHCP6_RECONFIGURE] = "RECONFIGURE",
[DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
[DHCP6_RELAY_FORW] = "RELAY-FORW",
[DHCP6_RELAY_REPL] = "RELAY-REPL",
};
const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
[DHCP6_STATUS_SUCCESS] = "Success",
[DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure",
[DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available",
[DHCP6_STATUS_NO_BINDING] = "Binding unavailable",
[DHCP6_STATUS_NOT_ON_LINK] = "Not on link",
[DHCP6_STATUS_USE_MULTICAST] = "Use multicast",
};
#define DHCP6_CLIENT_DONT_DESTROY(client) \
_cleanup_dhcp6_client_unref_ _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
{
return 0;
}
{
return 0;
}
const struct ether_addr *mac_addr)
{
if (mac_addr)
else
return 0;
}
size_t t;
switch(option) {
case DHCP6_OPTION_DNS_SERVERS:
case DHCP6_OPTION_DOMAIN_LIST:
case DHCP6_OPTION_NTP_SERVER:
break;
default:
return -EINVAL;
}
for (t = 0; t < client->req_opts_len; t++)
return -EEXIST;
return -ENOMEM;
return 0;
}
return -ENOMSG;
return 0;
}
}
client->transaction_id = 0;
client->retransmit_time = 0;
client->retransmit_count = 0;
return 0;
}
}
struct in6_addr all_servers =
int r;
if (!message)
return -ENOMEM;
case DHCP6_STATE_SOLICITATION:
if (r < 0)
return r;
break;
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
else
if (r < 0)
return r;
if (r < 0)
return r;
break;
case DHCP6_STATE_REBIND:
if (r < 0)
return r;
break;
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_RS:
case DHCP6_STATE_BOUND:
return -EINVAL;
}
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
return 0;
}
void *userdata) {
assert_return(s, -EINVAL);
return 0;
}
void *userdata) {
assert_return(s, -EINVAL);
return 0;
}
void *userdata) {
enum DHCP6State state;
assert(s);
/* 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)
return 0;
}
}
void *userdata) {
int r = 0;
char time_string[FORMAT_TIMESPAN_MAX];
assert(s);
case DHCP6_STATE_SOLICITATION:
return 0;
}
max_retransmit_count = 0;
break;
case DHCP6_STATE_REQUEST:
break;
case DHCP6_STATE_RENEW:
max_retransmit_count = 0;
/* 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:
max_retransmit_count = 0;
if (!client->timeout_resend_expire) {
&expire);
if (r < 0) {
client_stop(client, r);
return 0;
}
}
break;
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_RS:
case DHCP6_STATE_BOUND:
return 0;
}
if (max_retransmit_count &&
return 0;
}
r = client_send_message(client);
if (r >= 0)
if (r < 0)
goto error;
if (!client->retransmit_time) {
} else {
if (max_retransmit_time &&
else
}
client->retransmit_time, 0));
client);
if (r < 0)
goto error;
if (r < 0)
goto error;
if (r < 0)
goto error;
if (r < 0)
goto error;
}
if (r < 0)
client_stop(client, r);
return 0;
}
return 0;
if (detect_container(NULL) <= 0) {
/* not in a container, udev will be around */
if (!udev)
return -ENOMEM;
if (!device)
return -errno;
if (udev_device_get_is_initialized(device) <= 0)
/* not yet ready */
return -EBUSY;
}
if (name)
else
/* fall back to mac address if no predictable name available */
/* fold into 32 bits */
return 0;
}
sd_dhcp6_lease *lease) {
int r;
bool clientid = false;
&optval)) >= 0) {
switch (optcode) {
case DHCP6_OPTION_CLIENTID:
if (clientid) {
return -EINVAL;
}
return -EINVAL;
}
clientid = true;
break;
case DHCP6_OPTION_SERVERID:
if (r >= 0 && id) {
return -EINVAL;
}
if (r < 0)
return r;
break;
case DHCP6_OPTION_PREFERENCE:
if (optlen != 1)
return -EINVAL;
if (r < 0)
return r;
break;
case DHCP6_OPTION_STATUS_CODE:
if (optlen < 2)
return -EINVAL;
if (status) {
return -EINVAL;
}
break;
case DHCP6_OPTION_IA_NA:
if (r < 0 && r != -ENOMSG)
return r;
if (r < 0)
return r;
return -EINVAL;
}
break;
}
}
return -EINVAL;
}
if (r < 0)
return r;
}
{
int r;
return -EINVAL;
r = dhcp6_lease_new(&lease);
if (r < 0)
return -ENOMEM;
if (r < 0)
return r;
return DHCP6_STATE_BOUND;
}
int r;
return -EINVAL;
r = dhcp6_lease_new(&lease);
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
r = 0;
}
r = DHCP6_STATE_REQUEST;
return r;
}
void *userdata) {
assert(s);
if (r < 0 || buflen <= 0)
if (!message)
return -ENOMEM;
return 0;
}
case DHCP6_SOLICIT:
case DHCP6_REQUEST:
case DHCP6_CONFIRM:
case DHCP6_RENEW:
case DHCP6_REBIND:
case DHCP6_RELEASE:
case DHCP6_DECLINE:
case DHCP6_RELAY_FORW:
case DHCP6_RELAY_REPL:
return 0;
case DHCP6_ADVERTISE:
case DHCP6_REPLY:
case DHCP6_RECONFIGURE:
break;
default:
return 0;
}
htobe32(0x00ffffff)))
return 0;
case DHCP6_STATE_SOLICITATION:
if (r == DHCP6_STATE_REQUEST)
client_start(client, r);
break;
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
if (r < 0)
return 0;
if (r == DHCP6_STATE_BOUND) {
if (r < 0) {
client_stop(client, r);
return 0;
}
}
break;
case DHCP6_STATE_BOUND:
break;
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_RS:
return 0;
}
if (r >= 0) {
}
return 0;
}
{
int r;
char time_string[FORMAT_TIMESPAN_MAX];
client->retransmit_time = 0;
client->retransmit_count = 0;
switch (state) {
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_RS:
case DHCP6_STATE_SOLICITATION:
r = client_ensure_iaid(client);
if (r < 0)
return r;
if (r < 0)
return r;
client);
if (r < 0)
return r;
if (r < 0)
return r;
break;
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
break;
case DHCP6_STATE_BOUND:
if (r < 0)
return r;
return 0;
}
timeout, 0));
client);
if (r < 0)
return r;
if (r < 0)
return r;
timeout, 0));
client);
if (r < 0)
return r;
if (r < 0)
return r;
return 0;
}
CLOCK_MONOTONIC, 0, 0, client_timeout_resend,
client);
if (r < 0)
return r;
if (r < 0)
return r;
return 0;
}
{
return 0;
}
{
int r = 0;
r = client_reset(client);
if (r < 0)
return r;
}
int priority)
{
int r;
if (event)
else {
if (r < 0)
return 0;
}
return 0;
}
return 0;
}
if (!client)
return NULL;
}
if (client)
return client;
}
return NULL;
}
return client;
}
{
int r;
size_t t;
if (!client)
return -ENOMEM;
/* initialize DUID */
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 */
return -ENOMEM;
for (t = 0; t < client->req_opts_len; t++)
return 0;
}