All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 01/14] net: add l_net_get_ip_address()
@ 2020-10-15 17:17 James Prestwood
  2020-10-15 17:17 ` [PATCH 02/14] dhcp-util: add dhcp message builder APIs James Prestwood
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

---
 ell/net.c | 32 ++++++++++++++++++++++++++++++++
 ell/net.h |  1 +
 2 files changed, 33 insertions(+)

diff --git a/ell/net.c b/ell/net.c
index 0bff535..5551779 100644
--- a/ell/net.c
+++ b/ell/net.c
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/ioctl.h>
+#include <netinet/ip.h>
 
 #include "net.h"
 #include "net-private.h"
@@ -336,3 +337,34 @@ char **net_domain_list_parse(const uint8_t *raw, size_t raw_len)
 
 	return ret;
 }
+
+LIB_EXPORT uint32_t l_net_get_ip_address(int ifindex)
+{
+	struct ifreq ifr;
+	int sk, err;
+	struct sockaddr_in *server_ip;
+	uint32_t ret = 0;
+
+	sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (sk < 0)
+		return 0;
+
+	memset(&ifr, 0, sizeof(ifr));
+	ifr.ifr_ifindex = ifindex;
+
+	err = ioctl(sk, SIOCGIFNAME, &ifr);
+	if (err < 0)
+		goto done;
+
+	err = ioctl(sk, SIOCGIFADDR, &ifr);
+	if (err < 0)
+		goto done;
+
+	server_ip = (struct sockaddr_in *) &ifr.ifr_addr;
+	ret = server_ip->sin_addr.s_addr;
+
+done:
+	close(sk);
+
+	return ret;
+}
diff --git a/ell/net.h b/ell/net.h
index 6808e07..abaf785 100644
--- a/ell/net.h
+++ b/ell/net.h
@@ -34,6 +34,7 @@ bool l_net_get_mac_address(uint32_t ifindex, uint8_t *out_addr);
 char *l_net_get_name(uint32_t ifindex);
 bool l_net_hostname_is_root(const char *hostname);
 bool l_net_hostname_is_localhost(const char *hostname);
+uint32_t l_net_get_ip_address(int ifindex);
 
 #ifdef __cplusplus
 }
-- 
2.26.2

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

* [PATCH 02/14] dhcp-util: add dhcp message builder APIs
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 03/14] dhcp: update client code to use " James Prestwood
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

A new file was added, dhcp-util.c. Some enums/constant values
were moved from dhcp.c into dhcp-private.h for use with the
new builder APIs.
---
 Makefile.am        |   1 +
 ell/dhcp-private.h |  33 ++++++++++
 ell/dhcp-util.c    | 160 +++++++++++++++++++++++++++++++++++++++++++++
 ell/dhcp.c         |  16 -----
 4 files changed, 194 insertions(+), 16 deletions(-)
 create mode 100644 ell/dhcp-util.c

diff --git a/Makefile.am b/Makefile.am
index 9b3e3c9..beba535 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -127,6 +127,7 @@ ell_libell_la_SOURCES = $(linux_headers) \
 			ell/dhcp6.c \
 			ell/dhcp6-transport.c \
 			ell/dhcp6-lease.c \
+			ell/dhcp-util.c \
 			ell/cert.c \
 			ell/cert-private.h \
 			ell/ecc-private.h \
diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index a75bb8b..3aa89fb 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -27,6 +27,17 @@ enum {
 	DHCP_PORT_CLIENT = 68,
 };
 
+enum dhcp_message_type {
+	DHCP_MESSAGE_TYPE_DISCOVER = 1,
+	DHCP_MESSAGE_TYPE_OFFER = 2,
+	DHCP_MESSAGE_TYPE_REQUEST = 3,
+	DHCP_MESSAGE_TYPE_DECLINE = 4,
+	DHCP_MESSAGE_TYPE_ACK = 5,
+	DHCP_MESSAGE_TYPE_NAK = 6,
+	DHCP_MESSAGE_TYPE_RELEASE = 7,
+	DHCP_MESSAGE_TYPE_INFORM = 8,
+};
+
 /* RFC 2131, Table 1 */
 enum dhcp_op_code {
 	DHCP_OP_CODE_BOOTREQUEST = 1,
@@ -35,6 +46,11 @@ enum dhcp_op_code {
 
 #define DHCP_MAGIC 0x63825363
 
+/* RFC 2132, Section 9.6. DHCP Message Type */
+#define DHCP_OPTION_MESSAGE_TYPE 53
+#define DHCP_OPTION_PAD 0 /* RFC 2132, Section 3.1 */
+#define DHCP_OPTION_END 255 /* RFC 2132, Section 3.2 */
+
 /* RFC 2131, Figure 1 */
 struct dhcp_message {
 	uint8_t op;
@@ -126,3 +142,20 @@ struct l_dhcp_lease {
 struct l_dhcp_lease *_dhcp_lease_new(void);
 void _dhcp_lease_free(struct l_dhcp_lease *lease);
 struct l_dhcp_lease *_dhcp_lease_parse_options(struct dhcp_message_iter *iter);
+
+struct dhcp_message_builder {
+	unsigned int max;
+	uint8_t *pos;
+	uint8_t *start;
+};
+
+bool _dhcp_message_builder_init(struct dhcp_message_builder *builder,
+				struct dhcp_message *message,
+				size_t len, uint8_t type);
+bool _dhcp_message_builder_append(struct dhcp_message_builder *builder,
+					uint8_t code, size_t optlen,
+					const void *optval);
+bool _dhcp_message_builder_append_prl(struct dhcp_message_builder *builder,
+					const unsigned long *reqopts);
+uint8_t *_dhcp_message_builder_finalize(struct dhcp_message_builder *builder,
+					size_t *outlen);
diff --git a/ell/dhcp-util.c b/ell/dhcp-util.c
new file mode 100644
index 0000000..44ab1e2
--- /dev/null
+++ b/ell/dhcp-util.c
@@ -0,0 +1,160 @@
+/*
+ *
+ *  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
+ *
+ */
+#include <stdint.h>
+#include <linux/types.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "dhcp-private.h"
+#include "private.h"
+
+#define BITS_PER_LONG (sizeof(unsigned long) * 8)
+
+static void dhcp_init_header(struct dhcp_message *message, uint8_t type)
+{
+	switch (type) {
+	case DHCP_MESSAGE_TYPE_OFFER:
+	case DHCP_MESSAGE_TYPE_NAK:
+	case DHCP_MESSAGE_TYPE_ACK:
+		message->op = DHCP_OP_CODE_BOOTREPLY;
+		break;
+	default:
+		message->op = DHCP_OP_CODE_BOOTREQUEST;
+		break;
+	}
+
+	message->htype = 1;
+	message->hlen = 6;
+	message->magic = htonl(DHCP_MAGIC);
+	message->options[0] = DHCP_OPTION_END;
+}
+
+#define LEN_CHECK(builder, next) \
+	if (builder->pos - builder->start + next > builder->max) \
+		return false;
+
+bool _dhcp_message_builder_append(struct dhcp_message_builder *builder,
+					uint8_t code, size_t optlen,
+					const void *optval)
+{
+	switch (code) {
+	case DHCP_OPTION_PAD:
+	case DHCP_OPTION_END:
+		LEN_CHECK(builder, 1);
+
+		builder->pos[0] = code;
+		builder->pos += 1;
+		break;
+	default:
+		LEN_CHECK(builder, optlen + 2);
+
+		builder->pos[0] = code;
+		builder->pos[1] = optlen;
+		memcpy(builder->pos + 2, optval, optlen);
+
+		builder->pos += optlen + 2;
+		break;
+	}
+
+	return true;
+}
+
+bool _dhcp_message_builder_append_prl(struct dhcp_message_builder *builder,
+					const unsigned long *reqopts)
+{
+	uint8_t optlen = 0;
+	unsigned int i;
+	unsigned int j;
+
+	for (i = 0; i < 256 / BITS_PER_LONG; i++)
+		optlen += __builtin_popcountl(reqopts[i]);
+
+	/*
+	 * This function assumes that there's enough space to put the PRL
+	 * into the buffer without resorting to file or sname overloading
+	 */
+	LEN_CHECK(builder, optlen + 2U);
+
+	i = 0;
+	builder->pos[i++] = DHCP_OPTION_PARAMETER_REQUEST_LIST;
+	builder->pos[i++] = optlen;
+
+	for (j = 0; j < 256; j++) {
+		if (reqopts[j / BITS_PER_LONG] & 1UL << (j % BITS_PER_LONG)) {
+			builder->pos[i++] = j;
+		}
+	}
+
+	builder->pos += optlen + 2;
+
+	return true;
+}
+
+bool _dhcp_message_builder_init(struct dhcp_message_builder *builder,
+				struct dhcp_message *message,
+				size_t len, uint8_t type)
+{
+	if (!builder || !message || !len)
+		return false;
+
+	builder->max = len;
+	builder->pos = (uint8_t *) message->options;
+	builder->start = (uint8_t *) message;
+
+	dhcp_init_header(message, type);
+
+	return _dhcp_message_builder_append(builder, DHCP_OPTION_MESSAGE_TYPE,
+						1, &type);
+}
+
+static inline int dhcp_message_optimize(struct dhcp_message *message,
+					const uint8_t *end)
+{
+	/*
+	 * Don't bother sending a full sized dhcp_message as it is most likely
+	 * mostly zeros.  Instead truncate it at DHCP_OPTION_END and align to
+	 * the nearest 4 byte boundary.  Many implementations expect a packet
+	 * of a certain size or it is filtered, so we cap the length in
+	 * accordance to RFC 1542:
+	 * "The IP Total Length and UDP Length must be large enough to contain
+	 * the minimal BOOTP header of 300 octets"
+	 */
+	size_t len = align_len(end - (uint8_t *) message, 4);
+	if (len < 300)
+		len = 300;
+
+	return len;
+}
+
+uint8_t *_dhcp_message_builder_finalize(struct dhcp_message_builder *builder,
+					size_t *outlen)
+{
+	_dhcp_message_builder_append(builder, DHCP_OPTION_END, 0, NULL);
+
+	*outlen = dhcp_message_optimize((struct dhcp_message *)builder->start,
+				builder->pos);
+
+	return builder->start;
+}
diff --git a/ell/dhcp.c b/ell/dhcp.c
index fd548b5..097bf3d 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -50,9 +50,6 @@
 
 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
 
-#define DHCP_OPTION_PAD 0 /* RFC 2132, Section 3.1 */
-#define DHCP_OPTION_END 255 /* RFC 2132, Section 3.2 */
-
 /* RFC 2132, Section 9.3. Option Overload */
 #define DHCP_OPTION_OVERLOAD 52
 enum dhcp_option_overload {
@@ -61,19 +58,6 @@ enum dhcp_option_overload {
 	DHCP_OVERLOAD_BOTH = 3,
 };
 
-/* RFC 2132, Section 9.6. DHCP Message Type */
-#define DHCP_OPTION_MESSAGE_TYPE 53
-enum dhcp_message_type {
-	DHCP_MESSAGE_TYPE_DISCOVER = 1,
-	DHCP_MESSAGE_TYPE_OFFER = 2,
-	DHCP_MESSAGE_TYPE_REQUEST = 3,
-	DHCP_MESSAGE_TYPE_DECLINE = 4,
-	DHCP_MESSAGE_TYPE_ACK = 5,
-	DHCP_MESSAGE_TYPE_NAK = 6,
-	DHCP_MESSAGE_TYPE_RELEASE = 7,
-	DHCP_MESSAGE_TYPE_INFORM = 8,
-};
-
 #define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* Section 9.8 */
 #define DHCP_OPTION_MAXIMUM_MESSAGE_SIZE 57 /* Section 9.10 */
 #define DHCP_OPTION_CLIENT_IDENTIFIER 61 /* Section 9.14 */
-- 
2.26.2

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

* [PATCH 03/14] dhcp: update client code to use builder APIs
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
  2020-10-15 17:17 ` [PATCH 02/14] dhcp-util: add dhcp message builder APIs James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 04/14] dhcp-util: move iter APIs to dhcp-util James Prestwood
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

