All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast
@ 2020-10-16 17:39 James Prestwood
  2020-10-16 17:39 ` [PATCH v3 02/14] unit: update test-dhcp to use l2_send James Prestwood
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4101 bytes --]

Functionally this was being used as a broadcast only because the
destination address was a broadcast address. But providing a
MAC address would effectively turn this into a unicast over l2
which DHCP server requires.

To support server a destination MAC address was added to the
arguments and if NULL the destination will be set to a broadcast
address. The name of the op was changed to 'l2_send' to better
describe the new behavior. All client code will remain nearly the
same (just name changes) except having to set the destination MAC
to NULL indicating it is a broadcast.
---
 ell/dhcp-private.h   |  3 ++-
 ell/dhcp-transport.c | 10 +++++++---
 ell/dhcp.c           |  7 ++++---
 3 files changed, 13 insertions(+), 7 deletions(-)

v3:
 * Reworded commit description to be more clear that the original op
   was a broadcast only operation and was modified to work with
   both broadcast and unicast on l2

diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index 990162c..68ad7c2 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -106,9 +106,10 @@ typedef void (*dhcp_transport_rx_cb_t)(const void *, size_t, void *);
 
 struct dhcp_transport {
 	int (*open)(struct dhcp_transport *s, uint32_t xid);
-	int (*broadcast)(struct dhcp_transport *transport,
+	int (*l2_send)(struct dhcp_transport *transport,
 						uint32_t saddr, uint16_t sport,
 						uint32_t daddr, uint16_t dport,
+						const uint8_t *dest_mac,
 						const void *data, size_t len);
 	int (*bind)(struct dhcp_transport *transport, uint32_t saddr);
 	int (*send)(struct dhcp_transport *transport,
diff --git a/ell/dhcp-transport.c b/ell/dhcp-transport.c
index 1fa84b2..71d0c47 100644
--- a/ell/dhcp-transport.c
+++ b/ell/dhcp-transport.c
@@ -194,9 +194,10 @@ static void dhcp_set_ip_udp_headers(struct iphdr *ip, struct udphdr *udp,
 	ip->check = _dhcp_checksumv(iov, 1);
 }
 
-static int _dhcp_default_transport_broadcast(struct dhcp_transport *s,
+static int _dhcp_default_transport_l2_send(struct dhcp_transport *s,
 						uint32_t saddr, uint16_t sport,
 						uint32_t daddr, uint16_t dport,
+						const uint8_t *dest_mac,
 						const void *data, size_t len)
 {
 	struct dhcp_default_transport *transport =
@@ -221,7 +222,10 @@ static int _dhcp_default_transport_broadcast(struct dhcp_transport *s,
 	addr.sll_protocol = htons(ETH_P_IP);
 	addr.sll_ifindex = s->ifindex;
 	addr.sll_halen = ETH_ALEN;
-	memset(addr.sll_addr, 0xff, ETH_ALEN);
+	if (!dest_mac)
+		memset(addr.sll_addr, 0xff, ETH_ALEN);
+	else
+		memcpy(addr.sll_addr, dest_mac, ETH_ALEN);
 
 	memset(&msg, 0, sizeof(msg));
 	msg.msg_name = &addr;
@@ -501,7 +505,7 @@ struct dhcp_transport *_dhcp_default_transport_new(uint32_t ifindex,
 	transport->super.bind = _dhcp_default_transport_bind;
 	transport->super.close = _dhcp_default_transport_close;
 	transport->super.send = _dhcp_default_transport_send;
-	transport->super.broadcast = _dhcp_default_transport_broadcast;
+	transport->super.l2_send = _dhcp_default_transport_l2_send;
 
 	transport->super.ifindex = ifindex;
 	l_strlcpy(transport->ifname, ifname, IFNAMSIZ);
diff --git a/ell/dhcp.c b/ell/dhcp.c
index f52b470..d75d86f 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -354,9 +354,10 @@ static int dhcp_client_send_discover(struct l_dhcp_client *client)
 
 	_dhcp_message_builder_finalize(&builder, &len);
 
-	return client->transport->broadcast(client->transport,
+	return client->transport->l2_send(client->transport,
 					INADDR_ANY, DHCP_PORT_CLIENT,
 					INADDR_BROADCAST, DHCP_PORT_SERVER,
+					NULL,
 					discover, len);
 }
 
@@ -453,10 +454,10 @@ static int dhcp_client_send_request(struct l_dhcp_client *client)
 							&si, request, len);
 	}
 
-	return client->transport->broadcast(client->transport,
+	return client->transport->l2_send(client->transport,
 					INADDR_ANY, DHCP_PORT_CLIENT,
 					INADDR_BROADCAST, DHCP_PORT_SERVER,
-					request, len);
+					NULL, request, len);
 }
 
 static void dhcp_client_timeout_resend(struct l_timeout *timeout,
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 02/14] unit: update test-dhcp to use l2_send
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 03/14] dhcp-lease: add mac member and getter James Prestwood
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 984 bytes --]

---
 unit/test-dhcp.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/unit/test-dhcp.c b/unit/test-dhcp.c
index d825401..6ae8d71 100644
--- a/unit/test-dhcp.c
+++ b/unit/test-dhcp.c
@@ -673,9 +673,10 @@ static int fake_transport_send(struct dhcp_transport *transport,
 	return len;
 }
 
-static int fake_transport_broadcast(struct dhcp_transport *transprot,
+static int fake_transport_l2_send(struct dhcp_transport *transprot,
 					uint32_t saddr, uint16_t sport,
 					uint32_t daddr, uint16_t dport,
+					const uint8_t *dest_mac,
 					const void *data, size_t len)
 {
 	assert(len <= sizeof(client_packet));
@@ -702,7 +703,7 @@ static void test_discover(const void *data)
 	const struct l_dhcp_lease *lease;
 
 	transport->send = fake_transport_send;
-	transport->broadcast = fake_transport_broadcast;
+	transport->l2_send = fake_transport_l2_send;
 	transport->ifindex = 42;
 
 	client = l_dhcp_client_new(42);
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 03/14] dhcp-lease: add mac member and getter
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
  2020-10-16 17:39 ` [PATCH v3 02/14] unit: update test-dhcp to use l2_send James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 04/14] dhcp-server: basic DHCP server skeleton James Prestwood
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1933 bytes --]

Added for server since it needs to track each clients
MAC address.
---
 ell/dhcp-lease.c   | 8 ++++++++
 ell/dhcp-private.h | 2 ++
 ell/dhcp.h         | 1 +
 ell/ell.sym        | 1 +
 4 files changed, 12 insertions(+)

diff --git a/ell/dhcp-lease.c b/ell/dhcp-lease.c
index ac90c6a..59de3e3 100644
--- a/ell/dhcp-lease.c
+++ b/ell/dhcp-lease.c
@@ -278,3 +278,11 @@ LIB_EXPORT uint32_t l_dhcp_lease_get_lifetime(const struct l_dhcp_lease *lease)
 
 	return lease->lifetime;
 }
+
+LIB_EXPORT const uint8_t *l_dhcp_lease_get_mac(const struct l_dhcp_lease *lease)
+{
+	if (unlikely(!lease))
+		return NULL;
+
+	return lease->mac;
+}
diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index 68ad7c2..4276479 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -152,6 +152,8 @@ struct l_dhcp_lease {
 	uint32_t router;
 	uint32_t *dns;
 	char *domain_name;
+	/* for server */
+	uint8_t mac[6];
 };
 
 struct l_dhcp_lease *_dhcp_lease_new(void);
diff --git a/ell/dhcp.h b/ell/dhcp.h
index b8a5b41..c78b605 100644
--- a/ell/dhcp.h
+++ b/ell/dhcp.h
@@ -96,6 +96,7 @@ char *l_dhcp_lease_get_broadcast(const struct l_dhcp_lease *lease);
 char *l_dhcp_lease_get_server_id(const struct l_dhcp_lease *lease);
 char **l_dhcp_lease_get_dns(const struct l_dhcp_lease *lease);
 char *l_dhcp_lease_get_domain_name(const struct l_dhcp_lease *lease);
+const uint8_t *l_dhcp_lease_get_mac(const struct l_dhcp_lease *lease);
 
 uint32_t l_dhcp_lease_get_t1(const struct l_dhcp_lease *lease);
 uint32_t l_dhcp_lease_get_t2(const struct l_dhcp_lease *lease);
diff --git a/ell/ell.sym b/ell/ell.sym
index b3d5c71..5268b48 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -222,6 +222,7 @@ global:
 	/* dhcp */
 	l_dhcp_lease_get_address;
 	l_dhcp_lease_get_gateway;
+	l_dhcp_lease_get_mac;
 	l_dhcp_lease_get_netmask;
 	l_dhcp_lease_get_broadcast;
 	l_dhcp_lease_get_server_id;
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 04/14] dhcp-server: basic DHCP server skeleton
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
  2020-10-16 17:39 ` [PATCH v3 02/14] unit: update test-dhcp to use l2_send James Prestwood
  2020-10-16 17:39 ` [PATCH v3 03/14] dhcp-lease: add mac member and getter James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 05/14] dhcp-server: add transport framework James Prestwood
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 12542 bytes --]

