2011-07-25 12:00:57 +05:30
|
|
|
/* state.c - high level DHCP state machine
|
|
|
|
*
|
2015-02-13 12:24:57 +05:30
|
|
|
* Copyright (c) 2011-2015 Nicholas J. Kain <njkain at gmail dot com>
|
2011-07-25 12:00:57 +05:30
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
2011-06-30 09:17:31 +05:30
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
2014-03-31 02:32:48 +05:30
|
|
|
#include "nk/log.h"
|
|
|
|
#include "nk/random.h"
|
|
|
|
|
2011-06-30 09:17:31 +05:30
|
|
|
#include "state.h"
|
|
|
|
#include "ifchange.h"
|
|
|
|
#include "arp.h"
|
|
|
|
#include "options.h"
|
2014-03-13 02:21:10 +05:30
|
|
|
#include "ndhc.h"
|
2011-06-30 09:17:31 +05:30
|
|
|
#include "sys.h"
|
2015-02-14 15:50:04 +05:30
|
|
|
#include "netlink.h"
|
|
|
|
|
|
|
|
// Simulates netlink carrier down event if carrier went down while suspended.
|
|
|
|
#define SUSPEND_IF_NOCARRIER() \
|
|
|
|
if (r == -99) { \
|
|
|
|
cs->ifsPrevState = IFS_DOWN; \
|
|
|
|
ifnocarrier_action(cs); \
|
|
|
|
dhcp_wake_ts = -1; \
|
|
|
|
return; \
|
|
|
|
}
|
2011-06-30 09:17:31 +05:30
|
|
|
|
2015-02-14 11:14:21 +05:30
|
|
|
static void selecting_packet(struct client_state_t cs[static 1],
|
|
|
|
struct dhcpmsg packet[static 1],
|
2015-02-13 09:58:54 +05:30
|
|
|
uint8_t msgtype, uint32_t srcaddr);
|
2015-02-14 11:14:21 +05:30
|
|
|
static void an_packet(struct client_state_t cs[static 1],
|
|
|
|
struct dhcpmsg packet[static 1],
|
2015-02-13 09:58:54 +05:30
|
|
|
uint8_t msgtype, uint32_t srcaddr);
|
2015-02-14 11:14:21 +05:30
|
|
|
static void selecting_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts);
|
|
|
|
static void requesting_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts);
|
|
|
|
static void bound_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts);
|
|
|
|
static void renewing_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts);
|
|
|
|
static void rebinding_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts);
|
|
|
|
static void released_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts);
|
2015-02-14 08:59:03 +05:30
|
|
|
static void xmit_release(struct client_state_t cs[static 1]);
|
|
|
|
static void print_release(struct client_state_t cs[static 1]);
|
|
|
|
static void frenew(struct client_state_t cs[static 1]);
|
2011-06-30 09:17:31 +05:30
|
|
|
|
|
|
|
typedef struct {
|
2015-02-14 11:14:21 +05:30
|
|
|
void (*packet_fn)(struct client_state_t cs[static 1],
|
|
|
|
struct dhcpmsg packet[static 1],
|
2015-02-13 09:58:54 +05:30
|
|
|
uint8_t msgtype, uint32_t srcaddr);
|
2015-02-14 08:59:03 +05:30
|
|
|
void (*timeout_fn)(struct client_state_t cs[static 1], long long nowts);
|
|
|
|
void (*force_renew_fn)(struct client_state_t cs[static 1]);
|
|
|
|
void (*force_release_fn)(struct client_state_t cs[static 1]);
|
2011-06-30 09:17:31 +05:30
|
|
|
} dhcp_state_t;
|
|
|
|
|
2011-07-11 14:39:38 +05:30
|
|
|
static const dhcp_state_t dhcp_states[] = {
|
2011-07-06 03:59:06 +05:30
|
|
|
{ selecting_packet, selecting_timeout, 0, print_release}, // SELECTING
|
|
|
|
{ an_packet, requesting_timeout, 0, print_release}, // REQUESTING
|
|
|
|
{ 0, bound_timeout, frenew, xmit_release}, // BOUND
|
|
|
|
{ an_packet, renewing_timeout, 0, xmit_release}, // RENEWING
|
|
|
|
{ an_packet, rebinding_timeout, 0, xmit_release}, // REBINDING
|
2011-07-11 14:39:38 +05:30
|
|
|
{ 0, 0, 0, xmit_release}, // BOUND_GW_CHECK
|
|
|
|
{ 0, 0, 0, xmit_release}, // COLLISION_CHECK
|
2011-07-06 03:59:06 +05:30
|
|
|
{ 0, released_timeout, frenew, 0}, // RELEASED
|
|
|
|
{ 0, 0, 0, 0}, // NUM_STATES
|
2011-06-30 09:17:31 +05:30
|
|
|
};
|
|
|
|
|
2011-07-06 01:14:11 +05:30
|
|
|
static unsigned int num_dhcp_requests;
|
2011-07-11 22:54:59 +05:30
|
|
|
static long long dhcp_wake_ts = -1;
|
2011-07-06 01:14:11 +05:30
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
static int delay_timeout(struct client_state_t cs[static 1], size_t numpackets)
|
2011-06-30 12:57:57 +05:30
|
|
|
{
|
|
|
|
int to = 64;
|
|
|
|
char tot[] = { 4, 8, 16, 32, 64 };
|
|
|
|
if (numpackets < sizeof tot)
|
|
|
|
to = tot[numpackets];
|
2014-03-22 11:38:23 +05:30
|
|
|
// Distribution is a bit biased but it doesn't really matter.
|
|
|
|
return to * 1000 + (nk_random_u32(&cs->rnd32_state) & 0x7fffffffu) % 1000;
|
2011-06-30 12:57:57 +05:30
|
|
|
}
|
|
|
|
|
2015-02-15 07:17:14 +05:30
|
|
|
static int reinit_shared_deconfig(struct client_state_t cs[static 1])
|
2011-07-05 07:40:14 +05:30
|
|
|
{
|
2015-02-15 07:17:14 +05:30
|
|
|
if (ifchange_deconfig(cs) < 0)
|
|
|
|
return -1;
|
2011-07-06 01:32:11 +05:30
|
|
|
arp_close_fd(cs);
|
2011-07-05 07:40:14 +05:30
|
|
|
cs->clientAddr = 0;
|
2011-07-06 01:14:11 +05:30
|
|
|
num_dhcp_requests = 0;
|
2011-07-11 22:54:59 +05:30
|
|
|
cs->got_router_arp = 0;
|
|
|
|
cs->got_server_arp = 0;
|
|
|
|
memset(&cs->routerArp, 0, sizeof cs->routerArp);
|
|
|
|
memset(&cs->serverArp, 0, sizeof cs->serverArp);
|
2011-07-06 01:10:57 +05:30
|
|
|
arp_reset_send_stats();
|
2015-02-15 07:17:14 +05:30
|
|
|
return 0;
|
2011-07-11 22:54:59 +05:30
|
|
|
}
|
|
|
|
|
2015-02-15 07:17:14 +05:30
|
|
|
int reinit_selecting(struct client_state_t cs[static 1], int timeout)
|
2011-07-11 22:54:59 +05:30
|
|
|
{
|
2015-02-15 07:17:14 +05:30
|
|
|
if (reinit_shared_deconfig(cs) < 0) {
|
|
|
|
// XXX: This should retry until it succeeds.
|
|
|
|
suicide("%s: (%s) deconfiguring interface failed",
|
|
|
|
client_config.interface, __func__);
|
|
|
|
}
|
2011-07-11 22:54:59 +05:30
|
|
|
cs->dhcpState = DS_SELECTING;
|
|
|
|
dhcp_wake_ts = curms() + timeout;
|
2014-04-16 10:30:36 +05:30
|
|
|
start_dhcp_listen(cs);
|
2015-02-15 07:17:14 +05:30
|
|
|
return 0;
|
2011-07-05 07:40:14 +05:30
|
|
|
}
|
|
|
|
|
2015-02-15 07:17:14 +05:30
|
|
|
static int set_released(struct client_state_t cs[static 1])
|
2011-07-06 03:59:06 +05:30
|
|
|
{
|
2015-02-15 07:17:14 +05:30
|
|
|
if (reinit_shared_deconfig(cs) < 0) {
|
|
|
|
// XXX: This should retry until it succeeds.
|
|
|
|
suicide("%s: (%s) deconfiguring interface failed",
|
|
|
|
client_config.interface, __func__);
|
|
|
|
}
|
2011-07-06 03:59:06 +05:30
|
|
|
cs->dhcpState = DS_RELEASED;
|
2011-07-11 21:01:27 +05:30
|
|
|
dhcp_wake_ts = -1;
|
2014-04-16 10:30:36 +05:30
|
|
|
stop_dhcp_listen(cs);
|
2015-02-15 07:17:14 +05:30
|
|
|
return 0;
|
2011-07-06 03:59:06 +05:30
|
|
|
}
|
|
|
|
|
2011-06-30 09:17:31 +05:30
|
|
|
// Triggered after a DHCP lease request packet has been sent and no reply has
|
|
|
|
// been received within the response wait time. If we've not exceeded the
|
|
|
|
// maximum number of request retransmits, then send another packet and wait
|
|
|
|
// again. Otherwise, return to the DHCP initialization state.
|
2015-02-14 11:14:21 +05:30
|
|
|
static void requesting_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2015-02-14 15:50:04 +05:30
|
|
|
if (num_dhcp_requests >= 5) {
|
2011-07-05 07:40:14 +05:30
|
|
|
reinit_selecting(cs, 0);
|
2015-02-14 15:50:04 +05:30
|
|
|
return;
|
|
|
|
}
|
|
|
|
int r = send_selecting(cs);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning("%s: Failed to send a selecting request packet.",
|
|
|
|
client_config.interface);
|
|
|
|
SUSPEND_IF_NOCARRIER();
|
|
|
|
}
|
|
|
|
dhcp_wake_ts = nowts + delay_timeout(cs, num_dhcp_requests);
|
|
|
|
num_dhcp_requests++;
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
// Triggered when the lease has been held for a significant fraction of its
|
|
|
|
// total time, and it is time to renew the lease so that it is not lost.
|
2015-02-14 08:59:03 +05:30
|
|
|
static void bound_timeout(struct client_state_t cs[static 1], long long nowts)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2011-07-11 18:29:50 +05:30
|
|
|
long long rnt = cs->leaseStartTime + cs->renewTime * 1000;
|
|
|
|
if (nowts < rnt) {
|
2011-07-11 21:01:27 +05:30
|
|
|
dhcp_wake_ts = rnt;
|
2011-07-05 20:37:42 +05:30
|
|
|
return;
|
2011-07-11 18:29:50 +05:30
|
|
|
}
|
2011-06-30 09:17:31 +05:30
|
|
|
cs->dhcpState = DS_RENEWING;
|
2014-04-16 10:30:36 +05:30
|
|
|
start_dhcp_listen(cs);
|
2011-07-11 18:29:50 +05:30
|
|
|
renewing_timeout(cs, nowts);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
// Triggered when a DHCP renew request has been sent and no reply has been
|
|
|
|
// received within the response wait time. This function is also directly
|
|
|
|
// called by bound_timeout() when it is time to renew a lease before it
|
|
|
|
// expires. Check to see if the lease is still valid, and if it is, send
|
|
|
|
// a unicast DHCP renew packet. If it is not, then change to the REBINDING
|
2011-06-30 12:18:58 +05:30
|
|
|
// state to send broadcast queries.
|
2015-02-14 11:14:21 +05:30
|
|
|
static void renewing_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2011-06-30 12:18:58 +05:30
|
|
|
long long rbt = cs->leaseStartTime + cs->rebindTime * 1000;
|
2015-02-14 15:50:04 +05:30
|
|
|
if (nowts >= rbt) {
|
2011-06-30 09:17:31 +05:30
|
|
|
cs->dhcpState = DS_REBINDING;
|
2011-07-11 21:01:27 +05:30
|
|
|
rebinding_timeout(cs, nowts);
|
2015-02-14 15:50:04 +05:30
|
|
|
return;
|
2011-07-11 21:01:27 +05:30
|
|
|
}
|
2015-02-14 15:50:04 +05:30
|
|
|
if (rbt - nowts < 30000) {
|
|
|
|
dhcp_wake_ts = rbt;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int r = send_renew(cs);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning("%s: Failed to send a renew request packet.",
|
|
|
|
client_config.interface);
|
|
|
|
SUSPEND_IF_NOCARRIER();
|
|
|
|
}
|
|
|
|
dhcp_wake_ts = nowts + ((rbt - nowts) / 2);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2011-06-30 12:18:58 +05:30
|
|
|
// Triggered when a DHCP rebind request has been sent and no reply has been
|
|
|
|
// received within the response wait time. Check to see if the lease is still
|
|
|
|
// valid, and if it is, send a broadcast DHCP renew packet. If it is not, then
|
|
|
|
// change to the SELECTING state to get a new lease.
|
2015-02-14 11:14:21 +05:30
|
|
|
static void rebinding_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2011-06-30 12:18:58 +05:30
|
|
|
long long elt = cs->leaseStartTime + cs->lease * 1000;
|
2015-02-14 15:50:04 +05:30
|
|
|
if (nowts >= elt) {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Lease expired. Searching for a new lease...",
|
|
|
|
client_config.interface);
|
2011-07-12 02:03:57 +05:30
|
|
|
reinit_selecting(cs, 0);
|
2015-02-14 15:50:04 +05:30
|
|
|
return;
|
2011-07-12 02:03:57 +05:30
|
|
|
}
|
2015-02-14 15:50:04 +05:30
|
|
|
if (elt - nowts < 30000) {
|
|
|
|
dhcp_wake_ts = elt;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int r = send_rebind(cs);
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning("%s: Failed to send a rebind request packet.",
|
|
|
|
client_config.interface);
|
|
|
|
SUSPEND_IF_NOCARRIER();
|
|
|
|
}
|
|
|
|
dhcp_wake_ts = nowts + ((elt - nowts) / 2);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 11:14:21 +05:30
|
|
|
static void released_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2014-03-11 05:14:37 +05:30
|
|
|
(void)cs;
|
|
|
|
(void)nowts;
|
2011-07-11 21:01:27 +05:30
|
|
|
dhcp_wake_ts = -1;
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 11:14:21 +05:30
|
|
|
static int validate_serverid(struct client_state_t cs[static 1],
|
|
|
|
struct dhcpmsg packet[static 1],
|
|
|
|
const char typemsg[static 1])
|
2011-07-12 02:03:57 +05:30
|
|
|
{
|
2011-07-26 10:34:59 +05:30
|
|
|
int found;
|
|
|
|
uint32_t sid = get_option_serverid(packet, &found);
|
|
|
|
if (!found) {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Received %s with no server id. Ignoring it.",
|
|
|
|
client_config.interface, typemsg);
|
2011-07-12 02:03:57 +05:30
|
|
|
return 0;
|
|
|
|
}
|
2011-07-26 10:34:59 +05:30
|
|
|
if (cs->serverAddr != sid) {
|
2011-07-12 02:32:32 +05:30
|
|
|
char svrbuf[INET_ADDRSTRLEN];
|
2011-07-26 10:34:59 +05:30
|
|
|
inet_ntop(AF_INET, &(struct in_addr){.s_addr=sid},
|
2011-07-12 02:32:32 +05:30
|
|
|
svrbuf, sizeof svrbuf);
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Received %s with an unexpected server id: %s. Ignoring it.",
|
|
|
|
client_config.interface, typemsg, svrbuf);
|
2011-07-12 02:03:57 +05:30
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-07-06 18:56:07 +05:30
|
|
|
// Can transition to DS_BOUND or DS_SELECTING.
|
2015-02-14 11:14:21 +05:30
|
|
|
static void an_packet(struct client_state_t cs[static 1],
|
|
|
|
struct dhcpmsg packet[static 1], uint8_t msgtype,
|
|
|
|
uint32_t srcaddr)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2015-02-13 09:58:54 +05:30
|
|
|
(void)srcaddr;
|
2011-07-18 20:17:35 +05:30
|
|
|
if (msgtype == DHCPACK) {
|
2011-07-12 02:03:57 +05:30
|
|
|
if (!validate_serverid(cs, packet, "a DHCP ACK"))
|
|
|
|
return;
|
2011-07-26 10:34:59 +05:30
|
|
|
cs->lease = get_option_leasetime(packet);
|
2011-06-30 11:20:50 +05:30
|
|
|
cs->leaseStartTime = curms();
|
2011-07-26 10:34:59 +05:30
|
|
|
if (!cs->lease) {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: No lease time received; assuming 1h.",
|
|
|
|
client_config.interface);
|
2011-06-30 09:17:31 +05:30
|
|
|
cs->lease = 60 * 60;
|
|
|
|
} else {
|
2011-06-30 12:57:57 +05:30
|
|
|
if (cs->lease < 60) {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_warning("Server sent lease of <1m. Forcing lease to 1m.",
|
|
|
|
client_config.interface);
|
2011-06-30 12:57:57 +05:30
|
|
|
cs->lease = 60;
|
|
|
|
}
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
2011-06-30 11:20:50 +05:30
|
|
|
// Always use RFC2131 'default' values. It's not worth validating
|
|
|
|
// the remote server values, if they even exist, for sanity.
|
|
|
|
cs->renewTime = cs->lease >> 1;
|
2011-07-11 17:31:56 +05:30
|
|
|
cs->rebindTime = (cs->lease >> 3) * 0x7; // * 0.875
|
2011-07-11 21:01:27 +05:30
|
|
|
dhcp_wake_ts = cs->leaseStartTime + cs->renewTime * 1000;
|
2011-06-30 09:17:31 +05:30
|
|
|
|
2011-07-06 18:56:07 +05:30
|
|
|
// Only check if we are either in the REQUESTING state, or if we
|
|
|
|
// have received a lease with a different IP than what we had before.
|
|
|
|
if (cs->dhcpState == DS_REQUESTING ||
|
|
|
|
memcmp(&packet->yiaddr, &cs->clientAddr, 4)) {
|
2011-07-12 02:32:32 +05:30
|
|
|
char clibuf[INET_ADDRSTRLEN];
|
|
|
|
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->clientAddr},
|
|
|
|
clibuf, sizeof clibuf);
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Accepted a firm offer for %s. Validating...",
|
|
|
|
client_config.interface, clibuf);
|
2014-04-06 16:03:14 +05:30
|
|
|
if (arp_check(cs, packet) < 0) {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_warning("%s: Failed to make arp socket. Searching for new lease...",
|
|
|
|
client_config.interface);
|
2011-07-06 18:56:07 +05:30
|
|
|
reinit_selecting(cs, 3000);
|
|
|
|
}
|
2011-07-06 21:11:49 +05:30
|
|
|
} else {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Lease refreshed to %u seconds.",
|
|
|
|
client_config.interface, cs->lease);
|
2011-07-06 21:11:49 +05:30
|
|
|
cs->dhcpState = DS_BOUND;
|
|
|
|
arp_set_defense_mode(cs);
|
2014-04-16 10:30:36 +05:30
|
|
|
stop_dhcp_listen(cs);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2011-07-18 20:17:35 +05:30
|
|
|
} else if (msgtype == DHCPNAK) {
|
2011-07-12 02:03:57 +05:30
|
|
|
if (!validate_serverid(cs, packet, "a DHCP NAK"))
|
|
|
|
return;
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Our request was rejected. Searching for a new lease...",
|
|
|
|
client_config.interface);
|
2011-07-05 07:40:14 +05:30
|
|
|
reinit_selecting(cs, 3000);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-14 11:14:21 +05:30
|
|
|
static void selecting_packet(struct client_state_t cs[static 1],
|
|
|
|
struct dhcpmsg packet[static 1], uint8_t msgtype,
|
|
|
|
uint32_t srcaddr)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2011-07-18 20:17:35 +05:30
|
|
|
if (msgtype == DHCPOFFER) {
|
2011-07-26 10:34:59 +05:30
|
|
|
int found;
|
|
|
|
uint32_t sid = get_option_serverid(packet, &found);
|
|
|
|
if (found) {
|
2011-07-12 02:32:32 +05:30
|
|
|
char clibuf[INET_ADDRSTRLEN];
|
|
|
|
char svrbuf[INET_ADDRSTRLEN];
|
2015-02-13 09:58:54 +05:30
|
|
|
char srcbuf[INET_ADDRSTRLEN];
|
2011-07-26 10:34:59 +05:30
|
|
|
cs->serverAddr = sid;
|
2011-06-30 09:17:31 +05:30
|
|
|
cs->xid = packet->xid;
|
2011-07-01 21:07:13 +05:30
|
|
|
cs->clientAddr = packet->yiaddr;
|
2015-02-13 09:58:54 +05:30
|
|
|
cs->srcAddr = srcaddr;
|
2011-06-30 09:17:31 +05:30
|
|
|
cs->dhcpState = DS_REQUESTING;
|
2011-07-11 21:01:27 +05:30
|
|
|
dhcp_wake_ts = curms();
|
2011-07-06 01:14:11 +05:30
|
|
|
num_dhcp_requests = 0;
|
2011-07-12 02:32:32 +05:30
|
|
|
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->clientAddr},
|
|
|
|
clibuf, sizeof clibuf);
|
|
|
|
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->serverAddr},
|
|
|
|
svrbuf, sizeof svrbuf);
|
2015-02-13 09:58:54 +05:30
|
|
|
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->srcAddr},
|
|
|
|
srcbuf, sizeof srcbuf);
|
|
|
|
log_line("%s: Received IP offer: %s from server %s via %s.",
|
|
|
|
client_config.interface, clibuf, svrbuf, srcbuf);
|
2011-06-30 09:17:31 +05:30
|
|
|
} else {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Invalid offer received: it didn't have a server id.",
|
|
|
|
client_config.interface);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Triggered after a DHCP discover packet has been sent and no reply has
|
|
|
|
// been received within the response wait time. If we've not exceeded the
|
|
|
|
// maximum number of discover retransmits, then send another packet and wait
|
|
|
|
// again. Otherwise, background or fail.
|
2015-02-14 11:14:21 +05:30
|
|
|
static void selecting_timeout(struct client_state_t cs[static 1],
|
|
|
|
long long nowts)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2011-07-06 01:14:11 +05:30
|
|
|
if (cs->init && num_dhcp_requests >= 2) {
|
2011-06-30 12:57:57 +05:30
|
|
|
if (client_config.background_if_no_lease) {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: No lease; going to background.",
|
|
|
|
client_config.interface);
|
2011-06-30 12:57:57 +05:30
|
|
|
cs->init = 0;
|
2014-03-13 02:21:10 +05:30
|
|
|
background();
|
2014-03-31 02:51:27 +05:30
|
|
|
} else if (client_config.abort_if_no_lease)
|
2014-04-16 00:54:22 +05:30
|
|
|
suicide("%s: No lease; failing.", client_config.interface);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
2011-07-06 01:14:11 +05:30
|
|
|
if (num_dhcp_requests == 0)
|
2014-03-13 01:11:34 +05:30
|
|
|
cs->xid = nk_random_u32(&cs->rnd32_state);
|
2015-02-14 15:50:04 +05:30
|
|
|
int r = send_discover(cs);
|
|
|
|
if (r < 0) {
|
2014-04-16 03:29:15 +05:30
|
|
|
log_warning("%s: Failed to send a discover request packet.",
|
|
|
|
client_config.interface);
|
2015-02-14 15:50:04 +05:30
|
|
|
SUSPEND_IF_NOCARRIER();
|
|
|
|
}
|
2014-03-22 11:38:23 +05:30
|
|
|
dhcp_wake_ts = nowts + delay_timeout(cs, num_dhcp_requests);
|
2011-07-06 01:14:11 +05:30
|
|
|
num_dhcp_requests++;
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
static void xmit_release(struct client_state_t cs[static 1])
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2011-07-12 02:32:32 +05:30
|
|
|
char clibuf[INET_ADDRSTRLEN];
|
|
|
|
char svrbuf[INET_ADDRSTRLEN];
|
|
|
|
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->clientAddr},
|
|
|
|
clibuf, sizeof clibuf);
|
|
|
|
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->serverAddr},
|
|
|
|
svrbuf, sizeof svrbuf);
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Unicasting a release of %s to %s.", client_config.interface,
|
|
|
|
clibuf, svrbuf);
|
2015-02-14 15:50:04 +05:30
|
|
|
int r = send_release(cs);
|
|
|
|
if (r < 0) {
|
2014-04-16 03:29:15 +05:30
|
|
|
log_warning("%s: Failed to send a release request packet.",
|
|
|
|
client_config.interface);
|
2015-02-14 15:50:04 +05:30
|
|
|
SUSPEND_IF_NOCARRIER();
|
|
|
|
}
|
2011-07-06 03:59:06 +05:30
|
|
|
print_release(cs);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
static void print_release(struct client_state_t cs[static 1])
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2015-02-14 11:14:21 +05:30
|
|
|
log_line("%s: ndhc going to sleep. Wake it by sending a SIGUSR1.",
|
|
|
|
client_config.interface);
|
2011-07-06 03:59:06 +05:30
|
|
|
set_released(cs);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
static void frenew(struct client_state_t cs[static 1])
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2011-07-06 03:48:57 +05:30
|
|
|
if (cs->dhcpState == DS_BOUND) {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Forcing a DHCP renew...", client_config.interface);
|
2011-07-06 03:48:57 +05:30
|
|
|
cs->dhcpState = DS_RENEWING;
|
2014-04-16 10:30:36 +05:30
|
|
|
start_dhcp_listen(cs);
|
2015-02-14 15:50:04 +05:30
|
|
|
int r = send_renew(cs);
|
|
|
|
if (r < 0) {
|
2014-04-16 03:29:15 +05:30
|
|
|
log_warning("%s: Failed to send a renew request packet.",
|
|
|
|
client_config.interface);
|
2015-02-14 15:50:04 +05:30
|
|
|
SUSPEND_IF_NOCARRIER();
|
|
|
|
}
|
2011-07-06 03:48:57 +05:30
|
|
|
} else if (cs->dhcpState == DS_RELEASED)
|
|
|
|
reinit_selecting(cs, 0);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
void ifup_action(struct client_state_t cs[static 1])
|
2011-07-05 07:40:14 +05:30
|
|
|
{
|
2011-07-06 01:10:57 +05:30
|
|
|
// If we have a lease, check to see if our gateway is still valid via ARP.
|
2011-07-05 07:40:14 +05:30
|
|
|
// If it fails, state -> SELECTING.
|
2011-07-06 21:02:22 +05:30
|
|
|
if (cs->routerAddr && (cs->dhcpState == DS_BOUND ||
|
|
|
|
cs->dhcpState == DS_RENEWING ||
|
|
|
|
cs->dhcpState == DS_REBINDING)) {
|
2015-02-14 16:07:06 +05:30
|
|
|
int r = arp_gw_check(cs);
|
|
|
|
if (r >= 0) {
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Interface is back. Revalidating lease...",
|
2011-07-18 19:59:36 +05:30
|
|
|
client_config.interface);
|
2011-07-06 21:02:22 +05:30
|
|
|
return;
|
2015-02-14 16:07:06 +05:30
|
|
|
} else {
|
|
|
|
SUSPEND_IF_NOCARRIER();
|
2015-02-14 11:14:21 +05:30
|
|
|
log_warning("%s: arp_gw_check could not make arp socket.",
|
|
|
|
client_config.interface);
|
2015-02-14 16:07:06 +05:30
|
|
|
}
|
2011-07-06 01:10:57 +05:30
|
|
|
}
|
2011-07-06 21:02:22 +05:30
|
|
|
if (cs->dhcpState == DS_SELECTING)
|
|
|
|
return;
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Interface is back. Searching for new lease...",
|
2011-07-12 02:03:57 +05:30
|
|
|
client_config.interface);
|
2011-07-06 21:02:22 +05:30
|
|
|
reinit_selecting(cs, 0);
|
2011-07-05 07:40:14 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
void ifdown_action(struct client_state_t cs[static 1])
|
2011-07-05 07:40:14 +05:30
|
|
|
{
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Interface shut down. Going to sleep.",
|
|
|
|
client_config.interface);
|
2011-07-06 03:59:06 +05:30
|
|
|
set_released(cs);
|
2011-07-05 07:40:14 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
void ifnocarrier_action(struct client_state_t cs[static 1])
|
2011-07-05 07:40:14 +05:30
|
|
|
{
|
2014-03-11 05:14:37 +05:30
|
|
|
(void)cs;
|
2014-04-16 00:54:22 +05:30
|
|
|
log_line("%s: Carrier down.", client_config.interface);
|
2011-07-05 07:40:14 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 09:44:08 +05:30
|
|
|
void packet_action(struct client_state_t cs[static 1],
|
|
|
|
struct dhcpmsg packet[static 1], uint8_t msgtype,
|
|
|
|
uint32_t srcaddr)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
|
|
|
if (dhcp_states[cs->dhcpState].packet_fn)
|
2015-02-13 09:58:54 +05:30
|
|
|
dhcp_states[cs->dhcpState].packet_fn(cs, packet, msgtype, srcaddr);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
void timeout_action(struct client_state_t cs[static 1], long long nowts)
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
2011-07-11 20:09:36 +05:30
|
|
|
handle_arp_timeout(cs, nowts);
|
2011-06-30 09:17:31 +05:30
|
|
|
if (dhcp_states[cs->dhcpState].timeout_fn)
|
2011-07-11 18:29:50 +05:30
|
|
|
dhcp_states[cs->dhcpState].timeout_fn(cs, nowts);
|
2011-06-30 09:17:31 +05:30
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
void force_renew_action(struct client_state_t cs[static 1])
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
|
|
|
if (dhcp_states[cs->dhcpState].force_renew_fn)
|
|
|
|
dhcp_states[cs->dhcpState].force_renew_fn(cs);
|
|
|
|
}
|
|
|
|
|
2015-02-14 08:59:03 +05:30
|
|
|
void force_release_action(struct client_state_t cs[static 1])
|
2011-06-30 09:17:31 +05:30
|
|
|
{
|
|
|
|
if (dhcp_states[cs->dhcpState].force_release_fn)
|
|
|
|
dhcp_states[cs->dhcpState].force_release_fn(cs);
|
|
|
|
}
|
|
|
|
|
2011-07-11 21:01:27 +05:30
|
|
|
long long dhcp_get_wake_ts(void)
|
|
|
|
{
|
|
|
|
return dhcp_wake_ts;
|
|
|
|
}
|
|
|
|
|