nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

Blame SOURCES/0087-Add-support-for-non-Ethernet-network-cards.patch

8e15ce
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
8e15ce
From: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
8e15ce
Date: Wed, 10 Jul 2019 15:22:29 +0200
8e15ce
Subject: [PATCH] Add support for non-Ethernet network cards
8e15ce
8e15ce
This patch replaces fixed 6-byte link layer address with
8e15ce
up to 32-byte variable sized address.
8e15ce
This allows supporting Infiniband and Omni-Path fabric
8e15ce
which use 20-byte address, but other network card types
8e15ce
can also take advantage of this change.
8e15ce
The network card driver is responsible for replacing L2
8e15ce
header provided by grub2 if needed.
8e15ce
This approach is compatible with UEFI network stack which
8e15ce
also allows up to 32-byte variable size link address.
8e15ce
8e15ce
The BOOTP/DHCP packet format is limited to 16 byte client
8e15ce
hardware address, if link address is more that 16-bytes
8e15ce
then chaddr field in BOOTP it will be set to 0 as per rfc4390.
8e15ce
8e15ce
Resolves: rhbz#1370642
8e15ce
8e15ce
Signed-off-by: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
8e15ce
[msalter: Fix max string calculation in grub_net_hwaddr_to_str]
8e15ce
Signed-off-by: Mark Salter <msalter@redhat.com>
8e15ce
---
8e15ce
 grub-core/net/arp.c                    | 155 ++++++++++++++++++++++-----------
8e15ce
 grub-core/net/bootp.c                  |  15 ++--
8e15ce
 grub-core/net/drivers/efi/efinet.c     |   8 +-
8e15ce
 grub-core/net/drivers/emu/emunet.c     |   1 +
8e15ce
 grub-core/net/drivers/i386/pc/pxe.c    |  13 +--
8e15ce
 grub-core/net/drivers/ieee1275/ofnet.c |   2 +
8e15ce
 grub-core/net/drivers/uboot/ubootnet.c |   1 +
8e15ce
 grub-core/net/ethernet.c               |  88 +++++++++----------
8e15ce
 grub-core/net/icmp6.c                  |  15 ++--
8e15ce
 grub-core/net/ip.c                     |   4 +-
8e15ce
 grub-core/net/net.c                    |  50 ++++++-----
8e15ce
 include/grub/net.h                     |  19 ++--
8e15ce
 12 files changed, 219 insertions(+), 152 deletions(-)
8e15ce
8e15ce
diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c
8e15ce
index 54306e3b16d..67b409a8acc 100644
8e15ce
--- a/grub-core/net/arp.c
8e15ce
+++ b/grub-core/net/arp.c
8e15ce
@@ -31,22 +31,12 @@ enum
8e15ce
     ARP_REPLY = 2
8e15ce
   };
8e15ce
 
8e15ce
-enum
8e15ce
-  {
8e15ce
-    /* IANA ARP constant to define hardware type as ethernet. */
8e15ce
-    GRUB_NET_ARPHRD_ETHERNET = 1
8e15ce
-  };
8e15ce
-
8e15ce
-struct arppkt {
8e15ce
+struct arphdr {
8e15ce
   grub_uint16_t hrd;
8e15ce
   grub_uint16_t pro;
8e15ce
   grub_uint8_t hln;
8e15ce
   grub_uint8_t pln;
8e15ce
   grub_uint16_t op;
8e15ce
-  grub_uint8_t sender_mac[6];
8e15ce
-  grub_uint32_t sender_ip;
8e15ce
-  grub_uint8_t recv_mac[6];
8e15ce
-  grub_uint32_t recv_ip;
8e15ce
 } GRUB_PACKED;
8e15ce
 
8e15ce
 static int have_pending;
8e15ce
@@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
8e15ce
 			   const grub_net_network_level_address_t *proto_addr)
8e15ce
 {
8e15ce
   struct grub_net_buff nb;
8e15ce
-  struct arppkt *arp_packet;
8e15ce
+  struct arphdr *arp_header;
8e15ce
   grub_net_link_level_address_t target_mac_addr;
8e15ce
   grub_err_t err;
8e15ce
   int i;
8e15ce
   grub_uint8_t *nbd;
8e15ce
   grub_uint8_t arp_data[128];
8e15ce
+  grub_uint8_t hln;
8e15ce
+  grub_uint8_t pln;
8e15ce
+  grub_uint8_t arp_packet_len;
8e15ce
+  grub_uint8_t *tmp_ptr;
8e15ce
 
8e15ce
   if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
8e15ce
     return grub_error (GRUB_ERR_BUG, "unsupported address family");
8e15ce
@@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
8e15ce
   grub_netbuff_clear (&nb);
8e15ce
   grub_netbuff_reserve (&nb, 128);
8e15ce
 
8e15ce
-  err = grub_netbuff_push (&nb, sizeof (*arp_packet));
8e15ce
+  hln = inf->card->default_address.len;
8e15ce
+  pln = sizeof (proto_addr->ipv4);
8e15ce
+  arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln);
8e15ce
+
8e15ce
+  err = grub_netbuff_push (&nb, arp_packet_len);
8e15ce
   if (err)