---
 Makefile.am       |   1 +
 ell/dhcp-server.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++
 ell/dhcp.h        |  36 +++++
 ell/ell.sym       |  13 ++
 4 files changed, 407 insertions(+)
 create mode 100644 ell/dhcp-server.c

v3:
 * Made setting gateway, netmask, and ip range optional and instead
   assume default values if none are provided.

diff --git a/Makefile.am b/Makefile.am
index beba535..9bdf4dc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -128,6 +128,7 @@ ell_libell_la_SOURCES = $(linux_headers) \
 			ell/dhcp6-transport.c \
 			ell/dhcp6-lease.c \
 			ell/dhcp-util.c \
+			ell/dhcp-server.c \
 			ell/cert.c \
 			ell/cert-private.h \
 			ell/ecc-private.h \
diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
new file mode 100644
index 0000000..8af9704
--- /dev/null
+++ b/ell/dhcp-server.c
@@ -0,0 +1,357 @@
+/*
+ *
+ *  Embedded Linux library
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it 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.
+ *
+ *  This library 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 this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <net/ethernet.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <time.h>
+
+#include "private.h"
+#include "time.h"
+#include "net.h"
+#include "dhcp.h"
+#include "dhcp-private.h"
+#include "queue.h"
+#include "util.h"
+#include "strv.h"
+
+/* 8 hours */
+#define DEFAULT_DHCP_LEASE_SEC (8*60*60)
+
+/* 5 minutes  */
+#define OFFER_TIME (5*60)
+
+#define SERVER_PORT 67
+
+struct l_dhcp_server {
+	bool started;
+	int ifindex;
+	char *ifname;
+	uint32_t start_ip;
+	uint32_t end_ip;
+	uint32_t address;
+	uint32_t netmask;
+	uint32_t gateway;
+	uint32_t *dns_list;
+	uint32_t lease_seconds;
+
+	struct l_queue *lease_list;
+
+	l_dhcp_debug_cb_t debug_handler;
+	void *debug_data;
+
+	l_dhcp_server_event_cb_t event_handler;
+	void *user_data;
+	l_dhcp_destroy_cb_t event_destroy;
+};
+
+#define MAC "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_STR(a) a[0], a[1], a[2], a[3], a[4], a[5]
+
+#define IP_STR(uint_ip) \
+({ \
+	struct in_addr _in; \
+	char *_out; \
+	_in.s_addr = uint_ip; \
+	_out = inet_ntoa(_in); \
+	_out; \
+})
+
+#define SERVER_DEBUG(fmt, args...)					\
+	l_util_debug(server->debug_handler, server->debug_data,		\
+			"%s:%i " fmt, __func__, __LINE__, ## args)
+
+static bool match_lease_mac(const void *data, const void *user_data)
+{
+	const struct l_dhcp_lease *lease = data;
+	const uint8_t *mac = user_data;
+
+	return !memcmp(lease->mac, mac, 6);
+}
+
+static struct l_dhcp_lease *find_lease_by_mac(struct l_dhcp_server *server,
+						const uint8_t *mac)
+{
+	return l_queue_find(server->lease_list, match_lease_mac, mac);
+}
+
+LIB_EXPORT struct l_dhcp_server *l_dhcp_server_new(int ifindex)
+{
+	struct l_dhcp_server *server = l_new(struct l_dhcp_server, 1);
+	if (!server)
+		return NULL;
+
+	server->lease_list = l_queue_new();
+
+	server->started = false;
+
+	server->lease_seconds = DEFAULT_DHCP_LEASE_SEC;
+
+	server->ifindex = ifindex;
+	server->debug_handler = NULL;
+	server->debug_data = NULL;
+
+	return server;
+}
+
+LIB_EXPORT void l_dhcp_server_destroy(struct l_dhcp_server *server)
+{
+	if (unlikely(!server))
+		return;
+
+	l_dhcp_server_stop(server);
+
+	if (server->event_destroy)
+		server->event_destroy(server->user_data);
+
+	l_free(server->ifname);
+
+	l_queue_destroy(server->lease_list,
+				(l_queue_destroy_func_t) _dhcp_lease_free);
+
+	if (server->dns_list)
+		l_free(server->dns_list);
+
+	l_free(server);
+}
+
+LIB_EXPORT bool l_dhcp_server_start(struct l_dhcp_server *server)
+{
+	struct in_addr ia;
+
+	if (unlikely(!server))
+		return false;
+
+	if (server->started)
+		return false;
+
+	if (!server->address) {
+		if (!l_net_get_address(server->ifindex, &ia))
+			return false;
+
+		server->address = ia.s_addr;
+	}
+
+	/* Assign a default gateway if not already set */
+	if (!server->gateway)
+		server->gateway = server->address;
+
+	/* Assign a default netmask if not already */
+	if (!server->netmask) {
+		if (inet_aton("255.255.255.0", &ia) < 0)
+			return false;
+
+		server->netmask = ia.s_addr;
+	}
+
+	/*
+	 * Assign a default ip range if not already. This will default to
+	 * server->address + 1 ... 254
+	 */
+	if (!server->start_ip) {
+		server->start_ip = htonl(ntohl(server->address) + 1);
+		/* set last octet to 0x00 */
+		server->end_ip = server->start_ip & 0x00ffffff;
+		/* set last octet to 0xfe (254) */
+		server->end_ip |= 0xfe000000;
+	}
+
+	if (!server->ifname) {
+		server->ifname = l_net_get_name(server->ifindex);
+
+		if (!server->ifname)
+			return false;
+	}
+
+	SERVER_DEBUG("Starting DHCP server on %s", server->ifname);
+
+	server->started = true;
+
+	return true;
+}
+
+LIB_EXPORT bool l_dhcp_server_stop(struct l_dhcp_server *server)
+{
+	if (unlikely(!server))
+		return false;
+
+	if (!server->started)
+		return true;
+
+	server->started = false;
+
+	/* TODO: Add ability to save leases */
+
+	return true;
+}
+
+LIB_EXPORT bool l_dhcp_server_set_ip_range(struct l_dhcp_server *server,
+				const char *start_ip,
+				const char *end_ip)
+{
+	struct in_addr _host_addr;
+
+	if (unlikely(!server || !start_ip || !end_ip))
+		return false;
+
+	if (inet_aton((const char *)start_ip, &_host_addr) == 0)
+		return false;
+
+	server->start_ip = _host_addr.s_addr;
+
+	if (inet_aton((const char *) end_ip, &_host_addr) == 0)
+		return false;
+
+	server->end_ip = _host_addr.s_addr;
+
+	return true;
+}
+
+LIB_EXPORT void l_dhcp_server_set_debug(struct l_dhcp_server *server,
+				l_dhcp_debug_cb_t function,
+				void *user_data, l_dhcp_destroy_cb_t destory)
+{
+	if (unlikely(!server))
+		return;
+
+	server->debug_handler = function;
+	server->debug_data = user_data;
+}
+
+LIB_EXPORT void l_dhcp_server_set_lease_time(struct l_dhcp_server *server,
+					unsigned int lease_time)
+{
+	if (unlikely(!server))
+		return;
+
+	server->lease_seconds = lease_time;
+}
+
+LIB_EXPORT bool l_dhcp_server_set_event_handler(struct l_dhcp_server *server,
+					l_dhcp_server_event_cb_t handler,
+					void *user_data,
+					l_dhcp_destroy_cb_t destroy)
+{
+	if (unlikely(!server))
+		return false;
+
+	server->event_handler = handler;
+	server->user_data = user_data;
+	server->event_destroy = destroy;
+
+	return true;
+}
+
+LIB_EXPORT bool l_dhcp_server_set_ip_address(struct l_dhcp_server *server,
+						const char *ip)
+{
+	struct in_addr ia;
+
+	if (unlikely(!server))
+		return false;
+
+	if (inet_aton(ip, &ia) < 0)
+		return false;
+
+	server->address = ia.s_addr;
+
+	return true;
+}
+
+LIB_EXPORT bool l_dhcp_server_set_interface_name(struct l_dhcp_server *server,
+							const char *ifname)
+{
+	if (unlikely(!server || !ifname))
+		return false;
+
+	l_free(server->ifname);
+	server->ifname = l_strdup(ifname);
+
+	return true;
+}
+
+LIB_EXPORT bool l_dhcp_server_set_netmask(struct l_dhcp_server *server,
+						const char *mask)
+{
+	struct in_addr ia;
+
+	if (unlikely(!server || !mask))
+		return false;
+
+	if (inet_aton(mask, &ia) < 0)
+		return false;
+
+	server->netmask = ia.s_addr;
+
+	return true;
+}
+
+LIB_EXPORT bool l_dhcp_server_set_gateway(struct l_dhcp_server *server,
+						const char *ip)
+{
+	struct in_addr ia;
+
+	if (unlikely(!server || !ip))
+		return false;
+
+	if (inet_aton(ip, &ia) < 0)
+		return false;
+
+	server->gateway = ia.s_addr;
+
+	return true;
+}
+
+LIB_EXPORT bool l_dhcp_server_set_dns(struct l_dhcp_server *server, char **dns)
+{
+	unsigned int i;
+	uint32_t *dns_list;
+
+	if (unlikely(!server || !dns))
+		return false;
+
+	dns_list = l_new(uint32_t, l_strv_length(dns) + 1);
+
+	for (i = 0; dns[i]; i++) {
+		struct in_addr ia;
+
+		if (inet_aton(dns[i], &ia) < 0)
+			goto failed;
+
+		dns_list[i] = ia.s_addr;
+	}
+
+	if (server->dns_list)
+		l_free(server->dns_list);
+
+	server->dns_list = dns_list;
+
+	return true;
+
+failed:
+	l_free(dns_list);
+	return false;
+}
diff --git a/ell/dhcp.h b/ell/dhcp.h
index c78b605..0dc349e 100644
--- a/ell/dhcp.h
+++ b/ell/dhcp.h
@@ -31,6 +31,7 @@ extern "C" {
 
 struct l_dhcp_client;
 struct l_dhcp_lease;
+struct l_dhcp_server;
 
 /* RFC 2132 */
 enum l_dhcp_option {
@@ -56,12 +57,22 @@ enum l_dhcp_client_event {
 	L_DHCP_CLIENT_EVENT_NO_LEASE,
 };
 
+enum l_dhcp_server_event {
+	L_DHCP_SERVER_EVENT_NEW_LEASE,
+	L_DHCP_SERVER_EVENT_LEASE_EXPIRED,
+};
+
 typedef void (*l_dhcp_client_event_cb_t)(struct l_dhcp_client *client,
 						enum l_dhcp_client_event event,
 						void *userdata);
 typedef void (*l_dhcp_debug_cb_t)(const char *str, void *user_data);
 typedef void (*l_dhcp_destroy_cb_t)(void *userdata);
 
+typedef void (*l_dhcp_server_event_cb_t)(struct l_dhcp_server *server,
+					enum l_dhcp_server_event event,
+					void *user_data,
+					const struct l_dhcp_lease *lease);
+
 struct l_dhcp_client *l_dhcp_client_new(uint32_t ifindex);
 bool l_dhcp_client_add_request_option(struct l_dhcp_client *client,
 								uint8_t option);
@@ -89,6 +100,7 @@ bool l_dhcp_client_set_debug(struct l_dhcp_client *client,
 				l_dhcp_debug_cb_t function,
 				void *user_data, l_dhcp_destroy_cb_t destroy);
 
+
 char *l_dhcp_lease_get_address(const struct l_dhcp_lease *lease);
 char *l_dhcp_lease_get_gateway(const struct l_dhcp_lease *lease);
 char *l_dhcp_lease_get_netmask(const struct l_dhcp_lease *lease);
@@ -101,6 +113,30 @@ const uint8_t *l_dhcp_lease_get_mac(const struct l_dhcp_lease *lease);
 uint32_t l_dhcp_lease_get_t1(const struct l_dhcp_lease *lease);
 uint32_t l_dhcp_lease_get_t2(const struct l_dhcp_lease *lease);
 uint32_t l_dhcp_lease_get_lifetime(const struct l_dhcp_lease *lease);
+
+struct l_dhcp_server *l_dhcp_server_new(int ifindex);
+void l_dhcp_server_destroy(struct l_dhcp_server *server);
+bool l_dhcp_server_start(struct l_dhcp_server *server);
+bool l_dhcp_server_stop(struct l_dhcp_server *server);
+bool l_dhcp_server_set_ip_range(struct l_dhcp_server *server,
+				const char *start_ip,
+				const char *end_ip);
+void l_dhcp_server_set_debug(struct l_dhcp_server *server,
+				l_dhcp_debug_cb_t function,
+				void *user_data, l_dhcp_destroy_cb_t destory);
+bool l_dhcp_server_set_event_handler(struct l_dhcp_server *server,
+					l_dhcp_server_event_cb_t handler,
+					void *user_data,
+					l_dhcp_destroy_cb_t destroy);
+void l_dhcp_server_set_lease_time(struct l_dhcp_server *server,
+					unsigned int lease_time);
+bool l_dhcp_server_set_interface_name(struct l_dhcp_server *server,
+					const char *ifname);
+bool l_dhcp_server_set_ip_address(struct l_dhcp_server *server,
+						const char *ip);
+bool l_dhcp_server_set_netmask(struct l_dhcp_server *server, const char *mask);
+bool l_dhcp_server_set_gateway(struct l_dhcp_server *server, const char *ip);
+bool l_dhcp_server_set_dns(struct l_dhcp_server *server, char **dns);
 #ifdef __cplusplus
 }
 #endif
diff --git a/ell/ell.sym b/ell/ell.sym
index 5268b48..7a920ed 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -242,6 +242,19 @@ global:
 	l_dhcp_client_stop;
 	l_dhcp_client_set_event_handler;
 	l_dhcp_client_set_debug;
+	l_dhcp_server_new;
+	l_dhcp_server_destroy;
+	l_dhcp_server_start;
+	l_dhcp_server_stop;
+	l_dhcp_server_set_ip_range;
+	l_dhcp_server_set_debug;
+	l_dhcp_server_set_lease_time;
+	l_dhcp_server_set_event_handler;
+	l_dhcp_server_set_ip_address;
+	l_dhcp_server_set_interface_name;
+	l_dhcp_server_set_netmaks;
+	l_dhcp_server_set_gateway;
+	l_dhcp_server_set_dns;
 	/* dhcp6 */
 	l_dhcp6_client_new;
 	l_dhcp6_client_destroy;
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 05/14] dhcp-server: add transport framework
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (2 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 04/14] dhcp-server: basic DHCP server skeleton James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 06/14] dhcp-server: process DISCOVER and send OFFER James Prestwood
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3035 bytes --]