---
 ell/dhcp.c | 146 +++++++++++++++--------------------------------------
 1 file changed, 41 insertions(+), 105 deletions(-)

diff --git a/ell/dhcp.c b/ell/dhcp.c
index 097bf3d..d2be894 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -301,61 +301,6 @@ int _dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code,
 	return 0;
 }
 
-static int dhcp_append_prl(const unsigned long *reqopts,
-					uint8_t **buf, size_t *buflen)
-{
-	uint8_t optlen = 0;
-	unsigned int i;
-	unsigned int j;
-
-	if (!buf || !buflen)
-		return -EINVAL;
-
-	for (i = 0; i < 256 / BITS_PER_LONG; i++)
-		optlen += __builtin_popcountl(reqopts[i]);
-
-	/*
-	 * This function assumes that there's enough space to put the PRL
-	 * into the buffer without resorting to file or sname overloading
-	 */
-	if (*buflen < optlen + 2U)
-		return -ENOBUFS;
-
-	i = 0;
-	(*buf)[i++] = DHCP_OPTION_PARAMETER_REQUEST_LIST;
-	(*buf)[i++] = optlen;
-
-	for (j = 0; j < 256; j++) {
-		if (reqopts[j / BITS_PER_LONG] & 1UL << (j % BITS_PER_LONG))
-			(*buf)[i++] = j;
-	}
-
-	*buf += optlen + 2;
-	*buflen -= (optlen + 2);
-
-	return 0;
-}
-
-static int dhcp_message_init(struct dhcp_message *message,
-				enum dhcp_op_code op,
-				uint8_t type, uint32_t xid,
-				uint8_t **opt, size_t *optlen)
-{
-	int err;
-
-	message->op = op;
-	message->xid = L_CPU_TO_BE32(xid);
-	message->magic = L_CPU_TO_BE32(DHCP_MAGIC);
-	*opt = (uint8_t *)(message + 1);
-
-	err = _dhcp_option_append(opt, optlen,
-					DHCP_OPTION_MESSAGE_TYPE, 1, &type);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
 static void dhcp_message_set_address_type(struct dhcp_message *message,
 						uint8_t addr_type,
 						uint8_t addr_len)
@@ -504,16 +449,13 @@ static uint32_t dhcp_rebind_renew_retry_time(uint64_t start_t, uint32_t expiry)
 
 static int client_message_init(struct l_dhcp_client *client,
 					struct dhcp_message *message,
-					uint8_t type,
-					uint8_t **opt, size_t *optlen)
+					struct dhcp_message_builder *builder)
 {
-	int err;
 	uint16_t max_size;
 
-	err = dhcp_message_init(message, DHCP_OP_CODE_BOOTREQUEST,
-				type, client->xid, opt, optlen);
-	if (err < 0)
-		return err;
+	message->op = DHCP_OP_CODE_BOOTREQUEST;
+	message->xid = L_CPU_TO_BE32(client->xid);
+	message->magic = L_CPU_TO_BE32(DHCP_MAGIC);
 
 	dhcp_message_set_address_type(message, client->addr_type,
 							client->addr_len);
@@ -534,20 +476,19 @@ static int client_message_init(struct l_dhcp_client *client,
 	 */
 	message->secs = L_CPU_TO_BE16(dhcp_attempt_secs(client->start_t));
 
-	err = dhcp_append_prl(client->request_options, opt, optlen);
-	if (err < 0)
-		return err;
+	if (!_dhcp_message_builder_append_prl(builder,
+						client->request_options))
+		return -EINVAL;
 
 	/*
 	 * Set the maximum DHCP message size to the minimum legal value.  This
 	 * helps some buggy DHCP servers to not send bigger packets
 	 */
 	max_size = L_CPU_TO_BE16(576);
-	err = _dhcp_option_append(opt, optlen,
+	if (!_dhcp_message_builder_append(builder,
 					DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
-					2, &max_size);
-	if (err < 0)
-		return err;
+					2, &max_size))
+		return -EINVAL;
 
 	return 0;
 }
@@ -561,7 +502,7 @@ static void dhcp_client_event_notify(struct l_dhcp_client *client,
 
 static int dhcp_client_send_discover(struct l_dhcp_client *client)
 {
-	uint8_t *opt;
+	struct dhcp_message_builder builder;
 	size_t optlen = DHCP_MIN_OPTIONS_SIZE;
 	size_t len = sizeof(struct dhcp_message) + optlen;
 	L_AUTO_FREE_VAR(struct dhcp_message *, discover);
@@ -571,26 +512,19 @@ static int dhcp_client_send_discover(struct l_dhcp_client *client)
 
 	discover = (struct dhcp_message *) l_new(uint8_t, len);
 
-	err = client_message_init(client, discover,
-					DHCP_MESSAGE_TYPE_DISCOVER,
-					&opt, &optlen);
+	_dhcp_message_builder_init(&builder, discover, len,
+					DHCP_MESSAGE_TYPE_DISCOVER);
+
+	err = client_message_init(client, discover, &builder);
 	if (err < 0)
 		return err;
 
-	if (client->hostname) {
-		err = _dhcp_option_append(&opt, &optlen,
-						L_DHCP_OPTION_HOST_NAME,
+	if (client->hostname)
+		_dhcp_message_builder_append(&builder, L_DHCP_OPTION_HOST_NAME,
 						strlen(client->hostname),
 						client->hostname);
-		if (err < 0)
-			return err;
-	}
-
-	err = _dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
-	if (err < 0)
-		return err;
 
-	len = dhcp_message_optimize(discover, opt);
+	_dhcp_message_builder_finalize(&builder, &len);
 
 	return client->transport->broadcast(client->transport,
 					INADDR_ANY, DHCP_PORT_CLIENT,
@@ -600,7 +534,7 @@ static int dhcp_client_send_discover(struct l_dhcp_client *client)
 
 static int dhcp_client_send_request(struct l_dhcp_client *client)
 {
-	uint8_t *opt;
+	struct dhcp_message_builder builder;
 	size_t optlen = DHCP_MIN_OPTIONS_SIZE;
 	size_t len = sizeof(struct dhcp_message) + optlen;
 	L_AUTO_FREE_VAR(struct dhcp_message *, request);
@@ -610,9 +544,11 @@ static int dhcp_client_send_request(struct l_dhcp_client *client)
 
 	request = (struct dhcp_message *) l_new(uint8_t, len);
 
-	err = client_message_init(client, request,
-					DHCP_MESSAGE_TYPE_REQUEST,
-					&opt, &optlen);
+	_dhcp_message_builder_init(&builder, request, len,
+					DHCP_MESSAGE_TYPE_REQUEST);
+
+
+	err = client_message_init(client, request, &builder);
 	if (err < 0)
 		return err;
 
@@ -633,17 +569,20 @@ static int dhcp_client_send_request(struct l_dhcp_client *client)
 		 *
 		 * NOTE: 'SELECTING' is meant to be 'REQUESTING' in the RFC
 		 */
-		err = _dhcp_option_append(&opt, &optlen,
+		if (!_dhcp_message_builder_append(&builder,
 					L_DHCP_OPTION_SERVER_IDENTIFIER,
-					4, &client->lease->server_address);
-		if (err < 0)
-			return err;
+					4, &client->lease->server_address)) {
+			CLIENT_DEBUG("Failed to append server ID");
+			return -EINVAL;
+		}
 
-		err = _dhcp_option_append(&opt, &optlen,
+		if (!_dhcp_message_builder_append(&builder,
 					L_DHCP_OPTION_REQUESTED_IP_ADDRESS,
-					4, &client->lease->address);
-		if (err < 0)
-			return err;
+					4, &client->lease->address)) {
+			CLIENT_DEBUG("Failed to append requested IP");
+			return -EINVAL;
+		}
+
 		break;
 	case DHCP_STATE_RENEWING:
 	case DHCP_STATE_REBINDING:
@@ -659,19 +598,16 @@ static int dhcp_client_send_request(struct l_dhcp_client *client)
 	}
 
 	if (client->hostname) {
-		err = _dhcp_option_append(&opt, &optlen,
+		if (!_dhcp_message_builder_append(&builder,
 						L_DHCP_OPTION_HOST_NAME,
 						strlen(client->hostname),
-						client->hostname);
-		if (err < 0)
-			return err;
+						client->hostname)) {
+			CLIENT_DEBUG("Failed to append host name");
+			return -EINVAL;
+		}
 	}
 
-	err = _dhcp_option_append(&opt, &optlen, DHCP_OPTION_END, 0, NULL);
-	if (err < 0)
-		return err;
-
-	len = dhcp_message_optimize(request, opt);
+	_dhcp_message_builder_finalize(&builder, &len);
 
 	/*
 	 * RFC2131, Section 4.1:
-- 
2.26.2

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

* [PATCH 04/14] dhcp-util: move iter APIs to dhcp-util
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
  2020-10-15 17:17 ` [PATCH 02/14] dhcp-util: add dhcp message builder APIs James Prestwood
  2020-10-15 17:17 ` [PATCH 03/14] dhcp: update client code to use " James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 05/14] dhcp-transport: remove XID from open()/BPF James Prestwood
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

These were already exposed for use elsewhere but dhcp-util
is a better home for these APIs.
---
 ell/dhcp-util.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++
 ell/dhcp.c      | 160 ------------------------------------------------
 2 files changed, 160 insertions(+), 160 deletions(-)

diff --git a/ell/dhcp-util.c b/ell/dhcp-util.c
index 44ab1e2..42979d1 100644
--- a/ell/dhcp-util.c
+++ b/ell/dhcp-util.c
@@ -158,3 +158,163 @@ uint8_t *_dhcp_message_builder_finalize(struct dhcp_message_builder *builder,
 
 	return builder->start;
 }
+
+bool _dhcp_message_iter_init(struct dhcp_message_iter *iter,
+				const struct dhcp_message *message, size_t len)
+{
+	if (!message)
+		return false;
+
+	if (len < sizeof(struct dhcp_message))
+		return false;
+
+	if (L_BE32_TO_CPU(message->magic) != DHCP_MAGIC)
+		return false;
+
+	memset(iter, 0, sizeof(*iter));
+	iter->message = message;
+	iter->message_len = len;
+	iter->max = len - sizeof(struct dhcp_message);
+	iter->options = message->options;
+	iter->can_overload = true;
+
+	return true;
+}
+
+static bool next_option(struct dhcp_message_iter *iter,
+				uint8_t *t, uint8_t *l, const void **v)
+{
+	uint8_t type;
+	uint8_t len;
+
+	while (iter->pos < iter->max) {
+		type = iter->options[iter->pos];
+
+		switch (type) {
+		case DHCP_OPTION_PAD:
+			iter->pos += 1;
+			continue;
+		case DHCP_OPTION_END:
+			return false;
+		default:
+			break;
+		}
+
+		if (iter->pos + 2 >= iter->max)
+			return false;
+
+		len = iter->options[iter->pos + 1];
+
+		if (iter->pos + 2 + len > iter->max)
+			return false;
+
+		*t = type;
+		*l = len;
+		*v = &iter->options[iter->pos + 2];
+
+		iter->pos += 2 + len;
+		return true;
+	}
+
+	return false;
+}
+
+bool _dhcp_message_iter_next(struct dhcp_message_iter *iter, uint8_t *type,
+				uint8_t *len, const void **data)
+{
+	bool r;
+	uint8_t t, l;
+	const void *v;
+
+	do {
+		r = next_option(iter, &t, &l, &v);
+		if (!r) {
+			iter->can_overload = false;
+
+			if (iter->overload_file) {
+				iter->options = iter->message->file;
+				iter->pos = 0;
+				iter->max = sizeof(iter->message->file);
+				iter->overload_file = false;
+				continue;
+			}
+
+			if (iter->overload_sname) {
+				iter->options = iter->message->sname;
+				iter->pos = 0;
+				iter->max = sizeof(iter->message->sname);
+				iter->overload_sname = false;
+				continue;
+			}
+
+			return r;
+		}
+
+		switch (t) {
+		case DHCP_OPTION_OVERLOAD:
+			if (l != 1)
+				continue;
+
+			if (!iter->can_overload)
+				continue;
+
+			if (l_get_u8(v) & DHCP_OVERLOAD_FILE)
+				iter->overload_file = true;
+
+			if (l_get_u8(v) & DHCP_OVERLOAD_SNAME)
+				iter->overload_sname = true;
+
+			continue;
+		default:
+			if (type)
+				*type = t;
+
+			if (len)
+				*len = l;
+
+			if (data)
+				*data = v;
+			return r;
+		}
+	} while (true);
+
+	return false;
+}
+
+int _dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code,
+					size_t optlen, const void *optval)
+{
+	if (!buf || !buflen)
+		return -EINVAL;
+
+	switch (code) {
+
+	case DHCP_OPTION_PAD:
+	case DHCP_OPTION_END:
+		if (*buflen < 1)
+			return -ENOBUFS;
+
+		(*buf)[0] = code;
+		*buf += 1;
+		*buflen -= 1;
+		break;
+
+	default:
+		if (*buflen < optlen + 2)
+			return -ENOBUFS;
+
+		if (!optval)
+			return -EINVAL;
+
+		(*buf)[0] = code;
+		(*buf)[1] = optlen;
+		memcpy(&(*buf)[2], optval, optlen);
+
+		*buf += optlen + 2;
+		*buflen -= (optlen + 2);
+
+		break;
+	}
+
+	return 0;
+}
diff --git a/ell/dhcp.c b/ell/dhcp.c
index d2be894..b7b6263 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -141,166 +141,6 @@ const char *_dhcp_option_to_string(uint8_t option)
 	}
 }
 
-bool _dhcp_message_iter_init(struct dhcp_message_iter *iter,
-				const struct dhcp_message *message, size_t len)
-{
-	if (!message)
-		return false;
-
-	if (len < sizeof(struct dhcp_message))
-		return false;
-
-	if (L_BE32_TO_CPU(message->magic) != DHCP_MAGIC)
-		return false;
-
-	memset(iter, 0, sizeof(*iter));
-	iter->message = message;
-	iter->message_len = len;
-	iter->max = len - sizeof(struct dhcp_message);
-	iter->options = message->options;
-	iter->can_overload = true;
-
-	return true;
-}
-
-static bool next_option(struct dhcp_message_iter *iter,
-				uint8_t *t, uint8_t *l, const void **v)
-{
-	uint8_t type;
-	uint8_t len;
-
-	while (iter->pos < iter->max) {
-		type = iter->options[iter->pos];
-
-		switch (type) {
-		case DHCP_OPTION_PAD:
-			iter->pos += 1;
-			continue;
-		case DHCP_OPTION_END:
-			return false;
-		default:
-			break;
-		}
-
-		if (iter->pos + 2 >= iter->max)
-			return false;
-
-		len = iter->options[iter->pos + 1];
-
-		if (iter->pos + 2 + len > iter->max)
-			return false;
-
-		*t = type;
-		*l = len;
-		*v = &iter->options[iter->pos + 2];
-
-		iter->pos += 2 + len;
-		return true;
-	}
-
-	return false;
-}
-
-bool _dhcp_message_iter_next(struct dhcp_message_iter *iter, uint8_t *type,
-				uint8_t *len, const void **data)
-{
-	bool r;
-	uint8_t t, l;
-	const void *v;
-
-	do {
-		r = next_option(iter, &t, &l, &v);
-		if (!r) {
-			iter->can_overload = false;
-
-			if (iter->overload_file) {
-				iter->options = iter->message->file;
-				iter->pos = 0;
-				iter->max = sizeof(iter->message->file);
-				iter->overload_file = false;
-				continue;
-			}
-
-			if (iter->overload_sname) {
-				iter->options = iter->message->sname;
-				iter->pos = 0;
-				iter->max = sizeof(iter->message->sname);
-				iter->overload_sname = false;
-				continue;
-			}
-
-			return r;
-		}
-
-		switch (t) {
-		case DHCP_OPTION_OVERLOAD:
-			if (l != 1)
-				continue;
-
-			if (!iter->can_overload)
-				continue;
-
-			if (l_get_u8(v) & DHCP_OVERLOAD_FILE)
-				iter->overload_file = true;
-
-			if (l_get_u8(v) & DHCP_OVERLOAD_SNAME)
-				iter->overload_sname = true;
-
-			continue;
-		default:
-			if (type)
-				*type = t;
-
-			if (len)
-				*len = l;
-
-			if (data)
-				*data = v;
-			return r;
-		}
-	} while (true);
-
-	return false;
-}
-
-int _dhcp_option_append(uint8_t **buf, size_t *buflen, uint8_t code,
-					size_t optlen, const void *optval)
-{
-	if (!buf || !buflen)
-		return -EINVAL;
-
-	switch (code) {
-
-	case DHCP_OPTION_PAD:
-	case DHCP_OPTION_END:
-		if (*buflen < 1)
-			return -ENOBUFS;
-
-		(*buf)[0] = code;
-		*buf += 1;
-		*buflen -= 1;
-		break;
-
-	default:
-		if (*buflen < optlen + 2)
-			return -ENOBUFS;
-
-		if (!optval)
-			return -EINVAL;
-
-		(*buf)[0] = code;
-		(*buf)[1] = optlen;
-		memcpy(&(*buf)[2], optval, optlen);
-
-		*buf += optlen + 2;
-		*buflen -= (optlen + 2);
-
-		break;
-	}
-
-	return 0;
-}
-
 static void dhcp_message_set_address_type(struct dhcp_message *message,
 						uint8_t addr_type,
 						uint8_t addr_len)
-- 
2.26.2

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

* [PATCH 05/14] dhcp-transport: remove XID from open()/BPF
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (2 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 04/14] dhcp-util: move iter APIs to dhcp-util James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 06/14] dhcp-transport: add send_raw operation James Prestwood
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

In preparation for dhcp server the XID portion of the BPF
needs to be remove as DHCP server packets will not have
the XID. In addition, the xid argument was removed from
open() since it was only needed for the BPF.

In addition, the OPCODE_BOOT_REQUEST portion of the BPF
was removed to handle both REQUEST and REPLY messages.
---
 ell/dhcp-private.h   |  2 +-
 ell/dhcp-transport.c | 18 +++---------------
 ell/dhcp.c           |  3 +--
 3 files changed, 5 insertions(+), 18 deletions(-)

diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index 3aa89fb..bd2f01f 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -91,7 +91,7 @@ uint16_t _dhcp_checksumv(const struct iovec *iov, size_t iov_cnt);
 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 (*open)(struct dhcp_transport *s);
 	int (*broadcast)(struct dhcp_transport *transport,
 						uint32_t saddr, uint16_t sport,
 						uint32_t daddr, uint16_t dport,
diff --git a/ell/dhcp-transport.c b/ell/dhcp-transport.c
index e332f99..13e9953 100644
--- a/ell/dhcp-transport.c
+++ b/ell/dhcp-transport.c
@@ -328,7 +328,7 @@ static int _dhcp_default_transport_bind(struct dhcp_transport *s,
 	return 0;
 }
 
-static int kernel_raw_socket_open(uint32_t ifindex, uint16_t port, uint32_t xid)
+static int kernel_raw_socket_open(uint32_t ifindex, uint16_t port)
 {
 	int s;
 	struct sockaddr_ll addr;
@@ -382,11 +382,6 @@ static int kernel_raw_socket_open(uint32_t ifindex, uint16_t port, uint32_t xid)
 		/* A <- DHCP op */
 		BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
 				offsetof(struct dhcp_packet, dhcp.op)),
-		/* op == BOOTREPLY ? */
-		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K,
-				DHCP_OP_CODE_BOOTREPLY, 1, 0),
-		/* ignore */
-		BPF_STMT(BPF_RET + BPF_K, 0),
 		/* A <- DHCP header type */
 		BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
 				offsetof(struct dhcp_packet, dhcp.htype)),
@@ -394,13 +389,6 @@ static int kernel_raw_socket_open(uint32_t ifindex, uint16_t port, uint32_t xid)
 		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),
 		/* ignore */
 		BPF_STMT(BPF_RET + BPF_K, 0),
-		/* A <- client identifier */
-		BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
-				offsetof(struct dhcp_packet, dhcp.xid)),
-		/* client identifier == xid ? */
-		BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0),
-		/* ignore */
-		BPF_STMT(BPF_RET + BPF_K, 0),
 		/* A <- MAC address length */
 		BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
 				offsetof(struct dhcp_packet, dhcp.hlen)),
