Adds commands to support DHCP and PXE with IPv6.
New configs added:
- CMD_DHCP6
- DHCP6_PXE_CLIENTARCH
- DHCP6_PXE_DHCP_OPTION
- DHCP6_ENTERPRISE_ID
New commands added (when IPv6 is enabled):
- dhcp6
- pxe get -ipv6
- pxe boot -ipv6
Signed-off-by: Sean Edmond <seanedmond@microsoft.com>
Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
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);
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);
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);
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;
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)
help
Boot image via network using DHCP/TFTP protocol
+config CMD_DHCP6
+ bool "dhcp6"
+ depends on IPV6
+ help
+ Boot image via network using DHCPv6/TFTP protocol using IPv6.
+
+ Will perform 4-message exchange with DHCPv6 server, requesting
+ the minimum required options to TFTP boot. Complies with RFC 8415.
+
config BOOTP_MAY_FAIL
bool "Allow for the BOOTP/DHCP server to not be found"
depends on CMD_BOOTP
default "U-Boot.arm" if ARM
default "U-Boot"
+if CMD_DHCP6
+
+config DHCP6_PXE_CLIENTARCH
+ hex
+ default 0x16 if ARM64
+ default 0x15 if ARM
+ default 0xFF
+
+config DHCP6_PXE_DHCP_OPTION
+ bool "Request & store 'pxe_configfile' from DHCP6 server"
+
+config DHCP6_ENTERPRISE_ID
+ int "Enterprise ID to send in DHCPv6 Vendor Class Option"
+ default 0
+
+endif
+
config CMD_TFTPBOOT
bool "tftpboot"
default y
);
#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.\n"
+ "Use IPv6 hostIPaddr framed with [] brackets",
+ "[loadAddress] [[hostIPaddr:]bootfilename]");
+#endif
+
#if defined(CONFIG_CMD_DHCP)
static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
#include <command.h>
#include <fs.h>
#include <net.h>
+#include <net6.h>
+#include <malloc.h>
#include "pxe_utils.h"
{
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);
return 1;
}
+/*
+ * Looks for a pxe file with specified config file name,
+ * which is received from DHCPv4 option 209 or
+ * DHCPv6 option 60.
+ *
+ * Returns 1 on success or < 0 on error.
+ */
+static 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;
+}
+
/*
* Looks for a pxe file with a name based on the pxeuuid environment variable.
*
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 (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) &&
+ pxelinux_configfile && use_ipv6) {
+ if (pxe_dhcp_option_path(&ctx, pxefile_addr_r) > 0)
+ goto done;
+
+ goto error_exit;
+ }
+
/*
* Keep trying paths until we successfully get a file we're looking
* for.
i++;
}
+error_exit:
pxe_destroy_ctx(&ctx);
return -ENOENT;
char *fname;
ulong size;
int ret;
+ bool use_ipv6 = false;
- if (argc != 1)
- return CMD_RET_USAGE;
+ if (IS_ENABLED(CONFIG_IPV6)) {
+ if (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM))
+ use_ipv6 = true;
+
+ if (!(argc == 1 || (argc == 2 && use_ipv6)))
+ return CMD_RET_USAGE;
+ } else {
+ if (argc != 1)
+ return CMD_RET_USAGE;
+ }
pxefile_addr_str = from_env("pxefile_addr_r");
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);
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;
}
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;
}
}
static struct cmd_tbl cmd_pxe_sub[] = {
- U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
- U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
+ U_BOOT_CMD_MKENT(get, 2, 1, do_pxe_get, "", ""),
+ U_BOOT_CMD_MKENT(boot, 3, 1, do_pxe_boot, "", "")
};
static void __maybe_unused pxe_reloc(void)
return CMD_RET_USAGE;
}
-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"
+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"
);
-#endif
+
+#endif /* CONFIG_CMD_NET */
}
if (pxe_setup_ctx(&ctx, cmdtp, sysboot_read_file, &info, true,
- filename)) {
+ filename, false)) {
printf("Out of memory\n");
return CMD_RET_FAILURE;
}
* @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;
bool allow_abs_path;
char *bootdir;
ulong pxe_file_size;
+ bool use_ipv6;
};
/**
* @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
* "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 */