8e15ce
     return err;
8e15ce
 
8e15ce
-  arp_packet = (struct arppkt *) nb.data;
8e15ce
-  arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
8e15ce
-  arp_packet->hln = 6;
8e15ce
-  arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
8e15ce
-  arp_packet->pln = 4;
8e15ce
-  arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
8e15ce
-  /* Sender hardware address.  */
8e15ce
-  grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6);
8e15ce
-  arp_packet->sender_ip = inf->address.ipv4;
8e15ce
-  grub_memset (arp_packet->recv_mac, 0, 6);
8e15ce
-  arp_packet->recv_ip = proto_addr->ipv4;
8e15ce
-  /* Target protocol address */
8e15ce
-  grub_memset (&target_mac_addr.mac, 0xff, 6);
8e15ce
+  arp_header = (struct arphdr *) nb.data;
8e15ce
+  arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type);
8e15ce
+  arp_header->hln = hln;
8e15ce
+  arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
8e15ce
+  arp_header->pln = pln;
8e15ce
+  arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
8e15ce
+  tmp_ptr = nb.data + sizeof (*arp_header);
8e15ce
+
8e15ce
+  /* The source hardware address. */
8e15ce
+  grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln);
8e15ce
+  tmp_ptr += hln;
8e15ce
+
8e15ce
+  /* The source protocol address. */
8e15ce
+  grub_memcpy (tmp_ptr, &inf->address.ipv4, pln);
8e15ce
+  tmp_ptr += pln;
8e15ce
+
8e15ce
+  /* The target hardware address. */
8e15ce
+  grub_memset (tmp_ptr, 0, hln);
8e15ce
+  tmp_ptr += hln;
8e15ce
+
8e15ce
+  /* The target protocol address */
8e15ce
+  grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln);
8e15ce
+  tmp_ptr += pln;
8e15ce
+
8e15ce
+  grub_memset (&target_mac_addr.mac, 0xff, hln);
8e15ce
 
8e15ce
   nbd = nb.data;
8e15ce
   send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP);
8e15ce
@@ -114,28 +124,53 @@ grub_err_t
8e15ce
 grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
8e15ce
                       grub_uint16_t *vlantag)
8e15ce
 {
8e15ce
-  struct arppkt *arp_packet = (struct arppkt *) nb->data;
8e15ce
+  struct arphdr *arp_header = (struct arphdr *) nb->data;
8e15ce
   grub_net_network_level_address_t sender_addr, target_addr;
8e15ce
   grub_net_link_level_address_t sender_mac_addr;
8e15ce
   struct grub_net_network_level_interface *inf;
8e15ce
+  grub_uint16_t hw_type;
8e15ce
+  grub_uint8_t hln;
8e15ce
+  grub_uint8_t pln;
8e15ce
+  grub_uint8_t arp_packet_len;
8e15ce
+  grub_uint8_t *tmp_ptr;
8e15ce
 
8e15ce
-  if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
8e15ce
-      || arp_packet->pln != 4 || arp_packet->hln != 6
8e15ce
-      || nb->tail - nb->data < (int) sizeof (*arp_packet))
8e15ce
+  hw_type = card->default_address.type;
8e15ce
+  hln = card->default_address.len;
8e15ce
+  pln = sizeof(sender_addr.ipv4);
8e15ce
+  arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln);
8e15ce
+
8e15ce
+  if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
8e15ce
+      || arp_header->hrd != grub_cpu_to_be16 (hw_type)
8e15ce
+      || arp_header->hln != hln || arp_header->pln != pln
8e15ce
+      || nb->tail - nb->data < (int) arp_packet_len) {
8e15ce
     return GRUB_ERR_NONE;
8e15ce
+  }
8e15ce
 
8e15ce
+  tmp_ptr =  nb->data + sizeof (*arp_header);
8e15ce
+
8e15ce
+  /* The source hardware address. */
8e15ce
+  sender_mac_addr.type = hw_type;
8e15ce
+  sender_mac_addr.len = hln;
8e15ce
+  grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln);
8e15ce
+  tmp_ptr += hln;
8e15ce
+
8e15ce
+  /* The source protocol address. */
8e15ce
   sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
8e15ce
+  grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln);
8e15ce
+  tmp_ptr += pln;
8e15ce
+
8e15ce
+  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
8e15ce
+
8e15ce
+  /* The target hardware address. */
8e15ce
+  tmp_ptr += hln;
8e15ce
+
8e15ce
+  /* The target protocol address. */
8e15ce
   target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
8e15ce
-  sender_addr.ipv4 = arp_packet->sender_ip;
8e15ce
-  target_addr.ipv4 = arp_packet->recv_ip;
8e15ce
-  if (arp_packet->sender_ip == pending_req)
8e15ce
+  grub_memcpy(&target_addr.ipv4, tmp_ptr, pln);
8e15ce
+
8e15ce
+  if (sender_addr.ipv4 == pending_req)
8e15ce
     have_pending = 1;
8e15ce
 
8e15ce
-  sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-  grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac,
8e15ce
-	       sizeof (sender_mac_addr.mac));
8e15ce
-  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
8e15ce
-
8e15ce
   FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
8e15ce
   {
8e15ce
     /* Verify vlantag id */
8e15ce
@@ -148,11 +183,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
8e15ce
 
8e15ce
     /* Am I the protocol address target? */
8e15ce
     if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
8e15ce
-	&& arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
8e15ce
+	&& arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
8e15ce
       {
8e15ce
 	grub_net_link_level_address_t target;
8e15ce
 	struct grub_net_buff nb_reply;
8e15ce
-	struct arppkt *arp_reply;
8e15ce
+	struct arphdr *arp_reply;
8e15ce
 	grub_uint8_t arp_data[128];
8e15ce
 	grub_err_t err;
8e15ce
 
8e15ce
@@ -161,25 +196,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
8e15ce
 	grub_netbuff_clear (&nb_reply);
8e15ce
 	grub_netbuff_reserve (&nb_reply, 128);
8e15ce
 
8e15ce
-	err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet));
8e15ce
+	err = grub_netbuff_push (&nb_reply, arp_packet_len);
8e15ce
 	if (err)
8e15ce
 	  return err;
8e15ce
 
8e15ce
-	arp_reply = (struct arppkt *) nb_reply.data;
8e15ce
+	arp_reply = (struct arphdr *) nb_reply.data;
8e15ce
 
8e15ce
-	arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
8e15ce
+	arp_reply->hrd = grub_cpu_to_be16 (hw_type);
8e15ce
 	arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
8e15ce
-	arp_reply->pln = 4;
8e15ce
-	arp_reply->hln = 6;
8e15ce
+	arp_reply->pln = pln;
8e15ce
+	arp_reply->hln = hln;
8e15ce
 	arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY);
8e15ce
-	arp_reply->sender_ip = arp_packet->recv_ip;
8e15ce
-	arp_reply->recv_ip = arp_packet->sender_ip;
8e15ce
-	arp_reply->hln = 6;
8e15ce
-
8e15ce
-	target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-	grub_memcpy (target.mac, arp_packet->sender_mac, 6);
8e15ce
-	grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6);
8e15ce
-	grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6);
8e15ce
+
8e15ce
+	tmp_ptr = nb_reply.data + sizeof (*arp_reply);
8e15ce
+
8e15ce
+	/* The source hardware address. */
8e15ce
+	grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln);
8e15ce
+	tmp_ptr += hln;
8e15ce
+
8e15ce
+	/* The source protocol address. */
8e15ce
+	grub_memcpy (tmp_ptr, &target_addr.ipv4, pln);
8e15ce
+	tmp_ptr += pln;
8e15ce
+
8e15ce
+	/* The target hardware address. */
8e15ce
+	grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln);
8e15ce
+	tmp_ptr += hln;
8e15ce
+
8e15ce
+	/* The target protocol address */
8e15ce
+	grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln);
8e15ce
+	tmp_ptr += pln;
8e15ce
+
8e15ce
+	target.type = hw_type;
8e15ce
+	target.len = hln;
8e15ce
+	grub_memcpy (target.mac, sender_mac_addr.mac, hln);
8e15ce
 
8e15ce
 	/* Change operation to REPLY and send packet */
8e15ce
 	send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP);
8e15ce
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
8e15ce
index e28fb6a09f9..08b6b2b5d6c 100644
8e15ce
--- a/grub-core/net/bootp.c
8e15ce
+++ b/grub-core/net/bootp.c
8e15ce
@@ -233,7 +233,6 @@ grub_net_configure_by_dhcp_ack (const char *name,
8e15ce
 				int is_def, char **device, char **path)
8e15ce
 {
8e15ce
   grub_net_network_level_address_t addr;
8e15ce
-  grub_net_link_level_address_t hwaddr;
8e15ce
   struct grub_net_network_level_interface *inter;
8e15ce
   int mask = -1;
8e15ce
   char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
8e15ce
@@ -250,12 +249,8 @@ grub_net_configure_by_dhcp_ack (const char *name,
8e15ce
   if (path)
8e15ce
     *path = 0;
8e15ce
 
8e15ce
-  grub_memcpy (hwaddr.mac, bp->mac_addr,
8e15ce
-	       bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
8e15ce
-	       : sizeof (hwaddr.mac));
8e15ce
-  hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-
8e15ce
-  inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
8e15ce
+  grub_dprintf("dhcp", "configuring dhcp for %s\n", name);
8e15ce
+  inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags);
8e15ce
   if (!inter)
8e15ce
     return 0;
8e15ce
 
8e15ce
@@ -567,7 +562,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
8e15ce
   grub_memset (pack, 0, sizeof (*pack));
8e15ce
   pack->opcode = 1;
8e15ce
   pack->hw_type = 1;
8e15ce
-  pack->hw_len = 6;
8e15ce
+  pack->hw_len = iface->hwaddress.len > 16 ? 0
8e15ce
+                                              : iface->hwaddress.len;
8e15ce
+
8e15ce
   err = grub_get_datetime (&date);
8e15ce
   if (err || !grub_datetime2unixtime (&date, &t))
8e15ce
     {
8e15ce
@@ -580,7 +577,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface)
8e15ce
   else
8e15ce
     pack->ident = iface->xid;
8e15ce
 
8e15ce
-  grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6);
8e15ce
+  grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, pack->hw_len);
8e15ce
 
8e15ce
   grub_netbuff_push (nb, sizeof (*udph));
8e15ce
 
8e15ce
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
8e15ce
index 173fb63153c..a673bea807a 100644
8e15ce
--- a/grub-core/net/drivers/efi/efinet.c
8e15ce
+++ b/grub-core/net/drivers/efi/efinet.c
8e15ce
@@ -279,6 +279,9 @@ grub_efinet_findcards (void)
8e15ce
 	/* This should not happen... Why?  */
8e15ce
 	continue;
8e15ce
 
8e15ce
+      if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
8e15ce
+	continue;
8e15ce
+
8e15ce
       if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
8e15ce
 	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
8e15ce
 	continue;
8e15ce
@@ -315,10 +318,11 @@ grub_efinet_findcards (void)
8e15ce
       card->name = grub_xasprintf ("efinet%d", i++);
8e15ce
       card->driver = &efidriver;
8e15ce
       card->flags = 0;
8e15ce
-      card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
+      card->default_address.type = net->mode->if_type;
8e15ce
+      card->default_address.len = net->mode->hwaddr_size;
8e15ce
       grub_memcpy (card->default_address.mac,
8e15ce
 		   net->mode->current_address,
8e15ce
-		   sizeof (card->default_address.mac));
8e15ce
+		   net->mode->hwaddr_size);
8e15ce
       card->efi_net = net;
8e15ce
       card->efi_handle = *handle;
8e15ce
 
8e15ce
diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c
8e15ce
index b194920861f..5b6c5e16a6d 100644
8e15ce
--- a/grub-core/net/drivers/emu/emunet.c
8e15ce
+++ b/grub-core/net/drivers/emu/emunet.c
8e15ce
@@ -46,6 +46,7 @@ static struct grub_net_card emucard =
8e15ce
     .mtu = 1500,
8e15ce
     .default_address = {
8e15ce
 			 .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET,
8e15ce
+			 . len = 6,
8e15ce
 			 {.mac = {0, 1, 2, 3, 4, 5}}
8e15ce
 		       },
8e15ce
     .flags = 0
8e15ce
diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c
8e15ce
index 3f4152d036c..9f8fb4b6d2b 100644
8e15ce
--- a/grub-core/net/drivers/i386/pc/pxe.c
8e15ce
+++ b/grub-core/net/drivers/i386/pc/pxe.c
8e15ce
@@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe)
8e15ce
   grub_memset (ui, 0, sizeof (*ui));
8e15ce
   grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry);
8e15ce
 
8e15ce
+  grub_pxe_card.default_address.len = 6;
8e15ce
   grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr,
8e15ce
-	       sizeof (grub_pxe_card.default_address.mac));
8e15ce
-  for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
8e15ce
+	       grub_pxe_card.default_address.len);
8e15ce
+  for (i = 0; i < grub_pxe_card.default_address.len; i++)
8e15ce
     if (grub_pxe_card.default_address.mac[i] != 0)
8e15ce
       break;
8e15ce
-  if (i != sizeof (grub_pxe_card.default_address.mac))
8e15ce
+  if (i != grub_pxe_card.default_address.len)
8e15ce
     {
8e15ce
-      for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
8e15ce
+      for (i = 0; i < grub_pxe_card.default_address.len; i++)
8e15ce
 	if (grub_pxe_card.default_address.mac[i] != 0xff)
8e15ce
 	  break;
8e15ce
     }
8e15ce
-  if (i == sizeof (grub_pxe_card.default_address.mac))
8e15ce
+  if (i == grub_pxe_card.default_address.len)
8e15ce
     grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr,
8e15ce
-		 sizeof (grub_pxe_card.default_address.mac));
8e15ce
+		 grub_pxe_card.default_address.len);
8e15ce
   grub_pxe_card.mtu = ui->mtu;
8e15ce
 
8e15ce
   grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
8e15ce
index 3860b6f78d8..bcb3f9ea02d 100644
8e15ce
--- a/grub-core/net/drivers/ieee1275/ofnet.c
8e15ce
+++ b/grub-core/net/drivers/ieee1275/ofnet.c
8e15ce
@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
8e15ce
   grub_uint16_t vlantag = 0;
8e15ce
 
8e15ce
   hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
+  hw_addr.len = 6;
8e15ce
 
8e15ce
   args = bootpath + grub_strlen (devpath) + 1;
8e15ce
   do
8e15ce
@@ -503,6 +504,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
8e15ce
     grub_memcpy (&lla.mac, pprop, 6);
8e15ce
 
8e15ce
   lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
+  lla.len = 6;
8e15ce
   card->default_address = lla;
8e15ce
 
8e15ce
   card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
8e15ce
diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c
8e15ce
index 056052e40d5..22ebcbf211e 100644
8e15ce
--- a/grub-core/net/drivers/uboot/ubootnet.c
8e15ce
+++ b/grub-core/net/drivers/uboot/ubootnet.c
8e15ce
@@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet)
8e15ce
 
8e15ce
       grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6);
8e15ce
       card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
+      card->default_address.len = 6;
8e15ce
 
8e15ce
       card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
8e15ce
       card->txbuf = grub_zalloc (card->txbufsize);
8e15ce
diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c
8e15ce
index 4d7ceed6f93..9aae83a5eb4 100644
8e15ce
--- a/grub-core/net/ethernet.c
8e15ce
+++ b/grub-core/net/ethernet.c
8e15ce
@@ -29,13 +29,6 @@
8e15ce
 
8e15ce
 #define LLCADDRMASK 0x7f
8e15ce
 
8e15ce
-struct etherhdr
8e15ce
-{
8e15ce
-  grub_uint8_t dst[6];
8e15ce
-  grub_uint8_t src[6];
8e15ce
-  grub_uint16_t type;
8e15ce
-} GRUB_PACKED;
8e15ce
-
8e15ce
 struct llchdr
8e15ce
 {
8e15ce
   grub_uint8_t dsap;
8e15ce
@@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
8e15ce
 		      grub_net_link_level_address_t target_addr,
8e15ce
 		      grub_net_ethertype_t ethertype)
8e15ce
 {
8e15ce
-  struct etherhdr *eth;
8e15ce
+  grub_uint8_t *eth;
8e15ce
   grub_err_t err;
8e15ce
-  grub_uint8_t etherhdr_size;
8e15ce
-  grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER;
8e15ce
+  grub_uint32_t vlantag = 0;
8e15ce
+  grub_uint8_t hw_addr_len = inf->card->default_address.len;
8e15ce
+  grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2;
8e15ce
 
8e15ce
-  etherhdr_size = sizeof (*eth);
8e15ce
-  COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE);
8e15ce
+  /* Source and destination link addresses + ethertype + vlan tag */
8e15ce
+  COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) <
8e15ce
+		       GRUB_NET_MAX_LINK_HEADER_SIZE);
8e15ce
 
8e15ce
   /* Increase ethernet header in case of vlantag */
8e15ce
   if (inf->vlantag != 0)
8e15ce
@@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
8e15ce
   err = grub_netbuff_push (nb, etherhdr_size);
8e15ce
   if (err)
8e15ce
     return err;
8e15ce
-  eth = (struct etherhdr *) nb->data;
8e15ce
-  grub_memcpy (eth->dst, target_addr.mac, 6);
8e15ce
-  grub_memcpy (eth->src, inf->hwaddress.mac, 6);
8e15ce
+  eth = nb->data;
8e15ce
+  grub_memcpy (eth, target_addr.mac, hw_addr_len);
8e15ce
+  eth += hw_addr_len;
8e15ce
+  grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len);
8e15ce
+  eth += hw_addr_len;
8e15ce
+
8e15ce
+  /* Check if a vlan-tag is present. */
8e15ce
+  if (vlantag != 0)
8e15ce
+    {
8e15ce
+      *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag);
8e15ce
+      eth += sizeof (vlantag);
8e15ce
+    }
8e15ce
+
8e15ce
+  /* Write ethertype */
8e15ce
+  *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype);
8e15ce
 
8e15ce
-  eth->type = grub_cpu_to_be16 (ethertype);
8e15ce
   if (!inf->card->opened)
8e15ce
     {
8e15ce
       err = GRUB_ERR_NONE;
8e15ce
@@ -85,18 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
8e15ce
       inf->card->opened = 1;
8e15ce
     }
8e15ce
 
8e15ce
-  /* Check and add a vlan-tag if needed. */
8e15ce
-  if (inf->vlantag != 0)
8e15ce
-    {
8e15ce
-      /* Move eth type to the right */
8e15ce
-      grub_memcpy ((char *) nb->data + etherhdr_size - 2,
8e15ce
-                   (char *) nb->data + etherhdr_size - 6, 2);
8e15ce
-
8e15ce
-      /* Add the tag in the middle */
8e15ce
-      grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2);
8e15ce
-      grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2);
8e15ce
-    }
8e15ce
-
8e15ce
   return inf->card->driver->send (inf->card, nb);
8e15ce
 }
8e15ce
 
8e15ce
@@ -104,31 +98,40 @@ grub_err_t
8e15ce
 grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
8e15ce
 			       struct grub_net_card *card)
8e15ce
 {
8e15ce
-  struct etherhdr *eth;
8e15ce
+  grub_uint8_t *eth;
8e15ce
   struct llchdr *llch;
8e15ce
   struct snaphdr *snaph;
8e15ce
   grub_net_ethertype_t type;
8e15ce
   grub_net_link_level_address_t hwaddress;
8e15ce
   grub_net_link_level_address_t src_hwaddress;
8e15ce
   grub_err_t err;
8e15ce
-  grub_uint8_t etherhdr_size = sizeof (*eth);
8e15ce
+  grub_uint8_t hw_addr_len = card->default_address.len;
8e15ce
+  grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2;
8e15ce
   grub_uint16_t vlantag = 0;
8e15ce
 
8e15ce
+  eth = nb->data;
8e15ce
 
8e15ce
-  /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */
8e15ce
-  /* longer than the original one. The vlantag id is extracted and the header */
8e15ce
-  /* is reseted to the original size. */
8e15ce
-  if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER)
8e15ce
+  hwaddress.type = card->default_address.type;
8e15ce
+  hwaddress.len = hw_addr_len;
8e15ce
+  grub_memcpy (hwaddress.mac, eth, hw_addr_len);
8e15ce
+  eth += hw_addr_len;
8e15ce
+
8e15ce
+  src_hwaddress.type = card->default_address.type;
8e15ce
+  src_hwaddress.len = hw_addr_len;
8e15ce
+  grub_memcpy (src_hwaddress.mac, eth, hw_addr_len);
8e15ce
+  eth += hw_addr_len;
8e15ce
+
8e15ce
+  type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
8e15ce
+  if (type == VLANTAG_IDENTIFIER)
8e15ce
     {
8e15ce
-      vlantag = grub_get_unaligned16 (nb->data + etherhdr_size);
8e15ce
+      /* Skip vlan tag */
8e15ce
+      eth += 2;
8e15ce
+      vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
8e15ce
       etherhdr_size += 4;
8e15ce
-      /* Move eth type to the original position */
8e15ce
-      grub_memcpy((char *) nb->data + etherhdr_size - 6,
8e15ce
-                  (char *) nb->data + etherhdr_size - 2, 2);
8e15ce
+      eth += 2;
8e15ce
+      type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
8e15ce
     }
8e15ce
 
