[PATCH 2/2] net: dhcp6: pxe: Add DHCP/PXE commands for IPv6

seanedmond at linux.microsoft.com seanedmond at linux.microsoft.com
Thu Feb 2 01:26:26 CET 2023


From: Sean Edmond <seanedmond at microsoft.com>

Adds commands to support DHCP and PXE with IPv6.

New commands added (when IPv6 is enabled):
- dhcp6
- pxe get -ipv6
- pxe boot -ipv6

Signed-off-by: Sean Edmond <seanedmond at microsoft.com>
---
 boot/bootmeth_distro.c |  2 +-
 boot/bootmeth_pxe.c    |  4 +-
 boot/pxe_utils.c       |  3 +-
 cmd/net.c              | 22 +++++++++++
 cmd/pxe.c              | 86 +++++++++++++++++++++++++++++++++++++-----
 cmd/sysboot.c          |  2 +-
 include/net.h          |  2 +
 include/net6.h         |  2 -
 include/pxe_utils.h    | 10 ++++-
 9 files changed, 115 insertions(+), 18 deletions(-)

diff --git a/boot/bootmeth_distro.c b/boot/bootmeth_distro.c
index 356929828b..b4b73ecbf5 100644
--- a/boot/bootmeth_distro.c
+++ b/boot/bootmeth_distro.c
@@ -150,7 +150,7 @@ static int distro_boot(struct udevice *dev, struct bootflow *bflow)
 	info.dev = dev;
 	info.bflow = bflow;
 	ret = pxe_setup_ctx(&ctx, &cmdtp, distro_getfile, &info, true,
-			    bflow->subdir);
+			    bflow->subdir, false);
 	if (ret)
 		return log_msg_ret("ctx", -EINVAL);
 
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
index ecf8557af8..5a8af2bbd0 100644
--- a/boot/bootmeth_pxe.c
+++ b/boot/bootmeth_pxe.c
@@ -70,7 +70,7 @@ static int distro_pxe_read_bootflow(struct udevice *dev, struct bootflow *bflow)
 	addr = simple_strtoul(addr_str, NULL, 16);
 
 	log_debug("calling pxe_get()\n");
-	ret = pxe_get(addr, &bootdir, &size);
+	ret = pxe_get(addr, &bootdir, &size, false);
 	log_debug("pxe_get() returned %d\n", ret);
 	if (ret)
 		return log_msg_ret("pxeb", ret);
@@ -146,7 +146,7 @@ static int distro_pxe_boot(struct udevice *dev, struct bootflow *bflow)
 	info.bflow = bflow;
 	info.cmdtp = &cmdtp;
 	ret = pxe_setup_ctx(ctx, &cmdtp, distro_pxe_getfile, &info, false,
-			    bflow->subdir);
+			    bflow->subdir, false);
 	if (ret)
 		return log_msg_ret("ctx", -EINVAL);
 
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index 3a1e50f2b1..d13c47dd94 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -1578,7 +1578,7 @@ void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg)
 
 int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
 		  pxe_getfile_func getfile, void *userdata,
-		  bool allow_abs_path, const char *bootfile)
+		  bool allow_abs_path, const char *bootfile, bool use_ipv6)
 {
 	const char *last_slash;
 	size_t path_len = 0;
@@ -1588,6 +1588,7 @@ int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
 	ctx->getfile = getfile;
 	ctx->userdata = userdata;
 	ctx->allow_abs_path = allow_abs_path;
+	ctx->use_ipv6 = use_ipv6;
 
 	/* figure out the boot directory, if there is one */
 	if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
diff --git a/cmd/net.c b/cmd/net.c
index 4227321871..88d53d14d5 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -111,6 +111,28 @@ U_BOOT_CMD(
 );
 #endif
 
+#if defined(CONFIG_CMD_DHCP6)
+static int do_dhcp6(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[])
+{
+	int i;
+	int dhcp_argc;
+	char *dhcp_argv[] = {NULL, NULL, NULL, NULL};
+
+	/* Add -ipv6 flag for autoload */
+	for (i = 0; i < argc; i++)
+		dhcp_argv[i] = argv[i];
+	dhcp_argc = argc + 1;
+	dhcp_argv[dhcp_argc - 1] =  USE_IP6_CMD_PARAM;
+
+	return netboot_common(DHCP6, cmdtp, dhcp_argc, dhcp_argv);
+}
+
+U_BOOT_CMD(dhcp6,	3,	1,	do_dhcp6,
+	   "boot image via network using DHCPv6/TFTP protocol",
+	   "[loadAddress] [[hostIPaddr:]bootfilename]");
+#endif
+
 #if defined(CONFIG_CMD_DHCP)
 static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
 		   char *const argv[])
