From fa1e44d19d6a622241b5411039421976c674bd0f Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 13 Oct 2015 18:18:25 +0800 Subject: [PATCH 1/3] Make translate_slashes() public Signed-off-by: Gary Ching-Pang Lin --- include/str.h | 20 ++++++++++++++++++++ netboot.c | 18 ------------------ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/include/str.h b/include/str.h index 0f3e003..9a74836 100644 --- a/include/str.h +++ b/include/str.h @@ -42,4 +42,24 @@ strcata(CHAR8 *dest, const CHAR8 *src) return dest; } +static inline +__attribute__((unused)) +CHAR8 * +translate_slashes(char *str) +{ + int i; + int j; + if (str == NULL) + return (CHAR8 *)str; + + for (i = 0, j = 0; str[i] != '\0'; i++, j++) { + if (str[i] == '\\') { + str[j] = '/'; + if (str[i+1] == '\\') + i++; + } + } + return (CHAR8 *)str; +} + #endif /* SHIM_STR_H */ diff --git a/netboot.c b/netboot.c index ad5d37e..1cc1a2b 100644 --- a/netboot.c +++ b/netboot.c @@ -54,24 +54,6 @@ typedef struct { UINT8 Data[1]; } EFI_DHCP6_PACKET_OPTION; -static CHAR8 * -translate_slashes(char *str) -{ - int i; - int j; - if (str == NULL) - return (CHAR8 *)str; - - for (i = 0, j = 0; str[i] != '\0'; i++, j++) { - if (str[i] == '\\') { - str[j] = '/'; - if (str[i+1] == '\\') - i++; - } - } - return (CHAR8 *)str; -} - /* * usingNetboot * Returns TRUE if we identify a protocol that is enabled and Providing us with -- 2.7.1 From 6d6091c59660435e76a922daa76891928c878ae6 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Wed, 14 Oct 2015 16:59:22 +0800 Subject: [PATCH 2/3] Add HTTP and IpConfig headers Signed-off-by: Gary Ching-Pang Lin --- include/Http.h | 517 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/Ip4Config2.h | 315 +++++++++++++++++++++++++++++++ include/Ip6Config.h | 366 ++++++++++++++++++++++++++++++++++++ 3 files changed, 1198 insertions(+) create mode 100644 include/Http.h create mode 100644 include/Ip4Config2.h create mode 100644 include/Ip6Config.h diff --git a/include/Http.h b/include/Http.h new file mode 100644 index 0000000..cd77703 --- /dev/null +++ b/include/Http.h @@ -0,0 +1,517 @@ +/** @file + This file defines the EFI HTTP Protocol interface. It is split into + the following two main sections: + HTTP Service Binding Protocol (HTTPSB) + HTTP Protocol (HTTP) + + Copyright (c) 2016, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.5 + +**/ + +#ifndef __EFI_HTTP_PROTOCOL_H__ +#define __EFI_HTTP_PROTOCOL_H__ + +#define EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xbdc8e6af, 0xd9bc, 0x4379, {0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ + } + +#define EFI_HTTP_PROTOCOL_GUID \ + { \ + 0x7a59b29b, 0x910b, 0x4171, {0x82, 0x42, 0xa8, 0x5a, 0x0d, 0xf2, 0x5b, 0x5b } \ + } + +typedef struct _EFI_HTTP_PROTOCOL EFI_HTTP_PROTOCOL; + +/// +/// EFI_HTTP_VERSION +/// +typedef enum { + HttpVersion10, + HttpVersion11, + HttpVersionUnsupported +} EFI_HTTP_VERSION; + +/// +/// EFI_HTTP_METHOD +/// +typedef enum { + HttpMethodGet, + HttpMethodPost, + HttpMethodPatch, + HttpMethodOptions, + HttpMethodConnect, + HttpMethodHead, + HttpMethodPut, + HttpMethodDelete, + HttpMethodTrace, + HttpMethodMax +} EFI_HTTP_METHOD; + +/// +/// EFI_HTTP_STATUS_CODE +/// +typedef enum { + HTTP_STATUS_UNSUPPORTED_STATUS = 0, + HTTP_STATUS_100_CONTINUE, + HTTP_STATUS_101_SWITCHING_PROTOCOLS, + HTTP_STATUS_200_OK, + HTTP_STATUS_201_CREATED, + HTTP_STATUS_202_ACCEPTED, + HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, + HTTP_STATUS_204_NO_CONTENT, + HTTP_STATUS_205_RESET_CONTENT, + HTTP_STATUS_206_PARTIAL_CONTENT, + HTTP_STATUS_300_MULTIPLE_CHIOCES, + HTTP_STATUS_301_MOVED_PERMANENTLY, + HTTP_STATUS_302_FOUND, + HTTP_STATUS_303_SEE_OTHER, + HTTP_STATUS_304_NOT_MODIFIED, + HTTP_STATUS_305_USE_PROXY, + HTTP_STATUS_307_TEMPORARY_REDIRECT, + HTTP_STATUS_400_BAD_REQUEST, + HTTP_STATUS_401_UNAUTHORIZED, + HTTP_STATUS_402_PAYMENT_REQUIRED, + HTTP_STATUS_403_FORBIDDEN, + HTTP_STATUS_404_NOT_FOUND, + HTTP_STATUS_405_METHOD_NOT_ALLOWED, + HTTP_STATUS_406_NOT_ACCEPTABLE, + HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, + HTTP_STATUS_408_REQUEST_TIME_OUT, + HTTP_STATUS_409_CONFLICT, + HTTP_STATUS_410_GONE, + HTTP_STATUS_411_LENGTH_REQUIRED, + HTTP_STATUS_412_PRECONDITION_FAILED, + HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, + HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, + HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, + HTTP_STATUS_417_EXPECTATION_FAILED, + HTTP_STATUS_500_INTERNAL_SERVER_ERROR, + HTTP_STATUS_501_NOT_IMPLEMENTED, + HTTP_STATUS_502_BAD_GATEWAY, + HTTP_STATUS_503_SERVICE_UNAVAILABLE, + HTTP_STATUS_504_GATEWAY_TIME_OUT, + HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED +} EFI_HTTP_STATUS_CODE; + +/// +/// EFI_HTTPv4_ACCESS_POINT +/// +typedef struct { + /// + /// Set to TRUE to instruct the EFI HTTP instance to use the default address + /// information in every TCP connection made by this instance. In addition, when set + /// to TRUE, LocalAddress and LocalSubnet are ignored. + /// + BOOLEAN UseDefaultAddress; + /// + /// If UseDefaultAddress is set to FALSE, this defines the local IP address to be + /// used in every TCP connection opened by this instance. + /// + EFI_IPv4_ADDRESS LocalAddress; + /// + /// If UseDefaultAddress is set to FALSE, this defines the local subnet to be used + /// in every TCP connection opened by this instance. + /// + EFI_IPv4_ADDRESS LocalSubnet; + /// + /// This defines the local port to be used in + /// every TCP connection opened by this instance. + /// + UINT16 LocalPort; +} EFI_HTTPv4_ACCESS_POINT; + +/// +/// EFI_HTTPv6_ACCESS_POINT +/// +typedef struct { + /// + /// Local IP address to be used in every TCP connection opened by this instance. + /// + EFI_IPv6_ADDRESS LocalAddress; + /// + /// Local port to be used in every TCP connection opened by this instance. + /// + UINT16 LocalPort; +} EFI_HTTPv6_ACCESS_POINT; + +/// +/// EFI_HTTP_CONFIG_DATA_ACCESS_POINT +/// + + +typedef struct { + /// + /// HTTP version that this instance will support. + /// + EFI_HTTP_VERSION HttpVersion; + /// + /// Time out (in milliseconds) when blocking for requests. + /// + UINT32 TimeOutMillisec; + /// + /// Defines behavior of EFI DNS and TCP protocols consumed by this instance. If + /// FALSE, this instance will use EFI_DNS4_PROTOCOL and EFI_TCP4_PROTOCOL. If TRUE, + /// this instance will use EFI_DNS6_PROTOCOL and EFI_TCP6_PROTOCOL. + /// + BOOLEAN LocalAddressIsIPv6; + + union { + /// + /// When LocalAddressIsIPv6 is FALSE, this points to the local address, subnet, and + /// port used by the underlying TCP protocol. + /// + EFI_HTTPv4_ACCESS_POINT *IPv4Node; + /// + /// When LocalAddressIsIPv6 is TRUE, this points to the local IPv6 address and port + /// used by the underlying TCP protocol. + /// + EFI_HTTPv6_ACCESS_POINT *IPv6Node; + } AccessPoint; +} EFI_HTTP_CONFIG_DATA; + +/// +/// EFI_HTTP_REQUEST_DATA +/// +typedef struct { + /// + /// The HTTP method (e.g. GET, POST) for this HTTP Request. + /// + EFI_HTTP_METHOD Method; + /// + /// The URI of a remote host. From the information in this field, the HTTP instance + /// will be able to determine whether to use HTTP or HTTPS and will also be able to + /// determine the port number to use. If no port number is specified, port 80 (HTTP) + /// is assumed. See RFC 3986 for more details on URI syntax. + /// + CHAR16 *Url; +} EFI_HTTP_REQUEST_DATA; + +/// +/// EFI_HTTP_RESPONSE_DATA +/// +typedef struct { + /// + /// Response status code returned by the remote host. + /// + EFI_HTTP_STATUS_CODE StatusCode; +} EFI_HTTP_RESPONSE_DATA; + +/// +/// EFI_HTTP_HEADER +/// +typedef struct { + /// + /// Null terminated string which describes a field name. See RFC 2616 Section 14 for + /// detailed information about field names. + /// + CHAR8 *FieldName; + /// + /// Null terminated string which describes the corresponding field value. See RFC 2616 + /// Section 14 for detailed information about field values. + /// + CHAR8 *FieldValue; +} EFI_HTTP_HEADER; + +/// +/// EFI_HTTP_MESSAGE +/// +typedef struct { + /// + /// HTTP message data. + /// + union { + /// + /// When the token is used to send a HTTP request, Request is a pointer to storage that + /// contains such data as URL and HTTP method. + /// + EFI_HTTP_REQUEST_DATA *Request; + /// + /// When used to await a response, Response points to storage containing HTTP response + /// status code. + /// + EFI_HTTP_RESPONSE_DATA *Response; + } Data; + /// + /// Number of HTTP header structures in Headers list. On request, this count is + /// provided by the caller. On response, this count is provided by the HTTP driver. + /// + UINTN HeaderCount; + /// + /// Array containing list of HTTP headers. On request, this array is populated by the + /// caller. On response, this array is allocated and populated by the HTTP driver. It + /// is the responsibility of the caller to free this memory on both request and + /// response. + /// + EFI_HTTP_HEADER *Headers; + /// + /// Length in bytes of the HTTP body. This can be zero depending on the HttpMethod type. + /// + UINTN BodyLength; + /// + /// Body associated with the HTTP request or response. This can be NULL depending on + /// the HttpMethod type. + /// + VOID *Body; +} EFI_HTTP_MESSAGE; + + +/// +/// EFI_HTTP_TOKEN +/// +typedef struct { + /// + /// This Event will be signaled after the Status field is updated by the EFI HTTP + /// Protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL. The Task Priority + /// Level (TPL) of Event must be lower than or equal to TPL_CALLBACK. + /// + EFI_EVENT Event; + /// + /// Status will be set to one of the following value if the HTTP request is + /// successfully sent or if an unexpected error occurs: + /// EFI_SUCCESS: The HTTP request was successfully sent to the remote host. + /// EFI_HTTP_ERROR: The response message was successfully received but contains a + /// HTTP error. The response status code is returned in token. + /// EFI_ABORTED: The HTTP request was cancelled by the caller and removed from + /// the transmit queue. + /// EFI_TIMEOUT: The HTTP request timed out before reaching the remote host. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// + EFI_STATUS Status; + /// + /// Pointer to storage containing HTTP message data. + /// + EFI_HTTP_MESSAGE *Message; +} EFI_HTTP_TOKEN; + +/** + Returns the operational parameters for the current HTTP child instance. + + The GetModeData() function is used to read the current mode data (operational + parameters) for this HTTP protocol instance. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[out] HttpConfigData Point to buffer for operational parameters of this + HTTP instance. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_INVALID_PARAMETER This is NULL. + HttpConfigData is NULL. + HttpInstance->LocalAddressIsIPv6 is FALSE and + HttpConfigData->IPv4Node is NULL. + HttpInstance->LocalAddressIsIPv6 is TRUE and + HttpConfigData->IPv6Node is NULL. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI * EFI_HTTP_GET_MODE_DATA)( + IN EFI_HTTP_PROTOCOL *This, + OUT EFI_HTTP_CONFIG_DATA *HttpConfigData + ); + +/** + Initialize or brutally reset the operational parameters for this EFI HTTP instance. + + The Configure() function does the following: + When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring + timeout, local address, port, etc. + When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active + connections with remote hosts, canceling all asynchronous tokens, and flush request + and response buffers without informing the appropriate hosts. + + No other EFI HTTP function can be executed by this instance until the Configure() + function is executed and returns successfully. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] HttpConfigData Pointer to the configure data to configure the instance. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + HttpConfigData is NULL. + HttpConfigData->LocalAddressIsIPv6 is FALSE and + HttpConfigData->IPv4Node is NULL. + HttpConfigData->LocalAddressIsIPv6 is TRUE and + HttpConfigData->IPv6Node is NULL. + @retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling + Configure() with NULL to reset it. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when + executing Configure(). + @retval EFI_UNSUPPORTED One or more options in ConfigData are not supported + in the implementation. +**/ +typedef +EFI_STATUS +(EFIAPI * EFI_HTTP_CONFIGURE)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_CONFIG_DATA *HttpConfigData + ); + +/** + The Request() function queues an HTTP request to this HTTP instance, + similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent + successfully, or if there is an error, Status in token will be updated and Event will + be signaled. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Pointer to storage containing HTTP request token. + + @retval EFI_SUCCESS Outgoing data was processed. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit or receive queue. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token->Message is NULL. + Token->Message->Body is not NULL, + Token->Message->BodyLength is non-zero, and + Token->Message->Data is NULL, but a previous call to + Request()has not been completed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. + @retval EFI_UNSUPPORTED The HTTP method is not supported in current implementation. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_REQUEST) ( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + Abort an asynchronous HTTP request or response token. + + The Cancel() function aborts a pending HTTP request or response transaction. If + Token is not NULL and the token is in transmit or receive queues when it is being + cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will + be signaled. If the token is not in one of the queues, which usually means that the + asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL, + all asynchronous tokens issued by Request() or Response() will be aborted. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Point to storage containing HTTP request or response + token. + + @retval EFI_SUCCESS Request and Response queues are successfully flushed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance hasn't been configured. + @retval EFI_NOT_FOUND The asynchronous request or response token is not + found. + @retval EFI_UNSUPPORTED The implementation does not support this function. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_CANCEL)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + The Response() function queues an HTTP response to this HTTP instance, similar to + Receive() function in the EFI TCP driver. When the HTTP Response is received successfully, + or if there is an error, Status in token will be updated and Event will be signaled. + + The HTTP driver will queue a receive token to the underlying TCP instance. When data + is received in the underlying TCP instance, the data will be parsed and Token will + be populated with the response data. If the data received from the remote host + contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting + (asynchronously) for more data to be sent from the remote host before signaling + Event in Token. + + It is the responsibility of the caller to allocate a buffer for Body and specify the + size in BodyLength. If the remote host provides a response that contains a content + body, up to BodyLength bytes will be copied from the receive buffer into Body and + BodyLength will be updated with the amount of bytes received and copied to Body. This + allows the client to download a large file in chunks instead of into one contiguous + block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is + non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive + token to underlying TCP instance. If data arrives in the receive buffer, up to + BodyLength bytes of data will be copied to Body. The HTTP driver will then update + BodyLength with the amount of bytes received and copied to Body. + + If the HTTP driver does not have an open underlying TCP connection with the host + specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is + consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain + an open TCP connection between client and host. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Pointer to storage containing HTTP response token. + + @retval EFI_SUCCESS Allocation succeeded. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been + initialized. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token->Message->Headers is NULL. + Token->Message is NULL. + Token->Message->Body is not NULL, + Token->Message->BodyLength is non-zero, and + Token->Message->Data is NULL, but a previous call to + Response() has not been completed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. + @retval EFI_ACCESS_DENIED An open TCP connection is not present with the host + specified by response URL. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_RESPONSE) ( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + The Poll() function can be used by network drivers and applications to increase the + rate that data packets are moved between the communication devices and the transmit + and receive queues. + + In some systems, the periodic timer event in the managed network driver may not poll + the underlying communications device fast enough to transmit and/or receive all data + packets without missing incoming packets or dropping outgoing packets. Drivers and + applications that are experiencing packet loss should try calling the Poll() function + more often. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed.. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_READY No incoming or outgoing data is processed. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_POLL) ( + IN EFI_HTTP_PROTOCOL *This + ); + +/// +/// The EFI HTTP protocol is designed to be used by EFI drivers and applications to +/// create and transmit HTTP Requests, as well as handle HTTP responses that are +/// returned by a remote host. This EFI protocol uses and relies on an underlying EFI +/// TCP protocol. +/// +struct _EFI_HTTP_PROTOCOL { + EFI_HTTP_GET_MODE_DATA GetModeData; + EFI_HTTP_CONFIGURE Configure; + EFI_HTTP_REQUEST Request; + EFI_HTTP_CANCEL Cancel; + EFI_HTTP_RESPONSE Response; + EFI_HTTP_POLL Poll; +}; + +#endif diff --git a/include/Ip4Config2.h b/include/Ip4Config2.h new file mode 100644 index 0000000..b4f1d84 --- /dev/null +++ b/include/Ip4Config2.h @@ -0,0 +1,315 @@ +/** @file + This file provides a definition of the EFI IPv4 Configuration II + Protocol. + +Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +@par Revision Reference: +This Protocol is introduced in UEFI Specification 2.5 + +**/ +#ifndef __EFI_IP4CONFIG2_PROTOCOL_H__ +#define __EFI_IP4CONFIG2_PROTOCOL_H__ + +#include + +#define EFI_IP4_CONFIG2_PROTOCOL_GUID \ + { \ + 0x5b446ed1, 0xe30b, 0x4faa, {0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ + } + +typedef struct _EFI_IP4_CONFIG2_PROTOCOL EFI_IP4_CONFIG2_PROTOCOL; + + +/// +/// EFI_IP4_CONFIG2_DATA_TYPE +/// +typedef enum { + /// + /// The interface information of the communication device this EFI + /// IPv4 Configuration II Protocol instance manages. This type of + /// data is read only. The corresponding Data is of type + /// EFI_IP4_CONFIG2_INTERFACE_INFO. + /// + Ip4Config2DataTypeInterfaceInfo, + /// + /// The general configuration policy for the EFI IPv4 network stack + /// running on the communication device this EFI IPv4 + /// Configuration II Protocol instance manages. The policy will + /// affect other configuration settings. The corresponding Data is of + /// type EFI_IP4_CONFIG2_POLICY. + /// + Ip4Config2DataTypePolicy, + /// + /// The station addresses set manually for the EFI IPv4 network + /// stack. It is only configurable when the policy is + /// Ip4Config2PolicyStatic. The corresponding Data is of + /// type EFI_IP4_CONFIG2_MANUAL_ADDRESS. + /// + Ip4Config2DataTypeManualAddress, + /// + /// The gateway addresses set manually for the EFI IPv4 network + /// stack running on the communication device this EFI IPv4 + /// Configuration II Protocol manages. It is not configurable when + /// the policy is Ip4Config2PolicyDhcp. The gateway + /// addresses must be unicast IPv4 addresses. The corresponding + /// Data is a pointer to an array of EFI_IPv4_ADDRESS instances. + /// + Ip4Config2DataTypeGateway, + /// + /// The DNS server list for the EFI IPv4 network stack running on + /// the communication device this EFI IPv4 Configuration II + /// Protocol manages. It is not configurable when the policy is + /// Ip4Config2PolicyDhcp. The DNS server addresses must be + /// unicast IPv4 addresses. The corresponding Data is a pointer to + /// an array of EFI_IPv4_ADDRESS instances. + /// + Ip4Config2DataTypeDnsServer, + Ip4Config2DataTypeMaximum +} EFI_IP4_CONFIG2_DATA_TYPE; + +/// +/// EFI_IP4_CONFIG2_INTERFACE_INFO related definitions +/// +#define EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 + +/// +/// EFI_IP4_CONFIG2_INTERFACE_INFO +/// +typedef struct { + /// + /// The name of the interface. It is a NULL-terminated Unicode string. + /// + CHAR16 Name[EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; + /// + /// The interface type of the network interface. See RFC 1700, + /// section "Number Hardware Type". + /// + UINT8 IfType; + /// + /// The size, in bytes, of the network interface's hardware address. + /// + UINT32 HwAddressSize; + /// + /// The hardware address for the network interface. + /// + EFI_MAC_ADDRESS HwAddress; + /// + /// The station IPv4 address of this EFI IPv4 network stack. + /// + EFI_IPv4_ADDRESS StationAddress; + /// + /// The subnet address mask that is associated with the station address. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// Size of the following RouteTable, in bytes. May be zero. + /// + UINT32 RouteTableSize; + /// + /// The route table of the IPv4 network stack runs on this interface. + /// Set to NULL if RouteTableSize is zero. Type EFI_IP4_ROUTE_TABLE is defined in + /// EFI_IP4_PROTOCOL.GetModeData(). + /// + EFI_IP4_ROUTE_TABLE *RouteTable OPTIONAL; +} EFI_IP4_CONFIG2_INTERFACE_INFO; + +/// +/// EFI_IP4_CONFIG2_POLICY +/// +typedef enum { + /// + /// Under this policy, the Ip4Config2DataTypeManualAddress, + /// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration + /// data are required to be set manually. The EFI IPv4 Protocol will get all + /// required configuration such as IPv4 address, subnet mask and + /// gateway settings from the EFI IPv4 Configuration II protocol. + /// + Ip4Config2PolicyStatic, + /// + /// Under this policy, the Ip4Config2DataTypeManualAddress, + /// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration data are + /// not allowed to set via SetData(). All of these configurations are retrieved from DHCP + /// server or other auto-configuration mechanism. + /// + Ip4Config2PolicyDhcp, + Ip4Config2PolicyMax +} EFI_IP4_CONFIG2_POLICY; + +/// +/// EFI_IP4_CONFIG2_MANUAL_ADDRESS +/// +typedef struct { + /// + /// The IPv4 unicast address. + /// + EFI_IPv4_ADDRESS Address; + /// + /// The subnet mask. + /// + EFI_IPv4_ADDRESS SubnetMask; +} EFI_IP4_CONFIG2_MANUAL_ADDRESS; + +/** + Set the configuration for the EFI IPv4 network stack running on the communication device this EFI + IPv4 Configuration II Protocol instance manages. + + This function is used to set the configuration data of type DataType for the EFI IPv4 network stack + running on the communication device this EFI IPv4 Configuration II Protocol instance manages. + The successfully configured data is valid after system reset or power-off. + The DataSize is used to calculate the count of structure instances in the Data for some + DataType that multiple structure instances are allowed. + This function is always non-blocking. When setting some typeof configuration data, an + asynchronous process is invoked to check the correctness of the data, such as doing address conflict + detection on the manually set local IPv4 address. EFI_NOT_READY is returned immediately to + indicate that such an asynchronous process is invoked and the process is not finished yet. The caller + willing to get the result of the asynchronous process is required to call RegisterDataNotify() + to register an event on the specified configuration data. Once the event is signaled, the caller can call + GetData()to get back the configuration data in order to know the result. For other types of + configuration data that do not require an asynchronous configuration process, the result of the + operation is immediately returned. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to set. + @param[in] DataSize Size of the buffer pointed to by Data in bytes. + @param[in] Data The data buffer to set. The type ofthe data buffer is associated + with the DataType. + + @retval EFI_SUCCESS The specified configuration data for the EFI IPv4 network stack is set + successfully. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + This is NULL. + Data is NULL. + One or more fields in Data do not match the requirement of the data type + indicated by DataType. + @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified configuration + data can not be set under the current policy. + @retval EFI_ACCESS_DENIED Another set operation on the specified configuration data is already in process. + @retval EFI_NOT_READY An asynchronous process is invoked to set the specified configuration data and + the process is not finished yet. + @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type indicated by DataType. + @retval EFI_UNSUPPORTED This DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_SET_DATA) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Get the configuration data for the EFI IPv4 network stack running on the communication device this + EFI IPv4 Configuration II Protocol instance manages. + + This function returns the configuration data of type DataType for the EFI IPv4 network stack + running on the communication device this EFI IPv4 Configuration II Protocol instance manages. + The caller is responsible for allocating the buffer usedto return the specified configuration data and + the required size will be returned to the caller if the size of the buffer is too small. + EFI_NOT_READY is returned if the specified configuration data is not ready due to an already in + progress asynchronous configuration process. The caller can call RegisterDataNotify() to + register an event on the specified configuration data. Once the asynchronous configuration process is + finished, the event will be signaled and a subsequent GetData() call will return the specified + configuration data. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to get. + @param[out] DataSize On input, in bytes, the size of Data. On output, in bytes, the size + of buffer required to store the specified configuration data. + @param[in] Data The data buffer in which the configuration data is returned. The + type of the data buffer is associated with the DataType. Ignored + if DataSize is 0. + + @retval EFI_SUCCESS The specified configuration data is got successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + This is NULL. + DataSize is NULL. + Data is NULL if *DataSizeis not zero. + @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data + and the required size is returned in DataSize. + @retval EFI_NOT_READY The specified configuration data is not ready due to an already in + progress asynchronous configuration process. + @retval EFI_NOT_FOUND The specified configuration data is not found. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_GET_DATA) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN OUT UINTN *DataSize, + IN VOID *Data OPTIONAL + ); + +/** + Register an event that is to be signaled whenever a configuration process on the specified + configuration data is done. + + This function registers an event that is to be signaled whenever a configuration process on the + specified configuration data is done. An event can be registered for different DataType + simultaneously and the caller is responsible for determining which type of configuration data causes + the signaling of the event in such case. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to unregister the event for. + @param[in] Event The event to register. + + @retval EFI_SUCCESS The notification event for the specified configuration data is + registered. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_REGISTER_NOTIFY) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/** + Remove a previously registered event for the specified configuration data. + + This function removes a previously registeredevent for the specified configuration data. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to remove the previously registered event for. + @param[in] Event The event to unregister. + + @retval EFI_SUCCESS The event registered for the specified configuration data is removed. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_NOT_FOUND The Eventhas not been registered for the specified DataType. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_UNREGISTER_NOTIFY) ( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/// +/// The EFI_IP4_CONFIG2_PROTOCOL is designed to be the central repository for the common +/// configurations and the administrator configurable settings for the EFI IPv4 network stack. +/// An EFI IPv4 Configuration II Protocol instance will be installed on each communication device that +/// the EFI IPv4 network stack runs on. +/// +struct _EFI_IP4_CONFIG2_PROTOCOL { + EFI_IP4_CONFIG2_SET_DATA SetData; + EFI_IP4_CONFIG2_GET_DATA GetData; + EFI_IP4_CONFIG2_REGISTER_NOTIFY RegisterDataNotify; + EFI_IP4_CONFIG2_UNREGISTER_NOTIFY UnregisterDataNotify; +}; + +#endif diff --git a/include/Ip6Config.h b/include/Ip6Config.h new file mode 100644 index 0000000..003e50e --- /dev/null +++ b/include/Ip6Config.h @@ -0,0 +1,366 @@ +/** @file + This file provides a definition of the EFI IPv6 Configuration + Protocol. + +Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef __EFI_IP6CONFIG_PROTOCOL_H__ +#define __EFI_IP6CONFIG_PROTOCOL_H__ + +#include + +#define EFI_IP6_CONFIG_PROTOCOL_GUID \ + { \ + 0x937fe521, 0x95ae, 0x4d1a, {0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ + } + +typedef struct _EFI_IP6_CONFIG_PROTOCOL EFI_IP6_CONFIG_PROTOCOL; + +/// +/// EFI_IP6_CONFIG_DATA_TYPE +/// +typedef enum { + /// + /// The interface information of the communication + /// device this EFI IPv6 Configuration Protocol instance manages. + /// This type of data is read only.The corresponding Data is of type + /// EFI_IP6_CONFIG_INTERFACE_INFO. + /// + Ip6ConfigDataTypeInterfaceInfo, + /// + /// The alternative interface ID for the + /// communication device this EFI IPv6 Configuration Protocol + /// instance manages if the link local IPv6 address generated from + /// the interfaced ID based on the default source the EFI IPv6 + /// Protocol uses is a duplicate address. The length of the interface + /// ID is 64 bit. The corresponding Data is of type + /// EFI_IP6_CONFIG_INTERFACE_ID. + /// + Ip6ConfigDataTypeAltInterfaceId, + /// + /// The general configuration policy for the EFI IPv6 network + /// stack running on the communication device this EFI IPv6 + /// Configuration Protocol instance manages. The policy will affect + /// other configuration settings. The corresponding Data is of type + /// EFI_IP6_CONFIG_POLICY. + /// + Ip6ConfigDataTypePolicy, + /// + /// The number of consecutive + /// Neighbor Solicitation messages sent while performing Duplicate + /// Address Detection on a tentative address. A value of zero + /// indicates that Duplicate Address Detection will not be performed + /// on tentative addresses. The corresponding Data is of type + /// EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS. + /// + Ip6ConfigDataTypeDupAddrDetectTransmits, + /// + /// The station addresses set manually for the EFI + /// IPv6 network stack. It is only configurable when the policy is + /// Ip6ConfigPolicyManual. The corresponding Data is a + /// pointer to an array of EFI_IPv6_ADDRESS instances. + /// + Ip6ConfigDataTypeManualAddress, + /// + /// The gateway addresses set manually for the EFI IPv6 + /// network stack running on the communication device this EFI + /// IPv6 Configuration Protocol manages. It is not configurable when + /// the policy is Ip6ConfigPolicyAutomatic. The gateway + /// addresses must be unicast IPv6 addresses. The corresponding + /// Data is a pointer to an array of EFI_IPv6_ADDRESS instances. + /// + Ip6ConfigDataTypeGateway, + /// + /// The DNS server list for the EFI IPv6 network stack + /// running on the communication device this EFI IPv6 + /// Configuration Protocol manages. It is not configurable when the + /// policy is Ip6ConfigPolicyAutomatic.The DNS server + /// addresses must be unicast IPv6 addresses. The corresponding + /// Data is a pointer to an array of EFI_IPv6_ADDRESS instances. + /// + Ip6ConfigDataTypeDnsServer, + /// + /// The number of this enumeration memebers. + /// + Ip6ConfigDataTypeMaximum +} EFI_IP6_CONFIG_DATA_TYPE; + +/// +/// EFI_IP6_CONFIG_INTERFACE_INFO +/// describes the operational state of the interface this +/// EFI IPv6 Configuration Protocol instance manages. +/// +typedef struct { + /// + /// The name of the interface. It is a NULL-terminated string. + /// + CHAR16 Name[32]; + /// + /// The interface type of the network interface. + /// + UINT8 IfType; + /// + /// The size, in bytes, of the network interface's hardware address. + /// + UINT32 HwAddressSize; + /// + /// The hardware address for the network interface. + /// + EFI_MAC_ADDRESS HwAddress; + /// + /// Number of EFI_IP6_ADDRESS_INFO structures pointed to by AddressInfo. + /// + UINT32 AddressInfoCount; + /// + /// Pointer to an array of EFI_IP6_ADDRESS_INFO instances + /// which contain the local IPv6 addresses and the corresponding + /// prefix length information. Set to NULL if AddressInfoCount + /// is zero. + /// + EFI_IP6_ADDRESS_INFO *AddressInfo; + /// + /// Number of route table entries in the following RouteTable. + /// + UINT32 RouteCount; + /// + /// The route table of the IPv6 network stack runs on this interface. + /// Set to NULL if RouteCount is zero. + /// + EFI_IP6_ROUTE_TABLE *RouteTable; +} EFI_IP6_CONFIG_INTERFACE_INFO; + +/// +/// EFI_IP6_CONFIG_INTERFACE_ID +/// describes the 64-bit interface ID. +/// +typedef struct { + UINT8 Id[8]; +} EFI_IP6_CONFIG_INTERFACE_ID; + +/// +/// EFI_IP6_CONFIG_POLICY +/// defines the general configuration policy the EFI IPv6 +/// Configuration Protocol supports. +/// +typedef enum { + /// + /// Under this policy, the IpI6ConfigDataTypeManualAddress, + /// Ip6ConfigDataTypeGateway and Ip6ConfigDataTypeDnsServer + /// configuration data are required to be set manually. + /// The EFI IPv6 Protocol will get all required configuration + /// such as address, prefix and gateway settings from the EFI + /// IPv6 Configuration protocol. + /// + Ip6ConfigPolicyManual, + /// + /// Under this policy, the IpI6ConfigDataTypeManualAddress, + /// Ip6ConfigDataTypeGateway and Ip6ConfigDataTypeDnsServer + /// configuration data are not allowed to set via SetData(). + /// All of these configurations are retrieved from some auto + /// configuration mechanism. + /// The EFI IPv6 Protocol will use the IPv6 stateless address + /// autoconfiguration mechanism and/or the IPv6 stateful address + /// autoconfiguration mechanism described in the related RFCs to + /// get address and other configuration information + /// + Ip6ConfigPolicyAutomatic +} EFI_IP6_CONFIG_POLICY; + +/// +/// EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS +/// describes the number of consecutive Neighbor Solicitation messages sent +/// while performing Duplicate Address Detection on a tentative address. +/// The default value for a newly detected communication device is 1. +/// +typedef struct { + UINT32 DupAddrDetectTransmits; ///< The number of consecutive Neighbor Solicitation messages sent. +} EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS; + +/// +/// EFI_IP6_CONFIG_MANUAL_ADDRESS +/// is used to set the station address information for the EFI IPv6 network +/// stack manually when the policy is Ip6ConfigPolicyManual. +/// +typedef struct { + EFI_IPv6_ADDRESS Address; ///< The IPv6 unicast address. + BOOLEAN IsAnycast; ///< Set to TRUE if Address is anycast. + UINT8 PrefixLength; ///< The length, in bits, of the prefix associated with this Address. +} EFI_IP6_CONFIG_MANUAL_ADDRESS; + + +/** + Set the configuration for the EFI IPv6 network stack running on the communication + device this EFI IPv6 Configuration Protocol instance manages. + + This function is used to set the configuration data of type DataType for the EFI + IPv6 network stack running on the communication device this EFI IPv6 Configuration + Protocol instance manages. + + The DataSize is used to calculate the count of structure instances in the Data for + some DataType that multiple structure instances are allowed. + + This function is always non-blocking. When setting some type of configuration data, + an asynchronous process is invoked to check the correctness of the data, such as + doing Duplicate Address Detection on the manually set local IPv6 addresses. + EFI_NOT_READY is returned immediately to indicate that such an asynchronous process + is invoked and the process is not finished yet. The caller willing to get the result + of the asynchronous process is required to call RegisterDataNotify() to register an + event on the specified configuration data. Once the event is signaled, the caller + can call GetData() to get back the configuration data in order to know the result. + For other types of configuration data that do not require an asynchronous configuration + process, the result of the operation is immediately returned. + + @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to set. + @param[in] DataSize Size of the buffer pointed to by Data in bytes. + @param[in] Data The data buffer to set. The type of the data buffer is + associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data for the EFI IPv6 + network stack is set successfully. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - Data is NULL. + - One or more fields in Data do not match the requirement of the + data type indicated by DataType. + @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified + configuration data can not be set under the current policy + @retval EFI_ACCESS_DENIED Another set operation on the specified configuration + data is already in process. + @retval EFI_NOT_READY An asynchronous process is invoked to set the specified + configuration data and the process is not finished yet. + @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type + indicated by DataType. + @retval EFI_UNSUPPORTED This DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIG_SET_DATA)( + IN EFI_IP6_CONFIG_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA_TYPE DataType, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Get the configuration data for the EFI IPv6 network stack running on the communication + device this EFI IPv6 Configuration Protocol instance manages. + + This function returns the configuration data of type DataType for the EFI IPv6 network + stack running on the communication device this EFI IPv6 Configuration Protocol instance + manages. + + The caller is responsible for allocating the buffer used to return the specified + configuration data and the required size will be returned to the caller if the size of + the buffer is too small. + + EFI_NOT_READY is returned if the specified configuration data is not ready due to an + already in progress asynchronous configuration process. The caller can call RegisterDataNotify() + to register an event on the specified configuration data. Once the asynchronous configuration + process is finished, the event will be signaled and a subsequent GetData() call will return + the specified configuration data. + + @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to get. + @param[in,out] DataSize On input, in bytes, the size of Data. On output, in bytes, the + size of buffer required to store the specified configuration data. + @param[in] Data The data buffer in which the configuration data is returned. The + type of the data buffer is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data is got successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + - This is NULL. + - DataSize is NULL. + - Data is NULL if *DataSize is not zero. + @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data + and the required size is returned in DataSize. + @retval EFI_NOT_READY The specified configuration data is not ready due to an already in + progress asynchronous configuration process. + @retval EFI_NOT_FOUND The specified configuration data is not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIG_GET_DATA)( + IN EFI_IP6_CONFIG_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA_TYPE DataType, + IN OUT UINTN *DataSize, + IN VOID *Data OPTIONAL + ); + +/** + Register an event that is to be signaled whenever a configuration process on the specified + configuration data is done. + + This function registers an event that is to be signaled whenever a configuration process + on the specified configuration data is done. An event can be registered for different DataType + simultaneously and the caller is responsible for determining which type of configuration data + causes the signaling of the event in such case. + + @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to unregister the event for. + @param[in] Event The event to register. + + @retval EFI_SUCCESS The notification event for the specified configuration data is + registered. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not + supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIG_REGISTER_NOTIFY)( + IN EFI_IP6_CONFIG_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/** + Remove a previously registered event for the specified configuration data. + + This function removes a previously registered event for the specified configuration data. + + @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to remove the previously registered event for. + @param[in] Event The event to unregister. + + @retval EFI_SUCCESS The event registered for the specified configuration data is removed. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_NOT_FOUND The Event has not been registered for the specified + DataType. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIG_UNREGISTER_NOTIFY)( + IN EFI_IP6_CONFIG_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/// +/// The EFI_IP6_CONFIG_PROTOCOL provides the mechanism to set and get various +/// types of configurations for the EFI IPv6 network stack. +/// +struct _EFI_IP6_CONFIG_PROTOCOL { + EFI_IP6_CONFIG_SET_DATA SetData; + EFI_IP6_CONFIG_GET_DATA GetData; + EFI_IP6_CONFIG_REGISTER_NOTIFY RegisterDataNotify; + EFI_IP6_CONFIG_UNREGISTER_NOTIFY UnregisterDataNotify; +}; + +#endif -- 2.7.1 From 06e5348c1de053a0a07583a83629b21561ec2caa Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Wed, 14 Oct 2015 17:04:10 +0800 Subject: [PATCH 3/3] Add the optional HTTPBoot support This commit adds the basic support for HTTPBoot, i.e. to fetch the next stage loader with the HTTP protocol. It requires gnu-efi >= 3.0.3 to support the URI device path and Ip4Config2 or Ip6Config protocol support in the UEFI implementation. To build shim.efi with HTTPBoot support: make ENABLE_HTTPBOOT=1 shim.efi Signed-off-by: Gary Ching-Pang Lin --- Makefile | 9 + httpboot.c | 774 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ httpboot.h | 41 ++++ shim.c | 12 + 4 files changed, 836 insertions(+) create mode 100644 httpboot.c create mode 100644 httpboot.h diff --git a/Makefile b/Makefile index 2c3d554..f636500 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,10 @@ ifneq ($(origin OVERRIDE_SECURITY_POLICY), undefined) CFLAGS += -DOVERRIDE_SECURITY_POLICY endif +ifneq ($(origin ENABLE_HTTPBOOT), undefined) + CFLAGS += -DENABLE_HTTPBOOT +endif + ifeq ($(ARCH),x86_64) CFLAGS += -mno-mmx -mno-sse -mno-red-zone -nostdinc \ -maccumulate-outgoing-args \ @@ -75,6 +79,11 @@ MOK_SOURCES = MokManager.c shim.h include/console.h PasswordCrypt.c PasswordCryp FALLBACK_OBJS = fallback.o FALLBACK_SRCS = fallback.c +ifneq ($(origin ENABLE_HTTPBOOT), undefined) + OBJS += httpboot.o + SOURCES += httpboot.c httpboot.h +endif + all: $(TARGET) shim.crt: diff --git a/httpboot.c b/httpboot.c new file mode 100644 index 0000000..ad01b8d --- /dev/null +++ b/httpboot.c @@ -0,0 +1,774 @@ +/* + * Copyright 2015 SUSE LINUX GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Significant portions of this code are derived from Tianocore + * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel + * Corporation. + */ + +#include +#include +#include "str.h" +#include "Http.h" +#include "Ip4Config2.h" +#include "Ip6Config.h" + +extern UINT8 in_protocol; + +#define perror(fmt, ...) ({ \ + UINTN __perror_ret = 0; \ + if (!in_protocol) \ + __perror_ret = Print((fmt), ##__VA_ARGS__); \ + __perror_ret; \ + }) + +static UINTN +ascii_to_int (CONST CHAR8 *str) +{ + UINTN u; + CHAR8 c; + + // skip preceeding white space + while (*str && *str == ' ') { + str += 1; + } + + // convert digits + u = 0; + while ((c = *(str++))) { + if (c >= '0' && c <= '9') { + u = (u * 10) + c - '0'; + } else { + break; + } + } + + return u; +} + +static UINTN +convert_http_status_code (EFI_HTTP_STATUS_CODE status_code) +{ + if (status_code >= HTTP_STATUS_100_CONTINUE && + status_code < HTTP_STATUS_200_OK) { + return (status_code - HTTP_STATUS_100_CONTINUE + 100); + } else if (status_code >= HTTP_STATUS_200_OK && + status_code < HTTP_STATUS_300_MULTIPLE_CHIOCES) { + return (status_code - HTTP_STATUS_200_OK + 200); + } else if (status_code >= HTTP_STATUS_300_MULTIPLE_CHIOCES && + status_code < HTTP_STATUS_400_BAD_REQUEST) { + return (status_code - HTTP_STATUS_300_MULTIPLE_CHIOCES + 300); + } else if (status_code >= HTTP_STATUS_400_BAD_REQUEST && + status_code < HTTP_STATUS_500_INTERNAL_SERVER_ERROR) { + return (status_code - HTTP_STATUS_400_BAD_REQUEST + 400); + } else if (status_code >= HTTP_STATUS_500_INTERNAL_SERVER_ERROR) { + return (status_code - HTTP_STATUS_500_INTERNAL_SERVER_ERROR + 500); + } + + return 0; +} + +static EFI_DEVICE_PATH *devpath; +static EFI_MAC_ADDRESS mac_addr; +static IPv4_DEVICE_PATH ip4_node; +static IPv6_DEVICE_PATH ip6_node; +static BOOLEAN is_ip6; +static CHAR8 *uri; + +BOOLEAN +find_httpboot (EFI_HANDLE device) +{ + EFI_DEVICE_PATH *unpacked; + EFI_DEVICE_PATH *Node; + EFI_DEVICE_PATH *NextNode; + MAC_ADDR_DEVICE_PATH *MacNode; + URI_DEVICE_PATH *UriNode; + UINTN uri_size; + + if (!uri) + FreePool(uri); + + devpath = DevicePathFromHandle(device); + if (!devpath) { + perror(L"Failed to get device path\n"); + return FALSE; + } + + unpacked = UnpackDevicePath(devpath); + if (!unpacked) { + perror(L"Failed to unpack device path\n"); + return FALSE; + } + Node = unpacked; + + /* Traverse the device path to find IPv4()/Uri() or IPv6()/Uri() */ + while (!IsDevicePathEnd(Node)) { + /* Save the MAC node so we can match the net card later */ + if (DevicePathType(Node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(Node) == MSG_MAC_ADDR_DP) { + MacNode = (MAC_ADDR_DEVICE_PATH *)Node; + CopyMem(&mac_addr, &MacNode->MacAddress, sizeof(EFI_MAC_ADDRESS)); + } + + if (DevicePathType(Node) == MESSAGING_DEVICE_PATH && + (DevicePathSubType(Node) == MSG_IPv4_DP || + DevicePathSubType(Node) == MSG_IPv6_DP)) { + /* Save the IP node so we can set up the connection later */ + if (DevicePathSubType(Node) == MSG_IPv6_DP) { + CopyMem(&ip6_node, Node, sizeof(IPv6_DEVICE_PATH)); + is_ip6 = TRUE; + } else { + CopyMem(&ip4_node, Node, sizeof(IPv4_DEVICE_PATH)); + is_ip6 = FALSE; + } + + Node = NextDevicePathNode(Node); + NextNode = NextDevicePathNode(Node); + if (DevicePathType(Node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(Node) == MSG_URI_DP && + IsDevicePathEnd(NextNode)) { + /* Save the current URI */ + UriNode = (URI_DEVICE_PATH *)Node; + uri_size = strlena(UriNode->Uri); + uri = AllocatePool(uri_size + 1); + if (!uri) { + perror(L"Failed to allocate uri\n"); + return FALSE; + } + CopyMem(uri, UriNode->Uri, uri_size + 1); + FreePool(unpacked); + return TRUE; + } + } + Node = NextDevicePathNode(Node); + } + + FreePool(unpacked); + return FALSE; +} + +static EFI_STATUS +generate_next_uri (CONST CHAR8 *current_uri, CONST CHAR8 *next_loader, + CHAR8 **uri) +{ + CONST CHAR8 *ptr; + UINTN next_len; + UINTN path_len = 0; + UINTN count = 0; + + if (strncmpa(current_uri, (CHAR8 *)"http://", 7) == 0) { + ptr = current_uri + 7; + count += 7; + } else { + return EFI_INVALID_PARAMETER; + } + + /* Extract the path */ + next_len = strlena(next_loader); + while (*ptr != '\0') { + count++; + if (*ptr == '/') + path_len = count; + ptr++; + } + + *uri = AllocatePool(sizeof(CHAR8) * (path_len + next_len + 1)); + if (!*uri) + return EFI_OUT_OF_RESOURCES; + + CopyMem(*uri, current_uri, path_len); + CopyMem(*uri + path_len, next_loader, next_len); + (*uri)[path_len + next_len] = '\0'; + + return EFI_SUCCESS; +} + +static EFI_STATUS +extract_hostname (CONST CHAR8 *url, CHAR8 **hostname) +{ + CONST CHAR8 *ptr, *start; + UINTN host_len = 0; + + if (strncmpa(url, (CHAR8 *)"http://", 7) == 0) + start = url + 7; + else + return EFI_INVALID_PARAMETER; + + ptr = start; + while (*ptr != '/' && *ptr != '\0') { + host_len++; + ptr++; + } + + *hostname = AllocatePool(sizeof(CHAR8) * (host_len + 1)); + if (!*hostname) + return EFI_OUT_OF_RESOURCES; + + CopyMem(*hostname, start, host_len); + (*hostname)[host_len] = '\0'; + + return EFI_SUCCESS; +} + +#define SAME_MAC_ADDR(a, b) (!CompareMem(a, b, sizeof(EFI_MAC_ADDRESS))) + +static EFI_HANDLE +get_nic_handle (EFI_MAC_ADDRESS *mac) +{ + EFI_GUID http_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; + EFI_DEVICE_PATH *unpacked = NULL; + EFI_DEVICE_PATH *Node; + EFI_DEVICE_PATH *temp_path = NULL; + MAC_ADDR_DEVICE_PATH *MacNode; + EFI_HANDLE handle = NULL; + EFI_HANDLE *buffer; + UINTN NoHandles; + UINTN i; + EFI_STATUS status; + + /* Get the list of handles that support the HTTP service binding + protocol */ + status = uefi_call_wrapper(BS->LocateHandleBuffer, 5, + ByProtocol, + &http_binding_guid, + NULL, + &NoHandles, + &buffer); + if (EFI_ERROR(status)) + return NULL; + + for (i = 0; i < NoHandles; i++) { + temp_path = DevicePathFromHandle(buffer[i]); + + /* Match the MAC address */ + unpacked = UnpackDevicePath(temp_path); + if (!unpacked) { + perror(L"Failed to unpack device path\n"); + continue; + } + Node = unpacked; + while (!IsDevicePathEnd(Node)) { + if (DevicePathType(Node) == MESSAGING_DEVICE_PATH && + DevicePathSubType(Node) == MSG_MAC_ADDR_DP) { + MacNode = (MAC_ADDR_DEVICE_PATH *)Node; + if (SAME_MAC_ADDR(mac, &MacNode->MacAddress)) { + handle = buffer[i]; + goto out; + } + } + Node = NextDevicePathNode(Node); + } + FreePool(unpacked); + unpacked = NULL; + } + +out: + if (unpacked) + FreePool(unpacked); + FreePool(buffer); + + return handle; +} + +static BOOLEAN +is_unspecified_addr (EFI_IPv6_ADDRESS ip6) +{ + UINT8 i; + + for (i = 0; i<16; i++) { + if (ip6.Addr[i] != 0) + return FALSE; + } + + return TRUE; +} + +static EFI_STATUS +set_ip6(EFI_HANDLE *nic, IPv6_DEVICE_PATH *ip6node) +{ + EFI_GUID ip6_config_guid = EFI_IP6_CONFIG_PROTOCOL_GUID; + EFI_IP6_CONFIG_PROTOCOL *ip6cfg; + EFI_IP6_CONFIG_MANUAL_ADDRESS ip6; + EFI_IPv6_ADDRESS gateway; + EFI_STATUS status; + + status = uefi_call_wrapper(BS->HandleProtocol, 3, + nic, + &ip6_config_guid, + (VOID **)&ip6cfg); + if (EFI_ERROR (status)) + return status; + + ip6.Address = ip6node->LocalIpAddress; + ip6.PrefixLength = ip6node->PrefixLength; + ip6.IsAnycast = FALSE; + status = uefi_call_wrapper(ip6cfg->SetData, 4, + ip6cfg, + Ip6ConfigDataTypeManualAddress, + sizeof(ip6), + &ip6); + if (EFI_ERROR (status)) + return status; + + gateway = ip6node->GatewayIpAddress; + if (is_unspecified_addr(gateway)) + return EFI_SUCCESS; + + status = uefi_call_wrapper(ip6cfg->SetData, 4, + ip6cfg, + Ip6ConfigDataTypeGateway, + sizeof(gateway), + &gateway); + if (EFI_ERROR (status)) + return status; + + return EFI_SUCCESS; +} + +static EFI_STATUS +set_ip4(EFI_HANDLE *nic, IPv4_DEVICE_PATH *ip4node) +{ + EFI_GUID ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID; + EFI_IP4_CONFIG2_PROTOCOL *ip4cfg2; + EFI_IP4_CONFIG2_MANUAL_ADDRESS ip4; + EFI_IPv4_ADDRESS gateway; + EFI_STATUS status; + + status = uefi_call_wrapper(BS->HandleProtocol, 3, + nic, + &ip4_config2_guid, + (VOID **)&ip4cfg2); + if (EFI_ERROR (status)) + return status; + + ip4.Address = ip4node->LocalIpAddress; + ip4.SubnetMask = ip4node->SubnetMask; + status = uefi_call_wrapper(ip4cfg2->SetData, 4, + ip4cfg2, + Ip4Config2DataTypeManualAddress, + sizeof(ip4), + &ip4); + if (EFI_ERROR (status)) + return status; + + gateway = ip4node->GatewayIpAddress; + status = uefi_call_wrapper(ip4cfg2->SetData, 4, + ip4cfg2, + Ip4Config2DataTypeGateway, + sizeof(gateway), + &gateway); + if (EFI_ERROR (status)) + return status; + + return EFI_SUCCESS; +} + +static VOID EFIAPI +httpnotify (EFI_EVENT Event, VOID *Context) +{ + *((BOOLEAN *) Context) = TRUE; +} + +static EFI_STATUS +configure_http (EFI_HTTP_PROTOCOL *http, BOOLEAN is_ip6) +{ + EFI_HTTP_CONFIG_DATA http_mode; + EFI_HTTPv4_ACCESS_POINT ip4node; + EFI_HTTPv6_ACCESS_POINT ip6node; + + /* Configure HTTP */ + ZeroMem(&http_mode, sizeof(http_mode)); + http_mode.HttpVersion = HttpVersion11; + /* use the default time out */ + http_mode.TimeOutMillisec = 0; + + if (!is_ip6) { + http_mode.LocalAddressIsIPv6 = FALSE; + ZeroMem(&ip4node, sizeof(ip4node)); + ip4node.UseDefaultAddress = TRUE; + http_mode.AccessPoint.IPv4Node = &ip4node; + } else { + http_mode.LocalAddressIsIPv6 = TRUE; + ZeroMem(&ip6node, sizeof(ip6node)); + http_mode.AccessPoint.IPv6Node = &ip6node; + } + + return uefi_call_wrapper(http->Configure, 2, http, &http_mode); +} + +static EFI_STATUS +send_http_request (EFI_HTTP_PROTOCOL *http, CHAR8 *hostname, CHAR8 *uri) +{ + EFI_HTTP_TOKEN tx_token; + EFI_HTTP_MESSAGE tx_message; + EFI_HTTP_REQUEST_DATA request; + EFI_HTTP_HEADER headers[3]; + BOOLEAN request_done; + CHAR16 *Url = NULL; + EFI_STATUS status; + EFI_STATUS event_status; + + /* Convert the ascii string to the UCS2 string */ + Url = PoolPrint(L"%a", uri); + if (!Url) + return EFI_OUT_OF_RESOURCES; + + request.Method = HttpMethodGet; + request.Url = Url; + + /* Prepare the HTTP headers */ + headers[0].FieldName = (CHAR8 *)"Host"; + headers[0].FieldValue = hostname; + headers[1].FieldName = (CHAR8 *)"Accept"; + headers[1].FieldValue = (CHAR8 *)"*/*"; + headers[2].FieldName = (CHAR8 *)"User-Agent"; + headers[2].FieldValue = (CHAR8 *)"UefiHttpBoot/1.0"; + + tx_message.Data.Request = &request; + tx_message.HeaderCount = 3; + tx_message.Headers = headers; + tx_message.BodyLength = 0; + tx_message.Body = NULL; + + tx_token.Status = EFI_NOT_READY; + tx_token.Message = &tx_message; + tx_token.Event = NULL; + request_done = FALSE; + status = uefi_call_wrapper(BS->CreateEvent, 5, + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + httpnotify, + &request_done, + &tx_token.Event); + if (EFI_ERROR(status)) { + perror(L"Failed to Create Event for HTTP request: %r\n", status); + goto no_event; + } + + /* Send out the request */ + status = uefi_call_wrapper(http->Request, 2, http, &tx_token); + if (EFI_ERROR(status)) { + perror(L"HTTP request failed: %r\n", status); + goto error; + } + + /* Wait for the response */ + while (!request_done) + uefi_call_wrapper(http->Poll, 1, http); + + if (EFI_ERROR(tx_token.Status)) { + perror(L"HTTP request: %r\n", tx_token.Status); + status = tx_token.Status; + } + +error: + event_status = uefi_call_wrapper(BS->CloseEvent, 1, tx_token.Event); + if (EFI_ERROR(event_status)) { + perror(L"Failed to close Event for HTTP request: %r\n", + event_status); + } + +no_event: + if (Url) + FreePool(Url); + + return status; +} + +static EFI_STATUS +receive_http_response(EFI_HTTP_PROTOCOL *http, VOID **buffer, UINTN *buf_size) +{ + EFI_HTTP_TOKEN rx_token; + EFI_HTTP_MESSAGE rx_message; + EFI_HTTP_RESPONSE_DATA response; + EFI_HTTP_STATUS_CODE http_status; + BOOLEAN response_done; + UINTN i, downloaded; + CHAR8 rx_buffer[9216]; + EFI_STATUS status; + EFI_STATUS event_status; + + /* Initialize the rx message and buffer */ + response.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS; + rx_message.Data.Response = &response; + rx_message.HeaderCount = 0; + rx_message.Headers = 0; + rx_message.BodyLength = sizeof(rx_buffer); + rx_message.Body = rx_buffer; + + rx_token.Status = EFI_NOT_READY; + rx_token.Message = &rx_message; + rx_token.Event = NULL; + response_done = FALSE; + status = uefi_call_wrapper(BS->CreateEvent, 5, + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + httpnotify, + &response_done, + &rx_token.Event); + if (EFI_ERROR(status)) { + perror(L"Failed to Create Event for HTTP response: %r\n", status); + goto no_event; + } + + /* Notify the firmware to receive the HTTP messages */ + status = uefi_call_wrapper(http->Response, 2, http, &rx_token); + if (EFI_ERROR(status)) { + perror(L"HTTP response failed: %r\n", status); + goto error; + } + + /* Wait for the response */ + while (!response_done) + uefi_call_wrapper(http->Poll, 1, http); + + if (EFI_ERROR(rx_token.Status)) { + perror(L"HTTP response: %r\n", rx_token.Status); + status = rx_token.Status; + goto error; + } + + /* Check the HTTP status code */ + http_status = rx_token.Message->Data.Response->StatusCode; + if (http_status != HTTP_STATUS_200_OK) { + perror(L"HTTP Status Code: %d\n", + convert_http_status_code(http_status)); + status = EFI_ABORTED; + goto error; + } + + /* Check the length of the file */ + for (i = 0; i < rx_message.HeaderCount; i++) { + if (!strcmpa(rx_message.Headers[i].FieldName, (CHAR8 *)"Content-Length")) { + *buf_size = ascii_to_int(rx_message.Headers[i].FieldValue); + } + } + + if (*buf_size == 0) { + perror(L"Failed to get Content-Lenght\n"); + goto error; + } + + *buffer = AllocatePool(*buf_size); + if (!*buffer) { + perror(L"Failed to allocate new rx buffer\n"); + goto error; + } + + downloaded = rx_message.BodyLength; + + CopyMem(*buffer, rx_buffer, downloaded); + + /* Retreive the rest of the message */ + while (downloaded < *buf_size) { + if (rx_message.Headers) { + FreePool(rx_message.Headers); + } + rx_message.Headers = NULL; + rx_message.HeaderCount = 0; + rx_message.Data.Response = NULL; + rx_message.BodyLength = sizeof(rx_buffer); + rx_message.Body = rx_buffer; + + rx_token.Status = EFI_NOT_READY; + response_done = FALSE; + + status = uefi_call_wrapper(http->Response, 2, http, &rx_token); + if (EFI_ERROR(status)) { + perror(L"HTTP response failed: %r\n", status); + goto error; + } + + while (!response_done) + uefi_call_wrapper(http->Poll, 1, http); + + if (EFI_ERROR(rx_token.Status)) { + perror(L"HTTP response: %r\n", rx_token.Status); + status = rx_token.Status; + goto error; + } + + if (rx_message.BodyLength + downloaded > *buf_size) { + status = EFI_BAD_BUFFER_SIZE; + goto error; + } + + CopyMem(*buffer + downloaded, rx_buffer, rx_message.BodyLength); + + downloaded += rx_message.BodyLength; + } + +error: + event_status = uefi_call_wrapper(BS->CloseEvent, 1, rx_token.Event); + if (EFI_ERROR(event_status)) { + perror(L"Failed to close Event for HTTP response: %r\n", + event_status); + } + +no_event: + if (EFI_ERROR(status) && *buffer) + FreePool(*buffer); + + return status; +} + +static EFI_STATUS +http_fetch (EFI_HANDLE image, EFI_HANDLE device, + CHAR8 *hostname, CHAR8 *uri, BOOLEAN is_ip6, + VOID **buffer, UINTN *buf_size) +{ + EFI_GUID http_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; + EFI_GUID http_protocol_guid = EFI_HTTP_PROTOCOL_GUID; + EFI_SERVICE_BINDING *service; + EFI_HANDLE http_handle; + EFI_HTTP_PROTOCOL *http; + EFI_STATUS status; + EFI_STATUS child_status; + + *buffer = NULL; + *buf_size = 0; + + /* Open HTTP Service Binding Protocol */ + status = uefi_call_wrapper(BS->OpenProtocol, 6, device, + &http_binding_guid, (VOID **)&service, + image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (status)) + return status; + + /* Create the ChildHandle from the Service Binding */ + /* Set the handle to NULL to request a new handle */ + http_handle = NULL; + status = uefi_call_wrapper(service->CreateChild, 2, service, + &http_handle); + if (EFI_ERROR (status)) + return status; + + /* Get the http protocol */ + status = uefi_call_wrapper(BS->HandleProtocol, 3, http_handle, + &http_protocol_guid, (VOID **)&http); + if (EFI_ERROR (status)) { + perror(L"Failed to get http\n"); + goto error; + } + + status = configure_http(http, is_ip6); + if (EFI_ERROR (status)) { + perror(L"Failed to configure http: %r\n", status); + goto error; + } + + status = send_http_request(http, hostname, uri); + if (EFI_ERROR(status)) { + perror(L"Failed to send HTTP request: %r\n", status); + goto error; + } + + status = receive_http_response(http, buffer, buf_size); + if (EFI_ERROR(status)) { + perror(L"Failed to receive HTTP response: %r\n", status); + goto error; + } + +error: + child_status = uefi_call_wrapper(service->DestroyChild, 2, service, + http_handle); + + if (EFI_ERROR(status)) { + return status; + } else if (EFI_ERROR(child_status)) { + return child_status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +httpboot_fetch_buffer (EFI_HANDLE image, VOID **buffer, UINTN *buf_size) +{ + EFI_STATUS status; + EFI_HANDLE nic; + CHAR8 *next_loader = NULL; + CHAR8 *next_uri = NULL; + CHAR8 *hostname = NULL; + + if (!uri) + return EFI_NOT_READY; + + next_loader = translate_slashes(DEFAULT_LOADER_CHAR); + + /* Create the URI for the next loader based on the original URI */ + status = generate_next_uri(uri, next_loader, &next_uri); + if (EFI_ERROR (status)) { + perror(L"Next URI: %a, %r\n", next_uri, status); + goto error; + } + + /* Extract the hostname (or IP) from URI */ + status = extract_hostname(uri, &hostname); + if (EFI_ERROR (status)) { + perror(L"hostname: %a, %r\n", hostname, status); + goto error; + } + + /* Get the handle that associates with the NIC we are using and + also supports the HTTP service binding protocol */ + nic = get_nic_handle(&mac_addr); + if (!nic) { + goto error; + } + + /* UEFI stops DHCP after fetching the image and stores the related + information in the device path node. We have to set up the + connection on our own for the further operations. */ + if (!is_ip6) + status = set_ip4(nic, &ip4_node); + else + status = set_ip6(nic, &ip6_node); + if (EFI_ERROR (status)) { + perror(L"Failed to set IP for HTTPBoot: %r\n", status); + goto error; + } + + /* Use HTTP protocl to fetch the remote file */ + status = http_fetch (image, nic, hostname, next_uri, is_ip6, + buffer, buf_size); + if (EFI_ERROR (status)) { + perror(L"Failed to fetch image: %r\n", status); + goto error; + } + +error: + FreePool(uri); + uri = NULL; + if (next_uri) + FreePool(next_uri); + if (hostname) + FreePool(hostname); + + return status; +} diff --git a/httpboot.h b/httpboot.h new file mode 100644 index 0000000..79ee465 --- /dev/null +++ b/httpboot.h @@ -0,0 +1,41 @@ +/* + * Copyright 2015 SUSE LINUX GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Significant portions of this code are derived from Tianocore + * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel + * Corporation. + */ + +#ifndef _HTTPBOOT_H_ +#define _HTTPBOOT_H_ + +BOOLEAN find_httpboot (EFI_DEVICE_PATH *devpath); + +EFI_STATUS httpboot_fetch_buffer (EFI_HANDLE image, VOID **buffer, UINTN *buf_size); + +#endif diff --git a/shim.c b/shim.c index c93d96d..0e42a7b 100644 --- a/shim.c +++ b/shim.c @@ -39,6 +39,7 @@ #include "PeImage.h" #include "shim.h" #include "netboot.h" +#include "httpboot.h" #include "shim_cert.h" #include "replacements.h" #include "ucs2.h" @@ -1651,6 +1652,17 @@ EFI_STATUS start_image(EFI_HANDLE image_handle, CHAR16 *ImagePath) } data = sourcebuffer; datasize = sourcesize; +#if defined(ENABLE_HTTPBOOT) + } else if (find_httpboot(li->DeviceHandle)) { + efi_status = httpboot_fetch_buffer (image_handle, &sourcebuffer, + &sourcesize); + if (efi_status != EFI_SUCCESS) { + perror(L"Unable to fetch HTTP image: %r\n", efi_status); + return efi_status; + } + data = sourcebuffer; + datasize = sourcesize; +#endif } else { /* * Read the new executable off disk -- 2.7.1