8e15ce
-  eth = (struct etherhdr *) nb->data;
8e15ce
-  type = grub_be_to_cpu16 (eth->type);
8e15ce
   err = grub_netbuff_pull (nb, etherhdr_size);
8e15ce
   if (err)
8e15ce
     return err;
8e15ce
@@ -148,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
8e15ce
 	}
8e15ce
     }
8e15ce
 
8e15ce
-  hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-  grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac));
8e15ce
-  src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-  grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac));
8e15ce
-
8e15ce
   switch (type)
8e15ce
     {
8e15ce
       /* ARP packet. */
8e15ce
diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c
8e15ce
index 2cbd95dce25..56a3ec5c8e8 100644
8e15ce
--- a/grub-core/net/icmp6.c
8e15ce
+++ b/grub-core/net/icmp6.c
8e15ce
@@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
8e15ce
 		&& ohdr->len == 1)
8e15ce
 	      {
8e15ce
 		grub_net_link_level_address_t ll_address;
8e15ce
-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
8e15ce
+		ll_address.type = card->default_address.type;
8e15ce
+		ll_address.len = card->default_address.len;
8e15ce
+		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
8e15ce
 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
8e15ce
 	      }
8e15ce
 	  }
8e15ce
@@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
8e15ce
 		&& ohdr->len == 1)
8e15ce
 	      {
8e15ce
 		grub_net_link_level_address_t ll_address;
8e15ce
-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
8e15ce
+		ll_address.type = card->default_address.type;
8e15ce
+		ll_address.len = card->default_address.len;
8e15ce
+		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
8e15ce
 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
8e15ce
 	      }
8e15ce
 	  }
8e15ce
@@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
8e15ce
 		&& ohdr->len == 1)
8e15ce
 	      {
8e15ce
 		grub_net_link_level_address_t ll_address;
8e15ce
-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
8e15ce
+		ll_address.type = card->default_address.type;
8e15ce
+		ll_address.len = card->default_address.len;
8e15ce
+		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
8e15ce
 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
8e15ce
 	      }
8e15ce
 	    if (ohdr->type == OPTION_PREFIX && ohdr->len == 4)
8e15ce
diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
8e15ce
index ea5edf8f1f6..a5896f6dc26 100644
8e15ce
--- a/grub-core/net/ip.c
8e15ce
+++ b/grub-core/net/ip.c
8e15ce
@@ -276,8 +276,8 @@ handle_dgram (struct grub_net_buff *nb,
8e15ce
 	  if (inf->card == card
8e15ce
 	      && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
8e15ce
 	      && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
8e15ce
-	      && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
8e15ce
-			      sizeof (inf->hwaddress.mac)) == 0)
8e15ce
+	      && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
8e15ce
+			       bootp->hw_len) == 0 || bootp->hw_len == 0))
8e15ce
 	    {
8e15ce
 	      grub_net_process_dhcp (nb, inf);
8e15ce
 	      grub_netbuff_free (nb);
8e15ce
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
8e15ce
index 22f2689aaeb..a46f82362ed 100644
8e15ce
--- a/grub-core/net/net.c
8e15ce
+++ b/grub-core/net/net.c
8e15ce
@@ -133,8 +133,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
8e15ce
 								   << 48)
8e15ce
 	  && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1))))
8e15ce
     {
8e15ce
-      hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
-      grub_memset (hw_addr->mac, -1, 6);
8e15ce
+      hw_addr->type = inf->card->default_address.type;
8e15ce
+      hw_addr->len = inf->card->default_address.len;
8e15ce
+      grub_memset (hw_addr->mac, -1, hw_addr->len);
8e15ce
       return GRUB_ERR_NONE;
8e15ce
     }
8e15ce
 
8e15ce
@@ -142,6 +143,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
8e15ce
       && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff))
8e15ce
     {
8e15ce
       hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
8e15ce
+      hw_addr->len = inf->card->default_address.len;
8e15ce
       hw_addr->mac[0] = 0x33;
8e15ce
       hw_addr->mac[1] = 0x33;
8e15ce
       hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff);
8e15ce
@@ -762,23 +764,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
8e15ce
 void
8e15ce
 grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
