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 <justin.werner@caononical.com>
Signed-off-by: John Rigby <john.rigby@linaro.org>
diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c
index 050874d..de47e9a 100644
--- a/common/cmd_pxe.c
+++ b/common/cmd_pxe.c
@@ -23,6 +23,9 @@
 #include <linux/list.h>
 
 #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
 
@@ -94,22 +97,42 @@
 	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;
 
@@ -280,6 +303,25 @@
 	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.
  *
@@ -383,7 +425,12 @@
 	 * 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) {