@@ -448,7 +436,7 @@ error:
 	return -errno;
 }
 
-static int _dhcp_default_transport_open(struct dhcp_transport *s, uint32_t xid)
+static int _dhcp_default_transport_open(struct dhcp_transport *s)
 {
 	struct dhcp_default_transport *transport =
 		l_container_of(s, struct dhcp_default_transport, super);
@@ -457,7 +445,7 @@ static int _dhcp_default_transport_open(struct dhcp_transport *s, uint32_t xid)
 	if (transport->io)
 		return -EALREADY;
 
-	fd = kernel_raw_socket_open(s->ifindex, transport->port, xid);
+	fd = kernel_raw_socket_open(s->ifindex, transport->port);
 	if (fd < 0)
 		return fd;
 
diff --git a/ell/dhcp.c b/ell/dhcp.c
index b7b6263..aa9fe0f 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -972,8 +972,7 @@ LIB_EXPORT bool l_dhcp_client_start(struct l_dhcp_client *client)
 		l_getrandom(&client->xid, sizeof(client->xid));
 
 	if (client->transport->open)
-		if (client->transport->open(client->transport,
-							client->xid) < 0)
+		if (client->transport->open(client->transport) < 0)
 			return false;
 
 	_dhcp_transport_set_rx_callback(client->transport,
-- 
2.26.2

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

* [PATCH 06/14] dhcp-transport: add send_raw operation
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (3 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 05/14] dhcp-transport: remove XID from open()/BPF James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 07/14] dhcp-lease: add mac member and getter James Prestwood
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

This will be used for DHCP server where send() will not
work due to the client not yet having an IP.

The implementation was ported from connman:
<connman>/gdhcp/common.c: dhcp_send_raw_packet()
---
 ell/dhcp-private.h   |  7 +++++
 ell/dhcp-transport.c | 72 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 79 insertions(+)

diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index bd2f01f..2b8e940 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -100,6 +100,13 @@ struct dhcp_transport {
 	int (*send)(struct dhcp_transport *transport,
 					const struct sockaddr_in *dest,
 					const void *data, size_t len);
+	int (*send_raw)(struct dhcp_transport *s,
+					uint32_t source_ip,
+					int source_port,
+					uint32_t dest_ip,
+					int dest_port,
+					const uint8_t *dest_arp,
+					void *data, size_t len);
 	void (*close)(struct dhcp_transport *transport);
 	uint32_t ifindex;
 	dhcp_transport_rx_cb_t rx_cb;
diff --git a/ell/dhcp-transport.c b/ell/dhcp-transport.c
index 13e9953..5c2a31d 100644
--- a/ell/dhcp-transport.c
+++ b/ell/dhcp-transport.c
@@ -472,6 +472,77 @@ static void _dhcp_default_transport_close(struct dhcp_transport *s)
 	}
 }
 
+#define EXTEND_FOR_BUGGY_SERVERS 80
+
+static int _dhcp_default_transport_send_raw(struct dhcp_transport *s,
+						uint32_t source_ip,
+						int source_port,
+						uint32_t dest_ip,
+						int dest_port,
+						const uint8_t *dest_arp,
+						void *data, size_t len)
+{
+	struct sockaddr_ll dest;
+	size_t alloc_len = sizeof(struct dhcp_packet) -
+					sizeof(struct dhcp_message) + len;
+	L_AUTO_FREE_VAR(struct dhcp_packet *, packet);
+	int fd;
+	int n;
+
+	enum {
+		IP_UPD_DHCP_SIZE = sizeof(struct dhcp_packet) -
+						EXTEND_FOR_BUGGY_SERVERS,
+		UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE -
+				offsetof(struct dhcp_packet, udp),
+	};
+
+	packet = (struct dhcp_packet *)l_new(uint8_t, alloc_len);
+
+	fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (fd < 0)
+		return -errno;
+
+	memset(&dest, 0, sizeof(dest));
+
+	memcpy(&packet->dhcp, data, len);
+
+	dest.sll_family = AF_PACKET;
+	dest.sll_protocol = htons(ETH_P_IP);
+	dest.sll_ifindex = s->ifindex;
+	dest.sll_halen = 6;
+	memcpy(dest.sll_addr, dest_arp, 6);
+
+	if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
+		close(fd);
+		return -errno;
+	}
+
+	packet->ip.protocol = IPPROTO_UDP;
+	packet->ip.saddr = source_ip;
+	packet->ip.daddr = dest_ip;
+	packet->udp.source = htons(source_port);
+	packet->udp.dest = htons(dest_port);
+	packet->udp.len = htons(UPD_DHCP_SIZE);
+	packet->ip.tot_len = packet->udp.len;
+	packet->udp.check = _dhcp_checksum(packet, IP_UPD_DHCP_SIZE);
+	packet->ip.tot_len = htons(IP_UPD_DHCP_SIZE);
+	packet->ip.ihl = sizeof(packet->ip) >> 2;
+	packet->ip.version = IPVERSION;
+	packet->ip.ttl = IPDEFTTL;
+	packet->ip.check = _dhcp_checksum(&packet->ip, sizeof(packet->ip));
+
+	n = sendto(fd, packet, alloc_len, 0, (struct sockaddr *) &dest,
+			sizeof(dest));
+	if (n < 0) {
+		close(fd);
+		return n;
+	}
+
+	close(fd);
+
+	return 0;
+}
+
 struct dhcp_transport *_dhcp_default_transport_new(uint32_t ifindex,
 							const char *ifname,
 							uint16_t port)