diff --git a/cmd/pxe.c b/cmd/pxe.c
index db8e4697f2..ebc44fd661 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -11,6 +11,10 @@
 
 #include "pxe_utils.h"
 
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net6.h>
+#endif
+
 #ifdef CONFIG_CMD_NET
 const char *pxe_default_paths[] = {
 #ifdef CONFIG_SYS_SOC
@@ -29,12 +33,20 @@ static int do_get_tftp(struct pxe_context *ctx, const char *file_path,
 {
 	char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
 	int ret;
+	int num_args;
 
 	tftp_argv[1] = file_addr;
 	tftp_argv[2] = (void *)file_path;
+	if (ctx->use_ipv6) {
+		tftp_argv[3] = USE_IP6_CMD_PARAM;
+		num_args = 4;
+	} else {
+		num_args = 3;
+	}
 
-	if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
+	if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv))
 		return -ENOENT;
+
 	ret = pxe_get_file_size(sizep);
 	if (ret)
 		return log_msg_ret("tftp", ret);
@@ -43,6 +55,22 @@ static int do_get_tftp(struct pxe_context *ctx, const char *file_path,
 	return 1;
 }
 
+#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION)
+/*
+ * Looks for a pxe file with specified config file name,
+ * which is received from DHCP option 209.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static inline int pxe_dhcp_option_path(struct pxe_context *ctx, unsigned long pxefile_addr_r)
+{
+	int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r);
+
+	free(pxelinux_configfile);
+
+	return ret;
+}
+#endif
 /*
  * Looks for a pxe file with a name based on the pxeuuid environment variable.
  *
@@ -105,15 +133,25 @@ static int pxe_ipaddr_paths(struct pxe_context *ctx, unsigned long pxefile_addr_
 	return -ENOENT;
 }
 
-int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep)
+int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep, bool use_ipv6)
 {
 	struct cmd_tbl cmdtp[] = {};	/* dummy */
 	struct pxe_context ctx;
 	int i;
 
 	if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false,
-			  env_get("bootfile")))
+			  env_get("bootfile"), use_ipv6))
 		return -ENOMEM;
+
+#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION)
+	if (pxelinux_configfile && use_ipv6) {
+		if (pxe_dhcp_option_path(&ctx, pxefile_addr_r) > 0)
+			goto done;
+
+		goto error_exit;
+	}
+#endif
+
 	/*
 	 * Keep trying paths until we successfully get a file we're looking
 	 * for.
@@ -131,6 +169,7 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep)
 		i++;
 	}
 
+error_exit:
 	pxe_destroy_ctx(&ctx);
 
 	return -ENOENT;
@@ -169,9 +208,17 @@ do_pxe_get(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	char *fname;
 	ulong size;
 	int ret;
+	bool use_ipv6 = false;
 
-	if (argc != 1)
-		return CMD_RET_USAGE;
+	if (IS_ENABLED(CONFIG_IPV6)) {
+		if (argc != 1 && argc != 2)
+			return CMD_RET_USAGE;
+		if (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM))
+			use_ipv6 = true;
+	} else {
+		if (argc != 1)
+			return CMD_RET_USAGE;
+	}
 
 	pxefile_addr_str = from_env("pxefile_addr_r");
 
@@ -183,7 +230,7 @@ do_pxe_get(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	if (ret < 0)
 		return 1;
 
-	ret = pxe_get(pxefile_addr_r, &fname, &size);
+	ret = pxe_get(pxefile_addr_r, &fname, &size, use_ipv6);
 	switch (ret) {
 	case 0:
 		printf("Config file '%s' found\n", fname);
@@ -211,13 +258,19 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	char *pxefile_addr_str;
 	struct pxe_context ctx;
 	int ret;
+	bool use_ipv6 = false;
+
+	if (IS_ENABLED(CONFIG_IPV6)) {
+		if (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM))
+			use_ipv6 = true;
+	}
 
-	if (argc == 1) {
+	if (argc == 1 || (argc == 2 && use_ipv6)) {
 		pxefile_addr_str = from_env("pxefile_addr_r");
 		if (!pxefile_addr_str)
 			return 1;
 
-	} else if (argc == 2) {
+	} else if (argc == 2 || (argc == 3 && use_ipv6)) {
 		pxefile_addr_str = argv[1];
 	} else {
 		return CMD_RET_USAGE;
@@ -229,7 +282,7 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	}
 
 	if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false,
-			  env_get("bootfile"))) {
+			  env_get("bootfile"), use_ipv6)) {
 		printf("Out of memory\n");
 		return CMD_RET_FAILURE;
 	}
@@ -244,8 +297,13 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 }
 
 static struct cmd_tbl cmd_pxe_sub[] = {
+#if IS_ENABLED(CONFIG_IPV6)
+	U_BOOT_CMD_MKENT(get, 2, 1, do_pxe_get, "", ""),
+	U_BOOT_CMD_MKENT(boot, 3, 1, do_pxe_boot, "", "")
+#else
 	U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
 	U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
+#endif
 };
 
 static void __maybe_unused pxe_reloc(void)
@@ -281,9 +339,19 @@ static int do_pxe(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	return CMD_RET_USAGE;
 }
 
+#if IS_ENABLED(CONFIG_IPV6)
+U_BOOT_CMD(pxe, 4, 1, do_pxe,
+	   "commands to get and boot from pxe files\n"
+	   "To use IPv6 add -ipv6 parameter",
+	   "get [" USE_IP6_CMD_PARAM "] - try to retrieve a pxe file using tftp\n"
+	   "pxe boot [pxefile_addr_r] [-ipv6] - boot from the pxe file at pxefile_addr_r\n"
+);
+#else
 U_BOOT_CMD(pxe, 3, 1, do_pxe,
 	   "commands to get and boot from pxe files",
 	   "get - try to retrieve a pxe file using tftp\n"
 	   "pxe boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
 );
 #endif
+
+#endif /* CONFIG_CMD_NET */
diff --git a/cmd/sysboot.c b/cmd/sysboot.c
index 04c0702026..63a7806deb 100644
--- a/cmd/sysboot.c
+++ b/cmd/sysboot.c
@@ -101,7 +101,7 @@ static int do_sysboot(struct cmd_tbl *cmdtp, int flag, int argc,
 	}
 
 	if (pxe_setup_ctx(&ctx, cmdtp, sysboot_read_file, &info, true,
-			  filename)) {
+			  filename, false)) {
 		printf("Out of memory\n");
 		return CMD_RET_FAILURE;
 	}
