You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5053 lines
144 KiB
5053 lines
144 KiB
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
|
From: Michael Chang <mchang@suse.com> |
|
Date: Wed, 22 Feb 2017 14:27:50 +0800 |
|
Subject: [PATCH] Support UEFI networking protocols |
|
|
|
References: fate#320130, bsc#1015589, bsc#1076132 |
|
Patch-Mainline: no |
|
|
|
V1: |
|
* Add preliminary support of UEFI networking protocols |
|
* Support UEFI HTTPS Boot |
|
|
|
V2: |
|
* Workaround http data access in firmware |
|
* Fix DNS device path parsing for efinet device |
|
* Relaxed UEFI Protocol requirement |
|
* Support Intel OPA (Omni-Path Architecture) PXE Boot |
|
|
|
V3: |
|
* Fix bufio in calculating address of next_buf |
|
* Check HTTP respond code |
|
* Use HEAD request method to test before GET |
|
* Finish HTTP transaction in one go |
|
* Fix bsc#1076132 |
|
|
|
Signed-off-by: Michael Chang <mchang@suse.com> |
|
[pjones: make efi_netfs not duplicate symbols from efinet] |
|
Signed-off-by: Peter Jones <pjones@redhat.com> |
|
--- |
|
grub-core/Makefile.core.def | 12 + |
|
grub-core/io/bufio.c | 2 +- |
|
grub-core/kern/efi/efi.c | 96 ++- |
|
grub-core/net/drivers/efi/efinet.c | 27 + |
|
grub-core/net/efi/dhcp.c | 397 ++++++++++ |
|
grub-core/net/efi/efi_netfs.c | 57 ++ |
|
grub-core/net/efi/http.c | 419 +++++++++++ |
|
grub-core/net/efi/ip4_config.c | 398 ++++++++++ |
|
grub-core/net/efi/ip6_config.c | 422 +++++++++++ |
|
grub-core/net/efi/net.c | 1428 ++++++++++++++++++++++++++++++++++++ |
|
grub-core/net/efi/pxe.c | 424 +++++++++++ |
|
grub-core/net/net.c | 74 ++ |
|
util/grub-mknetdir.c | 23 +- |
|
include/grub/efi/api.h | 180 ++++- |
|
include/grub/efi/dhcp.h | 343 +++++++++ |
|
include/grub/efi/http.h | 215 ++++++ |
|
include/grub/net/efi.h | 144 ++++ |
|
17 files changed, 4620 insertions(+), 41 deletions(-) |
|
create mode 100644 grub-core/net/efi/dhcp.c |
|
create mode 100644 grub-core/net/efi/efi_netfs.c |
|
create mode 100644 grub-core/net/efi/http.c |
|
create mode 100644 grub-core/net/efi/ip4_config.c |
|
create mode 100644 grub-core/net/efi/ip6_config.c |
|
create mode 100644 grub-core/net/efi/net.c |
|
create mode 100644 grub-core/net/efi/pxe.c |
|
create mode 100644 include/grub/efi/dhcp.h |
|
create mode 100644 include/grub/efi/http.h |
|
create mode 100644 include/grub/net/efi.h |
|
|
|
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def |
|
index 4b7c45a7b06..c40170f2dd2 100644 |
|
--- a/grub-core/Makefile.core.def |
|
+++ b/grub-core/Makefile.core.def |
|
@@ -2299,6 +2299,12 @@ module = { |
|
common = hook/datehook.c; |
|
}; |
|
|
|
+module = { |
|
+ name = efi_netfs; |
|
+ common = net/efi/efi_netfs.c; |
|
+ enable = efi; |
|
+}; |
|
+ |
|
module = { |
|
name = net; |
|
common = net/net.c; |
|
@@ -2312,6 +2318,12 @@ module = { |
|
common = net/ethernet.c; |
|
common = net/arp.c; |
|
common = net/netbuff.c; |
|
+ efi = net/efi/net.c; |
|
+ efi = net/efi/http.c; |
|
+ efi = net/efi/pxe.c; |
|
+ efi = net/efi/ip4_config.c; |
|
+ efi = net/efi/ip6_config.c; |
|
+ efi = net/efi/dhcp.c; |
|
}; |
|
|
|
module = { |
|
diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c |
|
index a458c3aca78..1637731535e 100644 |
|
--- a/grub-core/io/bufio.c |
|
+++ b/grub-core/io/bufio.c |
|
@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len) |
|
return res; |
|
|
|
/* Need to read some more. */ |
|
- next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1); |
|
+ next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size; |
|
/* Now read between file->offset + res and bufio->buffer_at. */ |
|
if (file->offset + res < next_buf) |
|
{ |
|
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c |
|
index d6a2fb57789..2a446f5031b 100644 |
|
--- a/grub-core/kern/efi/efi.c |
|
+++ b/grub-core/kern/efi/efi.c |
|
@@ -755,7 +755,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) |
|
{ |
|
grub_efi_ipv4_device_path_t *ipv4 |
|
= (grub_efi_ipv4_device_path_t *) dp; |
|
- grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", |
|
+ grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x", |
|
(unsigned) ipv4->local_ip_address[0], |
|
(unsigned) ipv4->local_ip_address[1], |
|
(unsigned) ipv4->local_ip_address[2], |
|
@@ -768,33 +768,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) |
|
(unsigned) ipv4->remote_port, |
|
(unsigned) ipv4->protocol, |
|
(unsigned) ipv4->static_ip_address); |
|
+ if (len == sizeof (*ipv4)) |
|
+ { |
|
+ grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u", |
|
+ (unsigned) ipv4->gateway_ip_address[0], |
|
+ (unsigned) ipv4->gateway_ip_address[1], |
|
+ (unsigned) ipv4->gateway_ip_address[2], |
|
+ (unsigned) ipv4->gateway_ip_address[3], |
|
+ (unsigned) ipv4->subnet_mask[0], |
|
+ (unsigned) ipv4->subnet_mask[1], |
|
+ (unsigned) ipv4->subnet_mask[2], |
|
+ (unsigned) ipv4->subnet_mask[3]); |
|
+ } |
|
+ grub_printf (")"); |
|
} |
|
break; |
|
case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: |
|
{ |
|
grub_efi_ipv6_device_path_t *ipv6 |
|
= (grub_efi_ipv6_device_path_t *) dp; |
|
- grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", |
|
- (unsigned) ipv6->local_ip_address[0], |
|
- (unsigned) ipv6->local_ip_address[1], |
|
- (unsigned) ipv6->local_ip_address[2], |
|
- (unsigned) ipv6->local_ip_address[3], |
|
- (unsigned) ipv6->local_ip_address[4], |
|
- (unsigned) ipv6->local_ip_address[5], |
|
- (unsigned) ipv6->local_ip_address[6], |
|
- (unsigned) ipv6->local_ip_address[7], |
|
- (unsigned) ipv6->remote_ip_address[0], |
|
- (unsigned) ipv6->remote_ip_address[1], |
|
- (unsigned) ipv6->remote_ip_address[2], |
|
- (unsigned) ipv6->remote_ip_address[3], |
|
- (unsigned) ipv6->remote_ip_address[4], |
|
- (unsigned) ipv6->remote_ip_address[5], |
|
- (unsigned) ipv6->remote_ip_address[6], |
|
- (unsigned) ipv6->remote_ip_address[7], |
|
+ grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x", |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]), |
|
(unsigned) ipv6->local_port, |
|
(unsigned) ipv6->remote_port, |
|
(unsigned) ipv6->protocol, |
|
(unsigned) ipv6->static_ip_address); |
|
+ if (len == sizeof (*ipv6)) |
|
+ { |
|
+ grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", |
|
+ (unsigned) ipv6->prefix_length, |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]), |
|
+ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7])); |
|
+ } |
|
+ grub_printf (")"); |
|
} |
|
break; |
|
case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: |
|
@@ -834,6 +861,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) |
|
dump_vendor_path ("Messaging", |
|
(grub_efi_vendor_device_path_t *) dp); |
|
break; |
|
+ case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE: |
|
+ { |
|
+ grub_efi_uri_device_path_t *uri |
|
+ = (grub_efi_uri_device_path_t *) dp; |
|
+ grub_printf ("/URI(%s)", uri->uri); |
|
+ } |
|
+ break; |
|
+ case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE: |
|
+ { |
|
+ grub_efi_dns_device_path_t *dns |
|
+ = (grub_efi_dns_device_path_t *) dp; |
|
+ if (dns->is_ipv6) |
|
+ { |
|
+ grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)", |
|
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16), |
|
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])), |
|
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16), |
|
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])), |
|
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16), |
|
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])), |
|
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16), |
|
+ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]))); |
|
+ } |
|
+ else |
|
+ { |
|
+ grub_printf ("/DNS(%d.%d.%d.%d)", |
|
+ dns->dns_server_ip[0].v4.addr[0], |
|
+ dns->dns_server_ip[0].v4.addr[1], |
|
+ dns->dns_server_ip[0].v4.addr[2], |
|
+ dns->dns_server_ip[0].v4.addr[3]); |
|
+ } |
|
+ } |
|
+ break; |
|
default: |
|
grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); |
|
break; |
|
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c |
|
index 715a6168d77..e11d759f19a 100644 |
|
--- a/grub-core/net/drivers/efi/efinet.c |
|
+++ b/grub-core/net/drivers/efi/efinet.c |
|
@@ -27,6 +27,7 @@ |
|
#include <grub/lib/hexdump.h> |
|
#include <grub/types.h> |
|
#include <grub/net/netbuff.h> |
|
+#include <grub/env.h> |
|
|
|
GRUB_MOD_LICENSE ("GPLv3+"); |
|
|
|
@@ -491,6 +492,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u |
|
|
|
ldp = grub_efi_find_last_device_path (ddp); |
|
|
|
+ /* Skip the DNS Device */ |
|
+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE |
|
+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) |
|
+ { |
|
+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; |
|
+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; |
|
+ ldp->length = sizeof (*ldp); |
|
+ |
|
+ ldp = grub_efi_find_last_device_path (ddp); |
|
+ } |
|
+ |
|
if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE |
|
|| (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE |
|
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) |
|
@@ -760,6 +772,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, |
|
if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE |
|
|| (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE |
|
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE |
|
+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE |
|
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) |
|
continue; |
|
dup_dp = grub_efi_duplicate_device_path (dp); |
|
@@ -774,6 +787,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, |
|
dup_ldp->length = sizeof (*dup_ldp); |
|
} |
|
|
|
+ dup_ldp = grub_efi_find_last_device_path (dup_dp); |
|
+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) |
|
+ { |
|
+ dup_ldp = grub_efi_find_last_device_path (dup_dp); |
|
+ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; |
|
+ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; |
|
+ dup_ldp->length = sizeof (*dup_ldp); |
|
+ } |
|
+ |
|
dup_ldp = grub_efi_find_last_device_path (dup_dp); |
|
dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; |
|
dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; |
|
@@ -845,6 +867,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, |
|
|
|
GRUB_MOD_INIT(efinet) |
|
{ |
|
+ if (grub_efi_net_config) |
|
+ return; |
|
+ |
|
grub_efinet_findcards (); |
|
grub_efi_net_config = grub_efi_net_config_real; |
|
} |
|
@@ -856,5 +881,7 @@ GRUB_MOD_FINI(efinet) |
|
FOR_NET_CARDS_SAFE (card, next) |
|
if (card->driver == &efidriver) |
|
grub_net_card_unregister (card); |
|
+ |
|
+ grub_efi_net_config = NULL; |
|
} |
|
|
|
diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c |
|
new file mode 100644 |
|
index 00000000000..dbef63d8c08 |
|
--- /dev/null |
|
+++ b/grub-core/net/efi/dhcp.c |
|
@@ -0,0 +1,397 @@ |
|
+#include <grub/mm.h> |
|
+#include <grub/command.h> |
|
+#include <grub/efi/api.h> |
|
+#include <grub/efi/efi.h> |
|
+#include <grub/misc.h> |
|
+#include <grub/net/efi.h> |
|
+#include <grub/charset.h> |
|
+ |
|
+#ifdef GRUB_EFI_NET_DEBUG |
|
+static void |
|
+dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode) |
|
+{ |
|
+ switch (mode->state) |
|
+ { |
|
+ case GRUB_EFI_DHCP4_STOPPED: |
|
+ grub_printf ("STATE: STOPPED\n"); |
|
+ break; |
|
+ case GRUB_EFI_DHCP4_INIT: |
|
+ grub_printf ("STATE: INIT\n"); |
|
+ break; |
|
+ case GRUB_EFI_DHCP4_SELECTING: |
|
+ grub_printf ("STATE: SELECTING\n"); |
|
+ break; |
|
+ case GRUB_EFI_DHCP4_REQUESTING: |
|
+ grub_printf ("STATE: REQUESTING\n"); |
|
+ break; |
|
+ case GRUB_EFI_DHCP4_BOUND: |
|
+ grub_printf ("STATE: BOUND\n"); |
|
+ break; |
|
+ case GRUB_EFI_DHCP4_RENEWING: |
|
+ grub_printf ("STATE: RENEWING\n"); |
|
+ break; |
|
+ case GRUB_EFI_DHCP4_REBINDING: |
|
+ grub_printf ("STATE: REBINDING\n"); |
|
+ break; |
|
+ case GRUB_EFI_DHCP4_INIT_REBOOT: |
|
+ grub_printf ("STATE: INIT_REBOOT\n"); |
|
+ break; |
|
+ case GRUB_EFI_DHCP4_REBOOTING: |
|
+ grub_printf ("STATE: REBOOTING\n"); |
|
+ break; |
|
+ default: |
|
+ grub_printf ("STATE: UNKNOWN\n"); |
|
+ break; |
|
+ } |
|
+ |
|
+ grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n", |
|
+ mode->client_address[0], |
|
+ mode->client_address[1], |
|
+ mode->client_address[2], |
|
+ mode->client_address[3]); |
|
+ grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n", |
|
+ mode->server_address[0], |
|
+ mode->server_address[1], |
|
+ mode->server_address[2], |
|
+ mode->server_address[3]); |
|
+ grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n", |
|
+ mode->subnet_mask[0], |
|
+ mode->subnet_mask[1], |
|
+ mode->subnet_mask[2], |
|
+ mode->subnet_mask[3]); |
|
+ grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n", |
|
+ mode->router_address[0], |
|
+ mode->router_address[1], |
|
+ mode->router_address[2], |
|
+ mode->router_address[3]); |
|
+} |
|
+#endif |
|
+ |
|
+static grub_efi_ipv4_address_t * |
|
+grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet) |
|
+{ |
|
+ grub_efi_dhcp4_packet_option_t **option_list; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_uint32_t option_count = 0; |
|
+ grub_efi_uint32_t i; |
|
+ |
|
+ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL); |
|
+ |
|
+ if (status != GRUB_EFI_BUFFER_TOO_SMALL) |
|
+ return NULL; |
|
+ |
|
+ option_list = grub_malloc (option_count * sizeof(*option_list)); |
|
+ if (!option_list) |
|
+ return NULL; |
|
+ |
|
+ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_free (option_list); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ for (i = 0; i < option_count; ++i) |
|
+ { |
|
+ if (option_list[i]->op_code == 6) |
|
+ { |
|
+ grub_efi_ipv4_address_t *dns_address; |
|
+ |
|
+ if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0)) |
|
+ continue; |
|
+ |
|
+ /* We only contact primary dns */ |
|
+ dns_address = grub_malloc (sizeof (*dns_address)); |
|
+ if (!dns_address) |
|
+ { |
|
+ grub_free (option_list); |
|
+ return NULL; |
|
+ } |
|
+ grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address)); |
|
+ grub_free (option_list); |
|
+ return dns_address; |
|
+ } |
|
+ } |
|
+ |
|
+ grub_free (option_list); |
|
+ return NULL; |
|
+} |
|
+ |
|
+#if 0 |
|
+/* Somehow this doesn't work ... */ |
|
+static grub_err_t |
|
+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), |
|
+ int argc __attribute__ ((unused)), |
|
+ char **args __attribute__ ((unused))) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ { |
|
+ grub_efi_pxe_t *pxe = dev->ip4_pxe; |
|
+ grub_efi_pxe_mode_t *mode = pxe->mode; |
|
+ grub_efi_status_t status; |
|
+ |
|
+ if (!mode->started) |
|
+ { |
|
+ status = efi_call_2 (pxe->start, pxe, 0); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ grub_printf ("Couldn't start PXE\n"); |
|
+ } |
|
+ |
|
+ status = efi_call_2 (pxe->dhcp, pxe, 0); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_printf ("dhcp4 configure failed, %d\n", (int)status); |
|
+ continue; |
|
+ } |
|
+ |
|
+ dev->prefer_ip6 = 0; |
|
+ } |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+#endif |
|
+ |
|
+static grub_err_t |
|
+grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), |
|
+ int argc, |
|
+ char **args) |
|
+{ |
|
+ struct grub_efi_net_device *netdev; |
|
+ |
|
+ for (netdev = net_devices; netdev; netdev = netdev->next) |
|
+ { |
|
+ grub_efi_status_t status; |
|
+ grub_efi_dhcp4_mode_data_t mode; |
|
+ grub_efi_dhcp4_config_data_t config; |
|
+ grub_efi_dhcp4_packet_option_t *options; |
|
+ grub_efi_ipv4_address_t *dns_address; |
|
+ grub_efi_net_ip_manual_address_t net_ip; |
|
+ grub_efi_net_ip_address_t ip_addr; |
|
+ grub_efi_net_interface_t *inf = NULL; |
|
+ |
|
+ if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0) |
|
+ continue; |
|
+ |
|
+ grub_memset (&config, 0, sizeof(config)); |
|
+ |
|
+ config.option_count = 1; |
|
+ options = grub_malloc (sizeof(*options) + 2); |
|
+ /* Parameter request list */ |
|
+ options->op_code = 55; |
|
+ options->length = 3; |
|
+ /* subnet mask */ |
|
+ options->data[0] = 1; |
|
+ /* router */ |
|
+ options->data[1] = 3; |
|
+ /* DNS */ |
|
+ options->data[2] = 6; |
|
+ config.option_list = &options; |
|
+ |
|
+ /* FIXME: What if the dhcp has bounded */ |
|
+ status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config); |
|
+ grub_free (options); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_printf ("dhcp4 configure failed, %d\n", (int)status); |
|
+ continue; |
|
+ } |
|
+ |
|
+ status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_printf ("dhcp4 start failed, %d\n", (int)status); |
|
+ continue; |
|
+ } |
|
+ |
|
+ status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); |
|
+ continue; |
|
+ } |
|
+ |
|
+#ifdef GRUB_EFI_NET_DEBUG |
|
+ dhcp4_mode_print (&mode); |
|
+#endif |
|
+ |
|
+ for (inf = netdev->net_interfaces; inf; inf = inf->next) |
|
+ if (inf->prefer_ip6 == 0) |
|
+ break; |
|
+ |
|
+ grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address)); |
|
+ grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask)); |
|
+ |
|
+ if (!inf) |
|
+ { |
|
+ char *name = grub_xasprintf ("%s:dhcp", netdev->card_name); |
|
+ |
|
+ net_ip.is_ip6 = 0; |
|
+ inf = grub_efi_net_create_interface (netdev, |
|
+ name, |
|
+ &net_ip, |
|
+ 1); |
|
+ grub_free (name); |
|
+ } |
|
+ else |
|
+ { |
|
+ efi_net_interface_set_address (inf, &net_ip, 1); |
|
+ } |
|
+ |
|
+ grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4)); |
|
+ efi_net_interface_set_gateway (inf, &ip_addr); |
|
+ |
|
+ dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet); |
|
+ if (dns_address) |
|
+ efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address); |
|
+ |
|
+ } |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+ |
|
+static grub_err_t |
|
+grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), |
|
+ int argc, |
|
+ char **args) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ grub_efi_uint32_t ia_id; |
|
+ |
|
+ for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++) |
|
+ { |
|
+ grub_efi_dhcp6_config_data_t config; |
|
+ grub_efi_dhcp6_packet_option_t *option_list[1]; |
|
+ grub_efi_dhcp6_packet_option_t *opt; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_dhcp6_mode_data_t mode; |
|
+ grub_efi_dhcp6_retransmission_t retrans; |
|
+ grub_efi_net_ip_manual_address_t net_ip; |
|
+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; |
|
+ grub_efi_net_interface_t *inf = NULL; |
|
+ |
|
+ if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0) |
|
+ continue; |
|
+ |
|
+ opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t)); |
|
+ |
|
+#define GRUB_EFI_DHCP6_OPT_ORO 6 |
|
+ |
|
+ opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO); |
|
+ opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t)); |
|
+ |
|
+#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59 |
|
+#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23 |
|
+ |
|
+ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL)); |
|
+ grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t), |
|
+ grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)); |
|
+ |
|
+ option_list[0] = opt; |
|
+ retrans.irt = 4; |
|
+ retrans.mrc = 4; |
|
+ retrans.mrt = 32; |
|
+ retrans.mrd = 60; |
|
+ |
|
+ config.dhcp6_callback = NULL; |
|
+ config.callback_context = NULL; |
|
+ config.option_count = 1; |
|
+ config.option_list = option_list; |
|
+ config.ia_descriptor.ia_id = ia_id; |
|
+ config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA; |
|
+ config.ia_info_event = NULL; |
|
+ config.reconfigure_accept = 0; |
|
+ config.rapid_commit = 0; |
|
+ config.solicit_retransmission = &retrans; |
|
+ |
|
+ status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config); |
|
+ grub_free (opt); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_printf ("dhcp6 configure failed, %d\n", (int)status); |
|
+ continue; |
|
+ } |
|
+ status = efi_call_1 (dev->dhcp6->start, dev->dhcp6); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_printf ("dhcp6 start failed, %d\n", (int)status); |
|
+ continue; |
|
+ } |
|
+ |
|
+ status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); |
|
+ continue; |
|
+ } |
|
+ |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ if (inf->prefer_ip6 == 1) |
|
+ break; |
|
+ |
|
+ grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address)); |
|
+ net_ip.ip6.prefix_length = 64; |
|
+ net_ip.ip6.is_anycast = 0; |
|
+ net_ip.is_ip6 = 1; |
|
+ |
|
+ if (!inf) |
|
+ { |
|
+ char *name = grub_xasprintf ("%s:dhcp", dev->card_name); |
|
+ |
|
+ inf = grub_efi_net_create_interface (dev, |
|
+ name, |
|
+ &net_ip, |
|
+ 1); |
|
+ grub_free (name); |
|
+ } |
|
+ else |
|
+ { |
|
+ efi_net_interface_set_address (inf, &net_ip, 1); |
|
+ } |
|
+ |
|
+ { |
|
+ grub_efi_uint32_t count = 0; |
|
+ grub_efi_dhcp6_packet_option_t **options = NULL; |
|
+ grub_efi_uint32_t i; |
|
+ |
|
+ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL); |
|
+ |
|
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) |
|
+ { |
|
+ options = grub_malloc (count * sizeof(*options)); |
|
+ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); |
|
+ } |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ if (options) |
|
+ grub_free (options); |
|
+ continue; |
|
+ } |
|
+ |
|
+ for (i = 0; i < count; ++i) |
|
+ { |
|
+ if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)) |
|
+ { |
|
+ grub_efi_net_ip_address_t dns; |
|
+ grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6)); |
|
+ efi_net_interface_set_dns (inf, &dns); |
|
+ break; |
|
+ } |
|
+ } |
|
+ |
|
+ if (options) |
|
+ grub_free (options); |
|
+ } |
|
+ |
|
+ efi_call_1 (b->free_pool, mode.client_id); |
|
+ efi_call_1 (b->free_pool, mode.ia); |
|
+ } |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp; |
|
+grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6; |
|
diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c |
|
new file mode 100644 |
|
index 00000000000..ef371d885ea |
|
--- /dev/null |
|
+++ b/grub-core/net/efi/efi_netfs.c |
|
@@ -0,0 +1,57 @@ |
|
+#include <grub/dl.h> |
|
+#include <grub/env.h> |
|
+#define EFI_NET_CMD_PREFIX "net_efi" |
|
+#include <grub/net/efi.h> |
|
+ |
|
+GRUB_MOD_LICENSE ("GPLv3+"); |
|
+ |
|
+static grub_command_t cmd_efi_lsroutes; |
|
+static grub_command_t cmd_efi_lscards; |
|
+static grub_command_t cmd_efi_lsaddrs; |
|
+static grub_command_t cmd_efi_addaddr; |
|
+static grub_command_t cmd_efi_bootp; |
|
+static grub_command_t cmd_efi_bootp6; |
|
+ |
|
+static int initialized; |
|
+ |
|
+GRUB_MOD_INIT(efi_netfs) |
|
+{ |
|
+ if (grub_net_open) |
|
+ return; |
|
+ |
|
+ if (grub_efi_net_fs_init ()) |
|
+ { |
|
+ cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes, |
|
+ "", N_("list network routes")); |
|
+ cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards, |
|
+ "", N_("list network cards")); |
|
+ cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs, |
|
+ "", N_("list network addresses")); |
|
+ cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr, |
|
+ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), |
|
+ N_("Add a network address.")); |
|
+ cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp, |
|
+ N_("[CARD]"), |
|
+ N_("perform a bootp autoconfiguration")); |
|
+ cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6, |
|
+ N_("[CARD]"), |
|
+ N_("perform a bootp autoconfiguration")); |
|
+ initialized = 1; |
|
+ } |
|
+} |
|
+ |
|
+GRUB_MOD_FINI(efi_netfs) |
|
+{ |
|
+ if (initialized) |
|
+ { |
|
+ grub_unregister_command (cmd_efi_lsroutes); |
|
+ grub_unregister_command (cmd_efi_lscards); |
|
+ grub_unregister_command (cmd_efi_lsaddrs); |
|
+ grub_unregister_command (cmd_efi_addaddr); |
|
+ grub_unregister_command (cmd_efi_bootp); |
|
+ grub_unregister_command (cmd_efi_bootp6); |
|
+ grub_efi_net_fs_fini (); |
|
+ initialized = 0; |
|
+ return; |
|
+ } |
|
+} |
|
diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c |
|
new file mode 100644 |
|
index 00000000000..3f61fd2fa5b |
|
--- /dev/null |
|
+++ b/grub-core/net/efi/http.c |
|
@@ -0,0 +1,419 @@ |
|
+ |
|
+#include <grub/efi/api.h> |
|
+#include <grub/efi/efi.h> |
|
+#include <grub/misc.h> |
|
+#include <grub/net/efi.h> |
|
+#include <grub/charset.h> |
|
+ |
|
+static void |
|
+http_configure (struct grub_efi_net_device *dev, int prefer_ip6) |
|
+{ |
|
+ grub_efi_http_config_data_t http_config; |
|
+ grub_efi_httpv4_access_point_t httpv4_node; |
|
+ grub_efi_httpv6_access_point_t httpv6_node; |
|
+ grub_efi_status_t status; |
|
+ |
|
+ grub_efi_http_t *http = dev->http; |
|
+ |
|
+ grub_memset (&http_config, 0, sizeof(http_config)); |
|
+ http_config.http_version = GRUB_EFI_HTTPVERSION11; |
|
+ http_config.timeout_millisec = 5000; |
|
+ |
|
+ if (prefer_ip6) |
|
+ { |
|
+ grub_efi_uintn_t sz; |
|
+ grub_efi_ip6_config_manual_address_t manual_address; |
|
+ |
|
+ http_config.local_address_is_ipv6 = 1; |
|
+ sz = sizeof (manual_address); |
|
+ status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, |
|
+ &sz, &manual_address); |
|
+ |
|
+ if (status == GRUB_EFI_NOT_FOUND) |
|
+ { |
|
+ grub_printf ("The MANUAL ADDRESS is not found\n"); |
|
+ } |
|
+ |
|
+ /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_printf ("??? %d\n",(int) status); |
|
+ return; |
|
+ } |
|
+ |
|
+ grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address)); |
|
+ httpv6_node.local_port = 0; |
|
+ http_config.access_point.ipv6_node = &httpv6_node; |
|
+ } |
|
+ else |
|
+ { |
|
+ http_config.local_address_is_ipv6 = 0; |
|
+ grub_memset (&httpv4_node, 0, sizeof(httpv4_node)); |
|
+ httpv4_node.use_default_address = 1; |
|
+ |
|
+ /* Use random port here */ |
|
+ /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */ |
|
+ httpv4_node.local_port = 0; |
|
+ http_config.access_point.ipv4_node = &httpv4_node; |
|
+ } |
|
+ |
|
+ status = efi_call_2 (http->configure, http, &http_config); |
|
+ |
|
+ if (status == GRUB_EFI_ALREADY_STARTED) |
|
+ { |
|
+ /* XXX: This hangs HTTPS boot */ |
|
+#if 0 |
|
+ if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_error (GRUB_ERR_IO, N_("couldn't reset http instance")); |
|
+ grub_print_error (); |
|
+ return; |
|
+ } |
|
+ status = efi_call_2 (http->configure, http, &http_config); |
|
+#endif |
|
+ return; |
|
+ } |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status); |
|
+ grub_print_error (); |
|
+ return ; |
|
+ } |
|
+} |
|
+ |
|
+static grub_efi_boolean_t request_callback_done; |
|
+static grub_efi_boolean_t response_callback_done; |
|
+ |
|
+static void |
|
+grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)), |
|
+ void *context __attribute__ ((unused))) |
|
+{ |
|
+ request_callback_done = 1; |
|
+} |
|
+ |
|
+static void |
|
+grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)), |
|
+ void *context __attribute__ ((unused))) |
|
+{ |
|
+ response_callback_done = 1; |
|
+} |
|
+ |
|
+static grub_err_t |
|
+efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size) |
|
+{ |
|
+ grub_efi_http_request_data_t request_data; |
|
+ grub_efi_http_message_t request_message; |
|
+ grub_efi_http_token_t request_token; |
|
+ grub_efi_http_response_data_t response_data; |
|
+ grub_efi_http_message_t response_message; |
|
+ grub_efi_http_token_t response_token; |
|
+ grub_efi_http_header_t request_headers[3]; |
|
+ |
|
+ grub_efi_status_t status; |
|
+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; |
|
+ char *url = NULL; |
|
+ |
|
+ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; |
|
+ request_headers[0].field_value = (grub_efi_char8_t *)server; |
|
+ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; |
|
+ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; |
|
+ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; |
|
+ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; |
|
+ |
|
+ { |
|
+ grub_efi_ipv6_address_t address; |
|
+ const char *rest; |
|
+ grub_efi_char16_t *ucs2_url; |
|
+ grub_size_t url_len, ucs2_url_len; |
|
+ const char *protocol = (use_https == 1) ? "https" : "http"; |
|
+ |
|
+ if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) |
|
+ url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); |
|
+ else |
|
+ url = grub_xasprintf ("%s://%s%s", protocol, server, name); |
|
+ |
|
+ if (!url) |
|
+ { |
|
+ return grub_errno; |
|
+ } |
|
+ |
|
+ url_len = grub_strlen (url); |
|
+ ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8; |
|
+ ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0])); |
|
+ |
|
+ if (!ucs2_url) |
|
+ { |
|
+ grub_free (url); |
|
+ return grub_errno; |
|
+ } |
|
+ |
|
+ ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */ |
|
+ ucs2_url[ucs2_url_len] = 0; |
|
+ grub_free (url); |
|
+ request_data.url = ucs2_url; |
|
+ } |
|
+ |
|
+ request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; |
|
+ |
|
+ request_message.data.request = &request_data; |
|
+ request_message.header_count = 3; |
|
+ request_message.headers = request_headers; |
|
+ request_message.body_length = 0; |
|
+ request_message.body = NULL; |
|
+ |
|
+ /* request token */ |
|
+ request_token.event = NULL; |
|
+ request_token.status = GRUB_EFI_NOT_READY; |
|
+ request_token.message = &request_message; |
|
+ |
|
+ request_callback_done = 0; |
|
+ status = efi_call_5 (b->create_event, |
|
+ GRUB_EFI_EVT_NOTIFY_SIGNAL, |
|
+ GRUB_EFI_TPL_CALLBACK, |
|
+ grub_efi_http_request_callback, |
|
+ NULL, |
|
+ &request_token.event); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_free (request_data.url); |
|
+ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status); |
|
+ } |
|
+ |
|
+ status = efi_call_2 (http->request, http, &request_token); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ efi_call_1 (b->close_event, request_token.event); |
|
+ grub_free (request_data.url); |
|
+ return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status); |
|
+ } |
|
+ /* TODO: Add Timeout */ |
|
+ while (!request_callback_done) |
|
+ efi_call_1(http->poll, http); |
|
+ |
|
+ response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS; |
|
+ response_message.data.response = &response_data; |
|
+ /* herader_count will be updated by the HTTP driver on response */ |
|
+ response_message.header_count = 0; |
|
+ /* headers will be populated by the driver on response */ |
|
+ response_message.headers = NULL; |
|
+ /* use zero BodyLength to only receive the response headers */ |
|
+ response_message.body_length = 0; |
|
+ response_message.body = NULL; |
|
+ response_token.event = NULL; |
|
+ |
|
+ status = efi_call_5 (b->create_event, |
|
+ GRUB_EFI_EVT_NOTIFY_SIGNAL, |
|
+ GRUB_EFI_TPL_CALLBACK, |
|
+ grub_efi_http_response_callback, |
|
+ NULL, |
|
+ &response_token.event); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ efi_call_1 (b->close_event, request_token.event); |
|
+ grub_free (request_data.url); |
|
+ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status); |
|
+ } |
|
+ |
|
+ response_token.status = GRUB_EFI_SUCCESS; |
|
+ response_token.message = &response_message; |
|
+ |
|
+ /* wait for HTTP response */ |
|
+ response_callback_done = 0; |
|
+ status = efi_call_2 (http->response, http, &response_token); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ efi_call_1 (b->close_event, response_token.event); |
|
+ efi_call_1 (b->close_event, request_token.event); |
|
+ grub_free (request_data.url); |
|
+ return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status); |
|
+ } |
|
+ |
|
+ /* TODO: Add Timeout */ |
|
+ while (!response_callback_done) |
|
+ efi_call_1 (http->poll, http); |
|
+ |
|
+ if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK) |
|
+ { |
|
+ grub_efi_http_status_code_t status_code = response_message.data.response->status_code; |
|
+ |
|
+ if (response_message.headers) |
|
+ efi_call_1 (b->free_pool, response_message.headers); |
|
+ efi_call_1 (b->close_event, response_token.event); |
|
+ efi_call_1 (b->close_event, request_token.event); |
|
+ grub_free (request_data.url); |
|
+ if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND) |
|
+ { |
|
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name); |
|
+ } |
|
+ else |
|
+ { |
|
+ return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR, |
|
+ _("unsupported uefi http status code 0x%x"), status_code); |
|
+ } |
|
+ } |
|
+ |
|
+ if (file_size) |
|
+ { |
|
+ int i; |
|
+ /* parse the length of the file from the ContentLength header */ |
|
+ for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i) |
|
+ { |
|
+ if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length")) |
|
+ { |
|
+ *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10); |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ if (response_message.headers) |
|
+ efi_call_1 (b->free_pool, response_message.headers); |
|
+ efi_call_1 (b->close_event, response_token.event); |
|
+ efi_call_1 (b->close_event, request_token.event); |
|
+ grub_free (request_data.url); |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_ssize_t |
|
+efihttp_read (struct grub_efi_net_device *dev, |
|
+ char *buf, |
|
+ grub_size_t len) |
|
+{ |
|
+ grub_efi_http_message_t response_message; |
|
+ grub_efi_http_token_t response_token; |
|
+ |
|
+ grub_efi_status_t status; |
|
+ grub_size_t sum = 0; |
|
+ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; |
|
+ grub_efi_http_t *http = dev->http; |
|
+ |
|
+ if (!len) |
|
+ { |
|
+ grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read"); |
|
+ return -1; |
|
+ } |
|
+ |
|
+ efi_call_5 (b->create_event, |
|
+ GRUB_EFI_EVT_NOTIFY_SIGNAL, |
|
+ GRUB_EFI_TPL_CALLBACK, |
|
+ grub_efi_http_response_callback, |
|
+ NULL, |
|
+ &response_token.event); |
|
+ |
|
+ while (len) |
|
+ { |
|
+ response_message.data.response = NULL; |
|
+ response_message.header_count = 0; |
|
+ response_message.headers = NULL; |
|
+ response_message.body_length = len; |
|
+ response_message.body = buf; |
|
+ |
|
+ response_token.message = &response_message; |
|
+ response_token.status = GRUB_EFI_NOT_READY; |
|
+ |
|
+ response_callback_done = 0; |
|
+ |
|
+ status = efi_call_2 (http->response, http, &response_token); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ efi_call_1 (b->close_event, response_token.event); |
|
+ grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status); |
|
+ return -1; |
|
+ } |
|
+ |
|
+ while (!response_callback_done) |
|
+ efi_call_1(http->poll, http); |
|
+ |
|
+ sum += response_message.body_length; |
|
+ buf += response_message.body_length; |
|
+ len -= response_message.body_length; |
|
+ } |
|
+ |
|
+ efi_call_1 (b->close_event, response_token.event); |
|
+ |
|
+ return sum; |
|
+} |
|
+ |
|
+static grub_err_t |
|
+grub_efihttp_open (struct grub_efi_net_device *dev, |
|
+ int prefer_ip6 __attribute__ ((unused)), |
|
+ grub_file_t file, |
|
+ const char *filename __attribute__ ((unused)), |
|
+ int type) |
|
+{ |
|
+ grub_err_t err; |
|
+ grub_off_t size; |
|
+ char *buf; |
|
+ |
|
+ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); |
|
+ if (err != GRUB_ERR_NONE) |
|
+ return err; |
|
+ |
|
+ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size); |
|
+ if (err != GRUB_ERR_NONE) |
|
+ return err; |
|
+ |
|
+ buf = grub_malloc (size); |
|
+ efihttp_read (dev, buf, size); |
|
+ |
|
+ file->size = size; |
|
+ file->data = buf; |
|
+ file->not_easily_seekable = 0; |
|
+ file->device->net->offset = 0; |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_err_t |
|
+grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)), |
|
+ int prefer_ip6 __attribute__ ((unused)), |
|
+ grub_file_t file) |
|
+{ |
|
+ if (file->data) |
|
+ grub_free (file->data); |
|
+ |
|
+ file->data = 0; |
|
+ file->offset = 0; |
|
+ file->size = 0; |
|
+ file->device->net->offset = 0; |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_ssize_t |
|
+grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)), |
|
+ int prefer_ip6 __attribute__((unused)), |
|
+ grub_file_t file, |
|
+ char *buf, |
|
+ grub_size_t len) |
|
+{ |
|
+ grub_size_t r = len; |
|
+ |
|
+ if (!file->data || !buf || !len) |
|
+ return 0; |
|
+ |
|
+ if ((file->device->net->offset + len) > file->size) |
|
+ r = file->size - file->device->net->offset; |
|
+ |
|
+ if (r) |
|
+ { |
|
+ grub_memcpy (buf, (char *)file->data + file->device->net->offset, r); |
|
+ file->device->net->offset += r; |
|
+ } |
|
+ |
|
+ return r; |
|
+} |
|
+ |
|
+struct grub_efi_net_io io_http = |
|
+ { |
|
+ .configure = http_configure, |
|
+ .open = grub_efihttp_open, |
|
+ .read = grub_efihttp_read, |
|
+ .close = grub_efihttp_close |
|
+ }; |
|
diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c |
|
new file mode 100644 |
|
index 00000000000..b711a5d9457 |
|
--- /dev/null |
|
+++ b/grub-core/net/efi/ip4_config.c |
|
@@ -0,0 +1,398 @@ |
|
+ |
|
+#include <grub/efi/api.h> |
|
+#include <grub/efi/efi.h> |
|
+#include <grub/misc.h> |
|
+#include <grub/net/efi.h> |
|
+#include <grub/charset.h> |
|
+ |
|
+char * |
|
+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) |
|
+{ |
|
+ char *hw_addr, *p; |
|
+ int sz, s; |
|
+ int i; |
|
+ |
|
+ sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1; |
|
+ |
|
+ hw_addr = grub_malloc (sz); |
|
+ if (!hw_addr) |
|
+ return NULL; |
|
+ |
|
+ p = hw_addr; |
|
+ s = sz; |
|
+ for (i = 0; i < (int)hw_address_size; i++) |
|
+ { |
|
+ grub_snprintf (p, sz, "%02x:", hw_address[i]); |
|
+ p += sizeof ("XX:") - 1; |
|
+ s -= sizeof ("XX:") - 1; |
|
+ } |
|
+ |
|
+ hw_addr[sz - 2] = '\0'; |
|
+ return hw_addr; |
|
+} |
|
+ |
|
+char * |
|
+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address) |
|
+{ |
|
+ char *addr; |
|
+ |
|
+ addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX")); |
|
+ if (!addr) |
|
+ return NULL; |
|
+ |
|
+ /* FIXME: Use grub_xasprintf ? */ |
|
+ grub_snprintf (addr, |
|
+ sizeof ("XXX.XXX.XXX.XXX"), |
|
+ "%u.%u.%u.%u", |
|
+ (*address)[0], |
|
+ (*address)[1], |
|
+ (*address)[2], |
|
+ (*address)[3]); |
|
+ |
|
+ return addr; |
|
+} |
|
+ |
|
+int |
|
+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) |
|
+{ |
|
+ grub_uint32_t newip = 0; |
|
+ int i; |
|
+ const char *ptr = val; |
|
+ |
|
+ for (i = 0; i < 4; i++) |
|
+ { |
|
+ unsigned long t; |
|
+ t = grub_strtoul (ptr, (char **) &ptr, 0); |
|
+ if (grub_errno) |
|
+ { |
|
+ grub_errno = GRUB_ERR_NONE; |
|
+ return 0; |
|
+ } |
|
+ if (*ptr != '.' && i == 0) |
|
+ { |
|
+ /* XXX: t is in host byte order */ |
|
+ newip = t; |
|
+ break; |
|
+ } |
|
+ if (t & ~0xff) |
|
+ return 0; |
|
+ newip <<= 8; |
|
+ newip |= t; |
|
+ if (i != 3 && *ptr != '.') |
|
+ return 0; |
|
+ ptr++; |
|
+ } |
|
+ |
|
+ newip = grub_cpu_to_be32 (newip); |
|
+ |
|
+ grub_memcpy (address, &newip, sizeof(*address)); |
|
+ |
|
+ if (rest) |
|
+ *rest = (ptr - 1); |
|
+ return 1; |
|
+} |
|
+ |
|
+static grub_efi_ip4_config2_interface_info_t * |
|
+efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config) |
|
+{ |
|
+ grub_efi_uintn_t sz; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_ip4_config2_interface_info_t *interface_info; |
|
+ |
|
+ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); |
|
+ interface_info = grub_malloc (sz); |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ status = efi_call_4 (ip4_config->get_data, ip4_config, |
|
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, |
|
+ &sz, interface_info); |
|
+ |
|
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL) |
|
+ { |
|
+ grub_free (interface_info); |
|
+ interface_info = grub_malloc (sz); |
|
+ status = efi_call_4 (ip4_config->get_data, ip4_config, |
|
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, |
|
+ &sz, interface_info); |
|
+ } |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_free (interface_info); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return interface_info; |
|
+} |
|
+ |
|
+static grub_efi_ip4_config2_manual_address_t * |
|
+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) |
|
+{ |
|
+ grub_efi_uintn_t sz; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_ip4_config2_manual_address_t *manual_address; |
|
+ |
|
+ sz = sizeof (*manual_address); |
|
+ manual_address = grub_malloc (sz); |
|
+ if (!manual_address) |
|
+ return NULL; |
|
+ |
|
+ status = efi_call_4 (ip4_config->get_data, ip4_config, |
|
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, |
|
+ &sz, manual_address); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_free (manual_address); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return manual_address; |
|
+} |
|
+ |
|
+char * |
|
+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev) |
|
+{ |
|
+ grub_efi_ip4_config2_interface_info_t *interface_info; |
|
+ char *name; |
|
+ |
|
+ interface_info = efi_ip4_config_interface_info (dev->ip4_config); |
|
+ |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE |
|
+ * GRUB_MAX_UTF8_PER_UTF16 + 1); |
|
+ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, |
|
+ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; |
|
+ grub_free (interface_info); |
|
+ return name; |
|
+} |
|
+ |
|
+static char * |
|
+grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev) |
|
+{ |
|
+ grub_efi_ip4_config2_interface_info_t *interface_info; |
|
+ char *hw_addr; |
|
+ |
|
+ interface_info = efi_ip4_config_interface_info (dev->ip4_config); |
|
+ |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); |
|
+ grub_free (interface_info); |
|
+ |
|
+ return hw_addr; |
|
+} |
|
+ |
|
+static char * |
|
+grub_efi_ip4_interface_address (struct grub_efi_net_device *dev) |
|
+{ |
|
+ grub_efi_ip4_config2_manual_address_t *manual_address; |
|
+ char *addr; |
|
+ |
|
+ manual_address = efi_ip4_config_manual_address (dev->ip4_config); |
|
+ |
|
+ if (!manual_address) |
|
+ return NULL; |
|
+ |
|
+ addr = grub_efi_ip4_address_to_string (&manual_address->address); |
|
+ grub_free (manual_address); |
|
+ return addr; |
|
+} |
|
+ |
|
+ |
|
+static int |
|
+address_mask_size (grub_efi_ipv4_address_t *address) |
|
+{ |
|
+ grub_uint8_t i; |
|
+ grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address)); |
|
+ |
|
+ if (u32_addr == 0) |
|
+ return 0; |
|
+ |
|
+ for (i = 0; i < 32 ; ++i) |
|
+ { |
|
+ if (u32_addr == ((0xffffffff >> i) << i)) |
|
+ return (32 - i); |
|
+ } |
|
+ |
|
+ return -1; |
|
+} |
|
+ |
|
+static char ** |
|
+grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) |
|
+{ |
|
+ grub_efi_ip4_config2_interface_info_t *interface_info; |
|
+ char **ret; |
|
+ int i, id; |
|
+ |
|
+ interface_info = efi_ip4_config_interface_info (dev->ip4_config); |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1)); |
|
+ |
|
+ if (!ret) |
|
+ { |
|
+ grub_free (interface_info); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ id = 0; |
|
+ for (i = 0; i < (int)interface_info->route_table_size; i++) |
|
+ { |
|
+ char *subnet, *gateway, *mask; |
|
+ grub_uint32_t u32_subnet, u32_gateway; |
|
+ int mask_size; |
|
+ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; |
|
+ grub_efi_net_interface_t *inf; |
|
+ char *interface_name = NULL; |
|
+ |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ if (!inf->prefer_ip6) |
|
+ interface_name = inf->name; |
|
+ |
|
+ u32_gateway = grub_get_unaligned32 (&route_table->gateway_address); |
|
+ gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address); |
|
+ u32_subnet = grub_get_unaligned32 (&route_table->subnet_address); |
|
+ subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address); |
|
+ mask_size = address_mask_size (&route_table->subnet_mask); |
|
+ mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask); |
|
+ if (u32_subnet && !u32_gateway && interface_name) |
|
+ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name); |
|
+ else if (u32_subnet && u32_gateway) |
|
+ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); |
|
+ else if (!u32_subnet && u32_gateway) |
|
+ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); |
|
+ grub_free (subnet); |
|
+ grub_free (gateway); |
|
+ grub_free (mask); |
|
+ } |
|
+ |
|
+ ret[id] = NULL; |
|
+ grub_free (interface_info); |
|
+ return ret; |
|
+} |
|
+ |
|
+static grub_efi_net_interface_t * |
|
+grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) |
|
+{ |
|
+ grub_efi_ip4_config2_interface_info_t *interface_info; |
|
+ grub_efi_net_interface_t *inf; |
|
+ int i; |
|
+ grub_efi_ipv4_address_t *address = &ip_address->ip4; |
|
+ |
|
+ interface_info = efi_ip4_config_interface_info (dev->ip4_config); |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ for (i = 0; i < (int)interface_info->route_table_size; i++) |
|
+ { |
|
+ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; |
|
+ grub_uint32_t u32_address, u32_mask, u32_subnet; |
|
+ |
|
+ u32_address = grub_get_unaligned32 (address); |
|
+ u32_subnet = grub_get_unaligned32 (route_table->subnet_address); |
|
+ u32_mask = grub_get_unaligned32 (route_table->subnet_mask); |
|
+ |
|
+ /* SKIP Default GATEWAY */ |
|
+ if (!u32_subnet && !u32_mask) |
|
+ continue; |
|
+ |
|
+ if ((u32_address & u32_mask) == u32_subnet) |
|
+ { |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ if (!inf->prefer_ip6) |
|
+ { |
|
+ grub_free (interface_info); |
|
+ return inf; |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ grub_free (interface_info); |
|
+ return NULL; |
|
+} |
|
+ |
|
+static int |
|
+grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev, |
|
+ grub_efi_net_ip_manual_address_t *net_ip, |
|
+ int with_subnet) |
|
+{ |
|
+ grub_efi_status_t status; |
|
+ grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4; |
|
+ |
|
+ if (!with_subnet) |
|
+ { |
|
+ grub_efi_ip4_config2_manual_address_t *manual_address = |
|
+ efi_ip4_config_manual_address (dev->ip4_config); |
|
+ |
|
+ if (manual_address) |
|
+ { |
|
+ grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask)); |
|
+ grub_free (manual_address); |
|
+ } |
|
+ else |
|
+ { |
|
+ /* XXX: */ |
|
+ address->subnet_mask[0] = 0xff; |
|
+ address->subnet_mask[1] = 0xff; |
|
+ address->subnet_mask[2] = 0xff; |
|
+ address->subnet_mask[3] = 0; |
|
+ } |
|
+ } |
|
+ |
|
+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, |
|
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, |
|
+ sizeof(*address), address); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ return 0; |
|
+ |
|
+ return 1; |
|
+} |
|
+ |
|
+static int |
|
+grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev, |
|
+ grub_efi_net_ip_address_t *address) |
|
+{ |
|
+ grub_efi_status_t status; |
|
+ |
|
+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, |
|
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, |
|
+ sizeof (address->ip4), &address->ip4); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ return 0; |
|
+ return 1; |
|
+} |
|
+ |
|
+/* FIXME: Multiple DNS */ |
|
+static int |
|
+grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev, |
|
+ grub_efi_net_ip_address_t *address) |
|
+{ |
|
+ grub_efi_status_t status; |
|
+ |
|
+ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, |
|
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, |
|
+ sizeof (address->ip4), &address->ip4); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ return 0; |
|
+ return 1; |
|
+} |
|
+ |
|
+grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t) |
|
+ { |
|
+ .get_hw_address = grub_efi_ip4_interface_hw_address, |
|
+ .get_address = grub_efi_ip4_interface_address, |
|
+ .get_route_table = grub_efi_ip4_interface_route_table, |
|
+ .best_interface = grub_efi_ip4_interface_match, |
|
+ .set_address = grub_efi_ip4_interface_set_manual_address, |
|
+ .set_gateway = grub_efi_ip4_interface_set_gateway, |
|
+ .set_dns = grub_efi_ip4_interface_set_dns |
|
+ }; |
|
diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c |
|
new file mode 100644 |
|
index 00000000000..017c4d05bc7 |
|
--- /dev/null |
|
+++ b/grub-core/net/efi/ip6_config.c |
|
@@ -0,0 +1,422 @@ |
|
+#include <grub/efi/api.h> |
|
+#include <grub/efi/efi.h> |
|
+#include <grub/misc.h> |
|
+#include <grub/net/efi.h> |
|
+#include <grub/charset.h> |
|
+ |
|
+char * |
|
+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) |
|
+{ |
|
+ char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); |
|
+ char *p; |
|
+ int i; |
|
+ int squash; |
|
+ |
|
+ if (!str) |
|
+ return NULL; |
|
+ |
|
+ p = str; |
|
+ squash = 0; |
|
+ for (i = 0; i < 8; ++i) |
|
+ { |
|
+ grub_uint16_t addr; |
|
+ |
|
+ if (i == 7) |
|
+ squash = 2; |
|
+ |
|
+ addr = grub_get_unaligned16 (address->addr + i * 2); |
|
+ |
|
+ if (grub_be_to_cpu16 (addr)) |
|
+ { |
|
+ char buf[sizeof ("XXXX")]; |
|
+ if (i > 0) |
|
+ *p++ = ':'; |
|
+ grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr)); |
|
+ grub_strcpy (p, buf); |
|
+ p += grub_strlen (buf); |
|
+ |
|
+ if (squash == 1) |
|
+ squash = 2; |
|
+ } |
|
+ else |
|
+ { |
|
+ if (squash == 0) |
|
+ { |
|
+ *p++ = ':'; |
|
+ squash = 1; |
|
+ } |
|
+ else if (squash == 2) |
|
+ { |
|
+ *p++ = ':'; |
|
+ *p++ = '0'; |
|
+ } |
|
+ } |
|
+ } |
|
+ *p = '\0'; |
|
+ return str; |
|
+} |
|
+ |
|
+int |
|
+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest) |
|
+{ |
|
+ grub_uint16_t newip[8]; |
|
+ const char *ptr = val; |
|
+ int word, quaddot = -1; |
|
+ int bracketed = 0; |
|
+ |
|
+ if (ptr[0] == '[') { |
|
+ bracketed = 1; |
|
+ ptr++; |
|
+ } |
|
+ |
|
+ if (ptr[0] == ':' && ptr[1] != ':') |
|
+ return 0; |
|
+ if (ptr[0] == ':') |
|
+ ptr++; |
|
+ |
|
+ for (word = 0; word < 8; word++) |
|
+ { |
|
+ unsigned long t; |
|
+ if (*ptr == ':') |
|
+ { |
|
+ quaddot = word; |
|
+ word--; |
|
+ ptr++; |
|
+ continue; |
|
+ } |
|
+ t = grub_strtoul (ptr, (char **) &ptr, 16); |
|
+ if (grub_errno) |
|
+ { |
|
+ grub_errno = GRUB_ERR_NONE; |
|
+ break; |
|
+ } |
|
+ if (t & ~0xffff) |
|
+ return 0; |
|
+ newip[word] = grub_cpu_to_be16 (t); |
|
+ if (*ptr != ':') |
|
+ break; |
|
+ ptr++; |
|
+ } |
|
+ if (quaddot == -1 && word < 7) |
|
+ return 0; |
|
+ if (quaddot != -1) |
|
+ { |
|
+ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], |
|
+ (word - quaddot + 1) * sizeof (newip[0])); |
|
+ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); |
|
+ } |
|
+ grub_memcpy (address, newip, 16); |
|
+ if (bracketed && *ptr == ']') { |
|
+ ptr++; |
|
+ } |
|
+ if (rest) |
|
+ *rest = ptr; |
|
+ return 1; |
|
+} |
|
+ |
|
+static grub_efi_ip6_config_interface_info_t * |
|
+efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config) |
|
+{ |
|
+ grub_efi_uintn_t sz; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_ip6_config_interface_info_t *interface_info; |
|
+ |
|
+ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); |
|
+ interface_info = grub_malloc (sz); |
|
+ |
|
+ status = efi_call_4 (ip6_config->get_data, ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, |
|
+ &sz, interface_info); |
|
+ |
|
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL) |
|
+ { |
|
+ grub_free (interface_info); |
|
+ interface_info = grub_malloc (sz); |
|
+ status = efi_call_4 (ip6_config->get_data, ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, |
|
+ &sz, interface_info); |
|
+ } |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_free (interface_info); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return interface_info; |
|
+} |
|
+ |
|
+static grub_efi_ip6_config_manual_address_t * |
|
+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) |
|
+{ |
|
+ grub_efi_uintn_t sz; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_ip6_config_manual_address_t *manual_address; |
|
+ |
|
+ sz = sizeof (*manual_address); |
|
+ manual_address = grub_malloc (sz); |
|
+ if (!manual_address) |
|
+ return NULL; |
|
+ |
|
+ status = efi_call_4 (ip6_config->get_data, ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, |
|
+ &sz, manual_address); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_free (manual_address); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return manual_address; |
|
+} |
|
+ |
|
+char * |
|
+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev) |
|
+{ |
|
+ grub_efi_ip6_config_interface_info_t *interface_info; |
|
+ char *name; |
|
+ |
|
+ interface_info = efi_ip6_config_interface_info (dev->ip6_config); |
|
+ |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE |
|
+ * GRUB_MAX_UTF8_PER_UTF16 + 1); |
|
+ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, |
|
+ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; |
|
+ grub_free (interface_info); |
|
+ return name; |
|
+} |
|
+ |
|
+static char * |
|
+grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev) |
|
+{ |
|
+ grub_efi_ip6_config_interface_info_t *interface_info; |
|
+ char *hw_addr; |
|
+ |
|
+ interface_info = efi_ip6_config_interface_info (dev->ip6_config); |
|
+ |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); |
|
+ grub_free (interface_info); |
|
+ |
|
+ return hw_addr; |
|
+} |
|
+ |
|
+static char * |
|
+grub_efi_ip6_interface_address (struct grub_efi_net_device *dev) |
|
+{ |
|
+ grub_efi_ip6_config_manual_address_t *manual_address; |
|
+ char *addr; |
|
+ |
|
+ manual_address = efi_ip6_config_manual_address (dev->ip6_config); |
|
+ |
|
+ if (!manual_address) |
|
+ return NULL; |
|
+ |
|
+ addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address); |
|
+ grub_free (manual_address); |
|
+ return addr; |
|
+} |
|
+ |
|
+static char ** |
|
+grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) |
|
+{ |
|
+ grub_efi_ip6_config_interface_info_t *interface_info; |
|
+ char **ret; |
|
+ int i, id; |
|
+ |
|
+ interface_info = efi_ip6_config_interface_info (dev->ip6_config); |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1)); |
|
+ |
|
+ if (!ret) |
|
+ { |
|
+ grub_free (interface_info); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ id = 0; |
|
+ for (i = 0; i < (int)interface_info->route_count ; i++) |
|
+ { |
|
+ char *gateway, *destination; |
|
+ grub_uint64_t u64_gateway[2]; |
|
+ grub_uint64_t u64_destination[2]; |
|
+ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; |
|
+ grub_efi_net_interface_t *inf; |
|
+ char *interface_name = NULL; |
|
+ |
|
+ gateway = grub_efi_ip6_address_to_string (&route_table->gateway); |
|
+ destination = grub_efi_ip6_address_to_string (&route_table->destination); |
|
+ |
|
+ u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr); |
|
+ u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8); |
|
+ u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr); |
|
+ u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8); |
|
+ |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ if (inf->prefer_ip6) |
|
+ interface_name = inf->name; |
|
+ |
|
+ if ((!u64_gateway[0] && !u64_gateway[1]) |
|
+ && (u64_destination[0] || u64_destination[1])) |
|
+ { |
|
+ if (interface_name) |
|
+ { |
|
+ if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL) |
|
+ && (!u64_destination[1]) |
|
+ && (route_table->prefix_length == 64)) |
|
+ ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); |
|
+ else |
|
+ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); |
|
+ } |
|
+ } |
|
+ else if ((u64_gateway[0] || u64_gateway[1]) |
|
+ && (u64_destination[0] || u64_destination[1])) |
|
+ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); |
|
+ else if ((u64_gateway[0] || u64_gateway[1]) |
|
+ && (!u64_destination[0] && !u64_destination[1])) |
|
+ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); |
|
+ |
|
+ grub_free (gateway); |
|
+ grub_free (destination); |
|
+ } |
|
+ |
|
+ ret[id] = NULL; |
|
+ grub_free (interface_info); |
|
+ return ret; |
|
+} |
|
+ |
|
+static grub_efi_net_interface_t * |
|
+grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) |
|
+{ |
|
+ grub_efi_ip6_config_interface_info_t *interface_info; |
|
+ grub_efi_net_interface_t *inf; |
|
+ int i; |
|
+ grub_efi_ipv6_address_t *address = &ip_address->ip6; |
|
+ |
|
+ interface_info = efi_ip6_config_interface_info (dev->ip6_config); |
|
+ if (!interface_info) |
|
+ return NULL; |
|
+ |
|
+ for (i = 0; i < (int)interface_info->route_count ; i++) |
|
+ { |
|
+ grub_uint64_t u64_addr[2]; |
|
+ grub_uint64_t u64_subnet[2]; |
|
+ grub_uint64_t u64_mask[2]; |
|
+ |
|
+ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; |
|
+ |
|
+ /* SKIP Default GATEWAY */ |
|
+ if (route_table->prefix_length == 0) |
|
+ continue; |
|
+ |
|
+ u64_addr[0] = grub_get_unaligned64 (address); |
|
+ u64_addr[1] = grub_get_unaligned64 (address + 4); |
|
+ u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr); |
|
+ u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8); |
|
+ u64_mask[0] = (route_table->prefix_length <= 64) ? |
|
+ 0xffffffffffffffffULL << (64 - route_table->prefix_length) : |
|
+ 0xffffffffffffffffULL; |
|
+ u64_mask[1] = (route_table->prefix_length <= 64) ? |
|
+ 0 : |
|
+ 0xffffffffffffffffULL << (128 - route_table->prefix_length); |
|
+ |
|
+ if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0]) |
|
+ && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1])) |
|
+ { |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ if (inf->prefer_ip6) |
|
+ { |
|
+ grub_free (interface_info); |
|
+ return inf; |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ grub_free (interface_info); |
|
+ return NULL; |
|
+} |
|
+ |
|
+static int |
|
+grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev, |
|
+ grub_efi_net_ip_manual_address_t *net_ip, |
|
+ int with_subnet) |
|
+{ |
|
+ grub_efi_status_t status; |
|
+ grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6; |
|
+ |
|
+ if (!with_subnet) |
|
+ { |
|
+ grub_efi_ip6_config_manual_address_t *manual_address = |
|
+ efi_ip6_config_manual_address (dev->ip6_config); |
|
+ |
|
+ if (manual_address) |
|
+ { |
|
+ address->prefix_length = manual_address->prefix_length; |
|
+ grub_free (manual_address); |
|
+ } |
|
+ else |
|
+ { |
|
+ /* XXX: */ |
|
+ address->prefix_length = 64; |
|
+ } |
|
+ } |
|
+ |
|
+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, |
|
+ sizeof(*address), address); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ return 0; |
|
+ |
|
+ return 1; |
|
+} |
|
+ |
|
+static int |
|
+grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev, |
|
+ grub_efi_net_ip_address_t *address) |
|
+{ |
|
+ grub_efi_status_t status; |
|
+ |
|
+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, |
|
+ sizeof (address->ip6), &address->ip6); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ return 0; |
|
+ return 1; |
|
+} |
|
+ |
|
+static int |
|
+grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev, |
|
+ grub_efi_net_ip_address_t *address) |
|
+{ |
|
+ |
|
+ grub_efi_status_t status; |
|
+ |
|
+ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, |
|
+ sizeof (address->ip6), &address->ip6); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ return 0; |
|
+ return 1; |
|
+} |
|
+ |
|
+grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t) |
|
+ { |
|
+ .get_hw_address = grub_efi_ip6_interface_hw_address, |
|
+ .get_address = grub_efi_ip6_interface_address, |
|
+ .get_route_table = grub_efi_ip6_interface_route_table, |
|
+ .best_interface = grub_efi_ip6_interface_match, |
|
+ .set_address = grub_efi_ip6_interface_set_manual_address, |
|
+ .set_gateway = grub_efi_ip6_interface_set_gateway, |
|
+ .set_dns = grub_efi_ip6_interface_set_dns |
|
+ }; |
|
diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c |
|
new file mode 100644 |
|
index 00000000000..86bce6535d3 |
|
--- /dev/null |
|
+++ b/grub-core/net/efi/net.c |
|
@@ -0,0 +1,1428 @@ |
|
+#include <grub/net.h> |
|
+#include <grub/env.h> |
|
+#include <grub/mm.h> |
|
+#include <grub/misc.h> |
|
+#include <grub/dl.h> |
|
+#include <grub/command.h> |
|
+#include <grub/efi/api.h> |
|
+#include <grub/efi/efi.h> |
|
+#include <grub/i18n.h> |
|
+#include <grub/bufio.h> |
|
+#include <grub/efi/http.h> |
|
+#include <grub/efi/dhcp.h> |
|
+#include <grub/net/efi.h> |
|
+#include <grub/charset.h> |
|
+ |
|
+GRUB_MOD_LICENSE ("GPLv3+"); |
|
+ |
|
+#define GRUB_EFI_IP6_PREFIX_LENGTH 64 |
|
+ |
|
+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; |
|
+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; |
|
+static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; |
|
+static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; |
|
+static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; |
|
+static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; |
|
+static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID; |
|
+static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; |
|
+static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID; |
|
+ |
|
+struct grub_efi_net_device *net_devices; |
|
+ |
|
+static char *default_server; |
|
+static grub_efi_net_interface_t *net_interface; |
|
+static grub_efi_net_interface_t *net_default_interface; |
|
+ |
|
+#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6) |
|
+#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type) |
|
+#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz) |
|
+#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file) |
|
+#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__) |
|
+ |
|
+static grub_efi_handle_t |
|
+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, |
|
+ grub_efi_device_path_t **r_device_path) |
|
+{ |
|
+ grub_efi_handle_t handle; |
|
+ grub_efi_status_t status; |
|
+ |
|
+ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, |
|
+ protocol, &device_path, &handle); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ return 0; |
|
+ |
|
+ if (r_device_path) |
|
+ *r_device_path = device_path; |
|
+ |
|
+ return handle; |
|
+} |
|
+ |
|
+static int |
|
+url_parse_fields (const char *url, char **proto, char **host, char **path) |
|
+{ |
|
+ const char *p, *ps; |
|
+ grub_size_t l; |
|
+ |
|
+ *proto = *host = *path = NULL; |
|
+ ps = p = url; |
|
+ |
|
+ while ((p = grub_strchr (p, ':'))) |
|
+ { |
|
+ if (grub_strlen (p) < sizeof ("://") - 1) |
|
+ break; |
|
+ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) |
|
+ { |
|
+ l = p - ps; |
|
+ *proto = grub_malloc (l + 1); |
|
+ if (!*proto) |
|
+ { |
|
+ grub_print_error (); |
|
+ return 0; |
|
+ } |
|
+ |
|
+ grub_memcpy (*proto, ps, l); |
|
+ (*proto)[l] = '\0'; |
|
+ p += sizeof ("://") - 1; |
|
+ break; |
|
+ } |
|
+ ++p; |
|
+ } |
|
+ |
|
+ if (!*proto) |
|
+ { |
|
+ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); |
|
+ return 0; |
|
+ } |
|
+ |
|
+ ps = p; |
|
+ p = grub_strchr (p, '/'); |
|
+ |
|
+ if (!p) |
|
+ { |
|
+ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); |
|
+ grub_free (*proto); |
|
+ *proto = NULL; |
|
+ return 0; |
|
+ } |
|
+ |
|
+ l = p - ps; |
|
+ |
|
+ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') |
|
+ { |
|
+ *host = grub_malloc (l - 1); |
|
+ if (!*host) |
|
+ { |
|
+ grub_print_error (); |
|
+ grub_free (*proto); |
|
+ *proto = NULL; |
|
+ return 0; |
|
+ } |
|
+ grub_memcpy (*host, ps + 1, l - 2); |
|
+ (*host)[l - 2] = 0; |
|
+ } |
|
+ else |
|
+ { |
|
+ *host = grub_malloc (l + 1); |
|
+ if (!*host) |
|
+ { |
|
+ grub_print_error (); |
|
+ grub_free (*proto); |
|
+ *proto = NULL; |
|
+ return 0; |
|
+ } |
|
+ grub_memcpy (*host, ps, l); |
|
+ (*host)[l] = 0; |
|
+ } |
|
+ |
|
+ *path = grub_strdup (p); |
|
+ if (!*path) |
|
+ { |
|
+ grub_print_error (); |
|
+ grub_free (*host); |
|
+ grub_free (*proto); |
|
+ *host = NULL; |
|
+ *proto = NULL; |
|
+ return 0; |
|
+ } |
|
+ return 1; |
|
+} |
|
+ |
|
+static void |
|
+url_get_boot_location (const char *url, char **device, char **path, int is_default) |
|
+{ |
|
+ char *protocol, *server, *file; |
|
+ char *slash; |
|
+ |
|
+ if (!url_parse_fields (url, &protocol, &server, &file)) |
|
+ return; |
|
+ |
|
+ if ((slash = grub_strrchr (file, '/'))) |
|
+ *slash = 0; |
|
+ else |
|
+ *file = 0; |
|
+ |
|
+ *device = grub_xasprintf ("%s,%s", protocol, server); |
|
+ *path = grub_strdup(file); |
|
+ |
|
+ if (is_default) |
|
+ default_server = server; |
|
+ else |
|
+ grub_free (server); |
|
+ |
|
+ grub_free (protocol); |
|
+ grub_free (file); |
|
+} |
|
+ |
|
+static void |
|
+pxe_get_boot_location (const struct grub_net_bootp_packet *bp, |
|
+ char **device, |
|
+ char **path, |
|
+ int is_default) |
|
+{ |
|
+ char *server = grub_xasprintf ("%d.%d.%d.%d", |
|
+ ((grub_uint8_t *) &bp->server_ip)[0], |
|
+ ((grub_uint8_t *) &bp->server_ip)[1], |
|
+ ((grub_uint8_t *) &bp->server_ip)[2], |
|
+ ((grub_uint8_t *) &bp->server_ip)[3]); |
|
+ |
|
+ *device = grub_xasprintf ("tftp,%s", server); |
|
+ |
|
+ *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); |
|
+ |
|
+ if (*path) |
|
+ { |
|
+ char *slash; |
|
+ slash = grub_strrchr (*path, '/'); |
|
+ if (slash) |
|
+ *slash = 0; |
|
+ else |
|
+ **path = 0; |
|
+ } |
|
+ |
|
+ if (is_default) |
|
+ default_server = server; |
|
+ else |
|
+ grub_free (server); |
|
+} |
|
+ |
|
+static void |
|
+pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp, |
|
+ grub_size_t dhcp_size, |
|
+ char **device, |
|
+ char **path) |
|
+{ |
|
+ |
|
+ struct grub_net_dhcp6_option *dhcp_opt; |
|
+ grub_size_t dhcp_remain_size; |
|
+ *device = *path = 0; |
|
+ |
|
+ if (dhcp_size < sizeof (*dp)) |
|
+ { |
|
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); |
|
+ return; |
|
+ } |
|
+ |
|
+ dhcp_remain_size = dhcp_size - sizeof (*dp); |
|
+ dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options; |
|
+ |
|
+ while (dhcp_remain_size) |
|
+ { |
|
+ grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code); |
|
+ grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len); |
|
+ grub_uint16_t option_size = sizeof (*dhcp_opt) + len; |
|
+ |
|
+ if (dhcp_remain_size < option_size || code == 0) |
|
+ break; |
|
+ |
|
+ if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL) |
|
+ { |
|
+ char *url = grub_malloc (len + 1); |
|
+ |
|
+ grub_memcpy (url, dhcp_opt->data, len); |
|
+ url[len] = 0; |
|
+ |
|
+ url_get_boot_location ((const char *)url, device, path, 1); |
|
+ grub_free (url); |
|
+ break; |
|
+ } |
|
+ |
|
+ dhcp_remain_size -= option_size; |
|
+ dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size); |
|
+ } |
|
+} |
|
+ |
|
+static grub_efi_net_interface_t * |
|
+grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp, |
|
+ struct grub_efi_net_device *netdev, |
|
+ char **device, |
|
+ char **path) |
|
+{ |
|
+ grub_efi_net_interface_t *inf = NULL; |
|
+ |
|
+ while (1) |
|
+ { |
|
+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); |
|
+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); |
|
+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); |
|
+ |
|
+ if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) |
|
+ { |
|
+ if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) |
|
+ { |
|
+ grub_efi_uri_device_path_t *uri_dp; |
|
+ uri_dp = (grub_efi_uri_device_path_t *) dp; |
|
+ /* Beware that uri_dp->uri may not be null terminated */ |
|
+ url_get_boot_location ((const char *)uri_dp->uri, device, path, 1); |
|
+ } |
|
+ else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) |
|
+ { |
|
+ grub_efi_net_ip_manual_address_t net_ip; |
|
+ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp; |
|
+ |
|
+ if (inf) |
|
+ continue; |
|
+ grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address)); |
|
+ grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask)); |
|
+ net_ip.is_ip6 = 0; |
|
+ inf = grub_efi_net_create_interface (netdev, |
|
+ netdev->card_name, |
|
+ &net_ip, |
|
+ 1); |
|
+ } |
|
+ else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) |
|
+ { |
|
+ grub_efi_net_ip_manual_address_t net_ip; |
|
+ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp; |
|
+ |
|
+ if (inf) |
|
+ continue; |
|
+ grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address)); |
|
+ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; |
|
+ net_ip.ip6.is_anycast = 0; |
|
+ net_ip.is_ip6 = 1; |
|
+ inf = grub_efi_net_create_interface (netdev, |
|
+ netdev->card_name, |
|
+ &net_ip, |
|
+ 1); |
|
+ } |
|
+ } |
|
+ |
|
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) |
|
+ break; |
|
+ dp = (grub_efi_device_path_t *) ((char *) dp + len); |
|
+ } |
|
+ |
|
+ return inf; |
|
+} |
|
+ |
|
+static grub_efi_net_interface_t * |
|
+grub_efi_net_config_from_handle (grub_efi_handle_t *hnd, |
|
+ struct grub_efi_net_device *netdev, |
|
+ char **device, |
|
+ char **path) |
|
+{ |
|
+ grub_efi_pxe_t *pxe = NULL; |
|
+ |
|
+ if (hnd == netdev->ip4_pxe_handle) |
|
+ pxe = netdev->ip4_pxe; |
|
+ else if (hnd == netdev->ip6_pxe_handle) |
|
+ pxe = netdev->ip6_pxe; |
|
+ |
|
+ if (!pxe) |
|
+ return (grub_efi_net_config_from_device_path ( |
|
+ grub_efi_get_device_path (hnd), |
|
+ netdev, |
|
+ device, |
|
+ path)); |
|
+ |
|
+ if (pxe->mode->using_ipv6) |
|
+ { |
|
+ grub_efi_net_ip_manual_address_t net_ip; |
|
+ |
|
+ pxe_get_boot_location_v6 ( |
|
+ (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack, |
|
+ sizeof (pxe->mode->dhcp_ack), |
|
+ device, |
|
+ path); |
|
+ |
|
+ grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address)); |
|
+ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; |
|
+ net_ip.ip6.is_anycast = 0; |
|
+ net_ip.is_ip6 = 1; |
|
+ return (grub_efi_net_create_interface (netdev, |
|
+ netdev->card_name, |
|
+ &net_ip, |
|
+ 1)); |
|
+ } |
|
+ else |
|
+ { |
|
+ grub_efi_net_ip_manual_address_t net_ip; |
|
+ |
|
+ pxe_get_boot_location ( |
|
+ (const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack, |
|
+ device, |
|
+ path, |
|
+ 1); |
|
+ |
|
+ grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address)); |
|
+ grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask)); |
|
+ net_ip.is_ip6 = 0; |
|
+ return (grub_efi_net_create_interface (netdev, |
|
+ netdev->card_name, |
|
+ &net_ip, |
|
+ 1)); |
|
+ } |
|
+} |
|
+ |
|
+static const char * |
|
+grub_efi_net_var_get_address (struct grub_env_var *var, |
|
+ const char *val __attribute__ ((unused))) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ { |
|
+ grub_efi_net_interface_t *inf; |
|
+ |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ { |
|
+ char *var_name; |
|
+ |
|
+ var_name = grub_xasprintf ("net_%s_ip", inf->name); |
|
+ if (grub_strcmp (var_name, var->name) == 0) |
|
+ return efi_net_interface_get_address (inf); |
|
+ grub_free (var_name); |
|
+ var_name = grub_xasprintf ("net_%s_mac", inf->name); |
|
+ if (grub_strcmp (var_name, var->name) == 0) |
|
+ return efi_net_interface_get_hw_address (inf); |
|
+ grub_free (var_name); |
|
+ } |
|
+ } |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+static char * |
|
+grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)), |
|
+ const char *val) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ grub_efi_net_interface_t *inf; |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ if (grub_strcmp (inf->name, val) == 0) |
|
+ { |
|
+ net_default_interface = inf; |
|
+ return grub_strdup (val); |
|
+ } |
|
+ |
|
+ return NULL; |
|
+} |
|
+ |
|
+static char * |
|
+grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)), |
|
+ const char *val) |
|
+{ |
|
+ grub_free (default_server); |
|
+ default_server = grub_strdup (val); |
|
+ return grub_strdup (val); |
|
+} |
|
+ |
|
+static const char * |
|
+grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)), |
|
+ const char *val __attribute__ ((unused))) |
|
+{ |
|
+ return default_server ? : ""; |
|
+} |
|
+ |
|
+static const char * |
|
+grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)), |
|
+ const char *val __attribute__ ((unused))) |
|
+{ |
|
+ const char *intf = grub_env_get ("net_default_interface"); |
|
+ const char *ret = NULL; |
|
+ if (intf) |
|
+ { |
|
+ char *buf = grub_xasprintf ("net_%s_ip", intf); |
|
+ if (buf) |
|
+ ret = grub_env_get (buf); |
|
+ grub_free (buf); |
|
+ } |
|
+ return ret; |
|
+} |
|
+ |
|
+static const char * |
|
+grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)), |
|
+ const char *val __attribute__ ((unused))) |
|
+{ |
|
+ const char *intf = grub_env_get ("net_default_interface"); |
|
+ const char *ret = NULL; |
|
+ if (intf) |
|
+ { |
|
+ char *buf = grub_xasprintf ("net_%s_mac", intf); |
|
+ if (buf) |
|
+ ret = grub_env_get (buf); |
|
+ grub_free (buf); |
|
+ } |
|
+ return ret; |
|
+} |
|
+ |
|
+static void |
|
+grub_efi_net_export_interface_vars (void) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ { |
|
+ grub_efi_net_interface_t *inf; |
|
+ |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ { |
|
+ char *var; |
|
+ |
|
+ var = grub_xasprintf ("net_%s_ip", inf->name); |
|
+ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); |
|
+ grub_env_export (var); |
|
+ grub_free (var); |
|
+ var = grub_xasprintf ("net_%s_mac", inf->name); |
|
+ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); |
|
+ grub_env_export (var); |
|
+ grub_free (var); |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+grub_efi_net_unset_interface_vars (void) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ { |
|
+ grub_efi_net_interface_t *inf; |
|
+ |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ { |
|
+ char *var; |
|
+ |
|
+ var = grub_xasprintf ("net_%s_ip", inf->name); |
|
+ grub_register_variable_hook (var, 0, 0); |
|
+ grub_env_unset (var); |
|
+ grub_free (var); |
|
+ var = grub_xasprintf ("net_%s_mac", inf->name); |
|
+ grub_register_variable_hook (var, 0, 0); |
|
+ grub_env_unset (var); |
|
+ grub_free (var); |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+grub_efi_net_interface_t * |
|
+grub_efi_net_create_interface (struct grub_efi_net_device *dev, |
|
+ const char *interface_name, |
|
+ grub_efi_net_ip_manual_address_t *net_ip, |
|
+ int has_subnet) |
|
+{ |
|
+ grub_efi_net_interface_t *inf; |
|
+ |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ { |
|
+ if (inf->prefer_ip6 == net_ip->is_ip6) |
|
+ break; |
|
+ } |
|
+ |
|
+ if (!inf) |
|
+ { |
|
+ inf = grub_malloc (sizeof(*inf)); |
|
+ inf->name = grub_strdup (interface_name); |
|
+ inf->prefer_ip6 = net_ip->is_ip6; |
|
+ inf->dev = dev; |
|
+ inf->next = dev->net_interfaces; |
|
+ inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ; |
|
+ dev->net_interfaces = inf; |
|
+ } |
|
+ else |
|
+ { |
|
+ grub_free (inf->name); |
|
+ inf->name = grub_strdup (interface_name); |
|
+ } |
|
+ |
|
+ if (!efi_net_interface_set_address (inf, net_ip, has_subnet)) |
|
+ { |
|
+ grub_error (GRUB_ERR_BUG, N_("Set Address Failed")); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return inf; |
|
+} |
|
+ |
|
+static void |
|
+grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, |
|
+ char **path) |
|
+{ |
|
+ grub_efi_handle_t config_hnd; |
|
+ |
|
+ struct grub_efi_net_device *netdev; |
|
+ grub_efi_net_interface_t *inf; |
|
+ |
|
+ config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL); |
|
+ |
|
+ if (!config_hnd) |
|
+ return; |
|
+ |
|
+ for (netdev = net_devices; netdev; netdev = netdev->next) |
|
+ if (netdev->handle == config_hnd) |
|
+ break; |
|
+ |
|
+ if (!netdev) |
|
+ return; |
|
+ |
|
+ if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path))) |
|
+ return; |
|
+ |
|
+ grub_env_set ("net_default_interface", inf->name); |
|
+ grub_efi_net_export_interface_vars (); |
|
+} |
|
+ |
|
+static grub_err_t |
|
+grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)), |
|
+ grub_fs_dir_hook_t hook __attribute__ ((unused)), |
|
+ void *hook_data __attribute__ ((unused))) |
|
+{ |
|
+ if (!device->net) |
|
+ return grub_error (GRUB_ERR_BUG, "invalid net device"); |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_err_t |
|
+grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)), |
|
+ const char *name __attribute__ ((unused))) |
|
+{ |
|
+ struct grub_file *file, *bufio; |
|
+ |
|
+ file = grub_malloc (sizeof (*file)); |
|
+ if (!file) |
|
+ return grub_errno; |
|
+ |
|
+ grub_memcpy (file, file_out, sizeof (struct grub_file)); |
|
+ file->device->net->name = grub_strdup (name); |
|
+ |
|
+ if (!file->device->net->name) |
|
+ { |
|
+ grub_free (file); |
|
+ return grub_errno; |
|
+ } |
|
+ |
|
+ efi_net_interface(open, file, name); |
|
+ grub_print_error (); |
|
+ |
|
+ bufio = grub_bufio_open (file, 32768); |
|
+ if (!bufio) |
|
+ { |
|
+ grub_free (file->device->net->name); |
|
+ grub_free (file); |
|
+ return grub_errno; |
|
+ } |
|
+ grub_memcpy (file_out, bufio, sizeof (struct grub_file)); |
|
+ grub_free (bufio); |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_ssize_t |
|
+grub_efihttp_chunk_read (grub_file_t file, char *buf, |
|
+ grub_size_t len, grub_size_t chunk_size) |
|
+{ |
|
+ char *chunk = grub_malloc (chunk_size); |
|
+ grub_size_t sum = 0; |
|
+ |
|
+ while (len) |
|
+ { |
|
+ grub_ssize_t rd; |
|
+ grub_size_t sz = (len > chunk_size) ? chunk_size : len; |
|
+ |
|
+ rd = efi_net_interface (read, file, chunk, sz); |
|
+ |
|
+ if (rd <= 0) |
|
+ return rd; |
|
+ |
|
+ if (buf) |
|
+ { |
|
+ grub_memcpy (buf, chunk, rd); |
|
+ buf += rd; |
|
+ } |
|
+ sum += rd; |
|
+ len -= rd; |
|
+ } |
|
+ |
|
+ grub_free (chunk); |
|
+ return sum; |
|
+} |
|
+ |
|
+static grub_ssize_t |
|
+grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)), |
|
+ char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) |
|
+{ |
|
+ if (file->offset > file->device->net->offset) |
|
+ { |
|
+ grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240); |
|
+ } |
|
+ else if (file->offset < file->device->net->offset) |
|
+ { |
|
+ efi_net_interface (close, file); |
|
+ efi_net_interface (open, file, file->device->net->name); |
|
+ if (file->offset) |
|
+ grub_efihttp_chunk_read (file, NULL, file->offset, 10240); |
|
+ } |
|
+ |
|
+ return efi_net_interface (read, file, buf, len); |
|
+} |
|
+ |
|
+static grub_err_t |
|
+grub_efi_netfs_close (grub_file_t file) |
|
+{ |
|
+ efi_net_interface (close, file); |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_efi_handle_t |
|
+grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid) |
|
+{ |
|
+ grub_efi_service_binding_t *service; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_handle_t child_dev = NULL; |
|
+ |
|
+ service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); |
|
+ if (!service) |
|
+ { |
|
+ grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol")); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ status = efi_call_2 (service->create_child, service, &child_dev); |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), status); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return child_dev; |
|
+} |
|
+ |
|
+static grub_err_t |
|
+grub_efi_net_parse_address (const char *address, |
|
+ grub_efi_ip4_config2_manual_address_t *ip4, |
|
+ grub_efi_ip6_config_manual_address_t *ip6, |
|
+ int *is_ip6, |
|
+ int *has_cidr) |
|
+{ |
|
+ const char *rest; |
|
+ |
|
+ if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest)) |
|
+ { |
|
+ *is_ip6 = 0; |
|
+ if (*rest == '/') |
|
+ { |
|
+ grub_uint32_t subnet_mask_size; |
|
+ |
|
+ subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0); |
|
+ |
|
+ if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) |
|
+ { |
|
+ grub_uint32_t subnet_mask; |
|
+ |
|
+ subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size))); |
|
+ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); |
|
+ if (has_cidr) |
|
+ *has_cidr = 1; |
|
+ return GRUB_ERR_NONE; |
|
+ } |
|
+ } |
|
+ else if (*rest == 0) |
|
+ { |
|
+ grub_uint32_t subnet_mask = 0xffffffffU; |
|
+ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); |
|
+ if (has_cidr) |
|
+ *has_cidr = 0; |
|
+ return GRUB_ERR_NONE; |
|
+ } |
|
+ } |
|
+ else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest)) |
|
+ { |
|
+ *is_ip6 = 1; |
|
+ if (*rest == '/') |
|
+ { |
|
+ grub_efi_uint8_t prefix_length; |
|
+ |
|
+ prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0); |
|
+ if (!grub_errno && prefix_length <= 128 && *rest == 0) |
|
+ { |
|
+ ip6->prefix_length = prefix_length; |
|
+ ip6->is_anycast = 0; |
|
+ if (has_cidr) |
|
+ *has_cidr = 1; |
|
+ return GRUB_ERR_NONE; |
|
+ } |
|
+ } |
|
+ else if (*rest == 0) |
|
+ { |
|
+ ip6->prefix_length = 128; |
|
+ ip6->is_anycast = 0; |
|
+ if (has_cidr) |
|
+ *has_cidr = 0; |
|
+ return GRUB_ERR_NONE; |
|
+ } |
|
+ } |
|
+ |
|
+ return grub_error (GRUB_ERR_NET_BAD_ADDRESS, |
|
+ N_("unrecognised network address `%s'"), |
|
+ address); |
|
+} |
|
+ |
|
+static grub_efi_net_interface_t * |
|
+match_route (const char *server) |
|
+{ |
|
+ grub_err_t err; |
|
+ grub_efi_ip4_config2_manual_address_t ip4; |
|
+ grub_efi_ip6_config_manual_address_t ip6; |
|
+ grub_efi_net_interface_t *inf; |
|
+ int is_ip6 = 0; |
|
+ |
|
+ err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); |
|
+ |
|
+ if (err) |
|
+ { |
|
+ grub_print_error (); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ if (is_ip6) |
|
+ { |
|
+ struct grub_efi_net_device *dev; |
|
+ grub_efi_net_ip_address_t addr; |
|
+ |
|
+ grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address)); |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ if ((inf = efi_net_ip6_config->best_interface (dev, &addr))) |
|
+ return inf; |
|
+ } |
|
+ else |
|
+ { |
|
+ struct grub_efi_net_device *dev; |
|
+ grub_efi_net_ip_address_t addr; |
|
+ |
|
+ grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address)); |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ if ((inf = efi_net_ip4_config->best_interface (dev, &addr))) |
|
+ return inf; |
|
+ } |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+static void |
|
+grub_efi_net_add_pxebc_to_cards (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, &pxe_io_guid, |
|
+ 0, &num_handles); |
|
+ if (!handles) |
|
+ return; |
|
+ |
|
+ for (handle = handles; num_handles--; handle++) |
|
+ { |
|
+ grub_efi_device_path_t *dp, *ddp, *ldp; |
|
+ grub_efi_pxe_t *pxe; |
|
+ struct grub_efi_net_device *d; |
|
+ int is_ip6 = 0; |
|
+ |
|
+ dp = grub_efi_get_device_path (*handle); |
|
+ if (!dp) |
|
+ continue; |
|
+ |
|
+ ddp = grub_efi_duplicate_device_path (dp); |
|
+ ldp = grub_efi_find_last_device_path (ddp); |
|
+ |
|
+ if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE |
|
+ && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) |
|
+ { |
|
+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; |
|
+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; |
|
+ ldp->length = sizeof (*ldp); |
|
+ } |
|
+ else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE |
|
+ && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) |
|
+ { |
|
+ is_ip6 = 1; |
|
+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; |
|
+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; |
|
+ ldp->length = sizeof (*ldp); |
|
+ } |
|
+ |
|
+ for (d = net_devices; d; d = d->next) |
|
+ if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0) |
|
+ break; |
|
+ |
|
+ if (!d) |
|
+ { |
|
+ grub_free (ddp); |
|
+ continue; |
|
+ } |
|
+ |
|
+ pxe = grub_efi_open_protocol (*handle, &pxe_io_guid, |
|
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); |
|
+ |
|
+ if (!pxe) |
|
+ { |
|
+ grub_free (ddp); |
|
+ continue; |
|
+ } |
|
+ |
|
+ if (is_ip6) |
|
+ { |
|
+ d->ip6_pxe_handle = *handle; |
|
+ d->ip6_pxe = pxe; |
|
+ } |
|
+ else |
|
+ { |
|
+ d->ip4_pxe_handle = *handle; |
|
+ d->ip4_pxe = pxe; |
|
+ } |
|
+ |
|
+ grub_free (ddp); |
|
+ } |
|
+ |
|
+ grub_free (handles); |
|
+} |
|
+ |
|
+static void |
|
+set_ip_policy_to_static (void) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ { |
|
+ grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC; |
|
+ |
|
+ if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, |
|
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, |
|
+ sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS) |
|
+ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name); |
|
+ |
|
+ if (dev->ip6_config) |
|
+ { |
|
+ grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL; |
|
+ |
|
+ if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, |
|
+ sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS) |
|
+ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name); |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */ |
|
+static void |
|
+grub_efi_net_find_cards (void) |
|
+{ |
|
+ grub_efi_uintn_t num_handles; |
|
+ grub_efi_handle_t *handles; |
|
+ grub_efi_handle_t *handle; |
|
+ int id; |
|
+ |
|
+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid, |
|
+ 0, &num_handles); |
|
+ if (!handles) |
|
+ return; |
|
+ |
|
+ for (id = 0, handle = handles; num_handles--; handle++, id++) |
|
+ { |
|
+ grub_efi_device_path_t *dp; |
|
+ grub_efi_ip4_config2_protocol_t *ip4_config; |
|
+ grub_efi_ip6_config_protocol_t *ip6_config; |
|
+ grub_efi_handle_t http_handle; |
|
+ grub_efi_http_t *http; |
|
+ grub_efi_handle_t dhcp4_handle; |
|
+ grub_efi_dhcp4_protocol_t *dhcp4; |
|
+ grub_efi_handle_t dhcp6_handle; |
|
+ grub_efi_dhcp6_protocol_t *dhcp6; |
|
+ |
|
+ struct grub_efi_net_device *d; |
|
+ |
|
+ dp = grub_efi_get_device_path (*handle); |
|
+ if (!dp) |
|
+ continue; |
|
+ |
|
+ ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid, |
|
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); |
|
+ if (!ip4_config) |
|
+ continue; |
|
+ |
|
+ ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid, |
|
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); |
|
+ |
|
+ http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid); |
|
+ grub_errno = GRUB_ERR_NONE; |
|
+ http = (http_handle) |
|
+ ? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) |
|
+ : NULL; |
|
+ |
|
+ dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid); |
|
+ grub_errno = GRUB_ERR_NONE; |
|
+ dhcp4 = (dhcp4_handle) |
|
+ ? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) |
|
+ : NULL; |
|
+ |
|
+ |
|
+ dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid); |
|
+ grub_errno = GRUB_ERR_NONE; |
|
+ dhcp6 = (dhcp6_handle) |
|
+ ? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) |
|
+ : NULL; |
|
+ |
|
+ d = grub_malloc (sizeof (*d)); |
|
+ if (!d) |
|
+ { |
|
+ grub_free (handles); |
|
+ while (net_devices) |
|
+ { |
|
+ d = net_devices->next; |
|
+ grub_free (net_devices); |
|
+ net_devices = d; |
|
+ } |
|
+ return; |
|
+ } |
|
+ d->handle = *handle; |
|
+ d->ip4_config = ip4_config; |
|
+ d->ip6_config = ip6_config; |
|
+ d->http_handle = http_handle; |
|
+ d->http = http; |
|
+ d->dhcp4_handle = dhcp4_handle; |
|
+ d->dhcp4 = dhcp4; |
|
+ d->dhcp6_handle = dhcp6_handle; |
|
+ d->dhcp6 = dhcp6; |
|
+ d->next = net_devices; |
|
+ d->card_name = grub_xasprintf ("efinet%d", id); |
|
+ d->net_interfaces = NULL; |
|
+ net_devices = d; |
|
+ } |
|
+ |
|
+ grub_efi_net_add_pxebc_to_cards (); |
|
+ grub_free (handles); |
|
+ set_ip_policy_to_static (); |
|
+} |
|
+ |
|
+static void |
|
+listroutes_ip4 (struct grub_efi_net_device *netdev) |
|
+{ |
|
+ char **routes; |
|
+ |
|
+ routes = NULL; |
|
+ |
|
+ if ((routes = efi_net_ip4_config->get_route_table (netdev))) |
|
+ { |
|
+ char **r; |
|
+ |
|
+ for (r = routes; *r; ++r) |
|
+ grub_printf ("%s\n", *r); |
|
+ } |
|
+ |
|
+ if (routes) |
|
+ { |
|
+ char **r; |
|
+ |
|
+ for (r = routes; *r; ++r) |
|
+ grub_free (*r); |
|
+ grub_free (routes); |
|
+ } |
|
+} |
|
+ |
|
+static void |
|
+listroutes_ip6 (struct grub_efi_net_device *netdev) |
|
+{ |
|
+ char **routes; |
|
+ |
|
+ routes = NULL; |
|
+ |
|
+ if ((routes = efi_net_ip6_config->get_route_table (netdev))) |
|
+ { |
|
+ char **r; |
|
+ |
|
+ for (r = routes; *r; ++r) |
|
+ grub_printf ("%s\n", *r); |
|
+ } |
|
+ |
|
+ if (routes) |
|
+ { |
|
+ char **r; |
|
+ |
|
+ for (r = routes; *r; ++r) |
|
+ grub_free (*r); |
|
+ grub_free (routes); |
|
+ } |
|
+} |
|
+ |
|
+static grub_err_t |
|
+grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)), |
|
+ int argc __attribute__ ((unused)), |
|
+ char **args __attribute__ ((unused))) |
|
+{ |
|
+ struct grub_efi_net_device *netdev; |
|
+ |
|
+ for (netdev = net_devices; netdev; netdev = netdev->next) |
|
+ { |
|
+ listroutes_ip4 (netdev); |
|
+ listroutes_ip6 (netdev); |
|
+ } |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+static grub_err_t |
|
+grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)), |
|
+ int argc __attribute__ ((unused)), |
|
+ char **args __attribute__ ((unused))) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ { |
|
+ char *hw_addr; |
|
+ |
|
+ hw_addr = efi_net_ip4_config->get_hw_address (dev); |
|
+ |
|
+ if (hw_addr) |
|
+ { |
|
+ grub_printf ("%s %s\n", dev->card_name, hw_addr); |
|
+ grub_free (hw_addr); |
|
+ } |
|
+ } |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_err_t |
|
+grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)), |
|
+ int argc __attribute__ ((unused)), |
|
+ char **args __attribute__ ((unused))) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ grub_efi_net_interface_t *inf; |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ for (inf = dev->net_interfaces; inf; inf = inf->next) |
|
+ { |
|
+ char *hw_addr = NULL; |
|
+ char *addr = NULL; |
|
+ |
|
+ if ((hw_addr = efi_net_interface_get_hw_address (inf)) |
|
+ && (addr = efi_net_interface_get_address (inf))) |
|
+ grub_printf ("%s %s %s\n", inf->name, hw_addr, addr); |
|
+ |
|
+ if (hw_addr) |
|
+ grub_free (hw_addr); |
|
+ if (addr) |
|
+ grub_free (addr); |
|
+ } |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+/* FIXME: support MAC specifying. */ |
|
+static grub_err_t |
|
+grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)), |
|
+ int argc, char **args) |
|
+{ |
|
+ struct grub_efi_net_device *dev; |
|
+ grub_err_t err; |
|
+ grub_efi_ip4_config2_manual_address_t ip4; |
|
+ grub_efi_ip6_config_manual_address_t ip6; |
|
+ grub_efi_net_ip_manual_address_t net_ip; |
|
+ int is_ip6 = 0; |
|
+ int cidr = 0; |
|
+ |
|
+ if (argc != 3) |
|
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); |
|
+ |
|
+ for (dev = net_devices; dev; dev = dev->next) |
|
+ { |
|
+ if (grub_strcmp (dev->card_name, args[1]) == 0) |
|
+ break; |
|
+ } |
|
+ |
|
+ if (!dev) |
|
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); |
|
+ |
|
+ err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr); |
|
+ |
|
+ if (err) |
|
+ return err; |
|
+ |
|
+ net_ip.is_ip6 = is_ip6; |
|
+ if (is_ip6) |
|
+ grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6)); |
|
+ else |
|
+ grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4)); |
|
+ |
|
+ if (!grub_efi_net_create_interface (dev, |
|
+ args[0], |
|
+ &net_ip, |
|
+ cidr)) |
|
+ return grub_errno; |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static struct grub_fs grub_efi_netfs; |
|
+ |
|
+static grub_net_t |
|
+grub_net_open_real (const char *name __attribute__ ((unused))) |
|
+{ |
|
+ grub_size_t protnamelen; |
|
+ const char *protname, *server; |
|
+ grub_net_t ret; |
|
+ |
|
+ net_interface = NULL; |
|
+ |
|
+ if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) |
|
+ { |
|
+ protname = "tftp"; |
|
+ protnamelen = sizeof ("tftp") - 1; |
|
+ server = name + sizeof ("pxe:") - 1; |
|
+ } |
|
+ else if (grub_strcmp (name, "pxe") == 0) |
|
+ { |
|
+ protname = "tftp"; |
|
+ protnamelen = sizeof ("tftp") - 1; |
|
+ server = default_server; |
|
+ } |
|
+ else |
|
+ { |
|
+ const char *comma; |
|
+ |
|
+ comma = grub_strchr (name, ','); |
|
+ if (comma) |
|
+ { |
|
+ protnamelen = comma - name; |
|
+ server = comma + 1; |
|
+ protname = name; |
|
+ } |
|
+ else |
|
+ { |
|
+ protnamelen = grub_strlen (name); |
|
+ server = default_server; |
|
+ protname = name; |
|
+ } |
|
+ } |
|
+ |
|
+ if (!server) |
|
+ { |
|
+ grub_error (GRUB_ERR_NET_BAD_ADDRESS, |
|
+ N_("no server is specified")); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ /*FIXME: Use DNS translate name to address */ |
|
+ net_interface = match_route (server); |
|
+ |
|
+ /*XXX: should we check device with default gateway ? */ |
|
+ if (!net_interface && !(net_interface = net_default_interface)) |
|
+ { |
|
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), |
|
+ name); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ if ((protnamelen == (sizeof ("https") - 1) |
|
+ && grub_memcmp ("https", protname, protnamelen) == 0)) |
|
+ { |
|
+ net_interface->io = &io_http; |
|
+ net_interface->io_type = 1; |
|
+ } |
|
+ else if ((protnamelen == (sizeof ("http") - 1) |
|
+ && grub_memcmp ("http", protname, protnamelen) == 0)) |
|
+ { |
|
+ net_interface->io = &io_http; |
|
+ net_interface->io_type = 0; |
|
+ } |
|
+ else if (protnamelen == (sizeof ("tftp") - 1) |
|
+ && grub_memcmp ("tftp", protname, protnamelen) == 0) |
|
+ { |
|
+ net_interface->io = &io_pxe; |
|
+ net_interface->io_type = 0; |
|
+ } |
|
+ else |
|
+ { |
|
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), |
|
+ name); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */ |
|
+ efi_net_interface (configure); |
|
+ |
|
+ ret = grub_zalloc (sizeof (*ret)); |
|
+ if (!ret) |
|
+ return NULL; |
|
+ |
|
+ ret->server = grub_strdup (server); |
|
+ if (!ret->server) |
|
+ { |
|
+ grub_free (ret); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ ret->fs = &grub_efi_netfs; |
|
+ return ret; |
|
+} |
|
+#if 0 |
|
+static grub_command_t cmd_efi_lsaddr; |
|
+static grub_command_t cmd_efi_lscards; |
|
+static grub_command_t cmd_efi_lsroutes; |
|
+static grub_command_t cmd_efi_addaddr; |
|
+#endif |
|
+ |
|
+static struct grub_fs grub_efi_netfs = |
|
+ { |
|
+ .name = "efi netfs", |
|
+ .fs_dir = grub_efi_netfs_dir, |
|
+ .fs_open = grub_efi_netfs_open, |
|
+ .fs_read = grub_efi_netfs_read, |
|
+ .fs_close = grub_efi_netfs_close, |
|
+ .fs_label = NULL, |
|
+ .fs_uuid = NULL, |
|
+ .fs_mtime = NULL, |
|
+ }; |
|
+ |
|
+int |
|
+grub_efi_net_boot_from_https (void) |
|
+{ |
|
+ grub_efi_loaded_image_t *image = NULL; |
|
+ grub_efi_device_path_t *dp; |
|
+ |
|
+ image = grub_efi_get_loaded_image (grub_efi_image_handle); |
|
+ if (!image) |
|
+ return 0; |
|
+ |
|
+ dp = grub_efi_get_device_path (image->device_handle); |
|
+ |
|
+ while (1) |
|
+ { |
|
+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); |
|
+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); |
|
+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); |
|
+ |
|
+ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) |
|
+ && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) |
|
+ { |
|
+ grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; |
|
+ return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0; |
|
+ } |
|
+ |
|
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) |
|
+ break; |
|
+ dp = (grub_efi_device_path_t *) ((char *) dp + len); |
|
+ } |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+int |
|
+grub_efi_net_boot_from_opa (void) |
|
+{ |
|
+ grub_efi_loaded_image_t *image = NULL; |
|
+ grub_efi_device_path_t *dp; |
|
+ |
|
+ image = grub_efi_get_loaded_image (grub_efi_image_handle); |
|
+ if (!image) |
|
+ return 0; |
|
+ |
|
+ dp = grub_efi_get_device_path (image->device_handle); |
|
+ |
|
+ while (1) |
|
+ { |
|
+ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); |
|
+ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); |
|
+ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); |
|
+ |
|
+ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) |
|
+ && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)) |
|
+ { |
|
+ grub_efi_mac_address_device_path_t *mac_dp = (grub_efi_mac_address_device_path_t *)dp; |
|
+ return (mac_dp->if_type == 0xC7) ? 1 : 0; |
|
+ } |
|
+ |
|
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) |
|
+ break; |
|
+ dp = (grub_efi_device_path_t *) ((char *) dp + len); |
|
+ } |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+static char * |
|
+grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), |
|
+ const char *val __attribute__ ((unused))) |
|
+{ |
|
+ return NULL; |
|
+} |
|
+ |
|
+grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes; |
|
+grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards; |
|
+grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs; |
|
+grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr; |
|
+ |
|
+int |
|
+grub_efi_net_fs_init () |
|
+{ |
|
+ grub_efi_net_find_cards (); |
|
+ grub_efi_net_config = grub_efi_net_config_real; |
|
+ grub_net_open = grub_net_open_real; |
|
+ grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server, |
|
+ grub_efi_net_var_set_server); |
|
+ grub_env_export ("net_default_server"); |
|
+ grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server, |
|
+ grub_efi_net_var_set_server); |
|
+ grub_env_export ("pxe_default_server"); |
|
+ grub_register_variable_hook ("net_default_interface", 0, |
|
+ grub_efi_net_var_set_interface); |
|
+ grub_env_export ("net_default_interface"); |
|
+ grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip, |
|
+ 0); |
|
+ grub_env_export ("net_default_ip"); |
|
+ grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac, |
|
+ 0); |
|
+ grub_env_export ("net_default_mac"); |
|
+ |
|
+ grub_env_set ("grub_netfs_type", "efi"); |
|
+ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); |
|
+ grub_env_export ("grub_netfs_type"); |
|
+ |
|
+ return 1; |
|
+} |
|
+ |
|
+void |
|
+grub_efi_net_fs_fini (void) |
|
+{ |
|
+ grub_env_unset ("grub_netfs_type"); |
|
+ grub_efi_net_unset_interface_vars (); |
|
+ grub_register_variable_hook ("net_default_server", 0, 0); |
|
+ grub_env_unset ("net_default_server"); |
|
+ grub_register_variable_hook ("net_default_interface", 0, 0); |
|
+ grub_env_unset ("net_default_interface"); |
|
+ grub_register_variable_hook ("pxe_default_server", 0, 0); |
|
+ grub_env_unset ("pxe_default_server"); |
|
+ grub_register_variable_hook ("net_default_ip", 0, 0); |
|
+ grub_env_unset ("net_default_ip"); |
|
+ grub_register_variable_hook ("net_default_mac", 0, 0); |
|
+ grub_env_unset ("net_default_mac"); |
|
+ grub_efi_net_config = NULL; |
|
+ grub_net_open = NULL; |
|
+ grub_fs_unregister (&grub_efi_netfs); |
|
+} |
|
diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c |
|
new file mode 100644 |
|
index 00000000000..531949cba5c |
|
--- /dev/null |
|
+++ b/grub-core/net/efi/pxe.c |
|
@@ -0,0 +1,424 @@ |
|
+ |
|
+#include <grub/efi/api.h> |
|
+#include <grub/efi/efi.h> |
|
+#include <grub/misc.h> |
|
+#include <grub/net/efi.h> |
|
+#include <grub/charset.h> |
|
+ |
|
+static grub_efi_ip6_config_manual_address_t * |
|
+efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) |
|
+{ |
|
+ grub_efi_uintn_t sz; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_ip6_config_manual_address_t *manual_address; |
|
+ |
|
+ sz = sizeof (*manual_address); |
|
+ manual_address = grub_malloc (sz); |
|
+ if (!manual_address) |
|
+ return NULL; |
|
+ |
|
+ status = efi_call_4 (ip6_config->get_data, ip6_config, |
|
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, |
|
+ &sz, manual_address); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_free (manual_address); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return manual_address; |
|
+} |
|
+ |
|
+static grub_efi_ip4_config2_manual_address_t * |
|
+efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) |
|
+{ |
|
+ grub_efi_uintn_t sz; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_ip4_config2_manual_address_t *manual_address; |
|
+ |
|
+ sz = sizeof (*manual_address); |
|
+ manual_address = grub_malloc (sz); |
|
+ if (!manual_address) |
|
+ return NULL; |
|
+ |
|
+ status = efi_call_4 (ip4_config->get_data, ip4_config, |
|
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, |
|
+ &sz, manual_address); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ grub_free (manual_address); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return manual_address; |
|
+} |
|
+ |
|
+static void |
|
+pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6) |
|
+{ |
|
+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; |
|
+ |
|
+ grub_efi_pxe_mode_t *mode = pxe->mode; |
|
+ |
|
+ if (!mode->started) |
|
+ { |
|
+ grub_efi_status_t status; |
|
+ status = efi_call_2 (pxe->start, pxe, prefer_ip6); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ grub_printf ("Couldn't start PXE\n"); |
|
+ } |
|
+ |
|
+#if 0 |
|
+ grub_printf ("PXE STARTED: %u\n", mode->started); |
|
+ grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6); |
|
+#endif |
|
+ |
|
+ if (mode->using_ipv6) |
|
+ { |
|
+ grub_efi_ip6_config_manual_address_t *manual_address; |
|
+ manual_address = efi_ip6_config_manual_address (dev->ip6_config); |
|
+ |
|
+ if (manual_address && |
|
+ grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0) |
|
+ { |
|
+ grub_efi_status_t status; |
|
+ grub_efi_pxe_ip_address_t station_ip; |
|
+ |
|
+ grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr)); |
|
+ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ grub_printf ("Couldn't set station ip\n"); |
|
+ |
|
+ grub_free (manual_address); |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ grub_efi_ip4_config2_manual_address_t *manual_address; |
|
+ manual_address = efi_ip4_config_manual_address (dev->ip4_config); |
|
+ |
|
+ if (manual_address && |
|
+ grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0) |
|
+ { |
|
+ grub_efi_status_t status; |
|
+ grub_efi_pxe_ip_address_t station_ip; |
|
+ grub_efi_pxe_ip_address_t subnet_mask; |
|
+ |
|
+ grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr)); |
|
+ grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr)); |
|
+ |
|
+ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ grub_printf ("Couldn't set station ip\n"); |
|
+ |
|
+ grub_free (manual_address); |
|
+ } |
|
+ } |
|
+ |
|
+#if 0 |
|
+ if (mode->using_ipv6) |
|
+ { |
|
+ grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", |
|
+ mode->station_ip.v6.addr[0], |
|
+ mode->station_ip.v6.addr[1], |
|
+ mode->station_ip.v6.addr[2], |
|
+ mode->station_ip.v6.addr[3], |
|
+ mode->station_ip.v6.addr[4], |
|
+ mode->station_ip.v6.addr[5], |
|
+ mode->station_ip.v6.addr[6], |
|
+ mode->station_ip.v6.addr[7], |
|
+ mode->station_ip.v6.addr[8], |
|
+ mode->station_ip.v6.addr[9], |
|
+ mode->station_ip.v6.addr[10], |
|
+ mode->station_ip.v6.addr[11], |
|
+ mode->station_ip.v6.addr[12], |
|
+ mode->station_ip.v6.addr[13], |
|
+ mode->station_ip.v6.addr[14], |
|
+ mode->station_ip.v6.addr[15]); |
|
+ } |
|
+ else |
|
+ { |
|
+ grub_printf ("PXE STATION IP: %d.%d.%d.%d\n", |
|
+ mode->station_ip.v4.addr[0], |
|
+ mode->station_ip.v4.addr[1], |
|
+ mode->station_ip.v4.addr[2], |
|
+ mode->station_ip.v4.addr[3]); |
|
+ grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n", |
|
+ mode->subnet_mask.v4.addr[0], |
|
+ mode->subnet_mask.v4.addr[1], |
|
+ mode->subnet_mask.v4.addr[2], |
|
+ mode->subnet_mask.v4.addr[3]); |
|
+ } |
|
+#endif |
|
+ |
|
+ /* TODO: Set The Station IP to the IP2 Config */ |
|
+} |
|
+ |
|
+static int |
|
+parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) |
|
+{ |
|
+ grub_uint16_t newip[8]; |
|
+ const char *ptr = val; |
|
+ int word, quaddot = -1; |
|
+ int bracketed = 0; |
|
+ |
|
+ if (ptr[0] == '[') { |
|
+ bracketed = 1; |
|
+ ptr++; |
|
+ } |
|
+ |
|
+ if (ptr[0] == ':' && ptr[1] != ':') |
|
+ return 0; |
|
+ if (ptr[0] == ':') |
|
+ ptr++; |
|
+ |
|
+ for (word = 0; word < 8; word++) |
|
+ { |
|
+ unsigned long t; |
|
+ if (*ptr == ':') |
|
+ { |
|
+ quaddot = word; |
|
+ word--; |
|
+ ptr++; |
|
+ continue; |
|
+ } |
|
+ t = grub_strtoul (ptr, (char **) &ptr, 16); |
|
+ if (grub_errno) |
|
+ { |
|
+ grub_errno = GRUB_ERR_NONE; |
|
+ break; |
|
+ } |
|
+ if (t & ~0xffff) |
|
+ return 0; |
|
+ newip[word] = grub_cpu_to_be16 (t); |
|
+ if (*ptr != ':') |
|
+ break; |
|
+ ptr++; |
|
+ } |
|
+ if (quaddot == -1 && word < 7) |
|
+ return 0; |
|
+ if (quaddot != -1) |
|
+ { |
|
+ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], |
|
+ (word - quaddot + 1) * sizeof (newip[0])); |
|
+ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); |
|
+ } |
|
+ grub_memcpy (ip, newip, 16); |
|
+ if (bracketed && *ptr == ']') { |
|
+ ptr++; |
|
+ } |
|
+ if (rest) |
|
+ *rest = ptr; |
|
+ return 1; |
|
+} |
|
+ |
|
+static grub_err_t |
|
+pxe_open (struct grub_efi_net_device *dev, |
|
+ int prefer_ip6, |
|
+ grub_file_t file, |
|
+ const char *filename, |
|
+ int type __attribute__((unused))) |
|
+{ |
|
+ int i; |
|
+ char *p; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_pxe_ip_address_t server_ip; |
|
+ grub_efi_uint64_t file_size = 0; |
|
+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; |
|
+ |
|
+ if (pxe->mode->using_ipv6) |
|
+ { |
|
+ const char *rest; |
|
+ grub_uint64_t ip6[2]; |
|
+ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) |
|
+ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); |
|
+ /* TODO: ERROR Handling Here */ |
|
+#if 0 |
|
+ grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", |
|
+ server_ip.v6.addr[0], |
|
+ server_ip.v6.addr[1], |
|
+ server_ip.v6.addr[2], |
|
+ server_ip.v6.addr[3], |
|
+ server_ip.v6.addr[4], |
|
+ server_ip.v6.addr[5], |
|
+ server_ip.v6.addr[6], |
|
+ server_ip.v6.addr[7], |
|
+ server_ip.v6.addr[8], |
|
+ server_ip.v6.addr[9], |
|
+ server_ip.v6.addr[10], |
|
+ server_ip.v6.addr[11], |
|
+ server_ip.v6.addr[12], |
|
+ server_ip.v6.addr[13], |
|
+ server_ip.v6.addr[14], |
|
+ server_ip.v6.addr[15]); |
|
+#endif |
|
+ } |
|
+ else |
|
+ { |
|
+ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) |
|
+ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); |
|
+ } |
|
+ |
|
+ status = efi_call_10 (pxe->mtftp, |
|
+ pxe, |
|
+ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, |
|
+ NULL, |
|
+ 0, |
|
+ &file_size, |
|
+ NULL, |
|
+ &server_ip, |
|
+ (grub_efi_char8_t *)filename, |
|
+ NULL, |
|
+ 0); |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ return grub_error (GRUB_ERR_IO, "Couldn't get file size"); |
|
+ |
|
+ file->size = (grub_off_t)file_size; |
|
+ file->not_easily_seekable = 0; |
|
+ file->data = 0; |
|
+ file->device->net->offset = 0; |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_err_t |
|
+pxe_close (struct grub_efi_net_device *dev __attribute__((unused)), |
|
+ int prefer_ip6 __attribute__((unused)), |
|
+ grub_file_t file __attribute__((unused))) |
|
+{ |
|
+ file->offset = 0; |
|
+ file->size = 0; |
|
+ file->device->net->offset = 0; |
|
+ |
|
+ if (file->data) |
|
+ { |
|
+ grub_free (file->data); |
|
+ file->data = NULL; |
|
+ } |
|
+ |
|
+ return GRUB_ERR_NONE; |
|
+} |
|
+ |
|
+static grub_ssize_t |
|
+pxe_read (struct grub_efi_net_device *dev, |
|
+ int prefer_ip6, |
|
+ grub_file_t file, |
|
+ char *buf, |
|
+ grub_size_t len) |
|
+{ |
|
+ int i; |
|
+ char *p; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; |
|
+ grub_efi_uint64_t bufsz = len; |
|
+ grub_efi_pxe_ip_address_t server_ip; |
|
+ char *buf2 = NULL; |
|
+ |
|
+ if (file->data) |
|
+ { |
|
+ /* TODO: RANGE Check for offset and file size */ |
|
+ grub_memcpy (buf, (char*)file->data + file->device->net->offset, len); |
|
+ file->device->net->offset += len; |
|
+ return len; |
|
+ } |
|
+ |
|
+ if (file->device->net->offset) |
|
+ { |
|
+ grub_error (GRUB_ERR_BUG, "No Offet Read Possible"); |
|
+ grub_print_error (); |
|
+ return 0; |
|
+ } |
|
+ |
|
+ if (pxe->mode->using_ipv6) |
|
+ { |
|
+ const char *rest; |
|
+ grub_uint64_t ip6[2]; |
|
+ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) |
|
+ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); |
|
+ /* TODO: ERROR Handling Here */ |
|
+ } |
|
+ else |
|
+ { |
|
+ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) |
|
+ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); |
|
+ } |
|
+ |
|
+ status = efi_call_10 (pxe->mtftp, |
|
+ pxe, |
|
+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, |
|
+ buf, |
|
+ 0, |
|
+ &bufsz, |
|
+ NULL, |
|
+ &server_ip, |
|
+ (grub_efi_char8_t *)file->device->net->name, |
|
+ NULL, |
|
+ 0); |
|
+ |
|
+ if (bufsz != file->size) |
|
+ { |
|
+ grub_error (GRUB_ERR_BUG, "Short read should not happen here"); |
|
+ grub_print_error (); |
|
+ return 0; |
|
+ } |
|
+ |
|
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL) |
|
+ { |
|
+ |
|
+ buf2 = grub_malloc (bufsz); |
|
+ |
|
+ if (!buf2) |
|
+ { |
|
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY"); |
|
+ grub_print_error (); |
|
+ return 0; |
|
+ } |
|
+ |
|
+ status = efi_call_10 (pxe->mtftp, |
|
+ pxe, |
|
+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, |
|
+ buf2, |
|
+ 0, |
|
+ &bufsz, |
|
+ NULL, |
|
+ &server_ip, |
|
+ (grub_efi_char8_t *)file->device->net->name, |
|
+ NULL, |
|
+ 0); |
|
+ } |
|
+ |
|
+ if (status != GRUB_EFI_SUCCESS) |
|
+ { |
|
+ if (buf2) |
|
+ grub_free (buf2); |
|
+ |
|
+ grub_error (GRUB_ERR_IO, "Failed to Read File"); |
|
+ grub_print_error (); |
|
+ return 0; |
|
+ } |
|
+ |
|
+ if (buf2) |
|
+ grub_memcpy (buf, buf2, len); |
|
+ |
|
+ file->device->net->offset = len; |
|
+ |
|
+ if (buf2) |
|
+ file->data = buf2; |
|
+ |
|
+ return len; |
|
+} |
|
+ |
|
+struct grub_efi_net_io io_pxe = |
|
+ { |
|
+ .configure = pxe_configure, |
|
+ .open = pxe_open, |
|
+ .read = pxe_read, |
|
+ .close = pxe_close |
|
+ }; |
|
+ |
|
diff --git a/grub-core/net/net.c b/grub-core/net/net.c |
|
index 0ce5e675ed7..55aed92722c 100644 |
|
--- a/grub-core/net/net.c |
|
+++ b/grub-core/net/net.c |
|
@@ -32,6 +32,9 @@ |
|
#include <grub/loader.h> |
|
#include <grub/bufio.h> |
|
#include <grub/kernel.h> |
|
+#ifdef GRUB_MACHINE_EFI |
|
+#include <grub/net/efi.h> |
|
+#endif |
|
|
|
GRUB_MOD_LICENSE ("GPLv3+"); |
|
|
|
@@ -2033,8 +2036,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; |
|
static grub_command_t cmd_lsroutes, cmd_lscards; |
|
static grub_command_t cmd_lsaddr, cmd_slaac; |
|
|
|
+#ifdef GRUB_MACHINE_EFI |
|
+ |
|
+static enum { |
|
+ INIT_MODE_NONE, |
|
+ INIT_MODE_GRUB, |
|
+ INIT_MODE_EFI |
|
+} init_mode; |
|
+ |
|
+static grub_command_t cmd_bootp, cmd_bootp6; |
|
+ |
|
+#endif |
|
+ |
|
GRUB_MOD_INIT(net) |
|
{ |
|
+#ifdef GRUB_MACHINE_EFI |
|
+ if (grub_net_open) |
|
+ return; |
|
+ |
|
+ if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ()) |
|
+ && grub_efi_net_fs_init ()) |
|
+ { |
|
+ cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes, |
|
+ "", N_("list network routes")); |
|
+ cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards, |
|
+ "", N_("list network cards")); |
|
+ cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs, |
|
+ "", N_("list network addresses")); |
|
+ cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr, |
|
+ /* TRANSLATORS: HWADDRESS stands for |
|
+ "hardware address". */ |
|
+ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), |
|
+ N_("Add a network address.")); |
|
+ cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp, |
|
+ N_("[CARD]"), |
|
+ N_("perform a bootp autoconfiguration")); |
|
+ cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6, |
|
+ N_("[CARD]"), |
|
+ N_("perform a bootp autoconfiguration")); |
|
+ init_mode = INIT_MODE_EFI; |
|
+ return; |
|
+ } |
|
+#endif |
|
+ |
|
grub_register_variable_hook ("net_default_server", defserver_get_env, |
|
defserver_set_env); |
|
grub_env_export ("net_default_server"); |
|
@@ -2082,10 +2126,37 @@ GRUB_MOD_INIT(net) |
|
grub_net_restore_hw, |
|
GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); |
|
grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; |
|
+ |
|
+#ifdef GRUB_MACHINE_EFI |
|
+ grub_env_set ("grub_netfs_type", "grub"); |
|
+ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); |
|
+ grub_env_export ("grub_netfs_type"); |
|
+ init_mode = INIT_MODE_GRUB; |
|
+#endif |
|
+ |
|
} |
|
|
|
GRUB_MOD_FINI(net) |
|
{ |
|
+ |
|
+#ifdef GRUB_MACHINE_EFI |
|
+ if (init_mode == INIT_MODE_NONE) |
|
+ return; |
|
+ |
|
+ if (init_mode == INIT_MODE_EFI) |
|
+ { |
|
+ grub_unregister_command (cmd_lsroutes); |
|
+ grub_unregister_command (cmd_lscards); |
|
+ grub_unregister_command (cmd_lsaddr); |
|
+ grub_unregister_command (cmd_addaddr); |
|
+ grub_unregister_command (cmd_bootp); |
|
+ grub_unregister_command (cmd_bootp6); |
|
+ grub_efi_net_fs_fini (); |
|
+ init_mode = INIT_MODE_NONE; |
|
+ return; |
|
+ } |
|
+#endif |
|
+ |
|
grub_register_variable_hook ("net_default_server", 0, 0); |
|
grub_register_variable_hook ("pxe_default_server", 0, 0); |
|
|
|
@@ -2104,4 +2175,7 @@ GRUB_MOD_FINI(net) |
|
grub_net_fini_hw (0); |
|
grub_loader_unregister_preboot_hook (fini_hnd); |
|
grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; |
|
+#ifdef GRUB_MACHINE_EFI |
|
+ init_mode = INIT_MODE_NONE; |
|
+#endif |
|
} |
|
diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c |
|
index a2461cda1c4..77958dd9dd5 100644 |
|
--- a/util/grub-mknetdir.c |
|
+++ b/util/grub-mknetdir.c |
|
@@ -32,13 +32,15 @@ |
|
|
|
static char *rootdir = NULL, *subdir = NULL; |
|
static char *debug_image = NULL; |
|
+static char efi_netfs = 0; |
|
|
|
enum |
|
{ |
|
OPTION_NET_DIRECTORY = 0x301, |
|
OPTION_SUBDIR, |
|
OPTION_DEBUG, |
|
- OPTION_DEBUG_IMAGE |
|
+ OPTION_DEBUG_IMAGE, |
|
+ OPTION_DEBUG_EFI_NETFS |
|
}; |
|
|
|
static struct argp_option options[] = { |
|
@@ -49,6 +51,7 @@ static struct argp_option options[] = { |
|
0, N_("relative subdirectory on network server"), 2}, |
|
{"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, |
|
{"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, |
|
+ {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2}, |
|
{0, 0, 0, 0, 0, 0} |
|
}; |
|
|
|
@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state) |
|
free (subdir); |
|
subdir = xstrdup (arg); |
|
return 0; |
|
+ case OPTION_DEBUG_EFI_NETFS: |
|
+ efi_netfs = 1; |
|
+ return 0; |
|
/* This is an undocumented feature... */ |
|
case OPTION_DEBUG: |
|
verbosity++; |
|
@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state) |
|
} |
|
} |
|
|
|
- |
|
struct argp argp = { |
|
options, argp_parser, NULL, |
|
"\v"N_("Prepares GRUB network boot images at net_directory/subdir " |
|
@@ -92,7 +97,7 @@ struct argp argp = { |
|
|
|
static char *base; |
|
|
|
-static const struct |
|
+static struct |
|
{ |
|
const char *mkimage_target; |
|
const char *netmodule; |
|
@@ -156,6 +161,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform) |
|
grub_install_push_module (targets[platform].netmodule); |
|
|
|
output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext); |
|
+ |
|
grub_install_make_image_wrap (input_dir, prefix, output, |
|
0, load_cfg, |
|
targets[platform].mkimage_target, 0); |
|
@@ -195,7 +201,16 @@ main (int argc, char *argv[]) |
|
|
|
grub_install_mkdir_p (base); |
|
|
|
- grub_install_push_module ("tftp"); |
|
+ if (!efi_netfs) |
|
+ { |
|
+ grub_install_push_module ("tftp"); |
|
+ grub_install_push_module ("http"); |
|
+ } |
|
+ else |
|
+ { |
|
+ targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs"; |
|
+ targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs"; |
|
+ } |
|
|
|
if (!grub_install_source_directory) |
|
{ |
|
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h |
|
index 0b490195ad9..f431f49973e 100644 |
|
--- a/include/grub/efi/api.h |
|
+++ b/include/grub/efi/api.h |
|
@@ -622,6 +622,23 @@ typedef union |
|
|
|
typedef grub_efi_uint64_t grub_efi_physical_address_t; |
|
typedef grub_efi_uint64_t grub_efi_virtual_address_t; |
|
+typedef struct { |
|
+ grub_uint8_t addr[4]; |
|
+} grub_efi_pxe_ipv4_address_t; |
|
+ |
|
+typedef struct { |
|
+ grub_uint8_t addr[16]; |
|
+} grub_efi_pxe_ipv6_address_t; |
|
+ |
|
+typedef struct { |
|
+ grub_uint8_t addr[32]; |
|
+} grub_efi_pxe_mac_address_t; |
|
+ |
|
+typedef union { |
|
+ grub_uint32_t addr[4]; |
|
+ grub_efi_pxe_ipv4_address_t v4; |
|
+ grub_efi_pxe_ipv6_address_t v6; |
|
+} grub_efi_pxe_ip_address_t; |
|
|
|
struct grub_efi_guid |
|
{ |
|
@@ -889,6 +906,8 @@ struct grub_efi_ipv6_device_path |
|
grub_efi_uint16_t remote_port; |
|
grub_efi_uint16_t protocol; |
|
grub_efi_uint8_t static_ip_address; |
|
+ grub_efi_uint8_t prefix_length; |
|
+ grub_efi_ipv6_address_t gateway_ip_address; |
|
} GRUB_PACKED; |
|
typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; |
|
|
|
@@ -938,6 +957,15 @@ struct grub_efi_uri_device_path |
|
} GRUB_PACKED; |
|
typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; |
|
|
|
+#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE 31 |
|
+struct grub_efi_dns_device_path |
|
+{ |
|
+ grub_efi_device_path_t header; |
|
+ grub_efi_uint8_t is_ipv6; |
|
+ grub_efi_pxe_ip_address_t dns_server_ip[0]; |
|
+} GRUB_PACKED; |
|
+typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t; |
|
+ |
|
#define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 |
|
|
|
/* Media Device Path. */ |
|
@@ -1020,6 +1048,23 @@ struct grub_efi_bios_device_path |
|
} GRUB_PACKED; |
|
typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; |
|
|
|
+/* Service Binding definitions */ |
|
+struct grub_efi_service_binding; |
|
+ |
|
+typedef grub_efi_status_t |
|
+(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this, |
|
+ grub_efi_handle_t *child_handle); |
|
+ |
|
+typedef grub_efi_status_t |
|
+(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this, |
|
+ grub_efi_handle_t *child_handle); |
|
+ |
|
+typedef struct grub_efi_service_binding |
|
+{ |
|
+ grub_efi_service_binding_create_child create_child; |
|
+ grub_efi_service_binding_destroy_child destroy_child; |
|
+} grub_efi_service_binding_t; |
|
+ |
|
struct grub_efi_open_protocol_information_entry |
|
{ |
|
grub_efi_handle_t agent_handle; |
|
@@ -1569,23 +1614,27 @@ typedef struct grub_efi_pxe_tftp_error |
|
grub_efi_char8_t error_string[127]; |
|
} grub_efi_pxe_tftp_error_t; |
|
|
|
-typedef struct { |
|
- grub_uint8_t addr[4]; |
|
-} grub_efi_pxe_ipv4_address_t; |
|
+typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t; |
|
|
|
-typedef struct { |
|
- grub_uint8_t addr[16]; |
|
-} grub_efi_pxe_ipv6_address_t; |
|
+typedef enum { |
|
+ GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST, |
|
+ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, |
|
+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, |
|
+ GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, |
|
+ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, |
|
+ GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, |
|
+ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE, |
|
+ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, |
|
+ GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST |
|
+} grub_efi_pxe_base_code_tftp_opcode_t; |
|
|
|
typedef struct { |
|
- grub_uint8_t addr[32]; |
|
-} grub_efi_pxe_mac_address_t; |
|
- |
|
-typedef union { |
|
- grub_uint32_t addr[4]; |
|
- grub_efi_pxe_ipv4_address_t v4; |
|
- grub_efi_pxe_ipv6_address_t v6; |
|
-} grub_efi_pxe_ip_address_t; |
|
+ grub_efi_ip_address_t mcast_ip; |
|
+ grub_efi_pxe_base_code_udp_port_t c_port; |
|
+ grub_efi_pxe_base_code_udp_port_t s_port; |
|
+ grub_efi_uint16_t listen_timeout; |
|
+ grub_efi_uint16_t transmit_timeout; |
|
+} grub_efi_pxe_base_code_mtftp_info_t; |
|
|
|
#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 |
|
typedef struct grub_efi_pxe_ip_filter |
|
@@ -1652,17 +1701,31 @@ typedef struct grub_efi_pxe_mode |
|
typedef struct grub_efi_pxe |
|
{ |
|
grub_uint64_t rev; |
|
- void (*start) (void); |
|
+ grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6); |
|
void (*stop) (void); |
|
- void (*dhcp) (void); |
|
+ grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this, |
|
+ grub_efi_boolean_t sort_offers); |
|
void (*discover) (void); |
|
- void (*mftp) (void); |
|
+ grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this, |
|
+ grub_efi_pxe_base_code_tftp_opcode_t operation, |
|
+ void *buffer_ptr, |
|
+ grub_efi_boolean_t overwrite, |
|
+ grub_efi_uint64_t *buffer_size, |
|
+ grub_efi_uintn_t *block_size, |
|
+ grub_efi_pxe_ip_address_t *server_ip, |
|
+ //grub_efi_ip_address_t *server_ip, |
|
+ grub_efi_char8_t *filename, |
|
+ grub_efi_pxe_base_code_mtftp_info_t *info, |
|
+ grub_efi_boolean_t dont_use_buffer); |
|
void (*udpwrite) (void); |
|
void (*udpread) (void); |
|
void (*setipfilter) (void); |
|
void (*arp) (void); |
|
void (*setparams) (void); |
|
- void (*setstationip) (void); |
|
+ grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this, |
|
+ grub_efi_pxe_ip_address_t *new_station_ip, |
|
+ grub_efi_pxe_ip_address_t *new_subnet_mask); |
|
+ //void (*setstationip) (void); |
|
void (*setpackets) (void); |
|
struct grub_efi_pxe_mode *mode; |
|
} grub_efi_pxe_t; |
|
@@ -1924,6 +1987,44 @@ struct grub_efi_ip4_config2_protocol |
|
}; |
|
typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; |
|
|
|
+struct grub_efi_ip4_route_table { |
|
+ grub_efi_ipv4_address_t subnet_address; |
|
+ grub_efi_ipv4_address_t subnet_mask; |
|
+ grub_efi_ipv4_address_t gateway_address; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t; |
|
+ |
|
+#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 |
|
+ |
|
+struct grub_efi_ip4_config2_interface_info { |
|
+ grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; |
|
+ grub_efi_uint8_t if_type; |
|
+ grub_efi_uint32_t hw_address_size; |
|
+ grub_efi_mac_address_t hw_address; |
|
+ grub_efi_ipv4_address_t station_address; |
|
+ grub_efi_ipv4_address_t subnet_mask; |
|
+ grub_efi_uint32_t route_table_size; |
|
+ grub_efi_ip4_route_table_t *route_table; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t; |
|
+ |
|
+enum grub_efi_ip4_config2_policy { |
|
+ GRUB_EFI_IP4_CONFIG2_POLICY_STATIC, |
|
+ GRUB_EFI_IP4_CONFIG2_POLICY_DHCP, |
|
+ GRUB_EFI_IP4_CONFIG2_POLICY_MAX |
|
+}; |
|
+ |
|
+typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t; |
|
+ |
|
+struct grub_efi_ip4_config2_manual_address { |
|
+ grub_efi_ipv4_address_t address; |
|
+ grub_efi_ipv4_address_t subnet_mask; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t; |
|
+ |
|
enum grub_efi_ip6_config_data_type { |
|
GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, |
|
GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, |
|
@@ -1958,6 +2059,49 @@ struct grub_efi_ip6_config_protocol |
|
}; |
|
typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; |
|
|
|
+enum grub_efi_ip6_config_policy { |
|
+ GRUB_EFI_IP6_CONFIG_POLICY_MANUAL, |
|
+ GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC |
|
+}; |
|
+typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t; |
|
+ |
|
+struct grub_efi_ip6_address_info { |
|
+ grub_efi_ipv6_address_t address; |
|
+ grub_efi_uint8_t prefix_length; |
|
+}; |
|
+typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t; |
|
+ |
|
+struct grub_efi_ip6_route_table { |
|
+ grub_efi_pxe_ipv6_address_t gateway; |
|
+ grub_efi_pxe_ipv6_address_t destination; |
|
+ grub_efi_uint8_t prefix_length; |
|
+}; |
|
+typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t; |
|
+ |
|
+struct grub_efi_ip6_config_interface_info { |
|
+ grub_efi_char16_t name[32]; |
|
+ grub_efi_uint8_t if_type; |
|
+ grub_efi_uint32_t hw_address_size; |
|
+ grub_efi_mac_address_t hw_address; |
|
+ grub_efi_uint32_t address_info_count; |
|
+ grub_efi_ip6_address_info_t *address_info; |
|
+ grub_efi_uint32_t route_count; |
|
+ grub_efi_ip6_route_table_t *route_table; |
|
+}; |
|
+typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t; |
|
+ |
|
+struct grub_efi_ip6_config_dup_addr_detect_transmits { |
|
+ grub_efi_uint32_t dup_addr_detect_transmits; |
|
+}; |
|
+typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t; |
|
+ |
|
+struct grub_efi_ip6_config_manual_address { |
|
+ grub_efi_ipv6_address_t address; |
|
+ grub_efi_boolean_t is_anycast; |
|
+ grub_efi_uint8_t prefix_length; |
|
+}; |
|
+typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; |
|
+ |
|
#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ |
|
|| defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ |
|
|| defined(__riscv) |
|
diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h |
|
new file mode 100644 |
|
index 00000000000..fdb88eb810e |
|
--- /dev/null |
|
+++ b/include/grub/efi/dhcp.h |
|
@@ -0,0 +1,343 @@ |
|
+#ifndef GRUB_EFI_DHCP_HEADER |
|
+#define GRUB_EFI_DHCP_HEADER 1 |
|
+ |
|
+#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ |
|
+ { 0x9d9a39d8, 0xbd42, 0x4a73, \ |
|
+ { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \ |
|
+ } |
|
+ |
|
+#define GRUB_EFI_DHCP4_PROTOCOL_GUID \ |
|
+ { 0x8a219718, 0x4ef5, 0x4761, \ |
|
+ { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \ |
|
+ } |
|
+ |
|
+#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ |
|
+ { 0x9fb9a8a1, 0x2f4a, 0x43a6, \ |
|
+ { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \ |
|
+ } |
|
+ |
|
+#define GRUB_EFI_DHCP6_PROTOCOL_GUID \ |
|
+ { 0x87c8bad7, 0x595, 0x4053, \ |
|
+ { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \ |
|
+ } |
|
+ |
|
+typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t; |
|
+ |
|
+enum grub_efi_dhcp4_state { |
|
+ GRUB_EFI_DHCP4_STOPPED, |
|
+ GRUB_EFI_DHCP4_INIT, |
|
+ GRUB_EFI_DHCP4_SELECTING, |
|
+ GRUB_EFI_DHCP4_REQUESTING, |
|
+ GRUB_EFI_DHCP4_BOUND, |
|
+ GRUB_EFI_DHCP4_RENEWING, |
|
+ GRUB_EFI_DHCP4_REBINDING, |
|
+ GRUB_EFI_DHCP4_INIT_REBOOT, |
|
+ GRUB_EFI_DHCP4_REBOOTING |
|
+}; |
|
+ |
|
+typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t; |
|
+ |
|
+struct grub_efi_dhcp4_header { |
|
+ grub_efi_uint8_t op_code; |
|
+ grub_efi_uint8_t hw_type; |
|
+ grub_efi_uint8_t hw_addr_len; |
|
+ grub_efi_uint8_t hops; |
|
+ grub_efi_uint32_t xid; |
|
+ grub_efi_uint16_t seconds; |
|
+ grub_efi_uint16_t reserved; |
|
+ grub_efi_ipv4_address_t client_addr; |
|
+ grub_efi_ipv4_address_t your_addr; |
|
+ grub_efi_ipv4_address_t server_addr; |
|
+ grub_efi_ipv4_address_t gateway_addr; |
|
+ grub_efi_uint8_t client_hw_addr[16]; |
|
+ grub_efi_char8_t server_name[64]; |
|
+ grub_efi_char8_t boot_file_name[128]; |
|
+} GRUB_PACKED; |
|
+ |
|
+typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t; |
|
+ |
|
+struct grub_efi_dhcp4_packet { |
|
+ grub_efi_uint32_t size; |
|
+ grub_efi_uint32_t length; |
|
+ struct { |
|
+ grub_efi_dhcp4_header_t header; |
|
+ grub_efi_uint32_t magik; |
|
+ grub_efi_uint8_t option[1]; |
|
+ } dhcp4; |
|
+} GRUB_PACKED; |
|
+ |
|
+typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t; |
|
+ |
|
+struct grub_efi_dhcp4_listen_point { |
|
+ grub_efi_ipv4_address_t listen_address; |
|
+ grub_efi_ipv4_address_t subnet_mask; |
|
+ grub_efi_uint16_t listen_port; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t; |
|
+ |
|
+struct grub_efi_dhcp4_transmit_receive_token { |
|
+ grub_efi_status_t status; |
|
+ grub_efi_event_t completion_event; |
|
+ grub_efi_ipv4_address_t remote_address; |
|
+ grub_efi_uint16_t remote_port; |
|
+ grub_efi_ipv4_address_t gateway_address; |
|
+ grub_efi_uint32_t listen_point_count; |
|
+ grub_efi_dhcp4_listen_point_t *listen_points; |
|
+ grub_efi_uint32_t timeout_value; |
|
+ grub_efi_dhcp4_packet_t *packet; |
|
+ grub_efi_uint32_t response_count; |
|
+ grub_efi_dhcp4_packet_t *response_list; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t; |
|
+ |
|
+enum grub_efi_dhcp4_event { |
|
+ GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01, |
|
+ GRUB_EFI_DHCP4_RCVD_OFFER, |
|
+ GRUB_EFI_DHCP4_SELECT_OFFER, |
|
+ GRUB_EFI_DHCP4_SEND_REQUEST, |
|
+ GRUB_EFI_DHCP4_RCVD_ACK, |
|
+ GRUB_EFI_DHCP4_RCVD_NAK, |
|
+ GRUB_EFI_DHCP4_SEND_DECLINE, |
|
+ GRUB_EFI_DHCP4_BOUND_COMPLETED, |
|
+ GRUB_EFI_DHCP4_ENTER_RENEWING, |
|
+ GRUB_EFI_DHCP4_ENTER_REBINDING, |
|
+ GRUB_EFI_DHCP4_ADDRESS_LOST, |
|
+ GRUB_EFI_DHCP4_FAIL |
|
+}; |
|
+ |
|
+typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t; |
|
+ |
|
+struct grub_efi_dhcp4_packet_option { |
|
+ grub_efi_uint8_t op_code; |
|
+ grub_efi_uint8_t length; |
|
+ grub_efi_uint8_t data[1]; |
|
+} GRUB_PACKED; |
|
+ |
|
+typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t; |
|
+ |
|
+struct grub_efi_dhcp4_config_data { |
|
+ grub_efi_uint32_t discover_try_count; |
|
+ grub_efi_uint32_t *discover_timeout; |
|
+ grub_efi_uint32_t request_try_count; |
|
+ grub_efi_uint32_t *request_timeout; |
|
+ grub_efi_ipv4_address_t client_address; |
|
+ grub_efi_status_t (*dhcp4_callback) ( |
|
+ grub_efi_dhcp4_protocol_t *this, |
|
+ void *context, |
|
+ grub_efi_dhcp4_state_t current_state, |
|
+ grub_efi_dhcp4_event_t dhcp4_event, |
|
+ grub_efi_dhcp4_packet_t *packet, |
|
+ grub_efi_dhcp4_packet_t **new_packet |
|
+ ); |
|
+ void *callback_context; |
|
+ grub_efi_uint32_t option_count; |
|
+ grub_efi_dhcp4_packet_option_t **option_list; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t; |
|
+ |
|
+struct grub_efi_dhcp4_mode_data { |
|
+ grub_efi_dhcp4_state_t state; |
|
+ grub_efi_dhcp4_config_data_t config_data; |
|
+ grub_efi_ipv4_address_t client_address; |
|
+ grub_efi_mac_address_t client_mac_address; |
|
+ grub_efi_ipv4_address_t server_address; |
|
+ grub_efi_ipv4_address_t router_address; |
|
+ grub_efi_ipv4_address_t subnet_mask; |
|
+ grub_efi_uint32_t lease_time; |
|
+ grub_efi_dhcp4_packet_t *reply_packet; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t; |
|
+ |
|
+struct grub_efi_dhcp4_protocol { |
|
+ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this, |
|
+ grub_efi_dhcp4_mode_data_t *dhcp4_mode_data); |
|
+ grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this, |
|
+ grub_efi_dhcp4_config_data_t *dhcp4_cfg_data); |
|
+ grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this, |
|
+ grub_efi_event_t completion_event); |
|
+ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this, |
|
+ grub_efi_boolean_t rebind_request, |
|
+ grub_efi_event_t completion_event); |
|
+ grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this); |
|
+ grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this); |
|
+ grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this, |
|
+ grub_efi_dhcp4_packet_t *seed_packet, |
|
+ grub_efi_uint32_t delete_count, |
|
+ grub_efi_uint8_t *delete_list, |
|
+ grub_efi_uint32_t append_count, |
|
+ grub_efi_dhcp4_packet_option_t *append_list[], |
|
+ grub_efi_dhcp4_packet_t **new_packet); |
|
+ grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this, |
|
+ grub_efi_dhcp4_transmit_receive_token_t *token); |
|
+ grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this, |
|
+ grub_efi_dhcp4_packet_t *packet, |
|
+ grub_efi_uint32_t *option_count, |
|
+ grub_efi_dhcp4_packet_option_t *packet_option_list[]); |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t; |
|
+ |
|
+struct grub_efi_dhcp6_retransmission { |
|
+ grub_efi_uint32_t irt; |
|
+ grub_efi_uint32_t mrc; |
|
+ grub_efi_uint32_t mrt; |
|
+ grub_efi_uint32_t mrd; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t; |
|
+ |
|
+enum grub_efi_dhcp6_event { |
|
+ GRUB_EFI_DHCP6_SEND_SOLICIT, |
|
+ GRUB_EFI_DHCP6_RCVD_ADVERTISE, |
|
+ GRUB_EFI_DHCP6_SELECT_ADVERTISE, |
|
+ GRUB_EFI_DHCP6_SEND_REQUEST, |
|
+ GRUB_EFI_DHCP6_RCVD_REPLY, |
|
+ GRUB_EFI_DHCP6_RCVD_RECONFIGURE, |
|
+ GRUB_EFI_DHCP6_SEND_DECLINE, |
|
+ GRUB_EFI_DHCP6_SEND_CONFIRM, |
|
+ GRUB_EFI_DHCP6_SEND_RELEASE, |
|
+ GRUB_EFI_DHCP6_SEND_RENEW, |
|
+ GRUB_EFI_DHCP6_SEND_REBIND |
|
+}; |
|
+ |
|
+typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t; |
|
+ |
|
+struct grub_efi_dhcp6_packet_option { |
|
+ grub_efi_uint16_t op_code; |
|
+ grub_efi_uint16_t op_len; |
|
+ grub_efi_uint8_t data[1]; |
|
+} GRUB_PACKED; |
|
+ |
|
+typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t; |
|
+ |
|
+struct grub_efi_dhcp6_header { |
|
+ grub_efi_uint32_t transaction_id:24; |
|
+ grub_efi_uint32_t message_type:8; |
|
+} GRUB_PACKED; |
|
+ |
|
+typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t; |
|
+ |
|
+struct grub_efi_dhcp6_packet { |
|
+ grub_efi_uint32_t size; |
|
+ grub_efi_uint32_t length; |
|
+ struct { |
|
+ grub_efi_dhcp6_header_t header; |
|
+ grub_efi_uint8_t option[1]; |
|
+ } dhcp6; |
|
+} GRUB_PACKED; |
|
+ |
|
+typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t; |
|
+ |
|
+struct grub_efi_dhcp6_ia_address { |
|
+ grub_efi_ipv6_address_t ip_address; |
|
+ grub_efi_uint32_t preferred_lifetime; |
|
+ grub_efi_uint32_t valid_lifetime; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t; |
|
+ |
|
+enum grub_efi_dhcp6_state { |
|
+ GRUB_EFI_DHCP6_INIT, |
|
+ GRUB_EFI_DHCP6_SELECTING, |
|
+ GRUB_EFI_DHCP6_REQUESTING, |
|
+ GRUB_EFI_DHCP6_DECLINING, |
|
+ GRUB_EFI_DHCP6_CONFIRMING, |
|
+ GRUB_EFI_DHCP6_RELEASING, |
|
+ GRUB_EFI_DHCP6_BOUND, |
|
+ GRUB_EFI_DHCP6_RENEWING, |
|
+ GRUB_EFI_DHCP6_REBINDING |
|
+}; |
|
+ |
|
+typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t; |
|
+ |
|
+#define GRUB_EFI_DHCP6_IA_TYPE_NA 3 |
|
+#define GRUB_EFI_DHCP6_IA_TYPE_TA 4 |
|
+ |
|
+struct grub_efi_dhcp6_ia_descriptor { |
|
+ grub_efi_uint16_t type; |
|
+ grub_efi_uint32_t ia_id; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t; |
|
+ |
|
+struct grub_efi_dhcp6_ia { |
|
+ grub_efi_dhcp6_ia_descriptor_t descriptor; |
|
+ grub_efi_dhcp6_state_t state; |
|
+ grub_efi_dhcp6_packet_t *reply_packet; |
|
+ grub_efi_uint32_t ia_address_count; |
|
+ grub_efi_dhcp6_ia_address_t ia_address[1]; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t; |
|
+ |
|
+struct grub_efi_dhcp6_duid { |
|
+ grub_efi_uint16_t length; |
|
+ grub_efi_uint8_t duid[1]; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t; |
|
+ |
|
+struct grub_efi_dhcp6_mode_data { |
|
+ grub_efi_dhcp6_duid_t *client_id; |
|
+ grub_efi_dhcp6_ia_t *ia; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t; |
|
+ |
|
+struct grub_efi_dhcp6_config_data { |
|
+ grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this, |
|
+ void *context, |
|
+ grub_efi_dhcp6_state_t current_state, |
|
+ grub_efi_dhcp6_event_t dhcp6_event, |
|
+ grub_efi_dhcp6_packet_t *packet, |
|
+ grub_efi_dhcp6_packet_t **new_packet); |
|
+ void *callback_context; |
|
+ grub_efi_uint32_t option_count; |
|
+ grub_efi_dhcp6_packet_option_t **option_list; |
|
+ grub_efi_dhcp6_ia_descriptor_t ia_descriptor; |
|
+ grub_efi_event_t ia_info_event; |
|
+ grub_efi_boolean_t reconfigure_accept; |
|
+ grub_efi_boolean_t rapid_commit; |
|
+ grub_efi_dhcp6_retransmission_t *solicit_retransmission; |
|
+}; |
|
+ |
|
+typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t; |
|
+ |
|
+struct grub_efi_dhcp6_protocol { |
|
+ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this, |
|
+ grub_efi_dhcp6_mode_data_t *dhcp6_mode_data, |
|
+ grub_efi_dhcp6_config_data_t *dhcp6_config_data); |
|
+ grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this, |
|
+ grub_efi_dhcp6_config_data_t *dhcp6_cfg_data); |
|
+ grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this); |
|
+ grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this, |
|
+ grub_efi_boolean_t send_client_id, |
|
+ grub_efi_dhcp6_packet_option_t *option_request, |
|
+ grub_efi_uint32_t option_count, |
|
+ grub_efi_dhcp6_packet_option_t *option_list[], |
|
+ grub_efi_dhcp6_retransmission_t *retransmission, |
|
+ grub_efi_event_t timeout_event, |
|
+ grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this, |
|
+ void *context, |
|
+ grub_efi_dhcp6_packet_t *packet), |
|
+ void *callback_context); |
|
+ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this, |
|
+ grub_efi_boolean_t rebind_request); |
|
+ grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this, |
|
+ grub_efi_uint32_t address_count, |
|
+ grub_efi_ipv6_address_t *addresses); |
|
+ grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this, |
|
+ grub_efi_uint32_t address_count, |
|
+ grub_efi_ipv6_address_t *addresses); |
|
+ grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this); |
|
+ grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this, |
|
+ grub_efi_dhcp6_packet_t *packet, |
|
+ grub_efi_uint32_t *option_count, |
|
+ grub_efi_dhcp6_packet_option_t *packet_option_list[]); |
|
+}; |
|
+ |
|
+#endif /* ! GRUB_EFI_DHCP_HEADER */ |
|
diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h |
|
new file mode 100644 |
|
index 00000000000..c5e9a89f505 |
|
--- /dev/null |
|
+++ b/include/grub/efi/http.h |
|
@@ -0,0 +1,215 @@ |
|
+/* |
|
+ * GRUB -- GRand Unified Bootloader |
|
+ * Copyright (C) 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/>. |
|
+ */ |
|
+ |
|
+#ifndef GRUB_EFI_HTTP_HEADER |
|
+#define GRUB_EFI_HTTP_HEADER 1 |
|
+ |
|
+#include <grub/symbol.h> |
|
+#include <grub/net.h> |
|
+#include <grub/efi/api.h> |
|
+ |
|
+#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ |
|
+ { 0xbdc8e6af, 0xd9bc, 0x4379, \ |
|
+ { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ |
|
+ } |
|
+ |
|
+#define GRUB_EFI_HTTP_PROTOCOL_GUID \ |
|
+ { 0x7A59B29B, 0x910B, 0x4171, \ |
|
+ { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \ |
|
+ } |
|
+ |
|
+#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s |
|
+#define EFIHTTP_RX_BUF_LEN 10240 |
|
+ |
|
+//****************************************** |
|
+// Protocol Interface Structure |
|
+//****************************************** |
|
+struct grub_efi_http; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTP_VERSION |
|
+//****************************************** |
|
+typedef enum { |
|
+ GRUB_EFI_HTTPVERSION10, |
|
+ GRUB_EFI_HTTPVERSION11, |
|
+ GRUB_EFI_HTTPVERSIONUNSUPPORTED |
|
+} grub_efi_http_version_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTPv4_ACCESS_POINT |
|
+//****************************************** |
|
+typedef struct { |
|
+ grub_efi_boolean_t use_default_address; |
|
+ grub_efi_ipv4_address_t local_address; |
|
+ grub_efi_ipv4_address_t local_subnet; |
|
+ grub_efi_uint16_t local_port; |
|
+} grub_efi_httpv4_access_point_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTPv6_ACCESS_POINT |
|
+//****************************************** |
|
+typedef struct { |
|
+ grub_efi_ipv6_address_t local_address; |
|
+ grub_efi_uint16_t local_port; |
|
+} grub_efi_httpv6_access_point_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTP_CONFIG_DATA |
|
+//****************************************** |
|
+typedef struct { |
|
+ grub_efi_http_version_t http_version; |
|
+ grub_efi_uint32_t timeout_millisec; |
|
+ grub_efi_boolean_t local_address_is_ipv6; |
|
+ union { |
|
+ grub_efi_httpv4_access_point_t *ipv4_node; |
|
+ grub_efi_httpv6_access_point_t *ipv6_node; |
|
+ } access_point; |
|
+} grub_efi_http_config_data_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTP_METHOD |
|
+//****************************************** |
|
+typedef enum { |
|
+ GRUB_EFI_HTTPMETHODGET, |
|
+ GRUB_EFI_HTTPMETHODPOST, |
|
+ GRUB_EFI_HTTPMETHODPATCH, |
|
+ GRUB_EFI_HTTPMETHODOPTIONS, |
|
+ GRUB_EFI_HTTPMETHODCONNECT, |
|
+ GRUB_EFI_HTTPMETHODHEAD, |
|
+ GRUB_EFI_HTTPMETHODPUT, |
|
+ GRUB_EFI_HTTPMETHODDELETE, |
|
+ GRUB_EFI_HTTPMETHODTRACE, |
|
+} grub_efi_http_method_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTP_REQUEST_DATA |
|
+//****************************************** |
|
+typedef struct { |
|
+ grub_efi_http_method_t method; |
|
+ grub_efi_char16_t *url; |
|
+} grub_efi_http_request_data_t; |
|
+ |
|
+typedef enum { |
|
+ GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0, |
|
+ GRUB_EFI_HTTP_STATUS_100_CONTINUE, |
|
+ GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS, |
|
+ GRUB_EFI_HTTP_STATUS_200_OK, |
|
+ GRUB_EFI_HTTP_STATUS_201_CREATED, |
|
+ GRUB_EFI_HTTP_STATUS_202_ACCEPTED, |
|
+ GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, |
|
+ GRUB_EFI_HTTP_STATUS_204_NO_CONTENT, |
|
+ GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT, |
|
+ GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT, |
|
+ GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES, |
|
+ GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY, |
|
+ GRUB_EFI_HTTP_STATUS_302_FOUND, |
|
+ GRUB_EFI_HTTP_STATUS_303_SEE_OTHER, |
|
+ GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED, |
|
+ GRUB_EFI_HTTP_STATUS_305_USE_PROXY, |
|
+ GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT, |
|
+ GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST, |
|
+ GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED, |
|
+ GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED, |
|
+ GRUB_EFI_HTTP_STATUS_403_FORBIDDEN, |
|
+ GRUB_EFI_HTTP_STATUS_404_NOT_FOUND, |
|
+ GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED, |
|
+ GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE, |
|
+ GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, |
|
+ GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT, |
|
+ GRUB_EFI_HTTP_STATUS_409_CONFLICT, |
|
+ GRUB_EFI_HTTP_STATUS_410_GONE, |
|
+ GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED, |
|
+ GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED, |
|
+ GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, |
|
+ GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, |
|
+ GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, |
|
+ GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, |
|
+ GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED, |
|
+ GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR, |
|
+ GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED, |
|
+ GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY, |
|
+ GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE, |
|
+ GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT, |
|
+ GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED |
|
+} grub_efi_http_status_code_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTP_RESPONSE_DATA |
|
+//****************************************** |
|
+typedef struct { |
|
+ grub_efi_http_status_code_t status_code; |
|
+} grub_efi_http_response_data_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTP_HEADER |
|
+//****************************************** |
|
+typedef struct { |
|
+ grub_efi_char8_t *field_name; |
|
+ grub_efi_char8_t *field_value; |
|
+} grub_efi_http_header_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTP_MESSAGE |
|
+//****************************************** |
|
+typedef struct { |
|
+ union { |
|
+ grub_efi_http_request_data_t *request; |
|
+ grub_efi_http_response_data_t *response; |
|
+ } data; |
|
+ grub_efi_uint32_t header_count; |
|
+ grub_efi_http_header_t *headers; |
|
+ grub_efi_uint32_t body_length; |
|
+ void *body; |
|
+} grub_efi_http_message_t; |
|
+ |
|
+//****************************************** |
|
+// EFI_HTTP_TOKEN |
|
+//****************************************** |
|
+typedef struct { |
|
+ grub_efi_event_t event; |
|
+ grub_efi_status_t status; |
|
+ grub_efi_http_message_t *message; |
|
+} grub_efi_http_token_t; |
|
+ |
|
+struct grub_efi_http { |
|
+ grub_efi_status_t |
|
+ (*get_mode_data) (struct grub_efi_http *this, |
|
+ grub_efi_http_config_data_t *http_config_data); |
|
+ |
|
+ grub_efi_status_t |
|
+ (*configure) (struct grub_efi_http *this, |
|
+ grub_efi_http_config_data_t *http_config_data); |
|
+ |
|
+ grub_efi_status_t |
|
+ (*request) (struct grub_efi_http *this, |
|
+ grub_efi_http_token_t *token); |
|
+ |
|
+ grub_efi_status_t |
|
+ (*cancel) (struct grub_efi_http *this, |
|
+ grub_efi_http_token_t *token); |
|
+ |
|
+ grub_efi_status_t |
|
+ (*response) (struct grub_efi_http *this, |
|
+ grub_efi_http_token_t *token); |
|
+ |
|
+ grub_efi_status_t |
|
+ (*poll) (struct grub_efi_http *this); |
|
+}; |
|
+typedef struct grub_efi_http grub_efi_http_t; |
|
+ |
|
+#endif /* !GRUB_EFI_HTTP_HEADER */ |
|
diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h |
|
new file mode 100644 |
|
index 00000000000..de90d223e8e |
|
--- /dev/null |
|
+++ b/include/grub/net/efi.h |
|
@@ -0,0 +1,144 @@ |
|
+#ifndef GRUB_NET_EFI_HEADER |
|
+#define GRUB_NET_EFI_HEADER 1 |
|
+ |
|
+#include <grub/efi/api.h> |
|
+#include <grub/efi/http.h> |
|
+#include <grub/efi/dhcp.h> |
|
+#include <grub/command.h> |
|
+ |
|
+typedef struct grub_efi_net_interface grub_efi_net_interface_t; |
|
+typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t; |
|
+typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t; |
|
+typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t; |
|
+ |
|
+struct grub_efi_net_interface |
|
+{ |
|
+ char *name; |
|
+ int prefer_ip6; |
|
+ struct grub_efi_net_device *dev; |
|
+ struct grub_efi_net_io *io; |
|
+ grub_efi_net_ip_config_t *ip_config; |
|
+ int io_type; |
|
+ struct grub_efi_net_interface *next; |
|
+}; |
|
+ |
|
+#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev) |
|
+#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev) |
|
+#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev) |
|
+#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet) |
|
+#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr) |
|
+#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr) |
|
+ |
|
+struct grub_efi_net_ip_config |
|
+{ |
|
+ char * (*get_hw_address) (struct grub_efi_net_device *dev); |
|
+ char * (*get_address) (struct grub_efi_net_device *dev); |
|
+ char ** (*get_route_table) (struct grub_efi_net_device *dev); |
|
+ grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); |
|
+ int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet); |
|
+ int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); |
|
+ int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns); |
|
+}; |
|
+ |
|
+union grub_efi_net_ip_address |
|
+{ |
|
+ grub_efi_ipv4_address_t ip4; |
|
+ grub_efi_ipv6_address_t ip6; |
|
+}; |
|
+ |
|
+struct grub_efi_net_ip_manual_address |
|
+{ |
|
+ int is_ip6; |
|
+ union |
|
+ { |
|
+ grub_efi_ip4_config2_manual_address_t ip4; |
|
+ grub_efi_ip6_config_manual_address_t ip6; |
|
+ }; |
|
+}; |
|
+ |
|
+struct grub_efi_net_device |
|
+{ |
|
+ grub_efi_handle_t handle; |
|
+ grub_efi_ip4_config2_protocol_t *ip4_config; |
|
+ grub_efi_ip6_config_protocol_t *ip6_config; |
|
+ grub_efi_handle_t http_handle; |
|
+ grub_efi_http_t *http; |
|
+ grub_efi_handle_t ip4_pxe_handle; |
|
+ grub_efi_pxe_t *ip4_pxe; |
|
+ grub_efi_handle_t ip6_pxe_handle; |
|
+ grub_efi_pxe_t *ip6_pxe; |
|
+ grub_efi_handle_t dhcp4_handle; |
|
+ grub_efi_dhcp4_protocol_t *dhcp4; |
|
+ grub_efi_handle_t dhcp6_handle; |
|
+ grub_efi_dhcp6_protocol_t *dhcp6; |
|
+ char *card_name; |
|
+ grub_efi_net_interface_t *net_interfaces; |
|
+ struct grub_efi_net_device *next; |
|
+}; |
|
+ |
|
+struct grub_efi_net_io |
|
+{ |
|
+ void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6); |
|
+ grub_err_t (*open) (struct grub_efi_net_device *dev, |
|
+ int prefer_ip6, |
|
+ grub_file_t file, |
|
+ const char *filename, |
|
+ int type); |
|
+ grub_ssize_t (*read) (struct grub_efi_net_device *dev, |
|
+ int prefer_ip6, |
|
+ grub_file_t file, |
|
+ char *buf, |
|
+ grub_size_t len); |
|
+ grub_err_t (*close) (struct grub_efi_net_device *dev, |
|
+ int prefer_ip6, |
|
+ grub_file_t file); |
|
+}; |
|
+ |
|
+extern struct grub_efi_net_device *net_devices; |
|
+ |
|
+extern struct grub_efi_net_io io_http; |
|
+extern struct grub_efi_net_io io_pxe; |
|
+ |
|
+extern grub_efi_net_ip_config_t *efi_net_ip4_config; |
|
+extern grub_efi_net_ip_config_t *efi_net_ip6_config; |
|
+ |
|
+char * |
|
+grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address); |
|
+ |
|
+char * |
|
+grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address); |
|
+ |
|
+char * |
|
+grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address); |
|
+ |
|
+int |
|
+grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest); |
|
+ |
|
+int |
|
+grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest); |
|
+ |
|
+char * |
|
+grub_efi_ip6_interface_name (struct grub_efi_net_device *dev); |
|
+ |
|
+char * |
|
+grub_efi_ip4_interface_name (struct grub_efi_net_device *dev); |
|
+ |
|
+grub_efi_net_interface_t * |
|
+grub_efi_net_create_interface (struct grub_efi_net_device *dev, |
|
+ const char *interface_name, |
|
+ grub_efi_net_ip_manual_address_t *net_ip, |
|
+ int has_subnet); |
|
+ |
|
+int grub_efi_net_fs_init (void); |
|
+void grub_efi_net_fs_fini (void); |
|
+int grub_efi_net_boot_from_https (void); |
|
+int grub_efi_net_boot_from_opa (void); |
|
+ |
|
+extern grub_command_func_t grub_efi_net_list_routes; |
|
+extern grub_command_func_t grub_efi_net_list_cards; |
|
+extern grub_command_func_t grub_efi_net_list_addrs; |
|
+extern grub_command_func_t grub_efi_net_add_addr; |
|
+extern grub_command_func_t grub_efi_net_bootp; |
|
+extern grub_command_func_t grub_efi_net_bootp6; |
|
+ |
|
+#endif /* ! GRUB_NET_EFI_HEADER */
|
|
|