@@ -484,6 +555,7 @@ struct dhcp_transport *_dhcp_default_transport_new(uint32_t ifindex,
 	transport->super.close = _dhcp_default_transport_close;
 	transport->super.send = _dhcp_default_transport_send;
 	transport->super.broadcast = _dhcp_default_transport_broadcast;
+	transport->super.send_raw = _dhcp_default_transport_send_raw;
 
 	transport->super.ifindex = ifindex;
 	l_strlcpy(transport->ifname, ifname, IFNAMSIZ);
-- 
2.26.2

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

* [PATCH 07/14] dhcp-lease: add mac member and getter
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (4 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 06/14] dhcp-transport: add send_raw operation James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 08/14] dhcp-lease: change _dhcp_lease_free to take void* James Prestwood
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1580 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 +
 3 files changed, 11 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 2b8e940..6038354 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -144,6 +144,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);
-- 
2.26.2

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

* [PATCH 08/14] dhcp-lease: change _dhcp_lease_free to take void*
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (5 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 07/14] dhcp-lease: add mac member and getter James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 09/14] dhcp: prepare for DHCP server James Prestwood
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

This allows _dhcp_lease_free to be used with l_queue_destroy
directly without a wrapper function.
---
 ell/dhcp-lease.c   | 4 +++-
 ell/dhcp-private.h | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/ell/dhcp-lease.c b/ell/dhcp-lease.c
