Index: stand/efi/include/Protocol/Http.h
===================================================================
--- /dev/null
+++ stand/efi/include/Protocol/Http.h
@@ -0,0 +1,523 @@
+/* $FreeBSD$ */
+/** @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 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2017 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_CHOICES,
+ 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,
+ HTTP_STATUS_308_PERMANENT_REDIRECT
+} 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. It is the responsibility of the caller
+ to allocate the memory for HttpConfigData and
+ HttpConfigData->AccessPoint.IPv6Node/IPv4Node. In fact,
+ it is recommended to allocate sufficient memory to record
+ IPv6Node since it is big enough for all possibilities.
+
+ @retval EFI_SUCCESS Operation succeeded.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ HttpConfigData is NULL.
+ HttpConfigData->AccessPoint.IPv4Node or
+ HttpConfigData->AccessPoint.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->LocalAddressIsIPv6 is FALSE and
+ HttpConfigData->AccessPoint.IPv4Node is NULL.
+ HttpConfigData->LocalAddressIsIPv6 is TRUE and
+ HttpConfigData->AccessPoint.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 OPTIONAL
+ );
+
+/**
+ 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;
+};
+
+extern EFI_GUID gEfiHttpServiceBindingProtocolGuid;
+extern EFI_GUID gEfiHttpProtocolGuid;
+
+#endif
Index: stand/efi/include/Protocol/Ip4Config2.h
===================================================================
--- /dev/null
+++ stand/efi/include/Protocol/Ip4Config2.h
@@ -0,0 +1,324 @@
+/* $FreeBSD$ */
+/** @file
+ This file provides a definition of the EFI IPv4 Configuration II
+ Protocol.
+
+Copyright (c) 2015 - 2018, 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. When DataSize
+ /// is 0 and Data is NULL, the existing configuration is cleared
+ /// from the EFI IPv4 Configuration II Protocol instance.
+ ///
+ 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.
+ /// When DataSize is 0 and Data is NULL, the existing configuration
+ /// is cleared from the EFI IPv4 Configuration II Protocol instance.
+ ///
+ 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. When DataSize
+ /// is 0 and Data is NULL, the existing configuration is cleared
+ /// from the EFI IPv4 Configuration II Protocol instance.
+ ///
+ 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.
+ One or more fields in Data and DataSize 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;
+};
+
+extern EFI_GUID gEfiIp4Config2ProtocolGuid;
+
+#endif
+
Index: stand/efi/include/Protocol/ServiceBinding.h
===================================================================
--- /dev/null
+++ stand/efi/include/Protocol/ServiceBinding.h
@@ -0,0 +1,95 @@
+/* $FreeBSD$ */
+/** @file
+ UEFI Service Binding Protocol is defined in UEFI specification.
+
+ The file defines the generic Service Binding Protocol functions.
+ It provides services that are required to create and destroy child
+ handles that support a given set of protocols.
+
+ Copyright (c) 2006 - 2018, 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_SERVICE_BINDING_H__
+#define __EFI_SERVICE_BINDING_H__
+
+///
+/// Forward reference for pure ANSI compatibility
+///
+typedef struct _EFI_SERVICE_BINDING_PROTOCOL EFI_SERVICE_BINDING_PROTOCOL;
+
+/**
+ Creates a child handle and installs a protocol.
+
+ The CreateChild() function installs a protocol on ChildHandle.
+ If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
+ If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
+
+ @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param ChildHandle Pointer to the handle of the child to create. If it is NULL,
+ then a new handle is created. If it is a pointer to an existing UEFI handle,
+ then the protocol is added to the existing UEFI handle.
+
+ @retval EFI_SUCCES The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
+ the child
+ @retval other The child handle was not created
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SERVICE_BINDING_CREATE_CHILD)(
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ );
+
+/**
+ Destroys a child handle with a protocol installed on it.
+
+ The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
+ that was installed by CreateChild() from ChildHandle. If the removed protocol is the
+ last protocol on ChildHandle, then ChildHandle is destroyed.
+
+ @param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
+ @param ChildHandle Handle of the child to destroy
+
+ @retval EFI_SUCCES The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.
+ @retval EFI_INVALID_PARAMETER Child handle is NULL.
+ @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle
+ because its services are being used.
+ @retval other The child handle was not destroyed
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SERVICE_BINDING_DESTROY_CHILD)(
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+///
+/// The EFI_SERVICE_BINDING_PROTOCOL provides member functions to create and destroy
+/// child handles. A driver is responsible for adding protocols to the child handle
+/// in CreateChild() and removing protocols in DestroyChild(). It is also required
+/// that the CreateChild() function opens the parent protocol BY_CHILD_CONTROLLER
+/// to establish the parent-child relationship, and closes the protocol in DestroyChild().
+/// The pseudo code for CreateChild() and DestroyChild() is provided to specify the
+/// required behavior, not to specify the required implementation. Each consumer of
+/// a software protocol is responsible for calling CreateChild() when it requires the
+/// protocol and calling DestroyChild() when it is finished with that protocol.
+///
+struct _EFI_SERVICE_BINDING_PROTOCOL {
+ EFI_SERVICE_BINDING_CREATE_CHILD CreateChild;
+ EFI_SERVICE_BINDING_DESTROY_CHILD DestroyChild;
+};
+
+#endif
Index: stand/efi/include/efidevp.h
===================================================================
--- stand/efi/include/efidevp.h
+++ stand/efi/include/efidevp.h
@@ -232,6 +232,8 @@
UINT16 RemotePort;
UINT16 Protocol;
BOOLEAN StaticIpAddress;
+ EFI_IPv4_ADDRESS GatewayIpAddress;
+ EFI_IPv4_ADDRESS SubnetMask;
} IPv4_DEVICE_PATH;
#define MSG_IPv6_DP 0x0d
@@ -294,6 +296,26 @@
UINT16 Lun;
} SATA_DEVICE_PATH;
+
+/* DNS Device Path SubType */
+#define MSG_DNS_DP 0x1F
+typedef struct {
+ EFI_DEVICE_PATH Header;
+ /* Indicates the DNS server address is IPv4 or IPv6 address. */
+ UINT8 IsIPv6;
+ /* Instance of the DNS server address. */
+ /* XXX: actually EFI_IP_ADDRESS */
+ EFI_IPv4_ADDRESS DnsServerIp[];
+} DNS_DEVICE_PATH;
+
+/* Uniform Resource Identifiers (URI) Device Path SubType */
+#define MSG_URI_DP 0x18
+typedef struct {
+ EFI_DEVICE_PATH Header;
+ /* Instance of the URI pursuant to RFC 3986. */
+ CHAR8 Uri[];
+} URI_DEVICE_PATH;
+
#define MEDIA_DEVICE_PATH 0x04
#define MEDIA_HARDDRIVE_DP 0x01
Index: stand/efi/include/efilib.h
===================================================================
--- stand/efi/include/efilib.h
+++ stand/efi/include/efilib.h
@@ -42,6 +42,7 @@
extern struct devsw efipart_fddev;
extern struct devsw efipart_cddev;
extern struct devsw efipart_hddev;
+extern struct devsw efihttp_dev;
extern struct devsw efinet_dev;
extern struct netif_driver efinetif;
Index: stand/efi/libefi/Makefile
===================================================================
--- stand/efi/libefi/Makefile
+++ stand/efi/libefi/Makefile
@@ -12,6 +12,7 @@
efi_driver_utils.c \
efichar.c \
efienv.c \
+ efihttp.c \
efinet.c \
efipart.c \
efizfs.c \
Index: stand/efi/libefi/efihttp.c
===================================================================
--- /dev/null
+++ stand/efi/libefi/efihttp.c
@@ -0,0 +1,766 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 AUTHORS 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 AUTHORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include
+__FBSDID("$FreeBSD$");
+
+#include
+
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Poll timeout in milliseconds */
+static const int EFIHTTP_POLL_TIMEOUT = 300000;
+
+static EFI_GUID http_guid = EFI_HTTP_PROTOCOL_GUID;
+static EFI_GUID httpsb_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
+static EFI_GUID ip4config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
+
+static int efihttp_dev_init(void);
+static int efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size,
+ char *buf, size_t *rsize);
+static int efihttp_dev_open(struct open_file *f, ...);
+static int efihttp_dev_close(struct open_file *f);
+
+static int efihttp_fs_open(const char *path, struct open_file *f);
+static int efihttp_fs_close(struct open_file *f);
+static int efihttp_fs_read(struct open_file *f, void *buf, size_t size,
+ size_t *resid);
+static int efihttp_fs_write(struct open_file *f, const void *buf, size_t size,
+ size_t *resid);
+static off_t efihttp_fs_seek(struct open_file *f, off_t offset, int where);
+static int efihttp_fs_stat(struct open_file *f, struct stat *sb);
+static int efihttp_fs_readdir(struct open_file *f, struct dirent *d);
+
+struct open_efihttp {
+ EFI_HTTP_PROTOCOL *http;
+ EFI_HANDLE http_handle;
+ EFI_HANDLE dev_handle;
+ char *uri_base;
+};
+
+struct file_efihttp {
+ ssize_t size;
+ off_t offset;
+ char *path;
+ bool is_dir;
+};
+
+struct devsw efihttp_dev = {
+ .dv_name = "http",
+ .dv_type = DEVT_NET,
+ .dv_init = efihttp_dev_init,
+ .dv_strategy = efihttp_dev_strategy,
+ .dv_open = efihttp_dev_open,
+ .dv_close = efihttp_dev_close,
+ .dv_ioctl = noioctl,
+ .dv_print = NULL,
+ .dv_cleanup = NULL,
+};
+
+struct fs_ops efihttp_fsops = {
+ .fs_name = "efihttp",
+ .fo_open = efihttp_fs_open,
+ .fo_close = efihttp_fs_close,
+ .fo_read = efihttp_fs_read,
+ .fo_write = efihttp_fs_write,
+ .fo_seek = efihttp_fs_seek,
+ .fo_stat = efihttp_fs_stat,
+ .fo_readdir = efihttp_fs_readdir,
+};
+
+static void EFIAPI
+notify(EFI_EVENT event, void *context)
+{
+ bool *b;
+
+ b = (bool *)context;
+ *b = true;
+}
+
+static int
+setup_ipv4_config2(EFI_HANDLE handle, MAC_ADDR_DEVICE_PATH *mac,
+ IPv4_DEVICE_PATH *ipv4, DNS_DEVICE_PATH *dns)
+{
+ EFI_IP4_CONFIG2_PROTOCOL *ip4config2;
+ EFI_STATUS status;
+
+ status = BS->OpenProtocol(handle, &ip4config2_guid,
+ (void **)&ip4config2, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ if (ipv4) {
+ setenv("boot.netif.hwaddr",
+ ether_sprintf((u_char *)mac->MacAddress.Addr), 1);
+ setenv("boot.netif.ip",
+ inet_ntoa(*(struct in_addr *)ipv4->LocalIpAddress.Addr), 1);
+ setenv("boot.netif.netmask",
+ intoa(*(n_long *)ipv4->SubnetMask.Addr), 1);
+ setenv("boot.netif.gateway",
+ inet_ntoa(*(struct in_addr *)ipv4->GatewayIpAddress.Addr),
+ 1);
+ status = ip4config2->SetData(ip4config2,
+ Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY),
+ &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyStatic });
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+
+ status = ip4config2->SetData(ip4config2,
+ Ip4Config2DataTypeManualAddress,
+ sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS),
+ &(EFI_IP4_CONFIG2_MANUAL_ADDRESS) {
+ .Address = ipv4->LocalIpAddress,
+ .SubnetMask = ipv4->SubnetMask });
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+
+ if (ipv4->GatewayIpAddress.Addr[0] != 0) {
+ status = ip4config2->SetData(ip4config2,
+ Ip4Config2DataTypeGateway, sizeof(EFI_IPv4_ADDRESS),
+ &ipv4->GatewayIpAddress);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ }
+
+ if (dns) {
+ status = ip4config2->SetData(ip4config2,
+ Ip4Config2DataTypeDnsServer,
+ sizeof(EFI_IPv4_ADDRESS), &dns->DnsServerIp);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ }
+ } else {
+ status = ip4config2->SetData(ip4config2,
+ Ip4Config2DataTypePolicy, sizeof(EFI_IP4_CONFIG2_POLICY),
+ &(EFI_IP4_CONFIG2_POLICY) { Ip4Config2PolicyDhcp });
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ }
+
+ return (0);
+}
+
+static int
+efihttp_dev_init(void)
+{
+ EFI_DEVICE_PATH *imgpath, *devpath;
+ URI_DEVICE_PATH *uri;
+ EFI_HANDLE handle;
+ EFI_STATUS status;
+ int err;
+ bool found_http;
+
+ imgpath = efi_lookup_image_devpath(IH);
+ if (imgpath == NULL)
+ return (ENXIO);
+ devpath = imgpath;
+ found_http = false;
+ for (; !IsDevicePathEnd(devpath);
+ devpath = NextDevicePathNode(devpath)) {
+ if (DevicePathType(devpath) != MESSAGING_DEVICE_PATH ||
+ DevicePathSubType(devpath) != MSG_URI_DP)
+ continue;
+ uri = (URI_DEVICE_PATH *)devpath;
+ if (strncmp("http", uri->Uri, 4) == 0)
+ found_http = true;
+ }
+ if (!found_http)
+ return (ENXIO);
+
+ status = BS->LocateDevicePath(&httpsb_guid, &imgpath, &handle);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+
+ err = efi_register_handles(&efihttp_dev, &handle, NULL, 1);
+ return (err);
+}
+
+static int
+efihttp_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
+ size_t *rsize)
+{
+ return (EIO);
+}
+
+static int
+efihttp_dev_open(struct open_file *f, ...)
+{
+ EFI_HTTP_CONFIG_DATA config;
+ EFI_HTTPv4_ACCESS_POINT config_access;
+ DNS_DEVICE_PATH *dns;
+ EFI_DEVICE_PATH *devpath, *imgpath;
+ EFI_SERVICE_BINDING_PROTOCOL *sb;
+ IPv4_DEVICE_PATH *ipv4;
+ MAC_ADDR_DEVICE_PATH *mac;
+ URI_DEVICE_PATH *uri;
+ struct devdesc *dev;
+ struct open_efihttp *oh;
+ char *c;
+ EFI_HANDLE handle;
+ EFI_STATUS status;
+ int err, len;
+
+ imgpath = efi_lookup_image_devpath(IH);
+ if (imgpath == NULL)
+ return (ENXIO);
+ devpath = imgpath;
+ status = BS->LocateDevicePath(&httpsb_guid, &devpath, &handle);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ ipv4 = NULL;
+ dns = NULL;
+ uri = NULL;
+ for (; !IsDevicePathEnd(imgpath);
+ imgpath = NextDevicePathNode(imgpath)) {
+ if (DevicePathType(imgpath) != MESSAGING_DEVICE_PATH)
+ continue;
+ switch (DevicePathSubType(imgpath)) {
+ case MSG_MAC_ADDR_DP:
+ mac = (MAC_ADDR_DEVICE_PATH *)imgpath;
+ break;
+ case MSG_IPv4_DP:
+ ipv4 = (IPv4_DEVICE_PATH *)imgpath;
+ break;
+ case MSG_DNS_DP:
+ dns = (DNS_DEVICE_PATH *)imgpath;
+ break;
+ case MSG_URI_DP:
+ uri = (URI_DEVICE_PATH *)imgpath;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (uri == NULL)
+ return (ENXIO);
+
+ err = setup_ipv4_config2(handle, mac, ipv4, dns);
+ if (err)
+ return (err);
+
+ oh = calloc(1, sizeof(struct open_efihttp));
+ if (!oh)
+ return (ENOMEM);
+ oh->dev_handle = handle;
+ dev = (struct devdesc *)f->f_devdata;
+ dev->d_opendata = oh;
+
+ status = BS->OpenProtocol(handle, &httpsb_guid, (void **)&sb, IH, NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(status)) {
+ err = efi_status_to_errno(status);
+ goto end;
+ }
+
+ status = sb->CreateChild(sb, &oh->http_handle);
+ if (EFI_ERROR(status)) {
+ err = efi_status_to_errno(status);
+ goto end;
+ }
+
+ status = BS->OpenProtocol(oh->http_handle, &http_guid,
+ (void **)&oh->http, IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(status)) {
+ sb->DestroyChild(sb, oh->http_handle);
+ err = efi_status_to_errno(status);
+ goto end;
+ }
+
+ config.HttpVersion = HttpVersion11;
+ config.TimeOutMillisec = 0;
+ config.LocalAddressIsIPv6 = FALSE;
+ config.AccessPoint.IPv4Node = &config_access;
+ config_access.UseDefaultAddress = TRUE;
+ config_access.LocalPort = 0;
+ status = oh->http->Configure(oh->http, &config);
+ if (EFI_ERROR(status)) {
+ sb->DestroyChild(sb, oh->http_handle);
+ err = efi_status_to_errno(status);
+ goto end;
+ }
+
+ /*
+ * Here we make attempt to construct a "base" URI by stripping
+ * the last two path components from the loaded URI under the
+ * assumption that it is something like:
+ *
+ * http://127.0.0.1/foo/boot/loader.efi
+ *
+ * hoping to arriving at:
+ *
+ * http://127.0.0.1/foo/
+ */
+ len = DevicePathNodeLength(&uri->Header) - sizeof(URI_DEVICE_PATH);
+ oh->uri_base = malloc(len + 1);
+ if (oh->uri_base == NULL) {
+ err = ENOMEM;
+ goto end;
+ }
+ strncpy(oh->uri_base, uri->Uri, len);
+ oh->uri_base[len] = '\0';
+ c = strrchr(oh->uri_base, '/');
+ if (c != NULL)
+ *c = '\0';
+ c = strrchr(oh->uri_base, '/');
+ if (c != NULL && *(c + 1) != '\0')
+ *(c + 1) = '\0';
+
+ err = 0;
+end:
+ if (err != 0) {
+ free(dev->d_opendata);
+ dev->d_opendata = NULL;
+ }
+ return (err);
+}
+
+static int
+efihttp_dev_close(struct open_file *f)
+{
+ EFI_SERVICE_BINDING_PROTOCOL *sb;
+ struct devdesc *dev;
+ struct open_efihttp *oh;
+ EFI_STATUS status;
+
+ dev = (struct devdesc *)f->f_devdata;
+ oh = (struct open_efihttp *)dev->d_opendata;
+ status = BS->OpenProtocol(oh->dev_handle, &httpsb_guid, (void **)&sb,
+ IH, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ sb->DestroyChild(sb, oh->http_handle);
+ free(oh->uri_base);
+ free(oh);
+ dev->d_opendata = NULL;
+ return (0);
+}
+
+static int
+_efihttp_fs_open(const char *path, struct open_file *f)
+{
+ EFI_HTTP_CONFIG_DATA config;
+ EFI_HTTPv4_ACCESS_POINT config_access;
+ EFI_HTTP_TOKEN token;
+ EFI_HTTP_MESSAGE message;
+ EFI_HTTP_REQUEST_DATA request;
+ EFI_HTTP_RESPONSE_DATA response;
+ EFI_HTTP_HEADER headers[3];
+ char *host, *hostp;
+ char *c;
+ struct devdesc *dev;
+ struct open_efihttp *oh;
+ struct file_efihttp *fh;
+ EFI_STATUS status;
+ int i;
+ int polltime;
+ bool done;
+
+ dev = (struct devdesc *)f->f_devdata;
+ oh = (struct open_efihttp *)dev->d_opendata;
+ fh = calloc(1, sizeof(struct file_efihttp));
+ if (fh == NULL)
+ return (ENOMEM);
+ f->f_fsdata = fh;
+ fh->path = strdup(path);
+
+ /*
+ * Reset the HTTP state.
+ *
+ * EDK II's persistent HTTP connection handling is graceless,
+ * assuming that all connections are persistent regardless of
+ * any Connection: header or HTTP version reported by the
+ * server, and failing to send requests when a more sane
+ * implementation would seem to be just reestablishing the
+ * closed connection.
+ *
+ * In the hopes of having some robustness, we indicate to the
+ * server that we will close the connection by using a
+ * Connection: close header. And then here we manually
+ * unconfigure and reconfigure the http instance to force the
+ * connection closed.
+ */
+ memset(&config, 0, sizeof(config));
+ memset(&config_access, 0, sizeof(config_access));
+ config.AccessPoint.IPv4Node = &config_access;
+ status = oh->http->GetModeData(oh->http, &config);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ status = oh->http->Configure(oh->http, NULL);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ status = oh->http->Configure(oh->http, &config);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+
+ /* Send the read request */
+ done = false;
+ status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify,
+ &done, &token.Event);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+
+ /* extract the host portion of the URL */
+ host = strdup(oh->uri_base);
+ if (host == NULL)
+ return (ENOMEM);
+ hostp = host;
+ /* Remove the protocol scheme */
+ c = strchr(host, '/');
+ if (c != NULL && *(c + 1) == '/')
+ hostp = (c + 2);
+
+ /* Remove any path information */
+ c = strchr(hostp, '/');
+ if (c != NULL)
+ *c = '\0';
+
+ token.Status = EFI_NOT_READY;
+ token.Message = &message;
+ message.Data.Request = &request;
+ message.HeaderCount = 3;
+ message.Headers = headers;
+ message.BodyLength = 0;
+ message.Body = NULL;
+ request.Method = HttpMethodGet;
+ request.Url = calloc(strlen(oh->uri_base) + strlen(path) + 1, 2);
+ headers[0].FieldName = "Host";
+ headers[0].FieldValue = hostp;
+ headers[1].FieldName = "Connection";
+ headers[1].FieldValue = "close";
+ headers[2].FieldName = "Accept";
+ headers[2].FieldValue = "*/*";
+ cpy8to16(oh->uri_base, request.Url, strlen(oh->uri_base));
+ cpy8to16(path, request.Url + strlen(oh->uri_base), strlen(path));
+ status = oh->http->Request(oh->http, &token);
+ free(request.Url);
+ free(host);
+ if (EFI_ERROR(status)) {
+ BS->CloseEvent(token.Event);
+ return (efi_status_to_errno(status));
+ }
+
+ polltime = 0;
+ while (!done && polltime < EFIHTTP_POLL_TIMEOUT) {
+ status = oh->http->Poll(oh->http);
+ if (EFI_ERROR(status))
+ break;
+
+ if (!done) {
+ delay(100 * 1000);
+ polltime += 100;
+ }
+ }
+ BS->CloseEvent(token.Event);
+ if (EFI_ERROR(token.Status))
+ return (efi_status_to_errno(token.Status));
+
+ /* Wait for the read response */
+ done = false;
+ status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify,
+ &done, &token.Event);
+ if (EFI_ERROR(status))
+ return (efi_status_to_errno(status));
+ token.Status = EFI_NOT_READY;
+ token.Message = &message;
+ message.Data.Response = &response;
+ message.HeaderCount = 0;
+ message.Headers = NULL;
+ message.BodyLength = 0;
+ message.Body = NULL;
+ response.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS;
+ status = oh->http->Response(oh->http, &token);
+ if (EFI_ERROR(status)) {
+ BS->CloseEvent(token.Event);
+ return (efi_status_to_errno(status));
+ }
+
+ polltime = 0;
+ while (!done && polltime < EFIHTTP_POLL_TIMEOUT) {
+ status = oh->http->Poll(oh->http);
+ if (EFI_ERROR(status))
+ break;
+
+ if (!done) {
+ delay(100 * 1000);
+ polltime += 100;
+ }
+ }
+ BS->CloseEvent(token.Event);
+ if (EFI_ERROR(token.Status)) {
+ BS->FreePool(message.Headers);
+ return (efi_status_to_errno(token.Status));
+ }
+ if (response.StatusCode != HTTP_STATUS_200_OK) {
+ BS->FreePool(message.Headers);
+ return (EIO);
+ }
+ fh->size = 0;
+ fh->is_dir = false;
+ for (i = 0; i < message.HeaderCount; i++) {
+ if (strcasecmp(message.Headers[i].FieldName,
+ "Content-Length") == 0)
+ fh->size = strtoul(message.Headers[i].FieldValue, NULL,
+ 10);
+ else if (strcasecmp(message.Headers[i].FieldName,
+ "Content-type") == 0) {
+ if (strncmp(message.Headers[i].FieldValue, "text/html",
+ 9) == 0)
+ fh->is_dir = true;
+ }
+ }
+
+ return (0);
+}
+
+static int
+efihttp_fs_open(const char *path, struct open_file *f)
+{
+ char *path_slash;
+ int err;
+
+ /*
+ * If any path fails to open, try with a trailing slash in
+ * case it's a directory.
+ */
+ err = _efihttp_fs_open(path, f);
+ if (err != 0) {
+ path_slash = malloc(strlen(path) + 2);
+ if (path_slash == NULL)
+ return (ENOMEM);
+ strcpy(path_slash, path);
+ strcat(path_slash, "/");
+ err = _efihttp_fs_open(path_slash, f);
+ free(path_slash);
+ }
+ return (err);
+}
+
+static int
+efihttp_fs_close(struct open_file *f)
+{
+ return (0);
+}
+
+static int
+_efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ EFI_HTTP_TOKEN token;
+ EFI_HTTP_MESSAGE message;
+ EFI_STATUS status;
+ struct devdesc *dev;
+ struct open_efihttp *oh;
+ struct file_efihttp *fh;
+ bool done;
+ int polltime;
+
+ fh = (struct file_efihttp *)f->f_fsdata;
+
+ if (fh->size > 0 && fh->offset >= fh->size) {
+ if (resid != NULL)
+ *resid = size;
+
+ return 0;
+ }
+
+ dev = (struct devdesc *)f->f_devdata;
+ oh = (struct open_efihttp *)dev->d_opendata;
+ done = false;
+ status = BS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, notify,
+ &done, &token.Event);
+ if (EFI_ERROR(status)) {
+ return (efi_status_to_errno(status));
+ }
+ token.Status = EFI_NOT_READY;
+ token.Message = &message;
+ message.Data.Request = NULL;
+ message.HeaderCount = 0;
+ message.Headers = NULL;
+ message.BodyLength = size;
+ message.Body = buf;
+ status = oh->http->Response(oh->http, &token);
+ if (status == EFI_CONNECTION_FIN) {
+ if (resid)
+ *resid = size;
+ return (0);
+ } else if (EFI_ERROR(status)) {
+ BS->CloseEvent(token.Event);
+ return (efi_status_to_errno(status));
+ }
+ polltime = 0;
+ while (!done && polltime < EFIHTTP_POLL_TIMEOUT) {
+ status = oh->http->Poll(oh->http);
+ if (EFI_ERROR(status))
+ break;
+
+ if (!done) {
+ delay(100 * 1000);
+ polltime += 100;
+ }
+ }
+ BS->CloseEvent(token.Event);
+ if (token.Status == EFI_CONNECTION_FIN) {
+ if (resid)
+ *resid = size;
+ return (0);
+ } else if (EFI_ERROR(token.Status))
+ return (efi_status_to_errno(token.Status));
+ if (resid)
+ *resid = size - message.BodyLength;
+ fh->offset += message.BodyLength;
+ return (0);
+}
+
+static int
+efihttp_fs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ size_t res;
+ int err;
+
+ while (size > 0) {
+ err = _efihttp_fs_read(f, buf, size, &res);
+ if (err != 0 || res == size)
+ goto end;
+ buf += (size - res);
+ size = res;
+ }
+end:
+ if (resid)
+ *resid = size;
+ return (err);
+}
+
+static int
+efihttp_fs_write(struct open_file *f, const void *buf, size_t size, size_t *resid)
+{
+ return (EIO);
+}
+
+static off_t
+efihttp_fs_seek(struct open_file *f, off_t offset, int where)
+{
+ struct file_efihttp *fh;
+ char *path;
+ void *buf;
+ size_t res, res2;
+ int err;
+
+ fh = (struct file_efihttp *)f->f_fsdata;
+ if (where == SEEK_SET && fh->offset == offset)
+ return (0);
+ if (where == SEEK_SET && fh->offset < offset) {
+ buf = malloc(1500);
+ res = offset - fh->offset;
+ while (res > 0) {
+ err = _efihttp_fs_read(f, buf, min(1500, res), &res2);
+ if (err != 0) {
+ free(buf);
+ return (err);
+ }
+ res -= min(1500, res) - res2;
+ }
+ free(buf);
+ return (0);
+ } else if (where == SEEK_SET) {
+ path = fh->path;
+ fh->path = NULL;
+ efihttp_fs_close(f);
+ err = efihttp_fs_open(path, f);
+ free(path);
+ if (err != 0)
+ return (err);
+ return efihttp_fs_seek(f, offset, where);
+ }
+ return (EIO);
+}
+
+static int
+efihttp_fs_stat(struct open_file *f, struct stat *sb)
+{
+ struct file_efihttp *fh;
+
+ fh = (struct file_efihttp *)f->f_fsdata;
+ memset(sb, 0, sizeof(*sb));
+ sb->st_nlink = 1;
+ sb->st_mode = 0777 | (fh->is_dir ? S_IFDIR : S_IFREG);
+ sb->st_size = fh->size;
+ return (0);
+}
+
+static int
+efihttp_fs_readdir(struct open_file *f, struct dirent *d)
+{
+ static char *dirbuf = NULL, *db2, *cursor;
+ static int dirbuf_len = 0;
+ char *end;
+ struct file_efihttp *fh;
+
+ fh = (struct file_efihttp *)f->f_fsdata;
+ if (dirbuf_len < fh->size) {
+ db2 = realloc(dirbuf, fh->size);
+ if (db2 == NULL) {
+ free(dirbuf);
+ return (ENOMEM);
+ } else
+ dirbuf = db2;
+
+ dirbuf_len = fh->size;
+ }
+
+ if (fh->offset != fh->size) {
+ efihttp_fs_seek(f, 0, SEEK_SET);
+ efihttp_fs_read(f, dirbuf, dirbuf_len, NULL);
+ cursor = dirbuf;
+ }
+
+ cursor = strstr(cursor, "d_type = DT_DIR;
+ } else
+ d->d_type = DT_REG;
+ memcpy(d->d_name, cursor, end - cursor);
+ d->d_name[end - cursor] = '\0';
+
+ return (0);
+}
Index: stand/efi/loader/conf.c
===================================================================
--- stand/efi/loader/conf.c
+++ stand/efi/loader/conf.c
@@ -39,6 +39,7 @@
&efipart_fddev,
&efipart_cddev,
&efipart_hddev,
+ &efihttp_dev, /* ordering with efinet_dev matters */
&efinet_dev,
&vdisk_dev,
#ifdef EFI_ZFS_BOOT
@@ -54,6 +55,7 @@
&dosfs_fsops,
&ufs_fsops,
&cd9660_fsops,
+ &efihttp_fsops,
&tftp_fsops,
&nfs_fsops,
&gzipfs_fsops,
Index: stand/libsa/stand.h
===================================================================
--- stand/libsa/stand.h
+++ stand/libsa/stand.h
@@ -126,6 +126,7 @@
extern struct fs_ops ext2fs_fsops;
extern struct fs_ops splitfs_fsops;
extern struct fs_ops pkgfs_fsops;
+extern struct fs_ops efihttp_fsops;
/* where values for lseek(2) */
#define SEEK_SET 0 /* set file offset to offset */