summaryrefslogtreecommitdiffstats
path: root/debian/patches/efinet-set-network-from-uefi-devpath.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/efinet-set-network-from-uefi-devpath.patch')
-rw-r--r--debian/patches/efinet-set-network-from-uefi-devpath.patch388
1 files changed, 388 insertions, 0 deletions
diff --git a/debian/patches/efinet-set-network-from-uefi-devpath.patch b/debian/patches/efinet-set-network-from-uefi-devpath.patch
new file mode 100644
index 0000000..bf97ddf
--- /dev/null
+++ b/debian/patches/efinet-set-network-from-uefi-devpath.patch
@@ -0,0 +1,388 @@
+From 3f85b646c8f6188f6e2122fc90351fb900e1b337 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 27 Oct 2016 17:43:05 -0400
+Subject: efinet: Setting network from UEFI device path
+
+The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no
+longer provided for HTTP Boot. Instead, we have to get the HTTP boot
+information from the device path nodes defined in following UEFI Specification
+sections.
+
+ 9.3.5.12 IPv4 Device Path
+ 9.3.5.13 IPv6 Device Path
+ 9.3.5.23 Uniform Resource Identifiers (URI) Device Path
+
+This patch basically does:
+
+include/grub/efi/api.h:
+Add new structure of Uniform Resource Identifiers (URI) Device Path
+
+grub-core/net/drivers/efi/efinet.c:
+Check if PXE Base Code is available, if not it will try to obtain the netboot
+information from the device path where the image booted from. The DHCPACK
+packet is recoverd from the information in device patch and feed into the same
+DHCP packet processing functions to ensure the network interface is setting up
+the same way it used to be.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+
+Patch-Name: efinet-set-network-from-uefi-devpath.patch
+---
+ grub-core/net/drivers/efi/efinet.c | 268 ++++++++++++++++++++++++++++-
+ include/grub/efi/api.h | 11 ++
+ 2 files changed, 270 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index fc90415f2..2d3b00f0e 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -23,6 +23,7 @@
+ #include <grub/efi/api.h>
+ #include <grub/efi/efi.h>
+ #include <grub/i18n.h>
++#include <grub/net/netbuff.h>
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+@@ -324,6 +325,221 @@ grub_efinet_findcards (void)
+ grub_free (handles);
+ }
+
++static struct grub_net_buff *
++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
++{
++ grub_efi_uint16_t uri_len;
++ grub_efi_device_path_t *ldp, *ddp;
++ grub_efi_uri_device_path_t *uri_dp;
++ struct grub_net_buff *nb;
++ grub_err_t err;
++
++ ddp = grub_efi_duplicate_device_path (dp);
++ ldp = grub_efi_find_last_device_path (ddp);
++
++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++ {
++ grub_free (ddp);
++ return NULL;
++ }
++
++ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0;
++
++ if (!uri_len)
++ {
++ grub_free (ddp);
++ return NULL;
++ }
++
++ uri_dp = (grub_efi_uri_device_path_t *) ldp;
++
++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++ ldp->length = sizeof (*ldp);
++
++ ldp = grub_efi_find_last_device_path (ddp);
++
++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
++ {
++ grub_free (ddp);
++ return NULL;
++ }
++
++ nb = grub_netbuff_alloc (512);
++ if (!nb)
++ return NULL;
++
++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
++ {
++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
++ struct grub_net_bootp_packet *bp;
++ grub_uint8_t *ptr;
++
++ bp = (struct grub_net_bootp_packet *) nb->tail;
++ err = grub_netbuff_put (nb, sizeof (*bp) + 4);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++
++ if (sizeof(bp->boot_file) < uri_len)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len);
++ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip));
++ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip));
++
++ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0;
++ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1;
++ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2;
++ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3;
++
++ ptr = nb->tail;
++ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ *ptr++ = GRUB_NET_BOOTP_NETMASK;
++ *ptr++ = sizeof (ipv4->subnet_mask);
++ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask));
++
++ ptr = nb->tail;
++ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ *ptr++ = GRUB_NET_BOOTP_ROUTER;
++ *ptr++ = sizeof (ipv4->gateway_ip_address);
++ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address));
++
++ ptr = nb->tail;
++ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER;
++ *ptr++ = sizeof ("HTTPClient") - 1;
++ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
++
++ ptr = nb->tail;
++ err = grub_netbuff_put (nb, 1);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ *ptr = GRUB_NET_BOOTP_END;
++ *use_ipv6 = 0;
++
++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++ ldp->length = sizeof (*ldp);
++ ldp = grub_efi_find_last_device_path (ddp);
++
++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
++ {
++ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp;
++ bp->hw_type = mac->if_type;
++ bp->hw_len = sizeof (bp->mac_addr);
++ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len);
++ }
++ }
++ else
++ {
++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp;
++
++ struct grub_net_dhcp6_packet *d6p;
++ struct grub_net_dhcp6_option *opt;
++ struct grub_net_dhcp6_option_iana *iana;
++ struct grub_net_dhcp6_option_iaaddr *iaaddr;
++
++ d6p = (struct grub_net_dhcp6_packet *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*d6p));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ d6p->message_type = GRUB_NET_DHCP6_REPLY;
++
++ opt = (struct grub_net_dhcp6_option *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*opt));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr));
++
++ err = grub_netbuff_put (nb, sizeof(*iana));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++
++ opt = (struct grub_net_dhcp6_option *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*opt));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
++ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr));
++
++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*iaaddr));
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address));
++
++ opt = (struct grub_net_dhcp6_option *)nb->tail;
++ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len);
++ if (err)
++ {
++ grub_free (ddp);
++ grub_netbuff_free (nb);
++ return NULL;
++ }
++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL);
++ opt->len = grub_cpu_to_be16 (uri_len);
++ grub_memcpy (opt->data, uri_dp->uri, uri_len);
++
++ *use_ipv6 = 1;
++ }
++
++ grub_free (ddp);
++ return nb;
++}
++
+ static void
+ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ char **path)
+@@ -340,6 +556,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ grub_efi_device_path_t *cdp;
+ struct grub_efi_pxe *pxe;
+ struct grub_efi_pxe_mode *pxe_mode;
++ grub_uint8_t *packet_buf;
++ grub_size_t packet_bufsz ;
++ int ipv6;
++ struct grub_net_buff *nb = NULL;
++
+ if (card->driver != &efidriver)
+ continue;
+ cdp = grub_efi_get_device_path (card->efi_handle);
+@@ -359,11 +580,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ ldp = grub_efi_find_last_device_path (dp);
+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ continue;
+ dup_dp = grub_efi_duplicate_device_path (dp);
+ if (!dup_dp)
+ continue;
++
++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++ {
++ dup_ldp = grub_efi_find_last_device_path (dup_dp);
++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++ dup_ldp->length = sizeof (*dup_ldp);
++ }
++
+ dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+@@ -375,16 +606,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ }
+ pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+- if (! pxe)
+- continue;
+- pxe_mode = pxe->mode;
++ if (!pxe)
++ {
++ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6);
++ if (!nb)
++ {
++ grub_print_error ();
++ continue;
++ }
++ packet_buf = nb->head;
++ packet_bufsz = nb->tail - nb->head;
++ }
++ else
++ {
++ pxe_mode = pxe->mode;
++ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack;
++ packet_bufsz = sizeof (pxe_mode->dhcp_ack);
++ ipv6 = pxe_mode->using_ipv6;
++ }
+
+- if (pxe_mode->using_ipv6)
++ if (ipv6)
+ {
+ grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
+ (struct grub_net_dhcp6_packet *)
+- &pxe_mode->dhcp_ack,
+- sizeof (pxe_mode->dhcp_ack),
++ packet_buf,
++ packet_bufsz,
+ 1, device, path);
+ if (grub_errno)
+ grub_print_error ();
+@@ -393,10 +639,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ {
+ grub_net_configure_by_dhcp_ack (card->name, card, 0,
+ (struct grub_net_bootp_packet *)
+- &pxe_mode->dhcp_ack,
+- sizeof (pxe_mode->dhcp_ack),
++ packet_buf,
++ packet_bufsz,
+ 1, device, path);
+ }
++
++ if (nb)
++ grub_netbuff_free (nb);
++
+ return;
+ }
+ }
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 50ab8e844..4b4652ca5 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -849,6 +849,8 @@ struct grub_efi_ipv4_device_path
+ grub_efi_uint16_t remote_port;
+ grub_efi_uint16_t protocol;
+ grub_efi_uint8_t static_ip_address;
++ grub_efi_ipv4_address_t gateway_ip_address;
++ grub_efi_ipv4_address_t subnet_mask;
+ } GRUB_PACKED;
+ typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t;
+
+@@ -903,6 +905,15 @@ struct grub_efi_sata_device_path
+ } GRUB_PACKED;
+ typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t;
+
++#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE 24
++
++struct grub_efi_uri_device_path
++{
++ grub_efi_device_path_t header;
++ grub_efi_uint8_t uri[0];
++} GRUB_PACKED;
++typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
++
+ #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10
+
+ /* Media Device Path. */