static void
usage(void)
{
- printf("usage: "PACKAGE" [-dknpqxADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n"
+ printf("usage: "PACKAGE" [-dknpqxyADEGHKLOTV] [-c script] [-f file ] [-h hostname]\n"
" [-i classID ] [-l leasetime] [-m metric] [-o option] [-r ipaddr]\n"
" [-s ipaddr] [-t timeout] [-u userclass] [-F none|ptr|both]\n"
" [-I clientID] [-C hookscript] [-Q option] [-X ipaddr] <interface>\n");
syslog(LOG_ERR, "%s: failed to renew, attmepting to rebind",
iface->name);
- iface->state->state = DHS_REBINDING;
+ iface->state->state = DHS_REBIND;
delete_timeout(send_renew, iface);
iface->state->lease.server.s_addr = 0;
send_rebind(iface);
start_expire(void *arg)
{
struct interface *iface = arg;
- int ll = IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr));
+
+ if (iface->addr.s_addr == 0) {
+ /* We failed to reboot, so enter discovery. */
+ iface->state->interval = 0;
+ start_discover(iface);
+ return;
+ }
syslog(LOG_ERR, "%s: lease expired", iface->name);
delete_timeout(NULL, iface);
drop_config(iface, "EXPIRE");
iface->state->interval = 0;
if (iface->carrier != LINK_DOWN) {
- if (ll)
+ if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)))
start_interface(iface);
else
start_ipv4ll(iface);
}
}
- if (type == DHCP_OFFER && state->state == DHS_DISCOVERING) {
+ if (type == DHCP_OFFER && state->state == DHS_DISCOVER) {
+ lease->frominfo = 0;
lease->addr.s_addr = dhcp->yiaddr;
get_option_addr(&lease->server.s_addr, dhcp, DHO_SERVERID);
log_dhcp(LOG_INFO, "offered", iface, dhcp);
* then we can't ARP for duplicate detection. */
addr.s_addr = state->offer->yiaddr;
if (!has_address(iface->name, &addr, NULL)) {
- state->state = DHS_PROBING;
state->claims = 0;
state->probes = 0;
state->conflicts = 0;
return;
}
}
- state->state = DHS_REQUESTING;
+ state->state = DHS_REQUEST;
send_request(iface);
return;
}
*dhcpp = NULL;
/* Delete all timeouts for this interface. */
delete_timeout(NULL, iface);
+ lease->frominfo = 0;
bind_interface(iface);
}
struct interface *iface = arg;
struct if_options *ifo = iface->state->options;
- iface->state->state = DHS_DISCOVERING;
+ iface->state->state = DHS_DISCOVER;
iface->state->xid = arc4random();
open_sockets(iface);
delete_timeout(NULL, iface);
syslog(LOG_INFO, "%s: renewing lease of %s",
iface->name, inet_ntoa(iface->state->lease.addr));
- iface->state->state = DHS_RENEWING;
+ iface->state->state = DHS_RENEW;
iface->state->xid = arc4random();
open_sockets(iface);
send_renew(iface);
}
+static void
+start_timeout(void *arg)
+{
+ struct interface *iface = arg;
+
+ bind_interface(iface);
+ iface->state->interval = 0;
+ start_discover(iface);
+}
+
void
start_reboot(struct interface *iface)
{
syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
return;
}
+ if (ifo->reboot == 0) {
+ start_discover(iface);
+ return;
+ }
+ if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr))) {
+ if (ifo->options & DHCPCD_IPV4LL) {
+ iface->state->claims = 0;
+ send_arp_announce(iface);
+ } else
+ start_discover(iface);
+ return;
+ }
syslog(LOG_INFO, "%s: rebinding lease of %s",
iface->name, inet_ntoa(iface->state->lease.addr));
- iface->state->state = DHS_REBINDING;
+ iface->state->state = DHS_REBOOT;
iface->state->xid = arc4random();
iface->state->lease.server.s_addr = 0;
delete_timeout(NULL, iface);
- add_timeout_sec(ifo->timeout, start_expire, iface);
+ if (ifo->options & DHCPCD_LASTLEASE && iface->state->lease.frominfo)
+ add_timeout_sec(ifo->reboot, start_timeout, iface);
+ else
+ add_timeout_sec(ifo->reboot, start_expire, iface);
open_sockets(iface);
- send_rebind(iface);
+ if (ifo->options & DHCPCD_ARP)
+ send_arp_probe(iface);
+ else
+ send_request(iface);
}
static void
start_interface(void *arg)
{
struct interface *iface = arg;
+ struct stat st;
+ struct timeval now;
+ uint32_t l;
if (iface->carrier == LINK_DOWN) {
syslog(LOG_INFO, "%s: waiting for carrier", iface->name);
}
iface->start_uptime = uptime();
- if (!iface->state->lease.addr.s_addr)
+ iface->state->offer = read_lease(iface);
+/* if (iface->state->offer) {
+ if (IN_LINKLOCAL(htonl(iface->state->offer->yiaddr))) {
+ free(iface->state->offer);
+ iface->state->offer = NULL;
+ }
+ } */
+ if (iface->state->offer) {
+ get_lease(&iface->state->lease, iface->state->offer);
+ iface->state->lease.frominfo = 1;
+ /* Offset lease times and check expiry */
+ if (stat(iface->leasefile, &st) == 0 &&
+ get_option_uint32(&l, iface->state->offer, DHO_LEASETIME) == 0)
+ {
+ gettimeofday(&now, NULL);
+ if ((time_t)l < now.tv_sec - st.st_mtime) {
+ free(iface->state->offer);
+ iface->state->offer = NULL;
+ } else {
+ l = now.tv_sec - st.st_mtime;
+ iface->state->lease.leasetime -= l;
+ iface->state->lease.renewaltime -= l;
+ iface->state->lease.rebindtime -= l;
+ }
+ }
+ }
+ if (!iface->state->offer)
start_discover(iface);
- else if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)))
+ else if (IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)) &&
+ iface->state->options->options & DHCPCD_IPV4LL)
start_ipv4ll(iface);
else
start_reboot(iface);
{
struct interface *iface, *ifl;
int sig = signal_read();
- int do_reboot = 0, do_release = 0;
+ int do_release = 0;
switch (sig) {
case SIGINT:
break;
case SIGALRM:
syslog(LOG_INFO, "received SIGALRM, rebinding lease");
- do_reboot = 1;
+ for (iface = ifaces; iface; iface = iface->next)
+ start_reboot(iface);
+ return;
case SIGHUP:
syslog(LOG_INFO, "received SIGHUP, releasing lease");
do_release = 1;
break;
default:
- syslog (LOG_ERR,
- "received signal %d, but don't know what to do with it",
- sig);
+ syslog(LOG_ERR,
+ "received signal %d, but don't know what to do with it",
+ sig);
return;
}
ifl = iface;
if (!ifl)
break;
- if (do_reboot)
- start_reboot(ifl);
- else {
- if (do_release)
- send_release(ifl);
- if (!(ifl->state->options->options & DHCPCD_PERSISTENT))
- drop_config(ifl, do_release ? "RELEASE" : "STOP");
- }
+ if (do_release)
+ send_release(ifl);
+ if (!(ifl->state->options->options & DHCPCD_PERSISTENT))
+ drop_config(ifl, do_release ? "RELEASE" : "STOP");
}
exit(EXIT_FAILURE);
}
unlink(pidfile);
exit(EXIT_FAILURE);
}
+ if (sig == SIGALRM)
+ exit(EXIT_SUCCESS);
/* Spin until it exits */
syslog(LOG_INFO, "waiting for pid %d to exit", pid);
ts.tv_sec = 0;
/* Don't set any optional arguments here so we retain POSIX
* compatibility with getopt */
-#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xABC:DEF:GI:KLO:Q:TVX:"
+#define OPTS "bc:df:h:i:kl:m:no:pqr:s:t:u:v:xy:z:ABC:DEF:GI:KLO:Q:TVX:Z:"
const struct option cf_options[] = {
{"background", no_argument, NULL, 'b'},
{"userclass", required_argument, NULL, 'u'},
{"vendor", required_argument, NULL, 'v'},
{"exit", no_argument, NULL, 'x'},
+ {"reboot", required_argument, NULL, 'y'},
{"allowinterfaces", required_argument, NULL, 'z'},
{"noarp", no_argument, NULL, 'A'},
{"nobackground", no_argument, NULL, 'B'},
case 't':
ifo->timeout = atoint(arg);
if (ifo->timeout < 0) {
- syslog (LOG_ERR, "timeout must be a positive value");
+ syslog(LOG_ERR, "timeout must be a positive value");
return -1;
}
break;
ifo->vendor[0] += s + 2;
}
break;
+ case 'y':
+ ifo->reboot = atoint(arg);
+ if (ifo->reboot < 0) {
+ syslog(LOG_ERR, "reboot must be a positive value");
+ return -1;
+ }
+ break;
case 'z':
/* We only set this if we haven't got any interfaces */
if (!ifaces)
ifo->options |= DHCPCD_CLIENTID | DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
ifo->options |= DHCPCD_ARP | DHCPCD_IPV4LL | DHCPCD_LINK;
ifo->timeout = DEFAULT_TIMEOUT;
+ ifo->reboot = DEFAULT_REBOOT;
ifo->metric = -1;
gethostname(ifo->hostname + 1, sizeof(ifo->hostname));
if (strcmp(ifo->hostname + 1, "(none)") == 0 ||
}
}
- syslog(LOG_INFO, "%s: probing for an IPv4LL address", iface->name);
- delete_timeout(NULL, iface);
- iface->state->state = DHS_PROBING;
- free(iface->state->offer);
- iface->state->offer = make_ipv4ll_lease(0);
+ /* We maybe rebooting of an IPv4LL address. */
+ if (!iface->state->offer ||
+ !IN_LINKLOCAL(htonl(iface->state->offer->yiaddr)))
+ {
+ syslog(LOG_INFO, "%s: probing for an IPv4LL address", iface->name);
+ delete_timeout(NULL, iface);
+ free(iface->state->offer);
+ iface->state->offer = make_ipv4ll_lease(0);
+ iface->state->lease.frominfo = 0;
+ }
send_arp_probe(iface);
}
time_t up;
if (iface->state->fail.s_addr == iface->state->lease.addr.s_addr) {
- if (iface->state->state == DHS_PROBING)
+ up = uptime();
+ if (iface->state->defend + DEFEND_INTERVAL > up) {
drop_config(iface, "EXPIRE");
- else {
- up = uptime();
- if (iface->state->defend + DEFEND_INTERVAL > up) {
- drop_config(iface, "EXPIRE");
- iface->state->conflicts = -1;
- } else {
- iface->state->defend = up;
- return;
- }
+ iface->state->conflicts = -1;
+ } else {
+ iface->state->defend = up;
+ return;
}
}
close_sockets(iface);
+ free(iface->state->offer);
+ iface->state->offer = NULL;
if (++iface->state->conflicts > MAX_CONFLICTS) {
syslog(LOG_ERR, "%s: failed to acquire an IPv4LL address",
iface->name);
iface->state->interval = RATE_LIMIT_INTERVAL / 2;
start_discover(iface);
- } else
+ } else {
add_timeout_sec(PROBE_WAIT, start_ipv4ll, iface);
+ }
}