
From: Sean Edmond seanedmond@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@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 */