Merge tag 'efi-next-2024-11-18' of https://source.denx.de/u-boot/custodians/u-boot-efi into next
CI: https://source.denx.de/u-boot/custodians/u-boot-efi/-/pipelines/23430 - Prepare for implementing the EFI_HTTP_PROTOCOL: - Make wget functionality callable even if the wget command is not built (add CONFIG_WGET symbol). - Ensure that wget_with_dns() works the same with the old network stack and with lwIP. - Put server_name and port into wget_ctx. - Integrate struct wget_info into wget code. - Move ip_to_string to lib/net_utils.c
This commit is contained in:
+1
-4
@@ -2115,11 +2115,8 @@ config CMD_TFTPBOOT
|
||||
|
||||
config CMD_WGET
|
||||
bool "wget"
|
||||
depends on CMD_NET
|
||||
default y if SANDBOX
|
||||
select PROT_TCP if NET
|
||||
select PROT_TCP_LWIP if NET_LWIP
|
||||
select PROT_DNS_LWIP if NET_LWIP
|
||||
select WGET
|
||||
help
|
||||
wget is a simple command to download kernel, or other files,
|
||||
from a http server over TCP.
|
||||
|
||||
@@ -196,6 +196,8 @@ U_BOOT_CMD(
|
||||
#if defined(CONFIG_CMD_WGET)
|
||||
static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
wget_info = &default_wget_info;
|
||||
|
||||
return netboot_common(WGET, cmdtp, argc, argv);
|
||||
}
|
||||
|
||||
|
||||
+63
-1
@@ -8,6 +8,7 @@
|
||||
#include <env.h>
|
||||
#include <hexdump.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/types.h>
|
||||
#include <rand.h>
|
||||
#include <time.h>
|
||||
@@ -425,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);
|
||||
|
||||
@@ -494,7 +505,7 @@ int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
|
||||
*
|
||||
* @dst_addr: destination address to download the file
|
||||
* @uri: uri string of target file of wget
|
||||
* Return: downloaded file size, negative if failed
|
||||
* Return: zero on success, negative if failed
|
||||
*/
|
||||
int wget_with_dns(ulong dst_addr, char *uri);
|
||||
/**
|
||||
@@ -506,4 +517,55 @@ int wget_with_dns(ulong dst_addr, char *uri);
|
||||
bool wget_validate_uri(char *uri);
|
||||
//int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]);
|
||||
|
||||
/**
|
||||
* enum wget_http_method - http method
|
||||
*/
|
||||
enum wget_http_method {
|
||||
WGET_HTTP_METHOD_GET,
|
||||
WGET_HTTP_METHOD_POST,
|
||||
WGET_HTTP_METHOD_PATCH,
|
||||
WGET_HTTP_METHOD_OPTIONS,
|
||||
WGET_HTTP_METHOD_CONNECT,
|
||||
WGET_HTTP_METHOD_HEAD,
|
||||
WGET_HTTP_METHOD_PUT,
|
||||
WGET_HTTP_METHOD_DELETE,
|
||||
WGET_HTTP_METHOD_TRACE,
|
||||
WGET_HTTP_METHOD_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* define MAX_HTTP_HEADERS_SIZE - maximum headers buffer size
|
||||
*
|
||||
* When receiving http headers, wget fills a buffer with up
|
||||
* to MAX_HTTP_HEADERS_SIZE bytes of header information.
|
||||
*/
|
||||
#define MAX_HTTP_HEADERS_SIZE SZ_64K
|
||||
|
||||
/**
|
||||
* struct wget_http_info - wget parameters
|
||||
* @method: HTTP Method. Filled by client.
|
||||
* @status_code: HTTP status code. Filled by wget.
|
||||
* @file_size: download size. Filled by wget.
|
||||
* @buffer_size: size of client-provided buffer. Filled by client.
|
||||
* @set_bootdev: set boot device with download. Filled by client.
|
||||
* @check_buffer_size: check download does not exceed buffer size.
|
||||
* Filled by client.
|
||||
* @hdr_cont_len: content length according to headers. Filled by wget
|
||||
* @headers: buffer for headers. Filled by wget.
|
||||
*/
|
||||
struct wget_http_info {
|
||||
enum wget_http_method method;
|
||||
u32 status_code;
|
||||
ulong file_size;
|
||||
ulong buffer_size;
|
||||
bool set_bootdev;
|
||||
bool check_buffer_size;
|
||||
u32 hdr_cont_len;
|
||||
char *headers;
|
||||
};
|
||||
|
||||
extern struct wget_http_info default_wget_info;
|
||||
extern struct wget_http_info *wget_info;
|
||||
int wget_request(ulong dst_addr, char *uri, struct wget_http_info *info);
|
||||
|
||||
#endif /* __NET_COMMON_H__ */
|
||||
|
||||
@@ -16,15 +16,6 @@ void net_lwip_remove_netif(struct netif *netif);
|
||||
struct netif *net_lwip_get_netif(void);
|
||||
int net_lwip_rx(struct udevice *udev, struct netif *netif);
|
||||
|
||||
/**
|
||||
* wget_with_dns() - runs dns host IP address resulution before wget
|
||||
*
|
||||
* @dst_addr: destination address to download the file
|
||||
* @uri: uri string of target file of wget
|
||||
* Return: downloaded file size, negative if failed
|
||||
*/
|
||||
|
||||
int wget_with_dns(ulong dst_addr, char *uri);
|
||||
/**
|
||||
* wget_validate_uri() - varidate the uri
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -244,6 +244,15 @@ config NET_RANDOM_ETHADDR
|
||||
generated. It will be saved to the appropriate environment variable,
|
||||
too.
|
||||
|
||||
config WGET
|
||||
bool "Enable wget"
|
||||
select PROT_TCP if NET
|
||||
select PROT_TCP_LWIP if NET_LWIP
|
||||
select PROT_DNS_LWIP if NET_LWIP
|
||||
help
|
||||
Selecting this will enable wget, an interface to send HTTP requests
|
||||
via the network stack.
|
||||
|
||||
config TFTP_BLOCKSIZE
|
||||
int "TFTP block size"
|
||||
default 1468
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ obj-$(CONFIG_$(PHASE_)TCP_FUNCTION_FASTBOOT) += fastboot_tcp.o
|
||||
obj-$(CONFIG_CMD_WOL) += wol.o
|
||||
obj-$(CONFIG_PROT_UDP) += udp.o
|
||||
obj-$(CONFIG_PROT_TCP) += tcp.o
|
||||
obj-$(CONFIG_CMD_WGET) += wget.o
|
||||
obj-$(CONFIG_WGET) += wget.o
|
||||
|
||||
# Disable this warning as it is triggered by:
|
||||
# sprintf(buf, index ? "foo%d" : "foo", index)
|
||||
|
||||
+1
-1
@@ -5,4 +5,4 @@ obj-$(CONFIG_CMD_DHCP) += dhcp.o
|
||||
obj-$(CONFIG_CMD_DNS) += dns.o
|
||||
obj-$(CONFIG_CMD_PING) += ping.o
|
||||
obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
|
||||
obj-$(CONFIG_CMD_WGET) += wget.o
|
||||
obj-$(CONFIG_WGET) += wget.o
|
||||
|
||||
+44
-6
@@ -23,6 +23,8 @@ enum done_state {
|
||||
};
|
||||
|
||||
struct wget_ctx {
|
||||
char server_name[SERVER_NAME_SIZE];
|
||||
u16 port;
|
||||
char *path;
|
||||
ulong daddr;
|
||||
ulong saved_daddr;
|
||||
@@ -32,6 +34,18 @@ struct wget_ctx {
|
||||
enum done_state done;
|
||||
};
|
||||
|
||||
static void wget_lwip_fill_info(struct pbuf *hdr, u16_t hdr_len, u32_t hdr_cont_len)
|
||||
{
|
||||
if (wget_info->headers && hdr_len < MAX_HTTP_HEADERS_SIZE)
|
||||
pbuf_copy_partial(hdr, (void *)wget_info->headers, hdr_len, 0);
|
||||
wget_info->hdr_cont_len = (u32)hdr_cont_len;
|
||||
}
|
||||
|
||||
static void wget_lwip_set_file_size(u32_t rx_content_len)
|
||||
{
|
||||
wget_info->file_size = (ulong)rx_content_len;
|
||||
}
|
||||
|
||||
static int parse_url(char *url, char *host, u16 *port, char **path)
|
||||
{
|
||||
char *p, *pp;
|
||||
@@ -176,6 +190,13 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result,
|
||||
struct wget_ctx *ctx = arg;
|
||||
ulong elapsed;
|
||||
|
||||
wget_info->status_code = (u32)srv_res;
|
||||
|
||||
if (err == ERR_BUF) {
|
||||
ctx->done = FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (httpc_result != HTTPC_RESULT_OK) {
|
||||
log_err("\nHTTP client error %d\n", httpc_result);
|
||||
ctx->done = FAILURE;
|
||||
@@ -195,8 +216,11 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result,
|
||||
printf("%u bytes transferred in %lu ms (", rx_content_len, elapsed);
|
||||
print_size(rx_content_len / elapsed * 1000, "/s)\n");
|
||||
printf("Bytes transferred = %lu (%lx hex)\n", ctx->size, ctx->size);
|
||||
efi_set_bootdev("Net", "", ctx->path, map_sysmem(ctx->saved_daddr, 0),
|
||||
rx_content_len);
|
||||
if (wget_info->set_bootdev) {
|
||||
efi_set_bootdev("Net", "", ctx->path, map_sysmem(ctx->saved_daddr, 0),
|
||||
rx_content_len);
|
||||
}
|
||||
wget_lwip_set_file_size(rx_content_len);
|
||||
if (env_set_hex("filesize", rx_content_len) ||
|
||||
env_set_hex("fileaddr", ctx->saved_daddr)) {
|
||||
log_err("Could not set filesize or fileaddr\n");
|
||||
@@ -207,15 +231,24 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result,
|
||||
ctx->done = SUCCESS;
|
||||
}
|
||||
|
||||
static err_t httpc_headers_done_cb(httpc_state_t *connection, void *arg, struct pbuf *hdr,
|
||||
u16_t hdr_len, u32_t content_len)
|
||||
{
|
||||
wget_lwip_fill_info(hdr, hdr_len, content_len);
|
||||
|
||||
if (wget_info->check_buffer_size && (ulong)content_len > wget_info->buffer_size)
|
||||
return ERR_BUF;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
|
||||
{
|
||||
char server_name[SERVER_NAME_SIZE];
|
||||
httpc_connection_t conn;
|
||||
httpc_state_t *state;
|
||||
struct netif *netif;
|
||||
struct wget_ctx ctx;
|
||||
char *path;
|
||||
u16 port;
|
||||
|
||||
ctx.daddr = dst_addr;
|
||||
ctx.saved_daddr = dst_addr;
|
||||
@@ -224,7 +257,7 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
|
||||
ctx.prevsize = 0;
|
||||
ctx.start_time = 0;
|
||||
|
||||
if (parse_url(uri, server_name, &port, &path))
|
||||
if (parse_url(uri, ctx.server_name, &ctx.port, &path))
|
||||
return CMD_RET_USAGE;
|
||||
|
||||
netif = net_lwip_new_netif(udev);
|
||||
@@ -233,8 +266,9 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
|
||||
|
||||
memset(&conn, 0, sizeof(conn));
|
||||
conn.result_fn = httpc_result_cb;
|
||||
conn.headers_done_fn = httpc_headers_done_cb;
|
||||
ctx.path = path;
|
||||
if (httpc_get_file_dns(server_name, port, path, &conn, httpc_recv_cb,
|
||||
if (httpc_get_file_dns(ctx.server_name, ctx.port, path, &conn, httpc_recv_cb,
|
||||
&ctx, &state)) {
|
||||
net_lwip_remove_netif(netif);
|
||||
return CMD_RET_FAILURE;
|
||||
@@ -259,6 +293,9 @@ int wget_with_dns(ulong dst_addr, char *uri)
|
||||
{
|
||||
eth_set_current();
|
||||
|
||||
if (!wget_info)
|
||||
wget_info = &default_wget_info;
|
||||
|
||||
return wget_loop(eth_get_dev(), dst_addr, uri);
|
||||
}
|
||||
|
||||
@@ -285,6 +322,7 @@ int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
|
||||
if (parse_legacy_arg(url, nurl, sizeof(nurl)))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
wget_info = &default_wget_info;
|
||||
if (wget_with_dns(dst_addr, nurl))
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <net-common.h>
|
||||
|
||||
void copy_filename(char *dst, const char *src, int size)
|
||||
{
|
||||
@@ -11,3 +12,16 @@ void copy_filename(char *dst, const char *src, int size)
|
||||
*dst++ = *src++;
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
struct wget_http_info default_wget_info = {
|
||||
.method = WGET_HTTP_METHOD_GET,
|
||||
.set_bootdev = true,
|
||||
};
|
||||
|
||||
struct wget_http_info *wget_info;
|
||||
|
||||
int wget_request(ulong dst_addr, char *uri, struct wget_http_info *info)
|
||||
{
|
||||
wget_info = info ? info : &default_wget_info;
|
||||
return wget_with_dns(dst_addr, uri);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+71
-22
@@ -22,10 +22,10 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
/* The default, change with environment variable 'httpdstp' */
|
||||
#define SERVER_PORT 80
|
||||
|
||||
static const char bootfile1[] = "GET ";
|
||||
static const char bootfileGET[] = "GET ";
|
||||
static const char bootfileHEAD[] = "HEAD ";
|
||||
static const char bootfile3[] = " HTTP/1.0\r\n\r\n";
|
||||
static const char http_eom[] = "\r\n\r\n";
|
||||
static const char http_ok[] = "200";
|
||||
static const char content_len[] = "Content-Length";
|
||||
static const char linefeed[] = "\r\n";
|
||||
static struct in_addr web_server_ip;
|
||||
@@ -77,7 +77,7 @@ static inline int store_block(uchar *src, unsigned int offset, unsigned int len)
|
||||
ulong newsize = offset + len;
|
||||
uchar *ptr;
|
||||
|
||||
if (CONFIG_IS_ENABLED(LMB)) {
|
||||
if (CONFIG_IS_ENABLED(LMB) && wget_info->set_bootdev) {
|
||||
if (store_addr < image_load_addr ||
|
||||
lmb_read_check(store_addr, len)) {
|
||||
printf("\nwget error: ");
|
||||
@@ -132,8 +132,17 @@ static void wget_send_stored(void)
|
||||
IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
|
||||
offset = ptr;
|
||||
|
||||
memcpy(offset, &bootfile1, strlen(bootfile1));
|
||||
offset += strlen(bootfile1);
|
||||
switch (wget_info->method) {
|
||||
case WGET_HTTP_METHOD_HEAD:
|
||||
memcpy(offset, &bootfileHEAD, strlen(bootfileHEAD));
|
||||
offset += strlen(bootfileHEAD);
|
||||
break;
|
||||
case WGET_HTTP_METHOD_GET:
|
||||
default:
|
||||
memcpy(offset, &bootfileGET, strlen(bootfileGET));
|
||||
offset += strlen(bootfileGET);
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(offset, image_url, strlen(image_url));
|
||||
offset += strlen(image_url);
|
||||
@@ -193,6 +202,47 @@ static void wget_timeout_handler(void)
|
||||
#define PKT_QUEUE_OFFSET 0x20000
|
||||
#define PKT_QUEUE_PACKET_SIZE 0x800
|
||||
|
||||
static void wget_fill_info(const uchar *pkt, int hlen)
|
||||
{
|
||||
const char *first_space;
|
||||
const char *second_space;
|
||||
char *pos, *end;
|
||||
|
||||
if (wget_info->headers && hlen < MAX_HTTP_HEADERS_SIZE)
|
||||
strncpy(wget_info->headers, pkt, hlen);
|
||||
|
||||
//Get status code
|
||||
first_space = strchr(pkt, ' ');
|
||||
if (!first_space) {
|
||||
wget_info->status_code = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
second_space = strchr(first_space + 1, ' ');
|
||||
if (!second_space) {
|
||||
wget_info->status_code = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
wget_info->status_code = (u32)simple_strtoul(first_space + 1, &end, 10);
|
||||
|
||||
if (second_space != end)
|
||||
wget_info->status_code = -1;
|
||||
|
||||
pos = strstr((char *)pkt, content_len);
|
||||
|
||||
if (pos) {
|
||||
pos += sizeof(content_len) + 1;
|
||||
while (*pos == ' ')
|
||||
pos++;
|
||||
content_length = simple_strtoul(pos, &end, 10);
|
||||
debug_cond(DEBUG_WGET,
|
||||
"wget: Connected Len %lu\n",
|
||||
content_length);
|
||||
wget_info->hdr_cont_len = content_length;
|
||||
}
|
||||
}
|
||||
|
||||
static void wget_connected(uchar *pkt, unsigned int tcp_seq_num,
|
||||
u8 action, unsigned int tcp_ack_num, unsigned int len)
|
||||
{
|
||||
@@ -241,7 +291,11 @@ static void wget_connected(uchar *pkt, unsigned int tcp_seq_num,
|
||||
initial_data_seq_num = tcp_seq_num + hlen;
|
||||
next_data_seq_num = tcp_seq_num + len;
|
||||
|
||||
if (strstr((char *)pkt, http_ok) == 0) {
|
||||
wget_fill_info(pkt, hlen);
|
||||
debug_cond(DEBUG_WGET,
|
||||
"wget: HTTP Status Code %d\n", wget_info->status_code);
|
||||
|
||||
if (wget_info->status_code != 200) {
|
||||
debug_cond(DEBUG_WGET,
|
||||
"wget: Connected Bad Xfer\n");
|
||||
wget_loop_state = NETLOOP_FAIL;
|
||||
@@ -251,17 +305,6 @@ static void wget_connected(uchar *pkt, unsigned int tcp_seq_num,
|
||||
"wget: Connected Pkt %p hlen %x\n",
|
||||
pkt, hlen);
|
||||
|
||||
pos = strstr((char *)pkt, content_len);
|
||||
if (!pos) {
|
||||
content_length = -1;
|
||||
} else {
|
||||
pos += sizeof(content_len) + 2;
|
||||
strict_strtoul(pos, 10, &content_length);
|
||||
debug_cond(DEBUG_WGET,
|
||||
"wget: Connected Len %lu\n",
|
||||
content_length);
|
||||
}
|
||||
|
||||
net_boot_file_size = 0;
|
||||
|
||||
if (len > hlen) {
|
||||
@@ -397,10 +440,13 @@ static void wget_handler(uchar *pkt, u16 dport,
|
||||
case WGET_TRANSFERRED:
|
||||
printf("Packets received %d, Transfer Successful\n", packets);
|
||||
net_set_state(wget_loop_state);
|
||||
efi_set_bootdev("Net", "", image_url,
|
||||
map_sysmem(image_load_addr, 0),
|
||||
net_boot_file_size);
|
||||
env_set_hex("filesize", net_boot_file_size);
|
||||
wget_info->file_size = net_boot_file_size;
|
||||
if (wget_info->method == WGET_HTTP_METHOD_GET && wget_info->set_bootdev) {
|
||||
efi_set_bootdev("Net", "", image_url,
|
||||
map_sysmem(image_load_addr, 0),
|
||||
net_boot_file_size);
|
||||
env_set_hex("filesize", net_boot_file_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -425,6 +471,9 @@ static unsigned int random_port(void)
|
||||
|
||||
void wget_start(void)
|
||||
{
|
||||
if (!wget_info)
|
||||
wget_info = &default_wget_info;
|
||||
|
||||
image_url = strchr(net_boot_file_name, ':');
|
||||
if (image_url > 0) {
|
||||
web_server_ip = string_to_ip(net_boot_file_name);
|
||||
@@ -530,7 +579,7 @@ int wget_with_dns(ulong dst_addr, char *uri)
|
||||
out:
|
||||
free(str_copy);
|
||||
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user