---
 ell/dhcp-private.h |  4 ++++
 ell/dhcp-server.c  | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index 4276479..62abfca 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -21,6 +21,7 @@
  */
 
 struct l_dhcp_client;
+struct l_dhcp_server;
 
 enum {
 	DHCP_PORT_SERVER = 67,
@@ -141,6 +142,9 @@ bool _dhcp_client_set_transport(struct l_dhcp_client *client,
 					struct dhcp_transport *transport);
 void _dhcp_client_override_xid(struct l_dhcp_client *client, uint32_t xid);
 
+bool _dhcp_server_set_transport(struct l_dhcp_server *server,
+					struct dhcp_transport *transport);
+
 struct l_dhcp_lease {
 	uint32_t address;
 	uint32_t server_address;
diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index 8af9704..f4624ea 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -66,6 +66,8 @@ struct l_dhcp_server {
 	l_dhcp_server_event_cb_t event_handler;
 	void *user_data;
 	l_dhcp_destroy_cb_t event_destroy;
+
+	struct dhcp_transport *transport;
 };
 
 #define MAC "%02x:%02x:%02x:%02x:%02x:%02x"
@@ -98,6 +100,23 @@ static struct l_dhcp_lease *find_lease_by_mac(struct l_dhcp_server *server,
 	return l_queue_find(server->lease_list, match_lease_mac, mac);
 }
 
+static void listener_event(const void *data, size_t len, void *user_data)
+{
+}
+
+bool _dhcp_server_set_transport(struct l_dhcp_server *server,
+					struct dhcp_transport *transport)
+{
+	if (unlikely(!server))
+		return false;
+
+	if (server->transport)
+		_dhcp_transport_free(server->transport);
+
+	server->transport = transport;
+	return true;
+}
+
 LIB_EXPORT struct l_dhcp_server *l_dhcp_server_new(int ifindex)
 {
 	struct l_dhcp_server *server = l_new(struct l_dhcp_server, 1);
@@ -127,6 +146,7 @@ LIB_EXPORT void l_dhcp_server_destroy(struct l_dhcp_server *server)
 	if (server->event_destroy)
 		server->event_destroy(server->user_data);
 
+	_dhcp_transport_free(server->transport);
 	l_free(server->ifname);
 
 	l_queue_destroy(server->lease_list,
@@ -186,8 +206,22 @@ LIB_EXPORT bool l_dhcp_server_start(struct l_dhcp_server *server)
 			return false;
 	}
 
+	if (!server->transport) {
+		server->transport = _dhcp_default_transport_new(server->ifindex,
+					server->ifname, DHCP_PORT_SERVER);
+		if (!server->transport)
+			return false;
+	}
+
 	SERVER_DEBUG("Starting DHCP server on %s", server->ifname);
 
+	if (server->transport->open)
+		if (server->transport->open(server->transport, 0) < 0)
+			return false;
+
+	_dhcp_transport_set_rx_callback(server->transport, listener_event,
+						server);
+
 	server->started = true;
 
 	return true;
@@ -201,6 +235,9 @@ LIB_EXPORT bool l_dhcp_server_stop(struct l_dhcp_server *server)
 	if (!server->started)
 		return true;
 
+	if (server->transport->close)
+		server->transport->close(server->transport);
+
 	server->started = false;
 
 	/* TODO: Add ability to save leases */
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 06/14] dhcp-server: process DISCOVER and send OFFER
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (3 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 05/14] dhcp-server: add transport framework James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 07/14] dhcp-server: add REQUEST processing James Prestwood
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 8998 bytes --]

Add handling of DISCOVER messages and ability to send offers.
---
 ell/dhcp-server.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 321 insertions(+)

diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index f4624ea..2edf4b4 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -46,6 +46,14 @@
 
 #define SERVER_PORT 67
 
