[PATCH] net: lwip: introduce net_lwip_eth_stop() function

David Lechner dlechner at baylibre.com
Sat May 9 19:36:26 CEST 2026


Add a introduce net_lwip_eth_stop() function and use that to stop the
network interface after each command that uses the network.

This makes the behavior the same as the legacy net code and avoids
potential issues with the network interface being left in an active
state after a command finishes.

Signed-off-by: David Lechner <dlechner at baylibre.com>
---
Background:

While testing [1], I found that it would take down my local network if
I left the command prompt open for more than 30 seconds after running
any network command. The network activity light on the board running
U-Boot would go crazy and other network adapters on the network would
start getting watchdog timeouts. So apparently, it is doing something
quite low-level and I don't have any hardware to sniff that (Wireshark
on another computer was no help since all network adapters on the
network stopped working.) So I took a logical approach of looking at
the code to see if I could find anything that would cause this. This
seemed to only happen after I switched from the legacy network
implementation to the lwIP implementation, so I looked for differences
between the two implementations.

After some investigation, I found that the lwIP implementation was
different from the legacy implementation in that it does not call
eth_halt() after a network command. Since the problem happened only
when at the command prompt with no command running, this seemed like a
likely culprit. And indeed, it does seem to fix the issue for me.

For reference, the legacy implementation does something like this
as documented in doc/develop/driver-model/ethernet.rst:

	(some net operation (ping / tftp / whatever...))
	eth_init()
		ops->start()
	eth_send()
		ops->send()
	eth_rx()
		ops->recv()
		(process packet)
		if (ops->free_pkt)
			ops->free_pkt()
	eth_halt()
		ops->stop()

After this patch, the lwIP implementation will do the same thing for
all ethernet commands.

[1]: https://lore.kernel.org/u-boot/20260429-add-ethernet-support-for-genio-520-720-v4-0-be54e17239b7@baylibre.com/
---
 cmd/lwip/ping.c     | 10 ++++++++--
 cmd/lwip/sntp.c     | 10 ++++++++--
 include/net-lwip.h  |  1 +
 net/lwip/dhcp.c     | 15 +++++++++++----
 net/lwip/dns.c      |  6 +++++-
 net/lwip/net-lwip.c |  6 +++++-
 net/lwip/nfs.c      |  4 ++++
 net/lwip/tftp.c     |  4 ++++
 net/lwip/wget.c     | 34 ++++++++++++++++++++++------------
 9 files changed, 68 insertions(+), 22 deletions(-)

diff --git a/cmd/lwip/ping.c b/cmd/lwip/ping.c
index fc4cf7bde5f..836d1d8287f 100644
--- a/cmd/lwip/ping.c
+++ b/cmd/lwip/ping.c
@@ -163,6 +163,7 @@ static int ping_loop(struct udevice *udev, const ip_addr_t *addr)
 int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	ip_addr_t addr;
+	int ret = CMD_RET_FAILURE;
 
 	if (argc < 2)
 		return CMD_RET_USAGE;
@@ -176,8 +177,13 @@ restart:
 		if (net_start_again() == 0)
 			goto restart;
 		else
-			return CMD_RET_FAILURE;
+			goto out;
 	}
 
-	return CMD_RET_SUCCESS;
+	ret = CMD_RET_SUCCESS;
+
+out:
+	net_lwip_eth_stop();
+
+	return ret;
 }
diff --git a/cmd/lwip/sntp.c b/cmd/lwip/sntp.c
index 608345c873b..5fa400b104a 100644
--- a/cmd/lwip/sntp.c
+++ b/cmd/lwip/sntp.c
@@ -101,6 +101,7 @@ int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	ip_addr_t *srvip;
 	char *server;
 	ip_addr_t ipaddr;
+	int ret = CMD_RET_FAILURE;
 
 	switch (argc) {
 	case 1:
@@ -127,7 +128,12 @@ int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 		return CMD_RET_FAILURE;
 
 	if (sntp_loop(eth_get_dev(), srvip) < 0)
-		return CMD_RET_FAILURE;
+		goto out;
+
+	ret = CMD_RET_SUCCESS;
+
+out:
+	net_lwip_eth_stop();
 
-	return CMD_RET_SUCCESS;
+	return ret;
 }