diff --git a/include/net.h b/include/net.h
index cac818e292..7463b1285b 100644
--- a/include/net.h
+++ b/include/net.h
@@ -49,6 +49,8 @@ struct udevice;
  */
 #define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1)
 
+#define USE_IP6_CMD_PARAM	"-ipv6"
+
 /* IPv4 addresses are always 32 bits in size */
 struct in_addr {
 	__be32 s_addr;
diff --git a/include/net6.h b/include/net6.h
index 9b3de028e6..571c0593e5 100644
--- a/include/net6.h
+++ b/include/net6.h
@@ -39,8 +39,6 @@ struct in6_addr {
 #define IPV6_ADDRSCOPE_ORG	0x08
 #define IPV6_ADDRSCOPE_GLOBAL	0x0E
 
-#define USE_IP6_CMD_PARAM	"-ipv6"
-
 /**
  * struct ipv6hdr - Internet Protocol V6 (IPv6) header.
  *
diff --git a/include/pxe_utils.h b/include/pxe_utils.h
index 1e5e8424f5..9f19593048 100644
--- a/include/pxe_utils.h
+++ b/include/pxe_utils.h
@@ -93,6 +93,7 @@ typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path,
  * @bootdir: Directory that files are loaded from ("" if no directory). This is
  *	allocated
  * @pxe_file_size: Size of the PXE file
+ * @use_ipv6: TRUE : use IPv6 addressing, FALSE : use IPv4 addressing
  */
 struct pxe_context {
 	struct cmd_tbl *cmdtp;
@@ -112,6 +113,7 @@ struct pxe_context {
 	bool allow_abs_path;
 	char *bootdir;
 	ulong pxe_file_size;
+	bool use_ipv6;
 };
 
 /**
@@ -209,12 +211,14 @@ int format_mac_pxe(char *outbuf, size_t outbuf_len);
  * @allow_abs_path: true to allow absolute paths
  * @bootfile: Bootfile whose directory loaded files are relative to, NULL if
  *	none
+ * @use_ipv6: TRUE : use IPv6 addressing
+ *            FALSE : use IPv4 addressing
  * Return: 0 if OK, -ENOMEM if out of memory, -E2BIG if bootfile is larger than
  *	MAX_TFTP_PATH_LEN bytes
  */
 int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
 		  pxe_getfile_func getfile, void *userdata,
-		  bool allow_abs_path, const char *bootfile);
+		  bool allow_abs_path, const char *bootfile, bool use_ipv6);
 
 /**
  * pxe_destroy_ctx() - Destroy a PXE context
@@ -251,7 +255,9 @@ int pxe_get_file_size(ulong *sizep);
  *	"rpi/info", which indicates that all files should be fetched from the
  *	"rpi/" subdirectory
  * @sizep: Size of the PXE file (not bootfile)
+ * @use_ipv6: TRUE : use IPv6 addressing
+ *            FALSE : use IPv4 addressing
  */
-int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep);
+int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep, bool use_ipv6);
 
 #endif /* __PXE_UTILS_H */
-- 
2.39.0



More information about the U-Boot mailing list