+static const uint8_t MAC_BCAST_ADDR[ETH_ALEN] __attribute__((aligned(2))) = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const uint8_t MAC_ANY_ADDR[ETH_ALEN] __attribute__((aligned(2))) = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
 struct l_dhcp_server {
 	bool started;
 	int ifindex;
@@ -86,6 +94,14 @@ struct l_dhcp_server {
 	l_util_debug(server->debug_handler, server->debug_data,		\
 			"%s:%i " fmt, __func__, __LINE__, ## args)
 
+static bool is_expired_lease(struct l_dhcp_lease *lease)
+{
+	if (lease->lifetime < time(NULL))
+		return true;
+
+	return false;
+}
+
 static bool match_lease_mac(const void *data, const void *user_data)
 {
 	const struct l_dhcp_lease *lease = data;
@@ -100,8 +116,313 @@ static struct l_dhcp_lease *find_lease_by_mac(struct l_dhcp_server *server,
 	return l_queue_find(server->lease_list, match_lease_mac, mac);
 }
 
+/* Clear the old lease and create the new one */
+static int get_lease(struct l_dhcp_server *server, uint32_t yiaddr,
+				const uint8_t *mac,
+				struct l_dhcp_lease **lease_out)
+{
+	struct l_dhcp_lease *lease;
+
+	if (yiaddr == 0)
+		return -ENXIO;
+
+	if (yiaddr < server->start_ip)
+		return -ENXIO;
+
+	if (yiaddr > server->end_ip)
+		return -ENXIO;
+
+	if (memcmp(mac, MAC_BCAST_ADDR, ETH_ALEN) == 0)
+		return -ENXIO;
+
+	if (memcmp(mac, MAC_ANY_ADDR, ETH_ALEN) == 0)
+		return -ENXIO;
+
+	lease = find_lease_by_mac(server, mac);
+
+	if (lease) {
+		l_queue_remove(server->lease_list, lease);
+
+		*lease_out = lease;
+
+		return 0;
+	}
+
+	*lease_out = l_new(struct l_dhcp_lease, 1);
+	if (!*lease_out)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int compare_lifetime(const void *a, const void *b, void *user_data)
+{
+	const struct l_dhcp_lease *lease1 = a;
+	const struct l_dhcp_lease *lease2 = b;
+
+	return lease2->lifetime - lease1->lifetime;
+}
+
+static struct l_dhcp_lease *add_lease(struct l_dhcp_server *server,
+					uint32_t expire, const uint8_t *chaddr,
+					uint32_t yiaddr)
+{
+	struct l_dhcp_lease *lease = NULL;
+	int ret;
+
+	ret = get_lease(server, yiaddr, chaddr, &lease);
+	if (ret != 0)
+		return NULL;
+
+	memset(lease, 0, sizeof(*lease));
+
+	memcpy(lease->mac, chaddr, ETH_ALEN);
+	lease->address = yiaddr;
+
+	if (expire == 0)
+		lease->lifetime = time(NULL) + server->lease_seconds;
+	else
+		lease->lifetime = expire;
+
+	l_queue_insert(server->lease_list, lease, compare_lifetime, NULL);
+
+	SERVER_DEBUG("added lease IP %s for "MAC " lifetime=%u",
+			IP_STR(yiaddr), MAC_STR(chaddr),
+			lease->lifetime);
+
+	return lease;
+}
+
+static bool match_lease_ip(const void *data, const void *user_data)
+{
+	const struct l_dhcp_lease *lease = data;
+
+	return lease->address == L_PTR_TO_UINT(user_data);
+}
+
+static struct l_dhcp_lease *find_lease_by_nip(struct l_dhcp_server *server,
+						uint32_t nip)
+{
+	return l_queue_find(server->lease_list, match_lease_ip,
+				L_INT_TO_PTR(nip));
+}
+
+static bool check_requested_nip(struct l_dhcp_server *server,
+				uint32_t requested_nip)
+{
+	struct l_dhcp_lease *lease;
+
+	if (requested_nip == 0)
+		return false;
+
+	if (requested_nip < server->start_ip)
+		return false;
+
+	if (requested_nip > server->end_ip)
+		return false;
+
+	lease = find_lease_by_nip(server, requested_nip);
+	if (!lease)
+		return true;
+
+	if (!is_expired_lease(lease))
+		return false;
+
+	return true;
+}
+
+/* Check if the IP is taken; if it is, add it to the lease table */
+static bool arp_check(uint32_t nip, const uint8_t *safe_mac)
+{
+	/* TODO: Add ARP checking */
+	return true;
+}
+
+static uint32_t find_free_or_expired_nip(struct l_dhcp_server *server,
+						const uint8_t *safe_mac)
+{
+	uint32_t ip_addr;
+	struct l_dhcp_lease *lease;
+
+	for (ip_addr = server->start_ip; ip_addr <= server->end_ip; ip_addr++) {
+		/* e.g. 192.168.55.0 */
+		if ((ip_addr & 0xff) == 0)
+			continue;
+
+		/* e.g. 192.168.55.255 */
+		if ((ip_addr & 0xff) == 0xff)
+			continue;
+
+		lease = find_lease_by_nip(server, ip_addr);
+		if (lease)
+			continue;
+
+		if (arp_check(ip_addr, safe_mac))
+			return ip_addr;
+	}
+
+	lease = l_queue_peek_tail(server->lease_list);
+	if (!lease)
+		return 0;
+
+	if (!is_expired_lease(lease))
+		return 0;
+
+	if (!arp_check(lease->address, safe_mac))
+		return 0;
+
+	return lease->address;
+}
+
+static void server_message_init(struct l_dhcp_server *server,
+				const struct dhcp_message *client_msg,
+				struct dhcp_message *reply)
+{
+	reply->xid = client_msg->xid;
+	memcpy(reply->chaddr, client_msg->chaddr, sizeof(client_msg->chaddr));
+	reply->flags = client_msg->flags;
+	reply->giaddr = client_msg->giaddr;
+	reply->ciaddr = client_msg->ciaddr;
+}
+
+static void add_server_options(struct l_dhcp_server *server,
+				struct dhcp_message_builder *builder)
+{
+	int i;
+
+	if (server->netmask)
+		_dhcp_message_builder_append(builder, L_DHCP_OPTION_SUBNET_MASK,
+						4, &server->netmask);
+
+	if (server->gateway)
+		_dhcp_message_builder_append(builder, L_DHCP_OPTION_ROUTER,
+						4, &server->gateway);
+
+	if (server->dns_list) {
+		for (i = 0; server->dns_list[i]; i++);
+
+		_dhcp_message_builder_append(builder,
+					L_DHCP_OPTION_DOMAIN_NAME_SERVER,
+					i * 4, server->dns_list);
+	}
+}
+
+static void send_offer(struct l_dhcp_server *server,
+			const struct dhcp_message *client_msg,
+			struct l_dhcp_lease *lease, uint32_t requested_nip)
+{
+	struct dhcp_message_builder builder;
+	size_t len = sizeof(struct dhcp_message) + DHCP_MIN_OPTIONS_SIZE;
+	L_AUTO_FREE_VAR(struct dhcp_message *, reply);
+	uint32_t lease_time = L_CPU_TO_BE32(server->lease_seconds);
+
+	reply = (struct dhcp_message *) l_new(uint8_t, len);
+
+	if (lease)
+		reply->yiaddr = lease->address;
+	else if (check_requested_nip(server, requested_nip))
+		reply->yiaddr = requested_nip;
+	else
+		reply->yiaddr = find_free_or_expired_nip(server,
+							client_msg->chaddr);
+
+	if (!reply->yiaddr) {
+		SERVER_DEBUG("Could not find lease or send offer");
+		return;
+	}
+
+	lease = add_lease(server, OFFER_TIME, client_msg->chaddr,
+				reply->yiaddr);
+	if (!lease) {
+		SERVER_DEBUG("No free IP addresses, OFFER abandoned");
+		return;
+	}
+
+	server_message_init(server, client_msg, reply);
+
+	_dhcp_message_builder_init(&builder, reply, len,
+					DHCP_MESSAGE_TYPE_OFFER);
+
+	_dhcp_message_builder_append(&builder,
+					L_DHCP_OPTION_IP_ADDRESS_LEASE_TIME,
+					4, &lease_time);
+
+	_dhcp_message_builder_append(&builder, L_DHCP_OPTION_SERVER_IDENTIFIER,
+					4, &server->address);
+
+	add_server_options(server, &builder);
+
+	_dhcp_message_builder_finalize(&builder, &len);
+
+	SERVER_DEBUG("Sending OFFER of %s to "MAC, IP_STR(reply->yiaddr),
+			MAC_STR(reply->chaddr));
+
+	if (server->transport->l2_send(server->transport, server->address,
+					DHCP_PORT_SERVER,
+					reply->ciaddr, DHCP_PORT_CLIENT,
+					reply->chaddr, reply, len) < 0)
+		SERVER_DEBUG("Failed to send OFFER");
+}
+
 static void listener_event(const void *data, size_t len, void *user_data)
 {
+	struct l_dhcp_server *server = user_data;
+	const struct dhcp_message *message = data;
+	struct dhcp_message_iter iter;
+	uint8_t t, l;
+	const void *v;
+	struct l_dhcp_lease *lease;
+	uint8_t type = 0;
+	uint32_t server_id_opt = 0;
+	uint32_t requested_ip_opt = 0;
+
+	SERVER_DEBUG("");
+
+	if (!_dhcp_message_iter_init(&iter, message, len))
+		return;
+
+	while (_dhcp_message_iter_next(&iter, &t, &l, &v)) {
+		switch (t) {
+		case DHCP_OPTION_MESSAGE_TYPE:
+			if (l == 1)
+				type = l_get_u8(v);
+
+			break;
+		case L_DHCP_OPTION_SERVER_IDENTIFIER:
+			if (l == 4)
+				server_id_opt = L_GET_UNALIGNED(
+							(const uint32_t *) v);
+
+			if (server->address != server_id_opt)
+				return;
+
+			break;
+		case L_DHCP_OPTION_REQUESTED_IP_ADDRESS:
+			if (l == 4)
+				requested_ip_opt = L_GET_UNALIGNED(
+							(const uint32_t *) v);
+
+			break;
+		}
+	}
+
+	if (type == 0)
+		return;
+
+	lease = find_lease_by_mac(server, message->chaddr);
+	if (!lease)
+		SERVER_DEBUG("No lease found for "MAC,
+					MAC_STR(message->chaddr));
+
+	switch (type) {
+	case DHCP_MESSAGE_TYPE_DISCOVER:
+		SERVER_DEBUG("Received DISCOVER, requested IP %s",
+					IP_STR(requested_ip_opt));
+
+		send_offer(server, message, lease, requested_ip_opt);
+
+		break;
+	}
 }
 
 bool _dhcp_server_set_transport(struct l_dhcp_server *server,
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 07/14] dhcp-server: add REQUEST processing
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (4 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 06/14] dhcp-server: process DISCOVER and send OFFER James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 08/14] dhcp-server: handle DECLINE messages James Prestwood
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3364 bytes --]

Handle REQUEST packets and implement ACK/NAK responses.
---
 ell/dhcp-server.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index 2edf4b4..9c7fd21 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -364,6 +364,73 @@ static void send_offer(struct l_dhcp_server *server,
 		SERVER_DEBUG("Failed to send OFFER");
 }
 
+static void send_nak(struct l_dhcp_server *server,
+			const struct dhcp_message *client_msg)
+{
+	struct dhcp_message_builder builder;
+	size_t len = sizeof(struct dhcp_message) + DHCP_MIN_OPTIONS_SIZE;
+	L_AUTO_FREE_VAR(struct dhcp_message *, reply);
+
+	reply = (struct dhcp_message *) l_new(uint8_t, len);
+
+	server_message_init(server, client_msg, reply);
+
+	_dhcp_message_builder_init(&builder, reply, len, DHCP_MESSAGE_TYPE_NAK);
+
+	_dhcp_message_builder_finalize(&builder, &len);
+
+	if (server->transport->l2_send(server->transport, server->address,
+					DHCP_PORT_SERVER, reply->ciaddr,
+					DHCP_PORT_CLIENT, MAC_BCAST_ADDR,
+					reply, len) < 0)
+		SERVER_DEBUG("Failed to send NACK");
+}
+
+static void send_ack(struct l_dhcp_server *server,
+			const struct dhcp_message *client_msg, uint32_t dest)
+{
+	struct dhcp_message_builder builder;
+	size_t len = sizeof(struct dhcp_message) + DHCP_MIN_OPTIONS_SIZE;
+	L_AUTO_FREE_VAR(struct dhcp_message *, reply);
+	uint32_t lease_time = L_CPU_TO_BE32(server->lease_seconds);
+	struct l_dhcp_lease *lease;
+
+	reply = (struct dhcp_message *) l_new(uint8_t, len);
+
+	server_message_init(server, client_msg, reply);
+
+	_dhcp_message_builder_init(&builder, reply, len, DHCP_MESSAGE_TYPE_ACK);
+
+	reply->yiaddr = dest;
+
+	_dhcp_message_builder_append(&builder,
+					L_DHCP_OPTION_IP_ADDRESS_LEASE_TIME,
+					4, &lease_time);
+
+	add_server_options(server, &builder);
+
+	_dhcp_message_builder_append(&builder, L_DHCP_OPTION_SERVER_IDENTIFIER,
+					4, &server->address);
+
+	_dhcp_message_builder_finalize(&builder, &len);
+
+	SERVER_DEBUG("Sending ACK to %s", IP_STR(reply->yiaddr));
+
+	if (server->transport->l2_send(server->transport, server->address,
+					DHCP_PORT_SERVER, reply->ciaddr,
+					DHCP_PORT_CLIENT,
+					reply->chaddr, reply, len) < 0) {
+		SERVER_DEBUG("Failed to send ACK");
+		return;
+	}
+
+	lease = add_lease(server, 0, reply->chaddr, reply->yiaddr);
+
+	if (server->event_handler)
+		server->event_handler(server, L_DHCP_SERVER_EVENT_NEW_LEASE,
+					server->user_data, lease);
+}
+
 static void listener_event(const void *data, size_t len, void *user_data)
 {
 	struct l_dhcp_server *server = user_data;
@@ -421,6 +488,26 @@ static void listener_event(const void *data, size_t len, void *user_data)
 
 		send_offer(server, message, lease, requested_ip_opt);
 
+		break;
+	case DHCP_MESSAGE_TYPE_REQUEST:
+		SERVER_DEBUG("Received REQUEST, requested IP %s",
+				IP_STR(requested_ip_opt));
+
+		if (requested_ip_opt == 0) {
+			requested_ip_opt = message->ciaddr;
+			if (requested_ip_opt == 0)
+				break;
+		}
+
+		if (lease && requested_ip_opt == lease->address) {
+			send_ack(server, message, lease->address);
+			break;
+		}
+
+		if (server_id_opt || !lease) {
+			send_nak(server, message);
+			break;
+		}
 		break;
 	}
 }
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 08/14] dhcp-server: handle DECLINE messages
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (5 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 07/14] dhcp-server: add REQUEST processing James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 09/14] dhcp-server: add RELEASE message support James Prestwood
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1349 bytes --]

