9d15b4d
From de423b22780b0fd225a1ee476166777af29d53d0 Mon Sep 17 00:00:00 2001
f4c76c0
From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
f4c76c0
Date: Tue, 30 Oct 2012 15:19:39 -0200
ce21efa
Subject: [PATCH 024/123] Add vlan-tag support on IBM PPC machines
f4c76c0
f4c76c0
This patch adds support for virtual LAN (VLAN) tagging. VLAN tagging allows
f4c76c0
multiple VLANs in a bridged network to share the same physical network link but
f4c76c0
maintain isolation:
f4c76c0
f4c76c0
http://en.wikipedia.org/wiki/IEEE_802.1Q
f4c76c0
f4c76c0
This patch should fix this bugzilla:
f4c76c0
https://bugzilla.redhat.com/show_bug.cgi?id=871563
f4c76c0
---
f4c76c0
 grub-core/kern/ieee1275/init.c   |  1 +
f4c76c0
 grub-core/kern/ieee1275/openfw.c | 30 ++++++++++++++++++++++++++++
f4c76c0
 grub-core/net/ethernet.c         | 42 +++++++++++++++++++++++++++++++++++++---
f4c76c0
 include/grub/ieee1275/ieee1275.h |  1 +
f4c76c0
 include/grub/net.h               |  2 ++
f4c76c0
 5 files changed, 73 insertions(+), 3 deletions(-)
f4c76c0
f4c76c0
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
ce21efa
index 12590225e..5fa26e189 100644
f4c76c0
--- a/grub-core/kern/ieee1275/init.c
f4c76c0
+++ b/grub-core/kern/ieee1275/init.c
b9efc54
@@ -125,6 +125,7 @@ grub_machine_get_bootlocation (char **device, char **path)
f4c76c0
       char *dev, *canon;
f4c76c0
       char *ptr;
f4c76c0
       dev = grub_ieee1275_get_aliasdevname (bootpath);
f4c76c0
+      grub_ieee1275_parse_net_options (bootpath);
f4c76c0
       canon = grub_ieee1275_canonicalise_devname (dev);
f4c76c0
       ptr = canon + grub_strlen (canon) - 1;
f4c76c0
       while (ptr > canon && (*ptr == ',' || *ptr == ':'))
f4c76c0
diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c
ce21efa
index 6db8b9865..81276fae7 100644
f4c76c0
--- a/grub-core/kern/ieee1275/openfw.c
f4c76c0
+++ b/grub-core/kern/ieee1275/openfw.c
f4c76c0
@@ -23,6 +23,7 @@
f4c76c0
 #include <grub/mm.h>
f4c76c0
 #include <grub/ieee1275/ieee1275.h>
f4c76c0
 #include <grub/net.h>
f4c76c0
+#include <grub/env.h>
f4c76c0
 
f4c76c0
 enum grub_ieee1275_parse_type
f4c76c0
 {
f4c76c0
@@ -451,6 +452,35 @@ fail:
f4c76c0
   return ret;
f4c76c0
 }
f4c76c0
 
f4c76c0
+int
f4c76c0
+grub_ieee1275_parse_net_options (const char *path)
f4c76c0
+{
f4c76c0
+  char *comma;
f4c76c0
+  char *args;
f4c76c0
+  char *option = 0;
f4c76c0
+
f4c76c0
+  args = grub_ieee1275_get_devargs (path);
f4c76c0
+  if (!args)
f4c76c0
+    /* There is no option.  */
f4c76c0
+    return -1;
f4c76c0
+
f4c76c0
+  do
f4c76c0
+    {
f4c76c0
+      comma = grub_strchr (args, ',');
f4c76c0
+      if (! comma)
f4c76c0
+        option = grub_strdup (args);
f4c76c0
+      else
f4c76c0
+        option = grub_strndup (args, (grub_size_t)(comma - args));
f4c76c0
+      args = comma + 1;
f4c76c0
+
f4c76c0
+      if (! grub_strncmp(option, "vtag", 4))
f4c76c0
+          grub_env_set ("vlan-tag", option + grub_strlen("vtag="));
f4c76c0
+
f4c76c0
+    } while (comma);
f4c76c0
+
f4c76c0
+  return 0;
f4c76c0
+}
f4c76c0
+
f4c76c0
 char *
f4c76c0
 grub_ieee1275_get_device_type (const char *path)
