This patch implements HTTP Boot by using UEFI HTTP Protocols defined in the UEFI spec (v2.5+):
28.6 EFI HTTP Protocols It would be better to make efihttp as a single module similar to http.mod. But I cannot fit my implementation to the interfaces (grub_net_app_protocol). Some operations conflict: there is packets_pulled(), but no read(). So I placed efihttp in the net.mod. It will be much appreciated to have suggestions of the best way to get this patch integrated in grub. Signed-off-by: Ken Lin <ken....@hpe.com> Signed-off-by: Clay Chang <cl...@hpe.com> Reviewed-by: Keng-Yu Lin <ken...@hpe.com> --- grub-core/Makefile.core.def | 1 + grub-core/net/bootp.c | 6 + grub-core/net/drivers/efi/efihttp.c | 386 ++++++++++++++++++++++++++++++++++++ grub-core/net/drivers/efi/efinet.c | 1 + grub-core/net/net.c | 36 +++- include/grub/efi/api.h | 17 ++ include/grub/efi/http.h | 221 +++++++++++++++++++++ include/grub/err.h | 3 +- include/grub/net.h | 1 + 9 files changed, 669 insertions(+), 3 deletions(-) create mode 100755 grub-core/net/drivers/efi/efihttp.c create mode 100755 include/grub/efi/http.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 2dfa22a..6a35951 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2143,6 +2143,7 @@ module = { common = net/ethernet.c; common = net/arp.c; common = net/netbuff.c; + efi = net/drivers/efi/efihttp.c; }; module = { diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index de9239c..17ac54c 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -26,6 +26,9 @@ #include <grub/datetime.h> #include <grub/time.h> #include <grub/list.h> +#ifdef GRUB_MACHINE_EFI +#include <grub/efi/http.h> +#endif static int dissect_url (const char *url, char **proto, char **host, char **path) @@ -339,6 +342,9 @@ grub_net_configure_by_dhcp_ack (const char *name, } else grub_errno = GRUB_ERR_NONE; +#ifdef GRUB_MACHINE_EFI + grub_efihttp_configure (card, bp); +#endif grub_free (proto); grub_free (ip); diff --git a/grub-core/net/drivers/efi/efihttp.c b/grub-core/net/drivers/efi/efihttp.c new file mode 100755 index 0000000..7e63f5c --- /dev/null +++ b/grub-core/net/drivers/efi/efihttp.c @@ -0,0 +1,386 @@ +/* efihttp.c - EFI HTTP. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/misc.h> +#include <grub/efi/efi.h> +#include <grub/efi/api.h> +#include <grub/efi/http.h> +#include <grub/charset.h> + +/* EFI-HTTP(S) Boot variables */ +grub_efi_http_t *grub_efihttp = NULL; +static grub_efi_boolean_t grub_efihttp_request_callback_done; +static grub_efi_boolean_t grub_efihttp_response_callback_done; +static grub_uint8_t *efihttp_rx_buf; + +static void +grub_efihttp_request_callback (grub_efi_event_t event, void *context) +{ + grub_dprintf ("efihttp", "grub_efihttp_request_callback(), event:%p, context:%p\n", event, context); + grub_efihttp_request_callback_done = 1; +} + +static void +grub_efihttp_response_callback (grub_efi_event_t event, void *context) +{ + grub_dprintf ("efihttp", "grub_efihttp_request_callback(), event:%p, context:%p\n", event, context); + grub_efihttp_response_callback_done = 1; +} + +grub_err_t +grub_efihttp_configure (struct grub_net_card *card, const struct grub_net_bootp_packet *bp) +{ + grub_efi_guid_t grub_efihttp_sb_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; + grub_efi_guid_t grub_efihttp_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; + grub_efi_service_binding_t *grub_efihttp_sb = NULL; + grub_efi_handle_t grub_efihttp_handle = NULL; + grub_efi_http_config_data_t grub_efihttp_config_data; + grub_efi_httpv4_access_point_t grub_efihttp_ipv4_node; + grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; + grub_efi_status_t status; + + grub_dprintf ("efihttp", "Enter grub_efihttp_configure()\n"); + + grub_efihttp_sb = grub_efi_open_protocol (card->efi_handle, &grub_efihttp_sb_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (!grub_efihttp_sb) + { + grub_dprintf ("efihttp", "Fail to open the Service Binding protocol!\n"); + return GRUB_ERR_EFI; + } + + grub_dprintf ("efihttp", "sb->create_child()\n"); + status = efi_call_2 (grub_efihttp_sb->create_child, grub_efihttp_sb, &grub_efihttp_handle); + if (GRUB_EFI_SUCCESS != status) + { + grub_dprintf ("efihttp", "Fail to create child! status=%d\n", (int)status); + return GRUB_ERR_EFI; + } + + grub_dprintf ("efihttp", "b->handle_protocol()\n"); + status = efi_call_3(b->handle_protocol, grub_efihttp_handle, &grub_efihttp_guid, (void**)&grub_efihttp); + if (!grub_efihttp || GRUB_EFI_SUCCESS != status) + { + grub_dprintf ("efihttp", "Error! Fail to get HTTP protocol! status=%d\n", (int)status); + return GRUB_ERR_EFI; + } + + grub_memset (&grub_efihttp_config_data, 0, sizeof(grub_efihttp_config_data)); + grub_efihttp_config_data.http_version = GRUB_EFI_HTTPVERSION11; + grub_efihttp_config_data.timeout_millisec = 5000; + grub_efihttp_config_data.local_address_is_ipv6 = 0; + grub_memset (&grub_efihttp_ipv4_node, 0, sizeof(grub_efihttp_ipv4_node)); + grub_efihttp_ipv4_node.use_default_address = 0; + grub_memcpy ((void*)grub_efihttp_ipv4_node.local_address, &bp->your_ip, sizeof (bp->your_ip)); + grub_memcpy ((void*)grub_efihttp_ipv4_node.local_subnet, &bp->subnet_mask, sizeof (bp->subnet_mask)); + grub_efihttp_ipv4_node.local_port = 0; + grub_efihttp_config_data.access_point.ipv4_node = &grub_efihttp_ipv4_node; + + grub_dprintf ("efihttp", "grub_efihttp->configure()\n"); + status = efi_call_2 (grub_efihttp->configure, grub_efihttp, &grub_efihttp_config_data); + if (GRUB_EFI_SUCCESS != status) + { + grub_dprintf ("efihttp", "Fail to do configuration! status=%d\n", (int)status); + return GRUB_ERR_EFI; + } + + grub_dprintf ("efihttp", "Leave grub_efihttp_configure()\n"); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_efihttp_open (grub_file_t file, const char *filename) +{ + grub_efi_http_request_data_t request_data; + grub_efi_http_header_t request_headers[3]; + 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_boot_services_t *b = grub_efi_system_table->boot_services; + grub_efi_status_t status; + grub_efi_http_status_code_t http_status; + const char *http = "http://"; + char *url; + grub_efi_char16_t *usc2_url; + grub_uint32_t url_len, usc2_url_len; + grub_uint32_t offset, length, i; + + grub_dprintf ("efihttp", "Enter grub_efihttp_open(), file->name:%s\n", file->name); + grub_dprintf ("efihttp", "grub_efihttp:%p, grub_efihttp->request:%p\n", grub_efihttp, grub_efihttp->request); + + /* init */ + grub_memset (&request_data, 0, sizeof (grub_efi_http_request_data_t)); + request_message = grub_zalloc (sizeof (grub_efi_http_message_t)); + request_token = grub_zalloc (sizeof (grub_efi_http_token_t)); + grub_memset (&response_data, 0, sizeof (grub_efi_http_response_data_t)); + response_message = grub_zalloc (sizeof (grub_efi_http_message_t)); + response_token = grub_zalloc (sizeof (grub_efi_http_token_t)); + + request_data.method = GRUB_EFI_HTTPMETHODGET; + + /* url */ + url_len = grub_strlen (http) + grub_strlen (file->device->net->server) + grub_strlen (file->device->net->name); + url = grub_malloc ((url_len + 1) * sizeof (url[0])); + grub_memset (url, 0, url_len); + grub_strncpy (url, http, grub_strlen(http)); + offset = grub_strlen (http); + grub_strncpy (url + offset, file->device->net->server, grub_strlen (file->device->net->server)); + offset += grub_strlen (file->device->net->server); + grub_strncpy (url + offset, file->device->net->name, grub_strlen (file->device->net->name)); + url[url_len] = 0; + grub_dprintf ("efihttp", "url:%s\n", url); + usc2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8; + usc2_url = grub_malloc ((usc2_url_len + 1) * sizeof (usc2_url[0])); + usc2_url_len = grub_utf8_to_utf16 (usc2_url, usc2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */ + usc2_url[usc2_url_len] = 0; + request_data.url = usc2_url; + + /* headers */ + request_headers[0].field_name = (grub_efi_char8_t*)"Host"; + request_headers[0].field_value = (grub_efi_char8_t*)file->device->net->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"; + + 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; + grub_efihttp_request_callback_done = 0; + grub_dprintf ("efihttp", "b->create_event()\n"); + status = efi_call_5 (b->create_event, + GRUB_EFI_EVT_NOTIFY_SIGNAL, + GRUB_EFI_TPL_CALLBACK, + grub_efihttp_request_callback, + NULL, + &request_token->event); + if (GRUB_EFI_SUCCESS != status) + { + grub_dprintf ("efihttp", "Fail to create an event! status=%d\n", (int)status); + return status; + } + + grub_dprintf ("efihttp", "grub_efihttp:%p, grub_efihttp->request:%p\n", grub_efihttp, grub_efihttp->request); + + /* make a HTTP request */ + grub_dprintf ("efihttp", "Before grub_efihttp->request(), url:%s\n", url); + status = efi_call_2 (grub_efihttp->request, grub_efihttp, request_token); + grub_dprintf ("efihttp", "After grub_efihttp->request()\n"); + if (GRUB_EFI_SUCCESS != status) + { + grub_dprintf ("efihttp", "Fail to send a request! status=%d\n", (int)status); + return GRUB_ERR_EFI; + } + /* allow the network stack 10 seconds to send the request successfully */ + while (!grub_efihttp_request_callback_done) + { + efi_call_1(grub_efihttp->poll, grub_efihttp); // give the http driver more motivation + } + + response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS; + response_message->data.response = &response_data; + response_message->header_count = 0; // herader_count will be updated by the HTTP driver on response + response_message->headers = NULL; // headers will be populated by the driver on response + /* use zero BodyLength to only receive the response headers */ + response_message->body_length = 0; + response_message->body = NULL; + response_token->event = NULL; + efi_call_5 (b->create_event, + GRUB_EFI_EVT_NOTIFY_SIGNAL, + GRUB_EFI_TPL_CALLBACK, + grub_efihttp_response_callback, + NULL, + &response_token->event); + response_token->status = GRUB_EFI_SUCCESS; + response_token->message = response_message; + + /* wait for HTTP response */ + grub_efihttp_response_callback_done = 0; + grub_dprintf ("efihttp", "Before grub_efihttp->response()\n"); + status = efi_call_2 (grub_efihttp->response, grub_efihttp, response_token); + if (GRUB_EFI_SUCCESS != status) + { + grub_dprintf ("efihttp", "Fail to receive a response! status=%d\n", (int)status); + return status; + } + while (!grub_efihttp_response_callback_done) + { + efi_call_1 (grub_efihttp->poll, grub_efihttp); + } + grub_dprintf ("efihttp", "After grub_efihttp->response(), response_message->body_length:%d\n", response_message->body_length); + + /* check the HTTP status code */ + http_status = response_token->message->data.response->status_code; + grub_dprintf ("efihttp", "http_status=%d\n", (int)http_status); + + /* parse the length of the file from the ContentLength header */ + grub_dprintf ("efihttp", "response_message->header_count:%d\n", response_message->header_count); + for (length = 0, i = 0; i < response_message->header_count; ++i) + { + if (!grub_strcmp((const char*)response_message->headers[i].field_name, "Content-Length")) + { + length = grub_strtoul((const char*)response_message->headers[i].field_value, 0, 10); + break; + } + } + file->size = (grub_off_t)length; + + file->not_easily_seekable = 0; + file->data = (void*)filename; + file->device->net->offset = 0; + efihttp_rx_buf = grub_malloc (EFIHTTP_RX_BUF_LEN); + + /* release */ + grub_free (request_message); + grub_free (request_token); + grub_free (response_message); + grub_free (response_token); + + grub_dprintf ("efihttp", "Leave grub_efihttp_open(), file->size:%d, file->offset:%d\n", (int)file->size, (int)file->offset); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_efihttp_close (grub_file_t file) +{ + grub_efi_status_t status; + + grub_dprintf ("efihttp", "Enter grub_efihttp_close(), file->device->net->name:%s, file->offset:%d\n", file->device->net->name, (int)file->offset); + status = efi_call_2 (grub_efihttp->cancel, grub_efihttp, NULL); + if (GRUB_EFI_SUCCESS != status) + { + grub_dprintf ("efihttp", "Error! status=%d\n", (int)status); + return GRUB_ERR_EFI; + } + grub_free (efihttp_rx_buf); + file->offset = 0; + file->device->net->offset = 0; + grub_dprintf ("efihttp", "Leave grub_efihttp_close(), file->device->net->name:%s, file->offset:%d\n", file->device->net->name, (int)file->offset); + + return GRUB_ERR_NONE; +} + +grub_ssize_t +grub_efihttp_read (grub_file_t file, char *buf, grub_size_t len) +{ + grub_efi_http_response_data_t response_data; + grub_efi_http_message_t *response_message; + grub_efi_http_token_t *response_token; + grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; + grub_efi_status_t status; + grub_efi_http_status_code_t http_status; + char *ptr = buf; + grub_size_t amount, total = 0; + + grub_dprintf ("efihttp", "Enter grub_efihttp_read(), len:%d\n", (int)len); + + /* zero init */ + grub_memset (&response_data, 0, sizeof (grub_efi_http_response_data_t)); + response_message = grub_zalloc (sizeof (grub_efi_http_message_t)); + response_token = grub_zalloc (sizeof (grub_efi_http_token_t)); + + /* receive the data */ + response_message->data.response = &response_data; + response_message->header_count = 0; // herader_count will be updated by the HTTP driver on response + response_message->headers = NULL; // headers will be populated by the driver on response + response_message->body_length = EFIHTTP_RX_BUF_LEN; + response_message->body = efihttp_rx_buf; + response_token->event = NULL; + response_token->status = GRUB_EFI_NOT_READY; + response_token->message = response_message; + grub_efihttp_response_callback_done = 0; + efi_call_5 (b->create_event, + GRUB_EFI_EVT_NOTIFY_SIGNAL, + GRUB_EFI_TPL_CALLBACK, + grub_efihttp_response_callback, + NULL, + &response_token->event); + + while (len > 0) + { + grub_dprintf ("efihttp", "file->device->net->offset:%d, file->size:%d\n", (int)file->device->net->offset, (int)file->size); + amount = EFIHTTP_RX_BUF_LEN; + if (amount > len) + { + amount = len; + } + + response_message->data.response = NULL; + if (!response_message->headers) + { + grub_free(response_message->headers); + } + response_message->header_count = 0; + response_message->headers = NULL; + response_message->body_length = amount; + grub_memset(efihttp_rx_buf, 0, amount); + + /* accept another response */ + response_token->status = GRUB_EFI_NOT_READY; + grub_efihttp_response_callback_done = 0; //false; + grub_dprintf ("efihttp", "Before grub_efihttp->response(), response_message->body_length:%d\n", response_message->body_length); + status = efi_call_2 (grub_efihttp->response, grub_efihttp, response_token); + if (GRUB_EFI_SUCCESS != status) + { + grub_dprintf ("efihttp", "Error! status=%d\n", (int)status); + return 0; + } + + while (!grub_efihttp_response_callback_done) + { + efi_call_1(grub_efihttp->poll, grub_efihttp); + } + + grub_dprintf ("efihttp", "After grub_efihttp->response(), response_message->body_length:%d, response_token.status:%d\n", + response_message->body_length, (int)response_token->status); + + /* check the HTTP status code */ + http_status = response_token->message->data.response->status_code; + grub_dprintf ("efihttp", "http_status=%d\n", (int)http_status); + + len -= response_message->body_length; + total += response_message->body_length; + file->device->net->offset += response_message->body_length; + if (buf) + { + grub_memcpy (ptr, efihttp_rx_buf, response_message->body_length); + ptr += response_message->body_length; + } + grub_dprintf ("efihttp", "len:%d, total:%d, file->device->net->offset:%d\n", + (int)len, (int)total, (int)file->device->net->offset); + } + + /* release */ + grub_free (response_message); + grub_free (response_token); + + grub_dprintf ("efihttp", "Leave grub_efihttp_read(), file->offset:%d\n", (int)file->offset); + + return total; +} diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c index 82a28fb..82b0fdd 100644 --- a/grub-core/net/drivers/efi/efinet.c +++ b/grub-core/net/drivers/efi/efinet.c @@ -518,6 +518,7 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u } grub_memcpy (bp->boot_file, uri_dp->uri, uri_len); grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip)); + grub_memcpy (&bp->subnet_mask, ipv4->subnet_mask, sizeof (bp->subnet_mask)); grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip)); bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0; diff --git a/grub-core/net/net.c b/grub-core/net/net.c index 2b329ee..90c5b48 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/efi/http.h> +#endif GRUB_MOD_LICENSE ("GPLv3+"); @@ -1504,7 +1507,12 @@ grub_net_fs_open (struct grub_file *file_out, const char *name) return grub_errno; } - err = file->device->net->protocol->open (file, name); +#ifdef GRUB_MACHINE_EFI + if (grub_efihttp) + err = grub_efihttp_open (file, name); + else +#endif + err = file->device->net->protocol->open (file, name); if (err) { while (file->device->net->packs.first) @@ -1543,7 +1551,12 @@ grub_net_fs_close (grub_file_t file) grub_netbuff_free (file->device->net->packs.first->nb); grub_net_remove_packet (file->device->net->packs.first); } - file->device->net->protocol->close (file); +#ifdef GRUB_MACHINE_EFI + if (grub_efihttp) + grub_efihttp_close (file); + else +#endif + file->device->net->protocol->close (file); grub_free (file->device->net->name); return GRUB_ERR_NONE; } @@ -1774,6 +1787,25 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) static grub_ssize_t grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) { +#ifdef GRUB_MACHINE_EFI + if (grub_efihttp) + { + /* adjust the offset */ + if (file->offset > file->device->net->offset) + { + grub_efihttp_read (file, NULL, (file->offset - file->device->net->offset)); + } + else if (file->offset < file->device->net->offset) + { + grub_efihttp_close (file); + grub_efihttp_open (file, file->device->net->name); + if (file->offset) + grub_efihttp_read (file, NULL, file->offset); + } + + return grub_efihttp_read (file, buf, len); + } +#endif if (file->offset != file->device->net->offset) { grub_err_t err; diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index 99ba068..6a37eb9 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -982,6 +982,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; diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h new file mode 100755 index 0000000..3a2725b --- /dev/null +++ b/include/grub/efi/http.h @@ -0,0 +1,221 @@ +/* + * 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; + +extern grub_efi_http_t *grub_efihttp; +grub_err_t grub_efihttp_configure (struct grub_net_card *card, const struct grub_net_bootp_packet *bp); +grub_err_t grub_efihttp_open (grub_file_t file, const char *filename); +grub_err_t grub_efihttp_close (grub_file_t file); +grub_ssize_t grub_efihttp_read (grub_file_t file, char *buf, grub_size_t len); + +#endif /* !GRUB_EFI_HTTP_HEADER */ diff --git a/include/grub/err.h b/include/grub/err.h index 1590c68..eb0fc0e 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -71,7 +71,8 @@ typedef enum GRUB_ERR_NET_PACKET_TOO_BIG, GRUB_ERR_NET_NO_DOMAIN, GRUB_ERR_EOF, - GRUB_ERR_BAD_SIGNATURE + GRUB_ERR_BAD_SIGNATURE, + GRUB_ERR_EFI } grub_err_t; diff --git a/include/grub/net.h b/include/grub/net.h index 67c801e..d175b8f 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -435,6 +435,7 @@ struct grub_net_bootp_packet grub_uint16_t flags; grub_uint32_t client_ip; grub_uint32_t your_ip; + grub_uint32_t subnet_mask; grub_uint32_t server_ip; grub_uint32_t gateway_ip; grub_net_bootp_mac_addr_t mac_addr; -- 2.7.4 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel