* [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers
@ 2024-11-11 21:09 Adriano Cordova
2024-11-11 21:09 ` [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c Adriano Cordova
` (15 more replies)
0 siblings, 16 replies; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add support for EFI_HTTP_PROTOCOL, EFI_HTTP_SERVICE_BINDING_PROTOCOL,
and EFI_IP4_CONFIG2_PROTOCOL.
This series depends on the series 'wget: Expose wget to applications',
also found at:
https://github.com/0n41rd4/u-boot/commits/http-driver-wget
The fist two patches of this series are not efi specific and have also
been sent to the corresponding maintainers, but this series depends on
them, so they are added here for redundancy. A branch with both series
of patches, concatenated, is at:
https://github.com/0n41rd4/u-boot/commits/efi-http-driver
Adriano Cordova (13):
net: net_utils: Move ip_to_string to lib/net_utils.c
net: wget: let wget_with_dns work with dns disabled
efi_loader: device_path: add definition of
DEVICE_PATH_SUB_TYPE_MSG_IPV4
efi_loader: device_path: add efi_dp_from_ipv4
efi_api: add definitions for HTTP and IP4_CONFIG2 protocols
efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr
efi_loader: device_path: add support for HTTP device path
efi_loader: net: set EFI bootdevice device path to HTTP when loaded
from wget
efi_loader: net: add support to send http requests and parse http
headers
efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL
efi_loader: efi_net: add EFI_HTTP_PROTOCOL
efi_selftest: add test for HTTP protocol
efi_selftest: add test for IPv4 Config2 protocol
Heinrich Schuchardt (2):
efi_loader: add IPv4() to device path to text protocol
lib: uuid: display HTTP and IPV4 Config II protocols
include/efi_api.h | 220 +++++++++
include/efi_loader.h | 42 ++
include/net-common.h | 10 +
lib/efi_loader/Kconfig | 17 +
lib/efi_loader/Makefile | 2 +
lib/efi_loader/efi_device_path.c | 95 +++-
lib/efi_loader/efi_device_path_to_text.c | 23 +
lib/efi_loader/efi_http.c | 563 +++++++++++++++++++++++
lib/efi_loader/efi_ipconfig.c | 216 +++++++++
lib/efi_loader/efi_net.c | 316 ++++++++++++-
lib/efi_selftest/Makefile | 2 +
lib/efi_selftest/efi_selftest_http.c | 315 +++++++++++++
lib/efi_selftest/efi_selftest_ipconfig.c | 173 +++++++
lib/net_utils.c | 11 +
lib/uuid.c | 14 +
net/lwip/wget.c | 1 +
net/net.c | 11 -
net/wget.c | 39 +-
18 files changed, 2038 insertions(+), 32 deletions(-)
create mode 100644 lib/efi_loader/efi_http.c
create mode 100644 lib/efi_loader/efi_ipconfig.c
create mode 100644 lib/efi_selftest/efi_selftest_http.c
create mode 100644 lib/efi_selftest/efi_selftest_ipconfig.c
--
2.43.0
^ permalink raw reply [flat|nested] 39+ messages in thread
* [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-13 8:17 ` Ilias Apalodimas
` (2 more replies)
2024-11-11 21:09 ` [PATCH v3 02/15] net: wget: let wget_with_dns work with dns disabled Adriano Cordova
` (14 subsequent siblings)
15 siblings, 3 replies; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
The function string_to_ip is already in net_utils, which is
compiled unconditionally, but ip_to_string is currently only
accessible if the legacy network stack is selected. This
commit puts ip_to_string in net_utils.c and removes it from the
legacy network code.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
include/net-common.h | 10 ++++++++++
lib/net_utils.c | 11 +++++++++++
net/net.c | 11 -----------
3 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/include/net-common.h b/include/net-common.h
index 3cd0f34374..b7a519e36d 100644
--- a/include/net-common.h
+++ b/include/net-common.h
@@ -426,6 +426,16 @@ void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
*/
struct in_addr string_to_ip(const char *s);
+/**
+ * ip_to_string() - Convert a string to ip address
+ *
+ * Implemented in lib/net_utils.c (built unconditionally)
+ *
+ * @x: Input ip to parse
+ * @s: string containing the parsed ip address
+ */
+void ip_to_string(struct in_addr x, char *s);
+
/* copy a filename (allow for "..." notation, limit length) */
void copy_filename(char *dst, const char *src, int size);
diff --git a/lib/net_utils.c b/lib/net_utils.c
index c70fef0d99..621f6512b6 100644
--- a/lib/net_utils.c
+++ b/lib/net_utils.c
@@ -152,6 +152,17 @@ out_err:
}
#endif
+void ip_to_string(struct in_addr x, char *s)
+{
+ x.s_addr = ntohl(x.s_addr);
+ sprintf(s, "%d.%d.%d.%d",
+ (int) ((x.s_addr >> 24) & 0xff),
+ (int) ((x.s_addr >> 16) & 0xff),
+ (int) ((x.s_addr >> 8) & 0xff),
+ (int) ((x.s_addr >> 0) & 0xff)
+ );
+}
+
void string_to_enetaddr(const char *addr, uint8_t *enetaddr)
{
char *end;
diff --git a/net/net.c b/net/net.c
index f47e9fbe33..ca35704f66 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1723,17 +1723,6 @@ int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len)
return 1;
}
-void ip_to_string(struct in_addr x, char *s)
-{
- x.s_addr = ntohl(x.s_addr);
- sprintf(s, "%d.%d.%d.%d",
- (int) ((x.s_addr >> 24) & 0xff),
- (int) ((x.s_addr >> 16) & 0xff),
- (int) ((x.s_addr >> 8) & 0xff),
- (int) ((x.s_addr >> 0) & 0xff)
- );
-}
-
void vlan_to_string(ushort x, char *s)
{
x = ntohs(x);
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 02/15] net: wget: let wget_with_dns work with dns disabled
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
2024-11-11 21:09 ` [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-16 21:12 ` Heinrich Schuchardt
2024-11-11 21:09 ` [PATCH v3 03/15] efi_loader: device_path: add definition of DEVICE_PATH_SUB_TYPE_MSG_IPV4 Adriano Cordova
` (13 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
This was marked as TODO in the code:
-Enable use of wget_with_dns even if CMD_DNS is disabled if
the given uri has the ip address for the http server.
-Check for port in the uri when transforming to legacy wget
syntax inside wget_with_dns.
-Move the check for CMD_DNS inside wget_with_dns.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
net/wget.c | 38 ++++++++++++++++++++++++--------------
1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/net/wget.c b/net/wget.c
index 3bc2522cde..36158e0a9c 100644
--- a/net/wget.c
+++ b/net/wget.c
@@ -530,12 +530,10 @@ void wget_start(void)
wget_send(TCP_SYN, 0, 0, 0);
}
-#if (IS_ENABLED(CONFIG_CMD_DNS))
int wget_with_dns(ulong dst_addr, char *uri)
{
int ret;
- char *s, *host_name, *file_name, *str_copy;
-
+ char *s, *host_name, *file_name, *str_copy, *port;
/*
* Download file using wget.
*
@@ -556,18 +554,31 @@ int wget_with_dns(ulong dst_addr, char *uri)
}
file_name = s;
- /* TODO: If the given uri has ip address for the http server, skip dns */
- net_dns_resolve = host_name;
- net_dns_env_var = "httpserverip";
- if (net_loop(DNS) < 0) {
- log_err("Error: dns lookup of %s failed, check setup\n", net_dns_resolve);
- ret = -EINVAL;
- goto out;
- }
- s = env_get("httpserverip");
- if (!s) {
+ port = host_name;
+ host_name = strsep(&port, ":");
+
+ if (string_to_ip(host_name).s_addr != 0) {
+ s = host_name;
+ } else {
+#if IS_ENABLED(CONFIG_CMD_DNS)
+ net_dns_resolve = host_name;
+ net_dns_env_var = "httpserverip";
+ if (net_loop(DNS) < 0) {
+ log_err("DNS lookup of %s failed, check setup\n", net_dns_resolve);
+ ret = -EINVAL;
+ goto out;
+ }
+ s = env_get("httpserverip");
+ if (!s) {
+ log_err("DNS could not resolve %s\n", net_dns_resolve);
+ ret = -EINVAL;
+ goto out;
+ }
+#else
+ log_err("DNS disabled, %s could not be resolved\n", host_name);
ret = -EINVAL;
goto out;
+#endif
}
strlcpy(net_boot_file_name, s, sizeof(net_boot_file_name));
@@ -581,7 +592,6 @@ out:
return ret < 0 ? ret : 0;
}
-#endif
/**
* wget_validate_uri() - validate the uri for wget
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 03/15] efi_loader: device_path: add definition of DEVICE_PATH_SUB_TYPE_MSG_IPV4
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
2024-11-11 21:09 ` [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c Adriano Cordova
2024-11-11 21:09 ` [PATCH v3 02/15] net: wget: let wget_with_dns work with dns disabled Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-13 10:24 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 04/15] efi_loader: device_path: add efi_dp_from_ipv4 Adriano Cordova
` (12 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add definition for DEVICE_PATH_SUB_TYPE_MSG_IPV4 device path
subtype.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
Changes in v3:
- Removed alignment in struct efi_ipv4_address
include/efi_api.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/include/efi_api.h b/include/efi_api.h
index f07d074f93..99ee749522 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -616,6 +616,7 @@ struct efi_device_path_acpi_path {
# define DEVICE_PATH_SUB_TYPE_MSG_SCSI 0x02
# define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05
# define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b
+# define DEVICE_PATH_SUB_TYPE_MSG_IPV4 0x0c
# define DEVICE_PATH_SUB_TYPE_MSG_UART 0x0e
# define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f
# define DEVICE_PATH_SUB_TYPE_MSG_USB_WWI 0x10
@@ -691,6 +692,22 @@ struct efi_device_path_uri {
u8 uri[];
} __packed;
+struct efi_ipv4_address {
+ u8 ip_addr[4];
+};
+
+struct efi_device_path_ipv4 {
+ struct efi_device_path dp;
+ struct efi_ipv4_address local_ip_address;
+ struct efi_ipv4_address remote_ip_address;
+ u16 local_port;
+ u16 remote_port;
+ u16 protocol;
+ u8 static_ip_address;
+ struct efi_ipv4_address gateway_ip_address;
+ struct efi_ipv4_address subnet_mask;
+} __packed;
+
#define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04
# define DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH 0x01
# define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 04/15] efi_loader: device_path: add efi_dp_from_ipv4
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (2 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 03/15] efi_loader: device_path: add definition of DEVICE_PATH_SUB_TYPE_MSG_IPV4 Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-13 10:18 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 05/15] efi_loader: add IPv4() to device path to text protocol Adriano Cordova
` (11 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add efi_dp_from_ipv4 to form a device path from an ipv4 address.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
Changes in v3:
- Removed some unnecessary void* casts.
- Changed sizeof(struct efi_device_path_ipv4) to sizeof(*ipv4dp)
in efi_dp_from_ipv4.
lib/efi_loader/efi_device_path.c | 38 ++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index ee387e1dfd..82a45da1fa 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -974,6 +974,44 @@ struct efi_device_path __maybe_unused *efi_dp_from_eth(void)
return start;
}
+struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip,
+ struct efi_ipv4_address *mask,
+ struct efi_ipv4_address *srv)
+{
+ struct efi_device_path *dp1, *dp2;
+ efi_uintn_t ipv4dp_len;
+ struct efi_device_path_ipv4 *ipv4dp;
+ char *pos;
+
+ ipv4dp_len = sizeof(*ipv4dp);
+ ipv4dp = efi_alloc(ipv4dp_len + sizeof(END));
+ if (!ipv4dp) {
+ log_err("Out of memory\n");
+ return NULL;
+ }
+
+ ipv4dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
+ ipv4dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_IPV4;
+ ipv4dp->dp.length = ipv4dp_len;
+ ipv4dp->protocol = 6;
+ if (ip)
+ memcpy(&ipv4dp->local_ip_address, (void *)&ip, 4);
+ if (mask)
+ memcpy(&ipv4dp->subnet_mask, (void *)&mask, 4);
+ if (srv)
+ memcpy(&ipv4dp->subnet_mask, (void *)&srv, 4);
+ pos = (void *)((uintptr_t)ipv4dp + ipv4dp_len);
+ memcpy(pos, &END, sizeof(END));
+
+ dp1 = efi_dp_from_eth();
+ dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)ipv4dp, 0);
+
+ efi_free_pool(ipv4dp);
+ efi_free_pool(dp1);
+
+ return dp2;
+}
+
/* Construct a device-path for memory-mapped image */
struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
uint64_t start_address,
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 05/15] efi_loader: add IPv4() to device path to text protocol
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (3 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 04/15] efi_loader: device_path: add efi_dp_from_ipv4 Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-13 10:37 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 06/15] efi_api: add definitions for HTTP and IP4_CONFIG2 protocols Adriano Cordova
` (10 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Heinrich Schuchardt, Adriano Cordova
From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Implement Ipv4() node support in the device path to text protocol.
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
lib/efi_loader/efi_device_path_to_text.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
index 0c7b30a26e..481a9712d9 100644
--- a/lib/efi_loader/efi_device_path_to_text.c
+++ b/lib/efi_loader/efi_device_path_to_text.c
@@ -8,6 +8,7 @@
#include <blk.h>
#include <efi_loader.h>
#include <malloc.h>
+#include <net.h>
#define MAC_OUTPUT_LEN 22
#define UNKNOWN_OUTPUT_LEN 23
@@ -170,6 +171,28 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
break;
}
+ case DEVICE_PATH_SUB_TYPE_MSG_IPV4: {
+ struct efi_device_path_ipv4 *idp =
+ (struct efi_device_path_ipv4 *)dp;
+
+ s += sprintf(s, "IPv4(%pI4,", &idp->remote_ip_address);
+ switch (idp->protocol) {
+ case IPPROTO_TCP:
+ s += sprintf(s, "TCP,");
+ case IPPROTO_UDP:
+ s += sprintf(s, "UDP,");
+ default:
+ s += sprintf(s, "0x%x,", idp->protocol);
+ }
+ s += sprintf(s, idp->static_ip_address ? "Static" : "DHCP");
+ s += sprintf(s, ",%pI4", &idp->local_ip_address);
+ if (idp->dp.length == sizeof(struct efi_device_path_ipv4))
+ s += sprintf(s, ",%pI4,%pI4", &idp->gateway_ip_address,
+ &idp->subnet_mask);
+ s += sprintf(s, ")");
+
+ break;
+ }
case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: {
struct efi_device_path_usb_class *ucdp =
(struct efi_device_path_usb_class *)dp;
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 06/15] efi_api: add definitions for HTTP and IP4_CONFIG2 protocols
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (4 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 05/15] efi_loader: add IPv4() to device path to text protocol Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-18 12:08 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 07/15] efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr Adriano Cordova
` (9 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add EFI definitions for EFI_IP4_CONFIG2_PROTOCOL,
EFI_HTTP_SERVICE_BINDING_PROTOCOL, and EFI_HTTP_PROTOCOL.
According to UEFI spec 2.10.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
include/efi_api.h | 203 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 203 insertions(+)
diff --git a/include/efi_api.h b/include/efi_api.h
index 99ee749522..61c4eda8f8 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -1725,6 +1725,209 @@ struct efi_pxe_base_code_protocol {
struct efi_pxe_mode *mode;
};
+#define EFI_IP4_CONFIG2_PROTOCOL_GUID \
+ EFI_GUID(0x5b446ed1, 0xe30b, 0x4faa, \
+ 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80)
+
+enum efi_ip4_config2_data_type {
+ EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
+ EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
+ EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
+ EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
+ EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM,
+};
+
+struct efi_ip4_config2_protocol {
+ efi_status_t (EFIAPI * set_data)(struct efi_ip4_config2_protocol *this,
+ enum efi_ip4_config2_data_type data_type,
+ efi_uintn_t data_size,
+ void *data);
+ efi_status_t (EFIAPI * get_data)(struct efi_ip4_config2_protocol *this,
+ enum efi_ip4_config2_data_type data_type,
+ efi_uintn_t *data_size,
+ void *data);
+ efi_status_t (EFIAPI * register_data_notify)(struct efi_ip4_config2_protocol *this,
+ enum efi_ip4_config2_data_type data_type,
+ struct efi_event *event);
+ efi_status_t (EFIAPI * unregister_data_notify)(struct efi_ip4_config2_protocol *this,
+ enum efi_ip4_config2_data_type data_type,
+ struct efi_event *event);
+};
+
+struct efi_ip4_route_table {
+ struct efi_ipv4_address subnet_address;
+ struct efi_ipv4_address subnet_mask;
+ struct efi_ipv4_address gateway_address;
+};
+
+#define EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32
+
+struct efi_ip4_config2_interface_info {
+ u16 name[EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE];
+ u8 if_type;
+ u32 hw_address_size;
+ struct efi_mac_address hw_address;
+ struct efi_ipv4_address station_address;
+ struct efi_ipv4_address subnet_mask;
+ u32 route_table_size;
+ struct efi_ip4_route_table *route_table;
+};
+
+enum efi_ip4_config2_policy {
+ EFI_IP4_CONFIG2_POLICY_STATIC,
+ EFI_IP4_CONFIG2_POLICY_DHCP,
+ EFI_IP4_CONFIG2_POLICY_MAX
+};
+
+struct efi_ip4_config2_manual_address {
+ struct efi_ipv4_address address;
+ struct efi_ipv4_address subnet_mask;
+};
+
+#define EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \
+ EFI_GUID(0xbdc8e6af, 0xd9bc, 0x4379, \
+ 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c)
+
+struct efi_service_binding_protocol {
+ efi_status_t (EFIAPI * create_child)(struct efi_service_binding_protocol *this,
+ efi_handle_t *child_handle);
+ efi_status_t (EFIAPI * destroy_child)(struct efi_service_binding_protocol *this,
+ efi_handle_t child_handle);
+};
+
+#define EFI_HTTP_PROTOCOL_GUID \
+ EFI_GUID(0x7A59B29B, 0x910B, 0x4171, \
+ 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B)
+
+enum efi_http_version {
+ HTTPVERSION10,
+ HTTPVERSION11,
+ HTTPVERSIONUNSUPPORTED
+};
+
+struct efi_httpv4_access_point {
+ bool use_default_address;
+ struct efi_ipv4_address local_address;
+ struct efi_ipv4_address local_subnet;
+ u16 local_port;
+};
+
+union efi_http_access_point {
+ struct efi_httpv4_access_point *ipv4_node;
+ struct efi_httpv6_access_point *ipv6_node;
+};
+
+struct efi_http_config_data {
+ enum efi_http_version http_version;
+ u32 timeout;
+ bool is_ipv6;
+ union efi_http_access_point access_point;
+};
+
+enum efi_http_method {
+ HTTP_METHOD_GET,
+ HTTP_METHOD_POST,
+ HTTP_METHOD_PATCH,
+ HTTP_METHOD_OPTIONS,
+ HTTP_METHOD_CONNECT,
+ HTTP_METHOD_HEAD,
+ HTTP_METHOD_PUT,
+ HTTP_METHOD_DELETE,
+ HTTP_METHOD_TRACE,
+ HTTP_METHOD_MAX
+};
+
+enum efi_http_status_code {
+ 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
+};
+
+struct efi_http_request_data {
+ enum efi_http_method method;
+ u16 *url;
+};
+
+struct efi_http_response_data {
+ enum efi_http_status_code status_code;
+};
+
+struct efi_http_header {
+ char *field_name;
+ char *field_value;
+};
+
+struct efi_http_message {
+ union {
+ struct efi_http_request_data *request;
+ struct efi_http_response_data *response;
+ } data;
+ efi_uintn_t header_count;
+ struct efi_http_header *headers;
+ efi_uintn_t body_length;
+ void *body;
+};
+
+struct efi_http_token {
+ struct efi_event *event;
+ efi_status_t status;
+ struct efi_http_message *message;
+};
+
+struct efi_http_protocol {
+ efi_status_t (EFIAPI * get_mode_data)(struct efi_http_protocol *this,
+ struct efi_http_config_data *data);
+ efi_status_t (EFIAPI * configure)(struct efi_http_protocol *this,
+ struct efi_http_config_data *data);
+ efi_status_t (EFIAPI * request)(struct efi_http_protocol *this,
+ struct efi_http_token *token);
+ efi_status_t (EFIAPI * cancel)(struct efi_http_protocol *this,
+ struct efi_http_token *token);
+ efi_status_t (EFIAPI * response)(struct efi_http_protocol *this,
+ struct efi_http_token *token);
+ efi_status_t (EFIAPI * poll)(struct efi_http_protocol *this);
+};
+
#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \
0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 07/15] efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (5 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 06/15] efi_api: add definitions for HTTP and IP4_CONFIG2 protocols Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-18 12:21 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 08/15] efi_loader: device_path: add support for HTTP device path Adriano Cordova
` (8 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add the functions efi_net_set_addr and efi_net_get_addr to set
and get the ip address from efi code in a network agnostic way.
This could also go in net_common, or be compiled conditionally
for each network stack.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
include/efi_loader.h | 16 +++++++
lib/efi_loader/efi_net.c | 100 +++++++++++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 39809eac1b..612bc42816 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -125,6 +125,22 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
size_t buffer_size) { }
#endif
+#if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER)
+void efi_net_get_addr(struct efi_ipv4_address *ip,
+ struct efi_ipv4_address *mask,
+ struct efi_ipv4_address *gw);
+void efi_net_set_addr(struct efi_ipv4_address *ip,
+ struct efi_ipv4_address *mask,
+ struct efi_ipv4_address *gw);
+#else
+static inline void efi_net_get_addr(struct efi_ipv4_address *ip,
+ struct efi_ipv4_address *mask,
+ struct efi_ipv4_address *gw) { }
+static inline void efi_net_set_addr(struct efi_ipv4_address *ip,
+ struct efi_ipv4_address *mask,
+ struct efi_ipv4_address *gw) { }
+#endif
+
/* Maximum number of configuration tables */
#define EFI_MAX_CONFIGURATION_TABLES 16
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 7cd536705f..dd84b3f18d 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -17,6 +17,7 @@
#include <efi_loader.h>
#include <malloc.h>
+#include <vsprintf.h>
#include <net.h>
static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
@@ -997,3 +998,102 @@ out_of_resources:
printf("ERROR: Out of memory\n");
return EFI_OUT_OF_RESOURCES;
}
+
+void efi_net_get_addr(struct efi_ipv4_address *ip,
+ struct efi_ipv4_address *mask,
+ struct efi_ipv4_address *gw)
+{
+#ifdef CONFIG_NET_LWIP
+ char *ipstr = "ipaddr\0\0";
+ char *maskstr = "netmask\0\0";
+ char *gwstr = "gatewayip\0\0";
+ int idx;
+ struct in_addr tmp;
+ char *env;
+
+ idx = dev_seq(eth_get_dev());
+
+ if (idx < 0 || idx > 99) {
+ log_err("unexpected idx %d\n", idx);
+ return;
+ }
+
+ if (idx) {
+ sprintf(ipstr, "ipaddr%d", idx);
+ sprintf(maskstr, "netmask%d", idx);
+ sprintf(gwstr, "gatewayip%d", idx);
+ }
+
+ env = env_get(ipstr);
+ if (env && ip) {
+ tmp = string_to_ip(env);
+ memcpy((void *)ip, (void *)&tmp, 4);
+ }
+
+ env = env_get(maskstr);
+ if (env && mask) {
+ tmp = string_to_ip(env);
+ memcpy((void *)mask, (void *)&tmp, 4);
+ }
+ env = env_get(gwstr);
+ if (env && gw) {
+ tmp = string_to_ip(env);
+ memcpy((void *)gw, (void *)&tmp, 4);
+ }
+#else
+ if (ip)
+ memcpy((void *)ip, (void *)&net_ip, 4);
+ if (mask)
+ memcpy((void *)mask, (void *)&net_netmask, 4);
+#endif
+}
+
+void efi_net_set_addr(struct efi_ipv4_address *ip,
+ struct efi_ipv4_address *mask,
+ struct efi_ipv4_address *gw)
+{
+#ifdef CONFIG_NET_LWIP
+ char *ipstr = "ipaddr\0\0";
+ char *maskstr = "netmask\0\0";
+ char *gwstr = "gatewayip\0\0";
+ int idx;
+ struct in_addr *addr;
+ char tmp[46];
+
+ idx = dev_seq(eth_get_dev());
+
+ if (idx < 0 || idx > 99) {
+ log_err("unexpected idx %d\n", idx);
+ return;
+ }
+
+ if (idx) {
+ sprintf(ipstr, "ipaddr%d", idx);
+ sprintf(maskstr, "netmask%d", idx);
+ sprintf(gwstr, "gatewayip%d", idx);
+ }
+
+ if (ip) {
+ addr = (struct in_addr *)ip;
+ ip_to_string(*addr, tmp);
+ env_set(ipstr, tmp);
+ }
+
+ if (mask) {
+ addr = (struct in_addr *)mask;
+ ip_to_string(*addr, tmp);
+ env_set(maskstr, tmp);
+ }
+
+ if (gw) {
+ addr = (struct in_addr *)gw;
+ ip_to_string(*addr, tmp);
+ env_set(gwstr, tmp);
+ }
+#else
+ if (ip)
+ memcpy((void *)&net_ip, (void *)ip, 4);
+ if (mask)
+ memcpy((void *)&net_netmask, (void *)mask, 4);
+#endif
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 08/15] efi_loader: device_path: add support for HTTP device path
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (6 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 07/15] efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-13 8:15 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 09/15] efi_loader: net: set EFI bootdevice device path to HTTP when loaded from wget Adriano Cordova
` (7 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add efi_dp_from_http to form a device path from HTTP. The
device path is the concatenation of the device path returned
by efi_dp_from_ipv4 together with an URI node and an END node.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
Changes in v3:
- Moved argument checks in efi_dp_from_http to the beginning of the function
include/efi_loader.h | 1 +
lib/efi_loader/efi_device_path.c | 55 ++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 612bc42816..96b204dfc3 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -872,6 +872,7 @@ struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part);
struct efi_device_path *efi_dp_from_file(const struct efi_device_path *dp,
const char *path);
struct efi_device_path *efi_dp_from_eth(void);
+struct efi_device_path *efi_dp_from_http(const char *server);
struct efi_device_path *efi_dp_from_mem(uint32_t mem_type,
uint64_t start_address,
size_t size);
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 82a45da1fa..158f08b9e5 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -1012,6 +1012,61 @@ struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip,
return dp2;
}
+struct efi_device_path *efi_dp_from_http(const char *server)
+{
+ struct efi_device_path *dp1, *dp2;
+ struct efi_device_path_uri *uridp;
+ efi_uintn_t uridp_len;
+ char *pos;
+ char tmp[128];
+ struct efi_ipv4_address ip;
+ struct efi_ipv4_address mask;
+
+ if ((server && strlen("http://") + strlen(server) + 1 > 128) ||
+ (!server && IS_ENABLED(CONFIG_NET_LWIP)))
+ return NULL;
+
+ efi_net_get_addr(&ip, &mask, NULL);
+
+ dp1 = efi_dp_from_ipv4(&ip, &mask, NULL);
+
+ strcpy(tmp, "http://");
+
+#if IS_ENABLED(CONFIG_NET_LWIP)
+ if (server) {
+ memcpy(tmp + strlen("http://"), server, strlen(server) + 1);
+ }
+#else
+ if (server) {
+ memcpy(tmp + strlen("http://"), server, strlen(server) + 1);
+ } else {
+ ip_to_string(net_server_ip, tmp + strlen("http://"));
+ }
+#endif
+
+ uridp_len = sizeof(struct efi_device_path) + strlen(tmp) + 1;
+ uridp = efi_alloc(uridp_len + sizeof(END));
+ if (!uridp) {
+ log_err("Out of memory\n");
+ return NULL;
+ }
+ uridp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
+ uridp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_URI;
+ uridp->dp.length = uridp_len;
+ debug("device path: setting uri device path to %s\n", tmp);
+ memcpy(uridp->uri, tmp, strlen(tmp) + 1);
+
+ pos = (char *)uridp + uridp_len;
+ memcpy(pos, &END, sizeof(END));
+
+ dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)uridp, 0);
+
+ efi_free_pool(uridp);
+ efi_free_pool(dp1);
+
+ return dp2;
+}
+
/* Construct a device-path for memory-mapped image */
struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
uint64_t start_address,
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 09/15] efi_loader: net: set EFI bootdevice device path to HTTP when loaded from wget
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (7 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 08/15] efi_loader: device_path: add support for HTTP device path Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-18 12:23 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 10/15] efi_loader: net: add support to send http requests and parse http headers Adriano Cordova
` (6 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Set the device path of the efi boot device to an HTTP device path
(as formed by efi_dp_from_http) when the next boot stage is loaded
using wget (i.e., when wget is used with wget_info.set_bootdev=1).
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
include/efi_loader.h | 6 ++++++
lib/efi_loader/efi_device_path.c | 2 +-
lib/efi_loader/efi_net.c | 22 +++++++++++++++++++++-
net/lwip/wget.c | 1 +
net/wget.c | 1 +
5 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 96b204dfc3..f49f8e6be0 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -126,6 +126,10 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
#endif
#if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER)
+/* Call this to update the current device path of the efi net device */
+void efi_net_set_dp(const char *dev, const char *server);
+/* Call this to get the current device path of the efi net device */
+void efi_net_get_dp(void **dp);
void efi_net_get_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw);
@@ -133,6 +137,8 @@ void efi_net_set_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw);
#else
+static inline void efi_net_set_dp(const char *dev, const char *server) { }
+static inline void efi_net_get_dp(void **dp) { }
static inline void efi_net_get_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw) { }
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 158f08b9e5..afb4abc3ff 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -1168,7 +1168,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
(uintptr_t)image_addr, image_size);
} else if (IS_ENABLED(CONFIG_NETDEVICES) && !strcmp(dev, "Net")) {
- dp = efi_dp_from_eth();
+ efi_net_get_dp((void **)&dp);
} else if (!strcmp(dev, "Uart")) {
dp = efi_dp_from_uart();
} else {
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index dd84b3f18d..d4570d4d7c 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -16,6 +16,7 @@
*/
#include <efi_loader.h>
+#include <dm.h>
#include <malloc.h>
#include <vsprintf.h>
#include <net.h>
@@ -31,6 +32,7 @@ static size_t *receive_lengths;
static int rx_packet_idx;
static int rx_packet_num;
static struct efi_net_obj *netobj;
+static struct efi_device_path *net_dp;
/*
* The notification function of this event is called in every timer cycle
@@ -902,8 +904,10 @@ efi_status_t efi_net_register(void)
&netobj->net);
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
+ if (!net_dp)
+ efi_net_set_dp("Net", NULL);
r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
- efi_dp_from_eth());
+ net_dp);
if (r != EFI_SUCCESS)
goto failure_to_add_protocol;
r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid,
@@ -999,6 +1003,22 @@ out_of_resources:
return EFI_OUT_OF_RESOURCES;
}
+void efi_net_set_dp(const char *dev, const char *server)
+{
+ if (!strcmp(dev, "Net"))
+ net_dp = efi_dp_from_eth();
+ else if (!strcmp(dev, "Http"))
+ net_dp = efi_dp_from_http(server);
+}
+
+void efi_net_get_dp(void **dp)
+{
+ if (!net_dp)
+ efi_net_set_dp("Net", NULL);
+ if (dp && net_dp)
+ *dp = efi_dp_dup(net_dp);
+}
+
void efi_net_get_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw)
diff --git a/net/lwip/wget.c b/net/lwip/wget.c
index 53c3b169e0..5c44e324be 100644
--- a/net/lwip/wget.c
+++ b/net/lwip/wget.c
@@ -217,6 +217,7 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result,
print_size(rx_content_len / elapsed * 1000, "/s)\n");
printf("Bytes transferred = %lu (%lx hex)\n", ctx->size, ctx->size);
if (wget_info->set_bootdev) {
+ efi_net_set_dp("Http", ctx->server_name);
efi_set_bootdev("Net", "", ctx->path, map_sysmem(ctx->saved_daddr, 0),
rx_content_len);
}
diff --git a/net/wget.c b/net/wget.c
index 36158e0a9c..676d4db759 100644
--- a/net/wget.c
+++ b/net/wget.c
@@ -442,6 +442,7 @@ static void wget_handler(uchar *pkt, u16 dport,
net_set_state(wget_loop_state);
wget_info->file_size = net_boot_file_size;
if (wget_info->method == WGET_HTTP_METHOD_GET && wget_info->set_bootdev) {
+ efi_net_set_dp("Http", NULL);
efi_set_bootdev("Net", "", image_url,
map_sysmem(image_load_addr, 0),
net_boot_file_size);
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 10/15] efi_loader: net: add support to send http requests and parse http headers
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (8 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 09/15] efi_loader: net: set EFI bootdevice device path to HTTP when loaded from wget Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-12 13:51 ` Heinrich Schuchardt
2024-11-11 21:09 ` [PATCH v3 11/15] efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL Adriano Cordova
` (5 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add network-stack agnostic way to send an http request and
parse http headers from efi drivers. This uses wget as a
backend and communicates with it via efi_wget_info.
The function efi_net_do_request allocates a buffer on behalf of an
efi application using efi_alloc and passes it to wget to receive
the data. If the method is GET and the buffer is too small, it
re-allocates the buffer based on the last received Content-Length
header and tries again. If the method is HEAD it just issues one
request. So issuing a HEAD request (to update Content-Length) and
then a GET request is preferred but not required.
The function efi_net_parse_headers parses a raw buffer containing
an http header into an array of EFI specific 'http_header' structs.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
Changes in v3:
- Add a struct wget_http_info efi_wget_info for efi_net to pass to wget
when issuing wget requests, instead of using the old wget_info (see v2
of the series 'wget: Expose wget to applications').
- Let a pointer to the http status code be passed to efi_net_do_request
for it to fill it for the client after a request.
include/efi_loader.h | 13 ++++
lib/efi_loader/efi_net.c | 158 +++++++++++++++++++++++++++++++++++++++
2 files changed, 171 insertions(+)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index f49f8e6be0..4d05c08441 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -16,6 +16,7 @@
#include <image.h>
#include <pe.h>
#include <linux/list.h>
+#include <linux/sizes.h>
#include <linux/oid_registry.h>
struct blk_desc;
@@ -136,6 +137,18 @@ void efi_net_get_addr(struct efi_ipv4_address *ip,
void efi_net_set_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw);
+efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, ulong *buffer,
+ u32 *status_code, ulong *file_size, char *headers_buffer);
+#define MAX_HTTP_HEADERS_SIZE SZ_64K
+#define MAX_HTTP_HEADERS 100
+#define MAX_HTTP_HEADER_NAME 128
+#define MAX_HTTP_HEADER_VALUE 512
+struct http_header {
+ uchar name[MAX_HTTP_HEADER_NAME];
+ uchar value[MAX_HTTP_HEADER_VALUE];
+};
+
+void efi_net_parse_headers(ulong *num_headers, struct http_header *headers);
#else
static inline void efi_net_set_dp(const char *dev, const char *server) { }
static inline void efi_net_get_dp(void **dp) { }
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index d4570d4d7c..30234ae1c7 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -17,6 +17,7 @@
#include <efi_loader.h>
#include <dm.h>
+#include <linux/sizes.h>
#include <malloc.h>
#include <vsprintf.h>
#include <net.h>
@@ -34,6 +35,12 @@ static int rx_packet_num;
static struct efi_net_obj *netobj;
static struct efi_device_path *net_dp;
+static struct wget_http_info efi_wget_info = {
+ .set_bootdev = false,
+ .check_buffer_size = true,
+
+};
+
/*
* The notification function of this event is called in every timer cycle
* to check if a new network packet has been received.
@@ -1003,6 +1010,10 @@ out_of_resources:
return EFI_OUT_OF_RESOURCES;
}
+/**
+ * efi_net_set_dp() - set device path of efi net device
+ *
+ */
void efi_net_set_dp(const char *dev, const char *server)
{
if (!strcmp(dev, "Net"))
@@ -1011,6 +1022,10 @@ void efi_net_set_dp(const char *dev, const char *server)
net_dp = efi_dp_from_http(server);
}
+/**
+ * efi_net_set_dp() - get device path of efi net device
+ *
+ */
void efi_net_get_dp(void **dp)
{
if (!net_dp)
@@ -1019,6 +1034,10 @@ void efi_net_get_dp(void **dp)
*dp = efi_dp_dup(net_dp);
}
+/**
+ * efi_net_get_addr() - get IP address information
+ *
+ */
void efi_net_get_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw)
@@ -1068,6 +1087,10 @@ void efi_net_get_addr(struct efi_ipv4_address *ip,
#endif
}
+/**
+ * efi_net_set_addr() - set IP address information
+ *
+ */
void efi_net_set_addr(struct efi_ipv4_address *ip,
struct efi_ipv4_address *mask,
struct efi_ipv4_address *gw)
@@ -1117,3 +1140,138 @@ void efi_net_set_addr(struct efi_ipv4_address *ip,
memcpy((void *)&net_netmask, (void *)mask, 4);
#endif
}
+
+/**
+ * efi_net_set_buffer() - allocate a buffer of min 64K
+ *
+ */
+static efi_status_t efi_net_set_buffer(ulong *buffer, ulong size)
+{
+ efi_status_t ret = EFI_SUCCESS;
+
+ if (size < SZ_64K)
+ size = SZ_64K;
+
+ efi_free_pool((void *)*buffer);
+
+ *buffer = (ulong)efi_alloc(size);
+ if (!*buffer)
+ ret = EFI_OUT_OF_RESOURCES;
+
+ efi_wget_info.buffer_size = size;
+ //debug("efi_net: set buffer of size %lu at %lu\n", size, *buffer);
+ return ret;
+}
+
+/**
+ * efi_net_parse_headers() - parse HTTP headers
+ *
+ * Parses the raw buffer efi_wget_info.headers into an array headers
+ * of efi structs http_headers. The array should be at least
+ * MAX_HTTP_HEADERS long.
+ */
+void efi_net_parse_headers(ulong *num_headers, struct http_header *headers)
+{
+ if (!num_headers || !headers)
+ return;
+
+ // Populate info with http headers.
+ *num_headers = 0;
+ const uchar *line_start = efi_wget_info.headers;
+ const uchar *line_end;
+ ulong count;
+ struct http_header *current_header;
+ const uchar *separator;
+ size_t name_length, value_length;
+
+ // Skip the first line (request or status line)
+ line_end = strstr(line_start, "\r\n");
+
+ if (line_end)
+ line_start = line_end + 2;
+
+ while ((line_end = strstr(line_start, "\r\n")) != NULL) {
+ count = *num_headers;
+ if (line_start == line_end || count >= MAX_HTTP_HEADERS)
+ break;
+ current_header = headers + count;
+ separator = strchr(line_start, ':');
+ if (separator) {
+ name_length = separator - line_start;
+ ++separator;
+ while (*separator == ' ')
+ ++separator;
+ value_length = line_end - separator;
+ if (name_length < MAX_HTTP_HEADER_NAME &&
+ value_length < MAX_HTTP_HEADER_VALUE) {
+ strncpy(current_header->name, line_start, name_length);
+ current_header->name[name_length] = '\0';
+ strncpy(current_header->value, separator, value_length);
+ current_header->value[value_length] = '\0';
+ (*num_headers)++;
+ }
+ }
+ line_start = line_end + 2;
+ }
+}
+
+/**
+ * efi_net_do_request() - issue an HTTP request using wget
+ *
+ */
+efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, ulong *buffer,
+ u32 *status_code, ulong *file_size, char *headers_buffer)
+{
+ efi_status_t ret = EFI_SUCCESS;
+ int wget_ret;
+ static bool last_head;
+
+ if (!buffer || !file_size)
+ return EFI_ABORTED;
+
+ efi_wget_info.method = (enum wget_http_method)method;
+ efi_wget_info.headers = headers_buffer;
+
+ switch (method) {
+ case HTTP_METHOD_GET:
+ ret = efi_net_set_buffer(buffer, last_head ? efi_wget_info.hdr_cont_len : 0);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info);
+ if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) {
+ // Try again with updated buffer size
+ ret = efi_net_set_buffer(buffer, (ulong)efi_wget_info.hdr_cont_len);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ if (wget_request((ulong)*buffer, url, &efi_wget_info)) {
+ efi_free_pool((void *)*buffer);
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ }
+ } else if (wget_ret) {
+ efi_free_pool((void *)*buffer);
+ ret = EFI_DEVICE_ERROR;
+ goto out;
+ }
+ // Pass the actual number of received bytes to the application
+ *file_size = efi_wget_info.file_size;
+ *status_code = efi_wget_info.status_code;
+ last_head = false;
+ break;
+ case HTTP_METHOD_HEAD:
+ ret = efi_net_set_buffer(buffer, 0);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ wget_request((ulong)*buffer, url, &efi_wget_info);
+ *file_size = 0;
+ *status_code = efi_wget_info.status_code;
+ last_head = true;
+ break;
+ default:
+ ret = EFI_UNSUPPORTED;
+ break;
+ }
+
+out:
+ return ret;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 11/15] efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (9 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 10/15] efi_loader: net: add support to send http requests and parse http headers Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-18 12:44 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 12/15] efi_loader: efi_net: add EFI_HTTP_PROTOCOL Adriano Cordova
` (4 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add an implementation of the EFI_IP4_CONFIG2_PROTOCOL. The protocol
is attached to the handle of the efi network device. This is the same
handle where snp and pxe are attached to.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
include/efi_loader.h | 3 +
lib/efi_loader/Kconfig | 9 ++
lib/efi_loader/Makefile | 1 +
lib/efi_loader/efi_ipconfig.c | 216 ++++++++++++++++++++++++++++++++++
lib/efi_loader/efi_net.c | 20 +++-
5 files changed, 244 insertions(+), 5 deletions(-)
create mode 100644 lib/efi_loader/efi_ipconfig.c
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 4d05c08441..5029ac39f1 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -627,6 +627,9 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
efi_status_t efi_gop_register(void);
/* Called by bootefi to make the network interface available */
efi_status_t efi_net_register(void);
+/* Called by efi_net_register to make the ip4 config2 protocol available */
+efi_status_t efi_ipconfig_register(const efi_handle_t handle,
+ struct efi_ip4_config2_protocol *ip4config);
/* Called by bootefi to make the watchdog available */
efi_status_t efi_watchdog_register(void);
efi_status_t efi_initrd_register(void);
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 58d49789f1..d823b2855b 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -476,6 +476,15 @@ config EFI_RISCV_BOOT_PROTOCOL
replace the transfer via the device-tree. The latter is not
possible on systems using ACPI.
+config EFI_IP4_CONFIG2_PROTOCOL
+ bool "EFI_IP4_CONFIG2_PROTOCOL support"
+ default y
+ depends on NET || NET_LWIP
+ help
+ Provides an implementation of the EFI_IP4_CONFIG2_PROTOCOL, this
+ protocol can be used to set and get the current ip address and
+ other network information.
+
endmenu
menu "Misc options"
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 87131ab911..30cd1de9d6 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_EFI_ESRT) += efi_esrt.o
obj-$(CONFIG_VIDEO) += efi_gop.o
obj-$(CONFIG_BLK) += efi_disk.o
obj-$(CONFIG_NETDEVICES) += efi_net.o
+obj-$(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) += efi_ipconfig.o
obj-$(CONFIG_ACPI) += efi_acpi.o
obj-$(CONFIG_SMBIOS) += efi_smbios.o
obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
diff --git a/lib/efi_loader/efi_ipconfig.c b/lib/efi_loader/efi_ipconfig.c
new file mode 100644
index 0000000000..4853b2b05d
--- /dev/null
+++ b/lib/efi_loader/efi_ipconfig.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Implementation of EFI_IP4_CONFIG2_PROTOCOL
+ *
+ */
+
+#include <efi_loader.h>
+#include <image.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <net.h>
+
+static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
+
+struct efi_ip4_config2_manual_address current_http_ip;
+static enum efi_ip4_config2_policy current_policy;
+static char current_mac_addr[32];
+
+/* EFI_IP4_CONFIG2_PROTOCOL */
+
+/*
+ * efi_ip4_config2_set_data() - Set the configuration for the EFI IPv4 network
+ * stack running on the communication device
+ *
+ * This function implements EFI_IP4_CONFIG2_PROTOCOL.SetData()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @data_type: the type of data to set
+ * @data_size: size of the buffer pointed to by data in bytes
+ * @data: the data buffer to set
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_ip4_config2_set_data(struct efi_ip4_config2_protocol *this,
+ enum efi_ip4_config2_data_type data_type,
+ efi_uintn_t data_size,
+ void *data)
+{
+ EFI_ENTRY("%p, %d, %zu, %p", this, data_type, data_size, data);
+ efi_status_t ret = EFI_SUCCESS;
+
+ if (!this)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ switch (data_type) {
+ case EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO:
+ return EFI_EXIT(EFI_WRITE_PROTECTED);
+ case EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS:
+ if (current_policy != EFI_IP4_CONFIG2_POLICY_STATIC)
+ return EFI_EXIT(EFI_WRITE_PROTECTED);
+ if (data_size == 0 && !data) {
+ memset((void *)¤t_http_ip, 0,
+ sizeof(struct efi_ip4_config2_manual_address));
+ return EFI_EXIT(EFI_SUCCESS);
+ }
+ if (data && data_size == sizeof(struct efi_ip4_config2_manual_address)) {
+ memcpy((void *)¤t_http_ip, data,
+ sizeof(struct efi_ip4_config2_manual_address));
+ efi_net_set_addr(¤t_http_ip.address,
+ ¤t_http_ip.subnet_mask, NULL);
+ return EFI_EXIT(EFI_SUCCESS);
+ }
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+ case EFI_IP4_CONFIG2_DATA_TYPE_POLICY:
+ if (data && data_size == sizeof(enum efi_ip4_config2_policy)) {
+ current_policy = *(enum efi_ip4_config2_policy *)data;
+ return EFI_EXIT(EFI_SUCCESS);
+ }
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ default:
+ return EFI_EXIT(EFI_UNSUPPORTED);
+ }
+
+ return EFI_EXIT(ret);
+}
+
+/*
+ * efi_ip4_config2_get_data() - Get the configuration for the EFI IPv4 network
+ * stack running on the communication device
+ *
+ * This function implements EFI_IP4_CONFIG2_PROTOCOL.GetData()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @data_type: the type of data to get
+ * @data_size: size
+ * @data: the data buffer
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_ip4_config2_get_data(struct efi_ip4_config2_protocol *this,
+ enum efi_ip4_config2_data_type data_type,
+ efi_uintn_t *data_size,
+ void *data)
+{
+ EFI_ENTRY("%p, %d, %p, %p", this, data_type, data_size, data);
+
+ efi_status_t ret = EFI_SUCCESS;
+ struct efi_ip4_config2_interface_info *info;
+ int tmp;
+
+ if (!this || !data_size)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ if (*data_size && !data)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ tmp = sizeof(struct efi_ip4_config2_interface_info) + sizeof(struct efi_ip4_route_table);
+
+ switch (data_type) {
+ case EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO:
+ if (*data_size < tmp) {
+ *data_size = tmp;
+ return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+ }
+
+ info = (struct efi_ip4_config2_interface_info *)data;
+ memset(info, 0, sizeof(struct efi_ip4_config2_interface_info));
+
+ info->hw_address_size = 6;
+ memcpy(info->hw_address.mac_addr, current_mac_addr, 6);
+ // Set the route table size
+
+ info->route_table_size = 0;
+ break;
+ case EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS:
+ if (*data_size < sizeof(struct efi_ip4_config2_manual_address)) {
+ *data_size = sizeof(struct efi_ip4_config2_manual_address);
+ return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
+ }
+
+ efi_net_get_addr(¤t_http_ip.address, ¤t_http_ip.subnet_mask, NULL);
+ memcpy(data, (void *)¤t_http_ip,
+ sizeof(struct efi_ip4_config2_manual_address));
+
+ break;
+ default:
+ return EFI_EXIT(EFI_UNSUPPORTED);
+ break;
+ }
+ return EFI_EXIT(ret);
+}
+
+/*
+ * efi_ip4_config2_register_notify() - Register an event that is to be signaled whenever
+ * a configuration process on the specified configuration
+ * data is done
+ *
+ * This function implements EFI_IP4_CONFIG2_PROTOCOL.RegisterDataNotify()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @data_type: the type of data to register the event for
+ * @event: the event to register
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_ip4_config2_register_notify(struct efi_ip4_config2_protocol *this,
+ enum efi_ip4_config2_data_type data_type,
+ struct efi_event *event)
+{
+ EFI_ENTRY("%p, %d, %p", this, data_type, event);
+
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/*
+ * efi_ip4_config2_unregister_notify() - Remove a previously registered eventfor
+ * the specified configuration data
+ *
+ * This function implements EFI_IP4_CONFIG2_PROTOCOL.UnregisterDataNotify()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @data_type: the type of data to remove the event for
+ * @event: the event to unregister
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_ip4_config2_unregister_notify(struct efi_ip4_config2_protocol *this,
+ enum efi_ip4_config2_data_type data_type,
+ struct efi_event *event)
+{
+ EFI_ENTRY("%p, %d, %p", this, data_type, event);
+
+ return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/**
+ * efi_ipconfig_register() - register the ip4_config2 protocol
+ *
+ */
+efi_status_t efi_ipconfig_register(const efi_handle_t handle,
+ struct efi_ip4_config2_protocol *ip4config)
+{
+ efi_status_t r = EFI_SUCCESS;
+
+ r = efi_add_protocol(handle, &efi_ip4_config2_guid,
+ ip4config);
+ if (r != EFI_SUCCESS)
+ goto failure_to_add_protocol;
+
+ memcpy(current_mac_addr, eth_get_ethaddr(), 6);
+
+ ip4config->set_data = efi_ip4_config2_set_data;
+ ip4config->get_data = efi_ip4_config2_get_data;
+ ip4config->register_data_notify = efi_ip4_config2_register_notify;
+ ip4config->unregister_data_notify = efi_ip4_config2_unregister_notify;
+
+ return EFI_SUCCESS;
+failure_to_add_protocol:
+ printf("ERROR: Failure to add protocol\n");
+ return r;
+}
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 30234ae1c7..fa3b0c0007 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -54,11 +54,12 @@ static struct efi_event *wait_for_packet;
/**
* struct efi_net_obj - EFI object representing a network interface
*
- * @header: EFI object header
- * @net: simple network protocol interface
- * @net_mode: status of the network interface
- * @pxe: PXE base code protocol interface
- * @pxe_mode: status of the PXE base code protocol
+ * @header: EFI object header
+ * @net: simple network protocol interface
+ * @net_mode: status of the network interface
+ * @pxe: PXE base code protocol interface
+ * @pxe_mode: status of the PXE base code protocol
+ * @ip4_config2: IP4 Config2 protocol interface
*/
struct efi_net_obj {
struct efi_object header;
@@ -66,6 +67,9 @@ struct efi_net_obj {
struct efi_simple_network_mode net_mode;
struct efi_pxe_base_code_protocol pxe;
struct efi_pxe_mode pxe_mode;
+#ifdef CONFIG_EFI_IP4_CONFIG2_PROTOCOL
+ struct efi_ip4_config2_protocol ip4_config2;
+#endif
};
/*
@@ -993,6 +997,12 @@ efi_status_t efi_net_register(void)
return r;
}
+#ifdef CONFIG_EFI_IP4_CONFIG2_PROTOCOL
+ r = efi_ipconfig_register(&netobj->header, &netobj->ip4_config2);
+ if (r != EFI_SUCCESS)
+ goto failure_to_add_protocol;
+#endif
+
return EFI_SUCCESS;
failure_to_add_protocol:
printf("ERROR: Failure to add protocol\n");
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 12/15] efi_loader: efi_net: add EFI_HTTP_PROTOCOL
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (10 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 11/15] efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-12 14:02 ` Heinrich Schuchardt
2024-11-11 21:09 ` [PATCH v3 13/15] lib: uuid: display HTTP and IPV4 Config II protocols Adriano Cordova
` (3 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add an EFI HTTP driver. This commit implements the
EFI_HTTP_PROTOCOL and the EFI_HTTP_SERVICE_BINDING_PROTOCOL.
The latter is attached to the handle of th efi network
device. This is the same handle where snp, pxe, and ipconfig
are attached to.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
- Add documentation
- Clean up the way the buffer pointed to http_load_addr in the current
http instance was being freed.
- Remove unnecessary initialization new_instance->handle = NULL in
efi_http_service_binding_create_child.
include/efi_loader.h | 3 +
lib/efi_loader/Kconfig | 8 +
lib/efi_loader/Makefile | 1 +
lib/efi_loader/efi_http.c | 563 ++++++++++++++++++++++++++++++++++++++
lib/efi_loader/efi_net.c | 20 +-
5 files changed, 593 insertions(+), 2 deletions(-)
create mode 100644 lib/efi_loader/efi_http.c
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 5029ac39f1..dee7e1a9f3 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -630,6 +630,9 @@ efi_status_t efi_net_register(void);
/* Called by efi_net_register to make the ip4 config2 protocol available */
efi_status_t efi_ipconfig_register(const efi_handle_t handle,
struct efi_ip4_config2_protocol *ip4config);
+/* Called by efi_net_register to make the http protocol available */
+efi_status_t efi_http_register(const efi_handle_t handle,
+ struct efi_service_binding_protocol *http_service_binding);
/* Called by bootefi to make the watchdog available */
efi_status_t efi_watchdog_register(void);
efi_status_t efi_initrd_register(void);
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index d823b2855b..6d3309932c 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -485,6 +485,14 @@ config EFI_IP4_CONFIG2_PROTOCOL
protocol can be used to set and get the current ip address and
other network information.
+config EFI_HTTP_PROTOCOL
+ bool "EFI_HTTP_PROTOCOL support"
+ default y
+ depends on WGET
+ help
+ Provides an EFI HTTP driver implementing the EFI_HTTP_PROTOCOL. and
+ EFI_HTTP_SERVICE_BINDING_PROTOCOL.
+
endmenu
menu "Misc options"
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 30cd1de9d6..2a0b4172bd 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_VIDEO) += efi_gop.o
obj-$(CONFIG_BLK) += efi_disk.o
obj-$(CONFIG_NETDEVICES) += efi_net.o
obj-$(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) += efi_ipconfig.o
+obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_http.o
obj-$(CONFIG_ACPI) += efi_acpi.o
obj-$(CONFIG_SMBIOS) += efi_smbios.o
obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c
new file mode 100644
index 0000000000..75b8fc40ca
--- /dev/null
+++ b/lib/efi_loader/efi_http.c
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * An HTTP driver
+ *
+ * HTTP_PROTOCOL
+ * HTTP_SERVICE_BINDING_PROTOCOL
+ * IP4_CONFIG2_PROTOCOL
+ */
+
+#include <charset.h>
+#include <efi_loader.h>
+#include <image.h>
+#include <malloc.h>
+#include <mapmem.h>
+#include <net.h>
+
+static const efi_guid_t efi_http_service_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
+static const efi_guid_t efi_http_guid = EFI_HTTP_PROTOCOL_GUID;
+
+/**
+ * struct efi_http_instance - EFI object representing an HTTP protocol instance
+ *
+ * @http: EFI_HTTP_PROTOCOL interface
+ * @handle: handle to efi object
+ * @configured: configuration status
+ * @http_load_addr: data buffer
+ * @file_size: size of data
+ * @current_offset: offset in data buffer
+ * @status_code: HTTP status code
+ * @num_headers: number of received headers
+ * @headers: array of headers
+ * @headers_buffer: raw buffer with headers
+ */
+struct efi_http_instance {
+ struct efi_http_protocol http;
+ efi_handle_t handle;
+ bool configured;
+ ulong http_load_addr;
+ ulong file_size;
+ ulong current_offset;
+ u32 status_code;
+ ulong num_headers;
+ struct http_header headers[MAX_HTTP_HEADERS];
+ char headers_buffer[MAX_HTTP_HEADERS_SIZE];
+};
+
+static int num_instances;
+
+/*
+ * efi_u32_to_httpstatus() - convert u32 to status
+ *
+ */
+enum efi_http_status_code efi_u32_to_httpstatus(u32 status);
+
+/*
+ * efi_http_send_data() - sends data to client
+ *
+ *
+ * @client_buffer: client buffer to send data to
+ * @client_buffer_size: size of the client buffer
+ * @inst: HTTP instance for which to send data
+ *
+ * Return: status code
+ */
+static efi_status_t efi_http_send_data(void *client_buffer,
+ efi_uintn_t *client_buffer_size,
+ struct efi_http_instance *inst)
+{
+ efi_status_t ret = EFI_SUCCESS;
+ ulong total_size, transfer_size;
+ uchar *ptr;
+
+ // Amount of data left;
+ total_size = inst->file_size;
+ transfer_size = total_size - inst->current_offset;
+ debug("efi_http: sending data to client, total size %lu\n", total_size);
+ // Amount of data the client is willing to receive
+ if (transfer_size > *client_buffer_size)
+ transfer_size = *client_buffer_size;
+ else
+ *client_buffer_size = transfer_size;
+ debug("efi_http: transfer size %lu\n", transfer_size);
+ if (!transfer_size) // Ok, only headers
+ goto out;
+
+ if (!client_buffer) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ // Send data
+ ptr = map_sysmem(inst->http_load_addr + inst->current_offset, transfer_size);
+ memcpy(client_buffer, ptr, transfer_size);
+ unmap_sysmem(ptr);
+
+ inst->current_offset += transfer_size;
+
+ // Whole file served, clean the buffer:
+ if (inst->current_offset == inst->file_size) {
+ efi_free_pool((void *)inst->http_load_addr);
+ inst->http_load_addr = 0;
+ inst->current_offset = 0;
+ inst->file_size = 0;
+ }
+
+out:
+ return ret;
+}
+
+/* EFI_HTTP_PROTOCOL */
+
+/*
+ * efi_http_get_mode_data() - Gets the current operational status.
+ *
+ * This function implements EFI_HTTP_PROTOCOL.GetModeData()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @data: pointer to the buffer for operational parameters
+ * of this HTTP instance
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_http_get_mode_data(struct efi_http_protocol *this,
+ struct efi_http_config_data *data)
+{
+ EFI_ENTRY("%p, %p", this, data);
+
+ efi_status_t ret = EFI_UNSUPPORTED;
+
+ return EFI_EXIT(ret);
+}
+
+/*
+ * efi_http_configure() - Initializes operational status for this
+ * EFI HTTP instance.
+ *
+ * This function implements EFI_HTTP_PROTOCOL.Configure()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @data: pointer to the buffer for operational parameters of
+ * this HTTP instance
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_http_configure(struct efi_http_protocol *this,
+ struct efi_http_config_data *data)
+{
+ EFI_ENTRY("%p, %p", this, data);
+
+ efi_status_t ret = EFI_SUCCESS;
+ enum efi_http_version http_version;
+ struct efi_httpv4_access_point *ipv4_node;
+ struct efi_http_instance *http_instance;
+
+ if (!this) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ http_instance = (struct efi_http_instance *)this;
+
+ if (!data) {
+ efi_free_pool((void *)http_instance->http_load_addr);
+ http_instance->http_load_addr = 0;
+ http_instance->current_offset = 0;
+ http_instance->configured = false;
+
+ goto out;
+ }
+
+ if (http_instance->configured) {
+ ret = EFI_ALREADY_STARTED;
+ goto out;
+ }
+
+ http_version = data->http_version;
+ ipv4_node = data->access_point.ipv4_node;
+
+ if ((http_version != HTTPVERSION10 &&
+ http_version != HTTPVERSION11) ||
+ data->is_ipv6 || !ipv4_node) { /* Only support ipv4 */
+ ret = EFI_UNSUPPORTED;
+ goto out;
+ }
+
+ if (!ipv4_node->use_default_address) {
+ efi_net_set_addr((struct efi_ipv4_address *)&ipv4_node->local_address,
+ (struct efi_ipv4_address *)&ipv4_node->local_subnet, NULL);
+ }
+
+ http_instance->current_offset = 0;
+ http_instance->configured = true;
+
+out:
+ return EFI_EXIT(ret);
+}
+
+/*
+ * efi_http_request() - Queues an HTTP request to this HTTP instance
+ *
+ * This function implements EFI_HTTP_PROTOCOL.Request()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @token: pointer to storage containing HTTP request token
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_http_request(struct efi_http_protocol *this,
+ struct efi_http_token *token)
+{
+ EFI_ENTRY("%p, %p", this, token);
+
+ efi_status_t ret = EFI_SUCCESS;
+ u8 *tmp;
+ u8 url_8[1024];
+ u16 *url_16;
+ enum efi_http_method current_method;
+ struct efi_http_instance *http_instance;
+
+ if (!token || !this) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ http_instance = (struct efi_http_instance *)this;
+
+ if (!http_instance->configured) {
+ ret = EFI_NOT_STARTED;
+ goto out;
+ }
+
+ if (!token->message || !token->message->data.request)
+ goto out_invalid;
+
+ current_method = token->message->data.request->method;
+ url_16 = token->message->data.request->url;
+
+ /* Parse URL. It comes in UCS-2 encoding and follows RFC3986 */
+ tmp = url_8;
+ utf16_utf8_strncpy((char **)&tmp, url_16, 1024);
+
+ ret = efi_net_do_request(url_8, current_method, &http_instance->http_load_addr,
+ &http_instance->status_code, &http_instance->file_size,
+ http_instance->headers_buffer);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
+ // We have a new file
+ efi_net_parse_headers(&http_instance->num_headers, http_instance->headers);
+ http_instance->current_offset = 0;
+ token->status = EFI_SUCCESS;
+ goto out_signal;
+
+out_invalid:
+ ret = EFI_INVALID_PARAMETER;
+ token->status = EFI_ABORTED;
+out_signal:
+ efi_signal_event(token->event);
+out:
+ return EFI_EXIT(ret);
+}
+
+/*
+ * efi_http_cancel() - Abort an asynchronous HTTP request or response token
+ *
+ * This function implements EFI_HTTP_PROTOCOL.Cancel()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @token: pointer to storage containing HTTP request token
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_http_cancel(struct efi_http_protocol *this,
+ struct efi_http_token *token)
+{
+ EFI_ENTRY("%p, %p", this, token);
+
+ efi_status_t ret = EFI_UNSUPPORTED;
+
+ return EFI_EXIT(ret);
+}
+
+/*
+ * efi_http_response() - Queues an HTTP response to this HTTP instance
+ *
+ * This function implements EFI_HTTP_PROTOCOL.Response()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @token: pointer to storage containing HTTP request token
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_http_response(struct efi_http_protocol *this,
+ struct efi_http_token *token)
+{
+ EFI_ENTRY("%p, %p", this, token);
+
+ efi_status_t ret = EFI_SUCCESS;
+ struct efi_http_instance *http_instance;
+ struct efi_http_header **client_headers;
+ struct efi_http_response_data *response;
+
+ if (!token) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (!this || !token->message)
+ goto out_invalid;
+
+ http_instance = (struct efi_http_instance *)this;
+
+ // Set HTTP status code
+ if (token->message->data.response) { // TODO extra check, see spec.
+ response = token->message->data.response;
+ response->status_code = efi_u32_to_httpstatus(http_instance->status_code);
+ }
+ client_headers = &token->message->headers;
+ ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA,
+ (http_instance->num_headers) * sizeof(struct efi_http_header),
+ (void **)client_headers); // This is deallocated by the client.
+ if (ret != EFI_SUCCESS)
+ goto out_bad_signal;
+
+ // Send headers
+ token->message->header_count = http_instance->num_headers;
+ for (int i = 0; i < http_instance->num_headers; i++) {
+ (*client_headers)[i].field_name = http_instance->headers[i].name;
+ (*client_headers)[i].field_value = http_instance->headers[i].value;
+ }
+ if (ret != EFI_SUCCESS)
+ goto out_bad_signal;
+
+ ret = efi_http_send_data(token->message->body, &token->message->body_length, http_instance);
+ if (ret != EFI_SUCCESS)
+ goto out_bad_signal;
+
+ token->status = EFI_SUCCESS;
+ goto out_signal;
+
+out_invalid:
+ ret = EFI_INVALID_PARAMETER;
+out_bad_signal:
+ token->status = EFI_ABORTED;
+out_signal:
+ efi_signal_event(token->event);
+out:
+ return EFI_EXIT(ret);
+}
+
+/*
+ * efi_http_poll() - Polls for incoming data packets and processes outgoing data packets
+ *
+ * This function implements EFI_HTTP_PROTOCOL.Poll()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @token: pointer to storage containing HTTP request token
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_http_poll(struct efi_http_protocol *this)
+{
+ EFI_ENTRY("%p", this);
+
+ efi_status_t ret = EFI_UNSUPPORTED;
+
+ return EFI_EXIT(ret);
+}
+
+/* EFI_HTTP_SERVICE_BINDING_PROTOCOL */
+
+/*
+ * efi_http_service_binding_create_child() - Creates a child handle
+ * and installs a protocol
+ *
+ * This function implements EFI_HTTP_SERVICE_BINDING.CreateChild()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @child_handle: pointer to child handle
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_http_service_binding_create_child(
+ struct efi_service_binding_protocol *this,
+ efi_handle_t *child_handle)
+{
+ EFI_ENTRY("%p, %p", this, child_handle);
+
+ efi_status_t ret = EFI_SUCCESS;
+ struct efi_http_instance *new_instance;
+
+ if (!child_handle)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ new_instance = calloc(1, sizeof(struct efi_http_instance));
+ if (!new_instance) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto failure_to_add_protocol;
+ }
+
+ if (*child_handle) {
+ new_instance->handle = *child_handle;
+ goto install;
+ }
+
+ new_instance->handle = calloc(1, sizeof(struct efi_object));
+ if (!new_instance->handle) {
+ efi_free_pool((void *)new_instance);
+ ret = EFI_OUT_OF_RESOURCES;
+ goto failure_to_add_protocol;
+ }
+
+ efi_add_handle(new_instance->handle);
+ *child_handle = new_instance->handle;
+
+install:
+ ret = efi_add_protocol(new_instance->handle, &efi_http_guid,
+ &new_instance->http);
+ if (ret != EFI_SUCCESS)
+ goto failure_to_add_protocol;
+
+ new_instance->http.get_mode_data = efi_http_get_mode_data;
+ new_instance->http.configure = efi_http_configure;
+ new_instance->http.request = efi_http_request;
+ new_instance->http.cancel = efi_http_cancel;
+ new_instance->http.response = efi_http_response;
+ new_instance->http.poll = efi_http_poll;
+ ++num_instances;
+
+ return EFI_EXIT(EFI_SUCCESS);
+
+failure_to_add_protocol:
+ printf("ERROR: Failure to add protocol\n");
+ return EFI_EXIT(ret);
+}
+
+/*
+ * efi_http_service_binding_destroy_child() - Destroys a child handle with
+ * a protocol installed on it
+ *
+ * This function implements EFI_HTTP_SERVICE_BINDING.DestroyChild()
+ * See the Unified Extensible Firmware Interface
+ * (UEFI) specification for details.
+ *
+ * @this: pointer to the protocol instance
+ * @child_handle: child handle
+ * Return: status code
+ */
+static efi_status_t EFIAPI efi_http_service_binding_destroy_child(
+ struct efi_service_binding_protocol *this,
+ efi_handle_t child_handle)
+{
+ EFI_ENTRY("%p, %p", this, child_handle);
+ efi_status_t ret = EFI_SUCCESS;
+ struct efi_http_instance *http_instance;
+ struct efi_handler *phandler;
+ void *protocol_interface;
+
+ if (num_instances == 0)
+ return EFI_EXIT(EFI_NOT_FOUND);
+
+ if (!child_handle)
+ return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+ efi_search_protocol(child_handle, &efi_http_guid, &phandler);
+
+ if (phandler)
+ protocol_interface = phandler->protocol_interface;
+
+ ret = efi_delete_handle(child_handle);
+ if (ret != EFI_SUCCESS) {
+ printf("ERROR: Failure to remove protocol\n");
+ return EFI_EXIT(ret);
+ }
+
+ http_instance = (struct efi_http_instance *)protocol_interface;
+ efi_free_pool((void *)http_instance->http_load_addr);
+ http_instance->http_load_addr = 0;
+
+ free(protocol_interface);
+
+ num_instances--;
+
+ return EFI_EXIT(EFI_SUCCESS);
+}
+
+/**
+ * efi_http_register() - register the http protocol
+ *
+ */
+efi_status_t efi_http_register(const efi_handle_t handle,
+ struct efi_service_binding_protocol *http_service_binding)
+{
+ efi_status_t r = EFI_SUCCESS;
+
+ r = efi_add_protocol(handle, &efi_http_service_binding_guid,
+ http_service_binding);
+ if (r != EFI_SUCCESS)
+ goto failure_to_add_protocol;
+
+ http_service_binding->create_child = efi_http_service_binding_create_child;
+ http_service_binding->destroy_child = efi_http_service_binding_destroy_child;
+
+ return EFI_SUCCESS;
+failure_to_add_protocol:
+ printf("ERROR: Failure to add protocol\n");
+ return r;
+}
+
+enum efi_http_status_code efi_u32_to_httpstatus(u32 status)
+{
+ switch (status) {
+ case 100: return HTTP_STATUS_100_CONTINUE;
+ case 101: return HTTP_STATUS_101_SWITCHING_PROTOCOLS;
+ case 200: return HTTP_STATUS_200_OK;
+ case 201: return HTTP_STATUS_201_CREATED;
+ case 202: return HTTP_STATUS_202_ACCEPTED;
+ case 203: return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION;
+ case 204: return HTTP_STATUS_204_NO_CONTENT;
+ case 205: return HTTP_STATUS_205_RESET_CONTENT;
+ case 206: return HTTP_STATUS_206_PARTIAL_CONTENT;
+ case 300: return HTTP_STATUS_300_MULTIPLE_CHOICES;
+ case 301: return HTTP_STATUS_301_MOVED_PERMANENTLY;
+ case 302: return HTTP_STATUS_302_FOUND;
+ case 303: return HTTP_STATUS_303_SEE_OTHER;
+ case 304: return HTTP_STATUS_304_NOT_MODIFIED;
+ case 305: return HTTP_STATUS_305_USE_PROXY;
+ case 307: return HTTP_STATUS_307_TEMPORARY_REDIRECT;
+ case 400: return HTTP_STATUS_400_BAD_REQUEST;
+ case 401: return HTTP_STATUS_401_UNAUTHORIZED;
+ case 402: return HTTP_STATUS_402_PAYMENT_REQUIRED;
+ case 403: return HTTP_STATUS_403_FORBIDDEN;
+ case 404: return HTTP_STATUS_404_NOT_FOUND;
+ case 405: return HTTP_STATUS_405_METHOD_NOT_ALLOWED;
+ case 406: return HTTP_STATUS_406_NOT_ACCEPTABLE;
+ case 407: return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED;
+ case 408: return HTTP_STATUS_408_REQUEST_TIME_OUT;
+ case 409: return HTTP_STATUS_409_CONFLICT;
+ case 410: return HTTP_STATUS_410_GONE;
+ case 411: return HTTP_STATUS_411_LENGTH_REQUIRED;
+ case 412: return HTTP_STATUS_412_PRECONDITION_FAILED;
+ case 413: return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE;
+ case 414: return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE;
+ case 415: return HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE;
+ case 416: return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED;
+ case 417: return HTTP_STATUS_417_EXPECTATION_FAILED;
+ case 500: return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;
+ case 501: return HTTP_STATUS_501_NOT_IMPLEMENTED;
+ case 502: return HTTP_STATUS_502_BAD_GATEWAY;
+ case 503: return HTTP_STATUS_503_SERVICE_UNAVAILABLE;
+ case 504: return HTTP_STATUS_504_GATEWAY_TIME_OUT;
+ case 505: return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;
+ case 308: return HTTP_STATUS_308_PERMANENT_REDIRECT;
+ default: return HTTP_STATUS_UNSUPPORTED_STATUS;
+ }
+}
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index fa3b0c0007..de22c85acf 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -60,6 +60,7 @@ static struct efi_event *wait_for_packet;
* @pxe: PXE base code protocol interface
* @pxe_mode: status of the PXE base code protocol
* @ip4_config2: IP4 Config2 protocol interface
+ * @http_service_binding: Http service binding protocol interface
*/
struct efi_net_obj {
struct efi_object header;
@@ -70,6 +71,9 @@ struct efi_net_obj {
#ifdef CONFIG_EFI_IP4_CONFIG2_PROTOCOL
struct efi_ip4_config2_protocol ip4_config2;
#endif
+#ifdef CONFIG_EFI_HTTP_PROTOCOL
+ struct efi_service_binding_protocol http_service_binding;
+#endif
};
/*
@@ -1003,6 +1007,19 @@ efi_status_t efi_net_register(void)
goto failure_to_add_protocol;
#endif
+#ifdef CONFIG_EFI_HTTP_PROTOCOL
+ r = efi_http_register(&netobj->header, &netobj->http_service_binding);
+ if (r != EFI_SUCCESS)
+ goto failure_to_add_protocol;
+ /*
+ * No harm on doing the following. If the PXE handle is present, the client could
+ * find it and try to get its IP address from it. In here the PXE handle is present
+ * but the PXE protocol is not yet implmenented, so we add this in the meantime.
+ */
+ efi_net_get_addr((struct efi_ipv4_address *)&netobj->pxe_mode.station_ip,
+ (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL);
+#endif
+
return EFI_SUCCESS;
failure_to_add_protocol:
printf("ERROR: Failure to add protocol\n");
@@ -1162,8 +1179,6 @@ static efi_status_t efi_net_set_buffer(ulong *buffer, ulong size)
if (size < SZ_64K)
size = SZ_64K;
- efi_free_pool((void *)*buffer);
-
*buffer = (ulong)efi_alloc(size);
if (!*buffer)
ret = EFI_OUT_OF_RESOURCES;
@@ -1250,6 +1265,7 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, ulong *buf
wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info);
if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) {
// Try again with updated buffer size
+ efi_free_pool((void *)*buffer);
ret = efi_net_set_buffer(buffer, (ulong)efi_wget_info.hdr_cont_len);
if (ret != EFI_SUCCESS)
goto out;
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 13/15] lib: uuid: display HTTP and IPV4 Config II protocols
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (11 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 12/15] efi_loader: efi_net: add EFI_HTTP_PROTOCOL Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-13 8:09 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 14/15] efi_selftest: add test for HTTP protocol Adriano Cordova
` (2 subsequent siblings)
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Heinrich Schuchardt, Adriano Cordova
From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Add long texts for
* EFI HTTP Protocol
* EFI HTTP Service Binding Protocol
* EFI IPv4 Configuration II Protocol
to the uuid library.
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
lib/uuid.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/lib/uuid.c b/lib/uuid.c
index c6a27b7d04..3b2cf60fe1 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -174,6 +174,20 @@ static const struct {
"Firmware Management",
EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID
},
+#if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL)
+ {
+ "HTTP",
+ EFI_HTTP_PROTOCOL_GUID,
+ },
+ {
+ "HTTP Service Binding",
+ EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID,
+ },
+ {
+ "IPv4 Config2",
+ EFI_IP4_CONFIG2_PROTOCOL_GUID,
+ },
+#endif
/* Configuration table GUIDs */
{
"ACPI table",
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 14/15] efi_selftest: add test for HTTP protocol
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (12 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 13/15] lib: uuid: display HTTP and IPV4 Config II protocols Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-11 21:09 ` [PATCH v3 15/15] efi_selftest: add test for IPv4 Config2 protocol Adriano Cordova
2024-11-14 15:22 ` [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Ilias Apalodimas
15 siblings, 0 replies; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add a test for the EFI_HTTP_PROTOCOL and
EFI_SEVICE_BINDING_PROTOCOL.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
lib/efi_selftest/Makefile | 2 +-
lib/efi_selftest/efi_selftest_http.c | 315 +++++++++++++++++++++++++++
2 files changed, 316 insertions(+), 1 deletion(-)
create mode 100644 lib/efi_selftest/efi_selftest_http.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 414701893f..140c08effc 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -52,7 +52,7 @@ efi_selftest_watchdog.o
obj-$(CONFIG_EFI_ECPT) += efi_selftest_ecpt.o
obj-$(CONFIG_NETDEVICES) += efi_selftest_snp.o
-
+obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_http.o
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o
obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += \
efi_selftest_unicode_collation.o
diff --git a/lib/efi_selftest/efi_selftest_http.c b/lib/efi_selftest/efi_selftest_http.c
new file mode 100644
index 0000000000..ce3cf33887
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_http.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * efi_selftest_http
+ *
+ * This unit test covers the IPv4 Config2 Protocol, Http Service Binding Protocol,
+ * and Http Protocol.
+ *
+ * An Http HEAD and an Http GET request are sent to the same destination. The test
+ * is successful if the HEAD request gets a response with a valid Content-Length header
+ * and the subsequent GET request receives the amount of bytes informed by the previous
+ * Content-Length header.
+ *
+ */
+
+#include <efi_selftest.h>
+#include <charset.h>
+#include <net.h>
+
+static struct efi_boot_services *boottime;
+
+static struct efi_http_protocol *http;
+static struct efi_service_binding_protocol *http_service;
+static struct efi_ip4_config2_protocol *ip4_config2;
+static efi_handle_t http_protocol_handle;
+
+static const efi_guid_t efi_http_guid = EFI_HTTP_PROTOCOL_GUID;
+static const efi_guid_t efi_http_service_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
+static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
+static int callback_done;
+
+/*
+ * Setup unit test.
+ *
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ efi_status_t ret;
+ efi_handle_t *net_handle;
+ efi_uintn_t num_handles;
+ efi_handle_t *handles;
+ struct efi_http_config_data http_config;
+ struct efi_httpv4_access_point ipv4_node;
+
+ boottime = systable->boottime;
+
+ boottime->locate_handle_buffer(BY_PROTOCOL, &efi_ip4_config2_guid,
+ NULL, &num_handles, &handles);
+
+ for (net_handle = handles; num_handles--; net_handle++) {
+ ret = boottime->open_protocol(*net_handle, &efi_ip4_config2_guid,
+ (void **)&ip4_config2, 0, 0,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS || !ip4_config2)
+ continue;
+ ret = boottime->open_protocol(*net_handle,
+ &efi_http_service_binding_guid,
+ (void **)&http_service, 0, 0,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS || !http_service)
+ continue;
+ break; // Get first handle that supports both protocols
+ }
+
+ if (!ip4_config2 || !http_service) {
+ efi_st_error("Failed to locate ipv4 config2 or http service binding protocol\n");
+ return EFI_ST_FAILURE;
+ }
+
+ http_protocol_handle = NULL;
+ ret = http_service->create_child(http_service, &http_protocol_handle);
+ if (ret != EFI_SUCCESS || !http_protocol_handle) {
+ efi_st_error("Failed to create an http service instance\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = boottime->open_protocol(http_protocol_handle, &efi_http_guid,
+ (void **)&http, 0, 0, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS || !http) {
+ efi_st_error("Failed to open http protocol\n");
+ return EFI_ST_FAILURE;
+ }
+ efi_st_printf("HTTP Service Binding: child created successfully\n");
+
+ http_config.http_version = HTTPVERSION11;
+ http_config.is_ipv6 = false;
+ http_config.access_point.ipv4_node = &ipv4_node;
+ ipv4_node.use_default_address = true;
+
+ ret = http->configure(http, &http_config);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to configure http instance\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+void EFIAPI efi_test_http_callback(struct efi_event *event, void *context)
+{
+ callback_done = 1;
+}
+
+/*
+ * Execute unit test.
+ *
+ *
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ efi_status_t ret;
+ struct efi_http_request_data request_data;
+ struct efi_http_message request_message;
+ struct efi_http_token request_token;
+ struct efi_http_response_data response_data;
+ struct efi_http_message response_message;
+ struct efi_http_token response_token;
+ enum efi_http_status_code status_code;
+ void *response_buffer;
+ efi_uintn_t len, sum;
+ char *url = "http://example.com/";
+ u16 url_16[64];
+ u16 *tmp;
+
+ /* Setup may have failed */
+ if (!ip4_config2 || !http) {
+ efi_st_error("Cannot proceed with test after setup failure\n");
+ return EFI_ST_FAILURE;
+ }
+
+ tmp = url_16;
+ utf8_utf16_strcpy(&tmp, url);
+ request_data.url = url_16;
+ request_data.method = HTTP_METHOD_GET;
+
+ request_message.data.request = &request_data;
+ request_message.header_count = 3;
+ request_message.body_length = 0;
+ request_message.body = NULL;
+
+ /* request token */
+ request_token.event = NULL;
+ request_token.status = EFI_NOT_READY;
+ request_token.message = &request_message;
+ callback_done = 0;
+ ret = boottime->create_event(EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ efi_test_http_callback,
+ NULL,
+ &request_token.event);
+
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to create request event\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = http->request(http, &request_token);
+
+ if (ret != EFI_SUCCESS) {
+ boottime->close_event(request_token.event);
+ efi_st_printf("Failed to proceed with the http request\n");
+ return EFI_ST_SUCCESS;
+ }
+
+ while (!callback_done)
+ http->poll(http);
+
+ response_data.status_code = HTTP_STATUS_UNSUPPORTED_STATUS;
+ response_message.data.response = &response_data;
+ response_message.header_count = 0;
+ response_message.headers = NULL;
+ response_message.body_length = 0;
+ response_message.body = NULL;
+ response_token.event = NULL;
+
+ ret = boottime->create_event(EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ efi_test_http_callback,
+ NULL,
+ &response_token.event);
+
+ if (ret != EFI_SUCCESS) {
+ boottime->close_event(request_token.event);
+ efi_st_error("Failed to create response event\n");
+ return EFI_ST_FAILURE;
+ }
+
+ response_token.status = EFI_SUCCESS;
+ response_token.message = &response_message;
+
+ callback_done = 0;
+ ret = http->response(http, &response_token);
+
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed http first response\n");
+ goto fail;
+ }
+
+ while (!callback_done)
+ http->poll(http);
+
+ if (response_message.data.response->status_code != HTTP_STATUS_200_OK) {
+ status_code = response_message.data.response->status_code;
+ if (status_code == HTTP_STATUS_404_NOT_FOUND) {
+ efi_st_error("File not found\n");
+ } else {
+ efi_st_error("Bad http status %d\n",
+ response_message.data.response->status_code);
+ }
+ goto fail_free_hdr;
+ }
+
+ ret = boottime->allocate_pool(EFI_LOADER_CODE, response_message.body_length,
+ &response_buffer);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed allocating response buffer\n");
+ goto fail_free_hdr;
+ }
+
+ len = response_message.body_length;
+ sum = 0;
+ while (len) {
+ response_message.data.response = NULL;
+ response_message.header_count = 0;
+ response_message.headers = NULL;
+ response_message.body_length = len;
+ response_message.body = response_buffer + sum;
+
+ response_token.message = &response_message;
+ response_token.status = EFI_NOT_READY;
+
+ callback_done = 0;
+ ret = http->response(http, &response_token);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed http second response\n");
+ goto fail_free_buf;
+ }
+
+ while (!callback_done)
+ http->poll(http);
+
+ if (!response_message.body_length)
+ break;
+
+ len -= response_message.body_length;
+ sum += response_message.body_length;
+ }
+
+ if (len)
+ goto fail_free_buf;
+
+ boottime->free_pool(response_buffer);
+ if (response_message.headers)
+ boottime->free_pool(response_message.headers);
+ boottime->close_event(request_token.event);
+ boottime->close_event(response_token.event);
+ efi_st_printf("Efi Http request executed successfully\n");
+ return EFI_ST_SUCCESS;
+
+fail_free_buf:
+ boottime->free_pool(response_buffer);
+fail_free_hdr:
+ if (response_message.headers)
+ boottime->free_pool(response_message.headers);
+fail:
+ boottime->close_event(request_token.event);
+ boottime->close_event(response_token.event);
+ return EFI_ST_FAILURE;
+}
+
+/*
+ * Tear down unit test.
+ *
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int teardown(void)
+{
+ efi_status_t ret;
+ int exit_status = EFI_ST_SUCCESS;
+
+ if (!http_service || !http_protocol_handle) {
+ efi_st_error("No handles to destroy http instance");
+ exit_status = EFI_ST_FAILURE;
+ } else {
+ ret = http_service->destroy_child(http_service, http_protocol_handle);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to destroy http instance");
+ exit_status = EFI_ST_FAILURE;
+ }
+ efi_st_printf("HTTP Service Binding: child destroyed successfully\n");
+ }
+
+ return exit_status;
+}
+
+EFI_UNIT_TEST(http) = {
+ .name = "http protocol",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+ .teardown = teardown,
+#ifdef CONFIG_SANDBOX
+ /*
+ * Running this test on the sandbox requires setting environment
+ * variable ethact to a network interface connected to a DHCP server and
+ * ethrotate to 'no'.
+ */
+ .on_request = true,
+#endif
+};
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* [PATCH v3 15/15] efi_selftest: add test for IPv4 Config2 protocol
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (13 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 14/15] efi_selftest: add test for HTTP protocol Adriano Cordova
@ 2024-11-11 21:09 ` Adriano Cordova
2024-11-18 12:27 ` Ilias Apalodimas
2024-11-14 15:22 ` [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Ilias Apalodimas
15 siblings, 1 reply; 39+ messages in thread
From: Adriano Cordova @ 2024-11-11 21:09 UTC (permalink / raw)
To: u-boot
Cc: joe.hershberger, rfried.dev, jerome.forissier, xypron.glpk,
ilias.apalodimas, Adriano Cordova
Add a test for the EFI_IP4_CONFIG2_PROTOCOL. The test sets the ip
policy to static, adds an ip address, and then reads the current
ip address and checks for it to be the same as the one that was set.
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
(no changes since v2)
lib/efi_selftest/Makefile | 2 +
lib/efi_selftest/efi_selftest_ipconfig.c | 173 +++++++++++++++++++++++
2 files changed, 175 insertions(+)
create mode 100644 lib/efi_selftest/efi_selftest_ipconfig.c
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 140c08effc..17fbfad116 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -53,6 +53,8 @@ efi_selftest_watchdog.o
obj-$(CONFIG_EFI_ECPT) += efi_selftest_ecpt.o
obj-$(CONFIG_NETDEVICES) += efi_selftest_snp.o
obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_http.o
+obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_ipconfig.o
+
obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o
obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += \
efi_selftest_unicode_collation.o
diff --git a/lib/efi_selftest/efi_selftest_ipconfig.c b/lib/efi_selftest/efi_selftest_ipconfig.c
new file mode 100644
index 0000000000..e81ab4e334
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_ipconfig.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * efi_selftest_ipconfig
+ *
+ * This unit test covers the IPv4 Config2 Protocol.
+ *
+ */
+
+#include <efi_selftest.h>
+#include <charset.h>
+#include <net.h>
+
+static struct efi_boot_services *boottime;
+
+static struct efi_ip4_config2_protocol *ip4_config2;
+static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
+
+/*
+ * Setup unit test.
+ *
+ * Open IPv4 Config2 protocol
+ *
+ * @handle: handle of the loaded image
+ * @systable: system table
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+ const struct efi_system_table *systable)
+{
+ efi_status_t ret;
+ efi_handle_t *net_handle;
+ efi_uintn_t num_handles;
+ efi_handle_t *handles;
+
+ boottime = systable->boottime;
+
+ boottime->locate_handle_buffer(BY_PROTOCOL, &efi_ip4_config2_guid,
+ NULL, &num_handles, &handles);
+
+ for (net_handle = handles; num_handles--; net_handle++) {
+ ret = boottime->open_protocol(*net_handle, &efi_ip4_config2_guid,
+ (void **)&ip4_config2, 0, 0,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (ret != EFI_SUCCESS || !ip4_config2)
+ continue;
+ break; // Get first handle that supports ipv4
+ }
+
+ if (!ip4_config2) {
+ efi_st_error("Failed to locate ipv4 config2 protocol\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Execute unit test.
+ *
+ *
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+ efi_status_t ret;
+ enum efi_ip4_config2_policy policy;
+ efi_uintn_t data_size;
+ struct efi_ip4_config2_manual_address manual_address;
+ struct efi_ip4_config2_manual_address orig_address;
+ u8 netmask[] = {255, 255, 255, 0};
+ u8 ip[] = {10, 0, 0, 1};
+
+ /* Setup may have failed */
+ if (!ip4_config2) {
+ efi_st_error("Setup failure, cannot proceed with test\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Set policy to static */
+ policy = EFI_IP4_CONFIG2_POLICY_STATIC;
+ ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
+ sizeof(enum efi_ip4_config2_policy), (void *)&policy);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to set policy\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Save original ip address and netmask */
+ data_size = sizeof(struct efi_ip4_config2_manual_address);
+ ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ &data_size, &orig_address);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to save original ip address and netmask\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Set static ip and netmask */
+ memcpy((void *)&manual_address.address, (void *)ip,
+ sizeof(struct efi_ipv4_address));
+ memcpy((void *)&manual_address.subnet_mask, (void *)netmask,
+ sizeof(struct efi_ipv4_address));
+ ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ sizeof(struct efi_ip4_config2_manual_address), &manual_address);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to get ip address and netmask\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Try to set interface info, this should fail */
+ ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, 0, NULL);
+ if (ret == EFI_SUCCESS) {
+ efi_st_error("Interface info is read-only\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Get ip address and netmask and check that they match with the previously set ones */
+ data_size = sizeof(struct efi_ip4_config2_manual_address);
+ ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ &data_size, &manual_address);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to get ip address and netmask\n");
+ return EFI_ST_FAILURE;
+ }
+ if (memcmp((void *)ip, (void *)&manual_address.address,
+ sizeof(struct efi_ipv4_address)) ||
+ memcmp((void *)netmask, (void *)&manual_address.subnet_mask,
+ sizeof(struct efi_ipv4_address))) {
+ efi_st_error("Ip address mismatch\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Restore original ip address and netmask */
+ ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ sizeof(struct efi_ip4_config2_manual_address), &orig_address);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("Failed to restore original ip address and netmask\n");
+ return EFI_ST_FAILURE;
+ }
+
+ efi_st_printf("Efi ipconfig test execute succeeded\n");
+ return EFI_ST_SUCCESS;
+}
+
+/*
+ * Tear down unit test.
+ *
+ * Close the timer event created in setup.
+ * Shut down the network adapter.
+ *
+ * Return: EFI_ST_SUCCESS for success
+ */
+static int teardown(void)
+{
+ int exit_status = EFI_ST_SUCCESS;
+
+ return exit_status;
+}
+
+EFI_UNIT_TEST(ipconfig) = {
+ .name = "IPv4 config2 protocol",
+ .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+ .setup = setup,
+ .execute = execute,
+ .teardown = teardown,
+#ifdef CONFIG_SANDBOX
+ /*
+ * Running this test on the sandbox requires setting environment
+ * variable ethact to a network interface connected to a DHCP server and
+ * ethrotate to 'no'.
+ */
+ .on_request = true,
+#endif
+};
--
2.43.0
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [PATCH v3 10/15] efi_loader: net: add support to send http requests and parse http headers
2024-11-11 21:09 ` [PATCH v3 10/15] efi_loader: net: add support to send http requests and parse http headers Adriano Cordova
@ 2024-11-12 13:51 ` Heinrich Schuchardt
2024-11-13 14:02 ` Adriano Córdova
0 siblings, 1 reply; 39+ messages in thread
From: Heinrich Schuchardt @ 2024-11-12 13:51 UTC (permalink / raw)
To: Adriano Cordova
Cc: joe.hershberger, rfried.dev, jerome.forissier, ilias.apalodimas,
u-boot
On 11.11.24 22:09, Adriano Cordova wrote:
> Add network-stack agnostic way to send an http request and
> parse http headers from efi drivers. This uses wget as a
> backend and communicates with it via efi_wget_info.
>
> The function efi_net_do_request allocates a buffer on behalf of an
> efi application using efi_alloc and passes it to wget to receive
> the data. If the method is GET and the buffer is too small, it
> re-allocates the buffer based on the last received Content-Length
> header and tries again. If the method is HEAD it just issues one
> request. So issuing a HEAD request (to update Content-Length) and
> then a GET request is preferred but not required.
>
> The function efi_net_parse_headers parses a raw buffer containing
> an http header into an array of EFI specific 'http_header' structs.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> Changes in v3:
> - Add a struct wget_http_info efi_wget_info for efi_net to pass to wget
> when issuing wget requests, instead of using the old wget_info (see v2
> of the series 'wget: Expose wget to applications').
> - Let a pointer to the http status code be passed to efi_net_do_request
> for it to fill it for the client after a request.
>
> include/efi_loader.h | 13 ++++
> lib/efi_loader/efi_net.c | 158 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 171 insertions(+)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index f49f8e6be0..4d05c08441 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -16,6 +16,7 @@
> #include <image.h>
> #include <pe.h>
> #include <linux/list.h>
> +#include <linux/sizes.h>
> #include <linux/oid_registry.h>
>
> struct blk_desc;
> @@ -136,6 +137,18 @@ void efi_net_get_addr(struct efi_ipv4_address *ip,
> void efi_net_set_addr(struct efi_ipv4_address *ip,
> struct efi_ipv4_address *mask,
> struct efi_ipv4_address *gw);
> +efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, ulong *buffer,
> + u32 *status_code, ulong *file_size, char *headers_buffer);
> +#define MAX_HTTP_HEADERS_SIZE SZ_64K
> +#define MAX_HTTP_HEADERS 100
> +#define MAX_HTTP_HEADER_NAME 128
> +#define MAX_HTTP_HEADER_VALUE 512
> +struct http_header {
> + uchar name[MAX_HTTP_HEADER_NAME];
> + uchar value[MAX_HTTP_HEADER_VALUE];
> +};
> +
> +void efi_net_parse_headers(ulong *num_headers, struct http_header *headers);
> #else
> static inline void efi_net_set_dp(const char *dev, const char *server) { }
> static inline void efi_net_get_dp(void **dp) { }
> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
> index d4570d4d7c..30234ae1c7 100644
> --- a/lib/efi_loader/efi_net.c
> +++ b/lib/efi_loader/efi_net.c
> @@ -17,6 +17,7 @@
>
> #include <efi_loader.h>
> #include <dm.h>
> +#include <linux/sizes.h>
> #include <malloc.h>
> #include <vsprintf.h>
> #include <net.h>
> @@ -34,6 +35,12 @@ static int rx_packet_num;
> static struct efi_net_obj *netobj;
> static struct efi_device_path *net_dp;
>
> +static struct wget_http_info efi_wget_info = {
> + .set_bootdev = false,
> + .check_buffer_size = true,
> +
> +};
> +
> /*
> * The notification function of this event is called in every timer cycle
> * to check if a new network packet has been received.
> @@ -1003,6 +1010,10 @@ out_of_resources:
> return EFI_OUT_OF_RESOURCES;
> }
>
> +/**
> + * efi_net_set_dp() - set device path of efi net device
> + *
> + */
> void efi_net_set_dp(const char *dev, const char *server)
> {
> if (!strcmp(dev, "Net"))
> @@ -1011,6 +1022,10 @@ void efi_net_set_dp(const char *dev, const char *server)
> net_dp = efi_dp_from_http(server);
> }
>
> +/**
> + * efi_net_set_dp() - get device path of efi net device
> + *
> + */
> void efi_net_get_dp(void **dp)
> {
> if (!net_dp)
> @@ -1019,6 +1034,10 @@ void efi_net_get_dp(void **dp)
> *dp = efi_dp_dup(net_dp);
> }
>
> +/**
> + * efi_net_get_addr() - get IP address information
> + *
> + */
> void efi_net_get_addr(struct efi_ipv4_address *ip,
> struct efi_ipv4_address *mask,
> struct efi_ipv4_address *gw)
> @@ -1068,6 +1087,10 @@ void efi_net_get_addr(struct efi_ipv4_address *ip,
> #endif
> }
>
> +/**
> + * efi_net_set_addr() - set IP address information
> + *
> + */
> void efi_net_set_addr(struct efi_ipv4_address *ip,
> struct efi_ipv4_address *mask,
> struct efi_ipv4_address *gw)
> @@ -1117,3 +1140,138 @@ void efi_net_set_addr(struct efi_ipv4_address *ip,
> memcpy((void *)&net_netmask, (void *)mask, 4);
> #endif
> }
> +
> +/**
> + * efi_net_set_buffer() - allocate a buffer of min 64K
Please, describe the parameters.
> + *
> + */
> +static efi_status_t efi_net_set_buffer(ulong *buffer, ulong size)
Please, use size_t for sizes.
All invocations use size = 0. So we should drop the parameter.
> +{
> + efi_status_t ret = EFI_SUCCESS;
> +
> + if (size < SZ_64K)
> + size = SZ_64K;
> +
> + efi_free_pool((void *)*buffer);
> +
> + *buffer = (ulong)efi_alloc(size);
efi_alloc() returns a pointer.
There is no good reason to store pointers in ulong. Please, use void *
for pointers.
Patch 13/15 shows the resulting confusion:
In efi_http_send_data() you assume http_load_addr is a sandbox virtual
address:
ptr = map_sysmem(inst->http_load_addr + inst->current_offset,
transfer_size);
And a few lines below you assume that it is a pointer:
efi_free_pool((void *)inst->http_load_addr);
We should keep sandbox specific addresses which need map_sysmem() and
map_to_sysmem() out of the EFI implementation as far as possible.
So let parameter buffer be of type **void here.
We need a test that we can run both on the sandbox and on Q
> + if (!*buffer)
> + ret = EFI_OUT_OF_RESOURCES;
> +
> + efi_wget_info.buffer_size = size;
> + //debug("efi_net: set buffer of size %lu at %lu\n", size, *buffer);
It would be fine to have a debug statement here but, please, remove
lines that only where used during your development process.
Nits:
As described in doc/develop/codingstyle.rst:224:
"* Put a blank line before the last ``return`` in a function unless it
is the only line:"
> + return ret;
> +}
> +
> +/**
> + * efi_net_parse_headers() - parse HTTP headers
> + *
> + * Parses the raw buffer efi_wget_info.headers into an array headers
> + * of efi structs http_headers. The array should be at least
> + * MAX_HTTP_HEADERS long.
Please, describe the parameters.
> + */
> +void efi_net_parse_headers(ulong *num_headers, struct http_header *headers)
> +{
> + if (!num_headers || !headers)
> + return;
> +
> + // Populate info with http headers.
> + *num_headers = 0;
> + const uchar *line_start = efi_wget_info.headers;
> + const uchar *line_end;
> + ulong count;
> + struct http_header *current_header;
> + const uchar *separator;
> + size_t name_length, value_length;
> +
> + // Skip the first line (request or status line)
> + line_end = strstr(line_start, "\r\n");
> +
> + if (line_end)
> + line_start = line_end + 2;
> +
> + while ((line_end = strstr(line_start, "\r\n")) != NULL) {
> + count = *num_headers;
> + if (line_start == line_end || count >= MAX_HTTP_HEADERS)
> + break;
> + current_header = headers + count;
> + separator = strchr(line_start, ':');
> + if (separator) {
> + name_length = separator - line_start;
> + ++separator;
> + while (*separator == ' ')
> + ++separator;
> + value_length = line_end - separator;
> + if (name_length < MAX_HTTP_HEADER_NAME &&
> + value_length < MAX_HTTP_HEADER_VALUE) {
> + strncpy(current_header->name, line_start, name_length);
> + current_header->name[name_length] = '\0';
> + strncpy(current_header->value, separator, value_length);
> + current_header->value[value_length] = '\0';
> + (*num_headers)++;
> + }
> + }
> + line_start = line_end + 2;
> + }
> +}
> +
> +/**
> + * efi_net_do_request() - issue an HTTP request using wget
Please, complete the function description.
> + *
> + */
> +efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, ulong *buffer,
Please, use void **buffer. Below you are assuming *buffer is a pointer
and not a sandbox virtual address.
> + u32 *status_code, ulong *file_size, char *headers_buffer)
> +{
> + efi_status_t ret = EFI_SUCCESS;
> + int wget_ret;
> + static bool last_head;
> +
> + if (!buffer || !file_size)
> + return EFI_ABORTED;
> +
> + efi_wget_info.method = (enum wget_http_method)method;
Parameter method has type 'enum wget_http_method'. Please, remove the
superfluous conversion.
Best regards
Heinrich
> + efi_wget_info.headers = headers_buffer;
> +
> + switch (method) {
> + case HTTP_METHOD_GET:
> + ret = efi_net_set_buffer(buffer, last_head ? efi_wget_info.hdr_cont_len : 0);
> + if (ret != EFI_SUCCESS)
> + goto out;
> + wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info);
> + if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) {
> + // Try again with updated buffer size
> + ret = efi_net_set_buffer(buffer, (ulong)efi_wget_info.hdr_cont_len);
> + if (ret != EFI_SUCCESS)
> + goto out;
> + if (wget_request((ulong)*buffer, url, &efi_wget_info)) {
> + efi_free_pool((void *)*buffer);
> + ret = EFI_DEVICE_ERROR;
> + goto out;
> + }
> + } else if (wget_ret) {
> + efi_free_pool((void *)*buffer);
> + ret = EFI_DEVICE_ERROR;
> + goto out;
> + }
> + // Pass the actual number of received bytes to the application
> + *file_size = efi_wget_info.file_size;
> + *status_code = efi_wget_info.status_code;
> + last_head = false;
> + break;
> + case HTTP_METHOD_HEAD:
> + ret = efi_net_set_buffer(buffer, 0);
> + if (ret != EFI_SUCCESS)
> + goto out;
> + wget_request((ulong)*buffer, url, &efi_wget_info);
> + *file_size = 0;
> + *status_code = efi_wget_info.status_code;
> + last_head = true;
> + break;
> + default:
> + ret = EFI_UNSUPPORTED;
> + break;
> + }
> +
> +out:
> + return ret;
> +}
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 12/15] efi_loader: efi_net: add EFI_HTTP_PROTOCOL
2024-11-11 21:09 ` [PATCH v3 12/15] efi_loader: efi_net: add EFI_HTTP_PROTOCOL Adriano Cordova
@ 2024-11-12 14:02 ` Heinrich Schuchardt
0 siblings, 0 replies; 39+ messages in thread
From: Heinrich Schuchardt @ 2024-11-12 14:02 UTC (permalink / raw)
To: Adriano Cordova
Cc: joe.hershberger, rfried.dev, jerome.forissier, ilias.apalodimas,
u-boot
On 11.11.24 22:09, Adriano Cordova wrote:
> Add an EFI HTTP driver. This commit implements the
> EFI_HTTP_PROTOCOL and the EFI_HTTP_SERVICE_BINDING_PROTOCOL.
> The latter is attached to the handle of th efi network
> device. This is the same handle where snp, pxe, and ipconfig
> are attached to.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> - Add documentation
> - Clean up the way the buffer pointed to http_load_addr in the current
> http instance was being freed.
> - Remove unnecessary initialization new_instance->handle = NULL in
> efi_http_service_binding_create_child.
>
> include/efi_loader.h | 3 +
> lib/efi_loader/Kconfig | 8 +
> lib/efi_loader/Makefile | 1 +
> lib/efi_loader/efi_http.c | 563 ++++++++++++++++++++++++++++++++++++++
> lib/efi_loader/efi_net.c | 20 +-
> 5 files changed, 593 insertions(+), 2 deletions(-)
> create mode 100644 lib/efi_loader/efi_http.c
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 5029ac39f1..dee7e1a9f3 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -630,6 +630,9 @@ efi_status_t efi_net_register(void);
> /* Called by efi_net_register to make the ip4 config2 protocol available */
> efi_status_t efi_ipconfig_register(const efi_handle_t handle,
> struct efi_ip4_config2_protocol *ip4config);
> +/* Called by efi_net_register to make the http protocol available */
> +efi_status_t efi_http_register(const efi_handle_t handle,
> + struct efi_service_binding_protocol *http_service_binding);
> /* Called by bootefi to make the watchdog available */
> efi_status_t efi_watchdog_register(void);
> efi_status_t efi_initrd_register(void);
> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index d823b2855b..6d3309932c 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -485,6 +485,14 @@ config EFI_IP4_CONFIG2_PROTOCOL
> protocol can be used to set and get the current ip address and
> other network information.
>
> +config EFI_HTTP_PROTOCOL
> + bool "EFI_HTTP_PROTOCOL support"
> + default y
> + depends on WGET
> + help
> + Provides an EFI HTTP driver implementing the EFI_HTTP_PROTOCOL. and
> + EFI_HTTP_SERVICE_BINDING_PROTOCOL.
> +
> endmenu
>
> menu "Misc options"
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index 30cd1de9d6..2a0b4172bd 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -60,6 +60,7 @@ obj-$(CONFIG_VIDEO) += efi_gop.o
> obj-$(CONFIG_BLK) += efi_disk.o
> obj-$(CONFIG_NETDEVICES) += efi_net.o
> obj-$(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) += efi_ipconfig.o
> +obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_http.o
> obj-$(CONFIG_ACPI) += efi_acpi.o
> obj-$(CONFIG_SMBIOS) += efi_smbios.o
> obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
> diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c
> new file mode 100644
> index 0000000000..75b8fc40ca
> --- /dev/null
> +++ b/lib/efi_loader/efi_http.c
> @@ -0,0 +1,563 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * An HTTP driver
> + *
> + * HTTP_PROTOCOL
> + * HTTP_SERVICE_BINDING_PROTOCOL
> + * IP4_CONFIG2_PROTOCOL
> + */
> +
> +#include <charset.h>
> +#include <efi_loader.h>
> +#include <image.h>
> +#include <malloc.h>
> +#include <mapmem.h>
> +#include <net.h>
> +
> +static const efi_guid_t efi_http_service_binding_guid = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
> +static const efi_guid_t efi_http_guid = EFI_HTTP_PROTOCOL_GUID;
> +
> +/**
> + * struct efi_http_instance - EFI object representing an HTTP protocol instance
> + *
> + * @http: EFI_HTTP_PROTOCOL interface
> + * @handle: handle to efi object
> + * @configured: configuration status
Nits:
A tab is missing after @configured:.
> + * @http_load_addr: data buffer
> + * @file_size: size of data
> + * @current_offset: offset in data buffer
> + * @status_code: HTTP status code
> + * @num_headers: number of received headers
> + * @headers: array of headers
> + * @headers_buffer: raw buffer with headers
> + */
> +struct efi_http_instance {
> + struct efi_http_protocol http;
> + efi_handle_t handle;
> + bool configured;
> + ulong http_load_addr;
You are using this field to store a pointer. So the type should be void *.
> + ulong file_size;
> + ulong current_offset;
> + u32 status_code;
> + ulong num_headers;
> + struct http_header headers[MAX_HTTP_HEADERS];
> + char headers_buffer[MAX_HTTP_HEADERS_SIZE];
> +};
> +
> +static int num_instances;
> +
> +/*
> + * efi_u32_to_httpstatus() - convert u32 to status
> + *
> + */
> +enum efi_http_status_code efi_u32_to_httpstatus(u32 status);
> +
> +/*
> + * efi_http_send_data() - sends data to client
> + *
> + *
> + * @client_buffer: client buffer to send data to
> + * @client_buffer_size: size of the client buffer
> + * @inst: HTTP instance for which to send data
> + *
> + * Return: status code
> + */
> +static efi_status_t efi_http_send_data(void *client_buffer,
> + efi_uintn_t *client_buffer_size,
> + struct efi_http_instance *inst)
> +{
> + efi_status_t ret = EFI_SUCCESS;
> + ulong total_size, transfer_size;
> + uchar *ptr;
> +
> + // Amount of data left;
> + total_size = inst->file_size;
> + transfer_size = total_size - inst->current_offset;
> + debug("efi_http: sending data to client, total size %lu\n", total_size);
> + // Amount of data the client is willing to receive
> + if (transfer_size > *client_buffer_size)
> + transfer_size = *client_buffer_size;
> + else
> + *client_buffer_size = transfer_size;
> + debug("efi_http: transfer size %lu\n", transfer_size);
> + if (!transfer_size) // Ok, only headers
> + goto out;
> +
> + if (!client_buffer) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + // Send data
> + ptr = map_sysmem(inst->http_load_addr + inst->current_offset, transfer_size);
> + memcpy(client_buffer, ptr, transfer_size);
> + unmap_sysmem(ptr);
> +
> + inst->current_offset += transfer_size;
> +
> + // Whole file served, clean the buffer:
> + if (inst->current_offset == inst->file_size) {
> + efi_free_pool((void *)inst->http_load_addr);
When you assign ptr above you assume that http_load_addr is not a
pointer but a an address in the sandbox's virtual address space.
http_load_addr cannot be both a pointer and a sandbox virtual address.
> + inst->http_load_addr = 0;
> + inst->current_offset = 0;
> + inst->file_size = 0;
> + }
> +
> +out:
> + return ret;
> +}
> +
> +/* EFI_HTTP_PROTOCOL */
> +
> +/*
> + * efi_http_get_mode_data() - Gets the current operational status.
> + *
> + * This function implements EFI_HTTP_PROTOCOL.GetModeData()
Nits:
Missing period at end of sentence.
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @data: pointer to the buffer for operational parameters
> + * of this HTTP instance
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_http_get_mode_data(struct efi_http_protocol *this,
> + struct efi_http_config_data *data)
> +{
> + EFI_ENTRY("%p, %p", this, data);
> +
> + efi_status_t ret = EFI_UNSUPPORTED;
> +
> + return EFI_EXIT(ret);
> +}
> +
> +/*
> + * efi_http_configure() - Initializes operational status for this
> + * EFI HTTP instance.
> + *
> + * This function implements EFI_HTTP_PROTOCOL.Configure()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @data: pointer to the buffer for operational parameters of
> + * this HTTP instance
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_http_configure(struct efi_http_protocol *this,
> + struct efi_http_config_data *data)
> +{
> + EFI_ENTRY("%p, %p", this, data);
> +
> + efi_status_t ret = EFI_SUCCESS;
> + enum efi_http_version http_version;
> + struct efi_httpv4_access_point *ipv4_node;
> + struct efi_http_instance *http_instance;
> +
> + if (!this) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + http_instance = (struct efi_http_instance *)this;
> +
> + if (!data) {
> + efi_free_pool((void *)http_instance->http_load_addr);
> + http_instance->http_load_addr = 0;
> + http_instance->current_offset = 0;
> + http_instance->configured = false;
> +
> + goto out;
> + }
> +
> + if (http_instance->configured) {
> + ret = EFI_ALREADY_STARTED;
> + goto out;
> + }
> +
> + http_version = data->http_version;
> + ipv4_node = data->access_point.ipv4_node;
> +
> + if ((http_version != HTTPVERSION10 &&
> + http_version != HTTPVERSION11) ||
> + data->is_ipv6 || !ipv4_node) { /* Only support ipv4 */
> + ret = EFI_UNSUPPORTED;
> + goto out;
> + }
> +
> + if (!ipv4_node->use_default_address) {
> + efi_net_set_addr((struct efi_ipv4_address *)&ipv4_node->local_address,
> + (struct efi_ipv4_address *)&ipv4_node->local_subnet, NULL);
> + }
> +
> + http_instance->current_offset = 0;
> + http_instance->configured = true;
> +
> +out:
> + return EFI_EXIT(ret);
> +}
> +
> +/*
> + * efi_http_request() - Queues an HTTP request to this HTTP instance
> + *
> + * This function implements EFI_HTTP_PROTOCOL.Request()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @token: pointer to storage containing HTTP request token
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_http_request(struct efi_http_protocol *this,
> + struct efi_http_token *token)
> +{
> + EFI_ENTRY("%p, %p", this, token);
> +
> + efi_status_t ret = EFI_SUCCESS;
> + u8 *tmp;
> + u8 url_8[1024];
> + u16 *url_16;
> + enum efi_http_method current_method;
> + struct efi_http_instance *http_instance;
> +
> + if (!token || !this) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + http_instance = (struct efi_http_instance *)this;
> +
> + if (!http_instance->configured) {
> + ret = EFI_NOT_STARTED;
> + goto out;
> + }
> +
> + if (!token->message || !token->message->data.request)
> + goto out_invalid;
EDK II checks all parameters at the start of EfiHttpRequest() and does
not modify token->status if a parameter is invalid.
The instance state is checked only after the parameter validation.
See NetworkPkg/HttpDxe/HttpImpl.c in https://github.com/tianocore/edk2.
> +
> + current_method = token->message->data.request->method;
> + url_16 = token->message->data.request->url;
> +
> + /* Parse URL. It comes in UCS-2 encoding and follows RFC3986 */
> + tmp = url_8;
> + utf16_utf8_strncpy((char **)&tmp, url_16, 1024);
> +
> + ret = efi_net_do_request(url_8, current_method, &http_instance->http_load_addr,
> + &http_instance->status_code, &http_instance->file_size,
> + http_instance->headers_buffer);
> + if (ret != EFI_SUCCESS)
> + goto out;
> +
> + // We have a new file
With method HEAD we will not have received a file.
> + efi_net_parse_headers(&http_instance->num_headers, http_instance->headers);
> + http_instance->current_offset = 0;
> + token->status = EFI_SUCCESS;
> + goto out_signal;
> +
> +out_invalid:
> + ret = EFI_INVALID_PARAMETER;
> + token->status = EFI_ABORTED;
If the parameters are invalid, there is no need to signal an event.
> +out_signal:
> + efi_signal_event(token->event);
> +out:
> + return EFI_EXIT(ret);
> +}
> +
> +/*
> + * efi_http_cancel() - Abort an asynchronous HTTP request or response token
> + *
> + * This function implements EFI_HTTP_PROTOCOL.Cancel()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @token: pointer to storage containing HTTP request token
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_http_cancel(struct efi_http_protocol *this,
> + struct efi_http_token *token)
> +{
> + EFI_ENTRY("%p, %p", this, token);
> +
> + efi_status_t ret = EFI_UNSUPPORTED;
> +
> + return EFI_EXIT(ret);
> +}
> +
> +/*
> + * efi_http_response() - Queues an HTTP response to this HTTP instance
> + *
> + * This function implements EFI_HTTP_PROTOCOL.Response()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @token: pointer to storage containing HTTP request token
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_http_response(struct efi_http_protocol *this,
> + struct efi_http_token *token)
> +{
> + EFI_ENTRY("%p, %p", this, token);
> +
> + efi_status_t ret = EFI_SUCCESS;
> + struct efi_http_instance *http_instance;
> + struct efi_http_header **client_headers;
> + struct efi_http_response_data *response;
> +
> + if (!token) {
> + ret = EFI_INVALID_PARAMETER;
> + goto out;
> + }
> +
> + if (!this || !token->message)
> + goto out_invalid;
Why signal an event if the parameters are invalid?
I think we should just return EFI_INVALID_PARAMETER.
See EfiHttpResponse() in EDK II.
> +
> + http_instance = (struct efi_http_instance *)this;
> +
> + // Set HTTP status code
> + if (token->message->data.response) { // TODO extra check, see spec.
> + response = token->message->data.response;
> + response->status_code = efi_u32_to_httpstatus(http_instance->status_code);
> + }
> + client_headers = &token->message->headers;
> + ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA,
> + (http_instance->num_headers) * sizeof(struct efi_http_header),
> + (void **)client_headers); // This is deallocated by the client.
> + if (ret != EFI_SUCCESS)
> + goto out_bad_signal;
> +
> + // Send headers
> + token->message->header_count = http_instance->num_headers;
> + for (int i = 0; i < http_instance->num_headers; i++) {
> + (*client_headers)[i].field_name = http_instance->headers[i].name;
> + (*client_headers)[i].field_value = http_instance->headers[i].value;
> + }
> + if (ret != EFI_SUCCESS)
> + goto out_bad_signal;
We have already handled ret above.
> +
> + ret = efi_http_send_data(token->message->body, &token->message->body_length, http_instance);
> + if (ret != EFI_SUCCESS)
> + goto out_bad_signal;
> +
> + token->status = EFI_SUCCESS;
> + goto out_signal;
> +
> +out_invalid:
> + ret = EFI_INVALID_PARAMETER;
> +out_bad_signal:
> + token->status = EFI_ABORTED;
> +out_signal:
> + efi_signal_event(token->event);
> +out:
> + return EFI_EXIT(ret);
> +}
> +
> +/*
> + * efi_http_poll() - Polls for incoming data packets and processes outgoing data packets
> + *
> + * This function implements EFI_HTTP_PROTOCOL.Poll()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @token: pointer to storage containing HTTP request token
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_http_poll(struct efi_http_protocol *this)
> +{
> + EFI_ENTRY("%p", this);
> +
> + efi_status_t ret = EFI_UNSUPPORTED;
> +
> + return EFI_EXIT(ret);
> +}
> +
> +/* EFI_HTTP_SERVICE_BINDING_PROTOCOL */
> +
> +/*
> + * efi_http_service_binding_create_child() - Creates a child handle
> + * and installs a protocol
> + *
> + * This function implements EFI_HTTP_SERVICE_BINDING.CreateChild()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @child_handle: pointer to child handle
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_http_service_binding_create_child(
> + struct efi_service_binding_protocol *this,
> + efi_handle_t *child_handle)
> +{
> + EFI_ENTRY("%p, %p", this, child_handle);
> +
> + efi_status_t ret = EFI_SUCCESS;
> + struct efi_http_instance *new_instance;
> +
> + if (!child_handle)
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +
> + new_instance = calloc(1, sizeof(struct efi_http_instance));
> + if (!new_instance) {
> + ret = EFI_OUT_OF_RESOURCES;
> + goto failure_to_add_protocol;
> + }
> +
> + if (*child_handle) {
> + new_instance->handle = *child_handle;
> + goto install;
> + }
> +
> + new_instance->handle = calloc(1, sizeof(struct efi_object));
> + if (!new_instance->handle) {
> + efi_free_pool((void *)new_instance);
> + ret = EFI_OUT_OF_RESOURCES;
> + goto failure_to_add_protocol;
> + }
> +
> + efi_add_handle(new_instance->handle);
> + *child_handle = new_instance->handle;
> +
> +install:
> + ret = efi_add_protocol(new_instance->handle, &efi_http_guid,
> + &new_instance->http);
> + if (ret != EFI_SUCCESS)
> + goto failure_to_add_protocol;
> +
> + new_instance->http.get_mode_data = efi_http_get_mode_data;
> + new_instance->http.configure = efi_http_configure;
> + new_instance->http.request = efi_http_request;
> + new_instance->http.cancel = efi_http_cancel;
> + new_instance->http.response = efi_http_response;
> + new_instance->http.poll = efi_http_poll;
> + ++num_instances;
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +
> +failure_to_add_protocol:
> + printf("ERROR: Failure to add protocol\n");
Please, avoid writing to the console in EFI API implementations. Leave
error handling to the caller.
You may use EFI_PRINT() if you want debug output.
> + return EFI_EXIT(ret);
> +}
> +
> +/*
> + * efi_http_service_binding_destroy_child() - Destroys a child handle with
> + * a protocol installed on it
> + *
> + * This function implements EFI_HTTP_SERVICE_BINDING.DestroyChild()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @child_handle: child handle
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_http_service_binding_destroy_child(
> + struct efi_service_binding_protocol *this,
> + efi_handle_t child_handle)
> +{
> + EFI_ENTRY("%p, %p", this, child_handle);
> + efi_status_t ret = EFI_SUCCESS;
> + struct efi_http_instance *http_instance;
> + struct efi_handler *phandler;
> + void *protocol_interface;
> +
> + if (num_instances == 0)
> + return EFI_EXIT(EFI_NOT_FOUND);
> +
> + if (!child_handle)
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +
> + efi_search_protocol(child_handle, &efi_http_guid, &phandler);
> +
> + if (phandler)
> + protocol_interface = phandler->protocol_interface;
> +
> + ret = efi_delete_handle(child_handle);
> + if (ret != EFI_SUCCESS) {
> + printf("ERROR: Failure to remove protocol\n");
> + return EFI_EXIT(ret);
> + }
> +
> + http_instance = (struct efi_http_instance *)protocol_interface;
> + efi_free_pool((void *)http_instance->http_load_addr);
> + http_instance->http_load_addr = 0;
> +
> + free(protocol_interface);
> +
> + num_instances--;
> +
> + return EFI_EXIT(EFI_SUCCESS);
> +}
> +
> +/**
> + * efi_http_register() - register the http protocol
> + *
> + */
> +efi_status_t efi_http_register(const efi_handle_t handle,
> + struct efi_service_binding_protocol *http_service_binding)
> +{
> + efi_status_t r = EFI_SUCCESS;
> +
> + r = efi_add_protocol(handle, &efi_http_service_binding_guid,
> + http_service_binding);
> + if (r != EFI_SUCCESS)
> + goto failure_to_add_protocol;
> +
> + http_service_binding->create_child = efi_http_service_binding_create_child;
> + http_service_binding->destroy_child = efi_http_service_binding_destroy_child;
> +
> + return EFI_SUCCESS;
> +failure_to_add_protocol:
> + printf("ERROR: Failure to add protocol\n");
Please, avoid writing to the console in EFI API implementations.
You may use EFI_PRINT() if you want debug output.
Best regards
Heinrich
> + return r;
> +}
> +
> +enum efi_http_status_code efi_u32_to_httpstatus(u32 status)
> +{
> + switch (status) {
> + case 100: return HTTP_STATUS_100_CONTINUE;
> + case 101: return HTTP_STATUS_101_SWITCHING_PROTOCOLS;
> + case 200: return HTTP_STATUS_200_OK;
> + case 201: return HTTP_STATUS_201_CREATED;
> + case 202: return HTTP_STATUS_202_ACCEPTED;
> + case 203: return HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION;
> + case 204: return HTTP_STATUS_204_NO_CONTENT;
> + case 205: return HTTP_STATUS_205_RESET_CONTENT;
> + case 206: return HTTP_STATUS_206_PARTIAL_CONTENT;
> + case 300: return HTTP_STATUS_300_MULTIPLE_CHOICES;
> + case 301: return HTTP_STATUS_301_MOVED_PERMANENTLY;
> + case 302: return HTTP_STATUS_302_FOUND;
> + case 303: return HTTP_STATUS_303_SEE_OTHER;
> + case 304: return HTTP_STATUS_304_NOT_MODIFIED;
> + case 305: return HTTP_STATUS_305_USE_PROXY;
> + case 307: return HTTP_STATUS_307_TEMPORARY_REDIRECT;
> + case 400: return HTTP_STATUS_400_BAD_REQUEST;
> + case 401: return HTTP_STATUS_401_UNAUTHORIZED;
> + case 402: return HTTP_STATUS_402_PAYMENT_REQUIRED;
> + case 403: return HTTP_STATUS_403_FORBIDDEN;
> + case 404: return HTTP_STATUS_404_NOT_FOUND;
> + case 405: return HTTP_STATUS_405_METHOD_NOT_ALLOWED;
> + case 406: return HTTP_STATUS_406_NOT_ACCEPTABLE;
> + case 407: return HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED;
> + case 408: return HTTP_STATUS_408_REQUEST_TIME_OUT;
> + case 409: return HTTP_STATUS_409_CONFLICT;
> + case 410: return HTTP_STATUS_410_GONE;
> + case 411: return HTTP_STATUS_411_LENGTH_REQUIRED;
> + case 412: return HTTP_STATUS_412_PRECONDITION_FAILED;
> + case 413: return HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE;
> + case 414: return HTTP_STATUS_414_REQUEST_URI_TOO_LARGE;
> + case 415: return HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE;
> + case 416: return HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED;
> + case 417: return HTTP_STATUS_417_EXPECTATION_FAILED;
> + case 500: return HTTP_STATUS_500_INTERNAL_SERVER_ERROR;
> + case 501: return HTTP_STATUS_501_NOT_IMPLEMENTED;
> + case 502: return HTTP_STATUS_502_BAD_GATEWAY;
> + case 503: return HTTP_STATUS_503_SERVICE_UNAVAILABLE;
> + case 504: return HTTP_STATUS_504_GATEWAY_TIME_OUT;
> + case 505: return HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED;
> + case 308: return HTTP_STATUS_308_PERMANENT_REDIRECT;
> + default: return HTTP_STATUS_UNSUPPORTED_STATUS;
> + }
> +}
> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
> index fa3b0c0007..de22c85acf 100644
> --- a/lib/efi_loader/efi_net.c
> +++ b/lib/efi_loader/efi_net.c
> @@ -60,6 +60,7 @@ static struct efi_event *wait_for_packet;
> * @pxe: PXE base code protocol interface
> * @pxe_mode: status of the PXE base code protocol
> * @ip4_config2: IP4 Config2 protocol interface
> + * @http_service_binding: Http service binding protocol interface
> */
> struct efi_net_obj {
> struct efi_object header;
> @@ -70,6 +71,9 @@ struct efi_net_obj {
> #ifdef CONFIG_EFI_IP4_CONFIG2_PROTOCOL
> struct efi_ip4_config2_protocol ip4_config2;
> #endif
> +#ifdef CONFIG_EFI_HTTP_PROTOCOL
> + struct efi_service_binding_protocol http_service_binding;
> +#endif
> };
>
> /*
> @@ -1003,6 +1007,19 @@ efi_status_t efi_net_register(void)
> goto failure_to_add_protocol;
> #endif
>
> +#ifdef CONFIG_EFI_HTTP_PROTOCOL
> + r = efi_http_register(&netobj->header, &netobj->http_service_binding);
> + if (r != EFI_SUCCESS)
> + goto failure_to_add_protocol;
> + /*
> + * No harm on doing the following. If the PXE handle is present, the client could
> + * find it and try to get its IP address from it. In here the PXE handle is present
> + * but the PXE protocol is not yet implmenented, so we add this in the meantime.
> + */
> + efi_net_get_addr((struct efi_ipv4_address *)&netobj->pxe_mode.station_ip,
> + (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL);
> +#endif
> +
> return EFI_SUCCESS;
> failure_to_add_protocol:
> printf("ERROR: Failure to add protocol\n");
> @@ -1162,8 +1179,6 @@ static efi_status_t efi_net_set_buffer(ulong *buffer, ulong size)
> if (size < SZ_64K)
> size = SZ_64K;
>
> - efi_free_pool((void *)*buffer);
> -
> *buffer = (ulong)efi_alloc(size);
> if (!*buffer)
> ret = EFI_OUT_OF_RESOURCES;
> @@ -1250,6 +1265,7 @@ efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, ulong *buf
> wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info);
> if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) {
> // Try again with updated buffer size
> + efi_free_pool((void *)*buffer);
> ret = efi_net_set_buffer(buffer, (ulong)efi_wget_info.hdr_cont_len);
> if (ret != EFI_SUCCESS)
> goto out;
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 13/15] lib: uuid: display HTTP and IPV4 Config II protocols
2024-11-11 21:09 ` [PATCH v3 13/15] lib: uuid: display HTTP and IPV4 Config II protocols Adriano Cordova
@ 2024-11-13 8:09 ` Ilias Apalodimas
0 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-13 8:09 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk, Heinrich Schuchardt
Hi Adriano,
You forgot to add reviewed tags on this one.
I am reviewing the rest of the patches, so please go through the tags
and add them when you send a v4.
Thanks
/Ilias
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
>
> Add long texts for
>
> * EFI HTTP Protocol
> * EFI HTTP Service Binding Protocol
> * EFI IPv4 Configuration II Protocol
>
> to the uuid library.
>
> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> lib/uuid.c | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/lib/uuid.c b/lib/uuid.c
> index c6a27b7d04..3b2cf60fe1 100644
> --- a/lib/uuid.c
> +++ b/lib/uuid.c
> @@ -174,6 +174,20 @@ static const struct {
> "Firmware Management",
> EFI_FIRMWARE_MANAGEMENT_PROTOCOL_GUID
> },
> +#if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL)
> + {
> + "HTTP",
> + EFI_HTTP_PROTOCOL_GUID,
> + },
> + {
> + "HTTP Service Binding",
> + EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID,
> + },
> + {
> + "IPv4 Config2",
> + EFI_IP4_CONFIG2_PROTOCOL_GUID,
> + },
> +#endif
> /* Configuration table GUIDs */
> {
> "ACPI table",
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 08/15] efi_loader: device_path: add support for HTTP device path
2024-11-11 21:09 ` [PATCH v3 08/15] efi_loader: device_path: add support for HTTP device path Adriano Cordova
@ 2024-11-13 8:15 ` Ilias Apalodimas
2024-11-13 12:51 ` Adriano Córdova
0 siblings, 1 reply; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-13 8:15 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> Add efi_dp_from_http to form a device path from HTTP. The
> device path is the concatenation of the device path returned
> by efi_dp_from_ipv4 together with an URI node and an END node.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> Changes in v3:
> - Moved argument checks in efi_dp_from_http to the beginning of the function
>
> include/efi_loader.h | 1 +
> lib/efi_loader/efi_device_path.c | 55 ++++++++++++++++++++++++++++++++
> 2 files changed, 56 insertions(+)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 612bc42816..96b204dfc3 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -872,6 +872,7 @@ struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part);
> struct efi_device_path *efi_dp_from_file(const struct efi_device_path *dp,
> const char *path);
> struct efi_device_path *efi_dp_from_eth(void);
> +struct efi_device_path *efi_dp_from_http(const char *server);
> struct efi_device_path *efi_dp_from_mem(uint32_t mem_type,
> uint64_t start_address,
> size_t size);
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index 82a45da1fa..158f08b9e5 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -1012,6 +1012,61 @@ struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip,
> return dp2;
> }
>
> +struct efi_device_path *efi_dp_from_http(const char *server)
> +{
> + struct efi_device_path *dp1, *dp2;
> + struct efi_device_path_uri *uridp;
> + efi_uintn_t uridp_len;
> + char *pos;
> + char tmp[128];
> + struct efi_ipv4_address ip;
> + struct efi_ipv4_address mask;
> +
> + if ((server && strlen("http://") + strlen(server) + 1 > 128)
sizeof (tmp) instead of 128
> + (!server && IS_ENABLED(CONFIG_NET_LWIP)))
> + return NULL;
> +
> + efi_net_get_addr(&ip, &mask, NULL);
> +
> + dp1 = efi_dp_from_ipv4(&ip, &mask, NULL);
> +
> + strcpy(tmp, "http://");
I've sent this a while back which is close to merging [0]. I am ok
with merging http support first, but if it's not too much of a pain
can you rebase on top of that and add https:// as well?
> +
> +#if IS_ENABLED(CONFIG_NET_LWIP)
> + if (server) {
> + memcpy(tmp + strlen("http://"), server, strlen(server) + 1);
> + }
> +#else
> + if (server) {
> + memcpy(tmp + strlen("http://"), server, strlen(server) + 1);
> + } else {
> + ip_to_string(net_server_ip, tmp + strlen("http://"));
> + }
> +#endif
> +
I think it's easier to read if you rewrite this as
if (server)
memcpy(tmp + strlen("http://"), server, strlen(server) + 1);
else
if (!IS_ENABLED(CONFIG_NET_LWIP)
ip_to_string(net_server_ip, tmp + strlen("http://"));
> + uridp_len = sizeof(struct efi_device_path) + strlen(tmp) + 1;
> + uridp = efi_alloc(uridp_len + sizeof(END));
> + if (!uridp) {
> + log_err("Out of memory\n");
> + return NULL;
> + }
> + uridp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
> + uridp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_URI;
> + uridp->dp.length = uridp_len;
> + debug("device path: setting uri device path to %s\n", tmp);
> + memcpy(uridp->uri, tmp, strlen(tmp) + 1);
> +
> + pos = (char *)uridp + uridp_len;
> + memcpy(pos, &END, sizeof(END));
> +
> + dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)uridp, 0);
> +
> + efi_free_pool(uridp);
> + efi_free_pool(dp1);
> +
> + return dp2;
> +}
> +
> /* Construct a device-path for memory-mapped image */
> struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
> uint64_t start_address,
> --
> 2.43.0
>
[0] https://lore.kernel.org/u-boot/20241110083017.367565-1-ilias.apalodimas@linaro.org/
Thanks
/Ilias
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c
2024-11-11 21:09 ` [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c Adriano Cordova
@ 2024-11-13 8:17 ` Ilias Apalodimas
2024-11-16 20:56 ` Heinrich Schuchardt
2024-11-16 21:04 ` Heinrich Schuchardt
2 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-13 8:17 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
Reviewed-by tags missing for me * Heinrich
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> The function string_to_ip is already in net_utils, which is
> compiled unconditionally, but ip_to_string is currently only
> accessible if the legacy network stack is selected. This
> commit puts ip_to_string in net_utils.c and removes it from the
> legacy network code.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> include/net-common.h | 10 ++++++++++
> lib/net_utils.c | 11 +++++++++++
> net/net.c | 11 -----------
> 3 files changed, 21 insertions(+), 11 deletions(-)
>
> diff --git a/include/net-common.h b/include/net-common.h
> index 3cd0f34374..b7a519e36d 100644
> --- a/include/net-common.h
> +++ b/include/net-common.h
> @@ -426,6 +426,16 @@ void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
> */
> struct in_addr string_to_ip(const char *s);
>
> +/**
> + * ip_to_string() - Convert a string to ip address
> + *
> + * Implemented in lib/net_utils.c (built unconditionally)
> + *
> + * @x: Input ip to parse
> + * @s: string containing the parsed ip address
> + */
> +void ip_to_string(struct in_addr x, char *s);
> +
> /* copy a filename (allow for "..." notation, limit length) */
> void copy_filename(char *dst, const char *src, int size);
>
> diff --git a/lib/net_utils.c b/lib/net_utils.c
> index c70fef0d99..621f6512b6 100644
> --- a/lib/net_utils.c
> +++ b/lib/net_utils.c
> @@ -152,6 +152,17 @@ out_err:
> }
> #endif
>
> +void ip_to_string(struct in_addr x, char *s)
> +{
> + x.s_addr = ntohl(x.s_addr);
> + sprintf(s, "%d.%d.%d.%d",
> + (int) ((x.s_addr >> 24) & 0xff),
> + (int) ((x.s_addr >> 16) & 0xff),
> + (int) ((x.s_addr >> 8) & 0xff),
> + (int) ((x.s_addr >> 0) & 0xff)
> + );
> +}
> +
> void string_to_enetaddr(const char *addr, uint8_t *enetaddr)
> {
> char *end;
> diff --git a/net/net.c b/net/net.c
> index f47e9fbe33..ca35704f66 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -1723,17 +1723,6 @@ int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len)
> return 1;
> }
>
> -void ip_to_string(struct in_addr x, char *s)
> -{
> - x.s_addr = ntohl(x.s_addr);
> - sprintf(s, "%d.%d.%d.%d",
> - (int) ((x.s_addr >> 24) & 0xff),
> - (int) ((x.s_addr >> 16) & 0xff),
> - (int) ((x.s_addr >> 8) & 0xff),
> - (int) ((x.s_addr >> 0) & 0xff)
> - );
> -}
> -
> void vlan_to_string(ushort x, char *s)
> {
> x = ntohs(x);
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 04/15] efi_loader: device_path: add efi_dp_from_ipv4
2024-11-11 21:09 ` [PATCH v3 04/15] efi_loader: device_path: add efi_dp_from_ipv4 Adriano Cordova
@ 2024-11-13 10:18 ` Ilias Apalodimas
0 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-13 10:18 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> Add efi_dp_from_ipv4 to form a device path from an ipv4 address.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> Changes in v3:
> - Removed some unnecessary void* casts.
> - Changed sizeof(struct efi_device_path_ipv4) to sizeof(*ipv4dp)
> in efi_dp_from_ipv4.
>
> lib/efi_loader/efi_device_path.c | 38 ++++++++++++++++++++++++++++++++
> 1 file changed, 38 insertions(+)
>
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index ee387e1dfd..82a45da1fa 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -974,6 +974,44 @@ struct efi_device_path __maybe_unused *efi_dp_from_eth(void)
> return start;
> }
>
> +struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip,
> + struct efi_ipv4_address *mask,
> + struct efi_ipv4_address *srv)
> +{
> + struct efi_device_path *dp1, *dp2;
> + efi_uintn_t ipv4dp_len;
> + struct efi_device_path_ipv4 *ipv4dp;
> + char *pos;
> +
> + ipv4dp_len = sizeof(*ipv4dp);
> + ipv4dp = efi_alloc(ipv4dp_len + sizeof(END));
> + if (!ipv4dp) {
> + log_err("Out of memory\n");
> + return NULL;
> + }
> +
> + ipv4dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
> + ipv4dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_IPV4;
> + ipv4dp->dp.length = ipv4dp_len;
> + ipv4dp->protocol = 6;
> + if (ip)
> + memcpy(&ipv4dp->local_ip_address, (void *)&ip, 4);
> + if (mask)
> + memcpy(&ipv4dp->subnet_mask, (void *)&mask, 4);
> + if (srv)
> + memcpy(&ipv4dp->subnet_mask, (void *)&srv, 4);
The copies above seem wrong.
Isn't that supposed to be memcpy(&ipv4dp->local_ip_address, ip,
sizeof(*ip)); etc...
> + pos = (void *)((uintptr_t)ipv4dp + ipv4dp_len);
pos = (void *)(uintptr_t)ipv4dp+...
> + memcpy(pos, &END, sizeof(END));
> +
> + dp1 = efi_dp_from_eth();
> + dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)ipv4dp, 0);
> +
> + efi_free_pool(ipv4dp);
> + efi_free_pool(dp1);
> +
> + return dp2;
> +}
> +
> /* Construct a device-path for memory-mapped image */
> struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
> uint64_t start_address,
> --
> 2.43.0
>
Thanks
/Ilias
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 03/15] efi_loader: device_path: add definition of DEVICE_PATH_SUB_TYPE_MSG_IPV4
2024-11-11 21:09 ` [PATCH v3 03/15] efi_loader: device_path: add definition of DEVICE_PATH_SUB_TYPE_MSG_IPV4 Adriano Cordova
@ 2024-11-13 10:24 ` Ilias Apalodimas
0 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-13 10:24 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> Add definition for DEVICE_PATH_SUB_TYPE_MSG_IPV4 device path
> subtype.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> Changes in v3:
> - Removed alignment in struct efi_ipv4_address
>
> include/efi_api.h | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/include/efi_api.h b/include/efi_api.h
> index f07d074f93..99ee749522 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -616,6 +616,7 @@ struct efi_device_path_acpi_path {
> # define DEVICE_PATH_SUB_TYPE_MSG_SCSI 0x02
> # define DEVICE_PATH_SUB_TYPE_MSG_USB 0x05
> # define DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR 0x0b
> +# define DEVICE_PATH_SUB_TYPE_MSG_IPV4 0x0c
> # define DEVICE_PATH_SUB_TYPE_MSG_UART 0x0e
> # define DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS 0x0f
> # define DEVICE_PATH_SUB_TYPE_MSG_USB_WWI 0x10
> @@ -691,6 +692,22 @@ struct efi_device_path_uri {
> u8 uri[];
> } __packed;
>
> +struct efi_ipv4_address {
> + u8 ip_addr[4];
> +};
> +
> +struct efi_device_path_ipv4 {
> + struct efi_device_path dp;
> + struct efi_ipv4_address local_ip_address;
> + struct efi_ipv4_address remote_ip_address;
> + u16 local_port;
> + u16 remote_port;
> + u16 protocol;
> + u8 static_ip_address;
> + struct efi_ipv4_address gateway_ip_address;
> + struct efi_ipv4_address subnet_mask;
> +} __packed;
> +
> #define DEVICE_PATH_TYPE_MEDIA_DEVICE 0x04
> # define DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH 0x01
> # define DEVICE_PATH_SUB_TYPE_CDROM_PATH 0x02
> --
> 2.43.0
>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 05/15] efi_loader: add IPv4() to device path to text protocol
2024-11-11 21:09 ` [PATCH v3 05/15] efi_loader: add IPv4() to device path to text protocol Adriano Cordova
@ 2024-11-13 10:37 ` Ilias Apalodimas
0 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-13 10:37 UTC (permalink / raw)
To: Adriano Cordova, xypron.glpk, Heinrich Schuchardt
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier
Hi Heinrich,
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
>
> Implement Ipv4() node support in the device path to text protocol.
>
> Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> lib/efi_loader/efi_device_path_to_text.c | 23 +++++++++++++++++++++++
> 1 file changed, 23 insertions(+)
>
> diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
> index 0c7b30a26e..481a9712d9 100644
> --- a/lib/efi_loader/efi_device_path_to_text.c
> +++ b/lib/efi_loader/efi_device_path_to_text.c
> @@ -8,6 +8,7 @@
> #include <blk.h>
> #include <efi_loader.h>
> #include <malloc.h>
> +#include <net.h>
>
> #define MAC_OUTPUT_LEN 22
> #define UNKNOWN_OUTPUT_LEN 23
> @@ -170,6 +171,28 @@ static char *dp_msging(char *s, struct efi_device_path *dp)
>
> break;
> }
> + case DEVICE_PATH_SUB_TYPE_MSG_IPV4: {
> + struct efi_device_path_ipv4 *idp =
> + (struct efi_device_path_ipv4 *)dp;
> +
> + s += sprintf(s, "IPv4(%pI4,", &idp->remote_ip_address);
> + switch (idp->protocol) {
> + case IPPROTO_TCP:
> + s += sprintf(s, "TCP,");
> + case IPPROTO_UDP:
> + s += sprintf(s, "UDP,");
> + default:
> + s += sprintf(s, "0x%x,", idp->protocol);
> + }
> + s += sprintf(s, idp->static_ip_address ? "Static" : "DHCP");
> + s += sprintf(s, ",%pI4", &idp->local_ip_address);
> + if (idp->dp.length == sizeof(struct efi_device_path_ipv4))
> + s += sprintf(s, ",%pI4,%pI4", &idp->gateway_ip_address,
> + &idp->subnet_mask);
> + s += sprintf(s, ")");
How confident are we that the produced device path won't overflow?
IIRC we only have 512 of space there and sprintf isn't the best tool
to catch overflows.
Thanks
/Ilias
> +
> + break;
> + }
> case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: {
> struct efi_device_path_usb_class *ucdp =
> (struct efi_device_path_usb_class *)dp;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 08/15] efi_loader: device_path: add support for HTTP device path
2024-11-13 8:15 ` Ilias Apalodimas
@ 2024-11-13 12:51 ` Adriano Córdova
0 siblings, 0 replies; 39+ messages in thread
From: Adriano Córdova @ 2024-11-13 12:51 UTC (permalink / raw)
To: Ilias Apalodimas
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
El mié, 13 nov 2024 a las 5:16, Ilias Apalodimas (<
ilias.apalodimas@linaro.org>) escribió:
> On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
> >
> > Add efi_dp_from_http to form a device path from HTTP. The
> > device path is the concatenation of the device path returned
> > by efi_dp_from_ipv4 together with an URI node and an END node.
> >
> > Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> > ---
> >
> > Changes in v3:
> > - Moved argument checks in efi_dp_from_http to the beginning of the
> function
> >
> > include/efi_loader.h | 1 +
> > lib/efi_loader/efi_device_path.c | 55 ++++++++++++++++++++++++++++++++
> > 2 files changed, 56 insertions(+)
> >
> > diff --git a/include/efi_loader.h b/include/efi_loader.h
> > index 612bc42816..96b204dfc3 100644
> > --- a/include/efi_loader.h
> > +++ b/include/efi_loader.h
> > @@ -872,6 +872,7 @@ struct efi_device_path *efi_dp_part_node(struct
> blk_desc *desc, int part);
> > struct efi_device_path *efi_dp_from_file(const struct efi_device_path
> *dp,
> > const char *path);
> > struct efi_device_path *efi_dp_from_eth(void);
> > +struct efi_device_path *efi_dp_from_http(const char *server);
> > struct efi_device_path *efi_dp_from_mem(uint32_t mem_type,
> > uint64_t start_address,
> > size_t size);
> > diff --git a/lib/efi_loader/efi_device_path.c
> b/lib/efi_loader/efi_device_path.c
> > index 82a45da1fa..158f08b9e5 100644
> > --- a/lib/efi_loader/efi_device_path.c
> > +++ b/lib/efi_loader/efi_device_path.c
> > @@ -1012,6 +1012,61 @@ struct efi_device_path *efi_dp_from_ipv4(struct
> efi_ipv4_address *ip,
> > return dp2;
> > }
> >
> > +struct efi_device_path *efi_dp_from_http(const char *server)
> > +{
> > + struct efi_device_path *dp1, *dp2;
> > + struct efi_device_path_uri *uridp;
> > + efi_uintn_t uridp_len;
> > + char *pos;
> > + char tmp[128];
> > + struct efi_ipv4_address ip;
> > + struct efi_ipv4_address mask;
> > +
> > + if ((server && strlen("http://") + strlen(server) + 1 > 128)
>
> sizeof (tmp) instead of 128
>
> > + (!server && IS_ENABLED(CONFIG_NET_LWIP)))
> > + return NULL;
> > +
> > + efi_net_get_addr(&ip, &mask, NULL);
> > +
> > + dp1 = efi_dp_from_ipv4(&ip, &mask, NULL);
> > +
> > + strcpy(tmp, "http://");
>
> I've sent this a while back which is close to merging [0]. I am ok
> with merging http support first, but if it's not too much of a pain
> can you rebase on top of that and add https:// as well?
>
For that I'd have to change the wget patches too. I will try to add it in
the next version,
otherwise I can send a separated patch.
> > +
> > +#if IS_ENABLED(CONFIG_NET_LWIP)
> > + if (server) {
> > + memcpy(tmp + strlen("http://"), server, strlen(server)
> + 1);
> > + }
> > +#else
> > + if (server) {
> > + memcpy(tmp + strlen("http://"), server, strlen(server)
> + 1);
> > + } else {
> > + ip_to_string(net_server_ip, tmp + strlen("http://"));
> > + }
> > +#endif
> > +
>
> I think it's easier to read if you rewrite this as
> if (server)
> memcpy(tmp + strlen("http://"), server, strlen(server) + 1);
> else
> if (!IS_ENABLED(CONFIG_NET_LWIP)
> ip_to_string(net_server_ip, tmp + strlen("http://"));
>
> I agree, but then there is an empty else { } , not sure if that would
generate a warning.
> + uridp_len = sizeof(struct efi_device_path) + strlen(tmp) + 1;
> > + uridp = efi_alloc(uridp_len + sizeof(END));
> > + if (!uridp) {
> > + log_err("Out of memory\n");
> > + return NULL;
> > + }
> > + uridp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
> > + uridp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_URI;
> > + uridp->dp.length = uridp_len;
> > + debug("device path: setting uri device path to %s\n", tmp);
> > + memcpy(uridp->uri, tmp, strlen(tmp) + 1);
> > +
> > + pos = (char *)uridp + uridp_len;
> > + memcpy(pos, &END, sizeof(END));
> > +
> > + dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)uridp,
> 0);
> > +
> > + efi_free_pool(uridp);
> > + efi_free_pool(dp1);
> > +
> > + return dp2;
> > +}
> > +
> > /* Construct a device-path for memory-mapped image */
> > struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
> > uint64_t start_address,
> > --
> > 2.43.0
> >
>
> [0]
> https://lore.kernel.org/u-boot/20241110083017.367565-1-ilias.apalodimas@linaro.org/
>
> Thanks
> /Ilias
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 10/15] efi_loader: net: add support to send http requests and parse http headers
2024-11-12 13:51 ` Heinrich Schuchardt
@ 2024-11-13 14:02 ` Adriano Córdova
0 siblings, 0 replies; 39+ messages in thread
From: Adriano Córdova @ 2024-11-13 14:02 UTC (permalink / raw)
To: Heinrich Schuchardt
Cc: joe.hershberger, rfried.dev, jerome.forissier, ilias.apalodimas,
u-boot
El mar, 12 nov 2024 a las 10:51, Heinrich Schuchardt (<xypron.glpk@gmx.de>)
escribió:
> On 11.11.24 22:09, Adriano Cordova wrote:
> > Add network-stack agnostic way to send an http request and
> > parse http headers from efi drivers. This uses wget as a
> > backend and communicates with it via efi_wget_info.
> >
> > The function efi_net_do_request allocates a buffer on behalf of an
> > efi application using efi_alloc and passes it to wget to receive
> > the data. If the method is GET and the buffer is too small, it
> > re-allocates the buffer based on the last received Content-Length
> > header and tries again. If the method is HEAD it just issues one
> > request. So issuing a HEAD request (to update Content-Length) and
> > then a GET request is preferred but not required.
> >
> > The function efi_net_parse_headers parses a raw buffer containing
> > an http header into an array of EFI specific 'http_header' structs.
> >
> > Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> > ---
> >
> > Changes in v3:
> > - Add a struct wget_http_info efi_wget_info for efi_net to pass to wget
> > when issuing wget requests, instead of using the old wget_info (see v2
> > of the series 'wget: Expose wget to applications').
> > - Let a pointer to the http status code be passed to efi_net_do_request
> > for it to fill it for the client after a request.
> >
> > include/efi_loader.h | 13 ++++
> > lib/efi_loader/efi_net.c | 158 +++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 171 insertions(+)
> >
> > diff --git a/include/efi_loader.h b/include/efi_loader.h
> > index f49f8e6be0..4d05c08441 100644
> > --- a/include/efi_loader.h
> > +++ b/include/efi_loader.h
> > @@ -16,6 +16,7 @@
> > #include <image.h>
> > #include <pe.h>
> > #include <linux/list.h>
> > +#include <linux/sizes.h>
> > #include <linux/oid_registry.h>
> >
> > struct blk_desc;
> > @@ -136,6 +137,18 @@ void efi_net_get_addr(struct efi_ipv4_address *ip,
> > void efi_net_set_addr(struct efi_ipv4_address *ip,
> > struct efi_ipv4_address *mask,
> > struct efi_ipv4_address *gw);
> > +efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method,
> ulong *buffer,
> > + u32 *status_code, ulong *file_size, char
> *headers_buffer);
> > +#define MAX_HTTP_HEADERS_SIZE SZ_64K
> > +#define MAX_HTTP_HEADERS 100
> > +#define MAX_HTTP_HEADER_NAME 128
> > +#define MAX_HTTP_HEADER_VALUE 512
> > +struct http_header {
> > + uchar name[MAX_HTTP_HEADER_NAME];
> > + uchar value[MAX_HTTP_HEADER_VALUE];
> > +};
> > +
> > +void efi_net_parse_headers(ulong *num_headers, struct http_header
> *headers);
> > #else
> > static inline void efi_net_set_dp(const char *dev, const char *server)
> { }
> > static inline void efi_net_get_dp(void **dp) { }
> > diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
> > index d4570d4d7c..30234ae1c7 100644
> > --- a/lib/efi_loader/efi_net.c
> > +++ b/lib/efi_loader/efi_net.c
> > @@ -17,6 +17,7 @@
> >
> > #include <efi_loader.h>
> > #include <dm.h>
> > +#include <linux/sizes.h>
> > #include <malloc.h>
> > #include <vsprintf.h>
> > #include <net.h>
> > @@ -34,6 +35,12 @@ static int rx_packet_num;
> > static struct efi_net_obj *netobj;
> > static struct efi_device_path *net_dp;
> >
> > +static struct wget_http_info efi_wget_info = {
> > + .set_bootdev = false,
> > + .check_buffer_size = true,
> > +
> > +};
> > +
> > /*
> > * The notification function of this event is called in every timer
> cycle
> > * to check if a new network packet has been received.
> > @@ -1003,6 +1010,10 @@ out_of_resources:
> > return EFI_OUT_OF_RESOURCES;
> > }
> >
> > +/**
> > + * efi_net_set_dp() - set device path of efi net device
> > + *
> > + */
> > void efi_net_set_dp(const char *dev, const char *server)
> > {
> > if (!strcmp(dev, "Net"))
> > @@ -1011,6 +1022,10 @@ void efi_net_set_dp(const char *dev, const char
> *server)
> > net_dp = efi_dp_from_http(server);
> > }
> >
> > +/**
> > + * efi_net_set_dp() - get device path of efi net device
> > + *
> > + */
> > void efi_net_get_dp(void **dp)
> > {
> > if (!net_dp)
> > @@ -1019,6 +1034,10 @@ void efi_net_get_dp(void **dp)
> > *dp = efi_dp_dup(net_dp);
> > }
> >
> > +/**
> > + * efi_net_get_addr() - get IP address information
> > + *
> > + */
> > void efi_net_get_addr(struct efi_ipv4_address *ip,
> > struct efi_ipv4_address *mask,
> > struct efi_ipv4_address *gw)
> > @@ -1068,6 +1087,10 @@ void efi_net_get_addr(struct efi_ipv4_address *ip,
> > #endif
> > }
> >
> > +/**
> > + * efi_net_set_addr() - set IP address information
> > + *
> > + */
> > void efi_net_set_addr(struct efi_ipv4_address *ip,
> > struct efi_ipv4_address *mask,
> > struct efi_ipv4_address *gw)
> > @@ -1117,3 +1140,138 @@ void efi_net_set_addr(struct efi_ipv4_address
> *ip,
> > memcpy((void *)&net_netmask, (void *)mask, 4);
> > #endif
> > }
> > +
> > +/**
> > + * efi_net_set_buffer() - allocate a buffer of min 64K
>
> Please, describe the parameters.
>
> > + *
> > + */
> > +static efi_status_t efi_net_set_buffer(ulong *buffer, ulong size)
>
> Please, use size_t for sizes.
>
> All invocations use size = 0. So we should drop the parameter.
>
Some invocations still use it
> +{
> > + efi_status_t ret = EFI_SUCCESS;
> > +
> > + if (size < SZ_64K)
> > + size = SZ_64K;
> > +
> > + efi_free_pool((void *)*buffer);
> > +
> > + *buffer = (ulong)efi_alloc(size);
>
> efi_alloc() returns a pointer.
>
> There is no good reason to store pointers in ulong. Please, use void *
> for pointers.
>
Makes sense, I will change it. But wget uses ulong for now, so I still cast
to ulong before calling wget.
> Patch 13/15 shows the resulting confusion:
>
> In efi_http_send_data() you assume http_load_addr is a sandbox virtual
> address:
>
> ptr = map_sysmem(inst->http_load_addr + inst->current_offset,
> transfer_size);
>
> And a few lines below you assume that it is a pointer:
>
> efi_free_pool((void *)inst->http_load_addr);
>
> We should keep sandbox specific addresses which need map_sysmem() and
> map_to_sysmem() out of the EFI implementation as far as possible.
>
> So let parameter buffer be of type **void here.
>
> We need a test that we can run both on the sandbox and on Q
>
> > + if (!*buffer)
> > + ret = EFI_OUT_OF_RESOURCES;
> > +
> > + efi_wget_info.buffer_size = size;
> > + //debug("efi_net: set buffer of size %lu at %lu\n", size, *buffer);
>
> It would be fine to have a debug statement here but, please, remove
> lines that only where used during your development process.
>
> Nits:
> As described in doc/develop/codingstyle.rst:224:
>
> "* Put a blank line before the last ``return`` in a function unless it
> is the only line:"
>
> > + return ret;
> > +}
> > +
> > +/**
> > + * efi_net_parse_headers() - parse HTTP headers
> > + *
> > + * Parses the raw buffer efi_wget_info.headers into an array headers
> > + * of efi structs http_headers. The array should be at least
> > + * MAX_HTTP_HEADERS long.
>
> Please, describe the parameters.
>
> > + */
> > +void efi_net_parse_headers(ulong *num_headers, struct http_header
> *headers)
> > +{
> > + if (!num_headers || !headers)
> > + return;
> > +
> > + // Populate info with http headers.
> > + *num_headers = 0;
> > + const uchar *line_start = efi_wget_info.headers;
> > + const uchar *line_end;
> > + ulong count;
> > + struct http_header *current_header;
> > + const uchar *separator;
> > + size_t name_length, value_length;
> > +
> > + // Skip the first line (request or status line)
> > + line_end = strstr(line_start, "\r\n");
> > +
> > + if (line_end)
> > + line_start = line_end + 2;
> > +
> > + while ((line_end = strstr(line_start, "\r\n")) != NULL) {
> > + count = *num_headers;
> > + if (line_start == line_end || count >= MAX_HTTP_HEADERS)
> > + break;
> > + current_header = headers + count;
> > + separator = strchr(line_start, ':');
> > + if (separator) {
> > + name_length = separator - line_start;
> > + ++separator;
> > + while (*separator == ' ')
> > + ++separator;
> > + value_length = line_end - separator;
> > + if (name_length < MAX_HTTP_HEADER_NAME &&
> > + value_length < MAX_HTTP_HEADER_VALUE) {
> > + strncpy(current_header->name, line_start,
> name_length);
> > + current_header->name[name_length] = '\0';
> > + strncpy(current_header->value, separator,
> value_length);
> > + current_header->value[value_length] = '\0';
> > + (*num_headers)++;
> > + }
> > + }
> > + line_start = line_end + 2;
> > + }
> > +}
> > +
> > +/**
> > + * efi_net_do_request() - issue an HTTP request using wget
>
> Please, complete the function description.
>
> > + *
> > + */
> > +efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method,
> ulong *buffer,
>
> Please, use void **buffer. Below you are assuming *buffer is a pointer
> and not a sandbox virtual address.
>
> > + u32 *status_code, ulong *file_size, char
> *headers_buffer)
> > +{
> > + efi_status_t ret = EFI_SUCCESS;
> > + int wget_ret;
> > + static bool last_head;
> > +
> > + if (!buffer || !file_size)
> > + return EFI_ABORTED;
> > +
> > + efi_wget_info.method = (enum wget_http_method)method;
>
> Parameter method has type 'enum wget_http_method'. Please, remove the
> superfluous conversion.
>
> Parameter has type efi_http_method (efi_api.h), not wget_http_method
(net-common.h). These enums are the
same, I didn't want to expose the efi api to wget, but I could.
> Best regards
>
> Heinrich
>
> > + efi_wget_info.headers = headers_buffer;
> > +
> > + switch (method) {
> > + case HTTP_METHOD_GET:
> > + ret = efi_net_set_buffer(buffer, last_head ?
> efi_wget_info.hdr_cont_len : 0);
> > + if (ret != EFI_SUCCESS)
> > + goto out;
> > + wget_ret = wget_request((ulong)*buffer, url,
> &efi_wget_info);
> > + if ((ulong)efi_wget_info.hdr_cont_len >
> efi_wget_info.buffer_size) {
> > + // Try again with updated buffer size
> > + ret = efi_net_set_buffer(buffer,
> (ulong)efi_wget_info.hdr_cont_len);
> > + if (ret != EFI_SUCCESS)
> > + goto out;
> > + if (wget_request((ulong)*buffer, url,
> &efi_wget_info)) {
> > + efi_free_pool((void *)*buffer);
> > + ret = EFI_DEVICE_ERROR;
> > + goto out;
> > + }
> > + } else if (wget_ret) {
> > + efi_free_pool((void *)*buffer);
> > + ret = EFI_DEVICE_ERROR;
> > + goto out;
> > + }
> > + // Pass the actual number of received bytes to the
> application
> > + *file_size = efi_wget_info.file_size;
> > + *status_code = efi_wget_info.status_code;
> > + last_head = false;
> > + break;
> > + case HTTP_METHOD_HEAD:
> > + ret = efi_net_set_buffer(buffer, 0);
> > + if (ret != EFI_SUCCESS)
> > + goto out;
> > + wget_request((ulong)*buffer, url, &efi_wget_info);
> > + *file_size = 0;
> > + *status_code = efi_wget_info.status_code;
> > + last_head = true;
> > + break;
> > + default:
> > + ret = EFI_UNSUPPORTED;
> > + break;
> > + }
> > +
> > +out:
> > + return ret;
> > +}
>
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
` (14 preceding siblings ...)
2024-11-11 21:09 ` [PATCH v3 15/15] efi_selftest: add test for IPv4 Config2 protocol Adriano Cordova
@ 2024-11-14 15:22 ` Ilias Apalodimas
2024-11-14 16:16 ` Adriano Córdova
15 siblings, 1 reply; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-14 15:22 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
Hi Adriano,
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
> Add support for EFI_HTTP_PROTOCOL, EFI_HTTP_SERVICE_BINDING_PROTOCOL,
> and EFI_IP4_CONFIG2_PROTOCOL.
>
> This series depends on the series 'wget: Expose wget to applications',
> also found at:
> https://github.com/0n41rd4/u-boot/commits/http-driver-wget
>
> The fist two patches of this series are not efi specific and have also
> been sent to the corresponding maintainers, but this series depends on
> them, so they are added here for redundancy. A branch with both series
> of patches, concatenated, is at:
> https://github.com/0n41rd4/u-boot/commits/efi-http-driver
It would help a lot if we had pointers (or an EFI app) using this protocol
to test. Are you using any of that for devel/debugging?
Thanks
/Ilias
>
>
> Adriano Cordova (13):
> net: net_utils: Move ip_to_string to lib/net_utils.c
> net: wget: let wget_with_dns work with dns disabled
> efi_loader: device_path: add definition of
> DEVICE_PATH_SUB_TYPE_MSG_IPV4
> efi_loader: device_path: add efi_dp_from_ipv4
> efi_api: add definitions for HTTP and IP4_CONFIG2 protocols
> efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr
> efi_loader: device_path: add support for HTTP device path
> efi_loader: net: set EFI bootdevice device path to HTTP when loaded
> from wget
> efi_loader: net: add support to send http requests and parse http
> headers
> efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL
> efi_loader: efi_net: add EFI_HTTP_PROTOCOL
> efi_selftest: add test for HTTP protocol
> efi_selftest: add test for IPv4 Config2 protocol
>
> Heinrich Schuchardt (2):
> efi_loader: add IPv4() to device path to text protocol
> lib: uuid: display HTTP and IPV4 Config II protocols
>
> include/efi_api.h | 220 +++++++++
> include/efi_loader.h | 42 ++
> include/net-common.h | 10 +
> lib/efi_loader/Kconfig | 17 +
> lib/efi_loader/Makefile | 2 +
> lib/efi_loader/efi_device_path.c | 95 +++-
> lib/efi_loader/efi_device_path_to_text.c | 23 +
> lib/efi_loader/efi_http.c | 563 +++++++++++++++++++++++
> lib/efi_loader/efi_ipconfig.c | 216 +++++++++
> lib/efi_loader/efi_net.c | 316 ++++++++++++-
> lib/efi_selftest/Makefile | 2 +
> lib/efi_selftest/efi_selftest_http.c | 315 +++++++++++++
> lib/efi_selftest/efi_selftest_ipconfig.c | 173 +++++++
> lib/net_utils.c | 11 +
> lib/uuid.c | 14 +
> net/lwip/wget.c | 1 +
> net/net.c | 11 -
> net/wget.c | 39 +-
> 18 files changed, 2038 insertions(+), 32 deletions(-)
> create mode 100644 lib/efi_loader/efi_http.c
> create mode 100644 lib/efi_loader/efi_ipconfig.c
> create mode 100644 lib/efi_selftest/efi_selftest_http.c
> create mode 100644 lib/efi_selftest/efi_selftest_ipconfig.c
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers
2024-11-14 15:22 ` [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Ilias Apalodimas
@ 2024-11-14 16:16 ` Adriano Córdova
2024-11-14 16:33 ` Heinrich Schuchardt
0 siblings, 1 reply; 39+ messages in thread
From: Adriano Córdova @ 2024-11-14 16:16 UTC (permalink / raw)
To: Ilias Apalodimas
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
Hi Ilias,
I have been testing with grub, and with the efi selftest. Here are the
steps to test with a riscv grub:
1. Get grubriscv64.efi from e.g. the following .deb package
wget
http://launchpadlibrarian.net/754414418/grub-efi-riscv64-unsigned_2.12-5ubuntu5.1_riscv64.deb
2. Compile U-boot with qemu-riscv64_smode_defconfig. Enable CMD_WGET.
3. Create a tap interface:
$ sudo ip tuntap add dev tap0 mode tap
$ sudo ip addr add 10.0.0.0/24 dev tap0
$ sudo ip link set dev tap0 up
4. Start an http server in a directory containing grubriscv64.efi and a
test file (e.g. a riscv kernel)
$ sudo python3 -m http.server 80 --bind 10.0.0.0
5. Launch U-boot:
$ qemu-system-riscv64 \
-machine virt \
-nographic \
-kernel u-boot \
-netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
-device virtio-net-device,netdev=net0
6. Inside U-boot's console
=> setenv ipaddr 10.0.0.1
=> setenv netmask 255.255.255.0
=> wget 10.0.0.0:80/grubriscv64.efi <http://10.0.0.0/grubriscv64.efi>
=> bootefi $loadaddr
7. Print debug, check address and installed protocols (optional):
grub> set debug="peimage,net"
grub> net_ls_addr
grub> lsefi
8. Download a test file, e.g. a kernel, through http (here Image is a riscv
linux kernel):
grub> linux (http,10.0.0.0:80)/Image
9. Try boot it:
grub> boot
Best,
Adriano
El jue, 14 nov 2024 a las 12:22, Ilias Apalodimas (<
ilias.apalodimas@linaro.org>) escribió:
> Hi Adriano,
>
> On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
>> Add support for EFI_HTTP_PROTOCOL, EFI_HTTP_SERVICE_BINDING_PROTOCOL,
>> and EFI_IP4_CONFIG2_PROTOCOL.
>>
>> This series depends on the series 'wget: Expose wget to applications',
>> also found at:
>> https://github.com/0n41rd4/u-boot/commits/http-driver-wget
>>
>> The fist two patches of this series are not efi specific and have also
>> been sent to the corresponding maintainers, but this series depends on
>> them, so they are added here for redundancy. A branch with both series
>> of patches, concatenated, is at:
>> https://github.com/0n41rd4/u-boot/commits/efi-http-driver
>
>
> It would help a lot if we had pointers (or an EFI app) using this protocol
> to test. Are you using any of that for devel/debugging?
>
> Thanks
> /Ilias
>
>>
>>
>> Adriano Cordova (13):
>> net: net_utils: Move ip_to_string to lib/net_utils.c
>> net: wget: let wget_with_dns work with dns disabled
>> efi_loader: device_path: add definition of
>> DEVICE_PATH_SUB_TYPE_MSG_IPV4
>> efi_loader: device_path: add efi_dp_from_ipv4
>> efi_api: add definitions for HTTP and IP4_CONFIG2 protocols
>> efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr
>> efi_loader: device_path: add support for HTTP device path
>> efi_loader: net: set EFI bootdevice device path to HTTP when loaded
>> from wget
>> efi_loader: net: add support to send http requests and parse http
>> headers
>> efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL
>> efi_loader: efi_net: add EFI_HTTP_PROTOCOL
>> efi_selftest: add test for HTTP protocol
>> efi_selftest: add test for IPv4 Config2 protocol
>>
>> Heinrich Schuchardt (2):
>> efi_loader: add IPv4() to device path to text protocol
>> lib: uuid: display HTTP and IPV4 Config II protocols
>>
>> include/efi_api.h | 220 +++++++++
>> include/efi_loader.h | 42 ++
>> include/net-common.h | 10 +
>> lib/efi_loader/Kconfig | 17 +
>> lib/efi_loader/Makefile | 2 +
>> lib/efi_loader/efi_device_path.c | 95 +++-
>> lib/efi_loader/efi_device_path_to_text.c | 23 +
>> lib/efi_loader/efi_http.c | 563 +++++++++++++++++++++++
>> lib/efi_loader/efi_ipconfig.c | 216 +++++++++
>> lib/efi_loader/efi_net.c | 316 ++++++++++++-
>> lib/efi_selftest/Makefile | 2 +
>> lib/efi_selftest/efi_selftest_http.c | 315 +++++++++++++
>> lib/efi_selftest/efi_selftest_ipconfig.c | 173 +++++++
>> lib/net_utils.c | 11 +
>> lib/uuid.c | 14 +
>> net/lwip/wget.c | 1 +
>> net/net.c | 11 -
>> net/wget.c | 39 +-
>> 18 files changed, 2038 insertions(+), 32 deletions(-)
>> create mode 100644 lib/efi_loader/efi_http.c
>> create mode 100644 lib/efi_loader/efi_ipconfig.c
>> create mode 100644 lib/efi_selftest/efi_selftest_http.c
>> create mode 100644 lib/efi_selftest/efi_selftest_ipconfig.c
>>
>> --
>> 2.43.0
>>
>>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers
2024-11-14 16:16 ` Adriano Córdova
@ 2024-11-14 16:33 ` Heinrich Schuchardt
0 siblings, 0 replies; 39+ messages in thread
From: Heinrich Schuchardt @ 2024-11-14 16:33 UTC (permalink / raw)
To: Ilias Apalodimas
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
Adriano Córdova
On 11/14/24 17:16, Adriano Córdova wrote:
> Hi Ilias,
> I have been testing with grub, and with the efi selftest. Here are the
> steps to test with a riscv grub:
>
> 1. Get grubriscv64.efi from e.g. the following .deb package
> wget http://launchpadlibrarian.net/754414418/grub-efi-riscv64-
> unsigned_2.12-5ubuntu5.1_riscv64.deb <http://
> launchpadlibrarian.net/754414418/grub-efi-riscv64-
> unsigned_2.12-5ubuntu5.1_riscv64.deb>
If you are on Debian or Ubuntu you can use
dpkg -x grub-efi-riscv64-unsigned_2.12-5ubuntu5.1_riscv64.deb target_dir
for extraction.
On other distros
ar -x grub-efi-riscv64-unsigned_2.12-5ubuntu5.1_riscv64.deb
mkdir -p target_dir
tar --zstd -xf data.tar.zst -C target_dir
target_dir/usr/lib/grub/riscv64-efi/monolithic/grubnetriscv64.efi
is the file I am using. That one has all the network modules included.
Best regards
Heinrich
>
> 2. Compile U-boot with qemu-riscv64_smode_defconfig. Enable CMD_WGET.
>
> 3. Create a tap interface:
> $ sudo ip tuntap add dev tap0 mode tap
> $ sudo ip addr add 10.0.0.0/24 <http://10.0.0.0/24> dev tap0
> $ sudo ip link set dev tap0 up
>
> 4. Start an http server in a directory containing grubriscv64.efi and a
> test file (e.g. a riscv kernel)
> $ sudo python3 -m http.server 80 --bind 10.0.0.0
>
> 5. Launch U-boot:
> $ qemu-system-riscv64 \
> -machine virt \
> -nographic \
> -kernel u-boot \
> -netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
> -device virtio-net-device,netdev=net0
>
> 6. Inside U-boot's console
> => setenv ipaddr 10.0.0.1
> => setenv netmask 255.255.255.0
> => wget 10.0.0.0:80/grubriscv64.efi <http://10.0.0.0/grubriscv64.efi>
> => bootefi $loadaddr
>
> 7. Print debug, check address and installed protocols (optional):
> grub> set debug="peimage,net"
> grub> net_ls_addr
> grub> lsefi
>
> 8. Download a test file, e.g. a kernel, through http (here Image is a
> riscv linux kernel):
> grub> linux (http,10.0.0.0:80)/Image
>
> 9. Try boot it:
> grub> boot
>
> Best,
> Adriano
>
> El jue, 14 nov 2024 a las 12:22, Ilias Apalodimas
> (<ilias.apalodimas@linaro.org <mailto:ilias.apalodimas@linaro.org>>)
> escribió:
>
> Hi Adriano,
>
> On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com
> <mailto:adrianox@gmail.com>> wrote:
>
> Add support for EFI_HTTP_PROTOCOL,
> EFI_HTTP_SERVICE_BINDING_PROTOCOL,
> and EFI_IP4_CONFIG2_PROTOCOL.
>
> This series depends on the series 'wget: Expose wget to
> applications',
> also found at:
> https://github.com/0n41rd4/u-boot/commits/http-driver-wget
> <https://github.com/0n41rd4/u-boot/commits/http-driver-wget>
>
> The fist two patches of this series are not efi specific and
> have also
> been sent to the corresponding maintainers, but this series
> depends on
> them, so they are added here for redundancy. A branch with both
> series
> of patches, concatenated, is at:
> https://github.com/0n41rd4/u-boot/commits/efi-http-driver
> <https://github.com/0n41rd4/u-boot/commits/efi-http-driver>
>
>
> It would help a lot if we had pointers (or an EFI app) using this
> protocol to test. Are you using any of that for devel/debugging?
>
> Thanks
> /Ilias
>
>
>
> Adriano Cordova (13):
> net: net_utils: Move ip_to_string to lib/net_utils.c
> net: wget: let wget_with_dns work with dns disabled
> efi_loader: device_path: add definition of
> DEVICE_PATH_SUB_TYPE_MSG_IPV4
> efi_loader: device_path: add efi_dp_from_ipv4
> efi_api: add definitions for HTTP and IP4_CONFIG2 protocols
> efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr
> efi_loader: device_path: add support for HTTP device path
> efi_loader: net: set EFI bootdevice device path to HTTP when
> loaded
> from wget
> efi_loader: net: add support to send http requests and parse http
> headers
> efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL
> efi_loader: efi_net: add EFI_HTTP_PROTOCOL
> efi_selftest: add test for HTTP protocol
> efi_selftest: add test for IPv4 Config2 protocol
>
> Heinrich Schuchardt (2):
> efi_loader: add IPv4() to device path to text protocol
> lib: uuid: display HTTP and IPV4 Config II protocols
>
> include/efi_api.h | 220 +++++++++
> include/efi_loader.h | 42 ++
> include/net-common.h | 10 +
> lib/efi_loader/Kconfig | 17 +
> lib/efi_loader/Makefile | 2 +
> lib/efi_loader/efi_device_path.c | 95 +++-
> lib/efi_loader/efi_device_path_to_text.c | 23 +
> lib/efi_loader/efi_http.c | 563 +++++++++++++++
> ++++++++
> lib/efi_loader/efi_ipconfig.c | 216 +++++++++
> lib/efi_loader/efi_net.c | 316 ++++++++++++-
> lib/efi_selftest/Makefile | 2 +
> lib/efi_selftest/efi_selftest_http.c | 315 +++++++++++++
> lib/efi_selftest/efi_selftest_ipconfig.c | 173 +++++++
> lib/net_utils.c | 11 +
> lib/uuid.c | 14 +
> net/lwip/wget.c | 1 +
> net/net.c | 11 -
> net/wget.c | 39 +-
> 18 files changed, 2038 insertions(+), 32 deletions(-)
> create mode 100644 lib/efi_loader/efi_http.c
> create mode 100644 lib/efi_loader/efi_ipconfig.c
> create mode 100644 lib/efi_selftest/efi_selftest_http.c
> create mode 100644 lib/efi_selftest/efi_selftest_ipconfig.c
>
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c
2024-11-11 21:09 ` [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c Adriano Cordova
2024-11-13 8:17 ` Ilias Apalodimas
@ 2024-11-16 20:56 ` Heinrich Schuchardt
2024-11-16 21:04 ` Heinrich Schuchardt
2 siblings, 0 replies; 39+ messages in thread
From: Heinrich Schuchardt @ 2024-11-16 20:56 UTC (permalink / raw)
To: Adriano Cordova
Cc: joe.hershberger, rfried.dev, jerome.forissier, ilias.apalodimas,
u-boot
On 11/11/24 22:09, Adriano Cordova wrote:
> The function string_to_ip is already in net_utils, which is
> compiled unconditionally, but ip_to_string is currently only
> accessible if the legacy network stack is selected. This
> commit puts ip_to_string in net_utils.c and removes it from the
> legacy network code.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> ---
>
> (no changes since v2)
>
> include/net-common.h | 10 ++++++++++
> lib/net_utils.c | 11 +++++++++++
> net/net.c | 11 -----------
> 3 files changed, 21 insertions(+), 11 deletions(-)
>
> diff --git a/include/net-common.h b/include/net-common.h
> index 3cd0f34374..b7a519e36d 100644
> --- a/include/net-common.h
> +++ b/include/net-common.h
> @@ -426,6 +426,16 @@ void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
> */
> struct in_addr string_to_ip(const char *s);
>
> +/**
> + * ip_to_string() - Convert a string to ip address
> + *
> + * Implemented in lib/net_utils.c (built unconditionally)
> + *
> + * @x: Input ip to parse
> + * @s: string containing the parsed ip address
> + */
> +void ip_to_string(struct in_addr x, char *s);
> +
> /* copy a filename (allow for "..." notation, limit length) */
> void copy_filename(char *dst, const char *src, int size);
>
> diff --git a/lib/net_utils.c b/lib/net_utils.c
> index c70fef0d99..621f6512b6 100644
> --- a/lib/net_utils.c
> +++ b/lib/net_utils.c
> @@ -152,6 +152,17 @@ out_err:
> }
> #endif
>
> +void ip_to_string(struct in_addr x, char *s)
> +{
> + x.s_addr = ntohl(x.s_addr);
> + sprintf(s, "%d.%d.%d.%d",
> + (int) ((x.s_addr >> 24) & 0xff),
> + (int) ((x.s_addr >> 16) & 0xff),
> + (int) ((x.s_addr >> 8) & 0xff),
> + (int) ((x.s_addr >> 0) & 0xff)
> + );
> +}
> +
> void string_to_enetaddr(const char *addr, uint8_t *enetaddr)
> {
> char *end;
> diff --git a/net/net.c b/net/net.c
> index f47e9fbe33..ca35704f66 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -1723,17 +1723,6 @@ int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len)
> return 1;
> }
>
> -void ip_to_string(struct in_addr x, char *s)
> -{
> - x.s_addr = ntohl(x.s_addr);
> - sprintf(s, "%d.%d.%d.%d",
> - (int) ((x.s_addr >> 24) & 0xff),
> - (int) ((x.s_addr >> 16) & 0xff),
> - (int) ((x.s_addr >> 8) & 0xff),
> - (int) ((x.s_addr >> 0) & 0xff)
> - );
> -}
> -
> void vlan_to_string(ushort x, char *s)
> {
> x = ntohs(x);
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c
2024-11-11 21:09 ` [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c Adriano Cordova
2024-11-13 8:17 ` Ilias Apalodimas
2024-11-16 20:56 ` Heinrich Schuchardt
@ 2024-11-16 21:04 ` Heinrich Schuchardt
2 siblings, 0 replies; 39+ messages in thread
From: Heinrich Schuchardt @ 2024-11-16 21:04 UTC (permalink / raw)
To: Adriano Cordova
Cc: joe.hershberger, rfried.dev, jerome.forissier, ilias.apalodimas,
u-boot
On 11/11/24 22:09, Adriano Cordova wrote:
> The function string_to_ip is already in net_utils, which is
> compiled unconditionally, but ip_to_string is currently only
> accessible if the legacy network stack is selected. This
> commit puts ip_to_string in net_utils.c and removes it from the
> legacy network code.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
If patches are unchanged, please, copy the Reviewed-by, Acked-by, and
Signed-off tags when resubmitting.
Reviewed-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> ---
>
> (no changes since v2)
>
> include/net-common.h | 10 ++++++++++
> lib/net_utils.c | 11 +++++++++++
> net/net.c | 11 -----------
> 3 files changed, 21 insertions(+), 11 deletions(-)
>
> diff --git a/include/net-common.h b/include/net-common.h
> index 3cd0f34374..b7a519e36d 100644
> --- a/include/net-common.h
> +++ b/include/net-common.h
> @@ -426,6 +426,16 @@ void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
> */
> struct in_addr string_to_ip(const char *s);
>
> +/**
> + * ip_to_string() - Convert a string to ip address
> + *
> + * Implemented in lib/net_utils.c (built unconditionally)
> + *
> + * @x: Input ip to parse
> + * @s: string containing the parsed ip address
> + */
> +void ip_to_string(struct in_addr x, char *s);
> +
> /* copy a filename (allow for "..." notation, limit length) */
> void copy_filename(char *dst, const char *src, int size);
>
> diff --git a/lib/net_utils.c b/lib/net_utils.c
> index c70fef0d99..621f6512b6 100644
> --- a/lib/net_utils.c
> +++ b/lib/net_utils.c
> @@ -152,6 +152,17 @@ out_err:
> }
> #endif
>
> +void ip_to_string(struct in_addr x, char *s)
> +{
> + x.s_addr = ntohl(x.s_addr);
> + sprintf(s, "%d.%d.%d.%d",
> + (int) ((x.s_addr >> 24) & 0xff),
> + (int) ((x.s_addr >> 16) & 0xff),
> + (int) ((x.s_addr >> 8) & 0xff),
> + (int) ((x.s_addr >> 0) & 0xff)
> + );
> +}
> +
> void string_to_enetaddr(const char *addr, uint8_t *enetaddr)
> {
> char *end;
> diff --git a/net/net.c b/net/net.c
> index f47e9fbe33..ca35704f66 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -1723,17 +1723,6 @@ int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len)
> return 1;
> }
>
> -void ip_to_string(struct in_addr x, char *s)
> -{
> - x.s_addr = ntohl(x.s_addr);
> - sprintf(s, "%d.%d.%d.%d",
> - (int) ((x.s_addr >> 24) & 0xff),
> - (int) ((x.s_addr >> 16) & 0xff),
> - (int) ((x.s_addr >> 8) & 0xff),
> - (int) ((x.s_addr >> 0) & 0xff)
> - );
> -}
> -
> void vlan_to_string(ushort x, char *s)
> {
> x = ntohs(x);
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 02/15] net: wget: let wget_with_dns work with dns disabled
2024-11-11 21:09 ` [PATCH v3 02/15] net: wget: let wget_with_dns work with dns disabled Adriano Cordova
@ 2024-11-16 21:12 ` Heinrich Schuchardt
0 siblings, 0 replies; 39+ messages in thread
From: Heinrich Schuchardt @ 2024-11-16 21:12 UTC (permalink / raw)
To: Adriano Cordova
Cc: joe.hershberger, rfried.dev, jerome.forissier, ilias.apalodimas,
u-boot
On 11/11/24 22:09, Adriano Cordova wrote:
> This was marked as TODO in the code:
> -Enable use of wget_with_dns even if CMD_DNS is disabled if
> the given uri has the ip address for the http server.
> -Check for port in the uri when transforming to legacy wget
> syntax inside wget_with_dns.
> -Move the check for CMD_DNS inside wget_with_dns.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> net/wget.c | 38 ++++++++++++++++++++++++--------------
> 1 file changed, 24 insertions(+), 14 deletions(-)
>
> diff --git a/net/wget.c b/net/wget.c
> index 3bc2522cde..36158e0a9c 100644
> --- a/net/wget.c
> +++ b/net/wget.c
> @@ -530,12 +530,10 @@ void wget_start(void)
> wget_send(TCP_SYN, 0, 0, 0);
> }
>
> -#if (IS_ENABLED(CONFIG_CMD_DNS))
> int wget_with_dns(ulong dst_addr, char *uri)
> {
> int ret;
> - char *s, *host_name, *file_name, *str_copy;
> -
> + char *s, *host_name, *file_name, *str_copy, *port;
> /*
> * Download file using wget.
> *
> @@ -556,18 +554,31 @@ int wget_with_dns(ulong dst_addr, char *uri)
> }
> file_name = s;
>
> - /* TODO: If the given uri has ip address for the http server, skip dns */
> - net_dns_resolve = host_name;
> - net_dns_env_var = "httpserverip";
> - if (net_loop(DNS) < 0) {
> - log_err("Error: dns lookup of %s failed, check setup\n", net_dns_resolve);
> - ret = -EINVAL;
> - goto out;
> - }
> - s = env_get("httpserverip");
> - if (!s) {
> + port = host_name;
> + host_name = strsep(&port, ":");
> +
> + if (string_to_ip(host_name).s_addr != 0) {
In U-Coot code we prefer to remove the '!= 0':
if (string_to_ip(host_name).s_addr) {
> + s = host_name;
> + } else {
> +#if IS_ENABLED(CONFIG_CMD_DNS)
> + net_dns_resolve = host_name;
> + net_dns_env_var = "httpserverip";
> + if (net_loop(DNS) < 0) {
> + log_err("DNS lookup of %s failed, check setup\n", net_dns_resolve);
> + ret = -EINVAL;
> + goto out;
> + }
> + s = env_get("httpserverip");
> + if (!s) {
> + log_err("DNS could not resolve %s\n", net_dns_resolve);
In EFI protocols we don't want any message output.
The wget command may write a message when receiving EINVAL.
> + ret = -EINVAL;
> + goto out;
> + }
> +#else
> + log_err("DNS disabled, %s could not be resolved\n", host_name);
ditto
Best regards
Heinrich
> ret = -EINVAL;
> goto out;
> +#endif
> }
>
> strlcpy(net_boot_file_name, s, sizeof(net_boot_file_name));
> @@ -581,7 +592,6 @@ out:
>
> return ret < 0 ? ret : 0;
> }
> -#endif
>
> /**
> * wget_validate_uri() - validate the uri for wget
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 06/15] efi_api: add definitions for HTTP and IP4_CONFIG2 protocols
2024-11-11 21:09 ` [PATCH v3 06/15] efi_api: add definitions for HTTP and IP4_CONFIG2 protocols Adriano Cordova
@ 2024-11-18 12:08 ` Ilias Apalodimas
0 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-18 12:08 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> Add EFI definitions for EFI_IP4_CONFIG2_PROTOCOL,
> EFI_HTTP_SERVICE_BINDING_PROTOCOL, and EFI_HTTP_PROTOCOL.
> According to UEFI spec 2.10.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> include/efi_api.h | 203 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 203 insertions(+)
>
> diff --git a/include/efi_api.h b/include/efi_api.h
> index 99ee749522..61c4eda8f8 100644
> --- a/include/efi_api.h
> +++ b/include/efi_api.h
> @@ -1725,6 +1725,209 @@ struct efi_pxe_base_code_protocol {
> struct efi_pxe_mode *mode;
> };
>
> +#define EFI_IP4_CONFIG2_PROTOCOL_GUID \
> + EFI_GUID(0x5b446ed1, 0xe30b, 0x4faa, \
> + 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80)
> +
> +enum efi_ip4_config2_data_type {
> + EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
> + EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
> + EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
> + EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
> + EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
> + EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM,
> +};
> +
> +struct efi_ip4_config2_protocol {
> + efi_status_t (EFIAPI * set_data)(struct efi_ip4_config2_protocol *this,
> + enum efi_ip4_config2_data_type data_type,
> + efi_uintn_t data_size,
> + void *data);
> + efi_status_t (EFIAPI * get_data)(struct efi_ip4_config2_protocol *this,
> + enum efi_ip4_config2_data_type data_type,
> + efi_uintn_t *data_size,
> + void *data);
> + efi_status_t (EFIAPI * register_data_notify)(struct efi_ip4_config2_protocol *this,
> + enum efi_ip4_config2_data_type data_type,
> + struct efi_event *event);
> + efi_status_t (EFIAPI * unregister_data_notify)(struct efi_ip4_config2_protocol *this,
> + enum efi_ip4_config2_data_type data_type,
> + struct efi_event *event);
> +};
> +
> +struct efi_ip4_route_table {
> + struct efi_ipv4_address subnet_address;
> + struct efi_ipv4_address subnet_mask;
> + struct efi_ipv4_address gateway_address;
> +};
> +
> +#define EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32
> +
> +struct efi_ip4_config2_interface_info {
> + u16 name[EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE];
> + u8 if_type;
> + u32 hw_address_size;
> + struct efi_mac_address hw_address;
> + struct efi_ipv4_address station_address;
> + struct efi_ipv4_address subnet_mask;
> + u32 route_table_size;
> + struct efi_ip4_route_table *route_table;
> +};
> +
> +enum efi_ip4_config2_policy {
> + EFI_IP4_CONFIG2_POLICY_STATIC,
> + EFI_IP4_CONFIG2_POLICY_DHCP,
> + EFI_IP4_CONFIG2_POLICY_MAX
> +};
> +
> +struct efi_ip4_config2_manual_address {
> + struct efi_ipv4_address address;
> + struct efi_ipv4_address subnet_mask;
> +};
> +
> +#define EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \
> + EFI_GUID(0xbdc8e6af, 0xd9bc, 0x4379, \
> + 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c)
> +
> +struct efi_service_binding_protocol {
> + efi_status_t (EFIAPI * create_child)(struct efi_service_binding_protocol *this,
> + efi_handle_t *child_handle);
> + efi_status_t (EFIAPI * destroy_child)(struct efi_service_binding_protocol *this,
> + efi_handle_t child_handle);
> +};
> +
> +#define EFI_HTTP_PROTOCOL_GUID \
> + EFI_GUID(0x7A59B29B, 0x910B, 0x4171, \
> + 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B)
> +
> +enum efi_http_version {
> + HTTPVERSION10,
> + HTTPVERSION11,
> + HTTPVERSIONUNSUPPORTED
> +};
> +
> +struct efi_httpv4_access_point {
> + bool use_default_address;
> + struct efi_ipv4_address local_address;
> + struct efi_ipv4_address local_subnet;
> + u16 local_port;
> +};
> +
> +union efi_http_access_point {
> + struct efi_httpv4_access_point *ipv4_node;
> + struct efi_httpv6_access_point *ipv6_node;
> +};
> +
> +struct efi_http_config_data {
> + enum efi_http_version http_version;
> + u32 timeout;
> + bool is_ipv6;
> + union efi_http_access_point access_point;
> +};
> +
> +enum efi_http_method {
> + HTTP_METHOD_GET,
> + HTTP_METHOD_POST,
> + HTTP_METHOD_PATCH,
> + HTTP_METHOD_OPTIONS,
> + HTTP_METHOD_CONNECT,
> + HTTP_METHOD_HEAD,
> + HTTP_METHOD_PUT,
> + HTTP_METHOD_DELETE,
> + HTTP_METHOD_TRACE,
> + HTTP_METHOD_MAX
> +};
> +
> +enum efi_http_status_code {
> + 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
> +};
> +
> +struct efi_http_request_data {
> + enum efi_http_method method;
> + u16 *url;
> +};
> +
> +struct efi_http_response_data {
> + enum efi_http_status_code status_code;
> +};
> +
> +struct efi_http_header {
> + char *field_name;
> + char *field_value;
> +};
> +
> +struct efi_http_message {
> + union {
> + struct efi_http_request_data *request;
> + struct efi_http_response_data *response;
> + } data;
> + efi_uintn_t header_count;
> + struct efi_http_header *headers;
> + efi_uintn_t body_length;
> + void *body;
> +};
> +
> +struct efi_http_token {
> + struct efi_event *event;
> + efi_status_t status;
> + struct efi_http_message *message;
> +};
> +
> +struct efi_http_protocol {
> + efi_status_t (EFIAPI * get_mode_data)(struct efi_http_protocol *this,
> + struct efi_http_config_data *data);
> + efi_status_t (EFIAPI * configure)(struct efi_http_protocol *this,
> + struct efi_http_config_data *data);
> + efi_status_t (EFIAPI * request)(struct efi_http_protocol *this,
> + struct efi_http_token *token);
> + efi_status_t (EFIAPI * cancel)(struct efi_http_protocol *this,
> + struct efi_http_token *token);
> + efi_status_t (EFIAPI * response)(struct efi_http_protocol *this,
> + struct efi_http_token *token);
> + efi_status_t (EFIAPI * poll)(struct efi_http_protocol *this);
> +};
> +
> #define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
> EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \
> 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
> --
> 2.43.0
>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 07/15] efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr
2024-11-11 21:09 ` [PATCH v3 07/15] efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr Adriano Cordova
@ 2024-11-18 12:21 ` Ilias Apalodimas
2024-11-18 12:35 ` Adriano Córdova
0 siblings, 1 reply; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-18 12:21 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
Hi Adriano,
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> Add the functions efi_net_set_addr and efi_net_get_addr to set
> and get the ip address from efi code in a network agnostic way.
> This could also go in net_common, or be compiled conditionally
> for each network stack.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> include/efi_loader.h | 16 +++++++
> lib/efi_loader/efi_net.c | 100 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 116 insertions(+)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 39809eac1b..612bc42816 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -125,6 +125,22 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
> size_t buffer_size) { }
> #endif
>
> +#if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER)
> +void efi_net_get_addr(struct efi_ipv4_address *ip,
> + struct efi_ipv4_address *mask,
> + struct efi_ipv4_address *gw);
> +void efi_net_set_addr(struct efi_ipv4_address *ip,
> + struct efi_ipv4_address *mask,
> + struct efi_ipv4_address *gw);
> +#else
> +static inline void efi_net_get_addr(struct efi_ipv4_address *ip,
> + struct efi_ipv4_address *mask,
> + struct efi_ipv4_address *gw) { }
> +static inline void efi_net_set_addr(struct efi_ipv4_address *ip,
> + struct efi_ipv4_address *mask,
> + struct efi_ipv4_address *gw) { }
> +#endif
> +
> /* Maximum number of configuration tables */
> #define EFI_MAX_CONFIGURATION_TABLES 16
>
> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
> index 7cd536705f..dd84b3f18d 100644
> --- a/lib/efi_loader/efi_net.c
> +++ b/lib/efi_loader/efi_net.c
> @@ -17,6 +17,7 @@
>
> #include <efi_loader.h>
> #include <malloc.h>
> +#include <vsprintf.h>
> #include <net.h>
>
> static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
> @@ -997,3 +998,102 @@ out_of_resources:
> printf("ERROR: Out of memory\n");
> return EFI_OUT_OF_RESOURCES;
> }
> +
> +void efi_net_get_addr(struct efi_ipv4_address *ip,
> + struct efi_ipv4_address *mask,
> + struct efi_ipv4_address *gw)
> +{
> +#ifdef CONFIG_NET_LWIP
> + char *ipstr = "ipaddr\0\0";
> + char *maskstr = "netmask\0\0";
> + char *gwstr = "gatewayip\0\0";
You generally can't define strings like that and expect to change
them. The compiler places the string literal somewhere in memory which
is immutable.
If you want to keep the code as is, you need to define these as ipstr[].
> + int idx;
> + struct in_addr tmp;
> + char *env;
> +
> + idx = dev_seq(eth_get_dev());
> +
> + if (idx < 0 || idx > 99) {
> + log_err("unexpected idx %d\n", idx);
> + return;
> + }
> +
> + if (idx) {
Is 0 not legal here?
And why is the behavior differnt with and without LWIP?
> + sprintf(ipstr, "ipaddr%d", idx);
> + sprintf(maskstr, "netmask%d", idx);
> + sprintf(gwstr, "gatewayip%d", idx);
> + }
> +
> + env = env_get(ipstr);
> + if (env && ip) {
> + tmp = string_to_ip(env);
> + memcpy((void *)ip, (void *)&tmp, 4);
> + }
> +
> + env = env_get(maskstr);
> + if (env && mask) {
> + tmp = string_to_ip(env);
> + memcpy((void *)mask, (void *)&tmp, 4);
> + }
> + env = env_get(gwstr);
> + if (env && gw) {
> + tmp = string_to_ip(env);
> + memcpy((void *)gw, (void *)&tmp, 4);
> + }
> +#else
> + if (ip)
> + memcpy((void *)ip, (void *)&net_ip, 4);
> + if (mask)
> + memcpy((void *)mask, (void *)&net_netmask, 4);
Get rid of casts etc.
> +#endif
> +}
> +
> +void efi_net_set_addr(struct efi_ipv4_address *ip,
> + struct efi_ipv4_address *mask,
> + struct efi_ipv4_address *gw)
> +{
> +#ifdef CONFIG_NET_LWIP
> + char *ipstr = "ipaddr\0\0";
> + char *maskstr = "netmask\0\0";
> + char *gwstr = "gatewayip\0\0";
> + int idx;
> + struct in_addr *addr;
> + char tmp[46];
> +
> + idx = dev_seq(eth_get_dev());
> +
> + if (idx < 0 || idx > 99) {
> + log_err("unexpected idx %d\n", idx);
> + return;
> + }
> +
> + if (idx) {
> + sprintf(ipstr, "ipaddr%d", idx);
> + sprintf(maskstr, "netmask%d", idx);
> + sprintf(gwstr, "gatewayip%d", idx);
> + }
> +
> + if (ip) {
> + addr = (struct in_addr *)ip;
> + ip_to_string(*addr, tmp);
> + env_set(ipstr, tmp);
> + }
> +
> + if (mask) {
> + addr = (struct in_addr *)mask;
> + ip_to_string(*addr, tmp);
> + env_set(maskstr, tmp);
> + }
> +
> + if (gw) {
> + addr = (struct in_addr *)gw;
> + ip_to_string(*addr, tmp);
> + env_set(gwstr, tmp);
> + }
> +#else
> + if (ip)
> + memcpy((void *)&net_ip, (void *)ip, 4);
> + if (mask)
> + memcpy((void *)&net_netmask, (void *)mask, 4);
> +#endif
> +}
> --
> 2.43.0
>
Cheers
/Ilias
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 09/15] efi_loader: net: set EFI bootdevice device path to HTTP when loaded from wget
2024-11-11 21:09 ` [PATCH v3 09/15] efi_loader: net: set EFI bootdevice device path to HTTP when loaded from wget Adriano Cordova
@ 2024-11-18 12:23 ` Ilias Apalodimas
0 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-18 12:23 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> Set the device path of the efi boot device to an HTTP device path
> (as formed by efi_dp_from_http) when the next boot stage is loaded
> using wget (i.e., when wget is used with wget_info.set_bootdev=1).
We want the reasoning of why you need the change in the commit log,
instead of what the code does.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> include/efi_loader.h | 6 ++++++
> lib/efi_loader/efi_device_path.c | 2 +-
> lib/efi_loader/efi_net.c | 22 +++++++++++++++++++++-
> net/lwip/wget.c | 1 +
> net/wget.c | 1 +
> 5 files changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 96b204dfc3..f49f8e6be0 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -126,6 +126,10 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
> #endif
>
> #if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER)
> +/* Call this to update the current device path of the efi net device */
> +void efi_net_set_dp(const char *dev, const char *server);
> +/* Call this to get the current device path of the efi net device */
> +void efi_net_get_dp(void **dp);
> void efi_net_get_addr(struct efi_ipv4_address *ip,
> struct efi_ipv4_address *mask,
> struct efi_ipv4_address *gw);
> @@ -133,6 +137,8 @@ void efi_net_set_addr(struct efi_ipv4_address *ip,
> struct efi_ipv4_address *mask,
> struct efi_ipv4_address *gw);
> #else
> +static inline void efi_net_set_dp(const char *dev, const char *server) { }
> +static inline void efi_net_get_dp(void **dp) { }
> static inline void efi_net_get_addr(struct efi_ipv4_address *ip,
> struct efi_ipv4_address *mask,
> struct efi_ipv4_address *gw) { }
> diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
> index 158f08b9e5..afb4abc3ff 100644
> --- a/lib/efi_loader/efi_device_path.c
> +++ b/lib/efi_loader/efi_device_path.c
> @@ -1168,7 +1168,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
> dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
> (uintptr_t)image_addr, image_size);
> } else if (IS_ENABLED(CONFIG_NETDEVICES) && !strcmp(dev, "Net")) {
> - dp = efi_dp_from_eth();
> + efi_net_get_dp((void **)&dp);
> } else if (!strcmp(dev, "Uart")) {
> dp = efi_dp_from_uart();
> } else {
> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
> index dd84b3f18d..d4570d4d7c 100644
> --- a/lib/efi_loader/efi_net.c
> +++ b/lib/efi_loader/efi_net.c
> @@ -16,6 +16,7 @@
> */
>
> #include <efi_loader.h>
> +#include <dm.h>
> #include <malloc.h>
> #include <vsprintf.h>
> #include <net.h>
> @@ -31,6 +32,7 @@ static size_t *receive_lengths;
> static int rx_packet_idx;
> static int rx_packet_num;
> static struct efi_net_obj *netobj;
> +static struct efi_device_path *net_dp;
>
> /*
> * The notification function of this event is called in every timer cycle
> @@ -902,8 +904,10 @@ efi_status_t efi_net_register(void)
> &netobj->net);
> if (r != EFI_SUCCESS)
> goto failure_to_add_protocol;
> + if (!net_dp)
> + efi_net_set_dp("Net", NULL);
> r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
> - efi_dp_from_eth());
> + net_dp);
> if (r != EFI_SUCCESS)
> goto failure_to_add_protocol;
> r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid,
> @@ -999,6 +1003,22 @@ out_of_resources:
> return EFI_OUT_OF_RESOURCES;
> }
>
> +void efi_net_set_dp(const char *dev, const char *server)
> +{
> + if (!strcmp(dev, "Net"))
> + net_dp = efi_dp_from_eth();
> + else if (!strcmp(dev, "Http"))
> + net_dp = efi_dp_from_http(server);
> +}
> +
> +void efi_net_get_dp(void **dp)
> +{
> + if (!net_dp)
> + efi_net_set_dp("Net", NULL);
> + if (dp && net_dp)
> + *dp = efi_dp_dup(net_dp);
> +}
> +
> void efi_net_get_addr(struct efi_ipv4_address *ip,
> struct efi_ipv4_address *mask,
> struct efi_ipv4_address *gw)
> diff --git a/net/lwip/wget.c b/net/lwip/wget.c
> index 53c3b169e0..5c44e324be 100644
> --- a/net/lwip/wget.c
> +++ b/net/lwip/wget.c
> @@ -217,6 +217,7 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result,
> print_size(rx_content_len / elapsed * 1000, "/s)\n");
> printf("Bytes transferred = %lu (%lx hex)\n", ctx->size, ctx->size);
> if (wget_info->set_bootdev) {
> + efi_net_set_dp("Http", ctx->server_name);
> efi_set_bootdev("Net", "", ctx->path, map_sysmem(ctx->saved_daddr, 0),
> rx_content_len);
> }
> diff --git a/net/wget.c b/net/wget.c
> index 36158e0a9c..676d4db759 100644
> --- a/net/wget.c
> +++ b/net/wget.c
> @@ -442,6 +442,7 @@ static void wget_handler(uchar *pkt, u16 dport,
> net_set_state(wget_loop_state);
> wget_info->file_size = net_boot_file_size;
> if (wget_info->method == WGET_HTTP_METHOD_GET && wget_info->set_bootdev) {
> + efi_net_set_dp("Http", NULL);
> efi_set_bootdev("Net", "", image_url,
> map_sysmem(image_load_addr, 0),
> net_boot_file_size);
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 15/15] efi_selftest: add test for IPv4 Config2 protocol
2024-11-11 21:09 ` [PATCH v3 15/15] efi_selftest: add test for IPv4 Config2 protocol Adriano Cordova
@ 2024-11-18 12:27 ` Ilias Apalodimas
0 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-18 12:27 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
Overall this looks good. Get rid of the unneeded casts in memcpy for
the next version.
Thanks
/Ilias
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> Add a test for the EFI_IP4_CONFIG2_PROTOCOL. The test sets the ip
> policy to static, adds an ip address, and then reads the current
> ip address and checks for it to be the same as the one that was set.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> lib/efi_selftest/Makefile | 2 +
> lib/efi_selftest/efi_selftest_ipconfig.c | 173 +++++++++++++++++++++++
> 2 files changed, 175 insertions(+)
> create mode 100644 lib/efi_selftest/efi_selftest_ipconfig.c
>
> diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
> index 140c08effc..17fbfad116 100644
> --- a/lib/efi_selftest/Makefile
> +++ b/lib/efi_selftest/Makefile
> @@ -53,6 +53,8 @@ efi_selftest_watchdog.o
> obj-$(CONFIG_EFI_ECPT) += efi_selftest_ecpt.o
> obj-$(CONFIG_NETDEVICES) += efi_selftest_snp.o
> obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_http.o
> +obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_selftest_ipconfig.o
> +
> obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o
> obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += \
> efi_selftest_unicode_collation.o
> diff --git a/lib/efi_selftest/efi_selftest_ipconfig.c b/lib/efi_selftest/efi_selftest_ipconfig.c
> new file mode 100644
> index 0000000000..e81ab4e334
> --- /dev/null
> +++ b/lib/efi_selftest/efi_selftest_ipconfig.c
> @@ -0,0 +1,173 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * efi_selftest_ipconfig
> + *
> + * This unit test covers the IPv4 Config2 Protocol.
> + *
> + */
> +
> +#include <efi_selftest.h>
> +#include <charset.h>
> +#include <net.h>
> +
> +static struct efi_boot_services *boottime;
> +
> +static struct efi_ip4_config2_protocol *ip4_config2;
> +static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
> +
> +/*
> + * Setup unit test.
> + *
> + * Open IPv4 Config2 protocol
> + *
> + * @handle: handle of the loaded image
> + * @systable: system table
> + * Return: EFI_ST_SUCCESS for success
> + */
> +static int setup(const efi_handle_t handle,
> + const struct efi_system_table *systable)
> +{
> + efi_status_t ret;
> + efi_handle_t *net_handle;
> + efi_uintn_t num_handles;
> + efi_handle_t *handles;
> +
> + boottime = systable->boottime;
> +
> + boottime->locate_handle_buffer(BY_PROTOCOL, &efi_ip4_config2_guid,
> + NULL, &num_handles, &handles);
> +
> + for (net_handle = handles; num_handles--; net_handle++) {
> + ret = boottime->open_protocol(*net_handle, &efi_ip4_config2_guid,
> + (void **)&ip4_config2, 0, 0,
> + EFI_OPEN_PROTOCOL_GET_PROTOCOL);
> + if (ret != EFI_SUCCESS || !ip4_config2)
> + continue;
> + break; // Get first handle that supports ipv4
> + }
> +
> + if (!ip4_config2) {
> + efi_st_error("Failed to locate ipv4 config2 protocol\n");
> + return EFI_ST_FAILURE;
> + }
> +
> + return EFI_ST_SUCCESS;
> +}
> +
> +/*
> + * Execute unit test.
> + *
> + *
> + * Return: EFI_ST_SUCCESS for success
> + */
> +static int execute(void)
> +{
> + efi_status_t ret;
> + enum efi_ip4_config2_policy policy;
> + efi_uintn_t data_size;
> + struct efi_ip4_config2_manual_address manual_address;
> + struct efi_ip4_config2_manual_address orig_address;
> + u8 netmask[] = {255, 255, 255, 0};
> + u8 ip[] = {10, 0, 0, 1};
> +
> + /* Setup may have failed */
> + if (!ip4_config2) {
> + efi_st_error("Setup failure, cannot proceed with test\n");
> + return EFI_ST_FAILURE;
> + }
> +
> + /* Set policy to static */
> + policy = EFI_IP4_CONFIG2_POLICY_STATIC;
> + ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
> + sizeof(enum efi_ip4_config2_policy), (void *)&policy);
> + if (ret != EFI_SUCCESS) {
> + efi_st_error("Failed to set policy\n");
> + return EFI_ST_FAILURE;
> + }
> +
> + /* Save original ip address and netmask */
> + data_size = sizeof(struct efi_ip4_config2_manual_address);
> + ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
> + &data_size, &orig_address);
> + if (ret != EFI_SUCCESS) {
> + efi_st_error("Failed to save original ip address and netmask\n");
> + return EFI_ST_FAILURE;
> + }
> +
> + /* Set static ip and netmask */
> + memcpy((void *)&manual_address.address, (void *)ip,
> + sizeof(struct efi_ipv4_address));
> + memcpy((void *)&manual_address.subnet_mask, (void *)netmask,
> + sizeof(struct efi_ipv4_address));
> + ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
> + sizeof(struct efi_ip4_config2_manual_address), &manual_address);
> + if (ret != EFI_SUCCESS) {
> + efi_st_error("Failed to get ip address and netmask\n");
> + return EFI_ST_FAILURE;
> + }
> +
> + /* Try to set interface info, this should fail */
> + ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, 0, NULL);
> + if (ret == EFI_SUCCESS) {
> + efi_st_error("Interface info is read-only\n");
> + return EFI_ST_FAILURE;
> + }
> +
> + /* Get ip address and netmask and check that they match with the previously set ones */
> + data_size = sizeof(struct efi_ip4_config2_manual_address);
> + ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
> + &data_size, &manual_address);
> + if (ret != EFI_SUCCESS) {
> + efi_st_error("Failed to get ip address and netmask\n");
> + return EFI_ST_FAILURE;
> + }
> + if (memcmp((void *)ip, (void *)&manual_address.address,
> + sizeof(struct efi_ipv4_address)) ||
> + memcmp((void *)netmask, (void *)&manual_address.subnet_mask,
> + sizeof(struct efi_ipv4_address))) {
> + efi_st_error("Ip address mismatch\n");
> + return EFI_ST_FAILURE;
> + }
> +
> + /* Restore original ip address and netmask */
> + ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
> + sizeof(struct efi_ip4_config2_manual_address), &orig_address);
> + if (ret != EFI_SUCCESS) {
> + efi_st_error("Failed to restore original ip address and netmask\n");
> + return EFI_ST_FAILURE;
> + }
> +
> + efi_st_printf("Efi ipconfig test execute succeeded\n");
> + return EFI_ST_SUCCESS;
> +}
> +
> +/*
> + * Tear down unit test.
> + *
> + * Close the timer event created in setup.
> + * Shut down the network adapter.
> + *
> + * Return: EFI_ST_SUCCESS for success
> + */
> +static int teardown(void)
> +{
> + int exit_status = EFI_ST_SUCCESS;
> +
> + return exit_status;
> +}
> +
> +EFI_UNIT_TEST(ipconfig) = {
> + .name = "IPv4 config2 protocol",
> + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
> + .setup = setup,
> + .execute = execute,
> + .teardown = teardown,
> +#ifdef CONFIG_SANDBOX
> + /*
> + * Running this test on the sandbox requires setting environment
> + * variable ethact to a network interface connected to a DHCP server and
> + * ethrotate to 'no'.
> + */
> + .on_request = true,
> +#endif
> +};
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 07/15] efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr
2024-11-18 12:21 ` Ilias Apalodimas
@ 2024-11-18 12:35 ` Adriano Córdova
2024-11-18 13:45 ` Jerome Forissier
0 siblings, 1 reply; 39+ messages in thread
From: Adriano Córdova @ 2024-11-18 12:35 UTC (permalink / raw)
To: Ilias Apalodimas
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
Hi Ilias,
El lun, 18 nov 2024 a las 9:22, Ilias Apalodimas (<
ilias.apalodimas@linaro.org>) escribió:
> Hi Adriano,
>
> On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
> >
> > Add the functions efi_net_set_addr and efi_net_get_addr to set
> > and get the ip address from efi code in a network agnostic way.
> > This could also go in net_common, or be compiled conditionally
> > for each network stack.
> >
> > Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> > ---
> >
> > (no changes since v2)
> >
> > include/efi_loader.h | 16 +++++++
> > lib/efi_loader/efi_net.c | 100 +++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 116 insertions(+)
> >
> > diff --git a/include/efi_loader.h b/include/efi_loader.h
> > index 39809eac1b..612bc42816 100644
> > --- a/include/efi_loader.h
> > +++ b/include/efi_loader.h
> > @@ -125,6 +125,22 @@ static inline void efi_set_bootdev(const char *dev,
> const char *devnr,
> > size_t buffer_size) { }
> > #endif
> >
> > +#if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER)
> > +void efi_net_get_addr(struct efi_ipv4_address *ip,
> > + struct efi_ipv4_address *mask,
> > + struct efi_ipv4_address *gw);
> > +void efi_net_set_addr(struct efi_ipv4_address *ip,
> > + struct efi_ipv4_address *mask,
> > + struct efi_ipv4_address *gw);
> > +#else
> > +static inline void efi_net_get_addr(struct efi_ipv4_address *ip,
> > + struct efi_ipv4_address *mask,
> > + struct efi_ipv4_address *gw) { }
> > +static inline void efi_net_set_addr(struct efi_ipv4_address *ip,
> > + struct efi_ipv4_address *mask,
> > + struct efi_ipv4_address *gw) { }
> > +#endif
> > +
> > /* Maximum number of configuration tables */
> > #define EFI_MAX_CONFIGURATION_TABLES 16
> >
> > diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
> > index 7cd536705f..dd84b3f18d 100644
> > --- a/lib/efi_loader/efi_net.c
> > +++ b/lib/efi_loader/efi_net.c
> > @@ -17,6 +17,7 @@
> >
> > #include <efi_loader.h>
> > #include <malloc.h>
> > +#include <vsprintf.h>
> > #include <net.h>
> >
> > static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
> > @@ -997,3 +998,102 @@ out_of_resources:
> > printf("ERROR: Out of memory\n");
> > return EFI_OUT_OF_RESOURCES;
> > }
> > +
> > +void efi_net_get_addr(struct efi_ipv4_address *ip,
> > + struct efi_ipv4_address *mask,
> > + struct efi_ipv4_address *gw)
> > +{
> > +#ifdef CONFIG_NET_LWIP
> > + char *ipstr = "ipaddr\0\0";
> > + char *maskstr = "netmask\0\0";
> > + char *gwstr = "gatewayip\0\0";
>
> You generally can't define strings like that and expect to change
> them. The compiler places the string literal somewhere in memory which
> is immutable.
> If you want to keep the code as is, you need to define these as ipstr[].
>
> > + int idx;
> > + struct in_addr tmp;
> > + char *env;
> > +
> > + idx = dev_seq(eth_get_dev());
> > +
> > + if (idx < 0 || idx > 99) {
> > + log_err("unexpected idx %d\n", idx);
> > + return;
> > + }
> > +
> > + if (idx) {
>
> Is 0 not legal here?
> And why is the behavior differnt with and without LWIP?
>
This is how the lwip code deals with the environment variables for the IP
address, see
get_udev_ipv4_info in
https://github.com/u-boot/u-boot/blob/a38390284ad4261723d3a2411ba988828e994535/net/lwip/net-lwip.c#L91
In here I am trying to be consistent with that. In legacy the network stack
just uses the variables net_ip and net_netmask.
> > + sprintf(ipstr, "ipaddr%d", idx);
> > + sprintf(maskstr, "netmask%d", idx);
> > + sprintf(gwstr, "gatewayip%d", idx);
> > + }
> > +
> > + env = env_get(ipstr);
> > + if (env && ip) {
> > + tmp = string_to_ip(env);
> > + memcpy((void *)ip, (void *)&tmp, 4);
> > + }
> > +
> > + env = env_get(maskstr);
> > + if (env && mask) {
> > + tmp = string_to_ip(env);
> > + memcpy((void *)mask, (void *)&tmp, 4);
> > + }
> > + env = env_get(gwstr);
> > + if (env && gw) {
> > + tmp = string_to_ip(env);
> > + memcpy((void *)gw, (void *)&tmp, 4);
> > + }
> > +#else
> > + if (ip)
> > + memcpy((void *)ip, (void *)&net_ip, 4);
> > + if (mask)
> > + memcpy((void *)mask, (void *)&net_netmask, 4);
>
> Get rid of casts etc.
>
> > +#endif
> > +}
> > +
> > +void efi_net_set_addr(struct efi_ipv4_address *ip,
> > + struct efi_ipv4_address *mask,
> > + struct efi_ipv4_address *gw)
> > +{
> > +#ifdef CONFIG_NET_LWIP
> > + char *ipstr = "ipaddr\0\0";
> > + char *maskstr = "netmask\0\0";
> > + char *gwstr = "gatewayip\0\0";
> > + int idx;
> > + struct in_addr *addr;
> > + char tmp[46];
> > +
> > + idx = dev_seq(eth_get_dev());
> > +
> > + if (idx < 0 || idx > 99) {
> > + log_err("unexpected idx %d\n", idx);
> > + return;
> > + }
> > +
> > + if (idx) {
> > + sprintf(ipstr, "ipaddr%d", idx);
> > + sprintf(maskstr, "netmask%d", idx);
> > + sprintf(gwstr, "gatewayip%d", idx);
> > + }
> > +
> > + if (ip) {
> > + addr = (struct in_addr *)ip;
> > + ip_to_string(*addr, tmp);
> > + env_set(ipstr, tmp);
> > + }
> > +
> > + if (mask) {
> > + addr = (struct in_addr *)mask;
> > + ip_to_string(*addr, tmp);
> > + env_set(maskstr, tmp);
> > + }
> > +
> > + if (gw) {
> > + addr = (struct in_addr *)gw;
> > + ip_to_string(*addr, tmp);
> > + env_set(gwstr, tmp);
> > + }
> > +#else
> > + if (ip)
> > + memcpy((void *)&net_ip, (void *)ip, 4);
> > + if (mask)
> > + memcpy((void *)&net_netmask, (void *)mask, 4);
> > +#endif
> > +}
> > --
> > 2.43.0
> >
>
> Cheers
> /Ilias
>
Thanks,
Adriano
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 11/15] efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL
2024-11-11 21:09 ` [PATCH v3 11/15] efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL Adriano Cordova
@ 2024-11-18 12:44 ` Ilias Apalodimas
0 siblings, 0 replies; 39+ messages in thread
From: Ilias Apalodimas @ 2024-11-18 12:44 UTC (permalink / raw)
To: Adriano Cordova
Cc: u-boot, joe.hershberger, rfried.dev, jerome.forissier,
xypron.glpk
Hi Adriano
On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>
> Add an implementation of the EFI_IP4_CONFIG2_PROTOCOL. The protocol
> is attached to the handle of the efi network device. This is the same
> handle where snp and pxe are attached to.
>
> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
> ---
>
> (no changes since v2)
>
> include/efi_loader.h | 3 +
> lib/efi_loader/Kconfig | 9 ++
> lib/efi_loader/Makefile | 1 +
> lib/efi_loader/efi_ipconfig.c | 216 ++++++++++++++++++++++++++++++++++
> lib/efi_loader/efi_net.c | 20 +++-
> 5 files changed, 244 insertions(+), 5 deletions(-)
> create mode 100644 lib/efi_loader/efi_ipconfig.c
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 4d05c08441..5029ac39f1 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -627,6 +627,9 @@ int efi_disk_create_partitions(efi_handle_t parent, struct blk_desc *desc,
> efi_status_t efi_gop_register(void);
> /* Called by bootefi to make the network interface available */
> efi_status_t efi_net_register(void);
> +/* Called by efi_net_register to make the ip4 config2 protocol available */
> +efi_status_t efi_ipconfig_register(const efi_handle_t handle,
> + struct efi_ip4_config2_protocol *ip4config);
> /* Called by bootefi to make the watchdog available */
> efi_status_t efi_watchdog_register(void);
> efi_status_t efi_initrd_register(void);
> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index 58d49789f1..d823b2855b 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -476,6 +476,15 @@ config EFI_RISCV_BOOT_PROTOCOL
> replace the transfer via the device-tree. The latter is not
> possible on systems using ACPI.
>
> +config EFI_IP4_CONFIG2_PROTOCOL
> + bool "EFI_IP4_CONFIG2_PROTOCOL support"
> + default y
I think making this default 'y' is a bit too much.
The EFI_LOADER size keeps increasing. Can you only enable it on QEMU &
SANDBOX for testing?
> + depends on NET || NET_LWIP
> + help
> + Provides an implementation of the EFI_IP4_CONFIG2_PROTOCOL, this
> + protocol can be used to set and get the current ip address and
> + other network information.
> +
> endmenu
>
> menu "Misc options"
> diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
> index 87131ab911..30cd1de9d6 100644
> --- a/lib/efi_loader/Makefile
> +++ b/lib/efi_loader/Makefile
> @@ -59,6 +59,7 @@ obj-$(CONFIG_EFI_ESRT) += efi_esrt.o
> obj-$(CONFIG_VIDEO) += efi_gop.o
> obj-$(CONFIG_BLK) += efi_disk.o
> obj-$(CONFIG_NETDEVICES) += efi_net.o
> +obj-$(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) += efi_ipconfig.o
> obj-$(CONFIG_ACPI) += efi_acpi.o
> obj-$(CONFIG_SMBIOS) += efi_smbios.o
> obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
> diff --git a/lib/efi_loader/efi_ipconfig.c b/lib/efi_loader/efi_ipconfig.c
> new file mode 100644
> index 0000000000..4853b2b05d
> --- /dev/null
> +++ b/lib/efi_loader/efi_ipconfig.c
> @@ -0,0 +1,216 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Implementation of EFI_IP4_CONFIG2_PROTOCOL
> + *
> + */
> +
> +#include <efi_loader.h>
> +#include <image.h>
> +#include <malloc.h>
> +#include <mapmem.h>
> +#include <net.h>
> +
> +static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
> +
> +struct efi_ip4_config2_manual_address current_http_ip;
> +static enum efi_ip4_config2_policy current_policy;
> +static char current_mac_addr[32];
> +
> +/* EFI_IP4_CONFIG2_PROTOCOL */
> +
> +/*
> + * efi_ip4_config2_set_data() - Set the configuration for the EFI IPv4 network
> + * stack running on the communication device
> + *
> + * This function implements EFI_IP4_CONFIG2_PROTOCOL.SetData()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @data_type: the type of data to set
> + * @data_size: size of the buffer pointed to by data in bytes
> + * @data: the data buffer to set
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_ip4_config2_set_data(struct efi_ip4_config2_protocol *this,
> + enum efi_ip4_config2_data_type data_type,
> + efi_uintn_t data_size,
> + void *data)
> +{
> + EFI_ENTRY("%p, %d, %zu, %p", this, data_type, data_size, data);
> + efi_status_t ret = EFI_SUCCESS;
> +
> + if (!this)
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +
> + switch (data_type) {
> + case EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO:
> + return EFI_EXIT(EFI_WRITE_PROTECTED);
> + case EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS:
> + if (current_policy != EFI_IP4_CONFIG2_POLICY_STATIC)
> + return EFI_EXIT(EFI_WRITE_PROTECTED);
> + if (data_size == 0 && !data) {
> + memset((void *)¤t_http_ip, 0,
> + sizeof(struct efi_ip4_config2_manual_address));
> + return EFI_EXIT(EFI_SUCCESS);
> + }
> + if (data && data_size == sizeof(struct efi_ip4_config2_manual_address)) {
> + memcpy((void *)¤t_http_ip, data,
> + sizeof(struct efi_ip4_config2_manual_address));
> + efi_net_set_addr(¤t_http_ip.address,
> + ¤t_http_ip.subnet_mask, NULL);
Those functions are defined as void, but might fail and not define an
address. We should check that a valid address is set before returning
success?
> + return EFI_EXIT(EFI_SUCCESS);
> + }
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> + case EFI_IP4_CONFIG2_DATA_TYPE_POLICY:
> + if (data && data_size == sizeof(enum efi_ip4_config2_policy)) {
> + current_policy = *(enum efi_ip4_config2_policy *)data;
> + return EFI_EXIT(EFI_SUCCESS);
> + }
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
I think it's better if you exit with EFI_INVALID_PARAMETER at the top
of the function if data !NULL and datasize == 0 or data !=null and
datasize == 0
> +
> + default:
> + return EFI_EXIT(EFI_UNSUPPORTED);
> + }
> +
> + return EFI_EXIT(ret);
> +}
> +
> +/*
> + * efi_ip4_config2_get_data() - Get the configuration for the EFI IPv4 network
> + * stack running on the communication device
> + *
> + * This function implements EFI_IP4_CONFIG2_PROTOCOL.GetData()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @data_type: the type of data to get
> + * @data_size: size
> + * @data: the data buffer
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_ip4_config2_get_data(struct efi_ip4_config2_protocol *this,
> + enum efi_ip4_config2_data_type data_type,
> + efi_uintn_t *data_size,
> + void *data)
> +{
> + EFI_ENTRY("%p, %d, %p, %p", this, data_type, data_size, data);
> +
> + efi_status_t ret = EFI_SUCCESS;
> + struct efi_ip4_config2_interface_info *info;
> + int tmp;
> +
> + if (!this || !data_size)
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +
> + if (*data_size && !data)
> + return EFI_EXIT(EFI_INVALID_PARAMETER);
> +
> + tmp = sizeof(struct efi_ip4_config2_interface_info)
Always try to preferer defined variables -- sizeof(*info)
> + sizeof(struct efi_ip4_route_table);
> +
> + switch (data_type) {
> + case EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO:
> + if (*data_size < tmp) {
> + *data_size = tmp;
> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
> + }
> +
> + info = (struct efi_ip4_config2_interface_info *)data;
> + memset(info, 0, sizeof(struct efi_ip4_config2_interface_info));
> +
> + info->hw_address_size = 6;
> + memcpy(info->hw_address.mac_addr, current_mac_addr, 6);
> + // Set the route table size
> +
> + info->route_table_size = 0;
> + break;
> + case EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS:
> + if (*data_size < sizeof(struct efi_ip4_config2_manual_address)) {
> + *data_size = sizeof(struct efi_ip4_config2_manual_address);
> + return EFI_EXIT(EFI_BUFFER_TOO_SMALL);
> + }
> +
> + efi_net_get_addr(¤t_http_ip.address, ¤t_http_ip.subnet_mask, NULL);
> + memcpy(data, (void *)¤t_http_ip,
> + sizeof(struct efi_ip4_config2_manual_address));
> +
> + break;
> + default:
> + return EFI_EXIT(EFI_UNSUPPORTED);
> + break;
Fix the indentation here
> + }
> + return EFI_EXIT(ret);
> +}
> +
> +/*
> + * efi_ip4_config2_register_notify() - Register an event that is to be signaled whenever
> + * a configuration process on the specified configuration
> + * data is done
> + *
> + * This function implements EFI_IP4_CONFIG2_PROTOCOL.RegisterDataNotify()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @data_type: the type of data to register the event for
> + * @event: the event to register
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_ip4_config2_register_notify(struct efi_ip4_config2_protocol *this,
> + enum efi_ip4_config2_data_type data_type,
> + struct efi_event *event)
> +{
> + EFI_ENTRY("%p, %d, %p", this, data_type, event);
> +
> + return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +/*
> + * efi_ip4_config2_unregister_notify() - Remove a previously registered eventfor
> + * the specified configuration data
> + *
> + * This function implements EFI_IP4_CONFIG2_PROTOCOL.UnregisterDataNotify()
> + * See the Unified Extensible Firmware Interface
> + * (UEFI) specification for details.
> + *
> + * @this: pointer to the protocol instance
> + * @data_type: the type of data to remove the event for
> + * @event: the event to unregister
> + * Return: status code
> + */
> +static efi_status_t EFIAPI efi_ip4_config2_unregister_notify(struct efi_ip4_config2_protocol *this,
> + enum efi_ip4_config2_data_type data_type,
> + struct efi_event *event)
> +{
> + EFI_ENTRY("%p, %d, %p", this, data_type, event);
> +
> + return EFI_EXIT(EFI_UNSUPPORTED);
> +}
> +
> +/**
> + * efi_ipconfig_register() - register the ip4_config2 protocol
> + *
> + */
> +efi_status_t efi_ipconfig_register(const efi_handle_t handle,
> + struct efi_ip4_config2_protocol *ip4config)
> +{
> + efi_status_t r = EFI_SUCCESS;
> +
> + r = efi_add_protocol(handle, &efi_ip4_config2_guid,
> + ip4config);
> + if (r != EFI_SUCCESS)
> + goto failure_to_add_protocol;
No need for a goto here, just exit here
> +
> + memcpy(current_mac_addr, eth_get_ethaddr(), 6);
> +
> + ip4config->set_data = efi_ip4_config2_set_data;
> + ip4config->get_data = efi_ip4_config2_get_data;
> + ip4config->register_data_notify = efi_ip4_config2_register_notify;
> + ip4config->unregister_data_notify = efi_ip4_config2_unregister_notify;
> +
> + return EFI_SUCCESS;
> +failure_to_add_protocol:
> + printf("ERROR: Failure to add protocol\n");
log_err
> + return r;
> +}
> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
> index 30234ae1c7..fa3b0c0007 100644
> --- a/lib/efi_loader/efi_net.c
> +++ b/lib/efi_loader/efi_net.c
> @@ -54,11 +54,12 @@ static struct efi_event *wait_for_packet;
> /**
> * struct efi_net_obj - EFI object representing a network interface
> *
> - * @header: EFI object header
> - * @net: simple network protocol interface
> - * @net_mode: status of the network interface
> - * @pxe: PXE base code protocol interface
> - * @pxe_mode: status of the PXE base code protocol
> + * @header: EFI object header
> + * @net: simple network protocol interface
> + * @net_mode: status of the network interface
> + * @pxe: PXE base code protocol interface
> + * @pxe_mode: status of the PXE base code protocol
> + * @ip4_config2: IP4 Config2 protocol interface
> */
> struct efi_net_obj {
> struct efi_object header;
> @@ -66,6 +67,9 @@ struct efi_net_obj {
> struct efi_simple_network_mode net_mode;
> struct efi_pxe_base_code_protocol pxe;
> struct efi_pxe_mode pxe_mode;
> +#ifdef CONFIG_EFI_IP4_CONFIG2_PROTOCOL
> + struct efi_ip4_config2_protocol ip4_config2;
> +#endif
> };
>
> /*
> @@ -993,6 +997,12 @@ efi_status_t efi_net_register(void)
> return r;
> }
>
> +#ifdef CONFIG_EFI_IP4_CONFIG2_PROTOCOL
use IS_ENABLED instead
> + r = efi_ipconfig_register(&netobj->header, &netobj->ip4_config2);
> + if (r != EFI_SUCCESS)
> + goto failure_to_add_protocol;
> +#endif
> +
> return EFI_SUCCESS;
> failure_to_add_protocol:
> printf("ERROR: Failure to add protocol\n");
> --
> 2.43.0
>
Thanks
/Ilias
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH v3 07/15] efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr
2024-11-18 12:35 ` Adriano Córdova
@ 2024-11-18 13:45 ` Jerome Forissier
0 siblings, 0 replies; 39+ messages in thread
From: Jerome Forissier @ 2024-11-18 13:45 UTC (permalink / raw)
To: Adriano Córdova, Ilias Apalodimas
Cc: u-boot, joe.hershberger, rfried.dev, xypron.glpk
On 11/18/24 13:35, Adriano Córdova wrote:
> Hi Ilias,
>
> El lun, 18 nov 2024 a las 9:22, Ilias Apalodimas (<
> ilias.apalodimas@linaro.org>) escribió:
>
>> Hi Adriano,
>>
>> On Mon, 11 Nov 2024 at 23:10, Adriano Cordova <adrianox@gmail.com> wrote:
>>>
>>> Add the functions efi_net_set_addr and efi_net_get_addr to set
>>> and get the ip address from efi code in a network agnostic way.
>>> This could also go in net_common, or be compiled conditionally
>>> for each network stack.
>>>
>>> Signed-off-by: Adriano Cordova <adrianox@gmail.com>
>>> ---
>>>
>>> (no changes since v2)
>>>
>>> include/efi_loader.h | 16 +++++++
>>> lib/efi_loader/efi_net.c | 100 +++++++++++++++++++++++++++++++++++++++
>>> 2 files changed, 116 insertions(+)
>>>
>>> diff --git a/include/efi_loader.h b/include/efi_loader.h
>>> index 39809eac1b..612bc42816 100644
>>> --- a/include/efi_loader.h
>>> +++ b/include/efi_loader.h
>>> @@ -125,6 +125,22 @@ static inline void efi_set_bootdev(const char *dev,
>> const char *devnr,
>>> size_t buffer_size) { }
>>> #endif
>>>
>>> +#if CONFIG_IS_ENABLED(NETDEVICES) && CONFIG_IS_ENABLED(EFI_LOADER)
>>> +void efi_net_get_addr(struct efi_ipv4_address *ip,
>>> + struct efi_ipv4_address *mask,
>>> + struct efi_ipv4_address *gw);
>>> +void efi_net_set_addr(struct efi_ipv4_address *ip,
>>> + struct efi_ipv4_address *mask,
>>> + struct efi_ipv4_address *gw);
>>> +#else
>>> +static inline void efi_net_get_addr(struct efi_ipv4_address *ip,
>>> + struct efi_ipv4_address *mask,
>>> + struct efi_ipv4_address *gw) { }
>>> +static inline void efi_net_set_addr(struct efi_ipv4_address *ip,
>>> + struct efi_ipv4_address *mask,
>>> + struct efi_ipv4_address *gw) { }
>>> +#endif
>>> +
>>> /* Maximum number of configuration tables */
>>> #define EFI_MAX_CONFIGURATION_TABLES 16
>>>
>>> diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
>>> index 7cd536705f..dd84b3f18d 100644
>>> --- a/lib/efi_loader/efi_net.c
>>> +++ b/lib/efi_loader/efi_net.c
>>> @@ -17,6 +17,7 @@
>>>
>>> #include <efi_loader.h>
>>> #include <malloc.h>
>>> +#include <vsprintf.h>
>>> #include <net.h>
>>>
>>> static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
>>> @@ -997,3 +998,102 @@ out_of_resources:
>>> printf("ERROR: Out of memory\n");
>>> return EFI_OUT_OF_RESOURCES;
>>> }
>>> +
>>> +void efi_net_get_addr(struct efi_ipv4_address *ip,
>>> + struct efi_ipv4_address *mask,
>>> + struct efi_ipv4_address *gw)
>>> +{
>>> +#ifdef CONFIG_NET_LWIP
>>> + char *ipstr = "ipaddr\0\0";
>>> + char *maskstr = "netmask\0\0";
>>> + char *gwstr = "gatewayip\0\0";
>>
>> You generally can't define strings like that and expect to change
>> them. The compiler places the string literal somewhere in memory which
>> is immutable.
>> If you want to keep the code as is, you need to define these as ipstr[].
>>
>>> + int idx;
>>> + struct in_addr tmp;
>>> + char *env;
>>> +
>>> + idx = dev_seq(eth_get_dev());
>>> +
>>> + if (idx < 0 || idx > 99) {
>>> + log_err("unexpected idx %d\n", idx);
>>> + return;
>>> + }
>>> +
>>> + if (idx) {
>>
>> Is 0 not legal here?
>> And why is the behavior differnt with and without LWIP?
>>
>
> This is how the lwip code deals with the environment variables for the IP
> address, see
> get_udev_ipv4_info in
> https://github.com/u-boot/u-boot/blob/a38390284ad4261723d3a2411ba988828e994535/net/lwip/net-lwip.c#L91
> In here I am trying to be consistent with that.
It's a mistake and an oversight on my part. Ilias is right. I will send a
patch to fix lwIP.
Thanks,
--
Jerome
> In legacy the network stack
> just uses the variables net_ip and net_netmask.
>
>
>>> + sprintf(ipstr, "ipaddr%d", idx);
>>> + sprintf(maskstr, "netmask%d", idx);
>>> + sprintf(gwstr, "gatewayip%d", idx);
>>> + }
>>> +
>>> + env = env_get(ipstr);
>>> + if (env && ip) {
>>> + tmp = string_to_ip(env);
>>> + memcpy((void *)ip, (void *)&tmp, 4);
>>> + }
>>> +
>>> + env = env_get(maskstr);
>>> + if (env && mask) {
>>> + tmp = string_to_ip(env);
>>> + memcpy((void *)mask, (void *)&tmp, 4);
>>> + }
>>> + env = env_get(gwstr);
>>> + if (env && gw) {
>>> + tmp = string_to_ip(env);
>>> + memcpy((void *)gw, (void *)&tmp, 4);
>>> + }
>>> +#else
>>> + if (ip)
>>> + memcpy((void *)ip, (void *)&net_ip, 4);
>>> + if (mask)
>>> + memcpy((void *)mask, (void *)&net_netmask, 4);
>>
>> Get rid of casts etc.
>>
>>> +#endif
>>> +}
>>> +
>>> +void efi_net_set_addr(struct efi_ipv4_address *ip,
>>> + struct efi_ipv4_address *mask,
>>> + struct efi_ipv4_address *gw)
>>> +{
>>> +#ifdef CONFIG_NET_LWIP
>>> + char *ipstr = "ipaddr\0\0";
>>> + char *maskstr = "netmask\0\0";
>>> + char *gwstr = "gatewayip\0\0";
>>> + int idx;
>>> + struct in_addr *addr;
>>> + char tmp[46];
>>> +
>>> + idx = dev_seq(eth_get_dev());
>>> +
>>> + if (idx < 0 || idx > 99) {
>>> + log_err("unexpected idx %d\n", idx);
>>> + return;
>>> + }
>>> +
>>> + if (idx) {
>>> + sprintf(ipstr, "ipaddr%d", idx);
>>> + sprintf(maskstr, "netmask%d", idx);
>>> + sprintf(gwstr, "gatewayip%d", idx);
>>> + }
>>> +
>>> + if (ip) {
>>> + addr = (struct in_addr *)ip;
>>> + ip_to_string(*addr, tmp);
>>> + env_set(ipstr, tmp);
>>> + }
>>> +
>>> + if (mask) {
>>> + addr = (struct in_addr *)mask;
>>> + ip_to_string(*addr, tmp);
>>> + env_set(maskstr, tmp);
>>> + }
>>> +
>>> + if (gw) {
>>> + addr = (struct in_addr *)gw;
>>> + ip_to_string(*addr, tmp);
>>> + env_set(gwstr, tmp);
>>> + }
>>> +#else
>>> + if (ip)
>>> + memcpy((void *)&net_ip, (void *)ip, 4);
>>> + if (mask)
>>> + memcpy((void *)&net_netmask, (void *)mask, 4);
>>> +#endif
>>> +}
>>> --
>>> 2.43.0
>>>
>>
>> Cheers
>> /Ilias
>>
>
> Thanks,
> Adriano
>
^ permalink raw reply [flat|nested] 39+ messages in thread
end of thread, other threads:[~2024-11-18 13:45 UTC | newest]
Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-11 21:09 [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Adriano Cordova
2024-11-11 21:09 ` [PATCH v3 01/15] net: net_utils: Move ip_to_string to lib/net_utils.c Adriano Cordova
2024-11-13 8:17 ` Ilias Apalodimas
2024-11-16 20:56 ` Heinrich Schuchardt
2024-11-16 21:04 ` Heinrich Schuchardt
2024-11-11 21:09 ` [PATCH v3 02/15] net: wget: let wget_with_dns work with dns disabled Adriano Cordova
2024-11-16 21:12 ` Heinrich Schuchardt
2024-11-11 21:09 ` [PATCH v3 03/15] efi_loader: device_path: add definition of DEVICE_PATH_SUB_TYPE_MSG_IPV4 Adriano Cordova
2024-11-13 10:24 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 04/15] efi_loader: device_path: add efi_dp_from_ipv4 Adriano Cordova
2024-11-13 10:18 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 05/15] efi_loader: add IPv4() to device path to text protocol Adriano Cordova
2024-11-13 10:37 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 06/15] efi_api: add definitions for HTTP and IP4_CONFIG2 protocols Adriano Cordova
2024-11-18 12:08 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 07/15] efi_loader: efi_net: add efi_net_set_addr, efi_net_get_addr Adriano Cordova
2024-11-18 12:21 ` Ilias Apalodimas
2024-11-18 12:35 ` Adriano Córdova
2024-11-18 13:45 ` Jerome Forissier
2024-11-11 21:09 ` [PATCH v3 08/15] efi_loader: device_path: add support for HTTP device path Adriano Cordova
2024-11-13 8:15 ` Ilias Apalodimas
2024-11-13 12:51 ` Adriano Córdova
2024-11-11 21:09 ` [PATCH v3 09/15] efi_loader: net: set EFI bootdevice device path to HTTP when loaded from wget Adriano Cordova
2024-11-18 12:23 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 10/15] efi_loader: net: add support to send http requests and parse http headers Adriano Cordova
2024-11-12 13:51 ` Heinrich Schuchardt
2024-11-13 14:02 ` Adriano Córdova
2024-11-11 21:09 ` [PATCH v3 11/15] efi_loader: efi_net: add EFI_IP4_CONFIG2_PROTOCOL Adriano Cordova
2024-11-18 12:44 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 12/15] efi_loader: efi_net: add EFI_HTTP_PROTOCOL Adriano Cordova
2024-11-12 14:02 ` Heinrich Schuchardt
2024-11-11 21:09 ` [PATCH v3 13/15] lib: uuid: display HTTP and IPV4 Config II protocols Adriano Cordova
2024-11-13 8:09 ` Ilias Apalodimas
2024-11-11 21:09 ` [PATCH v3 14/15] efi_selftest: add test for HTTP protocol Adriano Cordova
2024-11-11 21:09 ` [PATCH v3 15/15] efi_selftest: add test for IPv4 Config2 protocol Adriano Cordova
2024-11-18 12:27 ` Ilias Apalodimas
2024-11-14 15:22 ` [PATCH v3 00/15] efi_loader: efi http and ipconfig drivers Ilias Apalodimas
2024-11-14 16:16 ` Adriano Córdova
2024-11-14 16:33 ` Heinrich Schuchardt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox