sd-dhcp-client.c revision 0c79c68d93d721d37ba088fb50dbf07bb0d447e5
/***
This file is part of systemd.
Copyright (C) 2013 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 <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <net/ethernet.h>
#include "util.h"
#include "list.h"
#include "dhcp-protocol.h"
#include "dhcp-internal.h"
#include "dhcp-lease-internal.h"
#include "sd-dhcp-client.h"
struct sd_dhcp_client {
int event_priority;
int index;
int fd;
union sockaddr_union link;
struct {
struct ether_addr mac_addr;
unsigned int attempt;
void *userdata;
};
static const uint8_t default_req_opts[] = {
};
void *userdata) {
return 0;
}
size_t i;
switch(option) {
case DHCP_OPTION_PAD:
case DHCP_OPTION_OVERLOAD:
case DHCP_OPTION_MESSAGE_TYPE:
case DHCP_OPTION_END:
return -EINVAL;
default:
break;
}
for (i = 0; i < client->req_opts_size; i++)
return -EEXIST;
return -ENOMEM;
return 0;
}
if (last_addr)
else
return 0;
}
return 0;
}
const struct ether_addr *addr) {
bool need_restart = false;
return 0;
"client, restarting");
need_restart = true;
}
if (need_restart)
return 0;
}
return -EADDRNOTAVAIL;
return 0;
}
return 0;
}
return 0;
}
return 0;
}
int r;
optlen);
if (r < 0)
return r;
/* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
refuse to issue an DHCP lease if 'secs' is set to zero */
/* Some DHCP servers will refuse to issue an DHCP lease if the Client
Identifier option is not set */
if (r < 0)
return r;
if (r < 0)
return r;
/* Some DHCP servers will send bigger DHCP packets than the
defined default size unless the Maximum Messge Size option
is explicitely set */
2, &max_size);
if (r < 0)
return r;
}
return 0;
}
}
int r;
if (r < 0)
return r;
/* seconds between sending first and last DISCOVER
* must always be strictly positive to deal with broken servers */
if (!discover)
return -ENOMEM;
if (r < 0)
return r;
if (r < 0)
return r;
}
if (r < 0)
return r;
if (r < 0)
return r;
return 0;
}
int r;
if (!request)
return -ENOMEM;
&optlen);
if (r < 0)
return r;
case DHCP_STATE_INIT_REBOOT:
if (r < 0)
return r;
break;
case DHCP_STATE_REQUESTING:
if (r < 0)
return r;
if (r < 0)
return r;
break;
case DHCP_STATE_INIT:
case DHCP_STATE_SELECTING:
case DHCP_STATE_REBOOTING:
case DHCP_STATE_BOUND:
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
break;
}
if (r < 0)
return r;
} else {
}
if (r < 0)
return r;
return 0;
}
void *userdata) {
usec_t next_timeout = 0;
int r;
assert(s);
if (r < 0)
goto error;
case DHCP_STATE_RENEWING:
if (time_left < 60)
time_left = 60;
break;
case DHCP_STATE_REBINDING:
if (time_left < 60)
time_left = 60;
break;
case DHCP_STATE_REBOOTING:
/* start over as we did not receive a timely ack or nak */
/* fall through */
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_SELECTING:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_BOUND:
break;
}
if (r < 0)
goto error;
if (r < 0)
goto error;
case DHCP_STATE_INIT:
r = client_send_discover(client);
if (r >= 0) {
} else {
goto error;
}
break;
case DHCP_STATE_SELECTING:
r = client_send_discover(client);
goto error;
break;
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
r = client_send_request(client);
goto error;
break;
case DHCP_STATE_REBOOTING:
case DHCP_STATE_BOUND:
break;
}
return 0;
client_stop(client, r);
/* Errors were dealt with when stopping the client, don't spill
errors into the event loop handler */
return 0;
}
int r;
client);
if (r < 0)
goto error;
if (r < 0)
goto error;
0, 0,
if (r < 0)
goto error;
if (r < 0)
client_stop(client, r);
return 0;
}
int r;
if (r < 0) {
client_stop(client, r);
return r;
}
}
}
void *userdata) {
/* start over as the lease was lost */
return 0;
}
int r;
if (r < 0) {
client_stop(client, r);
return 0;
}
}
void *userdata) {
int r;
if (r < 0) {
client_stop(client, r);
return 0;
}
}
int r;
r = dhcp_lease_new(&lease);
if (r < 0)
return r;
if (r != DHCP_OFFER) {
return -ENOMSG;
}
"address or lease lifetime, ignoring");
return -ENOMSG;
}
if (r < 0) {
"mask, and a fallback one can not be "
"generated, ignoring");
return -ENOMSG;
}
}
return 0;
}
int r;
r = dhcp_lease_new(&lease);
if (r < 0)
return r;
if (r == DHCP_NAK) {
return DHCP_EVENT_NO_LEASE;
}
if (r != DHCP_ACK) {
return -ENOMSG;
}
"address or lease lifetime, ignoring");
return -ENOMSG;
}
if (r < 0) {
"mask, and a fallback one can not be "
"generated, ignoring");
return -ENOMSG;
}
}
r = DHCP_EVENT_IP_CHANGE;
}
}
return r;
}
+ (random_u32() & 0x1fffff);
}
char time_string[FORMAT_TIMESPAN_MAX];
int r;
/* don't set timers for infinite leases */
return 0;
if (r < 0)
return r;
/* convert the various timeouts from relative (secs) to absolute (usecs) */
/* both T1 and T2 are given */
/* they are both valid */
} else {
/* discard both */
}
/* only T2 is given, and it is valid */
if (t2_timeout <= t1_timeout) {
/* the computed T1 would be invalid, so discard T2 */
}
/* only T1 is given, and it is valid */
if (t2_timeout <= t1_timeout) {
/* the computed T2 would be invalid, so discard T1 */
}
} else {
/* fall back to the default timeouts */
}
/* arm lifetime timeout */
if (r < 0)
return r;
if (r < 0)
return r;
lifetime_timeout - time_now, 0));
/* don't arm earlier timeouts if this has already expired */
if (lifetime_timeout <= time_now)
return 0;
/* arm T2 timeout */
&client->timeout_t2,
10 * USEC_PER_MSEC,
if (r < 0)
return r;
if (r < 0)
return r;
t2_timeout - time_now, 0));
/* don't arm earlier timeout if this has already expired */
if (t2_timeout <= time_now)
return 0;
/* arm T1 timeout */
&client->timeout_t1,
if (r < 0)
return r;
if (r < 0)
return r;
t1_timeout - time_now, 0));
return 0;
}
int len) {
int r = 0, notify_event = 0;
return 0;
}
return 0;
}
"expected (%u): ignoring",
return 0;
}
return 0;
}
ETH_ALEN)) {
"expected: ignoring");
return 0;
}
case DHCP_STATE_SELECTING:
if (r >= 0) {
0, 0,
if (r < 0)
goto error;
if (r < 0)
goto error;
} else if (r == -ENOMSG)
/* invalid message, let's ignore it */
return 0;
break;
case DHCP_STATE_REBOOTING:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
if (r == DHCP_EVENT_NO_LEASE) {
r = client_initialize(client);
if (r < 0)
goto error;
r = client_start(client);
if (r < 0)
goto error;
}
goto error;
} else if (r >= 0) {
else if (r != DHCP_EVENT_IP_ACQUIRE)
notify_event = r;
if (r < 0)
goto error;
if (notify_event)
} else if (r == -ENOMSG)
/* invalid message, let's ignore it */
return 0;
break;
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_BOUND:
break;
}
if (r < 0 || r == DHCP_EVENT_NO_LEASE)
return client_stop(client, r);
return 0;
}
assert(s);
if (r < 0 || buflen <= 0)
if (!message)
return -ENOMEM;
if (len < 0) {
return 0;
return 0;
}
.msg_iovlen = 1,
.msg_control = cmsgbuf,
.msg_controllen = sizeof(cmsgbuf),
};
bool checksum = true;
assert(s);
if (r < 0 || buflen <= 0)
if (!packet)
return -ENOMEM;
if (len < 0) {
return 0;
return 0;
break;
}
}
if (r < 0)
return 0;
len -= DHCP_IP_UDP_SIZE;
}
int r;
r = client_initialize(client);
if (r < 0)
return r;
return client_start(client);
}
}
int priority) {
int r;
if (event)
else {
if (r < 0)
return 0;
}
return 0;
}
return 0;
}
if (!client)
return NULL;
}
if (!client)
return;
}
if (!client)
return -ENOMEM;
return -ENOMEM;
return 0;
}