summaryrefslogtreecommitdiff
path: root/net/lwip
diff options
context:
space:
mode:
Diffstat (limited to 'net/lwip')
-rw-r--r--net/lwip/Makefile2
-rw-r--r--net/lwip/dhcp.c4
-rw-r--r--net/lwip/dns.c4
-rw-r--r--net/lwip/net-lwip.c89
-rw-r--r--net/lwip/ping.c11
-rw-r--r--net/lwip/tftp.c77
-rw-r--r--net/lwip/wget.c119
7 files changed, 247 insertions, 59 deletions
diff --git a/net/lwip/Makefile b/net/lwip/Makefile
index 950c5316bb9..5df222589b8 100644
--- a/net/lwip/Makefile
+++ b/net/lwip/Makefile
@@ -1,6 +1,6 @@
ccflags-y += -I$(srctree)/lib/lwip/lwip/src/include -I$(srctree)/lib/lwip/u-boot
-obj-$(CONFIG_$(SPL_)DM_ETH) += net-lwip.o
+obj-$(CONFIG_$(PHASE_)DM_ETH) += net-lwip.o
obj-$(CONFIG_CMD_DHCP) += dhcp.o
obj-$(CONFIG_CMD_DNS) += dns.o
obj-$(CONFIG_CMD_PING) += ping.o
diff --git a/net/lwip/dhcp.c b/net/lwip/dhcp.c
index 3b7e4700c6e..043d2ab6e94 100644
--- a/net/lwip/dhcp.c
+++ b/net/lwip/dhcp.c
@@ -3,6 +3,7 @@
#include <command.h>
#include <console.h>
+#include <env.h>
#include <log.h>
#include <dm/device.h>
#include <linux/delay.h>
@@ -115,7 +116,8 @@ int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
int ret;
struct udevice *dev;
- net_lwip_set_current();
+ if (net_lwip_eth_start() < 0)
+ return CMD_RET_FAILURE;
dev = eth_get_dev();
if (!dev) {
diff --git a/net/lwip/dns.c b/net/lwip/dns.c
index 149bdb784dc..6862869d9e3 100644
--- a/net/lwip/dns.c
+++ b/net/lwip/dns.c
@@ -3,6 +3,7 @@
#include <command.h>
#include <console.h>
+#include <env.h>
#include <lwip/dns.h>
#include <lwip/timeouts.h>
#include <net.h>
@@ -121,7 +122,8 @@ int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
if (argc == 3)
var = argv[2];
- net_lwip_set_current();
+ if (net_lwip_eth_start() < 0)
+ return CMD_RET_FAILURE;
return dns_loop(eth_get_dev(), name, var);
}
diff --git a/net/lwip/net-lwip.c b/net/lwip/net-lwip.c
index 6b7b696dbf0..abc52b32049 100644
--- a/net/lwip/net-lwip.c
+++ b/net/lwip/net-lwip.c
@@ -3,6 +3,7 @@
/* Copyright (C) 2024 Linaro Ltd. */
#include <command.h>
+#include <env.h>
#include <dm/device.h>
#include <dm/uclass.h>
#include <hexdump.h>
@@ -14,6 +15,7 @@
#include <lwip/init.h>
#include <lwip/prot/etharp.h>
#include <net.h>
+#include <timer.h>
/* xx:xx:xx:xx:xx:xx\0 */
#define MAC_ADDR_STRLEN 18
@@ -21,6 +23,8 @@
#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
void (*push_packet)(void *, int len) = 0;
#endif
+static int net_try_count;
+static int net_restarted;
int net_restart_wrap;
static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN];
uchar *net_rx_packets[PKTBUFSRX];
@@ -134,18 +138,27 @@ static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip,
return 0;
}
-/* Initialize the lwIP stack and the ethernet devices and set current device */
-void net_lwip_set_current(void)
+/*
+ * Initialize the network stack if needed and start the current device if valid
+ */
+int net_lwip_eth_start(void)
{
- static bool init_done;
-
- if (!init_done) {
- eth_init_rings();
- eth_init();
- lwip_init();
- init_done = true;
+ int ret;
+
+ net_init();
+ if (eth_is_on_demand_init()) {
+ eth_halt();
+ eth_set_current();
+ ret = eth_init();
+ if (ret < 0) {
+ eth_halt();
+ return ret;
+ }
+ } else {
+ eth_init_state_only();
}
- eth_set_current();
+
+ return 0;
}
static struct netif *new_netif(struct udevice *udev, bool with_ip)
@@ -224,11 +237,20 @@ void net_lwip_remove_netif(struct netif *netif)
free(netif);
}
+/*
+ * Initialize the network buffers, an ethernet device, and the lwIP stack
+ * (once).
+ */
int net_init(void)
{
- eth_set_current();
+ static bool init_done;
- net_lwip_new_netif(eth_get_dev());
+ if (!init_done) {
+ eth_init_rings();
+ eth_init();
+ lwip_init();
+ init_done = true;
+ }
return 0;
}
@@ -319,5 +341,48 @@ int net_loop(enum proto_t protocol)
u32_t sys_now(void)
{
+#if CONFIG_IS_ENABLED(SANDBOX_TIMER)
+ return timer_early_get_count();
+#else
return get_timer(0);
+#endif
+}
+
+int net_start_again(void)
+{
+ char *nretry;
+ int retry_forever = 0;
+ unsigned long retrycnt = 0;
+
+ nretry = env_get("netretry");
+ if (nretry) {
+ if (!strcmp(nretry, "yes"))
+ retry_forever = 1;
+ else if (!strcmp(nretry, "no"))
+ retrycnt = 0;
+ else if (!strcmp(nretry, "once"))
+ retrycnt = 1;
+ else
+ retrycnt = simple_strtoul(nretry, NULL, 0);
+ } else {
+ retrycnt = 0;
+ retry_forever = 0;
+ }
+
+ if ((!retry_forever) && (net_try_count > retrycnt)) {
+ eth_halt();
+ /*
+ * We don't provide a way for the protocol to return an error,
+ * but this is almost always the reason.
+ */
+ return -ETIMEDOUT;
+ }
+
+ net_try_count++;
+
+ eth_halt();
+#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
+ eth_try_another(!net_restarted);
+#endif
+ return eth_init();
}
diff --git a/net/lwip/ping.c b/net/lwip/ping.c
index c586a96806d..d8042ceecf9 100644
--- a/net/lwip/ping.c
+++ b/net/lwip/ping.c
@@ -168,10 +168,13 @@ int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
if (!ipaddr_aton(argv[1], &addr))
return CMD_RET_USAGE;
- net_lwip_set_current();
-
- if (ping_loop(eth_get_dev(), &addr) < 0)
- return CMD_RET_FAILURE;
+restart:
+ if (net_lwip_eth_start() < 0 || ping_loop(eth_get_dev(), &addr) < 0) {
+ if (net_start_again() == 0)
+ goto restart;
+ else
+ return CMD_RET_FAILURE;
+ }
return CMD_RET_SUCCESS;
}
diff --git a/net/lwip/tftp.c b/net/lwip/tftp.c
index 123d66b5dba..b7eb486ef77 100644
--- a/net/lwip/tftp.c
+++ b/net/lwip/tftp.c
@@ -6,8 +6,10 @@
#include <display_options.h>
#include <dm/device.h>
#include <efi_loader.h>
+#include <env.h>
#include <image.h>
#include <linux/delay.h>
+#include <linux/kconfig.h>
#include <lwip/apps/tftp_client.h>
#include <lwip/timeouts.h>
#include <mapmem.h>
@@ -15,6 +17,8 @@
#include <time.h>
#define PROGRESS_PRINT_STEP_BYTES (10 * 1024)
+/* Max time to wait for first data packet from server */
+#define NO_RSP_TIMEOUT_MS 10000
enum done_state {
NOT_DONE = 0,
@@ -31,6 +35,47 @@ struct tftp_ctx {
enum done_state done;
};
+/**
+ * store_block() - copy received data
+ *
+ * This function is called by the receive callback to copy a block of data
+ * into its final location (ctx->daddr). Before doing so, it checks if the copy
+ * is allowed.
+ *
+ * @ctx: the context for the current transfer
+ * @src: the data received from the TCP stack
+ * @len: the length of the data
+ */
+static int store_block(struct tftp_ctx *ctx, void *src, u16_t len)
+{
+ ulong store_addr = ctx->daddr;
+ void *ptr;
+
+ if (CONFIG_IS_ENABLED(LMB)) {
+ if (store_addr + len < store_addr ||
+ lmb_read_check(store_addr, len)) {
+ puts("\nTFTP error: ");
+ puts("trying to overwrite reserved memory...\n");
+ return -1;
+ }
+ }
+
+ ptr = map_sysmem(store_addr, len);
+ memcpy(ptr, src, len);
+ unmap_sysmem(ptr);
+
+ ctx->daddr += len;
+ ctx->size += len;
+ ctx->block_count++;
+ if (ctx->block_count % 10 == 0) {
+ putc('#');
+ if (ctx->block_count % (65 * 10) == 0)
+ puts("\n\t ");
+ }
+
+ return 0;
+}
+
static void *tftp_open(const char *fname, const char *mode, u8_t is_write)
{
return NULL;
@@ -71,17 +116,9 @@ static int tftp_write(void *handle, struct pbuf *p)
struct tftp_ctx *ctx = handle;
struct pbuf *q;
- for (q = p; q; q = q->next) {
- memcpy((void *)ctx->daddr, q->payload, q->len);
- ctx->daddr += q->len;
- ctx->size += q->len;
- ctx->block_count++;
- if (ctx->block_count % 10 == 0) {
- putc('#');
- if (ctx->block_count % (65 * 10) == 0)
- puts("\n\t ");
- }
- }
+ for (q = p; q; q = q->next)
+ if (store_block(ctx, q->payload, q->len) < 0)
+ return -1;
return 0;
}
@@ -106,6 +143,17 @@ static const struct tftp_context tftp_context = {
tftp_error
};
+static void no_response(void *arg)
+{
+ struct tftp_ctx *ctx = (struct tftp_ctx *)arg;
+
+ if (ctx->size)
+ return;
+
+ printf("Timeout!\n");
+ ctx->done = FAILURE;
+}
+
static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
ip_addr_t srvip, uint16_t srvport)
{
@@ -150,6 +198,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
return -1;
}
+ sys_timeout(NO_RSP_TIMEOUT_MS, no_response, &ctx);
while (!ctx.done) {
net_lwip_rx(udev, netif);
sys_check_timeouts();
@@ -159,6 +208,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
break;
}
}
+ sys_untimeout(no_response, (void *)&ctx);
tftp_cleanup();
@@ -280,7 +330,10 @@ int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
goto out;
}
- net_lwip_set_current();
+ if (net_lwip_eth_start() < 0) {
+ ret = CMD_RET_FAILURE;
+ goto out;
+ }
if (tftp_loop(eth_get_dev(), laddr, fname, srvip, port) < 0)
ret = CMD_RET_FAILURE;
diff --git a/net/lwip/wget.c b/net/lwip/wget.c
index ec098148835..f4fd9718285 100644
--- a/net/lwip/wget.c
+++ b/net/lwip/wget.c
@@ -5,9 +5,12 @@
#include <console.h>
#include <display_options.h>
#include <efi_loader.h>
+#include <env.h>
#include <image.h>
+#include <linux/kconfig.h>
#include <lwip/apps/http_client.h>
#include "lwip/altcp_tls.h"
+#include <lwip/errno.h>
#include <lwip/timeouts.h>
#include <rng.h>
#include <mapmem.h>
@@ -201,11 +204,58 @@ static int parse_legacy_arg(char *arg, char *nurl, size_t rem)
return 0;
}
+/**
+ * store_block() - copy received data
+ *
+ * This function is called by the receive callback to copy a block of data
+ * into its final location (ctx->daddr). Before doing so, it checks if the copy
+ * is allowed.
+ *
+ * @ctx: the context for the current transfer
+ * @src: the data received from the TCP stack
+ * @len: the length of the data
+ */
+static int store_block(struct wget_ctx *ctx, void *src, u16_t len)
+{
+ ulong store_addr = ctx->daddr;
+ uchar *ptr;
+
+ /* Avoid overflow */
+ if (wget_info->buffer_size && wget_info->buffer_size < ctx->size + len)
+ return -1;
+
+ if (CONFIG_IS_ENABLED(LMB) && wget_info->set_bootdev) {
+ if (store_addr + len < store_addr ||
+ lmb_read_check(store_addr, len)) {
+ if (!wget_info->silent) {
+ printf("\nwget error: ");
+ printf("trying to overwrite reserved memory\n");
+ }
+ return -1;
+ }
+ }
+
+ ptr = map_sysmem(store_addr, len);
+ memcpy(ptr, src, len);
+ unmap_sysmem(ptr);
+
+ ctx->daddr += len;
+ ctx->size += len;
+ if (ctx->size - ctx->prevsize > PROGRESS_PRINT_STEP_BYTES) {
+ if (!wget_info->silent)
+ printf("#");
+ ctx->prevsize = ctx->size;
+ }
+
+ return 0;
+}
+
static err_t httpc_recv_cb(void *arg, struct altcp_pcb *pcb, struct pbuf *pbuf,
err_t err)
{
struct wget_ctx *ctx = arg;
struct pbuf *buf;
+ err_t ret;
if (!pbuf)
return ERR_BUF;
@@ -214,18 +264,17 @@ static err_t httpc_recv_cb(void *arg, struct altcp_pcb *pcb, struct pbuf *pbuf,
ctx->start_time = get_timer(0);
for (buf = pbuf; buf; buf = buf->next) {
- memcpy((void *)ctx->daddr, buf->payload, buf->len);
- ctx->daddr += buf->len;
- ctx->size += buf->len;
- if (ctx->size - ctx->prevsize > PROGRESS_PRINT_STEP_BYTES) {
- printf("#");
- ctx->prevsize = ctx->size;
+ if (store_block(ctx, buf->payload, buf->len) < 0) {
+ altcp_abort(pcb);
+ ret = ERR_BUF;
+ goto out;
}
}
-
altcp_recved(pcb, pbuf->tot_len);
+ ret = ERR_OK;
+out:
pbuf_free(pbuf);
- return ERR_OK;
+ return ret;
}
static void httpc_result_cb(void *arg, httpc_result_t httpc_result,
@@ -255,11 +304,15 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result,
elapsed = get_timer(ctx->start_time);
if (!elapsed)
elapsed = 1;
- if (rx_content_len > PROGRESS_PRINT_STEP_BYTES)
- printf("\n");
- 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);
+ if (!wget_info->silent) {
+ if (rx_content_len > PROGRESS_PRINT_STEP_BYTES)
+ printf("\n");
+ 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);
+ }
if (wget_info->set_bootdev)
efi_set_bootdev("Http", ctx->server_name, ctx->path, map_sysmem(ctx->saved_daddr, 0),
rx_content_len);
@@ -339,7 +392,8 @@ static int _set_cacert(const void *addr, size_t sz)
mbedtls_x509_crt_init(&crt);
ret = mbedtls_x509_crt_parse(&crt, cacert, cacert_size);
if (ret) {
- printf("Could not parse certificates (%d)\n", ret);
+ if (!wget_info->silent)
+ printf("Could not parse certificates (%d)\n", ret);
free(cacert);
cacert = NULL;
cacert_size = 0;
@@ -372,13 +426,14 @@ static int set_cacert(char * const saddr, char * const ssz)
#endif
#endif /* CONFIG_WGET_CACERT || CONFIG_WGET_BUILTIN_CACERT */
-static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
+int wget_do_request(ulong dst_addr, char *uri)
{
#if CONFIG_IS_ENABLED(WGET_HTTPS)
altcp_allocator_t tls_allocator;
#endif
httpc_connection_t conn;
httpc_state_t *state;
+ struct udevice *udev;
struct netif *netif;
struct wget_ctx ctx;
char *path;
@@ -394,6 +449,14 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
if (parse_url(uri, ctx.server_name, &ctx.port, &path, &is_https))
return CMD_RET_USAGE;
+ if (net_lwip_eth_start() < 0)
+ return CMD_RET_FAILURE;
+
+ if (!wget_info)
+ wget_info = &default_wget_info;
+
+ udev = eth_get_dev();
+
netif = net_lwip_new_netif(udev);
if (!netif)
return -1;
@@ -413,9 +476,10 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
if (cacert_auth_mode == AUTH_REQUIRED) {
if (!ca || !ca_sz) {
- printf("Error: cacert authentication mode is "
- "'required' but no CA certificates "
- "given\n");
+ if (!wget_info->silent)
+ printf("Error: cacert authentication "
+ "mode is 'required' but no CA "
+ "certificates given\n");
return CMD_RET_FAILURE;
}
} else if (cacert_auth_mode == AUTH_NONE) {
@@ -430,6 +494,10 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
*/
}
+ if (!ca && !wget_info->silent) {
+ printf("WARNING: no CA certificates, ");
+ printf("HTTPS connections not authenticated\n");
+ }
tls_allocator.alloc = &altcp_tls_alloc;
tls_allocator.arg =
altcp_tls_create_config_client(ca, ca_sz,
@@ -454,6 +522,8 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
return CMD_RET_FAILURE;
}
+ errno = 0;
+
while (!ctx.done) {
net_lwip_rx(udev, netif);
sys_check_timeouts();
@@ -466,17 +536,10 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri)
if (ctx.done == SUCCESS)
return 0;
- return -1;
-}
-
-int wget_do_request(ulong dst_addr, char *uri)
-{
- net_lwip_set_current();
-
- if (!wget_info)
- wget_info = &default_wget_info;
+ if (errno == EPERM && !wget_info->silent)
+ printf("Certificate verification failed\n");
- return wget_loop(eth_get_dev(), dst_addr, uri);
+ return -1;
}
int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])