Process DECLINE messages from clients and remove any pending
leases that were created during DISCOVER.
---
 ell/dhcp-server.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index 9c7fd21..68dc8dd 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -116,6 +116,18 @@ static struct l_dhcp_lease *find_lease_by_mac(struct l_dhcp_server *server,
 	return l_queue_find(server->lease_list, match_lease_mac, mac);
 }
 
+static void remove_lease(struct l_dhcp_server *server,
+				struct l_dhcp_lease *lease)
+{
+	l_queue_remove(server->lease_list, lease);
+
+	if (server->event_handler)
+		server->event_handler(server, L_DHCP_SERVER_EVENT_LEASE_EXPIRED,
+					server->user_data, lease);
+
+	_dhcp_lease_free(lease);
+}
+
 /* Clear the old lease and create the new one */
 static int get_lease(struct l_dhcp_server *server, uint32_t yiaddr,
 				const uint8_t *mac,
@@ -509,6 +521,16 @@ static void listener_event(const void *data, size_t len, void *user_data)
 			break;
 		}
 		break;
+	case DHCP_MESSAGE_TYPE_DECLINE:
+		SERVER_DEBUG("Received DECLINE");
+
+		if (!server_id_opt || !requested_ip_opt || !lease)
+			break;
+
+		if (requested_ip_opt == lease->address)
+			remove_lease(server, lease);
+
+		break;
 	}
 }
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 09/14] dhcp-server: add RELEASE message support
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (6 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 08/14] dhcp-server: handle DECLINE messages James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 10/14] dhcp-server: add INFORM message handling James Prestwood
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1534 bytes --]

Handle RELEASE messages from clients. If there is a valid lease
set the expire time to now which releases the IP but also allows
the client to reconnect and maintain the same IP so long as
it hadn't been leased out again.
---
 ell/dhcp-server.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index 68dc8dd..b7910d7 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -205,6 +205,20 @@ static struct l_dhcp_lease *add_lease(struct l_dhcp_server *server,
 	return lease;
 }
 
+static void lease_set_expire(struct l_dhcp_server *server,
+			struct l_dhcp_lease *lease, uint32_t expire)
+{
+	l_queue_remove(server->lease_list, lease);
+
+	lease->lifetime = expire;
+
+	l_queue_insert(server->lease_list, lease, compare_lifetime, NULL);
+
+	if (server->event_handler)
+		server->event_handler(server, L_DHCP_SERVER_EVENT_LEASE_EXPIRED,
+					server->user_data, lease);
+}
+
 static bool match_lease_ip(const void *data, const void *user_data)
 {
 	const struct l_dhcp_lease *lease = data;
@@ -530,6 +544,16 @@ static void listener_event(const void *data, size_t len, void *user_data)
 		if (requested_ip_opt == lease->address)
 			remove_lease(server, lease);
 
+		break;
+	case DHCP_MESSAGE_TYPE_RELEASE:
+		SERVER_DEBUG("Received RELEASE");
+
+		if (!server_id_opt || !lease)
+			break;
+
+		if (message->ciaddr == lease->address)
+			lease_set_expire(server, lease, time(NULL));
+
 		break;
 	}
 }
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 10/14] dhcp-server: add INFORM message handling
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (7 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 09/14] dhcp-server: add RELEASE message support James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 11/14] unit: update dhcp test to use new builder APIs James Prestwood
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1636 bytes --]

