From 502afac1e0f8e509ecce1260375e987d04dd0a5f Mon Sep 17 00:00:00 2001 From: Justin L Werner Date: Thu, 9 Aug 2012 14:20:30 -0600 Subject: PXE: add dhcp option support for better pxe support "MAGIC" - 208 - An option whose presence and content verifies to the PXELINUX bootloader that the options numbered 209-211 are for the purpose as described herein. "ConfigFile" - 209 - Configures the path/filename component of the configuration file's location, which this bootloader should use to configure itself. "PathPrefix" - 210 - Configures a value to be prepended to the ConfigFile to discern the directory location of the file. "RebootTime" - 211 - Configures a timeout after which the bootstrap program will reboot the system (most likely returning it to PXE). Signed-off-by: Justin L Werner Signed-off-by: John Rigby --- common/cmd_pxe.c | 51 +++++++- common/main.c | 11 ++ include/configs/highbank.h | 2 + include/configs/igep00x0.h | 2 + include/configs/mx53loco.h | 2 + include/configs/omap3_beagle.h | 2 + include/configs/omap4_panda.h | 2 + include/configs/vexpress_common.h | 2 + net/Makefile | 1 + net/bootp.c | 11 +- net/magic.c | 242 ++++++++++++++++++++++++++++++++++++++ net/magic.h | 41 +++++++ 12 files changed, 366 insertions(+), 3 deletions(-) create mode 100644 net/magic.c create mode 100644 net/magic.h diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index bf32fb492..dc7c2049b 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -23,6 +23,9 @@ #include #include "menu.h" +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) +#include "../net/magic.h" +#endif #define MAX_TFTP_PATH_LEN 127 @@ -93,22 +96,42 @@ static int format_mac_pxe(char *outbuf, size_t outbuf_len) return 1; } +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) +/* + * Returns the directory the file specified in the bootfile env variable is + * in, unless DHCP MAGIC was received and we have a PathPrefix value, in which + * case the bootenv (if it was specified) is overridden. If bootfile + * isn't defined in the environment or obtained from PathPrefix DHCP + * vendor extension, return NULL, which should be interpreted as + * "don't prepend anything to paths". + */ +#else /* * Returns the directory the file specified in the bootfile env variable is * in. If bootfile isn't defined in the environment, return NULL, which should * be interpreted as "don't prepend anything to paths". */ +#endif static int get_bootfile_path(const char *file_path, char *bootfile_path, size_t bootfile_path_size) { char *bootfile, *last_slash; size_t path_len = 0; +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) + char *path_prefix = getenv(PXE_PATH_PREFIX); + + /* Override the initial environment */ + if (path_prefix) { + setenv("bootfile", path_prefix); + } +#endif + + bootfile = from_env("bootfile"); if (file_path[0] == '/') goto ret; bootfile = from_env("bootfile"); - if (!bootfile) goto ret; @@ -277,6 +300,25 @@ static int get_pxelinux_path(char *file, void *pxefile_addr_r) return get_pxe_file(path, pxefile_addr_r); } +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) +/* + * Attempt to load a config file obtained from DHCP vendor extension option + * + * Returns 1 on success or < 0 on error. + */ +static int pxe_dhcp_config_path(void *pxefile_addr_r) +{ + char *name = getenv(PXE_CONFIG_FILE); + int retval = -ENOENT; + + if (name && *name) { + retval = get_pxelinux_path(name, pxefile_addr_r); + } + + return retval; +} +#endif + /* * Looks for a pxe file with a name based on the pxeuuid environment variable. * @@ -379,7 +421,12 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) * Keep trying paths until we successfully get a file we're looking * for. */ - if (pxe_uuid_path((void *)pxefile_addr_r) > 0 +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) + if (pxe_dhcp_config_path(pxefile_addr_r) > 0 + || pxe_uuid_path(pxefile_addr_r) > 0 +#else + if (pxe_uuid_path(pxefile_addr_r) > 0 +#endif || pxe_mac_path((void *)pxefile_addr_r) > 0 || pxe_ipaddr_paths((void *)pxefile_addr_r) > 0 || get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) { diff --git a/common/main.c b/common/main.c index a93335798..00463bb07 100644 --- a/common/main.c +++ b/common/main.c @@ -43,6 +43,10 @@ #include #include +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) +#include "../net/magic.h" +#endif + #if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST) || defined(CONFIG_CMDLINE_EDITING) DECLARE_GLOBAL_DATA_PTR; #endif @@ -470,6 +474,13 @@ void init_cmd_timeout(void) */ void reset_cmd_timeout(void) { +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) + char *pxe_reboot_time = getenv(PXE_REBOOT_TIME); + + if (pxe_reboot_time && *pxe_reboot_time) { + retry_time = atoi(pxe_reboot_time); + } +#endif endtime = endtick(retry_time); } #endif diff --git a/include/configs/highbank.h b/include/configs/highbank.h index 791f3f546..bb06671f6 100644 --- a/include/configs/highbank.h +++ b/include/configs/highbank.h @@ -59,6 +59,8 @@ #define CONFIG_BOOTP_PXE #define CONFIG_BOOTP_PXE_CLIENTARCH 0x100 #define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.highbank" +#define CONFIG_BOOTP_VENDOREX +#define CONFIG_BOOTP_VENDOREX_PXE_SHARED /* * Command line configuration. diff --git a/include/configs/igep00x0.h b/include/configs/igep00x0.h index c26c1d3c2..9a40b4d21 100644 --- a/include/configs/igep00x0.h +++ b/include/configs/igep00x0.h @@ -287,6 +287,8 @@ #define CONFIG_BOOTP_PXE #define CONFIG_BOOTP_PXE_CLIENTARCH 0x100 #define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.omap3_igep0020" +#define CONFIG_BOOTP_VENDOREX +#define CONFIG_BOOTP_VENDOREX_PXE_SHARED #endif /* (CONFIG_CMD_NET) */ diff --git a/include/configs/mx53loco.h b/include/configs/mx53loco.h index 34f374226..2d2396a83 100644 --- a/include/configs/mx53loco.h +++ b/include/configs/mx53loco.h @@ -76,6 +76,8 @@ #define CONFIG_BOOTP_PXE #define CONFIG_BOOTP_PXE_CLIENTARCH 0x100 #define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.mx53_loco" +#define CONFIG_BOOTP_VENDOREX +#define CONFIG_BOOTP_VENDOREX_PXE_SHARED #define CONFIG_FEC_MXC #define IMX_FEC_BASE FEC_BASE_ADDR diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h index 064ffb95d..75f6dd960 100644 --- a/include/configs/omap3_beagle.h +++ b/include/configs/omap3_beagle.h @@ -154,6 +154,8 @@ #define CONFIG_BOOTP_PXE #define CONFIG_BOOTP_PXE_CLIENTARCH 0x100 #define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.omap3_beagle" +#define CONFIG_BOOTP_VENDOREX +#define CONFIG_BOOTP_VENDOREX_PXE_SHARED /* commands to include */ #include diff --git a/include/configs/omap4_panda.h b/include/configs/omap4_panda.h index 64a4ccc8e..a7e1b24e2 100644 --- a/include/configs/omap4_panda.h +++ b/include/configs/omap4_panda.h @@ -68,6 +68,8 @@ #define CONFIG_BOOTP_PXE #define CONFIG_BOOTP_PXE_CLIENTARCH 0x100 #define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.omap4_panda" +#define CONFIG_BOOTP_VENDOREX +#define CONFIG_BOOTP_VENDOREX_PXE_SHARED #include #define CONFIG_CMD_NET diff --git a/include/configs/vexpress_common.h b/include/configs/vexpress_common.h index e81a379a3..254c2308f 100644 --- a/include/configs/vexpress_common.h +++ b/include/configs/vexpress_common.h @@ -196,6 +196,8 @@ #define CONFIG_BOOTP_HOSTNAME #define CONFIG_BOOTP_PXE #define CONFIG_BOOTP_PXE_CLIENTARCH 0x100 +#define CONFIG_BOOTP_VENDOREX +#define CONFIG_BOOTP_VENDOREX_PXE_SHARED /* Miscellaneous configurable options */ #undef CONFIG_SYS_CLKS_IN_HZ diff --git a/net/Makefile b/net/Makefile index e7764ce93..2e3c217a7 100644 --- a/net/Makefile +++ b/net/Makefile @@ -33,6 +33,7 @@ COBJS-$(CONFIG_CMD_CDP) += cdp.o COBJS-$(CONFIG_CMD_DNS) += dns.o COBJS-$(CONFIG_CMD_NET) += eth.o COBJS-$(CONFIG_CMD_LINK_LOCAL) += link_local.o +COBJS-$(CONFIG_CMD_NET) += magic.o COBJS-$(CONFIG_CMD_NET) += net.o COBJS-$(CONFIG_CMD_NFS) += nfs.o COBJS-$(CONFIG_CMD_PING) += ping.o diff --git a/net/bootp.c b/net/bootp.c index 938d54101..13dac8420 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -85,7 +85,6 @@ u8 *__dhcp_vendorex_prep(u8 *e) while (*ptr) *e++ = *ptr++; } - return e; } @@ -95,6 +94,10 @@ u8 *__dhcp_vendorex_proc(u8 *popt) } u8 *dhcp_vendorex_prep(u8 *e) __attribute__((weak, alias("__dhcp_vendorex_prep"))); u8 *dhcp_vendorex_proc(u8 *e) __attribute__((weak, alias("__dhcp_vendorex_proc"))); + +#if defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) +# include "../net/magic.h" +#endif #endif #endif @@ -724,6 +727,9 @@ static void DhcpOptionsProcess(uchar *popt, struct Bootp_t *bp) int *to_ptr; #endif +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) + dhcp_vendorex_opts_done(); +#endif while (popt < end && *popt != 0xff) { oplen = *(popt + 1); switch (*popt) { @@ -817,6 +823,9 @@ static void DhcpOptionsProcess(uchar *popt, struct Bootp_t *bp) } popt += oplen + 2; /* Process next option */ } +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) + dhcp_vendorex_opts_done(); +#endif } static int DhcpMessageType(unsigned char *popt) diff --git a/net/magic.c b/net/magic.c new file mode 100644 index 000000000..59fff9234 --- /dev/null +++ b/net/magic.c @@ -0,0 +1,242 @@ +/* + * magic.c + * Copyright (c) 2012 Canonical LTD. + * Author: Justin L Werner + * See: RFC 5071 + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "bootp.h" + +#include + +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) +#include "magic.h" + +#define OPT_MAGIC 208 +#define OPT_CONFIG_FILE 209 +#define OPT_PATH_PREFIX 210 +#define OPT_REBOOT_TIME 211 + +#define OPT_MAGIC_LEN 4 +#define OPT_REBOOT_TIME_LEN 4 + + +static const u8 opt_magic_string[] = {0xf1, 0x0, 0x74, 0x7e}; + +static int opt_magic_seen = 0; +static u8 opt_config_file_value[UCHAR_MAX + 1]; +static u8 opt_path_prefix_value[UCHAR_MAX + 1]; +static size_t opt_reboot_time = 0; + +static u8 *parse_magic(u8 *); +static u8 *parse_config_file(u8 *); +static u8 *parse_path_prefix(u8 *); +static u8 *parse_reboot_time(u8 *); + + +/* + * Init/done processing any vendor extension options that we care + * about here. It is possible (at least in my env) for the PXE options + * processing to occur more than once. + */ +void +dhcp_vendorex_opts_done(void) +{ + opt_magic_seen = 0; + memset(opt_config_file_value, 0, sizeof(opt_config_file_value)); + memset(opt_path_prefix_value, 0, sizeof(opt_path_prefix_value)); + opt_reboot_time = 0; +} + +/* + * Add vendor option(s) to the request + * - add own opts and return e as ptr just beyond them + * + * For our common PXE MAGIC implementation, we don't add anything: it's a noop + */ +u8 * +dhcp_vendorex_prep (u8 *e) +{ + return e; +} + +/* + * Parse vendor options from a response + * - e points into the bp_vend[] array, which is OPT_SIZE + * returns next 'e' if recognized and accepted, NULL otherwise + */ +u8 * +dhcp_vendorex_proc (u8 *e) +{ + switch (*e) { + case OPT_MAGIC: + printf("INFO: DHCP PXE vendorex PXE MAGIC option encountered\n"); + e = parse_magic(++e); + break; + + case OPT_CONFIG_FILE: + printf("INFO: DHCP PXE vendorex PXE ConfigFile option encountered\n"); + e = parse_config_file(++e); + break; + + case OPT_PATH_PREFIX: + printf("INFO: DHCP PXE vendorex PXE PathPrefix option encountered\n"); + e = parse_path_prefix(++e); + break; + + case OPT_REBOOT_TIME: + printf("INFO: DHCP PXE vendorex RebootTime option encountered\n"); + e = parse_reboot_time(++e); + break; + + default: + e = NULL; + break; + } + + return e; +} + +static u8 * +parse_magic(u8 *e) +{ + size_t len = *e++; + + if (opt_magic_seen) { + printf("INFO: DHCP PXE vendorex MAGIC option already seen\n"); + } + + if (len != OPT_MAGIC_LEN) { + e = NULL; + printf("ERROR: DHCP PXE vendorex MAGIC has invalid length [%u]\n", len); + + } else if (memcmp(e, opt_magic_string, sizeof(opt_magic_string))) { + e = NULL; + opt_magic_seen = 0; + printf("ERROR: DHCP PXE vendorex MAGIC invalid magic value %02x:%02x:%02x:%02x\n", + (unsigned int) e[0], (unsigned int) e[1], (unsigned int) e[2], (unsigned int) e[3]); + + } else { + e += sizeof(opt_magic_string); + opt_magic_seen = 1; + printf("INFO: DHCP PXE vendorex MAGIC confirmed\n"); + } + + return e; +} + +static u8 * +parse_config_file(u8 *e) +{ + size_t len = *e++; + + if (! opt_magic_seen) { + printf("ERROR: DHCP PXE vendorex ConfigFile without MAGIC\n"); + e = NULL; + + } else if (len == 0) { + printf("WARNING: DHCP PXE vendorex ConfigFile string has zero length, ignoring\n"); + + } else { + memset(opt_config_file_value, 0, sizeof(opt_config_file_value)); + memcpy(opt_config_file_value, e, len); + e += len; + opt_config_file_value[len] = 0; + setenv(PXE_CONFIG_FILE, (char *)opt_config_file_value); + printf("INFO: DHCP PXE vendorex ConfigFile is [%s]\n", opt_config_file_value); + } + + return e; +} + +static u8 * +parse_path_prefix(u8 *e) +{ + size_t len = *e++; + + if (! opt_magic_seen) { + printf("ERROR: DHCP PXE vendorex ConfigFile without MAGIC\n"); + e = NULL; + + } if (len == 0) { + printf("WARNING: DHCP PXE vendorex PathPrefix string has zero length, ignoring\n"); + + } else { + memset(opt_path_prefix_value, 0, sizeof(opt_path_prefix_value)); + memcpy(opt_path_prefix_value, e, len); + e += len; + opt_path_prefix_value[len] = 0; + setenv(PXE_PATH_PREFIX, (char *)opt_path_prefix_value); + printf("INFO: DHCP PXE vendorex PathPrefix is [%s]\n", opt_path_prefix_value); + } + + return e; +} + +static u8 * +parse_reboot_time(u8 *e) +{ + size_t len = *e++; + char bfr[12]; + + if (! opt_magic_seen) { + printf("ERROR: DHCP PXE vendorex ConfigFile without MAGIC\n"); + e = NULL; + + } else if (len != OPT_REBOOT_TIME_LEN) { + e += len; + printf("WARNING: DHCP PXE vendorex RebootTime has invalid length [%u], ignoring\n", len); + + } else { + unsigned long value; + + memcpy(&value, e, OPT_REBOOT_TIME_LEN); + opt_reboot_time = (size_t) ntohl(value); + e += OPT_REBOOT_TIME_LEN; + + sprintf(bfr, "%u", opt_reboot_time); + setenv(PXE_REBOOT_TIME, bfr); + + printf("INFO: DHCP PXE vendorex RebootTime is [%u]\n", opt_reboot_time); + +#if defined(CONFIG_BOOT_RETRY_TIME) + if (opt_reboot_time < CONFIG_BOOT_RETRY_MIN) { + opt_reboot_time = CONFIG_BOOT_RETRY_MIN; + sprintf(bfr, "%u", opt_reboot_time); + setenv(PXE_REBOOT_TIME, bfr); + printf("INFO: DHCP PXE vendorex RebootTime adjusted up to allowable minimum value [%d]\n", + CONFIG_BOOT_RETRY_MIN); + } + reset_cmd_timeout(); +#else + printf("INFO: DHCP PXE vendorex RebootTime is N/A and ignored due to u-boot configs\n"); +#endif + } + + return e; +} +#else +const int no_arm_vendorex_options = 1; +#endif diff --git a/net/magic.h b/net/magic.h new file mode 100644 index 000000000..e5e04f250 --- /dev/null +++ b/net/magic.h @@ -0,0 +1,41 @@ +/* + * magic.h + * Copyright (c) 2012 Canonical LTD. + * Author: Justin L Werner + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ +#ifndef _NET_MAGIC_H +#define _NET_MAGIC_H + +#if defined(CONFIG_BOOTP_VENDOREX) && defined(CONFIG_BOOTP_VENDOREX_PXE_SHARED) +#ifndef UCHAR_MAX +# define UCHAR_MAX ((size_t)0xff) +#endif + +#define PXE_CONFIG_FILE "pxeconfigfile" +#define PXE_PATH_PREFIX "pxepathprefix" /* see "bootfile" in common/cmd_pxe.c */ +#define PXE_REBOOT_TIME "pxereboottime" + +extern void dhcp_vendorex_opts_done(void); + +#endif + +#endif -- cgit v1.2.3