aboutsummaryrefslogtreecommitdiffstats
path: root/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'dhcp.c')
-rw-r--r--dhcp.c381
1 files changed, 249 insertions, 132 deletions
diff --git a/dhcp.c b/dhcp.c
index 1854cf2..bd6c719 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -1,6 +1,6 @@
/*
* dhcpcd - DHCP client daemon
- * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
* All rights reserved
* Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,7 @@
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include "config.h"
@@ -57,7 +58,7 @@
/* Our aggregate option buffer.
* We ONLY use this when options are split, which for most purposes is
* practically never. See RFC3396 for details. */
-static uint8_t *dhcp_opt_buffer = NULL;
+static uint8_t *opt_buffer;
struct dhcp_opt {
uint8_t option;
@@ -67,9 +68,10 @@ struct dhcp_opt {
static const struct dhcp_opt const dhcp_opts[] = {
{ 1, IPV4 | REQUEST, "subnet_mask" },
- /* RFC 3442 states that the CSR has to come before all other routes.
- * For completeness, we also specify static routes, then routers. */
- { 121, RFC3442 | REQUEST, "classless_static_routes" },
+ /* RFC 3442 states that the CSR has to come before all other
+ * routes. For completeness, we also specify static routes,
+ * then routers. */
+ { 121, RFC3442, "classless_static_routes" },
{ 249, RFC3442, "ms_classless_static_routes" },
{ 33, IPV4 | ARRAY | REQUEST, "static_routes" },
{ 3, IPV4 | ARRAY | REQUEST, "routers" },
@@ -160,22 +162,52 @@ static const struct dhcp_opt const dhcp_opts[] = {
{ 0, 0, NULL }
};
+static const char *if_params[] = {
+ "interface",
+ "reason",
+ "pid",
+ "ifmetric",
+ "ifwireless",
+ "ifflags",
+ "profile",
+ "interface_order",
+ NULL
+};
+
+static const char *dhcp_params[] = {
+ "ip_address",
+ "subnet_cidr",
+ "network_number",
+ "ssid",
+ "filename",
+ "server_name",
+ NULL
+};
+
void
print_options(void)
{
const struct dhcp_opt *opt;
+ const char **p;
+
+ for (p = if_params; *p; p++)
+ printf(" - %s\n", *p);
+
+ for (p = dhcp_params; *p; p++)
+ printf(" %s\n", *p);
for (opt = dhcp_opts; opt->option; opt++)
if (opt->var)
printf("%03d %s\n", opt->option, opt->var);
}
-int make_option_mask(uint8_t *mask, char **opts, int add)
+int make_option_mask(uint8_t *mask, const char *opts, int add)
{
- char *token, *p = *opts, *t;
+ char *token, *o, *p, *t;
const struct dhcp_opt *opt;
int match, n;
+ o = p = xstrdup(opts);
while ((token = strsep(&p, ", "))) {
if (*token == '\0')
continue;
@@ -192,22 +224,28 @@ int make_option_mask(uint8_t *mask, char **opts, int add)
if (opt->option == n)
match = 1;
}
- if (match) {
- if (add == 1)
+ if (match) {
+ if (add == 2 && !(opt->type & IPV4)) {
+ free(o);
+ errno = EINVAL;
+ return -1;
+ }
+ if (add == 1 || add == 2)
add_option_mask(mask,
- opt->option);
+ opt->option);
else
del_option_mask(mask,
- opt->option);
+ opt->option);
break;
}
}
if (!opt->option) {
- *opts = token;
+ free(o);
errno = ENOENT;
return -1;
}
}
+ free(o);
return 0;
}
@@ -227,7 +265,9 @@ valid_length(uint8_t option, int dl, int *type)
if (type)
*type = opt->type;
- if (opt->type == 0 || opt->type & STRING || opt->type & RFC3442)
+ if (opt->type == 0 ||
+ opt->type & STRING ||
+ opt->type & RFC3442)
return 0;
sz = 0;
@@ -246,11 +286,13 @@ valid_length(uint8_t option, int dl, int *type)
return 0;
}
+#ifdef DEBUG_MEMORY
static void
free_option_buffer(void)
{
- free(dhcp_opt_buffer);
+ free(opt_buffer);
}
+#endif
#define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL, NULL)
static const uint8_t *
@@ -269,12 +311,14 @@ get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
o = *p++;
if (o == opt) {
if (op) {
- if (!dhcp_opt_buffer) {
- dhcp_opt_buffer = xmalloc(sizeof(struct dhcp_message));
+ if (!opt_buffer) {
+ opt_buffer = xmalloc(sizeof(*dhcp));
+#ifdef DEBUG_MEMORY
atexit(free_option_buffer);
+#endif
}
if (!bp)
- bp = dhcp_opt_buffer;
+ bp = opt_buffer;
memcpy(bp, op, ol);
bp += ol;
}
@@ -318,7 +362,7 @@ exit:
*len = bl;
if (bp) {
memcpy(bp, op, ol);
- return (const uint8_t *)&dhcp_opt_buffer;
+ return (const uint8_t *)opt_buffer;
}
if (op)
return op;
@@ -371,12 +415,13 @@ get_option_uint8(uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
if (!p)
return -1;
- *i = *(p);
+ if (i)
+ *i = *(p);
return 0;
}
/* Decode an RFC3397 DNS search order option into a space
- * seperated string. Returns length of string (including
+ * separated string. Returns length of string (including
* terminating zero) or zero on error. out may be NULL
* to just determine output length. */
static ssize_t
@@ -442,10 +487,8 @@ static ssize_t
decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p)
{
const uint8_t *e;
- ssize_t bytes = 0;
- ssize_t b;
+ ssize_t b, bytes = 0, ocets;
uint8_t cidr;
- uint8_t ocets;
struct in_addr addr;
char *o = out;
@@ -479,7 +522,7 @@ decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p)
/* If we have ocets then we have a destination and netmask */
if (ocets > 0) {
addr.s_addr = 0;
- memcpy(&addr.s_addr, p, (size_t)ocets);
+ memcpy(&addr.s_addr, p, ocets);
b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr);
p += ocets;
} else
@@ -506,7 +549,7 @@ decode_rfc3442_rt(int dl, const uint8_t *data)
const uint8_t *p = data;
const uint8_t *e;
uint8_t cidr;
- uint8_t ocets;
+ size_t ocets;
struct rt *routes = NULL;
struct rt *rt = NULL;
@@ -534,15 +577,9 @@ decode_rfc3442_rt(int dl, const uint8_t *data)
ocets = (cidr + 7) / 8;
/* If we have ocets then we have a destination and netmask */
if (ocets > 0) {
- memcpy(&rt->dest.s_addr, p, (size_t)ocets);
- memset(&rt->net.s_addr, 255, (size_t)ocets - 1);
- memset((uint8_t *)&rt->net.s_addr +
- (ocets - 1),
- (256 - (1 << (32 - cidr) % 8)), 1);
+ memcpy(&rt->dest.s_addr, p, ocets);
p += ocets;
- } else {
- rt->dest.s_addr = 0;
- rt->net.s_addr = 0;
+ rt->net.s_addr = htonl(~0U << (32 - cidr));
}
/* Finally, snag the router */
@@ -664,7 +701,8 @@ route_netmask(uint32_t ip_in)
* If we have a CSR then we only use that.
* Otherwise we add static routes and then routers. */
struct rt *
-get_option_routes(const struct dhcp_message *dhcp)
+get_option_routes(const struct dhcp_message *dhcp,
+ const char *ifname, int *opts)
{
const uint8_t *p;
const uint8_t *e;
@@ -679,8 +717,13 @@ get_option_routes(const struct dhcp_message *dhcp)
p = get_option(dhcp, DHO_MSCSR, &len, NULL);
if (p) {
routes = decode_rfc3442_rt(len, p);
- if (routes)
+ if (routes && !(*opts & DHCPCD_CSR_WARNED)) {
+ syslog(LOG_DEBUG,
+ "%s: using Classless Static Routes (RFC3442)",
+ ifname);
+ *opts |= DHCPCD_CSR_WARNED;
return routes;
+ }
}
/* OK, get our static routes first. */
@@ -747,17 +790,42 @@ encode_rfc1035(const char *src, uint8_t *dst)
return p - dst;
}
-#define PUTADDR(_type, _val) \
-{ \
- *p++ = _type; \
- *p++ = 4; \
- memcpy(p, &_val.s_addr, 4); \
- p += 4; \
+#define PUTADDR(_type, _val) \
+ { \
+ *p++ = _type; \
+ *p++ = 4; \
+ memcpy(p, &_val.s_addr, 4); \
+ p += 4; \
+ }
+
+int
+dhcp_message_add_addr(struct dhcp_message *dhcp,
+ uint8_t type, struct in_addr addr)
+{
+ uint8_t *p;
+ size_t len;
+
+ p = dhcp->options;
+ while (*p != DHO_END) {
+ p++;
+ p += *p + 1;
+ }
+
+ len = p - (uint8_t *)dhcp;
+ if (len + 6 > sizeof(*dhcp)) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ PUTADDR(type, addr);
+ *p = DHO_END;
+ return 0;
}
+
ssize_t
make_message(struct dhcp_message **message,
- const struct interface *iface, const struct dhcp_lease *lease,
- uint32_t xid, uint8_t type, const struct options *options)
+ const struct interface *iface,
+ uint8_t type)
{
struct dhcp_message *dhcp;
uint8_t *m, *lp, *p;
@@ -765,27 +833,27 @@ make_message(struct dhcp_message **message,
time_t up = uptime() - iface->start_uptime;
uint32_t ul;
uint16_t sz;
- const struct dhcp_opt *opt;
size_t len;
const char *hp;
+ const struct dhcp_opt *opt;
+ const struct if_options *ifo = iface->state->options;
+ const struct dhcp_lease *lease = &iface->state->lease;
+ printf("%s: Start\n", __func__);
dhcp = xzalloc(sizeof (*dhcp));
m = (uint8_t *)dhcp;
p = dhcp->options;
- if ((type == DHCP_INFORM ||
- type == DHCP_RELEASE ||
- type == DHCP_REQUEST) &&
- !IN_LINKLOCAL(ntohl(iface->addr.s_addr)))
+ if ((type == DHCP_INFORM || type == DHCP_RELEASE ||
+ (type == DHCP_REQUEST &&
+ iface->net.s_addr == lease->net.s_addr &&
+ (iface->state->new == NULL ||
+ iface->state->new->cookie == htonl(MAGIC_COOKIE)))))
{
dhcp->ciaddr = iface->addr.s_addr;
- /* Just incase we haven't actually configured the address yet */
+ /* In-case we haven't actually configured the address yet */
if (type == DHCP_INFORM && iface->addr.s_addr == 0)
dhcp->ciaddr = lease->addr.s_addr;
- /* Zero the address if we're currently on a different subnet */
- if (type == DHCP_REQUEST &&
- iface->net.s_addr != lease->net.s_addr)
- dhcp->ciaddr = 0;
}
dhcp->op = DHCP_BOOTREQUEST;
@@ -793,25 +861,24 @@ make_message(struct dhcp_message **message,
switch (iface->family) {
case ARPHRD_ETHER:
case ARPHRD_IEEE802:
- dhcp->hwlen = ETHER_ADDR_LEN;
- memcpy(&dhcp->chaddr, &iface->hwaddr, ETHER_ADDR_LEN);
- break;
- case ARPHRD_IEEE1394:
- case ARPHRD_INFINIBAND:
- dhcp->hwlen = 0;
- if (dhcp->ciaddr == 0 &&
- type != DHCP_DECLINE && type != DHCP_RELEASE)
- dhcp->flags = htons(BROADCAST_FLAG);
+ dhcp->hwlen = iface->hwlen;
+ memcpy(&dhcp->chaddr, &iface->hwaddr, iface->hwlen);
break;
}
+ if (ifo->options & DHCPCD_BROADCAST &&
+ dhcp->ciaddr == 0 &&
+ type != DHCP_DECLINE &&
+ type != DHCP_RELEASE)
+ dhcp->flags = htons(BROADCAST_FLAG);
+
if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
if (up < 0 || up > (time_t)UINT16_MAX)
dhcp->secs = htons((uint16_t)UINT16_MAX);
else
dhcp->secs = htons(up);
}
- dhcp->xid = xid;
+ dhcp->xid = iface->state->xid;
dhcp->cookie = htonl(MAGIC_COOKIE);
*p++ = DHO_MESSAGETYPE;
@@ -824,16 +891,20 @@ make_message(struct dhcp_message **message,
p += iface->clientid[0] + 1;
}
- if (lease->addr.s_addr && !IN_LINKLOCAL(htonl(lease->addr.s_addr))) {
+ if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) {
if (type == DHCP_DECLINE ||
- type == DHCP_DISCOVER ||
(type == DHCP_REQUEST &&
- lease->addr.s_addr != iface->addr.s_addr))
+ lease->addr.s_addr != iface->addr.s_addr))
{
PUTADDR(DHO_IPADDRESS, lease->addr);
if (lease->server.s_addr)
PUTADDR(DHO_SERVERID, lease->server);
}
+
+ if (type == DHCP_RELEASE) {
+ if (lease->server.s_addr)
+ PUTADDR(DHO_SERVERID, lease->server);
+ }
}
if (type == DHCP_DECLINE) {
@@ -844,10 +915,8 @@ make_message(struct dhcp_message **message,
p += len;
}
- if (type == DHCP_RELEASE) {
- if (lease->server.s_addr)
- PUTADDR(DHO_SERVERID, lease->server);
- }
+ if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST)
+ PUTADDR(DHO_IPADDRESS, ifo->req_addr);
if (type == DHCP_DISCOVER ||
type == DHCP_INFORM ||
@@ -859,29 +928,35 @@ make_message(struct dhcp_message **message,
if (sz < MTU_MIN) {
if (set_mtu(iface->name, MTU_MIN) == 0)
sz = MTU_MIN;
+ } else if (sz > MTU_MAX) {
+ /* Even though our MTU could be greater than
+ * MTU_MAX (1500) dhcpcd does not presently
+ * handle DHCP packets any bigger. */
+ sz = MTU_MAX;
}
sz = htons(sz);
memcpy(p, &sz, 2);
p += 2;
- if (options->userclass[0]) {
+ if (ifo->userclass[0]) {
*p++ = DHO_USERCLASS;
- memcpy(p, options->userclass, options->userclass[0] + 1);
- p += options->userclass[0] + 1;
+ memcpy(p, ifo->userclass, ifo->userclass[0] + 1);
+ p += ifo->userclass[0] + 1;
}
- if (options->vendorclassid[0]) {
+ if (ifo->vendorclassid[0]) {
*p++ = DHO_VENDORCLASSID;
- memcpy(p, options->vendorclassid,
- options->vendorclassid[0] + 1);
- p += options->vendorclassid[0] + 1;
+ memcpy(p, ifo->vendorclassid,
+ ifo->vendorclassid[0] + 1);
+ p += ifo->vendorclassid[0] + 1;
}
+
if (type != DHCP_INFORM) {
- if (options->leasetime != 0) {
+ if (ifo->leasetime != 0) {
*p++ = DHO_LEASETIME;
*p++ = 4;
- ul = htonl(options->leasetime);
+ ul = htonl(ifo->leasetime);
memcpy(p, &ul, 4);
p += 4;
}
@@ -891,18 +966,18 @@ make_message(struct dhcp_message **message,
* upto the first dot (the short hostname) as otherwise
* confuses some DHCP servers when updating DNS.
* The FQDN option should be used if a FQDN is required. */
- if (options->hostname[0]) {
+ if (ifo->options & DHCPCD_HOSTNAME && ifo->hostname[0]) {
*p++ = DHO_HOSTNAME;
- hp = strchr(options->hostname, '.');
+ hp = strchr(ifo->hostname, '.');
if (hp)
- len = hp - options->hostname;
+ len = hp - ifo->hostname;
else
- len = strlen(options->hostname);
+ len = strlen(ifo->hostname);
*p++ = len;
- memcpy(p, options->hostname, len);
+ memcpy(p, ifo->hostname, len);
p += len;
}
- if (options->fqdn != FQDN_DISABLE) {
+ if (ifo->fqdn != FQDN_DISABLE && ifo->hostname[0]) {
/* IETF DHC-FQDN option (81), RFC4702 */
*p++ = DHO_FQDN;
lp = p;
@@ -917,19 +992,19 @@ make_message(struct dhcp_message **message,
* N: 1 => Client requests Server to not
* update DNS
*/
- *p++ = (options->fqdn & 0x09) | 0x04;
+ *p++ = (ifo->fqdn & 0x09) | 0x04;
*p++ = 0; /* from server for PTR RR */
*p++ = 0; /* from server for A RR if S=1 */
- ul = encode_rfc1035(options->hostname, p);
+ ul = encode_rfc1035(ifo->hostname, p);
*lp += ul;
p += ul;
}
/* vendor is already encoded correctly, so just add it */
- if (options->vendor[0]) {
+ if (ifo->vendor[0]) {
*p++ = DHO_VENDOR;
- memcpy(p, options->vendor, options->vendor[0] + 1);
- p += options->vendor[0] + 1;
+ memcpy(p, ifo->vendor, ifo->vendor[0] + 1);
+ p += ifo->vendor[0] + 1;
}
*p++ = DHO_PARAMETERREQUESTLIST;
@@ -937,15 +1012,12 @@ make_message(struct dhcp_message **message,
*p++ = 0;
for (opt = dhcp_opts; opt->option; opt++) {
if (!(opt->type & REQUEST ||
- has_option_mask(options->requestmask, opt->option)))
+ has_option_mask(ifo->requestmask, opt->option)))
+ continue;
+ if (type == DHCP_INFORM &&
+ (opt->option == DHO_RENEWALTIME ||
+ opt->option == DHO_REBINDTIME))
continue;
- switch (opt->option) {
- case DHO_RENEWALTIME: /* FALLTHROUGH */
- case DHO_REBINDTIME:
- if (type == DHCP_INFORM)
- continue;
- break;
- }
*p++ = opt->option;
}
*n_params = p - n_params - 1;
@@ -974,16 +1046,20 @@ write_lease(const struct interface *iface, const struct dhcp_message *dhcp)
uint8_t l;
uint8_t o = 0;
- fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0400);
-#ifdef ANDROID
- if (fd == -1 && errno == EACCES) {
- /* the lease file might have been created when dhcpcd was running as root */
+ /* We don't write BOOTP leases */
+ if (is_bootp(dhcp)) {
unlink(iface->leasefile);
- fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0400);
+ return 0;
}
-#endif
- if (fd == -1)
+
+ syslog(LOG_DEBUG, "%s: writing lease `%s'",
+ iface->name, iface->leasefile);
+
+ fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0444);
+ if (fd == -1) {
+ syslog(LOG_ERR, "%s: open: %m", iface->name);
return -1;
+ }
/* Only write as much as we need */
while (p < e) {
@@ -1011,8 +1087,14 @@ read_lease(const struct interface *iface)
ssize_t bytes;
fd = open(iface->leasefile, O_RDONLY);
- if (fd == -1)
+ if (fd == -1) {
+ if (errno != ENOENT)
+ syslog(LOG_ERR, "%s: open `%s': %m",
+ iface->name, iface->leasefile);
return NULL;
+ }
+ syslog(LOG_DEBUG, "%s: reading lease `%s'",
+ iface->name, iface->leasefile);
dhcp = xmalloc(sizeof(*dhcp));
memset(dhcp, 0, sizeof(*dhcp));
bytes = read(fd, dhcp, sizeof(*dhcp));
@@ -1058,21 +1140,21 @@ print_string(char *s, ssize_t len, int dl, const uint8_t *data)
continue;
}
switch (c) {
- case '"': /* FALLTHROUGH */
- case '\'': /* FALLTHROUGH */
- case '$': /* FALLTHROUGH */
- case '`': /* FALLTHROUGH */
- case '\\': /* FALLTHROUGH */
- if (s) {
- if (len < 3) {
- errno = ENOBUFS;
- return -1;
- }
- *s++ = '\\';
- len--;
+ case '"': /* FALLTHROUGH */
+ case '\'': /* FALLTHROUGH */
+ case '$': /* FALLTHROUGH */
+ case '`': /* FALLTHROUGH */
+ case '\\':
+ if (s) {
+ if (len < 3) {
+ errno = ENOBUFS;
+ return -1;
}
- bytes++;
- break;
+ *s++ = '\\';
+ len--;
+ }
+ bytes++;
+ break;
}
if (s) {
*s++ = c;
@@ -1125,17 +1207,22 @@ print_option(char *s, ssize_t len, int type, int dl, const uint8_t *data)
if (!s) {
if (type & UINT8)
l = 3;
- else if (type & UINT16)
+ else if (type & UINT16) {
l = 5;
- else if (type & SINT16)
+ dl /= 2;
+ } else if (type & SINT16) {
l = 6;
- else if (type & UINT32)
+ dl /= 2;
+ } else if (type & UINT32) {
l = 10;
- else if (type & SINT32)
+ dl /= 4;
+ } else if (type & SINT32) {
l = 11;
- else if (type & IPV4)
+ dl /= 4;
+ } else if (type & IPV4) {
l = 16;
- else {
+ dl /= 4;
+ } else {
errno = EINVAL;
return -1;
}
@@ -1199,7 +1286,7 @@ setvar(char ***e, const char *prefix, const char *var, const char *value)
ssize_t
configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
- const struct options *options)
+ const struct if_options *ifo)
{
unsigned int i;
const uint8_t *p;
@@ -1220,12 +1307,12 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
for (opt = dhcp_opts; opt->option; opt++) {
if (!opt->var)
continue;
- if (has_option_mask(options->nomask, opt->option))
+ if (has_option_mask(ifo->nomask, opt->option))
continue;
if (get_option_raw(dhcp, opt->option))
e++;
}
- if (dhcp->yiaddr)
+ if (dhcp->yiaddr || dhcp->ciaddr)
e += 5;
if (*dhcp->bootfile && !(overl & 1))
e++;
@@ -1235,10 +1322,10 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
}
ep = env;
- if (dhcp->yiaddr) {
+ if (dhcp->yiaddr || dhcp->ciaddr) {
/* Set some useful variables that we derive from the DHCP
* message but are not necessarily in the options */
- addr.s_addr = dhcp->yiaddr;
+ addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr;
setvar(&ep, prefix, "ip_address", inet_ntoa(addr));
if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) {
net.s_addr = get_netmask(addr.s_addr);
@@ -1263,7 +1350,7 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
for (opt = dhcp_opts; opt->option; opt++) {
if (!opt->var)
continue;
- if (has_option_mask(options->nomask, opt->option))
+ if (has_option_mask(ifo->nomask, opt->option))
continue;
val = NULL;
p = get_option(dhcp, opt->option, &pl, NULL);
@@ -1286,3 +1373,33 @@ configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
return ep - env;
}
+
+void
+get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
+{
+ struct timeval now;
+
+ lease->cookie = dhcp->cookie;
+ /* BOOTP does not set yiaddr for replies when ciaddr is set. */
+ if (dhcp->yiaddr)
+ lease->addr.s_addr = dhcp->yiaddr;
+ else
+ lease->addr.s_addr = dhcp->ciaddr;
+ if (get_option_addr(&lease->net, dhcp, DHO_SUBNETMASK) == -1)
+ lease->net.s_addr = get_netmask(lease->addr.s_addr);
+ if (get_option_addr(&lease->brd, dhcp, DHO_BROADCAST) == -1)
+ lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
+ if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) == 0) {
+ /* Ensure that we can use the lease */
+ get_monotonic(&now);
+ if (now.tv_sec + (time_t)lease->leasetime < now.tv_sec)
+ lease->leasetime = ~0U; /* Infinite lease */
+ } else
+ lease->leasetime = ~0U; /* Default to infinite lease */
+ if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0)
+ lease->renewaltime = 0;
+ if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0)
+ lease->rebindtime = 0;
+ if (get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0)
+ lease->server.s_addr = INADDR_ANY;
+}