This allows clients to request local configuration details
if their IP is already configured.
---
 ell/dhcp-server.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/ell/dhcp-server.c b/ell/dhcp-server.c
index b7910d7..1eefda7 100644
--- a/ell/dhcp-server.c
+++ b/ell/dhcp-server.c
@@ -390,6 +390,30 @@ static void send_offer(struct l_dhcp_server *server,
 		SERVER_DEBUG("Failed to send OFFER");
 }
 
+static void send_inform(struct l_dhcp_server *server,
+				const struct dhcp_message *client_msg)
+{
+	struct dhcp_message_builder builder;
+	size_t len = sizeof(struct dhcp_message) + DHCP_MIN_OPTIONS_SIZE;
+	L_AUTO_FREE_VAR(struct dhcp_message *, reply);
+
+	reply = (struct dhcp_message *) l_new(uint8_t, len);
+
+	server_message_init(server, client_msg, reply);
+
+	_dhcp_message_builder_init(&builder, reply, len, DHCP_MESSAGE_TYPE_ACK);
+
+	add_server_options(server, &builder);
+
+	_dhcp_message_builder_finalize(&builder, &len);
+
+	if (server->transport->l2_send(server->transport, server->address,
+					DHCP_PORT_SERVER, reply->ciaddr,
+					DHCP_PORT_CLIENT, reply->chaddr,
+					reply, len) < 0)
+		SERVER_DEBUG("Failed to send INFORM");
+}
+
 static void send_nak(struct l_dhcp_server *server,
 			const struct dhcp_message *client_msg)
 {
@@ -555,6 +579,11 @@ static void listener_event(const void *data, size_t len, void *user_data)
 			lease_set_expire(server, lease, time(NULL));
 
 		break;
+	case DHCP_MESSAGE_TYPE_INFORM:
+		SERVER_DEBUG("Received INFORM");
+
+		send_inform(server, message);
+		break;
 	}
 }
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 11/14] unit: update dhcp test to use new builder APIs
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (8 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 10/14] dhcp-server: add INFORM message handling James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 12/14] examples: basic DHCP server example James Prestwood
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 3497 bytes --]

---
 unit/test-dhcp.c | 83 +++++++++++++++++++++---------------------------
 1 file changed, 37 insertions(+), 46 deletions(-)

diff --git a/unit/test-dhcp.c b/unit/test-dhcp.c
index 6ae8d71..955ed29 100644
--- a/unit/test-dhcp.c
+++ b/unit/test-dhcp.c
@@ -33,7 +33,7 @@
 #include <ell/ell.h>
 #include "ell/dhcp-private.h"
 
-static bool verbose = false;
+static bool verbose = true;
 static uint8_t client_packet[1024];
 static size_t client_packet_len;
 
@@ -365,9 +365,13 @@ static void test_option_8(const void *data)
 
 static void test_option_set(const void *data)
 {
-	static uint8_t result[64] = {'A', 'B', 'C', 'D' };
+	struct dhcp_message_builder builder;
+	struct dhcp_message *message;
+	size_t outlen;
+	uint8_t *msg_out;
+	unsigned int i;
+	static uint8_t result[sizeof(struct dhcp_message) + 64];
 	static uint8_t options[64] = {
-			'A', 'B', 'C', 'D',
 			160, 2, 0x11, 0x12,
 			0,
 			31, 8, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
@@ -377,51 +381,38 @@ static void test_option_set(const void *data)
 			255
 	};
 
-	size_t len, oldlen;
-	int pos, i;
-	uint8_t *opt;
+	message = (struct dhcp_message *)result;
 
-	assert(_dhcp_option_append(NULL, NULL, 0, 0, NULL) == -EINVAL);
-
-	len = 0;
-	opt = &result[0];
-	assert(_dhcp_option_append(&opt, NULL, 0, 0, NULL) == -EINVAL);
-	assert(opt == &result[0] && len == 0);
-
-	assert(_dhcp_option_append(&opt, &len, 0, 0, NULL) == -ENOBUFS);
-	assert(opt == &result[0] && len == 0);
-
-	opt = &result[4];
-	len = 1;
-	assert(_dhcp_option_append(&opt, &len, 0, 0, NULL) >= 0);
-	assert(opt == &result[5] && len == 0);
-
-	pos = 4;
-	len = 60;
-	while (pos < 64 && options[pos] != 255) {
-		opt = &result[pos];
-		oldlen = len;
-
-		assert(_dhcp_option_append(&opt, &len, options[pos],
-						options[pos + 1],
-						&options[pos + 2]) >= 0);
-
-		if (options[pos] == 0) {
-			assert(opt == &result[pos + 1]);
-			assert(len == oldlen - 1);
-			pos++;
-		} else {
-			assert(opt == &result[pos + 2 + options[pos + 1]]);
-			assert(len == oldlen - 2 - options[pos + 1]);
-			pos += 2 + options[pos + 1];
-		}
-	}
+	/* test a few failure conditions */
+	assert(!_dhcp_message_builder_init(NULL, NULL, 0, 0));
+	assert(!_dhcp_message_builder_init(&builder, message, 0, 0));
+
+	_dhcp_message_builder_init(&builder, message, sizeof(result),
+					DHCP_MESSAGE_TYPE_DISCOVER);
+	_dhcp_message_builder_append(&builder, 160, 2, options + 2);
+	_dhcp_message_builder_append(&builder, 0, 0, NULL);
+	_dhcp_message_builder_append(&builder, 31, 8, options + 7);
+	_dhcp_message_builder_append(&builder, 0, 0, NULL);
+	_dhcp_message_builder_append(&builder, 55, 3, options + 18);
+	_dhcp_message_builder_append(&builder, 17, 7, options + 23);
+	msg_out = _dhcp_message_builder_finalize(&builder, &outlen);
 
-	for (i = 0; i < pos; i++) {
-		if (verbose)
-			l_info("%2d: 0x%02x(0x%02x)\n",
-					i, result[i], options[i]);
-		assert(result[i] == options[i]);
+	/*
+	 * The builde APIs automatically append the type passed in during init
+	 * so we can skip over that in order to test the expected static data
+	 */
+
+	msg_out += sizeof(struct dhcp_message) + 3;
+
+	for (i = 0; i < outlen - sizeof(struct dhcp_message); i++) {
+		if (msg_out[i] != options[i]) {
+			if (verbose) {
+				l_info("byte[%d] did not match 0x%02x 0x%02x",
+					i, msg_out[i], options[i]);
+			}
+
+			assert(false);
+		}
 	}
 }
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 12/14] examples: basic DHCP server example
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (9 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 11/14] unit: update dhcp test to use new builder APIs James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 13/14] unit: add complete client/server dhcp test James Prestwood
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4992 bytes --]

---
 .gitignore             |   1 +
 Makefile.am            |   4 +-
 examples/dhcp-server.c | 129 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100644 examples/dhcp-server.c

diff --git a/.gitignore b/.gitignore
index c3d2790..e963359 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,6 +76,7 @@ examples/dbus-client
 examples/glib-eventloop
 examples/dhcp-client
 examples/dhcp6-client
+examples/dhcp-server
 test-suite.log
 tools/certchain-verify
 tools/genl-discover
diff --git a/Makefile.am b/Makefile.am
index 9bdf4dc..adedd1f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -326,7 +326,8 @@ unit_test_data_files = unit/settings.test unit/dbus.conf
 
 examples = examples/dbus-service examples/https-client-test \
 		examples/https-server-test examples/dbus-client \
-		examples/dhcp-client examples/dhcp6-client
+		examples/dhcp-client examples/dhcp6-client \
+		examples/dhcp-server
 
 if GLIB
 examples += examples/glib-eventloop
@@ -344,6 +345,7 @@ examples_glib_eventloop_CFLAGS = @GLIB_CFLAGS@
 examples_glib_eventloop_LDADD = ell/libell-private.la @GLIB_LIBS@
 examples_dhcp_client_LDADD = ell/libell-private.la
 examples_dhcp6_client_LDADD = ell/libell-private.la
+examples_dhcp_server_LDADD = ell/libell-private.la
 
 noinst_PROGRAMS += tools/certchain-verify tools/genl-discover \
 		   tools/genl-watch tools/genl-request tools/gpio
