sd-dhcp6-client.c revision 3733eec3e292e4ddb4cba5eb8d3bd8cbee7102d8
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright (C) 2014-2015 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 <linux/if_infiniband.h>
#include "udev.h"
#include "udev-util.h"
#include "util.h"
#include "random-util.h"
#include "network-internal.h"
#include "sd-dhcp6-client.h"
#include "dhcp6-protocol.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
#include "dhcp-identifier.h"
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
struct sd_dhcp6_client {
unsigned n_ref;
enum DHCP6State state;
int event_priority;
int index;
struct sd_dhcp6_lease *lease;
int fd;
bool information_request;
void *userdata;
};
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;
}
{
if (arp_type == ARPHRD_ETHER)
else if (arp_type == ARPHRD_INFINIBAND)
else
return -EINVAL;
return 0;
return 0;
}
{
return 0;
}
{
switch (type) {
case DHCP6_DUID_LLT:
return -EINVAL;
break;
case DHCP6_DUID_EN:
return -EINVAL;
break;
case DHCP6_DUID_LL:
return -EINVAL;
break;
case DHCP6_DUID_UUID:
return -EINVAL;
break;
default:
/* accept unknown type in order to be forward compatible */
break;
}
return 0;
}
bool enabled) {
return 0;
}
bool *enabled) {
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->transaction_start = 0;
client->retransmit_time = 0;
client->retransmit_count = 0;
return 0;
}
}
struct in6_addr all_servers =
int r;
if (!message)
return -ENOMEM;
break;
case DHCP6_STATE_SOLICITATION:
if (r < 0)
return r;
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_BOUND:
return -EINVAL;
}
if (r < 0)
return r;
if (r < 0)
return r;
else
elapsed_time = 0xffff;
sizeof(elapsed_time), &elapsed_time);
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);
break;
case DHCP6_STATE_SOLICITATION:
return 0;
}
break;
case DHCP6_STATE_REQUEST:
break;
case DHCP6_STATE_RENEW:
/* 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:
if (!client->timeout_resend_expire) {
&expire);
if (r < 0) {
client_stop(client, r);
return 0;
}
}
break;
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_BOUND:
return 0;
}
if (max_retransmit_count &&
return 0;
}
if (r < 0)
goto error;
if (r >= 0)
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)
goto error;
if (r < 0)
goto error;
}
if (r < 0)
client_stop(client, r);
return 0;
}
int r;
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;
}
sd_dhcp6_lease *lease) {
int r;
bool clientid = false;
len -= sizeof(DHCP6Message);
&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:
break;
}
if (r < 0 && r != -ENOMSG)
return r;
if (r < 0)
return r;
return -EINVAL;
}
break;
if (r < 0)
return r;
break;
case DHCP6_OPTION_DNS_SERVERS:
if (r < 0)
return r;
break;
case DHCP6_OPTION_DOMAIN_LIST:
if (r < 0)
return r;
break;
case DHCP6_OPTION_NTP_SERVER:
if (r < 0)
return r;
break;
if (r < 0)
return r;
break;
}
}
if (r == -ENOMSG)
r = 0;
if (r < 0 || !clientid) {
return -EINVAL;
}
if (r < 0)
}
return r;
}
{
int r;
bool rapid_commit;
return 0;
r = dhcp6_lease_new(&lease);
if (r < 0)
return -ENOMEM;
if (r < 0)
return r;
if (r < 0)
return r;
if (!rapid_commit)
return 0;
}
}
return DHCP6_STATE_BOUND;
}
int r;
return 0;
r = dhcp6_lease_new(&lease);
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0 || pref_advertise > pref_lease) {
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;
if (r < 0)
return 0;
break;
case DHCP6_STATE_SOLICITATION:
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:
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:
return 0;
}
if (r >= 0) {
}
return 0;
}
{
int r;
char time_string[FORMAT_TIMESPAN_MAX];
client->retransmit_time = 0;
client->retransmit_count = 0;
if (r < 0)
return r;
switch (state) {
case DHCP6_STATE_STOPPED:
return 0;
}
/* fall through */
case DHCP6_STATE_SOLICITATION:
break;
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
break;
case DHCP6_STATE_BOUND:
return 0;
}
timeout, 0));
client);
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
timeout, 0));
client);
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
return 0;
}
client);
if (r < 0)
return r;
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;
r = client_ensure_iaid(client);
if (r < 0)
return r;
r = client_ensure_duid(client);
if (r < 0)
return r;
if (r < 0)
return r;
client);
if (r < 0)
goto error;
if (r < 0)
goto error;
"dhcp6-receive-message");
if (r < 0)
goto error;
if (client->information_request)
"Managed");
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 NULL;
return client;
}
if (!client)
return NULL;
return NULL;
return NULL;
}
{
size_t t;
if (!client)
return -ENOMEM;
return -ENOMEM;
for (t = 0; t < client->req_opts_len; t++)
return 0;
}