[LEDE-DEV] [PATCH odhcpd 1/5] config: Support infinite as DHCP pool leasetime value

Hans Dedecker dedeckeh at gmail.com
Thu Nov 17 07:11:56 PST 2016


Add support for infinite leasetime value; this can be done by
specifying "infinite" as leasetime value which is similar to
dnsmasq infinite leasetime support.
Specifying "infinite" as leasetime is valid for both the host
and dhcp uci sections.
A DHCPv4/DHCPv6 assignment is now considered infinite if valid_unil
holds the value 0.

Signed-off-by: Hans Dedecker <dedeckeh at gmail.com>
---

This fixes broken IPv6 connectivity in case infinite is specified as
a leasetime value for a dhcp pool as odhcpd was considering this as
an invalid value and deleted the interface. This particular problem
can pop up if dnsmasq is used as DHCPv4 server with one of the pools
using infinite leasetime.

 src/config.c    |  7 ++++---
 src/dhcpv4.c    | 30 ++++++++++++++++--------------
 src/dhcpv6-ia.c | 20 +++++++++++---------
 src/odhcpd.h    |  2 ++
 4 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/src/config.c b/src/config.c
index ef51112..44b049d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -218,9 +218,10 @@ static void set_config(struct uci_section *s)
 }
 
 static double parse_leasetime(struct blob_attr *c) {
-	char *val = blobmsg_get_string(c), *endptr;
-	double time = strtod(val, &endptr);
-	if (time && endptr[0]) {
+	char *val = blobmsg_get_string(c), *endptr = NULL;
+	double time = strcmp(val, "infinite") ? strtod(val, &endptr) : UINT32_MAX;
+
+	if (time && endptr && endptr[0]) {
 		if (endptr[0] == 's')
 			time *= 1;
 		else if (endptr[0] == 'm')
diff --git a/src/dhcpv4.c b/src/dhcpv4.c
index f277a67..8469038 100644
--- a/src/dhcpv4.c
+++ b/src/dhcpv4.c
@@ -181,7 +181,8 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
 			a->addr = ntohl(lease->ipaddr.s_addr);
 			memcpy(a->hwaddr, lease->mac.ether_addr_octet, sizeof(a->hwaddr));
 			memcpy(a->hostname, lease->hostname, hostlen);
-			a->valid_until = LONG_MAX;
+			/* Infinite valid */
+			a->valid_until = 0;
 
 			// Assign to all interfaces
 			struct dhcpv4_assignment *c;
@@ -246,8 +247,7 @@ static void dhcpv4_put(struct dhcpv4_message *msg, uint8_t **cookie,
 	*cookie = c + len;
 }
 
-
-// Simple DHCPv6-server for information requests
+// Handler for DHCPv4 messages
 static void handle_dhcpv4(void *addr, void *data, size_t len,
 		struct interface *iface, _unused void *dest_addr)
 {
@@ -396,11 +396,13 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
 		val = htonl(leasetime);
 		dhcpv4_put(&reply, &cookie, DHCPV4_OPT_LEASETIME, 4, &val);
 
-		val = htonl(500 * leasetime / 1000);
-		dhcpv4_put(&reply, &cookie, DHCPV4_OPT_RENEW, 4, &val);
+		if (leasetime != UINT32_MAX) {
+			val = htonl(500 * leasetime / 1000);
+			dhcpv4_put(&reply, &cookie, DHCPV4_OPT_RENEW, 4, &val);
 
-		val = htonl(875 * leasetime / 1000);
-		dhcpv4_put(&reply, &cookie, DHCPV4_OPT_REBIND, 4, &val);
+			val = htonl(875 * leasetime / 1000);
+			dhcpv4_put(&reply, &cookie, DHCPV4_OPT_REBIND, 4, &val);
+		}
 
 		dhcpv4_put(&reply, &cookie, DHCPV4_OPT_NETMASK, 4, &ifnetmask.sin_addr);
 
@@ -598,7 +600,7 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
 			a = c;
 			if (c->addr == raddr)
 				break;
-		} else if (c->valid_until < now) {
+		} else if (!INFINITE_VALID(c->valid_until) && c->valid_until < now) {
 			list_del(&c->head);
 			free(c);
 		}
@@ -640,10 +642,10 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
 			leasetime = iface->dhcpv4_leasetime;
 		}
 
-		// Was only a solicitation: mark binding for removal
+		// Was only a discover; mark binding for removal
 		if (assigned && a->valid_until < now) {
-			a->valid_until = (msg == DHCPV4_MSG_DISCOVER) ? 0 :
-					(now + leasetime);
+			a->valid_until = ((msg == DHCPV4_MSG_DISCOVER) ? now : ((leasetime == UINT32_MAX) ?
+						0 : (time_t)(now + leasetime)));
 		} else if (!assigned && a) { // Cleanup failed assignment
 			free(a);
 			a = NULL;
@@ -652,9 +654,9 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
 		if (assigned && a)
 			lease = a;
 	} else if (msg == DHCPV4_MSG_RELEASE) {
-		if (a && a->valid_until != LONG_MAX)
-			a->valid_until = 0;
-	} else if (msg == DHCPV4_MSG_DECLINE && a && a->valid_until != LONG_MAX) {
+		if (a && !INFINITE_VALID(a->valid_until))
+			a->valid_until = now - 1;
+	} else if (msg == DHCPV4_MSG_DECLINE && a && !INFINITE_VALID(a->valid_until)) {
 		memset(a->hwaddr, 0, sizeof(a->hwaddr));
 		a->valid_until = now + 3600; // Block address for 1h
 	}
diff --git a/src/dhcpv6-ia.c b/src/dhcpv6-ia.c
index 4c321ac..597bc74 100644
--- a/src/dhcpv6-ia.c
+++ b/src/dhcpv6-ia.c
@@ -262,7 +262,7 @@ void dhcpv6_write_statefile(void)
 							m = i;
 
 					for (size_t i = 0; i < addrlen; ++i) {
-						if (addrs[i].prefix > 96 || c->valid_until <= now ||
+						if (addrs[i].prefix > 96 || (!INFINITE_VALID(c->valid_until) && c->valid_until <= now) ||
 								(iface->managed < RELAYD_MANAGED_NO_AFLAG && i != m &&
 										addrs[i].prefix == 64))
 							continue;
@@ -592,7 +592,8 @@ void dhcpv6_ia_postupdate(struct interface *iface, time_t now)
 	struct list_head reassign = LIST_HEAD_INIT(reassign);
 	struct dhcpv6_assignment *c, *d;
 	list_for_each_entry_safe(c, d, &iface->ia_assignments, head) {
-		if (c->clid_len == 0 || c->valid_until < now || c->managed_size)
+		if (c->clid_len == 0 || (!INFINITE_VALID(c->valid_until) && c->valid_until < now) ||
+				c->managed_size)
 			continue;
 
 		if (c->length < 128 && c->assigned >= border->assigned && c != border)
@@ -637,7 +638,7 @@ static void reconf_timer(struct uloop_timeout *event)
 
 		struct dhcpv6_assignment *a, *n;
 		list_for_each_entry_safe(a, n, &iface->ia_assignments, head) {
-			if (a->valid_until < now) {
+			if (!INFINITE_VALID(a->valid_until) && a->valid_until < now) {
 				if ((a->length < 128 && a->clid_len > 0) ||
 						(a->length == 128 && a->clid_len == 0)) {
 					list_del(&a->head);
@@ -768,9 +769,10 @@ static size_t append_reply(uint8_t *buf, size_t buflen, uint16_t status,
 				}
 			}
 
-			a->valid_until = valid + now;
-			out.t1 = htonl(pref * 5 / 10);
-			out.t2 = htonl(pref * 8 / 10);
+			/* UINT32_MAX is considered as infinite leasetime */
+			a->valid_until = (valid == UINT32_MAX) ? 0 : valid + now;
+			out.t1 = htonl((pref == UINT32_MAX) ? pref : pref * 5 / 10);
+			out.t2 = htonl((pref == UINT32_MAX) ? pref : pref * 8 / 10);
 
 			if (!out.t1)
 				out.t1 = htonl(1);
@@ -1031,7 +1033,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
 			if (((c->clid_len == clid_len && !memcmp(c->clid_data, clid_data, clid_len)) ||
 					(c->clid_len >= clid_len && !c->clid_data[0] && !c->clid_data[1]
 					        && !memcmp(c->mac, mac, sizeof(mac)))) &&
-					(c->iaid == ia->iaid || c->valid_until < now) &&
+					(c->iaid == ia->iaid || (!INFINITE_VALID(c->valid_until) && c->valid_until < now)) &&
 					((is_pd && c->length <= 64) || (is_na && c->length == 128))) {
 				a = c;
 
@@ -1114,7 +1116,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
 
 			// Was only a solicitation: mark binding for removal
 			if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
-				a->valid_until = 0;
+				a->valid_until = now;
 			} else if (assigned && hdr->msg_type == DHCPV6_MSG_REQUEST) {
 				if (hostname_len > 0) {
 					a->hostname = realloc(a->hostname, hostname_len + 1);
@@ -1141,7 +1143,7 @@ ssize_t dhcpv6_handle_ia(uint8_t *buf, size_t buflen, struct interface *iface,
 				if (a)
 					apply_lease(iface, a, true);
 			} else if (hdr->msg_type == DHCPV6_MSG_RELEASE) {
-				a->valid_until = 0;
+				a->valid_until = now - 1;
 				apply_lease(iface, a, false);
 			} else if (hdr->msg_type == DHCPV6_MSG_DECLINE && a->length == 128) {
 				a->clid_len = 0;
diff --git a/src/odhcpd.h b/src/odhcpd.h
index 3e8fc3e..e322ebd 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -44,6 +44,8 @@
 #define RELAYD_BUFFER_SIZE 8192
 #define RELAYD_MAX_PREFIXES 8
 
+#define INFINITE_VALID(x) ((x) == 0)
+
 #define _unused __attribute__((unused))
 #define _packed __attribute__((packed))
 
-- 
1.9.1




More information about the Lede-dev mailing list