diff --git a/examples/dhcp-server.c b/examples/dhcp-server.c
new file mode 100644
index 0000000..33c0983
--- /dev/null
+++ b/examples/dhcp-server.c
@@ -0,0 +1,129 @@
+/*
+ *
+ *  Embedded Linux library
+ *
+ *  Copyright (C) 2020  Intel Corporation. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it 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.
+ *
+ *  This library 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 this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <linux/if_arp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ell/ell.h>
+
+static void do_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	l_info("%s%s", prefix, str);
+}
+
+static void signal_handler(uint32_t signo, void *user_data)
+{
+	switch (signo) {
+	case SIGINT:
+	case SIGTERM:
+		l_info("Terminate");
+		l_main_quit();
+		break;
+	}
+}
+
+static void destroy_handler(void *data)
+{
+	l_info("DHCP server destroyed");
+}
+
+static void event_handler(struct l_dhcp_server *server,
+					enum l_dhcp_server_event event,
+					void *userdata,
+					const struct l_dhcp_lease *lease)
+{
+	const uint8_t *mac;
+	char *ip;
+
+	switch (event) {
+	case L_DHCP_SERVER_EVENT_NEW_LEASE:
+		mac = l_dhcp_lease_get_mac(lease);
+		ip = l_dhcp_lease_get_address(lease);
+
+		l_info("New lease client %02x:%02x:%02x:%02x:%02x:%02x %s",
+				mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+				ip);
+		l_free(ip);
+		break;
+	case L_DHCP_SERVER_EVENT_LEASE_EXPIRED:
+		break;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct l_dhcp_server *server;
+	int ifindex;
+	uint8_t mac[6];
+	char *dns[] = { "192.168.1.1", NULL };
+
+	if (argc < 2) {
+		printf("Usage: %s <interface index>\n", argv[0]);
+		exit(0);
+	}
+
+	ifindex = atoi(argv[1]);
+
+	if (!l_net_get_mac_address(ifindex, mac)) {
+		printf("Unable to get address from interface %d\n", ifindex);
+		exit(0);
+	}
+
+	if (!l_main_init())
+		return -1;
+
+	l_log_set_stderr();
+	l_debug_enable("*");
+
+	server = l_dhcp_server_new(ifindex);
+	l_dhcp_server_set_ip_range(server, "192.168.1.2", "192.168.1.100");
+	l_dhcp_server_set_netmask(server, "255.255.255.0");
+	l_dhcp_server_set_gateway(server, "192.168.1.1");
+	l_dhcp_server_set_dns(server, dns);
+	l_dhcp_server_set_lease_time(server, 10);
+	l_dhcp_server_set_debug(server, do_debug, "[DHCP SERV] ", NULL);
+	l_dhcp_server_set_event_handler(server, event_handler, NULL,
+						destroy_handler);
+	l_dhcp_server_start(server);
+
+	l_main_run_with_signal(signal_handler, NULL);
+
+	l_dhcp_server_stop(server);
+	l_dhcp_server_destroy(server);
+	l_main_exit();
+
+	return 0;
+}
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 13/14] unit: add complete client/server dhcp test
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (10 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 12/14] examples: basic DHCP server example James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 17:39 ` [PATCH v3 14/14] dhcp: Add support for setting address James Prestwood
  2020-10-16 18:58 ` [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast Denis Kenzior
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 5627 bytes --]

---
 unit/test-dhcp.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 161 insertions(+)

diff --git a/unit/test-dhcp.c b/unit/test-dhcp.c
index 955ed29..a481247 100644
--- a/unit/test-dhcp.c
+++ b/unit/test-dhcp.c
@@ -36,6 +36,8 @@
 static bool verbose = true;
 static uint8_t client_packet[1024];
 static size_t client_packet_len;
+static uint8_t server_packet[1024];
+static size_t server_packet_len;
 
 static void test_request_option(const void *data)
 {
@@ -736,6 +738,163 @@ static void test_discover(const void *data)
 	l_dhcp_client_destroy(client);
 }
 
+static bool l2_send_called = false;
+
+static int fake_transport_server_l2_send(struct dhcp_transport *s,
+					uint32_t source_ip,
+					uint16_t source_port,
+					uint32_t dest_ip,
+					uint16_t dest_port,
+					const uint8_t *dest_arp,
+					const void *data, size_t len)
+{
+	assert(len <= sizeof(server_packet));
+	memcpy(server_packet, data, len);
+	server_packet_len = len;
+
+	l2_send_called = true;
+
+	return 0;
+}
+
+static void server_event_handler(struct l_dhcp_server *server,
+					enum l_dhcp_server_event event,
+					void *userdata,
+					const struct l_dhcp_lease *lease)
+{
+	const uint8_t expected_mac[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+	const uint8_t *mac;
+	char *ip;
+
+	switch (event) {
+	case L_DHCP_SERVER_EVENT_NEW_LEASE:
+		mac = l_dhcp_lease_get_mac(lease);
+		ip = l_dhcp_lease_get_address(lease);
+
+		assert(!memcmp(mac, expected_mac, sizeof(expected_mac)));
+		assert(!strcmp(ip, "192.168.1.2"));
+
+		l_free(ip);
+		break;
+	case L_DHCP_SERVER_EVENT_LEASE_EXPIRED:
+		break;
+	}
+}
+
+static void do_debug(const char *str, void *user_data)
+{
+	const char *prefix = user_data;
+
+	l_info("%s%s", prefix, str);
+}
+
+static void test_complete_run(const void *data)
+{
+	static const uint8_t addr[6] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+	char *dns[] = { "192.168.1.1", "192.168.1.254", NULL };
+	struct l_dhcp_client *client;
+	struct l_dhcp_server *server;
+	struct dhcp_transport *cli_transport = l_new(struct dhcp_transport, 1);
+	struct dhcp_transport *srv_transport = l_new(struct dhcp_transport, 1);
+	const struct l_dhcp_lease *cli_lease;
+	/* client IP address */
+	char *cli_addr;
+	/* servers IP address */
+	char *srv_addr;
+	char *tmp_addr;
+	char **dns_list;
+
+	server = l_dhcp_server_new(41);
+
+	assert(l_dhcp_server_set_interface_name(server, "fake"));
+	assert(l_dhcp_server_set_ip_address(server, "192.168.1.1"));
+	assert(l_dhcp_server_set_ip_range(server, "192.168.1.2",
+						"192.168.1.100"));
+	assert(l_dhcp_server_set_netmask(server, "255.255.255.0"));
+	assert(l_dhcp_server_set_gateway(server, "192.168.1.1"));
+	assert(l_dhcp_server_set_dns(server, dns));
+	assert(l_dhcp_server_set_event_handler(server, server_event_handler,
+						NULL, NULL));
+
+	if (verbose)
+		l_dhcp_server_set_debug(server, do_debug, "[DHCP SERV] ", NULL);
+
+	srv_transport->ifindex = 41;
+	srv_transport->l2_send = fake_transport_server_l2_send;
+
+	assert(_dhcp_server_set_transport(server, srv_transport));
+
+	assert(l_dhcp_server_start(server));
+
+	client = l_dhcp_client_new(42);
+
+	assert(l_dhcp_client_set_address(client, ARPHRD_ETHER, addr, 6));
+	assert(l_dhcp_client_set_interface_name(client, "fake"));
+	assert(l_dhcp_client_set_hostname(client, "<hostname>"));
+	_dhcp_client_override_xid(client, 0x4d7c67c6);
+	assert(l_dhcp_client_set_event_handler(client,
+				event_handler_lease_obtained, NULL, NULL));
+
+	if (verbose)
+		l_dhcp_client_set_debug(client, do_debug, "[DHCP] ", NULL);
+
+	cli_transport->send = fake_transport_send;
+	cli_transport->l2_send = fake_transport_l2_send;
+	cli_transport->ifindex = 42;
+
+	assert(_dhcp_client_set_transport(client, cli_transport));
+
+	assert(l_dhcp_client_start(client));
+
+	/* RX DISCOVER */
+	srv_transport->rx_cb(client_packet, client_packet_len, server);
+	assert(l2_send_called);
+	l2_send_called = false;
+
+	/* RX OFFER */
+	cli_transport->rx_cb(server_packet, server_packet_len, client);
+
+	/* RX REQUEST */
+	srv_transport->rx_cb(client_packet, client_packet_len, server);
+	assert(l2_send_called);
+	l2_send_called = false;
+
+	/* RX ACK */
+	cli_transport->rx_cb(server_packet, server_packet_len, client);
+
+	assert(event_handler_called);
+
+	cli_lease = l_dhcp_client_get_lease(client);
+	assert(cli_lease);
+	cli_addr = l_dhcp_lease_get_address(cli_lease);
+	assert(cli_addr);
+	assert(!strcmp(cli_addr, "192.168.1.2"));
+	srv_addr = l_dhcp_lease_get_server_id(cli_lease);
+	assert(!strcmp(srv_addr, "192.168.1.1"));
+	l_free(srv_addr);
+	l_free(cli_addr);
+
+	tmp_addr = l_dhcp_lease_get_gateway(cli_lease);
+	assert(!strcmp(tmp_addr, "192.168.1.1"));
+	l_free(tmp_addr);
+
+	tmp_addr = l_dhcp_lease_get_netmask(cli_lease);
+	assert(!strcmp(tmp_addr, "255.255.255.0"));
+	l_free(tmp_addr);
+
+	dns_list = l_dhcp_lease_get_dns(cli_lease);
+	assert(dns_list && dns_list[0] && dns_list[1]);
+	assert(!strcmp(dns_list[0], "192.168.1.1"));
+	assert(!strcmp(dns_list[1], "192.168.1.254"));
+	l_strv_free(dns_list);
+
+	l_dhcp_client_stop(client);
+	l_dhcp_client_destroy(client);
+
+	l_dhcp_server_stop(server);
+	l_dhcp_server_destroy(server);
+}
+
 int main(int argc, char *argv[])
 {
 	l_test_init(&argc, &argv);
@@ -759,5 +918,7 @@ int main(int argc, char *argv[])
 
 	l_test_add("discover", test_discover, NULL);
 
+	l_test_add("complete run", test_complete_run, NULL);
+
 	return l_test_run();
 }
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v3 14/14] dhcp: Add support for setting address
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (11 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 13/14] unit: add complete client/server dhcp test James Prestwood
@ 2020-10-16 17:39 ` James Prestwood
  2020-10-16 18:58 ` [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast Denis Kenzior
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-16 17:39 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4821 bytes --]

