net: dhcp6: pxe: Add DHCP/PXE commands for IPv6
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>
This commit is contained in:
parent
a0245818f7
commit
7d0188927b
8 changed files with 132 additions and 23 deletions
|
@ -150,7 +150,7 @@ static int distro_boot(struct udevice *dev, struct bootflow *bflow)
|
||||||
info.dev = dev;
|
info.dev = dev;
|
||||||
info.bflow = bflow;
|
info.bflow = bflow;
|
||||||
ret = pxe_setup_ctx(&ctx, &cmdtp, distro_getfile, &info, true,
|
ret = pxe_setup_ctx(&ctx, &cmdtp, distro_getfile, &info, true,
|
||||||
bflow->subdir);
|
bflow->subdir, false);
|
||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("ctx", -EINVAL);
|
return log_msg_ret("ctx", -EINVAL);
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ static int distro_pxe_read_bootflow(struct udevice *dev, struct bootflow *bflow)
|
||||||
addr = simple_strtoul(addr_str, NULL, 16);
|
addr = simple_strtoul(addr_str, NULL, 16);
|
||||||
|
|
||||||
log_debug("calling pxe_get()\n");
|
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);
|
log_debug("pxe_get() returned %d\n", ret);
|
||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("pxeb", 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.bflow = bflow;
|
||||||
info.cmdtp = &cmdtp;
|
info.cmdtp = &cmdtp;
|
||||||
ret = pxe_setup_ctx(ctx, &cmdtp, distro_pxe_getfile, &info, false,
|
ret = pxe_setup_ctx(ctx, &cmdtp, distro_pxe_getfile, &info, false,
|
||||||
bflow->subdir);
|
bflow->subdir, false);
|
||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("ctx", -EINVAL);
|
return log_msg_ret("ctx", -EINVAL);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
|
||||||
pxe_getfile_func getfile, void *userdata,
|
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;
|
const char *last_slash;
|
||||||
size_t path_len = 0;
|
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->getfile = getfile;
|
||||||
ctx->userdata = userdata;
|
ctx->userdata = userdata;
|
||||||
ctx->allow_abs_path = allow_abs_path;
|
ctx->allow_abs_path = allow_abs_path;
|
||||||
|
ctx->use_ipv6 = use_ipv6;
|
||||||
|
|
||||||
/* figure out the boot directory, if there is one */
|
/* figure out the boot directory, if there is one */
|
||||||
if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
|
if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
|
||||||
|
|
26
cmd/Kconfig
26
cmd/Kconfig
|
@ -1673,6 +1673,15 @@ config CMD_DHCP
|
||||||
help
|
help
|
||||||
Boot image via network using DHCP/TFTP protocol
|
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
|
config BOOTP_MAY_FAIL
|
||||||
bool "Allow for the BOOTP/DHCP server to not be found"
|
bool "Allow for the BOOTP/DHCP server to not be found"
|
||||||
depends on CMD_BOOTP
|
depends on CMD_BOOTP
|
||||||
|
@ -1786,6 +1795,23 @@ config BOOTP_VCI_STRING
|
||||||
default "U-Boot.arm" if ARM
|
default "U-Boot.arm" if ARM
|
||||||
default "U-Boot"
|
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
|
config CMD_TFTPBOOT
|
||||||
bool "tftpboot"
|
bool "tftpboot"
|
||||||
default y
|
default y
|
||||||
|
|
23
cmd/net.c
23
cmd/net.c
|
@ -111,6 +111,29 @@ U_BOOT_CMD(
|
||||||
);
|
);
|
||||||
#endif
|
#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)
|
#if defined(CONFIG_CMD_DHCP)
|
||||||
static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
|
static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||||
char *const argv[])
|
char *const argv[])
|
||||||
|
|
85
cmd/pxe.c
85
cmd/pxe.c
|
@ -8,6 +8,8 @@
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
|
#include <net6.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
#include "pxe_utils.h"
|
#include "pxe_utils.h"
|
||||||
|
|
||||||
|
@ -29,12 +31,20 @@ static int do_get_tftp(struct pxe_context *ctx, const char *file_path,
|
||||||
{
|
{
|
||||||
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
|
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
|
||||||
int ret;
|
int ret;
|
||||||
|
int num_args;
|
||||||
|
|
||||||
tftp_argv[1] = file_addr;
|
tftp_argv[1] = file_addr;
|
||||||
tftp_argv[2] = (void *)file_path;
|
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;
|
return -ENOENT;
|
||||||
|
|
||||||
ret = pxe_get_file_size(sizep);
|
ret = pxe_get_file_size(sizep);
|
||||||
if (ret)
|
if (ret)
|
||||||
return log_msg_ret("tftp", ret);
|
return log_msg_ret("tftp", ret);
|
||||||
|
@ -43,6 +53,22 @@ static int do_get_tftp(struct pxe_context *ctx, const char *file_path,
|
||||||
return 1;
|
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.
|
* Looks for a pxe file with a name based on the pxeuuid environment variable.
|
||||||
*
|
*
|
||||||
|
@ -105,15 +131,24 @@ static int pxe_ipaddr_paths(struct pxe_context *ctx, unsigned long pxefile_addr_
|
||||||
return -ENOENT;
|
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 cmd_tbl cmdtp[] = {}; /* dummy */
|
||||||
struct pxe_context ctx;
|
struct pxe_context ctx;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false,
|
if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false,
|
||||||
env_get("bootfile")))
|
env_get("bootfile"), use_ipv6))
|
||||||
return -ENOMEM;
|
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
|
* Keep trying paths until we successfully get a file we're looking
|
||||||
* for.
|
* for.
|
||||||
|
@ -131,6 +166,7 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong *sizep)
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_exit:
|
||||||
pxe_destroy_ctx(&ctx);
|
pxe_destroy_ctx(&ctx);
|
||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
@ -169,9 +205,18 @@ do_pxe_get(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
char *fname;
|
char *fname;
|
||||||
ulong size;
|
ulong size;
|
||||||
int ret;
|
int ret;
|
||||||
|
bool use_ipv6 = false;
|
||||||
|
|
||||||
if (argc != 1)
|
if (IS_ENABLED(CONFIG_IPV6)) {
|
||||||
return CMD_RET_USAGE;
|
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");
|
pxefile_addr_str = from_env("pxefile_addr_r");
|
||||||
|
|
||||||
|
@ -183,7 +228,7 @@ do_pxe_get(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
ret = pxe_get(pxefile_addr_r, &fname, &size);
|
ret = pxe_get(pxefile_addr_r, &fname, &size, use_ipv6);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case 0:
|
case 0:
|
||||||
printf("Config file '%s' found\n", fname);
|
printf("Config file '%s' found\n", fname);
|
||||||
|
@ -211,13 +256,19 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
char *pxefile_addr_str;
|
char *pxefile_addr_str;
|
||||||
struct pxe_context ctx;
|
struct pxe_context ctx;
|
||||||
int ret;
|
int ret;
|
||||||
|
bool use_ipv6 = false;
|
||||||
|
|
||||||
if (argc == 1) {
|
if (IS_ENABLED(CONFIG_IPV6)) {
|
||||||
|
if (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM))
|
||||||
|
use_ipv6 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc == 1 || (argc == 2 && use_ipv6)) {
|
||||||
pxefile_addr_str = from_env("pxefile_addr_r");
|
pxefile_addr_str = from_env("pxefile_addr_r");
|
||||||
if (!pxefile_addr_str)
|
if (!pxefile_addr_str)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
} else if (argc == 2) {
|
} else if (argc == 2 || (argc == 3 && use_ipv6)) {
|
||||||
pxefile_addr_str = argv[1];
|
pxefile_addr_str = argv[1];
|
||||||
} else {
|
} else {
|
||||||
return CMD_RET_USAGE;
|
return CMD_RET_USAGE;
|
||||||
|
@ -229,7 +280,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,
|
if (pxe_setup_ctx(&ctx, cmdtp, do_get_tftp, NULL, false,
|
||||||
env_get("bootfile"))) {
|
env_get("bootfile"), use_ipv6)) {
|
||||||
printf("Out of memory\n");
|
printf("Out of memory\n");
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -244,8 +295,8 @@ do_pxe_boot(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cmd_tbl cmd_pxe_sub[] = {
|
static struct cmd_tbl cmd_pxe_sub[] = {
|
||||||
U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
|
U_BOOT_CMD_MKENT(get, 2, 1, do_pxe_get, "", ""),
|
||||||
U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
|
U_BOOT_CMD_MKENT(boot, 3, 1, do_pxe_boot, "", "")
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __maybe_unused pxe_reloc(void)
|
static void __maybe_unused pxe_reloc(void)
|
||||||
|
@ -281,9 +332,11 @@ static int do_pxe(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
||||||
return CMD_RET_USAGE;
|
return CMD_RET_USAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
U_BOOT_CMD(pxe, 3, 1, do_pxe,
|
U_BOOT_CMD(pxe, 4, 1, do_pxe,
|
||||||
"commands to get and boot from pxe files",
|
"commands to get and boot from pxe files\n"
|
||||||
"get - try to retrieve a pxe file using tftp\n"
|
"To use IPv6 add -ipv6 parameter",
|
||||||
"pxe boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
|
"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 */
|
||||||
|
|
|
@ -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,
|
if (pxe_setup_ctx(&ctx, cmdtp, sysboot_read_file, &info, true,
|
||||||
filename)) {
|
filename, false)) {
|
||||||
printf("Out of memory\n");
|
printf("Out of memory\n");
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
* @bootdir: Directory that files are loaded from ("" if no directory). This is
|
||||||
* allocated
|
* allocated
|
||||||
* @pxe_file_size: Size of the PXE file
|
* @pxe_file_size: Size of the PXE file
|
||||||
|
* @use_ipv6: TRUE : use IPv6 addressing, FALSE : use IPv4 addressing
|
||||||
*/
|
*/
|
||||||
struct pxe_context {
|
struct pxe_context {
|
||||||
struct cmd_tbl *cmdtp;
|
struct cmd_tbl *cmdtp;
|
||||||
|
@ -112,6 +113,7 @@ struct pxe_context {
|
||||||
bool allow_abs_path;
|
bool allow_abs_path;
|
||||||
char *bootdir;
|
char *bootdir;
|
||||||
ulong pxe_file_size;
|
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
|
* @allow_abs_path: true to allow absolute paths
|
||||||
* @bootfile: Bootfile whose directory loaded files are relative to, NULL if
|
* @bootfile: Bootfile whose directory loaded files are relative to, NULL if
|
||||||
* none
|
* 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
|
* Return: 0 if OK, -ENOMEM if out of memory, -E2BIG if bootfile is larger than
|
||||||
* MAX_TFTP_PATH_LEN bytes
|
* MAX_TFTP_PATH_LEN bytes
|
||||||
*/
|
*/
|
||||||
int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
|
int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
|
||||||
pxe_getfile_func getfile, void *userdata,
|
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
|
* 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/info", which indicates that all files should be fetched from the
|
||||||
* "rpi/" subdirectory
|
* "rpi/" subdirectory
|
||||||
* @sizep: Size of the PXE file (not bootfile)
|
* @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 */
|
#endif /* __PXE_UTILS_H */
|
||||||
|
|
Loading…
Reference in a new issue