index 59de3e3..f9545b5 100644
--- a/ell/dhcp-lease.c
+++ b/ell/dhcp-lease.c
@@ -41,8 +41,10 @@ struct l_dhcp_lease *_dhcp_lease_new(void)
 	return ret;
 }
 
-void _dhcp_lease_free(struct l_dhcp_lease *lease)
+void _dhcp_lease_free(void *data)
 {
+	struct l_dhcp_lease *lease = data;
+
 	if (!lease)
 		return;
 
diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index 6038354..f6058fd 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -149,7 +149,7 @@ struct l_dhcp_lease {
 };
 
 struct l_dhcp_lease *_dhcp_lease_new(void);
-void _dhcp_lease_free(struct l_dhcp_lease *lease);
+void _dhcp_lease_free(void *data);
 struct l_dhcp_lease *_dhcp_lease_parse_options(struct dhcp_message_iter *iter);
 
 struct dhcp_message_builder {
-- 
2.26.2

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

* [PATCH 09/14] dhcp: prepare for DHCP server
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (6 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 08/14] dhcp-lease: change _dhcp_lease_free to take void* James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 10/14] dhcp-server: initial implementation James Prestwood
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

Some defines were moved out of dhcp.c and into dhcp-private.h
so server can utilize them.
---
 ell/dhcp-private.h | 14 ++++++++++++++
 ell/dhcp.c         | 14 --------------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/ell/dhcp-private.h b/ell/dhcp-private.h
index f6058fd..bca68d4 100644
--- a/ell/dhcp-private.h
+++ b/ell/dhcp-private.h
@@ -44,6 +44,8 @@ enum dhcp_op_code {
 	DHCP_OP_CODE_BOOTREPLY = 2,
 };
 
+#define DHCP_MIN_OPTIONS_SIZE 312
+
 #define DHCP_MAGIC 0x63825363
 
 /* RFC 2132, Section 9.6. DHCP Message Type */
@@ -51,6 +53,18 @@ enum dhcp_op_code {
 #define DHCP_OPTION_PAD 0 /* RFC 2132, Section 3.1 */
 #define DHCP_OPTION_END 255 /* RFC 2132, Section 3.2 */
 
+/* RFC 2132, Section 9.3. Option Overload */
+#define DHCP_OPTION_OVERLOAD 52
+enum dhcp_option_overload {
+	DHCP_OVERLOAD_FILE = 1,
+	DHCP_OVERLOAD_SNAME = 2,
+	DHCP_OVERLOAD_BOTH = 3,
+};
+
+#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* Section 9.8 */
+#define DHCP_OPTION_MAXIMUM_MESSAGE_SIZE 57 /* Section 9.10 */
+#define DHCP_OPTION_CLIENT_IDENTIFIER 61 /* Section 9.14 */
+
 /* RFC 2131, Figure 1 */
 struct dhcp_message {
 	uint8_t op;
diff --git a/ell/dhcp.c b/ell/dhcp.c
index aa9fe0f..708c656 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -50,18 +50,6 @@
 
 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
 
-/* RFC 2132, Section 9.3. Option Overload */
-#define DHCP_OPTION_OVERLOAD 52
-enum dhcp_option_overload {
-	DHCP_OVERLOAD_FILE = 1,
-	DHCP_OVERLOAD_SNAME = 2,
-	DHCP_OVERLOAD_BOTH = 3,
-};
-
-#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* Section 9.8 */
-#define DHCP_OPTION_MAXIMUM_MESSAGE_SIZE 57 /* Section 9.10 */
-#define DHCP_OPTION_CLIENT_IDENTIFIER 61 /* Section 9.14 */
-
 enum dhcp_state {
 	DHCP_STATE_INIT,
 	DHCP_STATE_SELECTING,
@@ -175,8 +163,6 @@ static inline int dhcp_message_optimize(struct dhcp_message *message,
 	return len;
 }
 
-#define DHCP_MIN_OPTIONS_SIZE 312
-
 struct l_dhcp_client {
 	enum dhcp_state state;
 	unsigned long request_options[256 / BITS_PER_LONG];
-- 
2.26.2

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

* [PATCH 10/14] dhcp-server: initial implementation
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (7 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 09/14] dhcp: prepare for DHCP server James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 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-15 17:17 UTC (permalink / raw)
  To: ell

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

This was ported from connman to use ELL instead of GLib. The
only other functional changes were removing the options hash
and IP hash. This was done because there really isn't a need
for super quick access of both options and lease objects since
we are only talking about a maximum of 254 nodes (only 3 in
the options case), and likely much less in the real world.
---
 Makefile.am        |   1 +
 ell/dhcp-private.h |   4 +
 ell/dhcp-server.c  | 856 +++++++++++++++++++++++++++++++++++++++++++++
 ell/dhcp.h         |  39 +++
 4 files changed, 900 insertions(+)
 create mode 100644 ell/dhcp-server.c

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-private.h b/ell/dhcp-private.h
index bca68d4..8816f53 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,
@@ -147,6 +148,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
new file mode 100644
index 0000000..d99a900
--- /dev/null
+++ b/ell/dhcp-server.c
@@ -0,0 +1,856 @@
+/*
+ *
+ *  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
+
+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;
+	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;
+
+	struct dhcp_transport *transport;
+};
+
+#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 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;
+	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);
+}
+
+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,
+				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 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;
+
+	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->send_raw(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 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->send_raw(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)
+{
+	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->send_raw(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->send_raw(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;
+	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;
+	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;
+	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;
+	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;
+	case DHCP_MESSAGE_TYPE_INFORM:
+		SERVER_DEBUG("Received INFORM");
+
+		send_inform(server, message);
+		break;
+	}
+}
+
+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);
+	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);
+
+	_dhcp_transport_free(server->transport);
+	l_free(server->ifname);
+
+	l_queue_destroy(server->lease_list, _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)
+{
+	if (unlikely(!server))
+		return false;
+
+	if (server->started)
+		return false;
+
+	if (!server->address)
+		server->address = l_net_get_ip_address(server->ifindex);
+
+	if (!server->ifname) {
+		server->ifname = l_net_get_name(server->ifindex);
+
+		if (!server->ifname)
+			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)
+			return false;
+
+	_dhcp_transport_set_rx_callback(server->transport, listener_event,
+						server);
+
+	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;
+
+	if (server->transport->close)
+		server->transport->close(server->transport);
+
+	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;
+}
+
+LIB_EXPORT const struct l_dhcp_lease *l_dhcp_server_get_lease(
+						struct l_dhcp_server *server,
+						const uint8_t *mac)
+{
+	if (unlikely(!server || !mac))
+		return NULL;
+
+	return find_lease_by_mac(server, mac);
+}
diff --git a/ell/dhcp.h b/ell/dhcp.h
index c78b605..2d630fe 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,33 @@ 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);
+const struct l_dhcp_lease *l_dhcp_server_get_lease(
+						struct l_dhcp_server *server,
+						const uint8_t *mac);
 #ifdef __cplusplus
 }
 #endif
-- 
2.26.2

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

* [PATCH 11/14] unit: update dhcp test to use new builder APIs
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (8 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 10/14] dhcp-server: initial implementation James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 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-15 17:17 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 d825401..a890d74 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 12/14] examples: basic DHCP server example
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (9 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 11/14] unit: update dhcp test to use new builder APIs James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 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-15 17:17 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 13/14] unit: add complete client/server dhcp test
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (10 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 12/14] examples: basic DHCP server example James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 17:17 ` [PATCH 14/14] dhcp: Add support for setting address James Prestwood
  2020-10-15 18:19 ` [PATCH 01/14] net: add l_net_get_ip_address() Denis Kenzior
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

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

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

diff --git a/unit/test-dhcp.c b/unit/test-dhcp.c
index a890d74..43804ca 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)
 {
@@ -735,6 +737,173 @@ static void test_discover(const void *data)
 	l_dhcp_client_destroy(client);
 }
 
+static bool send_raw_called = false;
+
+static int fake_transport_send_raw(struct dhcp_transport *s,
+					uint32_t source_ip,
+					int source_port,
+					uint32_t dest_ip,
+					int dest_port,
+					const uint8_t *dest_arp,
+					void *data, size_t len)
+{
+	assert(len <= sizeof(server_packet));
+	memcpy(server_packet, data, len);
+	server_packet_len = len;
+
+	send_raw_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;
+	const struct l_dhcp_lease *srv_lease;
+	/* client IP address */
+	char *cli_addr;
+	/* servers leased IP address, should match cli_addr */
+	char *srv_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->send_raw = fake_transport_send_raw;
+
+	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->broadcast = fake_transport_broadcast;
+	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(send_raw_called);
+	send_raw_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(send_raw_called);
+	send_raw_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);
+
+	srv_lease = l_dhcp_server_get_lease(server, addr);
+	assert(srv_lease);
+	srv_cli_addr = l_dhcp_lease_get_address(srv_lease);
+	assert(!strcmp(cli_addr, srv_cli_addr));
+
+	l_free(cli_addr);
+	l_free(srv_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);
@@ -758,5 +927,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 14/14] dhcp: Add support for setting address
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (11 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 13/14] unit: add complete client/server dhcp test James Prestwood
@ 2020-10-15 17:17 ` James Prestwood
  2020-10-15 18:19 ` [PATCH 01/14] net: add l_net_get_ip_address() Denis Kenzior
  13 siblings, 0 replies; 15+ messages in thread
From: James Prestwood @ 2020-10-15 17:17 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 4184 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 | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/dhcp.h |  4 ++++
 2 files changed, 74 insertions(+)

diff --git a/ell/dhcp.c b/ell/dhcp.c
index 708c656..520646d 100644
--- a/ell/dhcp.c
+++ b/ell/dhcp.c
@@ -38,6 +38,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 +180,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;
@@ -580,6 +585,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)
@@ -623,6 +646,27 @@ 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 = 24;
+		uint32_t l = l_dhcp_lease_get_lifetime(client->lease);
+
+		a = l_rtnl_address_new(ip, prefix_len);
+		l_rtnl_address_set_noprefixroute(a, true);
+		l_rtnl_address_set_lifetimes(a, l, l);
+
+		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;
 }
 
@@ -985,6 +1029,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;
 
@@ -1038,3 +1095,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 2d630fe..a4c185c 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 01/14] net: add l_net_get_ip_address()
  2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
                   ` (12 preceding siblings ...)
  2020-10-15 17:17 ` [PATCH 14/14] dhcp: Add support for setting address James Prestwood