diff --git a/include/net-lwip.h b/include/net-lwip.h
index 20cb0992cce..5d0627eb271 100644
--- a/include/net-lwip.h
+++ b/include/net-lwip.h
@@ -35,6 +35,7 @@ int eth_init_state_only(void); /* Set active state */
 
 int net_lwip_dns_init(void);
 int net_lwip_eth_start(void);
+void net_lwip_eth_stop(void);
 struct netif *net_lwip_new_netif(struct udevice *udev);
 struct netif *net_lwip_new_netif_noip(struct udevice *udev);
 void net_lwip_remove_netif(struct netif *netif);
diff --git a/net/lwip/dhcp.c b/net/lwip/dhcp.c
index acdf601d7eb..18dc36ae7ca 100644
--- a/net/lwip/dhcp.c
+++ b/net/lwip/dhcp.c
@@ -138,18 +138,25 @@ int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	dev = eth_get_dev();
 	if (!dev) {
 		log_err("No network device\n");
-		return CMD_RET_FAILURE;
+		ret = CMD_RET_FAILURE;
+		goto out;
 	}
 
 	ret = dhcp_loop(dev);
 	if (ret)
-		return ret;
+		goto out;
 
 	if (argc > 1) {
 		struct cmd_tbl cmdtp = {};
 
-		return do_tftpb(&cmdtp, 0, argc, argv);
+		ret = do_tftpb(&cmdtp, 0, argc, argv);
+		goto out;
 	}
 
-	return CMD_RET_SUCCESS;
+	ret = CMD_RET_SUCCESS;
+
+out:
+	net_lwip_eth_stop();
+
+	return ret;
 }
diff --git a/net/lwip/dns.c b/net/lwip/dns.c
index 8b7b3b7f970..b92feb1081c 100644
--- a/net/lwip/dns.c
+++ b/net/lwip/dns.c
@@ -91,6 +91,7 @@ int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	char *name;
 	char *var = NULL;
+	int ret;
 
 	if (argc == 1 || argc > 3)
 		return CMD_RET_USAGE;
@@ -103,5 +104,8 @@ int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 	if (net_lwip_eth_start() < 0)
 		return CMD_RET_FAILURE;
 
-	return dns_loop(eth_get_dev(), name, var);
+	ret = dns_loop(eth_get_dev(), name, var);
+	net_lwip_eth_stop();
+
+	return ret;
 }
diff --git a/net/lwip/net-lwip.c b/net/lwip/net-lwip.c
index 0c83c004cab..773113b8c9c 100644
--- a/net/lwip/net-lwip.c
+++ b/net/lwip/net-lwip.c
@@ -181,7 +181,6 @@ int net_lwip_eth_start(void)
 	int ret;
 
 	net_init();
-	eth_halt();
 	eth_set_current();
 	ret = eth_init();
 	if (ret < 0) {
@@ -192,6 +191,11 @@ int net_lwip_eth_start(void)
 	return 0;
 }
 
