15a2072
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
15a2072
From: Michael Chang <mchang@suse.com>
15a2072
Date: Thu, 14 Jul 2016 18:45:14 +0800
15a2072
Subject: [PATCH] bootp: Add processing DHCPACK packet from HTTP Boot
15a2072
15a2072
The vendor class identifier with the string "HTTPClient" is used to denote the
15a2072
packet as responding to HTTP boot request. In DHCP4 config, the filename for
15a2072
HTTP boot is the URL of the boot file while for PXE boot it is the path to the
15a2072
boot file. As a consequence, the next-server becomes obseleted because the HTTP
15a2072
URL already contains the server address for the boot file. For DHCP6 config,
15a2072
there's no difference definition in existing config as dhcp6.bootfile-url can
15a2072
be used to specify URL for both HTTP and PXE boot file.
15a2072
15a2072
This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK
15a2072
packet by treating it as HTTP format, not as the PXE format.
15a2072
15a2072
Signed-off-by: Michael Chang <mchang@suse.com>
15a2072
Signed-off-by: Ken Lin <ken.lin@hpe.com>
15a2072
---
15a2072
 grub-core/net/bootp.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++--
15a2072
 include/grub/net.h    |  1 +
15a2072
 2 files changed, 67 insertions(+), 2 deletions(-)
15a2072
15a2072
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
15a2072
index 242cd1f4cbd..8b6fc9f2411 100644
15a2072
--- a/grub-core/net/bootp.c
15a2072
+++ b/grub-core/net/bootp.c
15a2072
@@ -20,6 +20,7 @@
15a2072
 #include <grub/env.h>
15a2072
 #include <grub/i18n.h>
15a2072
 #include <grub/command.h>
15a2072
+#include <grub/net.h>
15a2072
 #include <grub/net/ip.h>
15a2072
 #include <grub/net/netbuff.h>
15a2072
 #include <grub/net/udp.h>
15a2072
@@ -254,6 +255,11 @@ parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
15a2072
                                      taglength);
15a2072
           break;
15a2072
 
15a2072
+        case GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER:
15a2072
+          grub_env_set_net_property (name, "vendor_class_identifier", (const char *) ptr,
15a2072
+                                     taglength);
15a2072
+	  break;
15a2072
+
15a2072
 	case GRUB_NET_BOOTP_EXTENSIONS_PATH:
15a2072
           grub_env_set_net_property (name, "extensionspath", (const char *) ptr,
15a2072
                                      taglength);
15a2072
@@ -357,6 +363,66 @@ grub_net_configure_by_dhcp_ack (const char *name,
15a2072
     }
15a2072
 #endif
15a2072
 
15a2072
+  if (size > OFFSET_OF (vendor, bp))
15a2072
+    {
15a2072
+      char *cidvar;
15a2072
+      const char *cid;
15a2072
+
15a2072
+      parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
15a2072
+      cidvar = grub_xasprintf ("net_%s_%s", name, "vendor_class_identifier");
15a2072
+      cid = grub_env_get (cidvar);
15a2072
+      grub_free (cidvar);
15a2072
+
15a2072
+      if (cid && grub_strcmp (cid, "HTTPClient") == 0)
15a2072
+	{
15a2072
+	  char *proto, *ip, *pa;
15a2072
+
15a2072
+	  if (!dissect_url (bp->boot_file, &proto, &ip, &pa))
15a2072
+	    return inter;
15a2072
+
15a2072
+	  grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa));
15a2072
+	  if (is_def)
15a2072
+	    {
15a2072
+	      grub_net_default_server = grub_strdup (ip);
15a2072
+	      grub_env_set ("net_default_interface", name);
15a2072
+	      grub_env_export ("net_default_interface");
15a2072
+	    }
15a2072
+	  if (device && !*device)
15a2072
+	    {
15a2072
+	      *device = grub_xasprintf ("%s,%s", proto, ip);
15a2072
+	      grub_print_error ();
15a2072
+	    }
15a2072
+	  if (path)
15a2072
+	    {
15a2072
+	      *path = grub_strdup (pa);
15a2072
+	      grub_print_error ();
15a2072
+	      if (*path)
15a2072
+		{
15a2072
+		  char *slash;
15a2072
+		  slash = grub_strrchr (*path, '/');
15a2072
+		  if (slash)
15a2072
+		    *slash = 0;
15a2072
+		  else
15a2072
+		    **path = 0;
15a2072
+		}
15a2072
+	    }
15a2072
+	  grub_net_add_ipv4_local (inter, mask);
15a2072
+	  inter->dhcp_ack = grub_malloc (size);
15a2072
+	  if (inter->dhcp_ack)
15a2072
+	    {
15a2072
+	      grub_memcpy (inter->dhcp_ack, bp, size);
15a2072
+	      inter->dhcp_acklen = size;
15a2072
+	    }
15a2072
+	  else
15a2072
+	    grub_errno = GRUB_ERR_NONE;
15a2072
+
15a2072
+	  grub_free (proto);
15a2072
+	  grub_free (ip);
15a2072
+	  grub_free (pa);
15a2072
+	  return inter;
15a2072
+	}
15a2072
+    }
15a2072
+
15a2072
   if (size > OFFSET_OF (boot_file, bp))
15a2072
     grub_env_set_net_property (name, "boot_file", bp->boot_file,
15a2072
                                sizeof (bp->boot_file));
15a2072
@@ -421,8 +487,6 @@ grub_net_configure_by_dhcp_ack (const char *name,
15a2072
 	    **path = 0;
15a2072
 	}
15a2072
     }
15a2072
-  if (size > OFFSET_OF (vendor, bp))
15a2072
-    parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
15a2072
   grub_net_add_ipv4_local (inter, mask);
15a2072
   
15a2072
   inter->dhcp_ack = grub_malloc (size);
15a2072
diff --git a/include/grub/net.h b/include/grub/net.h
15a2072
index 5f78b22e109..9cf6da68973 100644
15a2072
--- a/include/grub/net.h
15a2072
+++ b/include/grub/net.h
15a2072
@@ -522,6 +522,7 @@ enum
15a2072
     GRUB_NET_BOOTP_DOMAIN = 0x0f,
15a2072
     GRUB_NET_BOOTP_ROOT_PATH = 0x11,
15a2072
     GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
15a2072
+    GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 0x3C,
15a2072
     GRUB_NET_BOOTP_CLIENT_ID = 0x3d,
15a2072
     GRUB_NET_BOOTP_CLIENT_UUID = 0x61,
15a2072
     GRUB_NET_BOOTP_END = 0xff