@ 2020-10-15 18:19 ` Denis Kenzior
  13 siblings, 0 replies; 15+ messages in thread
From: Denis Kenzior @ 2020-10-15 18:19 UTC (permalink / raw)
  To: ell

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

Hi James,

On 10/15/20 12:17 PM, James Prestwood wrote:
> ---
>   ell/net.c | 32 ++++++++++++++++++++++++++++++++
>   ell/net.h |  1 +
>   2 files changed, 33 insertions(+)
> 

Don't forget ell/ell.sym changes

> diff --git a/ell/net.c b/ell/net.c
> index 0bff535..5551779 100644
> --- a/ell/net.c
> +++ b/ell/net.c
> @@ -29,6 +29,7 @@
>   #include <unistd.h>
>   #include <errno.h>
>   #include <sys/ioctl.h>
> +#include <netinet/ip.h>
>   
>   #include "net.h"
>   #include "net-private.h"
> @@ -336,3 +337,34 @@ char **net_domain_list_parse(const uint8_t *raw, size_t raw_len)
>   
>   	return ret;
>   }
> +
> +LIB_EXPORT uint32_t l_net_get_ip_address(int ifindex)

Can we change the signature to:

bool l_net_get_address(int ifindex, struct in_addr *out)

That makes it more explicit that only IPv4 address is returned.

> +{
> +	struct ifreq ifr;
> +	int sk, err;
> +	struct sockaddr_in *server_ip;
> +	uint32_t ret = 0;
> +
> +	sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
> +	if (sk < 0)
> +		return 0;
> +
> +	memset(&ifr, 0, sizeof(ifr));
> +	ifr.ifr_ifindex = ifindex;
> +
> +	err = ioctl(sk, SIOCGIFNAME, &ifr);
> +	if (err < 0)
> +		goto done;
> +
> +	err = ioctl(sk, SIOCGIFADDR, &ifr);
> +	if (err < 0)
> +		goto done;
> +
> +	server_ip = (struct sockaddr_in *) &ifr.ifr_addr;
> +	ret = server_ip->sin_addr.s_addr;
> +
> +done:
> +	close(sk);
> +
> +	return ret;
> +}
> diff --git a/ell/net.h b/ell/net.h
> index 6808e07..abaf785 100644
> --- a/ell/net.h
> +++ b/ell/net.h
> @@ -34,6 +34,7 @@ bool l_net_get_mac_address(uint32_t ifindex, uint8_t *out_addr);
>   char *l_net_get_name(uint32_t ifindex);
>   bool l_net_hostname_is_root(const char *hostname);
>   bool l_net_hostname_is_localhost(const char *hostname);
> +uint32_t l_net_get_ip_address(int ifindex);
>   
>   #ifdef __cplusplus
>   }
> 

Regards,
-Denis

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

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

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-15 17:17 [PATCH 01/14] net: add l_net_get_ip_address() James Prestwood
2020-10-15 17:17 ` [PATCH 02/14] dhcp-util: add dhcp message builder APIs James Prestwood
2020-10-15 17:17 ` [PATCH 03/14] dhcp: update client code to use " James Prestwood
2020-10-15 17:17 ` [PATCH 04/14] dhcp-util: move iter APIs to dhcp-util James Prestwood
2020-10-15 17:17 ` [PATCH 05/14] dhcp-transport: remove XID from open()/BPF James Prestwood
2020-10-15 17:17 ` [PATCH 06/14] dhcp-transport: add send_raw operation James Prestwood
2020-10-15 17:17 ` [PATCH 07/14] dhcp-lease: add mac member and getter James Prestwood
2020-10-15 17:17 ` [PATCH 08/14] dhcp-lease: change _dhcp_lease_free to take void* James Prestwood
2020-10-15 17:17 ` [PATCH 09/14] dhcp: prepare for DHCP server James Prestwood
2020-10-15 17:17 ` [PATCH 10/14] dhcp-server: initial implementation James Prestwood
2020-10-15 17:17 ` [PATCH 11/14] unit: update dhcp test to use new builder APIs James Prestwood
2020-10-15 17:17 ` [PATCH 12/14] examples: basic DHCP server example James Prestwood
2020-10-15 17:17 ` [PATCH 13/14] unit: add complete client/server dhcp test James Prestwood
2020-10-15 17:17 ` [PATCH 14/14] dhcp: Add support for setting address James Prestwood
2020-10-15 18:19 ` [PATCH 01/14] net: add l_net_get_ip_address() 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.