summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames <james.mckenzie@citrix.com>2012-11-16 20:03:50 +0000
committerJames <james.mckenzie@citrix.com>2012-11-16 20:03:50 +0000
commitd68f2690a91e97cc6cf977876f4b013438d09dd3 (patch)
tree48dc6c90e1c10f36724193bb186ddf32d19ed8fb
parent90bfd94a67b0b5458afdcee4c78fce7d44981dd8 (diff)
downloadgrub-1.99-pq-d68f2690a91e97cc6cf977876f4b013438d09dd3.tar.gz
grub-1.99-pq-d68f2690a91e97cc6cf977876f4b013438d09dd3.tar.bz2
grub-1.99-pq-d68f2690a91e97cc6cf977876f4b013438d09dd3.zip
fish
-rw-r--r--master/jmm/efi-load-drivers-bis467
-rw-r--r--master/jmm/efi-sni-bis828
-rw-r--r--master/jmm/efi_call_7-bis58
-rw-r--r--master/jmm/networking-bis2262
-rw-r--r--master/series10
5 files changed, 3625 insertions, 0 deletions
diff --git a/master/jmm/efi-load-drivers-bis b/master/jmm/efi-load-drivers-bis
new file mode 100644
index 0000000..9cef5f7
--- /dev/null
+++ b/master/jmm/efi-load-drivers-bis
@@ -0,0 +1,467 @@
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index fa1d0c7..16526d0 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -37,6 +37,10 @@ grub_efi_system_table_t *grub_efi_system_table;
+ static grub_efi_guid_t console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID;
+ static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
+ static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
++static grub_efi_guid_t driver_binding_guid = GRUB_EFI_DRIVER_BINDING_GUID;
++static grub_efi_guid_t driver_configuration_guid = GRUB_EFI_DRIVER_CONFIGURATION_GUID;
++static grub_efi_guid_t driver_diagnostics_guid = GRUB_EFI_DRIVER_DIAGNOSTICS_GUID;
++static grub_efi_guid_t component_name_guid = GRUB_EFI_COMPONENT_NAME_GUID;
+
+ void *
+ grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration)
+@@ -740,3 +744,303 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
+ dp = (grub_efi_device_path_t *) ((char *) dp + len);
+ }
+ }
++
++
++grub_efi_status_t grub_efi_free_pool (void *ptr)
++{
++ grub_efi_boot_services_t *b;
++ b = grub_efi_system_table->boot_services;
++
++ return efi_call_1 (b->free_pool, ptr);
++}
++
++void * grub_efi_allocate_pool (grub_efi_memory_type_t type, grub_efi_uintn_t len)
++{
++ grub_efi_boot_services_t *b;
++ grub_efi_status_t status;
++ void *ret;
++ b = grub_efi_system_table->boot_services;
++
++ status = efi_call_3 (b->allocate_pool, type, len, &ret);
++
++ if (status != GRUB_EFI_SUCCESS)
++ return (void *) 0;
++
++ return ret;
++}
++
++
++static int grub_efi_guid_cmp (grub_efi_guid_t * a, grub_efi_guid_t * b)
++{
++ return grub_memcmp (a, b, sizeof (grub_efi_guid_t));
++}
++
++
++
++grub_efi_status_t
++grub_efi_scan_handle_database (grub_efi_handle_t driver_binding_handle,
++ grub_efi_uint32_t *
++ driver_binding_i,
++ grub_efi_handle_t controller_handle,
++ grub_efi_uint32_t * controller_i,
++ grub_efi_uintn_t * handle_count,
++ grub_efi_handle_t ** handle_buffer,
++ grub_efi_uint32_t ** handle_type)
++{
++ grub_efi_boot_services_t *b;
++ grub_efi_status_t status;
++ grub_efi_uintn_t i, j, k;
++ grub_efi_guid_t **protocol_guid_array;
++ grub_efi_uintn_t array_count;
++ grub_efi_uintn_t protocol_index;
++ grub_efi_open_protocol_information_entry_t *open_info;
++ grub_efi_uintn_t open_info_count;
++ grub_efi_boolean_t driver_binding_i_valid;
++ grub_efi_boolean_t controller_i_valid;
++
++ b = grub_efi_system_table->boot_services;
++
++ driver_binding_i_valid = 0;
++ if (driver_binding_i != NULL)
++ {
++ *driver_binding_i = 0xffffffff;
++ }
++
++ controller_i_valid = 0;
++ if (controller_i != NULL)
++ {
++ *controller_i = 0xffffffff;
++ }
++ *handle_count = 0;
++ *handle_buffer = NULL;
++ *handle_type = NULL;
++
++ //
++ // Retrieve the list of all handles from the handle database
++ //
++ status = efi_call_5 (b->locate_handle_buffer,
++ GRUB_EFI_ALL_HANDLES,
++ NULL, NULL, handle_count, handle_buffer);
++
++ if (status != GRUB_EFI_SUCCESS)
++ goto error;
++
++ *handle_type = grub_malloc (*handle_count * sizeof (grub_efi_uint32_t));
++ if (!*handle_type)
++ goto error;
++
++ for (i = 0; i < *handle_count; i++)
++ {
++
++ //
++ // Assume that the handle type is unknown
++ //
++ (*handle_type)[i] = GRUB_EFI_HANDLE_TYPE_UNKNOWN;
++
++ if (driver_binding_handle != NULL && driver_binding_i != NULL
++ && (*handle_buffer)[i] == driver_binding_handle)
++ {
++ *driver_binding_i = (grub_efi_uint32_t) i;
++ driver_binding_i_valid = 1;
++ }
++
++ if (controller_handle != NULL && controller_i != NULL
++ && (*handle_buffer)[i] == controller_handle)
++ {
++ *controller_i = (grub_efi_uint32_t) i;
++ controller_i_valid = 1;
++ }
++ }
++
++ for (i = 0; i < *handle_count; i++)
++ {
++
++ //
++ // Retrieve the list of all the protocols on each handle
++ //
++ status = efi_call_3 (b->protocols_per_handle,
++ (*handle_buffer)[i],
++ &protocol_guid_array, &array_count);
++
++ if (status != GRUB_EFI_SUCCESS)
++ continue;
++
++ for (protocol_index = 0; protocol_index < array_count; protocol_index++)
++ {
++
++ if (grub_efi_guid_cmp
++ (protocol_guid_array[protocol_index], &loaded_image_guid) == 0)
++ {
++ (*handle_type)[i] |= GRUB_EFI_HANDLE_TYPE_IMAGE_HANDLE;
++ }
++
++ if (grub_efi_guid_cmp
++ (protocol_guid_array[protocol_index],
++ &driver_binding_guid) == 0)
++ {
++ (*handle_type)[i] |= GRUB_EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE;
++ }
++
++ if (grub_efi_guid_cmp
++ (protocol_guid_array[protocol_index],
++ &driver_configuration_guid) == 0)
++ {
++ (*handle_type)[i] |=
++ GRUB_EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE;
++ }
++
++ if (grub_efi_guid_cmp
++ (protocol_guid_array[protocol_index],
++ &driver_diagnostics_guid) == 0)
++ {
++ (*handle_type)[i] |=
++ GRUB_EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE;
++ }
++
++ if (grub_efi_guid_cmp
++ (protocol_guid_array[protocol_index],
++ &component_name_guid) == 0)
++ {
++ (*handle_type)[i] |= GRUB_EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE;
++ }
++
++ if (grub_efi_guid_cmp
++ (protocol_guid_array[protocol_index], &device_path_guid) == 0)
++ {
++ (*handle_type)[i] |= GRUB_EFI_HANDLE_TYPE_DEVICE_HANDLE;
++ }
++
++ //
++ // Retrieve the list of agents that have opened each protocol
++ //
++ status = efi_call_4 (b->open_protocol_information,
++ (*handle_buffer)[i],
++ protocol_guid_array[protocol_index],
++ &open_info, &open_info_count);
++
++ if (status != GRUB_EFI_SUCCESS)
++ continue;
++
++ for (j = 0; j < open_info_count; j++)
++ {
++
++ if (driver_binding_handle != NULL
++ && open_info[j].agent_handle == driver_binding_handle)
++ {
++ if ((open_info[j].
++ attributes & GRUB_EFI_OPEN_PROTOCOL_BY_DRIVER) ==
++ GRUB_EFI_OPEN_PROTOCOL_BY_DRIVER)
++ {
++ //
++ // Mark the device handle as being managed by the driver specified by driver_binding_handle
++ //
++ (*handle_type)[i] |=
++ (GRUB_EFI_HANDLE_TYPE_DEVICE_HANDLE |
++ GRUB_EFI_HANDLE_TYPE_CONTROLLER_HANDLE);
++ //
++ // Mark the driver_binding_handle as being a driver that is managing at least one controller
++ //
++ if (driver_binding_i_valid)
++ {
++ (*handle_type)[*driver_binding_i] |=
++ GRUB_EFI_HANDLE_TYPE_DEVICE_DRIVER;
++ }
++ }
++ if ((open_info[j].
++ attributes &
++ GRUB_EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) ==
++ GRUB_EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
++ {
++ //
++ // Mark the driver_binding_handle as being a driver that is managing at least one child controller
++ //
++ if (driver_binding_i_valid)
++ {
++ (*handle_type)[*driver_binding_i] |=
++ GRUB_EFI_HANDLE_TYPE_BUS_DRIVER;
++ }
++ }
++
++ if (controller_handle != NULL
++ && (*handle_buffer)[i] == controller_handle)
++ {
++ if ((open_info[j].
++ attributes &
++ GRUB_EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) ==
++ GRUB_EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
++ {
++ for (k = 0; k < *handle_count; k++)
++ {
++ if ((*handle_buffer)[k] ==
++ open_info[j].controller_handle)
++ {
++ (*handle_type)[k] |=
++ (GRUB_EFI_HANDLE_TYPE_DEVICE_HANDLE |
++ GRUB_EFI_HANDLE_TYPE_CHILD_HANDLE);
++ }
++ }
++ }
++ }
++ }
++
++
++ if (driver_binding_handle == NULL
++ && open_info[j].controller_handle == controller_handle)
++ {
++ if ((open_info[j].
++ attributes & GRUB_EFI_OPEN_PROTOCOL_BY_DRIVER) ==
++ GRUB_EFI_OPEN_PROTOCOL_BY_DRIVER)
++ {
++ for (k = 0; k < *handle_count; k++)
++ {
++ if ((*handle_buffer)[k] ==
++ open_info[j].agent_handle)
++ {
++ (*handle_type)[k] |=
++ GRUB_EFI_HANDLE_TYPE_DEVICE_DRIVER;
++ }
++ }
++ }
++ if ((open_info[j].
++ attributes &
++ GRUB_EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) ==
++ GRUB_EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER)
++ {
++ (*handle_type)[i] |= GRUB_EFI_HANDLE_TYPE_PARENT_HANDLE;
++ for (k = 0; k < *handle_count; k++)
++ {
++ if ((*handle_buffer)[k] ==
++ open_info[j].agent_handle)
++ {
++ (*handle_type)[k] |=
++ GRUB_EFI_HANDLE_TYPE_BUS_DRIVER;
++ }
++ }
++ }
++ }
++
++ }
++ grub_efi_free_pool (open_info);
++
++ }
++ grub_efi_free_pool (protocol_guid_array);
++ }
++
++ return GRUB_EFI_SUCCESS;
++
++error:
++ if (*handle_type != NULL)
++ grub_free (*handle_type);
++
++ if (*handle_buffer != NULL)
++ grub_efi_free_pool (*handle_buffer);
++ *handle_count = 0;
++ *handle_buffer = NULL;
++ *handle_type = NULL;
++
++ return status;
++}
++
++
++
++
+diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
+index 1b0a872..a83bf2e 100644
+--- a/grub-core/kern/efi/init.c
++++ b/grub-core/kern/efi/init.c
+@@ -26,6 +26,66 @@
+ #include <grub/mm.h>
+ #include <grub/kernel.h>
+
++static void bind_all_drivers (void)
++{
++ grub_efi_uintn_t n_all_handles;
++ grub_efi_handle_t *all_handles;
++ grub_efi_status_t status;
++ grub_efi_boot_services_t *b;
++ grub_efi_uintn_t handle_count;
++ grub_efi_handle_t *handle_buffer;
++ grub_efi_uint32_t *handle_type;
++ unsigned int i, j;
++
++ b = grub_efi_system_table->boot_services;
++
++ all_handles =
++ grub_efi_locate_handle (GRUB_EFI_ALL_HANDLES, NULL, NULL, &n_all_handles);
++
++ if (!all_handles)
++ return;
++
++ for (i = 0; i < n_all_handles; ++i)
++ {
++ int is_device = 1;
++
++ status =
++ grub_efi_scan_handle_database (NULL, NULL, all_handles[i], NULL,
++ &handle_count, &handle_buffer,
++ &handle_type);
++
++ if (status != GRUB_EFI_SUCCESS)
++ continue;
++
++ if (handle_type[i] & GRUB_EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE)
++ is_device = 0;
++ if (handle_type[i] & GRUB_EFI_HANDLE_TYPE_IMAGE_HANDLE)
++ is_device = 0;
++
++ if (is_device)
++ {
++ int is_parent = 0;
++ for (j = 0; j < handle_count; ++j)
++ {
++ if (handle_type[j] & GRUB_EFI_HANDLE_TYPE_PARENT_HANDLE)
++ is_parent = 1;
++ }
++
++ if ((!is_parent)
++ && (handle_type[i] & GRUB_EFI_HANDLE_TYPE_DEVICE_HANDLE))
++ {
++ efi_call_4 (b->connect_controller, all_handles[i], NULL, NULL, 1);
++ }
++ }
++
++ grub_free (handle_type);
++ grub_efi_free_pool (handle_buffer);
++ }
++
++ grub_free (all_handles);
++}
++
++
+ void
+ grub_efi_init (void)
+ {
+@@ -39,6 +99,8 @@ grub_efi_init (void)
+ efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer,
+ 0, 0, 0, NULL);
+
++ bind_all_drivers();
++
+ grub_efidisk_init ();
+ }
+
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 535a3e3..d8bce06 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -119,6 +119,26 @@
+ { 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98 } \
+ }
+
++#define GRUB_EFI_DRIVER_BINDING_GUID \
++ { 0x18a031ab, 0xb443, 0x4d1a, \
++ {0xa5, 0xc0, 0xc, 0x9, 0x26, 0x1e, 0x9f, 0x71 } \
++ }
++
++#define GRUB_EFI_DRIVER_CONFIGURATION_GUID \
++ { 0x107a772b, 0xd5e1, 0x11d4, \
++ {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
++ }
++
++#define GRUB_EFI_DRIVER_DIAGNOSTICS_GUID \
++ { 0x0784924f, 0xe296, 0x11d4, \
++ { 0x9a, 0x49, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
++ }
++
++#define GRUB_EFI_COMPONENT_NAME_GUID \
++ { 0x107a772c, 0xd5e1, 0x11d4, \
++ {0x9a, 0x46, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
++ }
++
+ struct grub_efi_sal_system_table
+ {
+ grub_uint32_t signature;
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index e9c57dd..a5b557b 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -68,6 +68,32 @@ void grub_efi_init (void);
+ void grub_efi_fini (void);
+ void grub_efi_set_prefix (void);
+
++grub_efi_status_t EXPORT_FUNC(grub_efi_scan_handle_database) (
++ grub_efi_handle_t driver_binding_handle,
++ grub_efi_uint32_t *driver_binding_handle_index,
++ grub_efi_handle_t controller_handle,
++ grub_efi_uint32_t *controller_handle_index,
++ grub_efi_uintn_t *handle_count,
++ grub_efi_handle_t **handle_buffer,
++ grub_efi_uint32_t **handle_type);
++
++#define GRUB_EFI_HANDLE_TYPE_UNKNOWN 0x000
++#define GRUB_EFI_HANDLE_TYPE_IMAGE_HANDLE 0x001
++#define GRUB_EFI_HANDLE_TYPE_DRIVER_BINDING_HANDLE 0x002
++#define GRUB_EFI_HANDLE_TYPE_DEVICE_DRIVER 0x004
++#define GRUB_EFI_HANDLE_TYPE_BUS_DRIVER 0x008
++#define GRUB_EFI_HANDLE_TYPE_DRIVER_CONFIGURATION_HANDLE 0x010
++#define GRUB_EFI_HANDLE_TYPE_DRIVER_DIAGNOSTICS_HANDLE 0x020
++#define GRUB_EFI_HANDLE_TYPE_COMPONENT_NAME_HANDLE 0x040
++#define GRUB_EFI_HANDLE_TYPE_DEVICE_HANDLE 0x080
++#define GRUB_EFI_HANDLE_TYPE_PARENT_HANDLE 0x100
++#define GRUB_EFI_HANDLE_TYPE_CONTROLLER_HANDLE 0x200
++#define GRUB_EFI_HANDLE_TYPE_CHILD_HANDLE 0x400
++
++void *EXPORT_FUNC(grub_efi_allocate_pool) (grub_efi_memory_type_t type, grub_efi_uintn_t len);
++grub_efi_status_t EXPORT_FUNC(grub_efi_free_pool) (void *);
++
++
+ /* Variables. */
+ extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
+ extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
diff --git a/master/jmm/efi-sni-bis b/master/jmm/efi-sni-bis
new file mode 100644
index 0000000..d63ec90
--- /dev/null
+++ b/master/jmm/efi-sni-bis
@@ -0,0 +1,828 @@
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 2cdcc7b..e297c4f 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -107,6 +107,7 @@ kernel = {
+ x86 = kern/i386/pit.c;
+
+ x86_efi = disk/efi/efidisk.c;
++ x86_efi = net/efi/efinet.c;
+ x86_efi = kern/efi/efi.c;
+ x86_efi = kern/efi/init.c;
+ x86_efi = kern/efi/mm.c;
+diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
+index a83bf2e..0c2a88c 100644
+--- a/grub-core/kern/efi/init.c
++++ b/grub-core/kern/efi/init.c
+@@ -20,6 +20,7 @@
+ #include <grub/efi/efi.h>
+ #include <grub/efi/console.h>
+ #include <grub/efi/disk.h>
++#include <grub/efi/net.h>
+ #include <grub/term.h>
+ #include <grub/misc.h>
+ #include <grub/env.h>
+@@ -102,6 +103,7 @@ grub_efi_init (void)
+ bind_all_drivers();
+
+ grub_efidisk_init ();
++ grub_efinet_init ();
+ }
+
+ void
+@@ -133,6 +135,11 @@ grub_efi_set_prefix (void)
+ if (image)
+ {
+ if (!device)
++ device = grub_efinet_get_device_name (image->device_handle);
++ /* If we net booted - hard code the prefix */
++ if (device && !path)
++ path = grub_strdup("/grub/");
++ if (!device)
+ device = grub_efidisk_get_device_name (image->device_handle);
+ else if (device[0] == ',' || !device[0])
+ {
+@@ -187,6 +194,7 @@ grub_efi_set_prefix (void)
+ void
+ grub_efi_fini (void)
+ {
++ grub_efinet_fini ();
+ grub_efidisk_fini ();
+ grub_console_fini ();
+ }
+diff --git a/grub-core/kern/i386/efi/init.c b/grub-core/kern/i386/efi/init.c
+index f73f828..fe6971c 100644
+--- a/grub-core/kern/i386/efi/init.c
++++ b/grub-core/kern/i386/efi/init.c
+@@ -30,8 +30,8 @@
+ void
+ grub_machine_init (void)
+ {
+- grub_efi_init ();
+ grub_tsc_init ();
++ grub_efi_init ();
+ }
+
+ void
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 5dd5ada..0ec088e 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -225,7 +225,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ dp = grub_efi_get_device_path (dev_handle);
+ }
+
+- if (! dev->disk || ! dev_handle || ! dp)
++ if (dev->net)
++ {
++ dev_handle = grub_efinet_get_device_handle (dev->net);
++ if (dev_handle)
++ dp = grub_efi_get_device_path (dev_handle);
++ }
++
++ if ((! dev->disk && ! dev->net ) || ! dev_handle || ! dp)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, "not a valid root device");
+ goto fail;
+diff --git a/grub-core/net/efi/efinet.c b/grub-core/net/efi/efinet.c
+new file mode 100644
+index 0000000..f26aec1
+--- /dev/null
++++ b/grub-core/net/efi/efinet.c
+@@ -0,0 +1,541 @@
++/* efinet.c - EFI network access using SNI. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
++ *
++ * GRUB is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GRUB is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/dl.h>
++#include <grub/net.h>
++#include <grub/mm.h>
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/err.h>
++#include <grub/term.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/net.h>
++#include <grub/time.h>
++
++
++static grub_err_t grub_efinet_start (struct grub_net *);
++
++static grub_ether_addr ether_broadcast =
++ { {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
++
++struct grub_sni_data
++{
++ grub_efi_handle_t handle;
++ grub_efi_device_path_t *device_path;
++ grub_efi_simple_network_t *sni;
++ struct grub_sni_data *next;
++};
++
++static grub_efi_guid_t sni_guid = GRUB_EFI_SIMPLE_NETWORK_PROTOCOL;
++
++static struct grub_sni_data *sni_devices;
++
++/* Return the device path node right before the end node. */
++static grub_efi_device_path_t *
++find_last_device_path (const grub_efi_device_path_t * dp)
++{
++ grub_efi_device_path_t *next, *p;
++
++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
++ return 0;
++
++ for (p = (grub_efi_device_path_t *) dp, next =
++ GRUB_EFI_NEXT_DEVICE_PATH (p); !GRUB_EFI_END_ENTIRE_DEVICE_PATH (next);
++ p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next))
++ ;
++
++ return p;
++}
++
++/* Compare device paths. */
++static int
++compare_device_paths (const grub_efi_device_path_t * dp1,
++ const grub_efi_device_path_t * dp2)
++{
++ if (!dp1 || !dp2)
++ /* Return non-zero. */
++ return 1;
++
++ while (1)
++ {
++ grub_efi_uint8_t type1, type2;
++ grub_efi_uint8_t subtype1, subtype2;
++ grub_efi_uint16_t len1, len2;
++ int ret;
++
++ type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
++ type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
++
++ if (type1 != type2)
++ return (int) type2 - (int) type1;
++
++ subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
++ subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
++
++ if (subtype1 != subtype2)
++ return (int) subtype1 - (int) subtype2;
++
++ len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
++ len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
++
++ if (len1 != len2)
++ return (int) len1 - (int) len2;
++
++ ret = grub_memcmp (dp1, dp2, len1);
++ if (ret != 0)
++ return ret;
++
++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
++ break;
++
++ dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
++ dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
++ }
++
++ return 0;
++}
++
++
++
++static void
++free_devices (struct grub_sni_data *devices)
++{
++ struct grub_sni_data *p, *q;
++
++ for (p = devices; p; p = q)
++ {
++ q = p->next;
++ grub_free (p);
++ }
++}
++
++
++/* Add a device into a list of devices in an ascending order. */
++static void
++add_device (struct grub_sni_data *d)
++{
++ struct grub_sni_data **p;
++
++
++ for (p = &sni_devices; *p; p = &((*p)->next))
++ {
++ int ret;
++
++ ret = compare_device_paths (find_last_device_path ((*p)->device_path),
++ find_last_device_path (d->device_path));
++ if (ret == 0)
++ ret = compare_device_paths ((*p)->device_path, d->device_path);
++ if (ret == 0)
++ return;
++ else if (ret > 0)
++ break;
++ }
++
++
++ d->next = (*p);
++ (*p) = d;
++}
++
++
++
++static void
++make_devices (void)
++{
++ grub_efi_uintn_t num_handles;
++ grub_efi_handle_t *handles;
++ grub_efi_handle_t *handle;
++
++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &sni_guid,
++ 0, &num_handles);
++
++ if (!handles)
++ return;
++
++
++
++ for (handle = handles; num_handles--; handle++)
++ {
++ grub_efi_simple_network_t *sni;
++ grub_efi_device_path_t *dp;
++ struct grub_sni_data *d;
++
++
++ dp = grub_efi_get_device_path (*handle);
++
++ sni = grub_efi_open_protocol (*handle, &sni_guid,
++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++ if (!sni)
++ continue;
++
++
++ d = grub_malloc (sizeof (*d));
++ if (!d)
++ {
++ grub_free (handles);
++ return;
++ }
++
++ d->handle = *handle;
++ d->device_path = dp;
++ d->sni = sni;
++
++ add_device (d);
++
++ }
++
++
++ grub_free (handles);
++
++}
++static void
++enumerate_snis (void)
++{
++ make_devices ();
++}
++
++
++static int
++get_unit_number (const char *name)
++{
++ unsigned long unit;
++
++ if (name[0] != 's' || name[1] != 'n' || name[2] != 'i')
++ goto fail;
++
++ unit = grub_strtoul (name + 3, 0, 10);
++ if (grub_errno != GRUB_ERR_NONE)
++ goto fail;
++
++ return (int) unit;
++
++fail:
++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a sni");
++ return -1;
++}
++
++static struct grub_sni_data *
++get_device (int num)
++{
++ struct grub_sni_data *d;
++
++ for (d = sni_devices; d && num; d = d->next, num--);
++
++ if (num == 0)
++ return d;
++
++ return 0;
++}
++
++
++static int
++tx_worker (struct grub_net *net, const void *frame, int len)
++{
++ struct grub_sni_data *private = (struct grub_sni_data *) net->data;
++ grub_uint64_t current_time, tx_time;
++ void *buf = NULL;
++ grub_efi_status_t status;
++
++ static int need_bodge = 1;
++
++ /* GRR the beasty EFI on the 64bit macminis doesn't return */
++ /* addresses from sni->transmit in sni->get_status, so we have to bodge */
++ /* the obvious bodge of looking at tx_good_frames in ->statistics */
++ /* doesn't work as that call appears to be missing on macs, the alternative */
++ /* is to flush the transmit q before and return whenever any buffer is */
++ /* returned. */
++
++ /* Flush list of frames */
++ do
++ {
++ buf = NULL;
++ efi_call_3 (private->sni->get_status, private->sni, NULL,
++ (void **) &buf);
++ }
++ while (buf);
++
++
++ tx_time = grub_get_time_ms ();
++
++ status =
++ efi_call_7 (private->sni->transmit, private->sni, 0, len, frame, NULL,
++ NULL, NULL);
++
++ if (status == GRUB_EFI_NOT_READY)
++ return 0; /*Try again */
++
++ if (status != GRUB_EFI_SUCCESS)
++ {
++ grub_efinet_start (net); /*Reset the interface */
++ return 0; /*Try again */
++ }
++
++ do
++ {
++ current_time = grub_get_time_ms ();
++ buf = NULL;
++ status =
++ efi_call_3 (private->sni->get_status, private->sni, NULL,
++ (void **) &buf);
++
++ if (status != GRUB_EFI_SUCCESS)
++ continue;
++
++ if (buf == frame)
++ {
++ /*EFI did TRT we can return success */
++ need_bodge = 0;
++ return len;
++ }
++
++ if (need_bodge)
++ return len;
++
++ }
++ while ((current_time - tx_time) < 1000);
++
++ /*Tx timed out reset and try again */
++ grub_efinet_start (net); /*Reset the interface */
++ return 0; /*Try again */
++
++}
++
++
++
++static grub_err_t
++grub_efinet_open (const char *name, struct grub_net *net)
++{
++ int num;
++ struct grub_sni_data *d = NULL;
++
++
++ if (name)
++ {
++ num = get_unit_number (name);
++ if (num < 0)
++ return grub_errno;
++ net->name = grub_strdup (name);
++ }
++ else
++ {
++ num = 0;
++ net->name = grub_strdup ("sni0");
++ }
++
++ d = get_device (num);
++
++ if (!d)
++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device");
++
++
++ grub_printf("DEVICE PATH to %s:",name);
++ grub_efi_print_device_path(d->device_path);
++ grub_printf("\n");
++
++//net->id=num;
++ net->data = d;
++
++ return GRUB_ERR_NONE;
++}
++
++
++static grub_err_t
++grub_efinet_start (struct grub_net *net)
++{
++ struct grub_sni_data *private = (struct grub_sni_data *) net->data;
++ grub_efi_status_t status;
++
++ int tries = 3;
++
++ efi_call_1 (private->sni->shutdown, private->sni);
++ status = efi_call_3 (private->sni->initialize, private->sni, 0, 0);
++
++
++#if 0
++ efi_call_1 (private->sni->shutdown, private->sni);
++ efi_call_1 (private->sni->stop, private->sni);
++#endif
++
++ do
++ {
++ status = efi_call_1 (private->sni->start, private->sni);
++ if (status != GRUB_EFI_SUCCESS)
++ {
++ efi_call_1 (private->sni->shutdown, private->sni);
++ efi_call_1 (private->sni->stop, private->sni);
++ }
++ }
++ while ((status != GRUB_EFI_SUCCESS) && (tries--));
++
++ if (status != GRUB_EFI_SUCCESS)
++ return -1;
++
++ status = efi_call_3 (private->sni->initialize, private->sni, 0, 0);
++ if (status != GRUB_EFI_SUCCESS)
++ goto fail;
++
++ status =
++ efi_call_6 (private->sni->receive_filters, private->sni,
++ GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
++ GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST, 0, 0, 0, NULL);
++ if (status != GRUB_EFI_SUCCESS)
++ goto fail;
++
++ if (private->sni->mode->state != grub_efi_simple_network_initialized)
++ goto fail;
++
++ if (private->sni->mode->hw_address_size != GRUB_ETH_ALEN)
++ goto fail;
++
++ grub_memcpy (&net->my_eth_addr, private->sni->mode->current_address,
++ GRUB_ETH_ALEN);
++
++ net->is_running++;
++
++ return 0;
++
++fail:
++
++ efi_call_1 (private->sni->shutdown, private->sni);
++ efi_call_1 (private->sni->stop, private->sni);
++ return -1;
++}
++
++static void
++grub_efinet_stop (struct grub_net *net)
++{
++ struct grub_sni_data *private = (struct grub_sni_data *) net->data;
++
++ efi_call_1 (private->sni->shutdown, private->sni);
++ efi_call_1 (private->sni->stop, private->sni);
++ net->is_running = 0;
++}
++
++
++static void
++grub_efinet_close (struct grub_net *net)
++{
++ grub_efinet_stop (net);
++ grub_free (net->name);
++}
++
++
++static grub_err_t
++grub_efinet_send (struct grub_net *net, const void *frame, int len)
++{
++ int tries = 3;
++ int ret;
++
++ if (len <= 0)
++ return -1;
++
++ do
++ {
++ ret = tx_worker (net, frame, len);
++ if (ret > 0)
++ break;
++ }
++ while (tries--);
++
++
++ /* vodoo here - efi seems to drop packets in the TxQ for a short */
++ /* while after sending a broadcast packet - god alone knows why */
++
++ if (!grub_memcmp (frame, &ether_broadcast, GRUB_ETH_ALEN))
++ {
++ efi_call_1 (grub_efi_system_table->boot_services->stall, 100000);
++ }
++
++ return (ret > 0) ? GRUB_ERR_NONE : GRUB_ERR_WRITE_ERROR;
++
++}
++
++
++static grub_err_t
++grub_efinet_recv (struct grub_net *net, void *frame, int *lenp)
++{
++ struct grub_sni_data *private = (struct grub_sni_data *) net->data;
++ grub_efi_status_t st;
++ grub_efi_uintn_t len = GRUB_ETH_FRAME_LEN;
++
++ st =
++ efi_call_7 (private->sni->receive, private->sni, NULL, &len, frame, NULL,
++ NULL, NULL);
++
++ *lenp = len;
++
++
++ if (st == GRUB_EFI_NOT_READY)
++ return GRUB_ERR_TIMEOUT;
++ else if (st != GRUB_EFI_SUCCESS)
++ return GRUB_ERR_READ_ERROR;
++
++
++ return GRUB_ERR_NONE;
++}
++
++static struct grub_net_dev sni_net_dev = {
++ .name = "sni",
++ .open = grub_efinet_open,
++ .start = grub_efinet_start,
++ .stop = grub_efinet_stop,
++ .close = grub_efinet_close,
++ .send = grub_efinet_send,
++ .recv = grub_efinet_recv,
++ .next = 0
++};
++
++grub_efi_handle_t
++grub_net_efinet_get_device_handle(struct grub_net *net)
++{
++ struct grub_sni_data *private = (struct grub_sni_data *) net->data;
++ return private->handle;
++}
++
++void
++grub_net_efinet_init (void)
++{
++ enumerate_snis ();
++ grub_net_dev_register (&sni_net_dev);
++}
++
++void
++grub_net_efinet_fini (void)
++{
++ grub_net_dev_unregister (&sni_net_dev);
++ free_devices (sni_devices);
++}
++
++char * grub_net_efinet_get_device_name(grub_efi_handle_t h)
++{
++ struct grub_sni_data *p;
++ int i=0;
++
++ while (p=get_device(i)) {
++ if (p && (p->handle == h)) {
++ char *ret=grub_malloc (10); //FIXME
++ grub_sprintf(ret,"sni%d",i);
++ return ret;
++ }
++ i++;
++ }
++
++ return NULL;
++}
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index db63eec..a965d60 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -232,6 +232,12 @@ enum
+ GRUB_EFI_SAL_SYSTEM_TABLE_PLATFORM_FEATURE_ITCDRIFT = 8,
+ };
+
++#define GRUB_EFI_SIMPLE_NETWORK_PROTOCOL \
++ { 0xA19832B9, 0xAC25, 0x11D3, \
++ {0x9A, 0x2D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D} \
++ }
++
++
+ /* Enumerations. */
+ enum grub_efi_timer_delay
+ {
+@@ -1254,6 +1260,138 @@ struct grub_efi_block_io
+ };
+ typedef struct grub_efi_block_io grub_efi_block_io_t;
+
++
++struct grub_efi_network_statistics {
++ grub_efi_uint64_t rx_total_frames;
++ grub_efi_uint64_t rx_good_frames;
++ grub_efi_uint64_t rx_undersize_frames;
++ grub_efi_uint64_t rx_oversize_frames;
++ grub_efi_uint64_t rx_dropped_frames;
++ grub_efi_uint64_t rx_unicast_frames;
++ grub_efi_uint64_t rx_broadcast_frames;
++ grub_efi_uint64_t rx_multicast_frames;
++ grub_efi_uint64_t rx_crc_error_frames;
++ grub_efi_uint64_t rx_total_bytes;
++
++ grub_efi_uint64_t tx_total_frames;
++ grub_efi_uint64_t tx_good_frames;
++ grub_efi_uint64_t tx_undersize_frames;
++ grub_efi_uint64_t tx_oversize_frames;
++ grub_efi_uint64_t tx_dropped_frames;
++ grub_efi_uint64_t tx_unicast_frames;
++ grub_efi_uint64_t tx_broadcast_frames;
++ grub_efi_uint64_t tx_multicast_frames;
++ grub_efi_uint64_t tx_crc_error_frames;
++ grub_efi_uint64_t tx_total_bytes;
++
++ grub_efi_uint64_t collisions;
++ grub_efi_uint64_t unsupported_protocol;
++};
++typedef struct grub_efi_network_statistics grub_efi_network_statistics_t;
++
++enum grub_efi_simple_network_state {
++ grub_efi_simple_network_stopped,
++ grub_efi_simple_network_started,
++ grub_efi_simple_network_initialized,
++ grub_efi_simple_network_max_state
++};
++typedef enum grub_efi_simple_network_state grub_efi_simple_network_state_t;
++
++#define GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST 0x01
++#define GRUB_EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST 0x02
++#define GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST 0x04
++#define GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS 0x08
++#define GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST 0x10
++
++
++#define GRUB_EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT 0x01
++#define GRUB_EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT 0x02
++#define GRUB_EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT 0x04
++#define GRUB_EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT 0x08
++
++#define GRUB_EFI_MAX_MCAST_FILTER_CNT 16
++struct grub_efi_simple_network_mode
++{
++ grub_efi_uint32_t state;
++ grub_efi_uint32_t hw_address_size;
++ grub_efi_uint32_t media_header_size;
++ grub_efi_uint32_t max_packet_size;
++ grub_efi_uint32_t nv_ram_size;
++ grub_efi_uint32_t nv_ram_access_size;
++ grub_efi_uint32_t receive_filter_mask;
++ grub_efi_uint32_t receive_filter_setting;
++ grub_efi_uint32_t max_mcast_filter_count;
++ grub_efi_uint32_t mcast_filter_count;
++ grub_efi_mac_address_t mcast_filter[GRUB_EFI_MAX_MCAST_FILTER_CNT];
++ grub_efi_mac_address_t current_address;
++ grub_efi_mac_address_t broadcast_address;
++ grub_efi_mac_address_t permanent_address;
++ grub_efi_uint8_t if_type;
++ grub_efi_boolean_t mac_address_changeable;
++ grub_efi_boolean_t multiple_tx_supported;
++ grub_efi_boolean_t media_present_supported;
++ grub_efi_boolean_t media_present;
++};
++typedef struct grub_efi_simple_network_mode grub_efi_simple_network_mode_t;
++
++
++struct grub_efi_simple_network
++{
++ grub_efi_uint64_t revision;
++ grub_efi_status_t (*start) (struct grub_efi_simple_network *this);
++ grub_efi_status_t (*stop) (struct grub_efi_simple_network *this);
++ grub_efi_status_t (*initialize) (struct grub_efi_simple_network *this,
++ grub_efi_uintn_t extra_rx_buffer_size,
++ grub_efi_uintn_t extra_tx_buffer_size);
++ grub_efi_status_t (*reset) (struct grub_efi_simple_network *this,
++ grub_efi_boolean_t extended_verification);
++ grub_efi_status_t (*shutdown) (struct grub_efi_simple_network *this);
++ grub_efi_status_t (*receive_filters) (struct grub_efi_simple_network *this,
++ grub_efi_uint32_t enable,
++ grub_efi_uint32_t disable,
++ grub_efi_boolean_t reset_mcast_filter,
++ grub_efi_uintn_t mcast_filter_count,
++ grub_efi_mac_address_t *mcast_filter);
++ grub_efi_status_t (*station_address) (struct grub_efi_simple_network *this,
++ grub_efi_boolean_t reset,
++ grub_efi_mac_address_t *new);
++ grub_efi_status_t (*statistics) (struct grub_efi_simple_network *this,
++ grub_efi_boolean_t reset,
++ grub_efi_uintn_t *statistics_size,
++ grub_efi_network_statistics_t *statistics_table);
++ grub_efi_status_t (*mcast_ip_to_mac) (struct grub_efi_simple_network *this,
++ grub_efi_boolean_t ipv6,
++ grub_efi_ip_address_t *ip,
++ grub_efi_mac_address_t *mac);
++ grub_efi_status_t (*nvdata) (struct grub_efi_simple_network *this,
++ grub_efi_boolean_t read_write,
++ grub_efi_uintn_t offset,
++ grub_efi_uintn_t buffer_size,
++ void *buffer);
++ grub_efi_status_t (*get_status) (struct grub_efi_simple_network *this,
++ grub_efi_uint32_t *interrupt_status,
++ void **tx_buf);
++ grub_efi_status_t (*transmit) (struct grub_efi_simple_network *this,
++ grub_efi_uintn_t header_size,
++ grub_efi_uintn_t buffer_size,
++ void *buffer,
++ grub_efi_mac_address_t *src_addr,
++ grub_efi_mac_address_t *dst_addr,
++ grub_efi_uint16_t *protocol);
++ grub_efi_status_t (*receive) (struct grub_efi_simple_network *this,
++ grub_efi_uintn_t *header_size,
++ grub_efi_uintn_t *buffer_size,
++ void *buffer,
++ grub_efi_mac_address_t *src_addr,
++ grub_efi_mac_address_t *dst_addr,
++ grub_efi_uint16_t *protocol);
++ grub_efi_status_t (*wait_for_packet) (grub_efi_event_t event);
++ grub_efi_simple_network_mode_t *mode;
++};
++typedef struct grub_efi_simple_network grub_efi_simple_network_t;
++
++
++
+ #if GRUB_TARGET_SIZEOF_VOID_P == 4
+
+ #define efi_call_0(func) func()
+diff --git a/include/grub/efi/net.h b/include/grub/efi/net.h
+new file mode 100644
+index 0000000..368eaab
+--- /dev/null
++++ b/include/grub/efi/net.h
+@@ -0,0 +1,33 @@
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2006,2007 Free Software Foundation, Inc.
++ *
++ * GRUB is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GRUB is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_EFI_NET_HEADER
++#define GRUB_EFI_NET_HEADER 1
++
++#include <grub/efi/api.h>
++#include <grub/symbol.h>
++#include <grub/net.h>
++
++grub_efi_handle_t
++EXPORT_FUNC(grub_efinet_get_device_handle) (grub_net_t net);
++char *EXPORT_FUNC(grub_efinet_get_device_name) (grub_efi_handle_t *handle);
++
++void grub_efinet_init (void);
++void grub_efinet_fini (void);
++
++#endif /* ! GRUB_EFI_NET_HEADER */
diff --git a/master/jmm/efi_call_7-bis b/master/jmm/efi_call_7-bis
new file mode 100644
index 0000000..e41e0a3
--- /dev/null
+++ b/master/jmm/efi_call_7-bis
@@ -0,0 +1,58 @@
+diff --git a/grub-core/kern/x86_64/efi/callwrap.S b/grub-core/kern/x86_64/efi/callwrap.S
+index aae2678..36df0a6 100644
+--- a/grub-core/kern/x86_64/efi/callwrap.S
++++ b/grub-core/kern/x86_64/efi/callwrap.S
+@@ -95,6 +95,20 @@ FUNCTION(efi_wrap_6)
+ addq $64, %rsp
+ ret
+
++FUNCTION(efi_wrap_7)
++ subq $68, %rsp
++ mov 68+16(%rsp), %rax
++ mov %rax, 48(%rsp)
++ mov 68+8(%rsp), %rax
++ mov %rax, 40(%rsp)
++ mov %r9, 32(%rsp)
++ mov %r8, %r9
++ mov %rcx, %r8
++ mov %rsi, %rcx
++ call *%rdi
++ addq $68, %rsp
++ ret
++
+ FUNCTION(efi_wrap_10)
+ subq $96, %rsp
+ mov 96+40(%rsp), %rax
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index cb6b111..6c17bdb 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -1243,6 +1243,7 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
+ #define efi_call_4(func, a, b, c, d) func(a, b, c, d)
+ #define efi_call_5(func, a, b, c, d, e) func(a, b, c, d, e)
+ #define efi_call_6(func, a, b, c, d, e, f) func(a, b, c, d, e, f)
++#define efi_call_7(func, a, b, c, d, e, f, g) func(a, b, c, d, e, f, g)
+ #define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) func(a, b, c, d, e, f, g, h, i, j)
+
+ #else
+@@ -1264,6 +1265,9 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
+ #define efi_call_6(func, a, b, c, d, e, f) \
+ efi_wrap_6(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
+ (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f)
++#define efi_call_7(func, a, b, c, d, e, f, g) \
++ efi_wrap_7(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
++ (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f, (grub_uint64_t) g)
+ #define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) \
+ efi_wrap_10(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, \
+ (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f, (grub_uint64_t) g, \
+@@ -1285,6 +1289,10 @@ grub_uint64_t EXPORT_FUNC(efi_wrap_6) (void *func, grub_uint64_t arg1,
+ grub_uint64_t arg2, grub_uint64_t arg3,
+ grub_uint64_t arg4, grub_uint64_t arg5,
+ grub_uint64_t arg6);
++grub_uint64_t EXPORT_FUNC(efi_wrap_7) (void *func, grub_uint64_t arg1,
++ grub_uint64_t arg2, grub_uint64_t arg3,
++ grub_uint64_t arg4, grub_uint64_t arg5,
++ grub_uint64_t arg6, grub_uint64_t arg7);
+ grub_uint64_t EXPORT_FUNC(efi_wrap_10) (void *func, grub_uint64_t arg1,
+ grub_uint64_t arg2, grub_uint64_t arg3,
+ grub_uint64_t arg4, grub_uint64_t arg5,
diff --git a/master/jmm/networking-bis b/master/jmm/networking-bis
new file mode 100644
index 0000000..2752895
--- /dev/null
+++ b/master/jmm/networking-bis
@@ -0,0 +1,2262 @@
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 093f448..a49707e 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -9,6 +9,7 @@ library = {
+ common = grub-core/kern/command.c;
+ common = grub-core/kern/device.c;
+ common = grub-core/kern/disk.c;
++ common = grub-core/kern/net.c;
+ common = grub-core/kern/emu/getroot.c;
+ common = grub-core/kern/emu/hostdisk.c;
+ common = grub-core/kern/emu/misc.c;
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index 94f7f3f..0012e59 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -61,6 +61,7 @@ include $(srcdir)/Makefile.core.am
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/disk.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dl.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 6979369..2cdcc7b 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -56,6 +56,7 @@ kernel = {
+ common = kern/corecmd.c;
+ common = kern/device.c;
+ common = kern/disk.c;
++ common = kern/net.c;
+ common = kern/dl.c;
+ common = kern/env.c;
+ common = kern/err.c;
+@@ -948,6 +949,11 @@ module = {
+ };
+
+ module = {
++ name = tftp;
++ common = fs/tftp.c;
++};
++
++module = {
+ name = jfs;
+ common = fs/jfs.c;
+ };
+diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c
+index 7714011..c3dbe12 100644
+--- a/grub-core/commands/boot.c
++++ b/grub-core/commands/boot.c
+@@ -24,6 +24,7 @@
+ #include <grub/kernel.h>
+ #include <grub/mm.h>
+ #include <grub/i18n.h>
++#include <grub/net.h>
+
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+@@ -148,6 +149,8 @@ grub_loader_boot (void)
+ if (! grub_loader_loaded)
+ return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel");
+
++ grub_net_shutdown();
++
+ if (grub_loader_noreturn)
+ grub_machine_fini ();
+
+diff --git a/grub-core/fs/tftp.c b/grub-core/fs/tftp.c
+new file mode 100644
+index 0000000..941c907
+--- /dev/null
++++ b/grub-core/fs/tftp.c
+@@ -0,0 +1,504 @@
++/* tftp.c - tftp filesystem */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2002,2005,2007 Free Software Foundation, Inc.
++ *
++ * GRUB is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GRUB is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/net.h>
++#include <grub/fs.h>
++#include <grub/file.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/time.h>
++#include <grub/types.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/symbol.h>
++#include <grub/fs.h>
++#include <grub/dl.h>
++
++
++#define TFTPS_PORT 69
++
++#define TFTP_BLOCK_SIZE 512
++
++#define TFTP_OP_RRQ 1
++#define TFTP_OP_WRQ 2
++#define TFTP_OP_DATA 3
++#define TFTP_OP_ACK 4
++#define TFTP_OP_ERROR 5
++
++static grub_dl_t my_mod;
++
++typedef struct __attribute__ ((packed))
++{
++ grub_uint16_t op;
++ grub_uint8_t data[];
++} tftp_hdr;
++
++typedef struct __attribute__ ((packed))
++{
++ grub_uint16_t op;
++ grub_uint16_t block;
++ grub_uint8_t data[0];
++} tftp_ackdata;
++
++typedef struct __attribute__ ((packed))
++{
++ grub_uint16_t op;
++ grub_uint16_t errorcode;
++ grub_uint16_t errmsg[0];
++} tftp_err;
++
++
++#define TFTP_TIMEOUT 2000
++#define TFTP_TRIES 3
++
++enum tftp_state
++{
++ TFTP_STATE_IDLE = 0,
++ TFTP_STATE_SENT_REQ,
++ TFTP_STATE_DATA,
++ TFTP_STATE_TIMEDOUT,
++ TFTP_STATE_ERROR,
++ TFTP_STATE_DONE
++};
++typedef enum tftp_state tftp_state_t;
++
++struct tftp_file_data
++{
++ char path[1024];
++ tftp_state_t state;
++ grub_udp_socket_t *socket;
++ grub_net_t net;
++
++
++ grub_uint64_t timeout;
++
++ int length;
++ int buf_size;
++ grub_uint8_t *buf;
++};
++typedef struct tftp_file_data tftp_file_data_t;
++
++
++static void
++ack (grub_net_t net, grub_udp_socket_t * socket, int block,
++ grub_ipv4_addr * src, grub_uint16_t sport)
++{
++ tftp_ackdata ta;
++
++ ta.op = grub_net_htons (TFTP_OP_ACK);
++ ta.block = grub_net_htons (block);
++
++ grub_udp_send (net, socket->port, (grub_uint8_t *) & ta, sizeof (ta), src,
++ sport);
++}
++
++
++
++static void
++data (tftp_file_data_t * fd, grub_net_t net, grub_udp_socket_t * socket,
++ grub_uint8_t * packet, int len, grub_ipv4_addr * src,
++ grub_uint16_t sport)
++{
++ tftp_ackdata *td;
++ int block;
++ int offset;
++
++ if ((fd->state != TFTP_STATE_DATA) && (fd->state != TFTP_STATE_SENT_REQ))
++ return;
++
++ if (len < (int) sizeof (tftp_ackdata))
++ return;
++
++ fd->state = TFTP_STATE_DATA;
++
++ td = (tftp_ackdata *) packet;
++ len -= sizeof (tftp_ackdata);
++
++ block = grub_net_ntohs (td->block);
++
++ offset = (block - 1) * TFTP_BLOCK_SIZE;
++
++ if ((offset + len) > fd->length)
++ fd->length = offset + len;
++
++ if (len)
++ {
++
++ if (fd->length > fd->buf_size)
++ {
++ while (fd->length > fd->buf_size)
++ fd->buf_size <<= 1;
++
++ fd->buf = grub_realloc (fd->buf, fd->buf_size);
++
++ }
++ if (!fd->buf)
++ {
++ grub_printf ("failed to realloc %d bytes\n", fd->buf_size);
++ grub_millisleep (5000);
++ }
++
++ if (!fd->buf)
++ {
++ fd->state = TFTP_STATE_ERROR;
++ }
++ else
++ {
++ grub_memcpy (&fd->buf[offset], td->data, len);
++ }
++ }
++
++ fd->timeout = grub_get_time_ms () + TFTP_TIMEOUT;
++
++ if (len != TFTP_BLOCK_SIZE)
++ {
++ fd->state = TFTP_STATE_DONE;
++ }
++
++ ack (net, socket, block, src, sport);
++}
++
++static void
++error (tftp_file_data_t * fd)
++{
++ fd->state = TFTP_STATE_ERROR;
++}
++
++
++
++static void
++rrq (tftp_file_data_t * fd)
++{
++ grub_uint8_t frame[GRUB_UDP_DATA_LEN];
++ int len = 0;
++ char *fn = fd->path;
++
++ tftp_hdr *t = (tftp_hdr *) frame;
++ grub_uint8_t *ptr;
++
++ t->op = grub_net_htons (TFTP_OP_RRQ);
++ ptr = t->data;
++ len += sizeof (tftp_hdr);
++
++ while (*fn)
++ {
++ *(ptr++) = *(fn++);
++ len++;
++ }
++
++ *(ptr++) = 0;
++ *(ptr++) = 'o';
++ *(ptr++) = 'c';
++ *(ptr++) = 't';
++ *(ptr++) = 'e';
++ *(ptr++) = 't';
++ *(ptr++) = 0;
++ len += 7;
++
++ grub_udp_send (fd->net, fd->socket->port, frame, len, &fd->net->tftp_addr,
++ TFTPS_PORT);
++
++ fd->state = TFTP_STATE_SENT_REQ;
++}
++
++
++static void
++tftp_new_frame (grub_udp_socket_t * socket, grub_net_t net,
++ grub_uint8_t * msg, int len, grub_ipv4_addr * src,
++ grub_uint16_t src_port)
++{
++ tftp_file_data_t *fd = (tftp_file_data_t *) socket->data;
++ tftp_hdr *t;
++
++ if (grub_memcmp (src, &fd->net->tftp_addr, GRUB_IPV4_ALEN))
++ return;
++ if (len < (int) sizeof (tftp_hdr))
++ return;
++
++ t = (tftp_hdr *) msg;
++
++ switch (grub_net_ntohs (t->op))
++ {
++ case TFTP_OP_DATA:
++ data (fd, net, socket, msg, len, src, src_port);
++ break;
++ case TFTP_OP_ERROR:
++ error (fd);
++ break;
++ }
++}
++
++static int
++tftp (tftp_file_data_t * fd)
++{
++ int tries = 0;
++
++ fd->state = TFTP_STATE_IDLE;
++
++ fd->length = 0;
++ fd->buf_size = 1024;
++ fd->buf = grub_malloc (fd->buf_size);
++ if (!fd->buf)
++ goto fail;
++
++ fd->socket = grub_malloc (sizeof (struct grub_udp_socket));
++ if (!fd->socket)
++ goto fail;
++
++
++ fd->socket->data = fd;
++ fd->socket->new_frame = tftp_new_frame;
++
++ do
++ {
++ fd->socket->port = 0; /* We want to be given a different port for each attempt */
++
++ if (tries)
++ grub_sleep (1); /* Back off */
++
++ if (grub_udp_bind (fd->socket))
++ goto fail;
++
++ fd->timeout = grub_get_time_ms () + TFTP_TIMEOUT;
++
++ rrq (fd);
++
++ while ((grub_get_time_ms () < fd->timeout)
++ && (fd->state == TFTP_STATE_SENT_REQ))
++ grub_net_dispatch ();
++
++ if (fd->state == TFTP_STATE_SENT_REQ)
++ grub_udp_unbind (fd->socket);
++
++ }
++ while ((fd->state == TFTP_STATE_SENT_REQ) && (tries++ < TFTP_TRIES));
++
++
++ if (fd->state == TFTP_STATE_SENT_REQ)
++ {
++ grub_printf ("tftp - timeout after rrq\n");
++ //TIMEOUT
++ goto fail;
++ }
++
++ fd->timeout = grub_get_time_ms () + TFTP_TIMEOUT;
++
++ while ((grub_get_time_ms () < fd->timeout)
++ && (fd->state == TFTP_STATE_DATA))
++ grub_net_dispatch ();
++
++
++
++ if (fd->state == TFTP_STATE_DONE)
++ {
++ grub_dprintf ("tftp","tftp - success\n");
++ }
++ else if (fd->state == TFTP_STATE_ERROR)
++ {
++ grub_dprintf ("tftp","tftp - remote reported error\n");
++ }
++ else if (fd->state == TFTP_STATE_DATA)
++ {
++ grub_printf ("tftp - timeout in data phase\n");
++ }
++
++fail:
++
++ if (fd->socket)
++ {
++ grub_udp_unbind (fd->socket);
++ grub_free (fd->socket);
++ }
++ fd->socket = NULL;
++
++ return (fd->state == TFTP_STATE_DONE) ? fd->length : -1;
++
++}
++
++static void
++ip_to_x (grub_ipv4_addr * s, char *d)
++{
++ int i, j;
++
++ for (i = 0; i < 4; ++i)
++ {
++ for (j = 4; j >= 0; j -= 4)
++ {
++ int k = (s->s_addr[i] >> j) & 0xf;
++ if (k < 0xA)
++ *(d++) = '0' + k;
++ else
++ *(d++) = 'A' + (k - 0xA);
++ }
++ }
++ *(d++) = 0;
++}
++
++
++static grub_err_t
++grub_tftp_open (grub_file_t file, const char *name)
++{
++ char ipx[9];
++ char *p;
++ tftp_file_data_t *fd;
++ int i;
++ int j;
++ int ret;
++
++ grub_dl_ref (my_mod);
++
++ grub_dprintf ("tftp","tftp_open_called\n");
++
++ fd = grub_malloc (sizeof (*fd));
++ if (!fd)
++ goto fail;
++ file->data = fd;
++
++
++ fd->socket = NULL;
++ fd->net = file->device->net;
++
++ ip_to_x (&fd->net->my_addr, ipx);
++
++ for (j = 0; j < 2;++j)
++ {
++ for (i = 8; i >= 0; --i)
++ {
++
++ grub_strcpy (fd->path, file->device->net->dhcp_file);
++ p = grub_strrchr (fd->path, '/');
++ if (p)
++ {
++ p++;
++ }
++ else
++ {
++ p = fd->path;
++ }
++ if (!j) {
++#ifdef __x86_64__
++ *(p++)='x';
++ *(p++)='8';
++ *(p++)='6';
++ *(p++)='_';
++ *(p++)='6';
++ *(p++)='4';
++#else
++ *(p++)='i';
++ *(p++)='a';
++ *(p++)='3';
++ *(p++)='2';
++#endif
++ *(p++)='/';
++ }
++ grub_strcpy (p, ipx);
++ p += i;
++ *(p++) = '/';
++ grub_strcpy (p, name);
++
++ grub_dprintf ("tftp","tftp_open_called for %s\n", fd->path);
++
++ ret = tftp (fd);
++ if (ret >= 0) {
++ file->size = fd->length;
++ file->offset = 0;
++
++ return GRUB_ERR_NONE;
++ }
++ }
++ }
++
++ fail:
++
++ if (fd && fd->buf)
++ grub_free (fd->buf);
++
++ if (fd)
++ grub_free (fd);
++ grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
++
++ grub_dl_unref (my_mod);
++
++ return grub_errno;
++}
++
++static grub_ssize_t
++grub_tftp_read (grub_file_t file, char *buf, grub_size_t len)
++{
++ tftp_file_data_t *fd = (tftp_file_data_t *) file->data;
++
++ if (len > file->size - file->offset)
++ len = file->size - file->offset;
++
++ if (len <= 0)
++ return 0;
++
++ grub_memcpy (buf, &fd->buf[file->offset], len);
++
++ return len;
++}
++
++
++static grub_err_t
++grub_tftp_close (grub_file_t file)
++{
++ tftp_file_data_t *fd = (tftp_file_data_t *) file->data;
++
++ if (fd && fd->buf)
++ grub_free (fd->buf);
++ if (fd)
++ grub_free (fd);
++
++ grub_dl_unref (my_mod);
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_tftp_dir (grub_device_t device, const char *path,
++ int (*hook) (const char *filename,
++ const struct grub_dirhook_info *info))
++{
++ (void) device;
++ (void) path;
++ (void) hook;
++
++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
++ return grub_errno;
++}
++
++static struct grub_fs grub_fs_tftp = {
++ .name = "tftp",
++ .dir = grub_tftp_dir,
++ .open = grub_tftp_open,
++ .read = grub_tftp_read,
++ .close = grub_tftp_close,
++ .next = 0
++};
++
++GRUB_MOD_INIT(tftp)
++{
++ grub_fs_register (&grub_fs_tftp);
++ my_mod = mod;
++}
++
++GRUB_MOD_FINI(tftp)
++{
++ grub_fs_unregister (&grub_fs_tftp);
++}
+diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c
+index 3db14f5..13e4dee 100644
+--- a/grub-core/kern/device.c
++++ b/grub-core/kern/device.c
+@@ -30,6 +30,7 @@ grub_device_t
+ grub_device_open (const char *name)
+ {
+ grub_disk_t disk = 0;
++ grub_net_t net = 0;
+ grub_device_t dev = 0;
+
+ if (! name)
+@@ -48,7 +49,12 @@ grub_device_open (const char *name)
+
+ /* Try to open a disk. */
+ disk = grub_disk_open (name);
+- if (! disk)
++ if (! disk) {
++ grub_errno = GRUB_ERR_NONE;
++ net = grub_net_open(name);
++ }
++
++ if (!disk && !net)
+ goto fail;
+
+ dev->disk = disk;
+@@ -57,6 +63,8 @@ grub_device_open (const char *name)
+ return dev;
+
+ fail:
++ if (net)
++ grub_net_close (net);
+ if (disk)
+ grub_disk_close (disk);
+
+@@ -68,6 +76,8 @@ grub_device_open (const char *name)
+ grub_err_t
+ grub_device_close (grub_device_t device)
+ {
++ if (device->net)
++ grub_net_close (device->net);
+ if (device->disk)
+ grub_disk_close (device->disk);
+
+diff --git a/grub-core/kern/net.c b/grub-core/kern/net.c
+new file mode 100644
+index 0000000..49eecb5
+--- /dev/null
++++ b/grub-core/kern/net.c
+@@ -0,0 +1,1409 @@
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2002,2003,2004,2006,2007,2008 Free Software Foundation, Inc.
++ *
++ * GRUB is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GRUB is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/net.h>
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/time.h>
++#include <grub/file.h>
++
++ /*PORTS*/
++#define DHCPS_PORT 67
++#define DHCPC_PORT 68
++static int net_blocked = 0;
++
++static grub_net_dev_t grub_net_dev_list;
++static grub_net_t grub_net_list;
++
++static void net_dispatch (grub_net_t);
++
++grub_udp_socket_t *udp_listeners = NULL;
++
++#undef grub_dprintf
++#define grub_dprintf(a,b...) grub_printf(b)
++
++/*BYTE SEX*/
++static inline grub_uint16_t
++net_maybeswap16 (grub_uint16_t i)
++{
++ grub_uint16_t ret;
++
++ *((grub_uint8_t *) & ret) = i >> 8;
++ *(((grub_uint8_t *) & ret) + 1) = i & 0xff;
++
++ return ret;
++}
++
++grub_uint16_t
++grub_net_htons (grub_uint16_t i)
++{
++ return net_maybeswap16 (i);
++}
++
++grub_uint16_t
++grub_net_ntohs (grub_uint16_t i)
++{
++ return net_maybeswap16 (i);
++}
++
++static inline grub_uint32_t
++net_maybeswap32 (grub_uint32_t i)
++{
++ grub_uint32_t ret;
++
++ *((grub_uint8_t *) & ret) = i >> 24;
++ *(((grub_uint8_t *) & ret) + 1) = (i >> 16) & 0xff;
++ *(((grub_uint8_t *) & ret) + 2) = (i >> 8) & 0xff;
++ *(((grub_uint8_t *) & ret) + 3) = i & 0xff;
++
++ return ret;
++}
++
++grub_uint32_t
++grub_net_htonl (grub_uint32_t i)
++{
++ return net_maybeswap32 (i);
++}
++
++grub_uint32_t
++grub_net_ntohl (grub_uint32_t i)
++{
++ return net_maybeswap32 (i);
++}
++
++typedef struct __attribute__ ((packed))
++{
++ grub_ether_addr dst;
++ grub_ether_addr src;
++ grub_uint16_t type;
++ grub_uint8_t data[0];
++} ether_hdr;
++
++#define ETH_P_IP 0x0800
++#define ETH_P_ARP 0x0806
++
++static grub_ether_addr ether_broadcast =
++ { {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
++
++
++
++
++static grub_err_t
++ether_send (grub_net_t net, grub_uint16_t type, grub_uint8_t * buf,
++ int len, grub_ether_addr * dst)
++{
++ grub_uint8_t frame[GRUB_ETH_FRAME_LEN];
++ ether_hdr *h;
++
++ h = (ether_hdr *) frame;
++
++ if (len > GRUB_ETH_DATA_LEN)
++ len = GRUB_ETH_DATA_LEN;
++
++ grub_memcpy (&h->src, &net->my_eth_addr, GRUB_ETH_ALEN);
++ grub_memcpy (&h->dst, dst, GRUB_ETH_ALEN);
++
++ h->type = grub_net_htons (type);
++ grub_memcpy (h->data, buf, len);
++
++ return net->dev->send (net, frame, len + GRUB_ETH_HLEN);
++}
++
++static void ip_new_frame (grub_net_t, grub_uint8_t *, int, grub_ether_addr *);
++static void arp_new_frame (grub_net_t, grub_uint8_t *, int,
++ grub_ether_addr *);
++
++static void
++ether_new_frame (grub_net_t net, grub_uint8_t * frame, int len)
++{
++ ether_hdr *h;
++ int type;
++
++ if (len < GRUB_ETH_HLEN)
++ return;
++ if (len > GRUB_ETH_FRAME_LEN)
++ return;
++
++ h = (ether_hdr *) frame;
++
++ if (grub_memcmp (&h->dst, &net->my_eth_addr, GRUB_ETH_ALEN) &&
++ grub_memcmp (&h->dst, &ether_broadcast, GRUB_ETH_ALEN))
++ return;
++
++ type = grub_net_ntohs (h->type);
++
++ frame += GRUB_ETH_HLEN;
++ len -= GRUB_ETH_HLEN;
++
++
++ switch (type)
++ {
++ case ETH_P_IP:
++ ip_new_frame (net, frame, len, &h->src);
++ break;
++ case ETH_P_ARP:
++ arp_new_frame (net, frame, len, &h->src);
++ break;
++ }
++}
++
++ /* ARP */
++#define ARPHRD_ETHER 1
++#define ARPOP_REQUEST 1
++#define ARPOP_REPLY 2
++#define ARP_TABLE_SIZE 16
++typedef struct __attribute__ ((packed))
++{
++ grub_uint16_t hwaddr_type;
++ grub_uint16_t paddr_type;
++ grub_uint8_t hwaddr_len;
++ grub_uint8_t paddr_len;
++ grub_uint16_t op;
++ grub_uint8_t data[0];
++} arp_hdr;
++
++typedef struct __attribute__ ((packed))
++{
++ arp_hdr h;
++ grub_ether_addr hw_sender;
++ grub_ipv4_addr p_sender;
++ grub_ether_addr hw_target;
++ grub_ipv4_addr p_target;
++} arp_hdr_eth_ipv4;
++
++typedef enum
++{
++ ARP_STATE_EMPTY = 0,
++ ARP_STATE_UNRESOLVED,
++ ARP_STATE_RESOLVED
++} arp_state;
++
++
++typedef struct
++{
++ arp_state state;
++ grub_ipv4_addr ip;
++ grub_ether_addr mac;
++} arp_entry;
++
++
++static arp_entry arp_table[ARP_TABLE_SIZE];
++static int arp_next_entry;
++
++
++static void
++arp_add_hw (grub_ipv4_addr * ip, grub_ether_addr * mac)
++{
++ int i;
++
++ for (i = 0; i < ARP_TABLE_SIZE; ++i)
++ {
++ if (arp_table[i].state == ARP_STATE_EMPTY)
++ return;
++ if (!grub_memcmp (&arp_table[i].ip, ip, GRUB_IPV4_ALEN))
++ {
++ grub_memcpy (&arp_table[i].mac, mac, GRUB_ETH_ALEN);
++ arp_table[i].state = ARP_STATE_RESOLVED;
++ return;
++ }
++ }
++}
++
++static int
++arp_add_ip (grub_ipv4_addr * ip)
++{
++ int i;
++ for (i = 0; i < ARP_TABLE_SIZE; ++i)
++ {
++ if (arp_table[i].state == ARP_STATE_EMPTY)
++ break;
++ if (!grub_memcmp (&arp_table[i].ip, ip, GRUB_IPV4_ALEN))
++ return i;
++ }
++
++ i = arp_next_entry;
++ arp_table[i].state = ARP_STATE_UNRESOLVED;
++ grub_memcpy (&arp_table[i].ip, ip, GRUB_IPV4_ALEN);
++
++ arp_next_entry++;
++ if (arp_next_entry == ARP_TABLE_SIZE)
++ arp_next_entry = 0;
++
++ return i;
++}
++
++static void
++arp_send_reply (grub_net_t net, grub_ipv4_addr * i, grub_ether_addr * e)
++{
++
++ arp_hdr_eth_ipv4 ih;
++
++ ih.h.hwaddr_type = grub_net_htons (ARPHRD_ETHER);
++ ih.h.paddr_type = grub_net_htons (ETH_P_IP);
++ ih.h.hwaddr_len = GRUB_ETH_ALEN;
++ ih.h.paddr_len = GRUB_IPV4_ALEN;
++ ih.h.op = grub_net_htons (ARPOP_REPLY);
++
++ grub_memcpy (&ih.hw_sender, &net->my_eth_addr, GRUB_ETH_ALEN);
++ grub_memcpy (&ih.p_sender, &net->my_addr, GRUB_IPV4_ALEN);
++ grub_memcpy (&ih.hw_target, e, GRUB_ETH_ALEN);
++ grub_memcpy (&ih.p_target, i, GRUB_IPV4_ALEN);
++
++ ether_send (net, ETH_P_ARP, (grub_uint8_t *) & ih, sizeof (ih),
++ &ether_broadcast);
++
++}
++
++static void
++arp_send_request (grub_net_t net, grub_ipv4_addr * i)
++{
++ arp_hdr_eth_ipv4 ih;
++
++ arp_add_ip (i);
++
++ ih.h.hwaddr_type = grub_net_htons (ARPHRD_ETHER);
++ ih.h.paddr_type = grub_net_htons (ETH_P_IP);
++ ih.h.hwaddr_len = GRUB_ETH_ALEN;
++ ih.h.paddr_len = GRUB_IPV4_ALEN;
++ ih.h.op = grub_net_htons (ARPOP_REQUEST);
++
++ grub_memcpy (&ih.hw_sender, &net->my_eth_addr, GRUB_ETH_ALEN);
++ grub_memcpy (&ih.p_sender, &net->my_addr, GRUB_IPV4_ALEN);
++ grub_memcpy (&ih.hw_target, &ether_broadcast, GRUB_ETH_ALEN);
++ grub_memcpy (&ih.p_target, i, GRUB_IPV4_ALEN);
++
++ ether_send (net, ETH_P_ARP, (grub_uint8_t *) & ih, sizeof (ih),
++ &ether_broadcast);
++}
++
++#if 0 /*-Wunused*/
++static void
++arp_flush (void)
++{
++ int i;
++ for (i = 0; i < ARP_TABLE_SIZE; ++i)
++ {
++ arp_table[i].state = ARP_STATE_EMPTY;
++ }
++}
++#endif
++
++static void
++arp_new_frame (grub_net_t net, grub_uint8_t * arp, int len,
++ grub_ether_addr * src)
++{
++ arp_hdr *h;
++ arp_hdr_eth_ipv4 *ih;
++
++ (void) src;
++
++ if (len < (int) sizeof (arp_hdr))
++ return;
++
++ h = (arp_hdr *) arp;
++
++ if (grub_net_ntohs (h->hwaddr_type) != ARPHRD_ETHER)
++ return;
++ if (grub_net_ntohs (h->paddr_type) != ETH_P_IP)
++ return;
++
++ if (h->hwaddr_len != GRUB_ETH_ALEN)
++ return;
++ if (h->paddr_len != GRUB_IPV4_ALEN)
++ return;
++
++ ih = (arp_hdr_eth_ipv4 *) arp;
++
++ arp_add_hw (&ih->p_sender, &ih->hw_sender);
++
++ switch (grub_net_ntohs (h->op))
++ {
++ case ARPOP_REQUEST:
++ if (grub_memcmp (&ih->p_target, &net->my_addr, GRUB_IPV4_ALEN))
++ return;
++ arp_send_reply (net, &ih->p_sender, &ih->hw_sender);
++ break;
++ case ARPOP_REPLY:
++ arp_add_hw (&ih->p_target, &ih->hw_target);
++ break;
++ }
++}
++
++
++static grub_ether_addr *
++arp_get_mac (grub_net_t net, grub_ipv4_addr * ip)
++{
++ int tries = 5;
++ int i;
++ grub_uint64_t t;
++
++ i = arp_add_ip (ip);
++
++ do
++ {
++ if (arp_table[i].state == ARP_STATE_RESOLVED)
++ {
++ return &arp_table[i].mac;
++ }
++
++ t = grub_get_time_ms () + 1000;
++
++ arp_send_request (net, ip);
++
++ while ((arp_table[i].state == ARP_STATE_UNRESOLVED) &&
++ (grub_get_time_ms () < t))
++ {
++ net_dispatch (net);
++ }
++ }
++ while (tries--);
++
++ return NULL;
++}
++
++
++
++
++ /* IP */
++#define IPV4_ALEN 4
++#define IP_PROTO_IP 0x0
++#define IP_PROTO_ICMP 0x1
++#define IP_PROTO_TCP 0x6
++#define IP_PROTO_UDP 0x11
++typedef struct __attribute__ ((packed))
++{
++ grub_uint8_t ihl:4, version:4;
++ grub_uint8_t tos;
++ grub_uint16_t total_len;
++ grub_uint16_t id;
++ grub_uint16_t frag_off;
++ grub_uint8_t ttl;
++ grub_uint8_t protocol;
++ grub_uint16_t header_sum;
++ grub_ipv4_addr src;
++ grub_ipv4_addr dst;
++ grub_uint8_t options[0];
++} ipv4_header;
++
++
++#define IP_VERSION 4
++#define IP_DEFAULT_TTL 64
++#define IP_DEFAULT_TOS 0
++
++
++static grub_ipv4_addr ip_broadcast = { {0xff, 0xff, 0xff, 0xff} };
++
++static int
++ip_is_broadcast (grub_ipv4_addr * a)
++{
++ return !grub_memcmp (a, &ip_broadcast, GRUB_IPV4_ALEN);
++}
++
++
++static int
++ip_is_local (grub_net_t net, grub_ipv4_addr * a)
++{
++ int i;
++
++ for (i = 0; i < 4; ++i)
++ {
++ if ((a->s_addr[i] & net->my_mask.s_addr[i]) !=
++ (net->my_addr.s_addr[i] & net->my_mask.s_addr[i]))
++ return 0;
++ }
++
++ return 1;
++}
++
++static grub_uint16_t
++ip_checksum (grub_uint8_t * b, int len)
++{
++ grub_uint32_t ret = 0;
++
++ while (len > 1)
++ {
++ ret += *(grub_uint16_t *) b;
++ b += 2;
++ if (ret & 0x80000000)
++ ret = (ret & 0xFFFF) + (ret >> 16);
++ len -= 2;
++ }
++
++ if (len)
++ ret += (grub_uint16_t) * b;
++
++ while (ret >> 16)
++ ret = (ret & 0xFFFF) + (ret >> 16);
++
++
++ return ~ret;
++}
++static void udp_new_frame (grub_net_t, grub_uint8_t *, int, grub_ipv4_addr *);
++static void icmp_new_frame (grub_net_t, grub_uint8_t *, int,
++ grub_ipv4_addr *);
++
++
++
++static void
++ip_new_frame (grub_net_t net, grub_uint8_t * ip, int len,
++ grub_ether_addr * src)
++{
++ ipv4_header *h = (ipv4_header *) ip;
++
++ (void) src;
++
++ int plen;
++ grub_uint8_t *payload;
++
++ if (len < (int) sizeof (ipv4_header))
++ return;
++
++
++ if (h->version != IP_VERSION)
++ return;
++
++ if (len < 4 * h->ihl)
++ return;
++
++
++ if (grub_memcmp (&h->dst, &net->my_addr, GRUB_IPV4_ALEN)
++ && !ip_is_broadcast (&h->dst))
++ return;
++
++ if (ip_checksum (ip, 4 * h->ihl))
++ return;
++
++ /* FIXME: we don't do fragments */
++ if (grub_net_ntohs (h->frag_off) & 0x3fff)
++ return;
++
++ plen = grub_net_ntohs (h->total_len);
++ if (plen > len)
++ return;
++
++ payload = ip;
++
++ plen -= 4 * h->ihl;
++ payload += 4 * h->ihl;
++
++ switch (h->protocol)
++ {
++ case IP_PROTO_ICMP:
++ icmp_new_frame (net, payload, plen, &h->src);
++ break;
++ case IP_PROTO_UDP:
++ udp_new_frame (net, payload, plen, &h->src);
++ break;
++ }
++
++}
++
++
++
++
++static int
++ip_send (grub_net_t net, grub_uint8_t protocol, grub_uint8_t * data,
++ int dlen, grub_ipv4_addr * dst)
++{
++ grub_uint8_t packet[GRUB_IP_PACKET_LEN];
++ int len;
++
++ ipv4_header *h = (ipv4_header *) packet;
++ grub_ether_addr *edst;
++
++ if (ip_is_broadcast (dst))
++ {
++ edst = &ether_broadcast;
++ }
++ else if (ip_is_local (net, dst))
++ {
++ edst = arp_get_mac (net, dst);
++ }
++ else
++ {
++ edst = arp_get_mac (net, &net->my_router);
++ }
++
++ if (!edst)
++ return -1;
++
++
++ if (dlen > GRUB_IP_DATA_LEN)
++ dlen = GRUB_IP_DATA_LEN;
++
++ len = dlen + sizeof (ipv4_header);
++
++ h->version = IP_VERSION;
++ h->ihl = sizeof (ipv4_header) / 4;
++ h->tos = IP_DEFAULT_TOS;
++ h->total_len = grub_net_htons (len);
++ h->id = 0;
++ h->frag_off = grub_net_htons (0x4000);
++ h->ttl = IP_DEFAULT_TTL;
++ h->protocol = protocol;
++ h->header_sum = 0;
++ grub_memcpy (&h->src, &net->my_addr, GRUB_IPV4_ALEN);
++ grub_memcpy (&h->dst, dst, GRUB_IPV4_ALEN);
++
++ h->header_sum = ip_checksum (packet, sizeof (ipv4_header));
++
++
++ grub_memcpy (packet + sizeof (ipv4_header), data, dlen);
++
++ return ether_send (net, ETH_P_IP, packet, len, edst);
++}
++
++/* ICMP */
++
++#define ICMP_TYPE_ECHO 8
++#define ICMP_TYPE_ECHO_REPLY 0
++
++
++typedef struct __attribute__ ((packed))
++{
++ grub_uint8_t type;
++ grub_uint8_t code;
++ grub_uint16_t checksum;
++ grub_uint16_t id;
++ grub_uint16_t seq;
++ grub_uint8_t data[0];
++} icmp_echo;
++
++
++
++static void
++icmp_new_frame (grub_net_t net, grub_uint8_t * icmp, int len,
++ grub_ipv4_addr * src)
++{
++ icmp_echo *e, *r;
++ grub_uint8_t reply[GRUB_IP_DATA_LEN];
++
++ if (len < (int) sizeof (icmp_echo))
++ return;
++
++ e = (icmp_echo *) icmp;
++
++ if (e->type != ICMP_TYPE_ECHO)
++ return;
++
++ grub_memcpy (reply, icmp, len);
++
++ r = (icmp_echo *) reply;
++ r->type = ICMP_TYPE_ECHO_REPLY;
++
++ ip_send (net, IP_PROTO_ICMP, reply, len, src);
++}
++
++
++
++/* UDP */
++
++
++
++typedef struct __attribute__ ((packed))
++{
++ grub_uint16_t src_port;
++ grub_uint16_t dst_port;
++ grub_uint16_t length;
++ grub_uint16_t checksum;
++ grub_uint8_t data[0];
++} udp_hdr;
++
++static void dhcp_new_frame (grub_net_t, grub_uint8_t *,
++ int, grub_ipv4_addr *, grub_uint16_t);
++
++
++static void
++udp_new_frame (grub_net_t net, grub_uint8_t * udp, int len,
++ grub_ipv4_addr * src)
++{
++ grub_udp_socket_t *s;
++ udp_hdr *h;
++ grub_uint8_t *payload;
++ int plen;
++ int port;
++
++
++ if (len < (int) sizeof (udp_hdr))
++ return;
++
++ h = (udp_hdr *) udp;
++
++ plen = len - sizeof (udp_hdr);
++ payload = udp + sizeof (udp_hdr);
++
++ port = grub_net_ntohs (h->dst_port);
++
++
++ switch (port)
++ {
++ case DHCPC_PORT:
++ dhcp_new_frame (net, payload, plen, src, grub_net_ntohs (h->src_port));
++ break;
++ default:
++
++ for (s = udp_listeners; s; s = s->next)
++ {
++ if (port == s->port)
++ {
++ s->new_frame (s, net, payload, plen, src,
++ grub_net_ntohs (h->src_port));
++ }
++ }
++ }
++
++}
++
++int
++grub_udp_send (grub_net_t net, grub_uint16_t sport, grub_uint8_t * data,
++ int dlen, grub_ipv4_addr * dst, grub_uint16_t dport)
++{
++ grub_uint8_t packet[GRUB_UDP_PACKET_LEN];
++ udp_hdr *h = (udp_hdr *) packet;
++ int len;
++
++ len = dlen + sizeof (udp_hdr);
++
++ h->src_port = grub_net_htons (sport);
++ h->dst_port = grub_net_htons (dport);
++ h->length = grub_net_htons (len);
++ h->checksum = 0;
++
++ grub_memcpy (&h->data, data, dlen);
++
++ return ip_send (net, IP_PROTO_UDP, packet, len, dst);
++
++}
++
++
++/* DHCP */
++
++#define DHCP_MAX_MESSAGE_LEN ((GRUB_UDP_DATA_LEN)-256)
++#define DHCP_DEFAULT_MESSAGE_LEN 548
++#define DHCP_MAGIC_COOKIE_LEN 4
++
++#define DHCP_OP_BOOTREQUEST 1
++#define DHCP_OP_BOOTREPLY 2
++
++#define DHCP_FLAGS_BROADCAST 0x8000
++
++#define DHCP_MSG_TYPE_DISCOVER 1
++#define DHCP_MSG_TYPE_OFFER 2
++#define DHCP_MSG_TYPE_REQUEST 3
++#define DHCP_MSG_TYPE_DECLINE 4
++#define DHCP_MSG_TYPE_ACK 5
++#define DHCP_MSG_TYPE_NAK 6
++#define DHCP_MSG_TYPE_RELEASE 7
++#define DHCP_MSG_TYPE_INFORM 8
++
++
++#define DHCP_OPTION_SUBNET 1
++#define DHCP_OPTION_ROUTER 3
++#define DHCP_OPTION_BROADCAST 28
++#define DHCP_OPTION_REQUESTED_IP_ADDR 50
++#define DHCP_OPTION_TAG_DHCP 53
++#define DHCP_OPTION_SERVER_ID 54
++#define DHCP_OPTION_TAG_PARAMETER_REQUEST 55
++#define DHCP_OPTION_DHCP_MAX_MESSAGE_LEN 57
++#define DHCP_OPTION_TFTP_SERVER_NAME 66
++#define DHCP_OPTION_BOOTFILE_NAME 67
++#define DHCP_OPTION_END 255
++
++
++typedef struct PACKED
++{
++ grub_uint8_t op;
++ grub_uint8_t htype;
++ grub_uint8_t hlen;
++ grub_uint8_t hops;
++ grub_uint32_t xid;
++ grub_uint16_t secs;
++ grub_uint16_t flags;
++ grub_ipv4_addr ciaddr;
++ grub_ipv4_addr yiaddr;
++ grub_ipv4_addr siaddr;
++ grub_ipv4_addr giaddr;
++ grub_uint8_t chaddr[16];
++ grub_uint8_t sname[64];
++ grub_uint8_t file[128];
++ grub_uint8_t options[0];
++} dhcp_packet;
++
++
++
++#define DHCP_TRIES 5
++#define DHCP_WAIT_FOR_OFFERS 5000
++#define DHCP_WAIT_FOR_ACK 5000
++
++
++static grub_uint8_t dhcp_magic_cookie[DHCP_MAGIC_COOKIE_LEN] =
++ { 99, 130, 83, 99 };
++
++
++static grub_uint32_t dhcp_xid = 0xdeadbeef;
++
++
++
++
++static grub_uint8_t *
++dhcp_find_option (dhcp_packet * p, int len, int option)
++{
++ grub_uint8_t *optr = p->options;
++ int ol;
++
++ optr += DHCP_MAGIC_COOKIE_LEN;
++ len -= sizeof (dhcp_packet) + DHCP_MAGIC_COOKIE_LEN;
++
++ while (len > 0)
++ {
++ if (*optr == option)
++ return optr;
++ if (*optr == DHCP_OPTION_END)
++ return NULL;
++
++ optr++;
++ ol = *(optr++);
++ len -= 2;
++ optr += ol;
++ len -= ol;
++ }
++
++ return NULL;
++}
++
++static grub_uint8_t *
++dhcp_copy_option (grub_uint8_t * out, dhcp_packet * p, int len, int option)
++{
++ grub_uint8_t *in;
++ int n;
++
++ in = dhcp_find_option (p, len, option);
++ if (!in)
++ return out;
++
++ *(out++) = *(in++);
++ n = *(out++) = *(in++);
++ while (n--)
++ {
++ *(out++) = *(in++);
++ }
++ return out;
++}
++
++static void
++dhcp_find_ip_option (dhcp_packet * p, int len, int option, grub_ipv4_addr * a)
++{
++ grub_uint8_t *opt;
++
++ opt = dhcp_find_option (p, len, option);
++ if (!opt)
++ return;
++
++ opt++;
++ if (*opt != GRUB_IPV4_ALEN)
++ return;
++
++ opt++;
++
++ memcpy (a, opt, GRUB_IPV4_ALEN);
++}
++
++static grub_uint8_t *
++dhcp_add_generic_options (grub_uint8_t * optr, int dhcp_type)
++{
++ grub_uint8_t *lptr;
++ memcpy (optr, &dhcp_magic_cookie, DHCP_MAGIC_COOKIE_LEN);
++ optr += DHCP_MAGIC_COOKIE_LEN;
++
++ *(optr++) = DHCP_OPTION_TAG_DHCP;
++ *(optr++) = 1;
++ *(optr++) = dhcp_type;
++ *(optr++) = DHCP_OPTION_TAG_PARAMETER_REQUEST;
++ lptr = optr++;
++ *(optr++) = DHCP_OPTION_SUBNET;
++ *(optr++) = DHCP_OPTION_ROUTER;
++ *(optr++) = DHCP_OPTION_BROADCAST;
++ *(optr++) = DHCP_OPTION_REQUESTED_IP_ADDR;
++ *(optr++) = DHCP_OPTION_SERVER_ID;
++ *(optr++) = DHCP_OPTION_TFTP_SERVER_NAME;
++ *(optr++) = DHCP_OPTION_BOOTFILE_NAME;
++ *lptr = (grub_uint8_t) (optr - lptr) - 1;
++ *(optr++) = DHCP_OPTION_DHCP_MAX_MESSAGE_LEN;
++ *(optr++) = 2;
++ *(grub_uint16_t *) optr = grub_net_htons (DHCP_MAX_MESSAGE_LEN);
++ optr += 2;
++
++ return optr;
++}
++
++
++static void
++dhcp_acknak (grub_net_t net, dhcp_packet * an, int len)
++{
++ grub_uint8_t *opt;
++
++ opt = dhcp_find_option (an, len, DHCP_OPTION_TAG_DHCP);
++ if (!opt)
++ return;
++
++ switch (*(opt + 2))
++ {
++ case DHCP_MSG_TYPE_NAK:
++ net->dhcp_state = GRUB_DHCP_STATE_OFFERS;
++ return;
++ case DHCP_MSG_TYPE_ACK:
++ break;
++ default:
++ return;
++ }
++
++/* May the lord be praised we finally have an ACK */
++/* Set all the rubbish */
++
++ memcpy (net->dhcp_file, &an->file, sizeof (net->dhcp_file));
++ memcpy (&net->tftp_addr, &an->siaddr, GRUB_IPV4_ALEN);
++ memcpy (&net->my_addr, &an->yiaddr, GRUB_IPV4_ALEN);
++
++ dhcp_find_ip_option (an, len, DHCP_OPTION_SUBNET, &net->my_mask);
++ dhcp_find_ip_option (an, len, DHCP_OPTION_ROUTER, &net->my_router);
++ dhcp_find_ip_option (an, len, DHCP_OPTION_SERVER_ID, &net->dhcp_addr);
++
++ net->dhcp_state = GRUB_DHCP_STATE_BOUND;
++
++}
++
++
++
++static void
++dhcp_offer (grub_net_t net, dhcp_packet * off, int len)
++{
++ grub_uint8_t packet[DHCP_DEFAULT_MESSAGE_LEN];
++ dhcp_packet *req = (dhcp_packet *) packet;
++ grub_uint8_t *optr;
++
++ grub_memset (packet, 0, DHCP_DEFAULT_MESSAGE_LEN);
++
++ req->op = DHCP_OP_BOOTREQUEST;
++ req->htype = ARPHRD_ETHER;
++ req->hlen = GRUB_ETH_ALEN;
++ req->xid = dhcp_xid;
++
++ req->flags = grub_net_htons (DHCP_FLAGS_BROADCAST);
++
++ grub_memcpy (req->chaddr, &net->my_eth_addr, GRUB_ETH_ALEN);
++
++ optr = dhcp_add_generic_options (req->options, DHCP_MSG_TYPE_REQUEST);
++
++ optr = dhcp_copy_option (optr, off, len, DHCP_OPTION_SERVER_ID);
++
++ *(optr++) = DHCP_OPTION_REQUESTED_IP_ADDR;
++ *(optr++) = GRUB_IPV4_ALEN;
++ memcpy (optr, &off->yiaddr, GRUB_IPV4_ALEN);
++ optr += 4;
++
++ *(optr++) = DHCP_OPTION_END;
++
++ net->dhcp_state = GRUB_DHCP_STATE_ACKNAK;
++
++ grub_udp_send (net, DHCPC_PORT, packet, len, &ip_broadcast, DHCPS_PORT);
++}
++
++
++
++static int
++dhcp_discover (grub_net_t net)
++{
++ grub_uint8_t packet[DHCP_DEFAULT_MESSAGE_LEN];
++ grub_uint8_t *optr;
++ dhcp_packet *dis = (dhcp_packet *) packet;
++
++ grub_memset (packet, 0, DHCP_DEFAULT_MESSAGE_LEN);
++
++
++ dis->op = DHCP_OP_BOOTREQUEST;
++ dis->htype = ARPHRD_ETHER;
++ dis->hlen = GRUB_ETH_ALEN;
++ dis->xid = dhcp_xid;
++
++ dis->flags = grub_net_htons (DHCP_FLAGS_BROADCAST);
++
++ memcpy (dis->chaddr, &net->my_eth_addr, GRUB_ETH_ALEN);
++
++ optr = dhcp_add_generic_options (dis->options, DHCP_MSG_TYPE_DISCOVER);
++ *(optr++) = DHCP_OPTION_END;
++
++
++ return grub_udp_send (net, DHCPC_PORT, packet, sizeof (packet),
++ &ip_broadcast, DHCPS_PORT);
++}
++
++
++static void
++dhcp_new_frame (grub_net_t net, grub_uint8_t * data,
++ int len, grub_ipv4_addr * src, grub_uint16_t sport)
++{
++ dhcp_packet *d;
++
++ (void) src;
++
++ if (sport != DHCPS_PORT)
++ return;
++ if (len > DHCP_MAX_MESSAGE_LEN)
++ return;
++
++ if (len < (int) (sizeof (dhcp_packet) + 4))
++ return;
++
++ d = (dhcp_packet *) data;
++
++ if (d->op != DHCP_OP_BOOTREPLY)
++ return;
++ if (d->htype != ARPHRD_ETHER)
++ return;
++ if (d->hlen != GRUB_ETH_ALEN)
++ return;
++ if (d->xid != dhcp_xid)
++ return;
++ if (grub_memcmp (d->chaddr, &net->my_eth_addr, GRUB_ETH_ALEN))
++ return;
++ if (grub_memcmp (d->options, &dhcp_magic_cookie, DHCP_MAGIC_COOKIE_LEN))
++ return;
++
++ switch (net->dhcp_state)
++ {
++ case GRUB_DHCP_STATE_OFFERS:
++
++ if (len > DHCP_MAX_MESSAGE_LEN)
++ return;
++ dhcp_offer (net, d, len);
++ return;
++
++ case GRUB_DHCP_STATE_ACKNAK:
++ dhcp_acknak (net, d, len);
++ return;
++ }
++}
++
++
++
++
++/* slight wizzardry, fails go to STATE_OFFERS so it times out and */
++/* decrements the try counter before returning to tu_dhcp_state discover */
++/* this gives a back off and makes the logic simpler */
++
++
++static int
++dhcp (grub_net_t net)
++{
++ grub_uint64_t c;
++ int tries = DHCP_TRIES;
++
++ while (net->dhcp_state != GRUB_DHCP_STATE_BOUND)
++ {
++ c = grub_get_time_ms ();
++
++ switch (net->dhcp_state)
++ {
++ case GRUB_DHCP_STATE_DISCOVER:
++ net->dhcp_state = GRUB_DHCP_STATE_OFFERS;
++ dhcp_discover (net);
++ break;
++ case GRUB_DHCP_STATE_OFFERS:
++ while (((c + DHCP_WAIT_FOR_OFFERS) > grub_get_time_ms ())
++ && (net->dhcp_state == GRUB_DHCP_STATE_OFFERS))
++ net_dispatch (net);
++ if (net->dhcp_state == GRUB_DHCP_STATE_OFFERS)
++ {
++ if (!(tries--))
++ {
++ net->dhcp_state = GRUB_DHCP_STATE_GAVE_UP;
++ return -1;
++ }
++ else
++ {
++ net->dhcp_state = GRUB_DHCP_STATE_DISCOVER;
++ }
++ }
++ break;
++ case GRUB_DHCP_STATE_REQUEST:
++ break;
++ case GRUB_DHCP_STATE_ACKNAK:
++ while (((c + DHCP_WAIT_FOR_ACK) > grub_get_time_ms ())
++ && (net->dhcp_state == GRUB_DHCP_STATE_ACKNAK))
++ net_dispatch (net);
++
++ if (net->dhcp_state == GRUB_DHCP_STATE_ACKNAK)
++ {
++ net->dhcp_state = GRUB_DHCP_STATE_OFFERS; /* To decrement tries */
++ }
++ break;
++ case GRUB_DHCP_STATE_BOUND:
++ return 0;
++ case GRUB_DHCP_STATE_GAVE_UP:
++ return -1;
++ default:
++ net->dhcp_state = GRUB_DHCP_STATE_DISCOVER;
++ }
++ }
++ return 0;
++}
++
++
++/* Network */
++
++static void
++net_dispatch (grub_net_t net)
++{
++ grub_uint8_t frame[GRUB_ETH_FRAME_LEN];
++ int len;
++
++ len = sizeof (frame);
++ while (net->dev->recv (net, frame, &len) == GRUB_ERR_NONE)
++ {
++ if (!len) break;
++ ether_new_frame (net, frame, len);
++ len = sizeof (frame);
++ }
++
++}
++
++static int
++net_init (grub_net_t net)
++{
++ if (net_blocked)
++ return 0;
++
++ if ((!net->is_running) && (net->dev->start (net)))
++ return -1;
++
++ if (net->is_up)
++ return 0;
++
++ if (net->has_failed)
++ return -1;
++
++ if (!net->is_up)
++ {
++ if (dhcp (net))
++ {
++ net->has_failed++;
++ return -1;
++ }
++ net->is_up++;
++ }
++
++ return 0;
++}
++
++
++void
++grub_net_dev_register (grub_net_dev_t dev)
++{
++ dev->next = grub_net_dev_list;
++ grub_net_dev_list = dev;
++#if 1
++ grub_net_syslog ("grub says: hello world");
++#endif
++}
++
++void
++grub_net_dev_unregister (grub_net_dev_t dev)
++{
++ grub_net_dev_t *p, q;
++
++ /* FIXME: XXX: we need to tear down active interfaces if their */
++ /* drivers are being de-registered */
++
++ for (p = &grub_net_dev_list, q = *p; q; p = &(q->next), q = q->next)
++ if (q == dev)
++ {
++ *p = q->next;
++ break;
++ }
++}
++
++static grub_fs_t find_tftp_fs(void)
++{
++ grub_fs_t p;
++
++ for (p = grub_fs_list; p; p = p->next)
++ {
++ if (!grub_strcmp(p->name,"tftp"))
++ return p;
++ }
++
++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't find tftp filesystem to bind to net device");
++
++ return NULL;
++}
++
++grub_net_t
++grub_net_open (const char *name)
++{
++ grub_net_t net;
++ grub_net_dev_t dev;
++
++ grub_dprintf ("net", "opening `%s'...\n", name);
++
++ if (net_blocked)
++ return 0;
++
++ if (name && !grub_strcmp (name, "net"))
++ {
++ name = NULL;
++ }
++
++ /* See if we already have this device open */
++ for (net = grub_net_list; net; net = net->next)
++ {
++ if (!name || !grub_strcmp (net->name, name))
++ {
++ net_init (net);
++ return net->has_failed ? NULL:net;
++ }
++ }
++ for (dev = grub_net_dev_list; dev; dev = dev->next)
++ {
++ int ret;
++ grub_errno = GRUB_ERR_NONE;
++
++
++ net = (grub_net_t) grub_malloc (sizeof (*net));
++ if (!net)
++ return 0;
++
++
++ net->name = NULL;
++ net->dhcp_state = GRUB_DHCP_STATE_DISCOVER;
++ net->is_running = 0;
++ net->is_up = 0;
++ net->has_failed = 0;
++ net->fs = find_tftp_fs();
++ grub_memcpy (&net->my_addr, &ip_broadcast, GRUB_IPV4_ALEN);
++
++ /*Try opening the name with this device sets net->name */
++ ret=dev->open (name, net);
++
++ grub_dprintf ("net", "opening `%s' gave %d.\n", name, ret);
++
++ if (ret!=GRUB_ERR_NONE) { /*There was a problem*/
++
++ /*Fail - free*/
++ if (net->name)
++ grub_free ((char *) net->name);
++
++ grub_free(net);
++ net=NULL;
++ if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE) {
++ /*name made no sense - try next driver*/
++ grub_errno=GRUB_ERR_NONE;
++ continue;
++ } else {
++ /*There was a problem - if we have a name, fail*/
++ if (name)
++ goto fail;
++ /*we don't so try another device*/
++ grub_errno=GRUB_ERR_NONE;
++ continue;
++ }
++ }
++
++ /*The open worked add the opened device to the list*/
++ net->dev = dev;
++
++ net->next = grub_net_list;
++ grub_net_list = net;
++
++ /*Attempt initalization*/
++ net_init (net);
++
++ /*Do we have a working network - yes hurrah all done*/
++ if (net->is_up)
++ break;
++
++ /*no - try others*/
++ net=NULL;
++ }
++
++ if (!dev)
++ {
++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such device");
++ }
++
++
++fail:
++
++ if (!net)
++ {
++ grub_dprintf ("net", "opening `%s' failed.\n", name);
++ }
++
++ return net;
++}
++
++static void
++net_open_default (void)
++{
++ if (grub_net_list)
++ {
++ grub_net_open (grub_net_list->name);
++ }
++ else
++ {
++ grub_net_open (NULL);
++ }
++}
++
++
++void
++grub_net_close (grub_net_t net)
++{
++ grub_dprintf ("net", "closing `%s'.\n", net->name);
++
++ /* we don't actually close the network device as we're bound to want it later */
++}
++
++
++void
++grub_net_dispatch (void)
++{
++ grub_net_t net;
++
++ for (net = grub_net_list; net; net = net->next)
++ {
++ if (net->is_running)
++ net_dispatch (net);
++ }
++}
++
++void
++grub_net_shutdown (void)
++{
++ grub_net_t net;
++
++ while ((net = grub_net_list))
++ {
++ grub_net_list = net->next;
++
++ if (net->is_running)
++ {
++ net->dev->stop (net);
++ }
++ net->dev->close (net);
++ grub_free (net);
++ }
++
++}
++
++
++
++
++/* syslog */
++
++#define SYSLOG_HDR_LEN 5
++#define SYSLOG_PORT 514
++
++void
++grub_net_syslog (const char *msg)
++{
++ grub_uint8_t buf[GRUB_UDP_DATA_LEN];
++ grub_uint8_t *ptr;
++ int len;
++ int plen;
++
++ grub_net_t net;
++
++ if (net_blocked)
++ return;
++
++ grub_error_push ();
++
++ net_open_default ();
++
++ len = sizeof (buf) - 1;
++ ptr = buf;
++ plen = 0;
++
++ grub_memcpy (ptr, "<133>", SYSLOG_HDR_LEN);
++ ptr += SYSLOG_HDR_LEN;
++ len -= SYSLOG_HDR_LEN;
++ plen += SYSLOG_HDR_LEN;
++
++
++ while ((*msg) && len)
++ {
++ *(ptr++) = *(msg++);
++ len--;
++ plen++;
++ }
++
++ *(ptr++) = 0;
++ plen++;
++
++ for (net = grub_net_list; net; net = net->next)
++ {
++ if (net->is_running)
++ grub_udp_send (net, SYSLOG_PORT, buf, plen, &ip_broadcast,
++ SYSLOG_PORT);
++ }
++ grub_error_pop ();
++
++}
++
++
++static grub_uint16_t udp_port = 32000;
++
++grub_err_t
++grub_udp_bind (grub_udp_socket_t * socket)
++{
++ grub_udp_socket_t *p;
++
++ if (!socket->port)
++ socket->port = udp_port++;
++ socket->next = 0;
++
++ for (p = udp_listeners; p; p = p->next)
++ {
++ if (p->port == socket->port)
++ return GRUB_ERR_BAD_ARGUMENT;
++ }
++
++
++ socket->next = udp_listeners;
++ udp_listeners = socket;
++
++ return GRUB_ERR_NONE;
++}
++
++grub_err_t
++grub_udp_unbind (grub_udp_socket_t * socket)
++{
++ grub_udp_socket_t **p, *q;
++
++ for (p = &udp_listeners, q = *p; q; p = &(q->next), q = q->next)
++ if (q == socket)
++ {
++ *p = q->next;
++ return GRUB_ERR_NONE;
++ }
++
++ return GRUB_ERR_BAD_ARGUMENT;
++}
++
+diff --git a/include/grub/net.h b/include/grub/net.h
+index c6d71d5..e056718 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -23,50 +23,193 @@
+ #include <grub/err.h>
+ #include <grub/types.h>
+
++#define GRUB_ETH_FRAME_LEN 1514
++#define GRUB_ETH_HLEN 14
++#define GRUB_ETH_DATA_LEN (GRUB_ETH_FRAME_LEN - GRUB_ETH_HLEN)
++#define GRUB_IP_PACKET_LEN (GRUB_ETH_DATA_LEN)
++#define GRUB_IP_DATA_LEN ((GRUB_IP_PACKET_LEN) - 32)
++#define GRUB_UDP_PACKET_LEN (GRUB_IP_PACKET_LEN)
++#define GRUB_UDP_DATA_LEN ((GRUB_UDP_PACKET_LEN) - 8)
++
+ struct grub_net;
+
++#define GRUB_ETH_ALEN 6
++
++typedef struct
++{
++ grub_uint8_t s_addr[GRUB_ETH_ALEN];
++} grub_ether_addr;
++
++#define GRUB_IPV4_ALEN 4
++
++typedef struct
++{
++ grub_uint8_t s_addr[GRUB_IPV4_ALEN];
++} grub_ipv4_addr;
++
++
++typedef enum
++{
++ GRUB_DHCP_STATE_DISCOVER,
++ GRUB_DHCP_STATE_OFFERS,
++ GRUB_DHCP_STATE_REQUEST,
++ GRUB_DHCP_STATE_ACKNAK,
++ GRUB_DHCP_STATE_BOUND,
++ GRUB_DHCP_STATE_GAVE_UP
++} grub_dhcp_state;
++
++/* The usual form for a network device is that it should
++ scan for compatible hardware upon module startup and
++ make an internal list of such devices. When the network
++ layer calls open it will either be with some user
++ specificed device name eg (rtl2) in which case the driver
++ should see if it recognises it (here the rtl driver should
++ look for the 3rd device it recognises) or NULL it which case
++ the driver is to look for the first device it recognises.
++ Open will then fill in the relevant parts of the struct grub_net
++ that it has been passed.
++
++ start will then initalize and bring up the interface
++ setting net->is_running
++
++ send and recv will then send and receive packets from the network
++ note that the recv function may not be called sufficiently often
++ to prevent an overflow in the inbound buffer of the card and the
++ driver should cope with this. A call to recv, should flush any
++ pending packets in the transmit queue before returning
++
++ stop will prevent the network card from accessing host memory
++ until the next start making it safe for an operating system
++ boot or some other driver to interact with the card.
++
++ close will free resources allocated in the open
++ (if net->name is freed, it must be set yo NULL)
++
++ and the module unload function should tear down the list of
++ devices. NB the network stack MUST always call stop and close
++ before the the module unloads.
++
++*/
++
++
+ struct grub_net_dev
+ {
+- /* The device name. */
+- const char *name;
+-
+- /* FIXME: Just a template. */
+- int (*probe) (struct grub_net *net, const void *addr);
+- void (*reset) (struct grub_net *net);
+- int (*poll) (struct grub_net *net);
+- void (*transmit) (struct grub_net *net, const void *destip,
+- unsigned srcsock, unsigned destsock, const void *packet);
+- void (*disable) (struct grub_net *net);
+-
+- /* The next net device. */
+- struct grub_net_dev *next;
++ const char *name; /* Name of driver */
++
++ /* Open routine, name is either a specific
++ device name eg "rtl3" or is NULL to indicate
++ that the driver should attempt to configure
++ the first device in the system it supports
++ will return GRUB_ERR_NONE upon success and
++ GRUB_ERR_UNKNOWN_DEVICE if no such deivce
++ is found, the open routine shall not start
++ any DMA transactions. open shall fill in
++ net->name */
++ grub_err_t (*open) (const char *name, struct grub_net * net);
++
++
++
++ /* put the network card into a state
++ where it may receive and transmit.
++ start shall set net->is_running
++ on success and net->my_eth_addr
++ shall be set */
++ grub_err_t (*start) (struct grub_net * net);
++
++ /* put the network card into a state
++ where it shall not attempt to read
++ or write from host memory. stop shall
++ clear net->is_running */
++ void (*stop) (struct grub_net * net);
++
++ /* release the resources consumed by
++ open. If close frees net->name, it
++ MUST set net->name to NULL */
++ void (*close) (struct grub_net * net);
++
++ /* transmit one ethernet frame */
++ grub_err_t (*send) (struct grub_net * net, const void *buf, int len);
++
++ /* receive one ethernet frame, if no
++ frame is available recv shall return
++ GRUB_ERR_TIMEOUT and set *len to zero */
++ grub_err_t (*recv) (struct grub_net * net, void *buf, int *len);
++
++ /* The next net driver. */
++ struct grub_net_dev *next;
+ };
+ typedef struct grub_net_dev *grub_net_dev_t;
+
+ struct grub_fs;
+
++/* We keep a list of open network devices, because doing otherwise */
++/* would require starting and stopping the network for each request */
+ struct grub_net
+ {
+- /* The net name. */
+- const char *name;
++ const char *name; /* Name of device, should be set with
++ grub_malloc-ed storage by the driver's
++ open routine */
+
+- /* The underlying disk device. */
+- grub_net_dev_t dev;
++ grub_ether_addr my_eth_addr;
++ grub_ipv4_addr my_addr;
++ grub_ipv4_addr my_mask;
++ grub_ipv4_addr my_router;
++ grub_ipv4_addr dhcp_addr;
++ grub_ipv4_addr tftp_addr;
+
+- /* The binding filesystem. */
+- struct grub_fs *fs;
++ char dhcp_file[128];
+
+- /* FIXME: More data would be required, such as an IP address, a mask,
+- a gateway, etc. */
++ int dhcp_state;
+
+- /* Device-specific data. */
+- void *data;
++ int is_running; /*Interface has been started - set
++ by dev->start */
++ int is_up; /*Interface is up - dhcp has
++ succeded in getting an address */
++ int has_failed; /*Interface has failed to come up -
++ used to prevent endless dhcp timeouts */
++
++ grub_net_dev_t dev; /* The underlying net device. */
++
++ struct grub_fs *fs; /* The binding filesystem. */
++
++
++ void *data; /* Device-instance-specific data. */
++
++ struct grub_net *next;
+ };
+ typedef struct grub_net *grub_net_t;
+
+-/* FIXME: How to abstract networks? More consideration is necessary. */
+
+-/* Note: Networks are very different from disks, because networks must
+- be initialized before used, and the status is persistent. */
++struct grub_udp_socket
++{
++ int port;
++ void (*new_frame) (struct grub_udp_socket * socket, grub_net_t net,
++ grub_uint8_t * msg, int len, grub_ipv4_addr * src,
++ grub_uint16_t src_port);
++ void *data;
++ struct grub_udp_socket *next;
++};
++typedef struct grub_udp_socket grub_udp_socket_t;
++
++void EXPORT_FUNC (grub_net_dev_register) (grub_net_dev_t dev);
++void EXPORT_FUNC (grub_net_dev_unregister) (grub_net_dev_t dev);
++grub_net_t EXPORT_FUNC (grub_net_open) (const char *name);
++void EXPORT_FUNC (grub_net_close) (grub_net_t net);
++void EXPORT_FUNC (grub_net_shutdown) (void);
++void EXPORT_FUNC (grub_net_dispatch) (void);
++void EXPORT_FUNC (grub_net_syslog) (const char *msg);
++
++void EXPORT_FUNC (grub_net_dispatch) (void);
++int EXPORT_FUNC (grub_udp_send) (grub_net_t net, grub_uint16_t sport,
++ grub_uint8_t * data, int dlen,
++ grub_ipv4_addr * dst, grub_uint16_t dport);
++grub_err_t EXPORT_FUNC (grub_udp_bind) (grub_udp_socket_t * socket);
++grub_err_t EXPORT_FUNC (grub_udp_unbind) (grub_udp_socket_t * socket);
++
++grub_uint32_t EXPORT_FUNC (grub_net_htonl) (grub_uint32_t);
++grub_uint32_t EXPORT_FUNC (grub_net_ntohl) (grub_uint32_t);
++grub_uint16_t EXPORT_FUNC (grub_net_htons) (grub_uint16_t);
++grub_uint16_t EXPORT_FUNC (grub_net_ntohs) (grub_uint16_t);
++
+
+ #endif /* ! GRUB_NET_HEADER */
diff --git a/master/series b/master/series
index 823bd9a..8a47714 100644
--- a/master/series
+++ b/master/series
@@ -45,6 +45,16 @@ debian/efi_disk_cache.patch
debian/dirlen.patch
debian/hurd.patch
debian/userland-part.patch
+#jmm/efi_call_7
+jmm/efi_call_7-bis
+#jmm/efi-load-drivers
+jmm/efi-load-drivers-bis
+#jmm/networking
+#jmm/networking2
+jmm/networking-bis
+#jmm/efi-sni
+jmm/efi-sni-bis
+no-prefix-bail
endstop
#
#