8e15ce
 {
8e15ce
-  str[0] = 0;
8e15ce
-  switch (addr->type)
8e15ce
+  char *ptr;
8e15ce
+  unsigned i;
8e15ce
+  int maxstr;
8e15ce
+
8e15ce
+  if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
8e15ce
     {
8e15ce
-    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
8e15ce
-      {
8e15ce
-	char *ptr;
8e15ce
-	unsigned i;
8e15ce
-	for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++)
8e15ce
-	  {
8e15ce
-	    grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
8e15ce
-			   "%02x:", addr->mac[i] & 0xff);
8e15ce
-	    ptr += (sizeof ("XX:") - 1);
8e15ce
-	  }
8e15ce
-      return;
8e15ce
-      }
8e15ce
+       str[0] = 0;
8e15ce
+       grub_printf (_("Unsupported hw address type %d len %d\n"),
8e15ce
+		    addr->type, addr->len);
8e15ce
+       return;
8e15ce
+    }
8e15ce
+  maxstr = addr->len * grub_strlen ("XX:");
8e15ce
+  for (ptr = str, i = 0; i < addr->len; i++)
8e15ce
+    {
8e15ce
+      ptr += grub_snprintf (ptr, maxstr - (ptr - str),
8e15ce
+		     "%02x:", addr->mac[i] & 0xff);
8e15ce
     }
8e15ce
-  grub_printf (_("Unsupported hw address type %d\n"), addr->type);
8e15ce
 }
8e15ce
 
8e15ce
 int
8e15ce
@@ -789,13 +791,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
8e15ce
     return -1;
8e15ce
   if (a->type > b->type)
8e15ce
     return +1;
8e15ce
-  switch (a->type)
8e15ce
+  if (a->len < b->len)
8e15ce
+    return -1;
8e15ce
+  if (a->len > b->len)
8e15ce
+    return +1;
8e15ce
+  if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
8e15ce
     {
8e15ce
-    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
8e15ce
-      return grub_memcmp (a->mac, b->mac, sizeof (a->mac));
8e15ce
+      grub_printf (_("Unsupported hw address type %d len %d\n"),
8e15ce
+		   a->type, a->len);
8e15ce
+      return + 1;
8e15ce
     }
8e15ce
-  grub_printf (_("Unsupported hw address type %d\n"), a->type);
8e15ce
-  return 1;
8e15ce
+  return grub_memcmp (a->mac, b->mac, a->len);
8e15ce
 }
8e15ce
 
8e15ce
 int
8e15ce
diff --git a/include/grub/net.h b/include/grub/net.h
8e15ce
index 8a05ec4fe7a..af0404db7e3 100644
8e15ce
--- a/include/grub/net.h
8e15ce
+++ b/include/grub/net.h
8e15ce
@@ -29,7 +29,8 @@
8e15ce
 
8e15ce
 enum
8e15ce
   {
8e15ce
-    GRUB_NET_MAX_LINK_HEADER_SIZE = 64,
8e15ce
+    GRUB_NET_MAX_LINK_HEADER_SIZE = 96,
8e15ce
+    GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32,
8e15ce
     GRUB_NET_UDP_HEADER_SIZE = 8,
8e15ce
     GRUB_NET_TCP_HEADER_SIZE = 20,
8e15ce
     GRUB_NET_OUR_IPV4_HEADER_SIZE = 20,
8e15ce
@@ -42,15 +43,17 @@ enum
8e15ce
 
8e15ce
 typedef enum grub_link_level_protocol_id 
8e15ce
 {
8e15ce
-  GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
8e15ce
+  /* IANA ARP constant to define hardware type. */
8e15ce
+  GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1,
8e15ce
 } grub_link_level_protocol_id_t;
8e15ce
 
8e15ce
 typedef struct grub_net_link_level_address
8e15ce
 {
8e15ce
   grub_link_level_protocol_id_t type;
8e15ce
+  grub_uint8_t len;
8e15ce
   union
8e15ce
   {
8e15ce
-    grub_uint8_t mac[6];
8e15ce
+    grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE];
8e15ce
   };
8e15ce
 } grub_net_link_level_address_t;
8e15ce
 
8e15ce
@@ -566,11 +569,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a,
8e15ce
 #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")
8e15ce
 
8e15ce
 /*
8e15ce
-  Currently suppoerted adresses:
8e15ce
-  ethernet:   XX:XX:XX:XX:XX:XX
8e15ce
+  Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE
8e15ce
  */
8e15ce
-
8e15ce
-#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX"))
8e15ce
+#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\
8e15ce
+	"XX:XX:XX:XX:XX:XX:XX:XX:"\
8e15ce
+	"XX:XX:XX:XX:XX:XX:XX:XX:"\
8e15ce
+	"XX:XX:XX:XX:XX:XX:XX:XX:"\
8e15ce
+	"XX:XX:XX:XX:XX:XX:XX:XX"))
8e15ce
 
8e15ce
 void
8e15ce
 grub_net_addr_to_str (const grub_net_network_level_address_t *target,