Add optional support for the dhcp client to set the DHCP
address automatically. This is done by providing an RTNL
object with l_dhcp_client_set_rtnl.
---
 ell/dhcp.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/dhcp.h |  4 +++
 2 files changed, 88 insertions(+)

v3:
 * Fixed issue with assuming a prefix length of 24
 * Set broadcast address

diff --git a/ell/dhcp.c b/ell/dhcp.c
index d75d86f..1e261c2 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -29,6 +29,7 @@
 #include <linux/types.h>
 #include <net/if_arp.h>
 #include <errno.h>
+#include <arpa/inet.h>
 
 #include "private.h"
 #include "random.h"
@@ -38,6 +39,8 @@
 #include "timeout.h"
 #include "dhcp.h"
 #include "dhcp-private.h"
+#include "netlink.h"
+#include "rtnl.h"
 
 #define CLIENT_DEBUG(fmt, args...)					\
 	l_util_debug(client->debug_handler, client->debug_data,		\
@@ -178,6 +181,9 @@ struct l_dhcp_client {
 	struct l_timeout *timeout_resend;
 	struct l_timeout *timeout_lease;
 	struct l_dhcp_lease *lease;
+	struct l_netlink *rtnl;
+	uint32_t rtnl_add_cmdid;
+	struct l_rtnl_address *rtnl_configured_address;
 	uint8_t attempt;
 	l_dhcp_client_event_cb_t event_handler;
 	void *event_data;
@@ -583,6 +589,24 @@ error:
 	l_dhcp_client_stop(client);
 }
 
+static void dhcp_client_address_add_cb(int error, uint16_t type,
+						const void *data, uint32_t len,
+						void *user_data)
+{
+	struct l_dhcp_client *client = user_data;
+
+	client->rtnl_add_cmdid = 0;
+
+	if (error < 0 && error != -EEXIST) {
+		l_rtnl_address_free(client->rtnl_configured_address);
+		client->rtnl_configured_address = NULL;
+		CLIENT_DEBUG("Unable to set address on ifindex: %u: %d(%s)",
+				client->ifindex, error,
+				strerror(-error));
+		return;
+	}
+}
+
 static int dhcp_client_receive_ack(struct l_dhcp_client *client,
 					const struct dhcp_message *ack,
 					size_t len)
@@ -626,6 +650,40 @@ static int dhcp_client_receive_ack(struct l_dhcp_client *client,
 			client->state == DHCP_STATE_REBOOTING)
 		r = L_DHCP_CLIENT_EVENT_LEASE_OBTAINED;
 
+	if (client->rtnl) {
+		struct l_rtnl_address *a;
+		L_AUTO_FREE_VAR(char *, ip) =
+			l_dhcp_lease_get_address(client->lease);
+		uint8_t prefix_len;
+		uint32_t l = l_dhcp_lease_get_lifetime(client->lease);
+		char *netmask = l_dhcp_lease_get_netmask(client->lease);
+		char *broadcast = l_dhcp_lease_get_broadcast(client->lease);
+		struct in_addr in_addr;
+
+		if (inet_pton(AF_INET, netmask, &in_addr) > 0)
+			prefix_len = __builtin_popcountl(in_addr.s_addr);
+		else
+			prefix_len = 24;
+
+		l_free(netmask);
+
+		a = l_rtnl_address_new(ip, prefix_len);
+		l_rtnl_address_set_noprefixroute(a, true);
+		l_rtnl_address_set_lifetimes(a, l, l);
+		l_rtnl_address_set_broadcast(a, broadcast);
+
+		l_free(broadcast);
+
+		client->rtnl_add_cmdid =
+			l_rtnl_ifaddr_add(client->rtnl, client->ifindex, a,
+						dhcp_client_address_add_cb,
+						client, NULL);
+		if (client->rtnl_add_cmdid)
+			client->rtnl_configured_address = a;
+		else
+			CLIENT_DEBUG("Configuring address via RTNL failed");
+	}
+
 	return r;
 }
 
@@ -989,6 +1047,19 @@ LIB_EXPORT bool l_dhcp_client_stop(struct l_dhcp_client *client)
 	if (unlikely(!client))
 		return false;
 
+	if (client->rtnl_add_cmdid) {
+		l_netlink_cancel(client->rtnl, client->rtnl_add_cmdid);
+		client->rtnl_add_cmdid = 0;
+	}
+
+	if (client->rtnl_configured_address) {
+		l_rtnl_ifaddr_delete(client->rtnl, client->ifindex,
+					client->rtnl_configured_address,
+					NULL, NULL, NULL);
+		l_rtnl_address_free(client->rtnl_configured_address);
+		client->rtnl_configured_address = NULL;
+	}
+
 	l_timeout_remove(client->timeout_resend);
 	client->timeout_resend = NULL;
 
@@ -1042,3 +1113,16 @@ LIB_EXPORT bool l_dhcp_client_set_debug(struct l_dhcp_client *client,
 
 	return true;
 }
+
+LIB_EXPORT bool l_dhcp_client_set_rtnl(struct l_dhcp_client *client,
+					struct l_netlink *rtnl)
+{
+	if (unlikely(!client))
+		return false;
+
+	if (unlikely(client->state != DHCP_STATE_INIT))
+		return false;
+
+	client->rtnl = rtnl;
+	return true;
+}
diff --git a/ell/dhcp.h b/ell/dhcp.h
index 0dc349e..e586740 100644
--- a/ell/dhcp.h
+++ b/ell/dhcp.h
@@ -31,6 +31,7 @@ extern "C" {
 
 struct l_dhcp_client;
 struct l_dhcp_lease;
+struct l_netlink;
 struct l_dhcp_server;
 
 /* RFC 2132 */
@@ -85,6 +86,9 @@ bool l_dhcp_client_set_interface_name(struct l_dhcp_client *client,
 bool l_dhcp_client_set_hostname(struct l_dhcp_client *client,
 							const char *hostname);
 
+bool l_dhcp_client_set_rtnl(struct l_dhcp_client *client,
+					struct l_netlink *rtnl);
+
 const struct l_dhcp_lease *l_dhcp_client_get_lease(
 					const struct l_dhcp_client *client);
 
-- 
2.26.2

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast
  2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
                   ` (12 preceding siblings ...)
  2020-10-16 17:39 ` [PATCH v3 14/14] dhcp: Add support for setting address James Prestwood
@ 2020-10-16 18:58 ` Denis Kenzior
  13 siblings, 0 replies; 15+ messages in thread
From: Denis Kenzior @ 2020-10-16 18:58 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1095 bytes --]

Hi James,

On 10/16/20 12:39 PM, James Prestwood wrote:
> Functionally this was being used as a broadcast only because the
> destination address was a broadcast address. But providing a
> MAC address would effectively turn this into a unicast over l2
> which DHCP server requires.
> 
> To support server a destination MAC address was added to the
> arguments and if NULL the destination will be set to a broadcast
> address. The name of the op was changed to 'l2_send' to better
> describe the new behavior. All client code will remain nearly the
> same (just name changes) except having to set the destination MAC
> to NULL indicating it is a broadcast.
> ---
>   ell/dhcp-private.h   |  3 ++-
>   ell/dhcp-transport.c | 10 +++++++---
>   ell/dhcp.c           |  7 ++++---
>   3 files changed, 13 insertions(+), 7 deletions(-)
> 
> v3:
>   * Reworded commit description to be more clear that the original op
>     was a broadcast only operation and was modified to work with
>     both broadcast and unicast on l2
> 

Patches 1-3 applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-10-16 18:58 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-16 17:39 [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast James Prestwood
2020-10-16 17:39 ` [PATCH v3 02/14] unit: update test-dhcp to use l2_send James Prestwood
2020-10-16 17:39 ` [PATCH v3 03/14] dhcp-lease: add mac member and getter James Prestwood
2020-10-16 17:39 ` [PATCH v3 04/14] dhcp-server: basic DHCP server skeleton James Prestwood
2020-10-16 17:39 ` [PATCH v3 05/14] dhcp-server: add transport framework James Prestwood
2020-10-16 17:39 ` [PATCH v3 06/14] dhcp-server: process DISCOVER and send OFFER James Prestwood
2020-10-16 17:39 ` [PATCH v3 07/14] dhcp-server: add REQUEST processing James Prestwood
2020-10-16 17:39 ` [PATCH v3 08/14] dhcp-server: handle DECLINE messages James Prestwood
2020-10-16 17:39 ` [PATCH v3 09/14] dhcp-server: add RELEASE message support James Prestwood
2020-10-16 17:39 ` [PATCH v3 10/14] dhcp-server: add INFORM message handling James Prestwood
2020-10-16 17:39 ` [PATCH v3 11/14] unit: update dhcp test to use new builder APIs James Prestwood
2020-10-16 17:39 ` [PATCH v3 12/14] examples: basic DHCP server example James Prestwood
2020-10-16 17:39 ` [PATCH v3 13/14] unit: add complete client/server dhcp test James Prestwood
2020-10-16 17:39 ` [PATCH v3 14/14] dhcp: Add support for setting address James Prestwood
2020-10-16 18:58 ` [PATCH v3 01/14] dhcp-transport: rework 'broadcast' op to allow unicast Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.