+void net_lwip_eth_stop(void)
+{
+	eth_halt();
+}
+
 static struct netif *new_netif(struct udevice *udev, bool with_ip)
 {
 	unsigned char enetaddr[ARP_HLEN];
diff --git a/net/lwip/nfs.c b/net/lwip/nfs.c
index 9e6b801e465..4cc36373fdd 100644
--- a/net/lwip/nfs.c
+++ b/net/lwip/nfs.c
@@ -187,6 +187,7 @@ static int nfs_loop(struct udevice *udev, ulong addr, char *fname,
 int do_nfs(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	int ret = CMD_RET_SUCCESS;
+	bool started = false;
 	char *arg = NULL;
 	char *words[2] = { };
 	char *fname = NULL;
@@ -281,10 +282,13 @@ int do_nfs(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 		ret = CMD_RET_FAILURE;
 		goto out;
 	}
+	started = true;
 
 	if (nfs_loop(eth_get_dev(), laddr, fname, srvip) < 0)
 		ret = CMD_RET_FAILURE;
 out:
+	if (started)
+		net_lwip_eth_stop();
 	if (arg != net_boot_file_name)
 		free(arg);
 	return ret;
diff --git a/net/lwip/tftp.c b/net/lwip/tftp.c
index 7f3b28b8507..571c38172f9 100644
--- a/net/lwip/tftp.c
+++ b/net/lwip/tftp.c
@@ -261,6 +261,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
 int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	int ret = CMD_RET_SUCCESS;
+	bool started = false;
 	char *arg = NULL;
 	char *words[3] = { };
 	char *fname = NULL;
@@ -365,12 +366,15 @@ int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 		ret = CMD_RET_FAILURE;
 		goto out;
 	}
+	started = true;
 
 	if (tftp_loop(eth_get_dev(), laddr, fname, srvip, port) < 0)
 		ret = CMD_RET_FAILURE;
 	else
 		image_load_addr = laddr;
 out:
+	if (started)
+		net_lwip_eth_stop();
 	if (arg != net_boot_file_name)
 		free(arg);
 	return ret;
diff --git a/net/lwip/wget.c b/net/lwip/wget.c
index 502c0faebb2..7a0348c87f9 100644
--- a/net/lwip/wget.c
+++ b/net/lwip/wget.c
@@ -302,6 +302,7 @@ int wget_do_request(ulong dst_addr, char *uri)
 	struct udevice *udev;
 	struct netif *netif;
 	struct wget_ctx ctx;
+	int ret = CMD_RET_USAGE;
 	char *path;
 	bool is_https;
 
@@ -327,11 +328,13 @@ int wget_do_request(ulong dst_addr, char *uri)
 
 	netif = net_lwip_new_netif(udev);
 	if (!netif)
-		return -1;
+		goto out_stop;
 
 	/* if URL with hostname init dns */
-	if (!ipaddr_aton(ctx.server_name, NULL) && net_lwip_dns_init())
-		return CMD_RET_FAILURE;
+	if (!ipaddr_aton(ctx.server_name, NULL) && net_lwip_dns_init()) {
+		ret = CMD_RET_FAILURE;
+		goto out_remove_netif;
+	}
 
 	memset(&conn, 0, sizeof(conn));
 #if CONFIG_IS_ENABLED(WGET_HTTPS)
@@ -353,8 +356,9 @@ int wget_do_request(ulong dst_addr, char *uri)
 					printf("Error: cacert authentication "
 					       "mode is 'required' but no CA "
 					       "certificates given\n");
-				return CMD_RET_FAILURE;
-		       }
+				ret = CMD_RET_FAILURE;
+				goto out_remove_netif;
+			}
 		} else if (cacert_auth_mode == AUTH_NONE) {
 			ca = NULL;
 			ca_sz = 0;
@@ -378,8 +382,7 @@ int wget_do_request(ulong dst_addr, char *uri)
 
 		if (!tls_allocator.arg) {
 			log_err("error: Cannot create a TLS connection\n");
-			net_lwip_remove_netif(netif);
-			return -1;
+			goto out_remove_netif;
 		}
 
 		conn.altcp_allocator = &tls_allocator;
@@ -391,8 +394,8 @@ int wget_do_request(ulong dst_addr, char *uri)
 	ctx.path = path;
 	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;
+		ret = CMD_RET_FAILURE;
+		goto out_remove_netif;
 	}
 
 	errno = 0;
@@ -405,13 +408,20 @@ int wget_do_request(ulong dst_addr, char *uri)
 
 	net_lwip_remove_netif(netif);
 
-	if (ctx.done == SUCCESS)
-		return 0;
+	if (ctx.done == SUCCESS) {
+		ret = 0;
+		goto out_stop;
+	}
 
 	if (errno == EPERM && !wget_info->silent)
 		printf("Certificate verification failed\n");
 
-	return -1;
+out_remove_netif:
+	net_lwip_remove_netif(netif);
+out_stop:
+	net_lwip_eth_stop();
+
+	return ret;
 }
 
 /**

---
base-commit: 22a285380e35a31d0a882af66278bc1edc1b917e
change-id: 20260509-net-lwip-add-stop-function-7f7794074844

Best regards,
--  
David Lechner <dlechner at baylibre.com>



More information about the U-Boot mailing list