f4c76c0
 {
f4c76c0
diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c
ce21efa
index c397b1b34..faaca67c5 100644
f4c76c0
--- a/grub-core/net/ethernet.c
f4c76c0
+++ b/grub-core/net/ethernet.c
f4c76c0
@@ -23,6 +23,7 @@
f4c76c0
 #include <grub/net/arp.h>
f4c76c0
 #include <grub/net/netbuff.h>
f4c76c0
 #include <grub/net.h>
f4c76c0
+#include <grub/env.h>
f4c76c0
 #include <grub/time.h>
f4c76c0
 #include <grub/net/arp.h>
f4c76c0
 
f4c76c0
@@ -56,10 +57,19 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
f4c76c0
 {
f4c76c0
   struct etherhdr *eth;
f4c76c0
   grub_err_t err;
f4c76c0
+  grub_uint32_t vlantag = 0;
f4c76c0
+  grub_uint8_t etherhdr_size;
f4c76c0
 
f4c76c0
-  COMPILE_TIME_ASSERT (sizeof (*eth) < GRUB_NET_MAX_LINK_HEADER_SIZE);
f4c76c0
+  etherhdr_size = sizeof (*eth);
f4c76c0
+  COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE);
f4c76c0
 
f4c76c0
-  err = grub_netbuff_push (nb, sizeof (*eth));
f4c76c0
+  const char *vlantag_text = grub_env_get ("vlan-tag");
f4c76c0
+  if (vlantag_text != 0) {
f4c76c0
+      etherhdr_size += 4;
f4c76c0
+      vlantag = grub_strtoul (vlantag_text, 0, 16);
f4c76c0
+  }
f4c76c0
+
f4c76c0
+  err = grub_netbuff_push (nb, etherhdr_size);
f4c76c0
   if (err)
f4c76c0
     return err;
f4c76c0
   eth = (struct etherhdr *) nb->data;
f4c76c0
@@ -76,6 +86,19 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
f4c76c0
 	return err;
f4c76c0
       inf->card->opened = 1;
f4c76c0
     }
f4c76c0
+
f4c76c0
+  /* Check if a vlan-tag is needed. */
f4c76c0
+  if (vlantag != 0)
f4c76c0
+    {
f4c76c0
+      /* Move eth type to the right */
f4c76c0
+      grub_memcpy((char *) nb->data + etherhdr_size - 2,
f4c76c0
+                  (char *) nb->data + etherhdr_size - 6, 2);
f4c76c0
+
f4c76c0
+      /* Add the tag in the middle */
f4c76c0
+      grub_memcpy((char *) nb->data + etherhdr_size - 6,
f4c76c0
+                  &vlantag, 4);
f4c76c0
+    }
f4c76c0
+
f4c76c0
   return inf->card->driver->send (inf->card, nb);
f4c76c0
 }
f4c76c0
 
f4c76c0
@@ -90,10 +113,23 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
f4c76c0
   grub_net_link_level_address_t hwaddress;
f4c76c0
   grub_net_link_level_address_t src_hwaddress;
f4c76c0
   grub_err_t err;
f4c76c0
+  grub_uint8_t etherhdr_size = sizeof (*eth);
f4c76c0
+
f4c76c0
+  grub_uint16_t vlantag_identifier = 0;
f4c76c0
+  grub_memcpy (&vlantag_identifier, nb->data + etherhdr_size - 2, 2);
f4c76c0
+
f4c76c0
+  /* Check if a vlan-tag is present. */
f4c76c0
+  if (vlantag_identifier == VLANTAG_IDENTIFIER)
f4c76c0
+    {
f4c76c0
+      etherhdr_size += 4;
f4c76c0
+      /* Move eth type to the original position */
f4c76c0
+      grub_memcpy((char *) nb->data + etherhdr_size - 6,
f4c76c0
+                  (char *) nb->data + etherhdr_size - 2, 2);
f4c76c0
+    }
f4c76c0
 
f4c76c0
   eth = (struct etherhdr *) nb->data;
f4c76c0
   type = grub_be_to_cpu16 (eth->type);
f4c76c0
-  err = grub_netbuff_pull (nb, sizeof (*eth));
f4c76c0
+  err = grub_netbuff_pull (nb, etherhdr_size);
f4c76c0
   if (err)
f4c76c0
     return err;
f4c76c0
 
f4c76c0
diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
ce21efa
index ab4f284c3..663935da7 100644
f4c76c0
--- a/include/grub/ieee1275/ieee1275.h
f4c76c0
+++ b/include/grub/ieee1275/ieee1275.h
0ac23e2
@@ -238,6 +238,7 @@ void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath,
f4c76c0
 						struct grub_ieee1275_devalias *alias);
0ac23e2
 int EXPORT_FUNC(grub_ieee1275_cas_reboot) (char *script);
0ac23e2
 int EXPORT_FUNC(grub_ieee1275_set_boot_last_label) (const char *text);
f4c76c0
+int EXPORT_FUNC(grub_ieee1275_parse_net_options) (const char *path);
f4c76c0
 
f4c76c0
 #define FOR_IEEE1275_DEVALIASES(alias) for (grub_ieee1275_devalias_init_iterator (&(alias)); grub_ieee1275_devalias_next (&(alias));)
f4c76c0
 
f4c76c0
diff --git a/include/grub/net.h b/include/grub/net.h
ce21efa
index 2192fa186..6ac9d72bf 100644
f4c76c0
--- a/include/grub/net.h
f4c76c0
+++ b/include/grub/net.h
0ac23e2
@@ -561,4 +561,6 @@ extern char *grub_net_default_server;
f4c76c0
 #define GRUB_NET_INTERVAL 400
f4c76c0
 #define GRUB_NET_INTERVAL_ADDITION 20
f4c76c0
 
f4c76c0
+#define VLANTAG_IDENTIFIER 0x8100
f4c76c0
+
f4c76c0
 #endif /* ! GRUB_NET_HEADER */
f4c76c0
-- 
ce21efa
2.14.3
f4c76c0