public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCHv2 1/3] net/lwip: add lwip-external submodule
@ 2023-06-29 12:34 Maxim Uvarov
  2023-06-29 12:34 ` [PATCHv2 2/3] net/lwip: add README.lwip Maxim Uvarov
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Maxim Uvarov @ 2023-06-29 12:34 UTC (permalink / raw)
  To: u-boot
  Cc: pbrobinson, ilias.apalodimas, joe.hershberger, rfried.dev, trini,
	goldsimon, lwip-devel, Maxim Uvarov

This commit adds the lwip library as a git submodule. I think
there has to be advantages to compile lwip inside U-boot,
i.e. use the same compiler and flags as the main code.
One of them is LTO and the other is to enable additional debug
options for network protocol during development. Also we can
copy lwip library code inside U-boot, but for now I don't want
to send all lwip code to the mailing list. So it's git submodule.

Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
---
 .gitmodules            | 3 +++
 lib/lwip/lwip-external | 1 +
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 lib/lwip/lwip-external

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..afc709af10
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lib/lwip/lwip-external"]
+	path = lib/lwip/lwip-external
+	url = https://git.savannah.nongnu.org/git/lwip.git
diff --git a/lib/lwip/lwip-external b/lib/lwip/lwip-external
new file mode 160000
index 0000000000..3fe8d2fc43
--- /dev/null
+++ b/lib/lwip/lwip-external
@@ -0,0 +1 @@
+Subproject commit 3fe8d2fc43a9b69f7ed28c63d44a7744f9c0def9
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCHv2 2/3] net/lwip: add README.lwip
  2023-06-29 12:34 [PATCHv2 1/3] net/lwip: add lwip-external submodule Maxim Uvarov
@ 2023-06-29 12:34 ` Maxim Uvarov
  2023-06-30 10:01   ` Ilias Apalodimas
  2023-06-29 12:34 ` [PATCHv2 3/3] net/lwip: add lwip library for the network stack Maxim Uvarov
  2023-06-29 19:10 ` [PATCHv2 1/3] net/lwip: add lwip-external submodule Simon Glass
  2 siblings, 1 reply; 11+ messages in thread
From: Maxim Uvarov @ 2023-06-29 12:34 UTC (permalink / raw)
  To: u-boot
  Cc: pbrobinson, ilias.apalodimas, joe.hershberger, rfried.dev, trini,
	goldsimon, lwip-devel, Maxim Uvarov

Just add inital README.lwip doc.

Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
---
 doc/README.lwip | 90 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 doc/README.lwip

diff --git a/doc/README.lwip b/doc/README.lwip
new file mode 100644
index 0000000000..16f41049ab
--- /dev/null
+++ b/doc/README.lwip
@@ -0,0 +1,90 @@
+	RFC LWIP IP stack intergation for U-boot
+        ----------------------------------------
+
+Reliable and bug free IP stack is usually an issue when you are trying to write it
+from scratch. It looks like not, but when addinging new features it will be chelledging.
+This RFC work is a demo to enable lwIP (lightweight IP) which is a widely used open-source
+TCP/IP stack designed for embedded systems for U-boot. That will allow using already
+written network applications for microcontrollers.
+
+LwIP  license:
+lwIP is licensed under a BSD-style license: http://lwip.wikia.com/wiki/License.
+
+Main features include:
+- Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE
+- DHCP client, DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), SNMP agent (v1, v2c, v3, private MIB support & MIB compiler)
+- APIs: specialized APIs for enhanced performance, optional Berkeley-alike socket API
+- Extended features: IP forwarding over multiple network interfaces, TCP congestion control, RTT estimation and fast recovery/fast retransmit
+- Addon applications: HTTP(S) server, SNTP client, SMTP(S) client, ping, NetBIOS nameserver, mDNS responder, MQTT client, TFTP server
+
+U-boot implementation details:
+
+1. In general we can build lwIP as .a library and link it against u-boot or compile it in
+the U-boot tree in the same way as other U-boot files. There are few reasons why I selected
+the second variant: iwIP is very customizable with defines for features, memory size, types of
+allocation, some internal types and platform specific code. And it was more easy to enable/disable
+ debug which is also done with defines, and is needed periodically.
+
+2. lwIP has 2 APIs - raw mode and sequential (as lwIP names it, or socket API as we name it in Linux).
+  This RFC implements only raw API as the proof of work.
+
+Raw IP means that the call back function for RX path is registered and will be called when packet
+data passes the IP stack and is ready for the application.
+
+This RFC has an unmodified working ping example from lwip sources which registeres this callback.
+  ping_pcb = raw_new(IP_PROTO_ICMP);
+  raw_recv(ping_pcb, ping_recv, NULL); <- ping_recv is app callback.
+  raw_bind(ping_pcb, IP_ADDR_ANY)
+
+Socket API also gives nice advantages due it will be easy to port linux socket applications to u-boot.
+I.e. lwIP sockets compatible with the linux ones. But that will require RX thread running in the background.
+So that means we need some kind of scheduler, locking and threading support or find some other solution.
+
+3.  Input and output
+
+RX packet path is injected to U-boot eth_rx() polling loop and TX patch is in eth_send() accordingly.
+So we do not touch any drivers code and just eat packets when they are ready.
+
+4. Testing
+
+Unmodified ping example can be used. I did ping from qemu/u-boot tap device on the host:
+
+=> lwip init
+=> lwip ping 192.168.1.2
+ping: recv 3 ms
+tcpdump on the host:
+5:09:10.925951 ARP, Request who-has 192.168.1.200 tell 192.168.1.200, length 28 15:09:12.114643 IP6 fe80::38e2:41ff:fec3:8bda > ip6-allrouters: ICMP6, router solicitation, length 16 15:09:20.370725 ARP, Request who-has 192.168.1.2 tell 192.168.1.200, length 28 15:09:20.370740 ARP, Reply 192.168.1.2 is-at 3a:e2:41:c3:8b:da (oui Unknown), length 28 15:09:20.372789 IP 192.168.1.200 > 192.168.1.2: ICMP echo request, id 44975, seq 1, length 40 15:09:20.372810 IP 192.168.1.2 > 192.168.1.200: ICMP echo reply, id 44975, seq 1, length 40 15:09:25.426636 ARP, Request who-has 192.168.1.200 tell 192.168.1.2, length 28 15:09:25.426870 ARP, Reply 192.168.1.200 is-at f6:11:01:02:03:04 (oui Unknown), length 28
+
+
+5. Wget example
+
+Http server has 192.168.1.2 IP address. (I did not port DNS resolving yet,
+but it's also exist in lwip.) So example just downloads some file with http
+protocol:
+
+Net:   eth0: virtio-net#30
+Hit any key to stop autoboot:  0 
+=> lwip init
+Starting lwIP, local interface IP is 192.168.1.200
+Initialized LWIP stack
+=> lwip wget http://192.168.1.2/
+downloading http://192.168.1.2/ to addr 0x40200000
+downloaded chunk size 294, to addr 0x40200000
+downloaded chunk size 318, to addr 0x40200126
+=> md 0x40200000 0x40
+40200000: 4f44213c 50595443 74682045 0a3e6c6d  <!DOCTYPE html>.
+40200010: 6d74683c 3c0a3e6c 64616568 743c0a3e  <html>.<head>.<t
+40200020: 656c7469 6c65573e 656d6f63 206f7420  itle>Welcome to 
+40200030: 6e69676e 2f3c2178 6c746974 3c0a3e65  nginx!</title>.<
+40200040: 6c797473 200a3e65 62202020 2079646f  style>.    body 
+40200050: 20200a7b 20202020 69772020 3a687464  {.        width:
+40200060: 65353320 200a3b6d 20202020 6d202020   35em;.        m
+40200070: 69677261 30203a6e 74756120 200a3b6f  argin: 0 auto;. 
+40200080: 20202020 66202020 2d746e6f 696d6166         font-fami
+40200090: 203a796c 6f686154 202c616d 64726556  ly: Tahoma, Verd
+402000a0: 2c616e61 69724120 202c6c61 736e6173  ana, Arial, sans
+402000b0: 7265732d 0a3b6669 20202020 2f3c0a7d  -serif;.    }.</
+402000c0: 6c797473 3c0a3e65 6165682f 3c0a3e64  style>.</head>.<
+402000d0: 79646f62 683c0a3e 65573e31 6d6f636c  body>.<h1>Welcom
+402000e0: 6f742065 69676e20 3c21786e 3e31682f  e to nginx!</h1>
+402000f0: 3e703c0a 79206649 7320756f 74206565  .<p>If you see t
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCHv2 3/3] net/lwip: add lwip library for the network stack
  2023-06-29 12:34 [PATCHv2 1/3] net/lwip: add lwip-external submodule Maxim Uvarov
  2023-06-29 12:34 ` [PATCHv2 2/3] net/lwip: add README.lwip Maxim Uvarov
@ 2023-06-29 12:34 ` Maxim Uvarov
  2023-06-30 10:03   ` Ilias Apalodimas
  2023-06-30 16:38   ` Tom Rini
  2023-06-29 19:10 ` [PATCHv2 1/3] net/lwip: add lwip-external submodule Simon Glass
  2 siblings, 2 replies; 11+ messages in thread
From: Maxim Uvarov @ 2023-06-29 12:34 UTC (permalink / raw)
  To: u-boot
  Cc: pbrobinson, ilias.apalodimas, joe.hershberger, rfried.dev, trini,
	goldsimon, lwip-devel, Maxim Uvarov

This commit adds lwip library for the U-boot network
stack. Supported commands: ping, tftp, dhcp and wget.

Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
---
 .gitignore                            |   9 +
 cmd/net.c                             |  38 +++-
 include/net.h                         |   2 +-
 lib/Kconfig                           |   2 +
 lib/Makefile                          |   2 +
 lib/lwip/Kconfig                      | 108 ++++++++++
 lib/lwip/Makefile                     |  98 +++++++++
 lib/lwip/apps/dhcp/lwip-dhcp.c        |  52 +++++
 lib/lwip/apps/http/lwip-wget.c        |  71 +++++++
 lib/lwip/apps/ping/lwip_ping.c        |  37 ++++
 lib/lwip/apps/ping/lwip_ping.h        |  24 +++
 lib/lwip/apps/ping/ping.h             |  35 ++++
 lib/lwip/apps/tftp/lwip-tftp.c        | 121 +++++++++++
 lib/lwip/cmd-lwip.c                   | 276 ++++++++++++++++++++++++++
 lib/lwip/lwipopts.h                   | 203 +++++++++++++++++++
 lib/lwip/port/if.c                    | 260 ++++++++++++++++++++++++
 lib/lwip/port/include/arch/cc.h       |  46 +++++
 lib/lwip/port/include/arch/sys_arch.h |  59 ++++++
 lib/lwip/port/include/limits.h        |   0
 lib/lwip/port/sys-arch.c              |  20 ++
 lib/lwip/ulwip.h                      |   9 +
 net/eth-uclass.c                      |   4 +-
 net/net.c                             |  25 +++
 23 files changed, 1496 insertions(+), 5 deletions(-)
 create mode 100644 lib/lwip/Kconfig
 create mode 100644 lib/lwip/Makefile
 create mode 100644 lib/lwip/apps/dhcp/lwip-dhcp.c
 create mode 100644 lib/lwip/apps/http/lwip-wget.c
 create mode 100644 lib/lwip/apps/ping/lwip_ping.c
 create mode 100644 lib/lwip/apps/ping/lwip_ping.h
 create mode 100644 lib/lwip/apps/ping/ping.h
 create mode 100644 lib/lwip/apps/tftp/lwip-tftp.c
 create mode 100644 lib/lwip/cmd-lwip.c
 create mode 100644 lib/lwip/lwipopts.h
 create mode 100644 lib/lwip/port/if.c
 create mode 100644 lib/lwip/port/include/arch/cc.h
 create mode 100644 lib/lwip/port/include/arch/sys_arch.h
 create mode 100644 lib/lwip/port/include/limits.h
 create mode 100644 lib/lwip/port/sys-arch.c
 create mode 100644 lib/lwip/ulwip.h

diff --git a/.gitignore b/.gitignore
index eb769f144c..be3676c59e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -104,3 +104,12 @@ __pycache__
 # pylint files
 /pylint.cur
 /pylint.out/
+
+lib/lwip/lwip-external
+lib/lwip/apps/ping/ping.c
+lib/lwip/apps/http/http_client.c
+lib/lwip/apps/http/http_client.h
+lib/lwip/apps/tftp/tftp.c
+lib/lwip/apps/tftp/tftp_client.h
+lib/lwip/apps/tftp/tftp_common.h
+lib/lwip/apps/tftp/tftp_example.h
diff --git a/cmd/net.c b/cmd/net.c
index 0e9f200ca9..5b3dfd6c7e 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -36,6 +36,10 @@ U_BOOT_CMD(
 #endif
 
 #ifdef CONFIG_CMD_TFTPBOOT
+#if defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
+int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[]);
+#endif
 int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
 	int ret;
@@ -56,7 +60,12 @@ U_BOOT_CMD(
 );
 #else
 U_BOOT_CMD(
-	tftpboot,	3,	1,	do_tftpb,
+	tftpboot,	3,	1,
+#if defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
+	do_lwip_tftp,
+#else
+	do_tftpb,
+#endif
 	"load file via network using TFTP protocol",
 	"[loadAddress] [[hostIPaddr:]bootfilename]"
 );
@@ -112,7 +121,11 @@ U_BOOT_CMD(
 static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
 		   char *const argv[])
 {
+#if defined(CONFIG_CMD_LWIP_REPLACE_DHCP)
+	return do_lwip_dhcp();
+#else
 	return netboot_common(DHCP, cmdtp, argc, argv);
+#endif
 }
 
 U_BOOT_CMD(
@@ -137,13 +150,22 @@ U_BOOT_CMD(
 #endif
 
 #if defined(CONFIG_CMD_WGET)
+#if defined(CONFIG_CMD_LWIP_REPLACE_WGET)
+int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[])
+#endif
 static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
 {
 	return netboot_common(WGET, cmdtp, argc, argv);
 }
 
 U_BOOT_CMD(
-	wget,   3,      1,      do_wget,
+	wget,   3,      1,
+#if defined(CONFIG_CMD_LWIP_REPLACE_WGET)
+	do_lwip_wget,
+#else
+	do_wget,
+#endif
 	"boot image via network using HTTP protocol",
 	"[loadAddress] [[hostIPaddr:]path and image name]"
 );
@@ -376,6 +398,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
 }
 
 #if defined(CONFIG_CMD_PING)
+#if defined(CONFIG_CMD_LWIP_REPLACE_PING)
+extern int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[]);
+#else
 static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
 		   char *const argv[])
 {
@@ -395,9 +421,15 @@ static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
 
 	return CMD_RET_SUCCESS;
 }
+#endif
 
 U_BOOT_CMD(
-	ping,	2,	1,	do_ping,
+	ping,	2,	1,
+#if defined(CONFIG_CMD_LWIP_REPLACE_PING)
+	do_lwip_ping,
+#else
+	do_ping,
+#endif
 	"send ICMP ECHO_REQUEST to network host",
 	"pingAddress"
 );
diff --git a/include/net.h b/include/net.h
index 1a99009959..8622983597 100644
--- a/include/net.h
+++ b/include/net.h
@@ -561,7 +561,7 @@ extern int		net_restart_wrap;	/* Tried all network devices */
 
 enum proto_t {
 	BOOTP, RARP, ARP, TFTPGET, DHCP, PING, PING6, DNS, NFS, CDP, NETCONS,
-	SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, WGET
+	SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, WGET, LWIP
 };
 
 extern char	net_boot_file_name[1024];/* Boot File name */
diff --git a/lib/Kconfig b/lib/Kconfig
index 3c5a4ab386..7485a1f3bf 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -1031,3 +1031,5 @@ menu "FWU Multi Bank Updates"
 source lib/fwu_updates/Kconfig
 
 endmenu
+
+source lib/lwip/Kconfig
diff --git a/lib/Makefile b/lib/Makefile
index d77b33e7f4..3b80a41187 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -91,6 +91,8 @@ obj-$(CONFIG_LIBAVB) += libavb/
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/
 obj-$(CONFIG_$(SPL_TPL_)OF_REAL) += fdtdec_common.o fdtdec.o
 
+obj-y += lwip/
+
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16-ccitt.o
 obj-$(CONFIG_$(SPL_TPL_)HASH) += crc16-ccitt.o
diff --git a/lib/lwip/Kconfig b/lib/lwip/Kconfig
new file mode 100644
index 0000000000..80d540ba54
--- /dev/null
+++ b/lib/lwip/Kconfig
@@ -0,0 +1,108 @@
+menu "LWIP"
+config LWIP_LIB
+	bool "Support LWIP library"
+	help
+	  Selecting this option will enable the shared LWIP library code.
+
+menu "LWIP options"
+config LWIP_LIB_DEBUG
+	bool "enable debug"
+	default n
+config LWIP_LIB_NOASSERT
+	bool "disable asserts"
+	default y
+	help
+	    Disabling asserts reduces binary size on 16k.
+config LWIP_LIB_TCP
+        bool "tcp"
+        default y
+config LWIP_LIB_UDP
+        bool "udp"
+        default y
+config LWIP_LIB_DNS
+        bool "dns"
+        default n
+config LWIP_LIB_DHCP
+        bool "dhcp"
+        default y
+
+config LWIP_LIB_LOOPBACK
+        bool "loopback"
+        default n
+        help
+	   Increases size on 1k.
+config LWIP_LIB_SOCKET
+        bool "socket API"
+        default n
+config LWIP_LIB_NETCONN
+        bool "netconn API"
+        default n
+config LWIP_LIB_MEM_SIZE
+	int "mem size"
+	default 1600
+	range 1 4096
+	help
+	    MEM_SIZE: the size of the heap memory. If the application will send
+	    a lot of data that needs to be copied, this should be set high.
+
+config LWIP_LIB_PBUF_LINK_HLEN
+        int "pbuf link hlen"
+        default 14
+        range 4 1024
+        help
+	   PBUF_LINK_HLEN: the number of bytes that should be allocated for a
+           link level header. The default is 14, the standard value for Ethernet.
+endmenu
+
+config CMD_LWIP
+        bool "lwip cmd"
+        default y
+	depends on LWIP_LIB
+        help
+          lwip networking command.
+
+config CMD_LWIP_PING
+        bool "ping"
+        default y
+	depends on CMD_LWIP
+        help
+          lwip ping command.
+
+config CMD_LWIP_REPLACE_PING
+        bool "replace original ping command"
+        default n
+
+config CMD_LWIP_WGET
+        bool "wget"
+        default y
+	depends on CMD_LWIP
+        help
+          lwip wget command.
+
+config CMD_LWIP_REPLACE_WGET
+	bool "replace original wget command"
+	default n
+
+config CMD_LWIP_TFTP
+        bool "tftp"
+        default y
+	depends on CMD_LWIP
+        help
+          lwip tftp command.
+
+config CMD_LWIP_REPLACE_TFTP
+	bool "replace original tftp command"
+	default n
+
+config CMD_LWIP_DHCP
+        bool "dhcp"
+        default y
+	depends on CMD_LWIP
+	depends on LWIP_LIB_DHCP
+        help
+          lwip dhcp command.
+
+config CMD_LWIP_REPLACE_DHCP
+	bool "replace original dhcp command"
+	default n
+endmenu
diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile
new file mode 100644
index 0000000000..6f68eb04ed
--- /dev/null
+++ b/lib/lwip/Makefile
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+
+LWIPDIR=lwip-external/src
+
+ccflags-y += -I$(CURDIR)/lib/lwip/port/include
+ccflags-y += -I$(CURDIR)/lib/lwip/lwip-external/src/include -I$(CURDIR)/lib/lwip
+
+obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/init.o \
+	$(LWIPDIR)/core/def.o \
+	$(LWIPDIR)/core/dns.o \
+	$(LWIPDIR)/core/inet_chksum.o \
+	$(LWIPDIR)/core/ip.o \
+	$(LWIPDIR)/core/mem.o \
+	$(LWIPDIR)/core/memp.o \
+	$(LWIPDIR)/core/netif.o \
+	$(LWIPDIR)/core/pbuf.o \
+	$(LWIPDIR)/core/raw.o \
+	$(LWIPDIR)/core/stats.o \
+	$(LWIPDIR)/core/sys.o \
+	$(LWIPDIR)/core/altcp.o \
+	$(LWIPDIR)/core/altcp_alloc.o \
+	$(LWIPDIR)/core/altcp_tcp.o \
+	$(LWIPDIR)/core/tcp.o \
+	$(LWIPDIR)/core/tcp_in.o \
+	$(LWIPDIR)/core/tcp_out.o \
+	$(LWIPDIR)/core/timeouts.o \
+	$(LWIPDIR)/core/udp.o
+
+# IPv4
+obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/ipv4/acd.o \
+        $(LWIPDIR)/core/ipv4/autoip.o \
+        $(LWIPDIR)/core/ipv4/dhcp.o \
+        $(LWIPDIR)/core/ipv4/etharp.o \
+        $(LWIPDIR)/core/ipv4/icmp.o \
+        $(LWIPDIR)/core/ipv4/igmp.o \
+        $(LWIPDIR)/core/ipv4/ip4_frag.o \
+        $(LWIPDIR)/core/ipv4/ip4.o \
+        $(LWIPDIR)/core/ipv4/ip4_addr.o
+# IPv6
+obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/ipv6/dhcp6.o \
+        $(LWIPDIR)/core/ipv6/ethip6.o \
+        $(LWIPDIR)/core/ipv6/icmp6.o \
+        $(LWIPDIR)/core/ipv6/inet6.o \
+        $(LWIPDIR)/core/ipv6/ip6.o \
+        $(LWIPDIR)/core/ipv6/ip6_addr.o \
+        $(LWIPDIR)/core/ipv6/ip6_frag.o \
+        $(LWIPDIR)/core/ipv6/mld6.o \
+        $(LWIPDIR)/core/ipv6/nd6.o
+# API
+obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/api/api_lib.o \
+	$(LWIPDIR)/api/api_msg.o \
+	$(LWIPDIR)/api/err.o \
+	$(LWIPDIR)/api/if_api.o \
+	$(LWIPDIR)/api/netbuf.o \
+	$(LWIPDIR)/api/netdb.o \
+	$(LWIPDIR)/api/netifapi.o \
+	$(LWIPDIR)/api/sockets.o \
+	$(LWIPDIR)/api/tcpip.o
+
+# Netdevs
+obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/netif/ethernet.o
+
+obj-$(CONFIG_LWIP_LIB) += port/if.o
+obj-$(CONFIG_LWIP_LIB) += port/sys-arch.o
+
+obj-$(CONFIG_CMD_LWIP) += cmd-lwip.o
+
+.PHONY: $(obj)/apps/ping/ping.c
+$(obj)/apps/ping/ping.o: $(obj)/apps/ping/ping.c
+$(obj)/apps/ping/ping.c:
+	cp ./lib/lwip/lwip-external/contrib/apps/ping/ping.c $(obj)/apps/ping/ping.c
+
+obj-$(CONFIG_CMD_LWIP) += apps/ping/ping.o
+obj-$(CONFIG_CMD_LWIP) += apps/ping/lwip_ping.o
+
+$(obj)/apps/http/http_clinet.o: $(obj)/apps/http/http_client.c
+.PHONY: $(obj)/apps/http/http_client.c
+$(obj)/apps/http/http_client.c:
+	cp ./lib/lwip/lwip-external/src/apps/http/http_client.c $(obj)/apps/http/http_client.c
+	cp ./lib/lwip/lwip-external/src/include/lwip/apps/http_client.h $(obj)/apps/http/http_client.h
+
+obj-$(CONFIG_CMD_LWIP_WGET) += apps/http/http_client.o
+obj-$(CONFIG_CMD_LWIP_WGET) += apps/http/lwip-wget.o
+
+$(obj)/apps/tftp/tftp.o: $(obj)/apps/tftp/tftp.c
+.PHONY: $(obj)/apps/tftp/tftp.c
+$(obj)/apps/tftp/tftp.c:
+	cp ./lib/lwip/lwip-external/src/apps/tftp/tftp.c $(obj)/apps/tftp/tftp.c
+	cp ./lib/lwip/lwip-external/src/include/lwip/apps/tftp_client.h $(obj)/apps/tftp/tftp_client.h
+	cp ./lib/lwip/lwip-external/src/include/lwip/apps/tftp_common.h $(obj)/apps/tftp/tftp_common.h
+	cp ./lib/lwip/lwip-external/contrib/examples/tftp/tftp_example.h $(obj)/apps/tftp/tftp_example.h
+
+obj-$(CONFIG_CMD_LWIP_TFTP) += apps/tftp/tftp.o
+obj-$(CONFIG_CMD_LWIP_TFTP) += apps/tftp/lwip-tftp.o
+
+obj-$(CONFIG_CMD_LWIP_DHCP) += apps/dhcp/lwip-dhcp.o
diff --git a/lib/lwip/apps/dhcp/lwip-dhcp.c b/lib/lwip/apps/dhcp/lwip-dhcp.c
new file mode 100644
index 0000000000..2e4812c7dd
--- /dev/null
+++ b/lib/lwip/apps/dhcp/lwip-dhcp.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <console.h>
+
+#include <lwip/dhcp.h>
+#include <lwip/prot/dhcp.h>
+
+#include "../../../lwip/ulwip.h"
+
+static struct dhcp dhcp;
+static bool dhcp_is_set;
+extern struct netif uboot_netif;
+
+static int ulwip_dhcp_tmo(void)
+{
+	switch (dhcp.state) {
+	case DHCP_STATE_BOUND:
+		env_set("bootfile", dhcp.boot_file_name);
+		env_set("ipaddr", ip4addr_ntoa(&dhcp.offered_ip_addr));
+		env_set("netmask", ip4addr_ntoa(&dhcp.offered_sn_mask));
+		env_set("serverip", ip4addr_ntoa(&dhcp.server_ip_addr));
+		printf("DHCP client bound to address %s\n", ip4addr_ntoa(&dhcp.offered_ip_addr));
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+int ulwip_dhcp(void)
+{
+	int err;
+
+	ulwip_set_tmo(ulwip_dhcp_tmo);
+
+	if (!dhcp_is_set) {
+		dhcp_set_struct(&uboot_netif, &dhcp);
+		dhcp_is_set = true;
+	}
+	err = dhcp_start(&uboot_netif);
+	if (err)
+		printf("dhcp_start error %d\n", err);
+
+	return err;
+}
diff --git a/lib/lwip/apps/http/lwip-wget.c b/lib/lwip/apps/http/lwip-wget.c
new file mode 100644
index 0000000000..07aabd15f3
--- /dev/null
+++ b/lib/lwip/apps/http/lwip-wget.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <console.h>
+
+#include "http_client.h"
+#include "../../../lwip/ulwip.h"
+
+static ulong daddr;
+static httpc_connection_t settings;
+
+static err_t httpc_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
+{
+	struct pbuf *q;
+	LWIP_UNUSED_ARG(err);
+
+	if (!p)
+		return ERR_BUF;
+
+	for (q = p; q != NULL; q = q->next) {
+		memcpy((void *)daddr, q->payload, q->len);
+		printf("downloaded chunk size %d, to addr 0x%lx\n", q->len, daddr);
+		daddr += q->len;
+	}
+	altcp_recved(pcb, p->tot_len);
+	pbuf_free(p);
+	return ERR_OK;
+}
+
+static void httpc_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len,
+			 u32_t srv_res, err_t err)
+{
+	if (httpc_result == HTTPC_RESULT_OK) {
+		printf("\n%d bytes successfully downloaded.\n", rx_content_len);
+		ulwip_exit(0);
+	} else {
+		printf("\nhttp eroror: %d\n", httpc_result);
+		ulwip_exit(-1);
+	}
+}
+
+int lwip_wget(ulong addr, char *url)
+{
+	err_t err;
+	int port = 80;
+	char *server_name;
+	httpc_state_t *connection;
+
+	daddr = addr;
+	server_name = env_get("serverip");
+	if (!server_name) {
+		printf("error: serverip variable has to be set\n");
+		return CMD_RET_FAILURE;
+	}
+
+	printf("downloading %s to addr 0x%lx\n", url, addr);
+	memset(&settings, 0, sizeof(httpc_connection_t));
+	settings.result_fn = httpc_result;
+	err = httpc_get_file_dns(server_name, port, url, &settings,
+				 httpc_recv, NULL,  &connection);
+	if (err != ERR_OK) {
+		printf("httpc_init_connection failed\n");
+		return err;
+	}
+	return 0;
+}
diff --git a/lib/lwip/apps/ping/lwip_ping.c b/lib/lwip/apps/ping/lwip_ping.c
new file mode 100644
index 0000000000..a05dc76326
--- /dev/null
+++ b/lib/lwip/apps/ping/lwip_ping.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#include "lwip/opt.h"
+#include "lwip/ip_addr.h"
+#include "ping.h"
+
+#include "../../../lwip/ulwip.h"
+
+static ip_addr_t ip_target;
+
+static int ulwip_ping_tmo(void)
+{
+
+	printf("ping failed; host %s is not alive\n", ipaddr_ntoa(&ip_target));
+	return 0;
+}
+
+int lwip_ping_init(char *ping_addr)
+{
+	int err;
+
+	err = ipaddr_aton(ping_addr, &ip_target);
+	if (err == 0) {
+		printf("wrong ping addr string \"%s\" \n", ping_addr);
+		return -1;
+	}
+
+	ulwip_set_tmo(ulwip_ping_tmo);
+
+	ping_init(&ip_target);
+
+	return 0;
+}
diff --git a/lib/lwip/apps/ping/lwip_ping.h b/lib/lwip/apps/ping/lwip_ping.h
new file mode 100644
index 0000000000..7f08095427
--- /dev/null
+++ b/lib/lwip/apps/ping/lwip_ping.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#ifndef LWIP_PING_H
+#define LWIP_PING_H
+
+#include <lwip/ip_addr.h>
+
+/**
+ * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used
+ */
+#ifndef PING_USE_SOCKETS
+#define PING_USE_SOCKETS   0
+#endif
+
+int lwip_ping_init(char *ping_addr);
+
+void ping_raw_init(void);
+void ping_send_now(void);
+
+#endif /* LWIP_PING_H */
diff --git a/lib/lwip/apps/ping/ping.h b/lib/lwip/apps/ping/ping.h
new file mode 100644
index 0000000000..0dd4bd78c7
--- /dev/null
+++ b/lib/lwip/apps/ping/ping.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include "../../../lwip/ulwip.h"
+
+#include "lwip/prot/ip4.h"
+
+#define ip4_print_parts(a, b, c, d) \
+	printf("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, a, b, c, d);
+
+#define ip4_print(ipaddr) \
+	ip4_print_parts(\
+			(u16_t)((ipaddr) != NULL ? ip4_addr1_16(ipaddr) : 0), \
+			(u16_t)((ipaddr) != NULL ? ip4_addr2_16(ipaddr) : 0), \
+			(u16_t)((ipaddr) != NULL ? ip4_addr3_16(ipaddr) : 0), \
+			(u16_t)((ipaddr) != NULL ? ip4_addr4_16(ipaddr) : 0))
+
+
+#define LWIP_DEBUG 1 /* ping_time is under ifdef*/
+#define PING_RESULT(cond) { \
+	if (cond == 1) { \
+		printf("host "); \
+		ip4_print(addr); \
+		printf(" is alive\n"); \
+		printf(" %"U32_F" ms\n", (sys_now() - ping_time)); \
+		ulwip_exit(0); \
+	} else { \
+		printf("ping failed; host "); \
+		ip4_print(addr); \
+		printf(" is not alive\n"); \
+		ulwip_exit(-1); \
+	} \
+     } while (0);
+
+#include "lwip/ip_addr.h"
+void ping_init(const ip_addr_t *ping_addr);
diff --git a/lib/lwip/apps/tftp/lwip-tftp.c b/lib/lwip/apps/tftp/lwip-tftp.c
new file mode 100644
index 0000000000..c38e83c8ee
--- /dev/null
+++ b/lib/lwip/apps/tftp/lwip-tftp.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <console.h>
+
+#include "lwip/apps/tftp_client.h"
+#include "lwip/apps/tftp_server.h"
+#include "tftp_example.h"
+
+#include <string.h>
+
+#include "../../../lwip/ulwip.h"
+
+#if LWIP_UDP
+
+static ulong daddr;
+static ulong size;
+
+static void *tftp_open(const char *fname, const char *mode, u8_t is_write)
+{
+	LWIP_UNUSED_ARG(mode);
+	return NULL;
+}
+
+static void tftp_close(void *handle)
+{
+	printf("\ndone\n");
+	printf("Bytes transferred = %ld (0x%lx hex)\n", size, size);
+	ulwip_exit(0);
+}
+
+static int tftp_read(void *handle, void *buf, int bytes)
+{
+	return 0;
+}
+
+static int tftp_write(void *handle, struct pbuf *p)
+{
+	struct pbuf *q;
+
+	for (q = p; q != NULL; q = q->next) {
+		memcpy((void *)daddr, q->payload, q->len);
+		/* printf("downloaded chunk size %d, to addr 0x%lx\n", q->len, daddr); */
+		daddr += q->len;
+		size += q->len;
+		printf("#");
+	}
+
+	return 0;
+}
+
+/* For TFTP client only */
+static void tftp_error(void *handle, int err, const char *msg, int size)
+{
+	char message[100];
+
+	LWIP_UNUSED_ARG(handle);
+
+	memset(message, 0, sizeof(message));
+	MEMCPY(message, msg, LWIP_MIN(sizeof(message)-1, (size_t)size));
+
+	printf("TFTP error: %d (%s)", err, message);
+}
+
+static const struct tftp_context tftp = {
+	tftp_open,
+	tftp_close,
+	tftp_read,
+	tftp_write,
+	tftp_error
+};
+
+int lwip_tftp(ulong addr, char *fname)
+{
+	void *f = (void *)0x1; /*fake handle*/
+	err_t err;
+	ip_addr_t srv;
+	int ret;
+	char *server_ip;
+
+	if (!fname || addr == 0)
+		return CMD_RET_FAILURE;
+
+	size = 0;
+	daddr = addr;
+	server_ip = env_get("serverip");
+	if (!server_ip) {
+		printf("error: serverip variable has to be set\n");
+		return CMD_RET_FAILURE;
+	}
+
+	ret = ipaddr_aton(server_ip, &srv);
+	LWIP_ASSERT("ipaddr_aton failed", ret == 1);
+
+	printf("TFTP from server %s; our IP address is %s\n",
+			server_ip, env_get("ipaddr"));
+	printf("Filename '%s'.\n", fname);
+	printf("Load address: 0x%lx\n", daddr);
+	printf("Loading:");
+
+	err = tftp_init_client(&tftp);
+	if (!(err == ERR_OK || err == ERR_USE))
+		printf("tftp_init_client err: %d\n", err);
+
+	err = tftp_get(f, &srv, TFTP_PORT, fname, TFTP_MODE_OCTET);
+	/* might return different errors, like routing problems */
+	if (err != ERR_OK) {
+		printf("tftp_get err=%d\n", err);
+	}
+	LWIP_ASSERT("tftp_get failed", err == ERR_OK);
+
+	return err;
+}
+#else
+#error "UDP has to be supported"
+#endif /* LWIP_UDP */
diff --git a/lib/lwip/cmd-lwip.c b/lib/lwip/cmd-lwip.c
new file mode 100644
index 0000000000..d7cdc4e411
--- /dev/null
+++ b/lib/lwip/cmd-lwip.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * (C) Copyright 2023 Maxim Uvarov, maxim.uvarov@linaro.org
+ */
+
+#include <common.h>
+#include <command.h>
+#include <console.h>
+#include <display_options.h>
+#include <memalign.h>
+#include <net.h>
+#include <image.h>
+
+#include "apps/ping/lwip_ping.h"
+#include "ulwip.h"
+
+extern int uboot_lwip_init(void);
+extern int uboot_lwip_loop_is_done(void);
+
+static int do_lwip_info(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[])
+{
+	printf("TBD: %s\n", __func__);
+	return CMD_RET_SUCCESS;
+}
+
+static int do_lwip_init(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[])
+{
+	if (!uboot_lwip_init())
+		return CMD_RET_SUCCESS;
+	return CMD_RET_FAILURE;
+}
+
+static int lwip_empty_tmo(void) { return 0; };
+int (*ulwip_tmo)(void) = lwip_empty_tmo;
+void ulwip_set_tmo(int (*tmo)(void))
+{
+	ulwip_tmo = tmo;
+}
+
+static void ulwip_clear_tmo(void)
+{
+	ulwip_tmo = lwip_empty_tmo;
+}
+
+static void ulwip_timeout_handler(void)
+{
+	eth_halt();
+	ulwip_tmo();
+	net_set_state(NETLOOP_FAIL);	/* we did not get the reply */
+	ulwip_loop_set(0);
+}
+
+static int ulwip_loop(void)
+{
+	ulwip_loop_set(1);
+	if (net_loop(LWIP) < 0) {
+		ulwip_loop_set(0);
+		return CMD_RET_FAILURE;
+	}
+	ulwip_loop_set(0);
+	return CMD_RET_SUCCESS;
+}
+
+#if !defined(CONFIG_CMD_LWIP_REPLACE_PING)
+static
+#endif
+int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[])
+{
+	if (argc < 2) {
+		printf("argc = %d, error\n", argc);
+		return CMD_RET_USAGE;
+	}
+
+	uboot_lwip_init();
+
+	eth_init(); /* activate u-boot eth dev */
+
+	printf("Using %s device\n", eth_get_name());
+	printf("pinging addr: %s\n", argv[1]);
+
+	net_set_timeout_handler(1000UL, ulwip_timeout_handler);
+
+	if (lwip_ping_init(argv[1])) {
+		printf("ping init fail\n");
+		return CMD_RET_FAILURE;
+	}
+
+	ping_send_now();
+
+	return ulwip_loop();
+}
+
+extern int lwip_wget(ulong addr, char *url);
+
+#if !defined(CONFIG_CMD_LWIP_REPLACE_WGET)
+static
+#endif
+int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[])
+{
+	char *url;
+
+	if (argc < 2) {
+		printf("argc = %d, error\n", argc);
+		return CMD_RET_USAGE;
+	}
+	url = argv[1];
+
+	uboot_lwip_init();
+
+	eth_init(); /* activate u-boot eth dev */
+
+	lwip_wget(image_load_addr, url);
+
+	return ulwip_loop();
+}
+
+#if defined(CONFIG_CMD_LWIP_TFTP)
+extern int lwip_tftp(ulong addr, char *filename);
+#if !defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
+static
+#endif
+int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[])
+{
+	char *filename;
+	ulong addr;
+	char *end;
+	int ret;
+
+	switch (argc) {
+	case 1:
+		filename = env_get("bootfile");
+		break;
+	case 2:
+		/*
+		 * Only one arg - accept two forms:
+		 * Just load address, or just boot file name. The latter
+		 * form must be written in a format which can not be
+		 * mis-interpreted as a valid number.
+		 */
+		addr = hextoul(argv[1], &end);
+		if (end == (argv[1] + strlen(argv[1]))) {
+			image_load_addr = addr;
+			filename = env_get("bootfile");
+		} else {
+			filename = argv[1];
+		}
+		break;
+	case 3:
+		image_load_addr = hextoul(argv[1], NULL);
+		filename = argv[2];
+		break;
+	default:
+		return CMD_RET_USAGE;
+	}
+
+	uboot_lwip_init();
+
+	eth_init(); /* activate u-boot eth dev */
+
+	ret = lwip_tftp(image_load_addr, filename);
+	if (ret)
+		return ret;
+
+	return ulwip_loop();
+}
+#endif
+
+#if defined(CONFIG_CMD_LWIP_DHCP)
+extern int ulwip_dhcp(void);
+
+#if !defined(CONFIG_CMD_LWIP_REPLACE_DHCP)
+static
+#endif
+int do_lwip_dhcp(void)
+{
+	int ret;
+	char *filename;
+
+	uboot_lwip_init();
+
+	ret = ulwip_dhcp();
+
+	net_set_timeout_handler(2000UL, ulwip_timeout_handler);
+
+	ulwip_loop();
+	if (IS_ENABLED(CONFIG_CMD_LWIP_TFTP)) {
+		ulwip_clear_tmo();
+
+		filename = env_get("bootfile");
+		if (!filename) {
+			printf("no bootfile\n");
+			return CMD_RET_FAILURE;
+		}
+
+		eth_init(); /* activate u-boot eth dev */
+		net_set_timeout_handler(20000UL, ulwip_timeout_handler);
+		lwip_tftp(image_load_addr, filename);
+
+		ret =  ulwip_loop();
+	}
+
+	return ret;
+}
+
+static int _do_lwip_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
+		char *const argv[])
+{
+	return do_lwip_dhcp();
+}
+#endif
+
+static struct cmd_tbl cmds[] = {
+	U_BOOT_CMD_MKENT(info, 1, 0, do_lwip_info, "Info and stats", ""),
+	U_BOOT_CMD_MKENT(init, 1, 0, do_lwip_init,
+			 "initialize lwip stack", ""),
+#if defined(CONFIG_CMD_LWIP_PING)
+	U_BOOT_CMD_MKENT(ping, 2, 0, do_lwip_ping,
+			 "send ICMP ECHO_REQUEST to network host",
+			 "pingAddress"),
+#endif
+#if defined(CONFIG_CMD_LWIP_WGET)
+	U_BOOT_CMD_MKENT(wget, 2, 0, do_lwip_wget, "", ""),
+#endif
+#if defined(CONFIG_CMD_LWIP_TFTP)
+	U_BOOT_CMD_MKENT(tftp, 3, 0, do_lwip_tftp,
+			"boot image via network using TFTP protocol\n",
+			"[loadAddress] [[hostIPaddr:]bootfilename]"),
+#endif
+#if defined(CONFIG_CMD_LWIP_DHCP)
+	U_BOOT_CMD_MKENT(dhcp, 1, 0, _do_lwip_dhcp,
+			"boot image via network using DHCP/TFTP protocol",
+			""),
+#endif
+};
+
+static int do_ops(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[])
+{
+	struct cmd_tbl *cp;
+
+	cp = find_cmd_tbl(argv[1], cmds, ARRAY_SIZE(cmds));
+
+	argc--;
+	argv++;
+
+	if (cp == NULL || argc > cp->maxargs)
+		return CMD_RET_USAGE;
+	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
+		return CMD_RET_SUCCESS;
+
+	return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+	lwip, 4, 1, do_ops,
+	"LWIP sub system",
+	"info - display info\n"
+	"init - init LWIP\n"
+	"ping addr - pingAddress\n"
+	"wget http://IPadress/url/\n"
+	"tftp [loadAddress] [[hostIPaddr:]bootfilename]\n"
+	"dhcp - boot image via network using DHCP/TFTP protocol\n"
+	);
+
+/* Old command kept for compatibility. Same as 'mmc info' */
+U_BOOT_CMD(
+	lwipinfo, 1, 0, do_lwip_info,
+	"display LWIP info",
+	"- display LWIP stack info"
+);
diff --git a/lib/lwip/lwipopts.h b/lib/lwip/lwipopts.h
new file mode 100644
index 0000000000..b943d7b9be
--- /dev/null
+++ b/lib/lwip/lwipopts.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#ifndef LWIP_LWIPOPTS_H
+#define LWIP_LWIPOPTS_H
+
+#include "lwipopts.h"
+
+#if defined(CONFIG_LWIP_LIB_DEBUG)
+#define LWIP_DEBUG 1
+#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
+#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON
+#define ETHARP_DEBUG                    LWIP_DBG_OFF
+#define NETIF_DEBUG                     LWIP_DBG_OFF
+#define PBUF_DEBUG                      LWIP_DBG_OFF
+#define API_LIB_DEBUG                   LWIP_DBG_OFF
+#define API_MSG_DEBUG                   LWIP_DBG_OFF
+#define SOCKETS_DEBUG                   LWIP_DBG_OFF
+#define ICMP_DEBUG                      LWIP_DBG_OFF
+#define IGMP_DEBUG                      LWIP_DBG_OFF
+#define INET_DEBUG                      LWIP_DBG_OFF
+#define IP_DEBUG                        LWIP_DBG_OFF
+#define IP_REASS_DEBUG                  LWIP_DBG_OFF
+#define RAW_DEBUG                       LWIP_DBG_OFF
+#define MEM_DEBUG                       LWIP_DBG_OFF
+#define MEMP_DEBUG                      LWIP_DBG_OFF
+#define SYS_DEBUG                       LWIP_DBG_OFF
+#define TIMERS_DEBUG                    LWIP_DBG_OFF
+#define TCP_DEBUG                       LWIP_DBG_OFF
+#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF
+#define TCP_FR_DEBUG                    LWIP_DBG_OFF
+#define TCP_RTO_DEBUG                   LWIP_DBG_OFF
+#define TCP_CWND_DEBUG                  LWIP_DBG_OFF
+#define TCP_WND_DEBUG                   LWIP_DBG_OFF
+#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF
+#define TCP_RST_DEBUG                   LWIP_DBG_OFF
+#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF
+#define UDP_DEBUG                       LWIP_DBG_OFF
+#define TCPIP_DEBUG                     LWIP_DBG_OFF
+#define SLIP_DEBUG                      LWIP_DBG_OFF
+#define DHCP_DEBUG                      LWIP_DBG_ON
+#define AUTOIP_DEBUG                    LWIP_DBG_ON
+#define DNS_DEBUG                       LWIP_DBG_OFF
+#define IP6_DEBUG                       LWIP_DBG_OFF
+#define DHCP6_DEBUG                     LWIP_DBG_OFF
+#else
+#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
+#define LWIP_DBG_TYPES_ON               LWIP_DBG_OFF
+#define ETHARP_DEBUG                    LWIP_DBG_OFF
+#define NETIF_DEBUG                     LWIP_DBG_OFF
+#define PBUF_DEBUG                      LWIP_DBG_OFF
+#define API_LIB_DEBUG                   LWIP_DBG_OFF
+#define API_MSG_DEBUG                   LWIP_DBG_OFF
+#define SOCKETS_DEBUG                   LWIP_DBG_OFF
+#define ICMP_DEBUG                      LWIP_DBG_OFF
+#define IGMP_DEBUG                      LWIP_DBG_OFF
+#define INET_DEBUG                      LWIP_DBG_OFF
+#define IP_DEBUG                        LWIP_DBG_OFF
+#define IP_REASS_DEBUG                  LWIP_DBG_OFF
+#define RAW_DEBUG                       LWIP_DBG_OFF
+#define MEM_DEBUG                       LWIP_DBG_OFF
+#define MEMP_DEBUG                      LWIP_DBG_OFF
+#define SYS_DEBUG                       LWIP_DBG_OFF
+#define TIMERS_DEBUG                    LWIP_DBG_OFF
+#define TCP_DEBUG                       LWIP_DBG_OFF
+#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF
+#define TCP_FR_DEBUG                    LWIP_DBG_OFF
+#define TCP_RTO_DEBUG                   LWIP_DBG_OFF
+#define TCP_CWND_DEBUG                  LWIP_DBG_OFF
+#define TCP_WND_DEBUG                   LWIP_DBG_OFF
+#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF
+#define TCP_RST_DEBUG                   LWIP_DBG_OFF
+#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF
+#define UDP_DEBUG                       LWIP_DBG_OFF
+#define TCPIP_DEBUG                     LWIP_DBG_OFF
+#define SLIP_DEBUG                      LWIP_DBG_OFF
+#define DHCP_DEBUG                      LWIP_DBG_OFF
+#define AUTOIP_DEBUG                    LWIP_DBG_OFF
+#define DNS_DEBUG                       LWIP_DBG_OFF
+#define IP6_DEBUG                       LWIP_DBG_OFF
+#define DHCP6_DEBUG                     LWIP_DBG_OFF
+#endif
+#define LWIP_TESTMODE                   0
+
+#if defined(CONFIG_LWIP_LIB_NOASSERT)
+#define LWIP_NOASSERT 1
+#define LWIP_ASSERT(message, assertion)
+#endif
+
+#include "lwip/debug.h"
+
+#define SYS_LIGHTWEIGHT_PROT            0
+#define NO_SYS                          0
+
+#define MEM_ALIGNMENT                   1
+#define MEM_SIZE                        CONFIG_LWIP_LIB_MEM_SIZE
+
+#define MEMP_NUM_PBUF                   4
+#define MEMP_NUM_RAW_PCB                2
+#define MEMP_NUM_UDP_PCB                4
+#define MEMP_NUM_TCP_PCB                2
+#define MEMP_NUM_TCP_PCB_LISTEN         2
+#define MEMP_NUM_TCP_SEG                16
+#define MEMP_NUM_REASSDATA              1
+#define MEMP_NUM_ARP_QUEUE              2
+#define MEMP_NUM_SYS_TIMEOUT            4
+#define MEMP_NUM_NETBUF                 2
+#define MEMP_NUM_NETCONN               32
+#define MEMP_NUM_TCPIP_MSG_API          8
+#define MEMP_NUM_TCPIP_MSG_INPKT        8
+#define PBUF_POOL_SIZE                  8
+
+#define LWIP_ARP                        1
+
+#define IP_FORWARD                      0
+#define IP_OPTIONS_ALLOWED              1
+#define IP_REASSEMBLY                   1
+#define IP_FRAG                         1
+#define IP_REASS_MAXAGE                 3
+#define IP_REASS_MAX_PBUFS              4
+#define IP_FRAG_USES_STATIC_BUF         0
+
+#define IP_DEFAULT_TTL                  255
+
+#define LWIP_ICMP                       1
+
+#define LWIP_RAW                        1
+
+#if defined(CONFIG_LWIP_LIB_DHCP)
+#define LWIP_DHCP                       1
+#define LWIP_DHCP_BOOTP_FILE		1
+#else
+#define LWIP_DHCP                       0
+#endif
+#define LWIP_DHCP_DOES_ACD_CHECK	0
+
+#define LWIP_AUTOIP                     0
+
+#define LWIP_SNMP                       0
+
+#define LWIP_IGMP                       0
+
+#if defined(CONFIG_LWIP_LIB_DNS)
+#define LWIP_DNS                        1
+#else
+#define LWIP_DNS                        0
+#endif
+
+#if defined(CONFIG_LWIP_LIB_TCP)
+#define LWIP_UDP                        1
+#else
+#define LWIP_UDP                        0
+#endif
+
+#if defined(CONFIG_LWIP_LIB_TCP)
+#define LWIP_TCP                        1
+#else
+#define LWIP_TCP                        0
+#endif
+
+#define LWIP_LISTEN_BACKLOG             0
+
+#define PBUF_LINK_HLEN                  CONFIG_LWIP_LIB_PBUF_LINK_HLEN
+#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS + 40 + PBUF_LINK_HLEN)
+
+#define LWIP_HAVE_LOOPIF                0
+
+#if defined(CONFIG_LWIP_LIB_NETCONN)
+#define LWIP_NETCONN                    1
+#else
+#define LWIP_NETCONN                    0
+#define LWIP_DISABLE_MEMP_SANITY_CHECKS 1
+#endif
+
+#if defined(CONFIG_LWIP_LIB_SOCKET)
+#define LWIP_SOCKET                     1
+
+#define SO_REUSE                        1
+#else
+#define LWIP_SOCKET                     0
+#define SO_REUSE                        0
+#endif
+
+#define LWIP_STATS                      0
+
+#define PPP_SUPPORT                     0
+
+#define LWIP_TCPIP_CORE_LOCKING		0
+
+#if defined(CONFIG_LWIP_LIB_LOOPBACK)
+#define LWIP_NETIF_LOOPBACK		1
+#else
+#define LWIP_NETIF_LOOPBACK		0
+#endif
+/* use malloc instead of pool */
+#define MEMP_MEM_MALLOC                 1
+#define MEMP_MEM_INIT			1
+#define MEM_LIBC_MALLOC			1
+
+#endif /* LWIP_LWIPOPTS_H */
diff --git a/lib/lwip/port/if.c b/lib/lwip/port/if.c
new file mode 100644
index 0000000000..15d44054be
--- /dev/null
+++ b/lib/lwip/port/if.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#include <common.h>
+#include <command.h>
+extern int eth_init(void); /* net.h */
+extern void string_to_enetaddr(const char *addr, uint8_t *enetaddr); /* net.h */
+extern struct in_addr net_ip;
+extern u8 net_ethaddr[6];
+
+#include "lwip/debug.h"
+#include "lwip/arch.h"
+#include "netif/etharp.h"
+#include "lwip/stats.h"
+#include "lwip/def.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+#include "lwip/netif.h"
+
+#include "lwip/ip.h"
+
+#define IFNAME0 'e'
+#define IFNAME1 '0'
+
+static struct pbuf *low_level_input(struct netif *netif);
+static int uboot_net_use_lwip;
+
+int ulwip_enabled(void)
+{
+	return uboot_net_use_lwip;
+}
+
+/* 1 - in loop
+ * 0 - no loop
+ */
+static int loop_lwip;
+
+/* ret 1 - in loop
+ *     0 - no loop
+ */
+int ulwip_in_loop(void)
+{
+	return loop_lwip;
+}
+
+void ulwip_loop_set(int loop)
+{
+	loop_lwip = loop;
+}
+
+static int ulwip_app_err;
+
+void ulwip_exit(int err)
+{
+	ulwip_app_err = err;
+	ulwip_loop_set(0);
+}
+
+int ulwip_app_get_err(void)
+{
+	return ulwip_app_err;
+}
+
+struct uboot_lwip_if {
+};
+
+#if defined(CONFIG_CMD_LWIP_DHCP)
+struct netif uboot_netif;
+#else
+static struct netif uboot_netif;
+#endif
+
+#define LWIP_PORT_INIT_NETMASK(addr)  IP4_ADDR((addr), 255, 255, 255, 0)
+
+extern uchar *net_rx_packet;
+extern int    net_rx_packet_len;
+
+int uboot_lwip_poll(void)
+{
+	struct pbuf *p;
+	int err;
+
+	p = low_level_input(&uboot_netif);
+	if (!p) {
+		printf("error p = low_level_input = NULL\n");
+		return 0;
+	}
+
+	err = ethernet_input(p, &uboot_netif);
+	if (err)
+		printf("ip4_input err %d\n", err);
+
+	return 0;
+}
+
+static struct pbuf *low_level_input(struct netif *netif)
+{
+	struct pbuf *p, *q;
+	u16_t len = net_rx_packet_len;
+	uchar *data = net_rx_packet;
+
+#if ETH_PAD_SIZE
+	len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
+#endif
+
+	/* We allocate a pbuf chain of pbufs from the pool. */
+	p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
+	if (p) {
+#if ETH_PAD_SIZE
+		pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
+#endif
+		/* We iterate over the pbuf chain until we have read the entire
+		 * packet into the pbuf.
+		 */
+		for (q = p; q != NULL; q = q->next) {
+			/* Read enough bytes to fill this pbuf in the chain. The
+			 * available data in the pbuf is given by the q->len
+			 * variable.
+			 * This does not necessarily have to be a memcpy, you can also preallocate
+			 * pbufs for a DMA-enabled MAC and after receiving truncate it to the
+			 * actually received size. In this case, ensure the tot_len member of the
+			 * pbuf is the sum of the chained pbuf len members.
+			 */
+			MEMCPY(q->payload, data, q->len);
+			data += q->len;
+		}
+		//acknowledge that packet has been read();
+
+#if ETH_PAD_SIZE
+		pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
+#endif
+		LINK_STATS_INC(link.recv);
+	} else {
+		//drop packet();
+		LINK_STATS_INC(link.memerr);
+		LINK_STATS_INC(link.drop);
+	}
+
+	return p;
+}
+
+static int ethernetif_input(struct pbuf *p, struct netif *netif)
+{
+	struct ethernetif *ethernetif;
+
+	ethernetif = netif->state;
+
+	/* move received packet into a new pbuf */
+	p = low_level_input(netif);
+
+	/* if no packet could be read, silently ignore this */
+	if (p) {
+		/* pass all packets to ethernet_input, which decides what packets it supports */
+		if (netif->input(p, netif) != ERR_OK) {
+			LWIP_DEBUGF(NETIF_DEBUG, ("%s: IP input error\n", __func__));
+			pbuf_free(p);
+			p = NULL;
+		}
+	}
+	return 0;
+}
+
+static err_t low_level_output(struct netif *netif, struct pbuf *p)
+{
+	int err;
+
+	err = eth_send(p->payload, p->len);
+	if (err != 0) {
+		printf("eth_send error %d\n", err);
+		return ERR_ABRT;
+	}
+	return ERR_OK;
+}
+
+err_t uboot_lwip_if_init(struct netif *netif)
+{
+	struct uboot_lwip_if *uif = (struct uboot_lwip_if *)malloc(sizeof(struct uboot_lwip_if));
+
+	if (!uif) {
+		printf("uboot_lwip_if: out of memory\n");
+		return ERR_MEM;
+	}
+	netif->state = uif;
+
+	netif->name[0] = IFNAME0;
+	netif->name[1] = IFNAME1;
+
+	netif->hwaddr_len = ETHARP_HWADDR_LEN;
+	string_to_enetaddr(env_get("ethaddr"), netif->hwaddr);
+#if defined(CONFIG_LWIP_LIB_DEBUG)
+	printf("              MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
+	       netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2],
+	       netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]);
+#endif
+
+#if LWIP_IPV4
+	netif->output = etharp_output;
+#endif /* LWIP_IPV4 */
+#if LWIP_IPV6
+	netif->output_ip6 = ethip6_output;
+#endif /* LWIP_IPV6 */
+	netif->linkoutput = low_level_output;
+	netif->mtu = 1500;
+	netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
+
+	eth_init(); /* activate u-boot eth dev */
+
+	if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) {
+		printf("Initialized LWIP stack\n");
+	}
+
+	return ERR_OK;
+}
+
+int uboot_lwip_init(void)
+{
+	ip4_addr_t ipaddr, netmask, gw;
+
+	if (uboot_net_use_lwip)
+		return CMD_RET_SUCCESS;
+
+	ip4_addr_set_zero(&gw);
+	ip4_addr_set_zero(&ipaddr);
+	ip4_addr_set_zero(&netmask);
+
+	ipaddr_aton(env_get("ipaddr"), &ipaddr);
+	ipaddr_aton(env_get("ipaddr"), &netmask);
+
+	LWIP_PORT_INIT_NETMASK(&netmask);
+	if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) {
+		printf("Starting lwIP, IP: %s\n", ip4addr_ntoa(&ipaddr));
+		printf("               GW: %s\n", ip4addr_ntoa(&gw));
+		printf("             mask: %s\n", ip4addr_ntoa(&netmask));
+	}
+
+	if (!netif_add(&uboot_netif, &ipaddr, &netmask, &gw,
+		       &uboot_netif, uboot_lwip_if_init, ethernetif_input))
+		printf("err: netif_add failed!\n");
+
+	netif_set_up(&uboot_netif);
+	netif_set_link_up(&uboot_netif);
+#if LWIP_IPV6
+	netif_create_ip6_linklocal_address(&uboot_netif, 1);
+	printf("             IPv6: %s\n", ip6addr_ntoa(netif_ip6_addr(uboot_netif, 0)));
+#endif /* LWIP_IPV6 */
+
+	uboot_net_use_lwip = 1;
+
+	return CMD_RET_SUCCESS;
+}
+
+/* placeholder, not used now */
+void uboot_lwip_destroy(void)
+{
+	uboot_net_use_lwip = 0;
+}
diff --git a/lib/lwip/port/include/arch/cc.h b/lib/lwip/port/include/arch/cc.h
new file mode 100644
index 0000000000..db30d7614e
--- /dev/null
+++ b/lib/lwip/port/include/arch/cc.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#ifndef LWIP_ARCH_CC_H
+#define LWIP_ARCH_CC_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#define LWIP_ERRNO_INCLUDE <errno.h>
+
+#define LWIP_ERRNO_STDINCLUDE	1
+#define LWIP_NO_UNISTD_H 1
+#define LWIP_TIMEVAL_PRIVATE 1
+
+extern unsigned int lwip_port_rand(void);
+#define LWIP_RAND() (lwip_port_rand())
+
+/* different handling for unit test, normally not needed */
+#ifdef LWIP_NOASSERT_ON_ERROR
+#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
+						    handler; }} while (0)
+#endif
+
+#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS
+
+#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
+				    x, __LINE__, __FILE__); } while (0)
+
+static inline int atoi(const char *str)
+{
+	int r = 0;
+	int i;
+
+	for (i = 0; str[i] != '\0'; ++i)
+		r = r * 10 + str[i] - '0';
+
+	return r;
+}
+
+#define LWIP_ERR_T int
+
+#endif /* LWIP_ARCH_CC_H */
diff --git a/lib/lwip/port/include/arch/sys_arch.h b/lib/lwip/port/include/arch/sys_arch.h
new file mode 100644
index 0000000000..8d95146275
--- /dev/null
+++ b/lib/lwip/port/include/arch/sys_arch.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#ifndef LWIP_ARCH_SYS_ARCH_H
+#define LWIP_ARCH_SYS_ARCH_H
+
+#include "lwip/opt.h"
+#include "lwip/arch.h"
+#include "lwip/err.h"
+
+#define ERR_NEED_SCHED 123
+
+void sys_arch_msleep(u32_t delay_ms);
+#define sys_msleep(ms) sys_arch_msleep(ms)
+
+#if SYS_LIGHTWEIGHT_PROT
+typedef u32_t sys_prot_t;
+#endif /* SYS_LIGHTWEIGHT_PROT */
+
+#include <errno.h>
+
+#define SYS_MBOX_NULL NULL
+#define SYS_SEM_NULL  NULL
+
+typedef u32_t sys_prot_t;
+
+struct sys_sem;
+typedef struct sys_sem *sys_sem_t;
+#define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL))
+#define sys_sem_set_invalid(sem) do { if ((sem) != NULL) { *(sem) = NULL; }} while (0)
+
+/* let sys.h use binary semaphores for mutexes */
+#define LWIP_COMPAT_MUTEX 1
+#define LWIP_COMPAT_MUTEX_ALLOWED 1
+
+struct sys_mbox;
+typedef struct sys_mbox *sys_mbox_t;
+#define sys_mbox_valid(mbox) (((mbox) != NULL) && (*(mbox) != NULL))
+#define sys_mbox_set_invalid(mbox) do { if ((mbox) != NULL) { *(mbox) = NULL; }} while (0)
+
+struct sys_thread;
+typedef struct sys_thread *sys_thread_t;
+
+static inline u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
+{
+	return 0;
+};
+
+static inline err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
+{
+	return 0;
+};
+
+#define sys_sem_signal(s)
+
+#endif /* LWIP_ARCH_SYS_ARCH_H */
diff --git a/lib/lwip/port/include/limits.h b/lib/lwip/port/include/limits.h
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/lib/lwip/port/sys-arch.c b/lib/lwip/port/sys-arch.c
new file mode 100644
index 0000000000..609eeccf8c
--- /dev/null
+++ b/lib/lwip/port/sys-arch.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+ */
+
+#include <common.h>
+#include <rand.h>
+#include "lwip/opt.h"
+
+u32_t sys_now(void)
+{
+	return get_timer(0);
+}
+
+u32_t lwip_port_rand(void)
+{
+	return (u32_t)rand();
+}
+
diff --git a/lib/lwip/ulwip.h b/lib/lwip/ulwip.h
new file mode 100644
index 0000000000..11ca52aa1f
--- /dev/null
+++ b/lib/lwip/ulwip.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+int ulwip_enabled(void);
+int ulwip_in_loop(void);
+int ulwip_loop_set(int loop);
+int ulwip_exit(int err);
+int uboot_lwip_poll(void);
+int ulwip_app_get_err(void);
+void ulwip_set_tmo(int (*tmo)(void));
diff --git a/net/eth-uclass.c b/net/eth-uclass.c
index f41da4b37b..6031ad805d 100644
--- a/net/eth-uclass.c
+++ b/net/eth-uclass.c
@@ -367,8 +367,10 @@ int eth_send(void *packet, int length)
 	if (!current)
 		return -ENODEV;
 
-	if (!eth_is_active(current))
+	if (!eth_is_active(current)) {
+		printf("%s() !eth_is_active\n", __func__);
 		return -EINVAL;
+	}
 
 	ret = eth_get_ops(current)->send(current, packet, length);
 	if (ret < 0) {
diff --git a/net/net.c b/net/net.c
index 57da9bda85..aa9dd85a99 100644
--- a/net/net.c
+++ b/net/net.c
@@ -121,6 +121,7 @@
 #endif
 #include <net/tcp.h>
 #include <net/wget.h>
+#include "../lib/lwip/ulwip.h"
 
 /** BOOTP EXTENTIONS **/
 
@@ -438,7 +439,11 @@ int net_loop(enum proto_t protocol)
 #endif
 
 	bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
+#if defined(CONFIG_LWIP_LIB)
+	if (!ulwip_enabled() || !ulwip_in_loop())
+#endif
 	net_init();
+
 	if (eth_is_on_demand_init()) {
 		eth_halt();
 		eth_set_current();
@@ -619,10 +624,23 @@ restart:
 		 */
 		eth_rx();
 
+#if defined(CONFIG_LWIP_LIB)
+		if (ulwip_enabled()) {
+			net_set_state(NETLOOP_CONTINUE);
+			if (!ulwip_in_loop()) {
+				if (ulwip_app_get_err())
+					net_set_state(NETLOOP_FAIL);
+				else
+					net_set_state(NETLOOP_SUCCESS);
+				goto done;
+			}
+		}
+#endif
 		/*
 		 *	Abort if ctrl-c was pressed.
 		 */
 		if (ctrlc()) {
+			printf("-->enter ctrlc\n");
 			/* cancel any ARP that may not have completed */
 			net_arp_wait_packet_ip.s_addr = 0;
 
@@ -1177,6 +1195,13 @@ void net_process_received_packet(uchar *in_packet, int len)
 	if (len < ETHER_HDR_SIZE)
 		return;
 
+#if defined(CONFIG_LWIP_LIB)
+	if (ulwip_enabled()) {
+		uboot_lwip_poll();
+		return;
+	}
+#endif
+
 #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
 	if (push_packet) {
 		(*push_packet)(in_packet, len);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 1/3] net/lwip: add lwip-external submodule
  2023-06-29 12:34 [PATCHv2 1/3] net/lwip: add lwip-external submodule Maxim Uvarov
  2023-06-29 12:34 ` [PATCHv2 2/3] net/lwip: add README.lwip Maxim Uvarov
  2023-06-29 12:34 ` [PATCHv2 3/3] net/lwip: add lwip library for the network stack Maxim Uvarov
@ 2023-06-29 19:10 ` Simon Glass
  2 siblings, 0 replies; 11+ messages in thread
From: Simon Glass @ 2023-06-29 19:10 UTC (permalink / raw)
  To: Maxim Uvarov
  Cc: u-boot, pbrobinson, ilias.apalodimas, joe.hershberger, rfried.dev,
	trini, goldsimon, lwip-devel

Hi Maxim,

On Thu, 29 Jun 2023 at 13:39, Maxim Uvarov <maxim.uvarov@linaro.org> wrote:
>
> This commit adds the lwip library as a git submodule. I think
> there has to be advantages to compile lwip inside U-boot,
> i.e. use the same compiler and flags as the main code.
> One of them is LTO and the other is to enable additional debug
> options for network protocol during development. Also we can
> copy lwip library code inside U-boot, but for now I don't want
> to send all lwip code to the mailing list. So it's git submodule.

Fairy nuff. You can send the full patch later.

Regards,
Simon

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 2/3] net/lwip: add README.lwip
  2023-06-29 12:34 ` [PATCHv2 2/3] net/lwip: add README.lwip Maxim Uvarov
@ 2023-06-30 10:01   ` Ilias Apalodimas
  2023-06-30 16:33     ` Tom Rini
  2023-07-03 16:22     ` Maxim Uvarov
  0 siblings, 2 replies; 11+ messages in thread
From: Ilias Apalodimas @ 2023-06-30 10:01 UTC (permalink / raw)
  To: Maxim Uvarov
  Cc: u-boot, pbrobinson, joe.hershberger, rfried.dev, trini, goldsimon,
	lwip-devel

Hi Maxim,

On Thu, Jun 29, 2023 at 06:34:29PM +0600, Maxim Uvarov wrote:
> Just add inital README.lwip doc.

We'll need a more accurate description for this.  The first paragraph of
the documentation you are adding would do

>
> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> ---
>  doc/README.lwip | 90 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 90 insertions(+)
>  create mode 100644 doc/README.lwip
>
> diff --git a/doc/README.lwip b/doc/README.lwip
> new file mode 100644
> index 0000000000..16f41049ab
> --- /dev/null
> +++ b/doc/README.lwip
> @@ -0,0 +1,90 @@
> +	RFC LWIP IP stack intergation for U-boot
> +        ----------------------------------------
> +
> +Reliable and bug free IP stack is usually an issue when you are trying to write it

I am not sure about the bug free part :).  Just move this entire paragraph as
part of the commit message and remove the 'RFC' parts.

> +from scratch. It looks like not, but when addinging new features it will be chelledging.
> +This RFC work is a demo to enable lwIP (lightweight IP) which is a widely used open-source
> +TCP/IP stack designed for embedded systems for U-boot. That will allow using already
> +written network applications for microcontrollers.
> +
> +LwIP  license:
> +lwIP is licensed under a BSD-style license: http://lwip.wikia.com/wiki/License.
> +
> +Main features include:
> +- Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE
> +- DHCP client, DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), SNMP agent (v1, v2c, v3, private MIB support & MIB compiler)
> +- APIs: specialized APIs for enhanced performance, optional Berkeley-alike socket API
> +- Extended features: IP forwarding over multiple network interfaces, TCP congestion control, RTT estimation and fast recovery/fast retransmit
> +- Addon applications: HTTP(S) server, SNTP client, SMTP(S) client, ping, NetBIOS nameserver, mDNS responder, MQTT client, TFTP server
> +
> +U-boot implementation details:
> +
> +1. In general we can build lwIP as .a library and link it against u-boot or compile it in
> +the U-boot tree in the same way as other U-boot files. There are few reasons why I selected
> +the second variant: iwIP is very customizable with defines for features, memory size, types of
> +allocation, some internal types and platform specific code. And it was more easy to enable/disable
> + debug which is also done with defines, and is needed periodically.
> +
> +2. lwIP has 2 APIs - raw mode and sequential (as lwIP names it, or socket API as we name it in Linux).
> +  This RFC implements only raw API as the proof of work.
> +
> +Raw IP means that the call back function for RX path is registered and will be called when packet
> +data passes the IP stack and is ready for the application.
> +
> +This RFC has an unmodified working ping example from lwip sources which registeres this callback.
> +  ping_pcb = raw_new(IP_PROTO_ICMP);
> +  raw_recv(ping_pcb, ping_recv, NULL); <- ping_recv is app callback.
> +  raw_bind(ping_pcb, IP_ADDR_ANY)
> +
> +Socket API also gives nice advantages due it will be easy to port linux socket applications to u-boot.
> +I.e. lwIP sockets compatible with the linux ones. But that will require RX thread running in the background.
> +So that means we need some kind of scheduler, locking and threading support or find some other solution.
> +
> +3.  Input and output
> +
> +RX packet path is injected to U-boot eth_rx() polling loop and TX patch is in eth_send() accordingly.
> +So we do not touch any drivers code and just eat packets when they are ready.
> +
> +4. Testing
> +
> +Unmodified ping example can be used. I did ping from qemu/u-boot tap device on the host:
> +
> +=> lwip init
> +=> lwip ping 192.168.1.2
> +ping: recv 3 ms
> +tcpdump on the host:
> +5:09:10.925951 ARP, Request who-has 192.168.1.200 tell 192.168.1.200, length 28 15:09:12.114643 IP6 fe80::38e2:41ff:fec3:8bda > ip6-allrouters: ICMP6, router solicitation, length 16 15:09:20.370725 ARP, Request who-has 192.168.1.2 tell 192.168.1.200, length 28 15:09:20.370740 ARP, Reply 192.168.1.2 is-at 3a:e2:41:c3:8b:da (oui Unknown), length 28 15:09:20.372789 IP 192.168.1.200 > 192.168.1.2: ICMP echo request, id 44975, seq 1, length 40 15:09:20.372810 IP 192.168.1.2 > 192.168.1.200: ICMP echo reply, id 44975, seq 1, length 40 15:09:25.426636 ARP, Request who-has 192.168.1.200 tell 192.168.1.2, length 28 15:09:25.426870 ARP, Reply 192.168.1.200 is-at f6:11:01:02:03:04 (oui Unknown), length 28
> +
> +
> +5. Wget example
> +
> +Http server has 192.168.1.2 IP address. (I did not port DNS resolving yet,
> +but it's also exist in lwip.) So example just downloads some file with http
> +protocol:
> +
> +Net:   eth0: virtio-net#30
> +Hit any key to stop autoboot:  0
> +=> lwip init
> +Starting lwIP, local interface IP is 192.168.1.200
> +Initialized LWIP stack
> +=> lwip wget http://192.168.1.2/
> +downloading http://192.168.1.2/ to addr 0x40200000

Does wget with lwip work with dns as well?

> +downloaded chunk size 294, to addr 0x40200000
> +downloaded chunk size 318, to addr 0x40200126
> +=> md 0x40200000 0x40
> +40200000: 4f44213c 50595443 74682045 0a3e6c6d  <!DOCTYPE html>.
> +40200010: 6d74683c 3c0a3e6c 64616568 743c0a3e  <html>.<head>.<t
> +40200020: 656c7469 6c65573e 656d6f63 206f7420  itle>Welcome to
> +40200030: 6e69676e 2f3c2178 6c746974 3c0a3e65  nginx!</title>.<
> +40200040: 6c797473 200a3e65 62202020 2079646f  style>.    body
> +40200050: 20200a7b 20202020 69772020 3a687464  {.        width:
> +40200060: 65353320 200a3b6d 20202020 6d202020   35em;.        m
> +40200070: 69677261 30203a6e 74756120 200a3b6f  argin: 0 auto;.
> +40200080: 20202020 66202020 2d746e6f 696d6166         font-fami
> +40200090: 203a796c 6f686154 202c616d 64726556  ly: Tahoma, Verd
> +402000a0: 2c616e61 69724120 202c6c61 736e6173  ana, Arial, sans
> +402000b0: 7265732d 0a3b6669 20202020 2f3c0a7d  -serif;.    }.</
> +402000c0: 6c797473 3c0a3e65 6165682f 3c0a3e64  style>.</head>.<
> +402000d0: 79646f62 683c0a3e 65573e31 6d6f636c  body>.<h1>Welcom
> +402000e0: 6f742065 69676e20 3c21786e 3e31682f  e to nginx!</h1>
> +402000f0: 3e703c0a 79206649 7320756f 74206565  .<p>If you see t
> --
> 2.30.2
>

Thanks
/Ilias

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 3/3] net/lwip: add lwip library for the network stack
  2023-06-29 12:34 ` [PATCHv2 3/3] net/lwip: add lwip library for the network stack Maxim Uvarov
@ 2023-06-30 10:03   ` Ilias Apalodimas
  2023-06-30 10:31     ` Maxim Uvarov
  2023-06-30 16:38   ` Tom Rini
  1 sibling, 1 reply; 11+ messages in thread
From: Ilias Apalodimas @ 2023-06-30 10:03 UTC (permalink / raw)
  To: Maxim Uvarov
  Cc: u-boot, pbrobinson, joe.hershberger, rfried.dev, trini, goldsimon,
	lwip-devel

Hi Maxim,

On Thu, Jun 29, 2023 at 06:34:30PM +0600, Maxim Uvarov wrote:
> This commit adds lwip library for the U-boot network
> stack. Supported commands: ping, tftp, dhcp and wget.
>
> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> ---
>  .gitignore                            |   9 +
>  cmd/net.c                             |  38 +++-
>  include/net.h                         |   2 +-
>  lib/Kconfig                           |   2 +
>  lib/Makefile                          |   2 +
>  lib/lwip/Kconfig                      | 108 ++++++++++
>  lib/lwip/Makefile                     |  98 +++++++++
>  lib/lwip/apps/dhcp/lwip-dhcp.c        |  52 +++++
>  lib/lwip/apps/http/lwip-wget.c        |  71 +++++++
>  lib/lwip/apps/ping/lwip_ping.c        |  37 ++++
>  lib/lwip/apps/ping/lwip_ping.h        |  24 +++

I thought we could compile dhcp/wget etc directly from lwip.  Do we have to
copy them over?

Thanks
/Ilias
>  lib/lwip/apps/ping/ping.h             |  35 ++++
>  lib/lwip/apps/tftp/lwip-tftp.c        | 121 +++++++++++
>  lib/lwip/cmd-lwip.c                   | 276 ++++++++++++++++++++++++++
>  lib/lwip/lwipopts.h                   | 203 +++++++++++++++++++
>  lib/lwip/port/if.c                    | 260 ++++++++++++++++++++++++
>  lib/lwip/port/include/arch/cc.h       |  46 +++++
>  lib/lwip/port/include/arch/sys_arch.h |  59 ++++++
>  lib/lwip/port/include/limits.h        |   0
>  lib/lwip/port/sys-arch.c              |  20 ++
>  lib/lwip/ulwip.h                      |   9 +
>  net/eth-uclass.c                      |   4 +-
>  net/net.c                             |  25 +++
>  23 files changed, 1496 insertions(+), 5 deletions(-)
>  create mode 100644 lib/lwip/Kconfig
>  create mode 100644 lib/lwip/Makefile
>  create mode 100644 lib/lwip/apps/dhcp/lwip-dhcp.c
>  create mode 100644 lib/lwip/apps/http/lwip-wget.c
>  create mode 100644 lib/lwip/apps/ping/lwip_ping.c
>  create mode 100644 lib/lwip/apps/ping/lwip_ping.h
>  create mode 100644 lib/lwip/apps/ping/ping.h
>  create mode 100644 lib/lwip/apps/tftp/lwip-tftp.c
>  create mode 100644 lib/lwip/cmd-lwip.c
>  create mode 100644 lib/lwip/lwipopts.h
>  create mode 100644 lib/lwip/port/if.c
>  create mode 100644 lib/lwip/port/include/arch/cc.h
>  create mode 100644 lib/lwip/port/include/arch/sys_arch.h
>  create mode 100644 lib/lwip/port/include/limits.h
>  create mode 100644 lib/lwip/port/sys-arch.c
>  create mode 100644 lib/lwip/ulwip.h
>
> diff --git a/.gitignore b/.gitignore
> index eb769f144c..be3676c59e 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -104,3 +104,12 @@ __pycache__
>  # pylint files
>  /pylint.cur
>  /pylint.out/
> +
> +lib/lwip/lwip-external
> +lib/lwip/apps/ping/ping.c
> +lib/lwip/apps/http/http_client.c
> +lib/lwip/apps/http/http_client.h
> +lib/lwip/apps/tftp/tftp.c
> +lib/lwip/apps/tftp/tftp_client.h
> +lib/lwip/apps/tftp/tftp_common.h
> +lib/lwip/apps/tftp/tftp_example.h
> diff --git a/cmd/net.c b/cmd/net.c
> index 0e9f200ca9..5b3dfd6c7e 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -36,6 +36,10 @@ U_BOOT_CMD(
>  #endif
>
>  #ifdef CONFIG_CMD_TFTPBOOT
> +#if defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
> +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc,
> +		 char *const argv[]);
> +#endif
>  int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
>  {
>  	int ret;
> @@ -56,7 +60,12 @@ U_BOOT_CMD(
>  );
>  #else
>  U_BOOT_CMD(
> -	tftpboot,	3,	1,	do_tftpb,
> +	tftpboot,	3,	1,
> +#if defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
> +	do_lwip_tftp,
> +#else
> +	do_tftpb,
> +#endif
>  	"load file via network using TFTP protocol",
>  	"[loadAddress] [[hostIPaddr:]bootfilename]"
>  );
> @@ -112,7 +121,11 @@ U_BOOT_CMD(
>  static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
>  		   char *const argv[])
>  {
> +#if defined(CONFIG_CMD_LWIP_REPLACE_DHCP)
> +	return do_lwip_dhcp();
> +#else
>  	return netboot_common(DHCP, cmdtp, argc, argv);
> +#endif
>  }
>
>  U_BOOT_CMD(
> @@ -137,13 +150,22 @@ U_BOOT_CMD(
>  #endif
>
>  #if defined(CONFIG_CMD_WGET)
> +#if defined(CONFIG_CMD_LWIP_REPLACE_WGET)
> +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
> +		 char *const argv[])
> +#endif
>  static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
>  {
>  	return netboot_common(WGET, cmdtp, argc, argv);
>  }
>
>  U_BOOT_CMD(
> -	wget,   3,      1,      do_wget,
> +	wget,   3,      1,
> +#if defined(CONFIG_CMD_LWIP_REPLACE_WGET)
> +	do_lwip_wget,
> +#else
> +	do_wget,
> +#endif
>  	"boot image via network using HTTP protocol",
>  	"[loadAddress] [[hostIPaddr:]path and image name]"
>  );
> @@ -376,6 +398,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
>  }
>
>  #if defined(CONFIG_CMD_PING)
> +#if defined(CONFIG_CMD_LWIP_REPLACE_PING)
> +extern int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> +			char *const argv[]);
> +#else
>  static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
>  		   char *const argv[])
>  {
> @@ -395,9 +421,15 @@ static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
>
>  	return CMD_RET_SUCCESS;
>  }
> +#endif
>
>  U_BOOT_CMD(
> -	ping,	2,	1,	do_ping,
> +	ping,	2,	1,
> +#if defined(CONFIG_CMD_LWIP_REPLACE_PING)
> +	do_lwip_ping,
> +#else
> +	do_ping,
> +#endif
>  	"send ICMP ECHO_REQUEST to network host",
>  	"pingAddress"
>  );
> diff --git a/include/net.h b/include/net.h
> index 1a99009959..8622983597 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -561,7 +561,7 @@ extern int		net_restart_wrap;	/* Tried all network devices */
>
>  enum proto_t {
>  	BOOTP, RARP, ARP, TFTPGET, DHCP, PING, PING6, DNS, NFS, CDP, NETCONS,
> -	SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, WGET
> +	SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, WGET, LWIP
>  };
>
>  extern char	net_boot_file_name[1024];/* Boot File name */
> diff --git a/lib/Kconfig b/lib/Kconfig
> index 3c5a4ab386..7485a1f3bf 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -1031,3 +1031,5 @@ menu "FWU Multi Bank Updates"
>  source lib/fwu_updates/Kconfig
>
>  endmenu
> +
> +source lib/lwip/Kconfig
> diff --git a/lib/Makefile b/lib/Makefile
> index d77b33e7f4..3b80a41187 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -91,6 +91,8 @@ obj-$(CONFIG_LIBAVB) += libavb/
>  obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/
>  obj-$(CONFIG_$(SPL_TPL_)OF_REAL) += fdtdec_common.o fdtdec.o
>
> +obj-y += lwip/
> +
>  ifdef CONFIG_SPL_BUILD
>  obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16-ccitt.o
>  obj-$(CONFIG_$(SPL_TPL_)HASH) += crc16-ccitt.o
> diff --git a/lib/lwip/Kconfig b/lib/lwip/Kconfig
> new file mode 100644
> index 0000000000..80d540ba54
> --- /dev/null
> +++ b/lib/lwip/Kconfig
> @@ -0,0 +1,108 @@
> +menu "LWIP"
> +config LWIP_LIB
> +	bool "Support LWIP library"
> +	help
> +	  Selecting this option will enable the shared LWIP library code.
> +
> +menu "LWIP options"
> +config LWIP_LIB_DEBUG
> +	bool "enable debug"
> +	default n
> +config LWIP_LIB_NOASSERT
> +	bool "disable asserts"
> +	default y
> +	help
> +	    Disabling asserts reduces binary size on 16k.
> +config LWIP_LIB_TCP
> +        bool "tcp"
> +        default y
> +config LWIP_LIB_UDP
> +        bool "udp"
> +        default y
> +config LWIP_LIB_DNS
> +        bool "dns"
> +        default n
> +config LWIP_LIB_DHCP
> +        bool "dhcp"
> +        default y
> +
> +config LWIP_LIB_LOOPBACK
> +        bool "loopback"
> +        default n
> +        help
> +	   Increases size on 1k.
> +config LWIP_LIB_SOCKET
> +        bool "socket API"
> +        default n
> +config LWIP_LIB_NETCONN
> +        bool "netconn API"
> +        default n
> +config LWIP_LIB_MEM_SIZE
> +	int "mem size"
> +	default 1600
> +	range 1 4096
> +	help
> +	    MEM_SIZE: the size of the heap memory. If the application will send
> +	    a lot of data that needs to be copied, this should be set high.
> +
> +config LWIP_LIB_PBUF_LINK_HLEN
> +        int "pbuf link hlen"
> +        default 14
> +        range 4 1024
> +        help
> +	   PBUF_LINK_HLEN: the number of bytes that should be allocated for a
> +           link level header. The default is 14, the standard value for Ethernet.
> +endmenu
> +
> +config CMD_LWIP
> +        bool "lwip cmd"
> +        default y
> +	depends on LWIP_LIB
> +        help
> +          lwip networking command.
> +
> +config CMD_LWIP_PING
> +        bool "ping"
> +        default y
> +	depends on CMD_LWIP
> +        help
> +          lwip ping command.
> +
> +config CMD_LWIP_REPLACE_PING
> +        bool "replace original ping command"
> +        default n
> +
> +config CMD_LWIP_WGET
> +        bool "wget"
> +        default y
> +	depends on CMD_LWIP
> +        help
> +          lwip wget command.
> +
> +config CMD_LWIP_REPLACE_WGET
> +	bool "replace original wget command"
> +	default n
> +
> +config CMD_LWIP_TFTP
> +        bool "tftp"
> +        default y
> +	depends on CMD_LWIP
> +        help
> +          lwip tftp command.
> +
> +config CMD_LWIP_REPLACE_TFTP
> +	bool "replace original tftp command"
> +	default n
> +
> +config CMD_LWIP_DHCP
> +        bool "dhcp"
> +        default y
> +	depends on CMD_LWIP
> +	depends on LWIP_LIB_DHCP
> +        help
> +          lwip dhcp command.
> +
> +config CMD_LWIP_REPLACE_DHCP
> +	bool "replace original dhcp command"
> +	default n
> +endmenu
> diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile
> new file mode 100644
> index 0000000000..6f68eb04ed
> --- /dev/null
> +++ b/lib/lwip/Makefile
> @@ -0,0 +1,98 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> +
> +LWIPDIR=lwip-external/src
> +
> +ccflags-y += -I$(CURDIR)/lib/lwip/port/include
> +ccflags-y += -I$(CURDIR)/lib/lwip/lwip-external/src/include -I$(CURDIR)/lib/lwip
> +
> +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/init.o \
> +	$(LWIPDIR)/core/def.o \
> +	$(LWIPDIR)/core/dns.o \
> +	$(LWIPDIR)/core/inet_chksum.o \
> +	$(LWIPDIR)/core/ip.o \
> +	$(LWIPDIR)/core/mem.o \
> +	$(LWIPDIR)/core/memp.o \
> +	$(LWIPDIR)/core/netif.o \
> +	$(LWIPDIR)/core/pbuf.o \
> +	$(LWIPDIR)/core/raw.o \
> +	$(LWIPDIR)/core/stats.o \
> +	$(LWIPDIR)/core/sys.o \
> +	$(LWIPDIR)/core/altcp.o \
> +	$(LWIPDIR)/core/altcp_alloc.o \
> +	$(LWIPDIR)/core/altcp_tcp.o \
> +	$(LWIPDIR)/core/tcp.o \
> +	$(LWIPDIR)/core/tcp_in.o \
> +	$(LWIPDIR)/core/tcp_out.o \
> +	$(LWIPDIR)/core/timeouts.o \
> +	$(LWIPDIR)/core/udp.o
> +
> +# IPv4
> +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/ipv4/acd.o \
> +        $(LWIPDIR)/core/ipv4/autoip.o \
> +        $(LWIPDIR)/core/ipv4/dhcp.o \
> +        $(LWIPDIR)/core/ipv4/etharp.o \
> +        $(LWIPDIR)/core/ipv4/icmp.o \
> +        $(LWIPDIR)/core/ipv4/igmp.o \
> +        $(LWIPDIR)/core/ipv4/ip4_frag.o \
> +        $(LWIPDIR)/core/ipv4/ip4.o \
> +        $(LWIPDIR)/core/ipv4/ip4_addr.o
> +# IPv6
> +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/ipv6/dhcp6.o \
> +        $(LWIPDIR)/core/ipv6/ethip6.o \
> +        $(LWIPDIR)/core/ipv6/icmp6.o \
> +        $(LWIPDIR)/core/ipv6/inet6.o \
> +        $(LWIPDIR)/core/ipv6/ip6.o \
> +        $(LWIPDIR)/core/ipv6/ip6_addr.o \
> +        $(LWIPDIR)/core/ipv6/ip6_frag.o \
> +        $(LWIPDIR)/core/ipv6/mld6.o \
> +        $(LWIPDIR)/core/ipv6/nd6.o
> +# API
> +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/api/api_lib.o \
> +	$(LWIPDIR)/api/api_msg.o \
> +	$(LWIPDIR)/api/err.o \
> +	$(LWIPDIR)/api/if_api.o \
> +	$(LWIPDIR)/api/netbuf.o \
> +	$(LWIPDIR)/api/netdb.o \
> +	$(LWIPDIR)/api/netifapi.o \
> +	$(LWIPDIR)/api/sockets.o \
> +	$(LWIPDIR)/api/tcpip.o
> +
> +# Netdevs
> +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/netif/ethernet.o
> +
> +obj-$(CONFIG_LWIP_LIB) += port/if.o
> +obj-$(CONFIG_LWIP_LIB) += port/sys-arch.o
> +
> +obj-$(CONFIG_CMD_LWIP) += cmd-lwip.o
> +
> +.PHONY: $(obj)/apps/ping/ping.c
> +$(obj)/apps/ping/ping.o: $(obj)/apps/ping/ping.c
> +$(obj)/apps/ping/ping.c:
> +	cp ./lib/lwip/lwip-external/contrib/apps/ping/ping.c $(obj)/apps/ping/ping.c
> +
> +obj-$(CONFIG_CMD_LWIP) += apps/ping/ping.o
> +obj-$(CONFIG_CMD_LWIP) += apps/ping/lwip_ping.o
> +
> +$(obj)/apps/http/http_clinet.o: $(obj)/apps/http/http_client.c
> +.PHONY: $(obj)/apps/http/http_client.c
> +$(obj)/apps/http/http_client.c:
> +	cp ./lib/lwip/lwip-external/src/apps/http/http_client.c $(obj)/apps/http/http_client.c
> +	cp ./lib/lwip/lwip-external/src/include/lwip/apps/http_client.h $(obj)/apps/http/http_client.h
> +
> +obj-$(CONFIG_CMD_LWIP_WGET) += apps/http/http_client.o
> +obj-$(CONFIG_CMD_LWIP_WGET) += apps/http/lwip-wget.o
> +
> +$(obj)/apps/tftp/tftp.o: $(obj)/apps/tftp/tftp.c
> +.PHONY: $(obj)/apps/tftp/tftp.c
> +$(obj)/apps/tftp/tftp.c:
> +	cp ./lib/lwip/lwip-external/src/apps/tftp/tftp.c $(obj)/apps/tftp/tftp.c
> +	cp ./lib/lwip/lwip-external/src/include/lwip/apps/tftp_client.h $(obj)/apps/tftp/tftp_client.h
> +	cp ./lib/lwip/lwip-external/src/include/lwip/apps/tftp_common.h $(obj)/apps/tftp/tftp_common.h
> +	cp ./lib/lwip/lwip-external/contrib/examples/tftp/tftp_example.h $(obj)/apps/tftp/tftp_example.h
> +
> +obj-$(CONFIG_CMD_LWIP_TFTP) += apps/tftp/tftp.o
> +obj-$(CONFIG_CMD_LWIP_TFTP) += apps/tftp/lwip-tftp.o
> +
> +obj-$(CONFIG_CMD_LWIP_DHCP) += apps/dhcp/lwip-dhcp.o
> diff --git a/lib/lwip/apps/dhcp/lwip-dhcp.c b/lib/lwip/apps/dhcp/lwip-dhcp.c
> new file mode 100644
> index 0000000000..2e4812c7dd
> --- /dev/null
> +++ b/lib/lwip/apps/dhcp/lwip-dhcp.c
> @@ -0,0 +1,52 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <console.h>
> +
> +#include <lwip/dhcp.h>
> +#include <lwip/prot/dhcp.h>
> +
> +#include "../../../lwip/ulwip.h"
> +
> +static struct dhcp dhcp;
> +static bool dhcp_is_set;
> +extern struct netif uboot_netif;
> +
> +static int ulwip_dhcp_tmo(void)
> +{
> +	switch (dhcp.state) {
> +	case DHCP_STATE_BOUND:
> +		env_set("bootfile", dhcp.boot_file_name);
> +		env_set("ipaddr", ip4addr_ntoa(&dhcp.offered_ip_addr));
> +		env_set("netmask", ip4addr_ntoa(&dhcp.offered_sn_mask));
> +		env_set("serverip", ip4addr_ntoa(&dhcp.server_ip_addr));
> +		printf("DHCP client bound to address %s\n", ip4addr_ntoa(&dhcp.offered_ip_addr));
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	return 0;
> +}
> +
> +int ulwip_dhcp(void)
> +{
> +	int err;
> +
> +	ulwip_set_tmo(ulwip_dhcp_tmo);
> +
> +	if (!dhcp_is_set) {
> +		dhcp_set_struct(&uboot_netif, &dhcp);
> +		dhcp_is_set = true;
> +	}
> +	err = dhcp_start(&uboot_netif);
> +	if (err)
> +		printf("dhcp_start error %d\n", err);
> +
> +	return err;
> +}
> diff --git a/lib/lwip/apps/http/lwip-wget.c b/lib/lwip/apps/http/lwip-wget.c
> new file mode 100644
> index 0000000000..07aabd15f3
> --- /dev/null
> +++ b/lib/lwip/apps/http/lwip-wget.c
> @@ -0,0 +1,71 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <console.h>
> +
> +#include "http_client.h"
> +#include "../../../lwip/ulwip.h"
> +
> +static ulong daddr;
> +static httpc_connection_t settings;
> +
> +static err_t httpc_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *p, err_t err)
> +{
> +	struct pbuf *q;
> +	LWIP_UNUSED_ARG(err);
> +
> +	if (!p)
> +		return ERR_BUF;
> +
> +	for (q = p; q != NULL; q = q->next) {
> +		memcpy((void *)daddr, q->payload, q->len);
> +		printf("downloaded chunk size %d, to addr 0x%lx\n", q->len, daddr);
> +		daddr += q->len;
> +	}
> +	altcp_recved(pcb, p->tot_len);
> +	pbuf_free(p);
> +	return ERR_OK;
> +}
> +
> +static void httpc_result(void *arg, httpc_result_t httpc_result, u32_t rx_content_len,
> +			 u32_t srv_res, err_t err)
> +{
> +	if (httpc_result == HTTPC_RESULT_OK) {
> +		printf("\n%d bytes successfully downloaded.\n", rx_content_len);
> +		ulwip_exit(0);
> +	} else {
> +		printf("\nhttp eroror: %d\n", httpc_result);
> +		ulwip_exit(-1);
> +	}
> +}
> +
> +int lwip_wget(ulong addr, char *url)
> +{
> +	err_t err;
> +	int port = 80;
> +	char *server_name;
> +	httpc_state_t *connection;
> +
> +	daddr = addr;
> +	server_name = env_get("serverip");
> +	if (!server_name) {
> +		printf("error: serverip variable has to be set\n");
> +		return CMD_RET_FAILURE;
> +	}
> +
> +	printf("downloading %s to addr 0x%lx\n", url, addr);
> +	memset(&settings, 0, sizeof(httpc_connection_t));
> +	settings.result_fn = httpc_result;
> +	err = httpc_get_file_dns(server_name, port, url, &settings,
> +				 httpc_recv, NULL,  &connection);
> +	if (err != ERR_OK) {
> +		printf("httpc_init_connection failed\n");
> +		return err;
> +	}
> +	return 0;
> +}
> diff --git a/lib/lwip/apps/ping/lwip_ping.c b/lib/lwip/apps/ping/lwip_ping.c
> new file mode 100644
> index 0000000000..a05dc76326
> --- /dev/null
> +++ b/lib/lwip/apps/ping/lwip_ping.c
> @@ -0,0 +1,37 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#include "lwip/opt.h"
> +#include "lwip/ip_addr.h"
> +#include "ping.h"
> +
> +#include "../../../lwip/ulwip.h"
> +
> +static ip_addr_t ip_target;
> +
> +static int ulwip_ping_tmo(void)
> +{
> +
> +	printf("ping failed; host %s is not alive\n", ipaddr_ntoa(&ip_target));
> +	return 0;
> +}
> +
> +int lwip_ping_init(char *ping_addr)
> +{
> +	int err;
> +
> +	err = ipaddr_aton(ping_addr, &ip_target);
> +	if (err == 0) {
> +		printf("wrong ping addr string \"%s\" \n", ping_addr);
> +		return -1;
> +	}
> +
> +	ulwip_set_tmo(ulwip_ping_tmo);
> +
> +	ping_init(&ip_target);
> +
> +	return 0;
> +}
> diff --git a/lib/lwip/apps/ping/lwip_ping.h b/lib/lwip/apps/ping/lwip_ping.h
> new file mode 100644
> index 0000000000..7f08095427
> --- /dev/null
> +++ b/lib/lwip/apps/ping/lwip_ping.h
> @@ -0,0 +1,24 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#ifndef LWIP_PING_H
> +#define LWIP_PING_H
> +
> +#include <lwip/ip_addr.h>
> +
> +/**
> + * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used
> + */
> +#ifndef PING_USE_SOCKETS
> +#define PING_USE_SOCKETS   0
> +#endif
> +
> +int lwip_ping_init(char *ping_addr);
> +
> +void ping_raw_init(void);
> +void ping_send_now(void);
> +
> +#endif /* LWIP_PING_H */
> diff --git a/lib/lwip/apps/ping/ping.h b/lib/lwip/apps/ping/ping.h
> new file mode 100644
> index 0000000000..0dd4bd78c7
> --- /dev/null
> +++ b/lib/lwip/apps/ping/ping.h
> @@ -0,0 +1,35 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#include "../../../lwip/ulwip.h"
> +
> +#include "lwip/prot/ip4.h"
> +
> +#define ip4_print_parts(a, b, c, d) \
> +	printf("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, a, b, c, d);
> +
> +#define ip4_print(ipaddr) \
> +	ip4_print_parts(\
> +			(u16_t)((ipaddr) != NULL ? ip4_addr1_16(ipaddr) : 0), \
> +			(u16_t)((ipaddr) != NULL ? ip4_addr2_16(ipaddr) : 0), \
> +			(u16_t)((ipaddr) != NULL ? ip4_addr3_16(ipaddr) : 0), \
> +			(u16_t)((ipaddr) != NULL ? ip4_addr4_16(ipaddr) : 0))
> +
> +
> +#define LWIP_DEBUG 1 /* ping_time is under ifdef*/
> +#define PING_RESULT(cond) { \
> +	if (cond == 1) { \
> +		printf("host "); \
> +		ip4_print(addr); \
> +		printf(" is alive\n"); \
> +		printf(" %"U32_F" ms\n", (sys_now() - ping_time)); \
> +		ulwip_exit(0); \
> +	} else { \
> +		printf("ping failed; host "); \
> +		ip4_print(addr); \
> +		printf(" is not alive\n"); \
> +		ulwip_exit(-1); \
> +	} \
> +     } while (0);
> +
> +#include "lwip/ip_addr.h"
> +void ping_init(const ip_addr_t *ping_addr);
> diff --git a/lib/lwip/apps/tftp/lwip-tftp.c b/lib/lwip/apps/tftp/lwip-tftp.c
> new file mode 100644
> index 0000000000..c38e83c8ee
> --- /dev/null
> +++ b/lib/lwip/apps/tftp/lwip-tftp.c
> @@ -0,0 +1,121 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <console.h>
> +
> +#include "lwip/apps/tftp_client.h"
> +#include "lwip/apps/tftp_server.h"
> +#include "tftp_example.h"
> +
> +#include <string.h>
> +
> +#include "../../../lwip/ulwip.h"
> +
> +#if LWIP_UDP
> +
> +static ulong daddr;
> +static ulong size;
> +
> +static void *tftp_open(const char *fname, const char *mode, u8_t is_write)
> +{
> +	LWIP_UNUSED_ARG(mode);
> +	return NULL;
> +}
> +
> +static void tftp_close(void *handle)
> +{
> +	printf("\ndone\n");
> +	printf("Bytes transferred = %ld (0x%lx hex)\n", size, size);
> +	ulwip_exit(0);
> +}
> +
> +static int tftp_read(void *handle, void *buf, int bytes)
> +{
> +	return 0;
> +}
> +
> +static int tftp_write(void *handle, struct pbuf *p)
> +{
> +	struct pbuf *q;
> +
> +	for (q = p; q != NULL; q = q->next) {
> +		memcpy((void *)daddr, q->payload, q->len);
> +		/* printf("downloaded chunk size %d, to addr 0x%lx\n", q->len, daddr); */
> +		daddr += q->len;
> +		size += q->len;
> +		printf("#");
> +	}
> +
> +	return 0;
> +}
> +
> +/* For TFTP client only */
> +static void tftp_error(void *handle, int err, const char *msg, int size)
> +{
> +	char message[100];
> +
> +	LWIP_UNUSED_ARG(handle);
> +
> +	memset(message, 0, sizeof(message));
> +	MEMCPY(message, msg, LWIP_MIN(sizeof(message)-1, (size_t)size));
> +
> +	printf("TFTP error: %d (%s)", err, message);
> +}
> +
> +static const struct tftp_context tftp = {
> +	tftp_open,
> +	tftp_close,
> +	tftp_read,
> +	tftp_write,
> +	tftp_error
> +};
> +
> +int lwip_tftp(ulong addr, char *fname)
> +{
> +	void *f = (void *)0x1; /*fake handle*/
> +	err_t err;
> +	ip_addr_t srv;
> +	int ret;
> +	char *server_ip;
> +
> +	if (!fname || addr == 0)
> +		return CMD_RET_FAILURE;
> +
> +	size = 0;
> +	daddr = addr;
> +	server_ip = env_get("serverip");
> +	if (!server_ip) {
> +		printf("error: serverip variable has to be set\n");
> +		return CMD_RET_FAILURE;
> +	}
> +
> +	ret = ipaddr_aton(server_ip, &srv);
> +	LWIP_ASSERT("ipaddr_aton failed", ret == 1);
> +
> +	printf("TFTP from server %s; our IP address is %s\n",
> +			server_ip, env_get("ipaddr"));
> +	printf("Filename '%s'.\n", fname);
> +	printf("Load address: 0x%lx\n", daddr);
> +	printf("Loading:");
> +
> +	err = tftp_init_client(&tftp);
> +	if (!(err == ERR_OK || err == ERR_USE))
> +		printf("tftp_init_client err: %d\n", err);
> +
> +	err = tftp_get(f, &srv, TFTP_PORT, fname, TFTP_MODE_OCTET);
> +	/* might return different errors, like routing problems */
> +	if (err != ERR_OK) {
> +		printf("tftp_get err=%d\n", err);
> +	}
> +	LWIP_ASSERT("tftp_get failed", err == ERR_OK);
> +
> +	return err;
> +}
> +#else
> +#error "UDP has to be supported"
> +#endif /* LWIP_UDP */
> diff --git a/lib/lwip/cmd-lwip.c b/lib/lwip/cmd-lwip.c
> new file mode 100644
> index 0000000000..d7cdc4e411
> --- /dev/null
> +++ b/lib/lwip/cmd-lwip.c
> @@ -0,0 +1,276 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * (C) Copyright 2023 Maxim Uvarov, maxim.uvarov@linaro.org
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <console.h>
> +#include <display_options.h>
> +#include <memalign.h>
> +#include <net.h>
> +#include <image.h>
> +
> +#include "apps/ping/lwip_ping.h"
> +#include "ulwip.h"
> +
> +extern int uboot_lwip_init(void);
> +extern int uboot_lwip_loop_is_done(void);
> +
> +static int do_lwip_info(struct cmd_tbl *cmdtp, int flag, int argc,
> +		      char *const argv[])
> +{
> +	printf("TBD: %s\n", __func__);
> +	return CMD_RET_SUCCESS;
> +}
> +
> +static int do_lwip_init(struct cmd_tbl *cmdtp, int flag, int argc,
> +		      char *const argv[])
> +{
> +	if (!uboot_lwip_init())
> +		return CMD_RET_SUCCESS;
> +	return CMD_RET_FAILURE;
> +}
> +
> +static int lwip_empty_tmo(void) { return 0; };
> +int (*ulwip_tmo)(void) = lwip_empty_tmo;
> +void ulwip_set_tmo(int (*tmo)(void))
> +{
> +	ulwip_tmo = tmo;
> +}
> +
> +static void ulwip_clear_tmo(void)
> +{
> +	ulwip_tmo = lwip_empty_tmo;
> +}
> +
> +static void ulwip_timeout_handler(void)
> +{
> +	eth_halt();
> +	ulwip_tmo();
> +	net_set_state(NETLOOP_FAIL);	/* we did not get the reply */
> +	ulwip_loop_set(0);
> +}
> +
> +static int ulwip_loop(void)
> +{
> +	ulwip_loop_set(1);
> +	if (net_loop(LWIP) < 0) {
> +		ulwip_loop_set(0);
> +		return CMD_RET_FAILURE;
> +	}
> +	ulwip_loop_set(0);
> +	return CMD_RET_SUCCESS;
> +}
> +
> +#if !defined(CONFIG_CMD_LWIP_REPLACE_PING)
> +static
> +#endif
> +int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> +		 char *const argv[])
> +{
> +	if (argc < 2) {
> +		printf("argc = %d, error\n", argc);
> +		return CMD_RET_USAGE;
> +	}
> +
> +	uboot_lwip_init();
> +
> +	eth_init(); /* activate u-boot eth dev */
> +
> +	printf("Using %s device\n", eth_get_name());
> +	printf("pinging addr: %s\n", argv[1]);
> +
> +	net_set_timeout_handler(1000UL, ulwip_timeout_handler);
> +
> +	if (lwip_ping_init(argv[1])) {
> +		printf("ping init fail\n");
> +		return CMD_RET_FAILURE;
> +	}
> +
> +	ping_send_now();
> +
> +	return ulwip_loop();
> +}
> +
> +extern int lwip_wget(ulong addr, char *url);
> +
> +#if !defined(CONFIG_CMD_LWIP_REPLACE_WGET)
> +static
> +#endif
> +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
> +		 char *const argv[])
> +{
> +	char *url;
> +
> +	if (argc < 2) {
> +		printf("argc = %d, error\n", argc);
> +		return CMD_RET_USAGE;
> +	}
> +	url = argv[1];
> +
> +	uboot_lwip_init();
> +
> +	eth_init(); /* activate u-boot eth dev */
> +
> +	lwip_wget(image_load_addr, url);
> +
> +	return ulwip_loop();
> +}
> +
> +#if defined(CONFIG_CMD_LWIP_TFTP)
> +extern int lwip_tftp(ulong addr, char *filename);
> +#if !defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
> +static
> +#endif
> +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc,
> +		 char *const argv[])
> +{
> +	char *filename;
> +	ulong addr;
> +	char *end;
> +	int ret;
> +
> +	switch (argc) {
> +	case 1:
> +		filename = env_get("bootfile");
> +		break;
> +	case 2:
> +		/*
> +		 * Only one arg - accept two forms:
> +		 * Just load address, or just boot file name. The latter
> +		 * form must be written in a format which can not be
> +		 * mis-interpreted as a valid number.
> +		 */
> +		addr = hextoul(argv[1], &end);
> +		if (end == (argv[1] + strlen(argv[1]))) {
> +			image_load_addr = addr;
> +			filename = env_get("bootfile");
> +		} else {
> +			filename = argv[1];
> +		}
> +		break;
> +	case 3:
> +		image_load_addr = hextoul(argv[1], NULL);
> +		filename = argv[2];
> +		break;
> +	default:
> +		return CMD_RET_USAGE;
> +	}
> +
> +	uboot_lwip_init();
> +
> +	eth_init(); /* activate u-boot eth dev */
> +
> +	ret = lwip_tftp(image_load_addr, filename);
> +	if (ret)
> +		return ret;
> +
> +	return ulwip_loop();
> +}
> +#endif
> +
> +#if defined(CONFIG_CMD_LWIP_DHCP)
> +extern int ulwip_dhcp(void);
> +
> +#if !defined(CONFIG_CMD_LWIP_REPLACE_DHCP)
> +static
> +#endif
> +int do_lwip_dhcp(void)
> +{
> +	int ret;
> +	char *filename;
> +
> +	uboot_lwip_init();
> +
> +	ret = ulwip_dhcp();
> +
> +	net_set_timeout_handler(2000UL, ulwip_timeout_handler);
> +
> +	ulwip_loop();
> +	if (IS_ENABLED(CONFIG_CMD_LWIP_TFTP)) {
> +		ulwip_clear_tmo();
> +
> +		filename = env_get("bootfile");
> +		if (!filename) {
> +			printf("no bootfile\n");
> +			return CMD_RET_FAILURE;
> +		}
> +
> +		eth_init(); /* activate u-boot eth dev */
> +		net_set_timeout_handler(20000UL, ulwip_timeout_handler);
> +		lwip_tftp(image_load_addr, filename);
> +
> +		ret =  ulwip_loop();
> +	}
> +
> +	return ret;
> +}
> +
> +static int _do_lwip_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
> +		char *const argv[])
> +{
> +	return do_lwip_dhcp();
> +}
> +#endif
> +
> +static struct cmd_tbl cmds[] = {
> +	U_BOOT_CMD_MKENT(info, 1, 0, do_lwip_info, "Info and stats", ""),
> +	U_BOOT_CMD_MKENT(init, 1, 0, do_lwip_init,
> +			 "initialize lwip stack", ""),
> +#if defined(CONFIG_CMD_LWIP_PING)
> +	U_BOOT_CMD_MKENT(ping, 2, 0, do_lwip_ping,
> +			 "send ICMP ECHO_REQUEST to network host",
> +			 "pingAddress"),
> +#endif
> +#if defined(CONFIG_CMD_LWIP_WGET)
> +	U_BOOT_CMD_MKENT(wget, 2, 0, do_lwip_wget, "", ""),
> +#endif
> +#if defined(CONFIG_CMD_LWIP_TFTP)
> +	U_BOOT_CMD_MKENT(tftp, 3, 0, do_lwip_tftp,
> +			"boot image via network using TFTP protocol\n",
> +			"[loadAddress] [[hostIPaddr:]bootfilename]"),
> +#endif
> +#if defined(CONFIG_CMD_LWIP_DHCP)
> +	U_BOOT_CMD_MKENT(dhcp, 1, 0, _do_lwip_dhcp,
> +			"boot image via network using DHCP/TFTP protocol",
> +			""),
> +#endif
> +};
> +
> +static int do_ops(struct cmd_tbl *cmdtp, int flag, int argc,
> +		     char *const argv[])
> +{
> +	struct cmd_tbl *cp;
> +
> +	cp = find_cmd_tbl(argv[1], cmds, ARRAY_SIZE(cmds));
> +
> +	argc--;
> +	argv++;
> +
> +	if (cp == NULL || argc > cp->maxargs)
> +		return CMD_RET_USAGE;
> +	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
> +		return CMD_RET_SUCCESS;
> +
> +	return cp->cmd(cmdtp, flag, argc, argv);
> +}
> +
> +U_BOOT_CMD(
> +	lwip, 4, 1, do_ops,
> +	"LWIP sub system",
> +	"info - display info\n"
> +	"init - init LWIP\n"
> +	"ping addr - pingAddress\n"
> +	"wget http://IPadress/url/\n"
> +	"tftp [loadAddress] [[hostIPaddr:]bootfilename]\n"
> +	"dhcp - boot image via network using DHCP/TFTP protocol\n"
> +	);
> +
> +/* Old command kept for compatibility. Same as 'mmc info' */
> +U_BOOT_CMD(
> +	lwipinfo, 1, 0, do_lwip_info,
> +	"display LWIP info",
> +	"- display LWIP stack info"
> +);
> diff --git a/lib/lwip/lwipopts.h b/lib/lwip/lwipopts.h
> new file mode 100644
> index 0000000000..b943d7b9be
> --- /dev/null
> +++ b/lib/lwip/lwipopts.h
> @@ -0,0 +1,203 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#ifndef LWIP_LWIPOPTS_H
> +#define LWIP_LWIPOPTS_H
> +
> +#include "lwipopts.h"
> +
> +#if defined(CONFIG_LWIP_LIB_DEBUG)
> +#define LWIP_DEBUG 1
> +#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
> +#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON
> +#define ETHARP_DEBUG                    LWIP_DBG_OFF
> +#define NETIF_DEBUG                     LWIP_DBG_OFF
> +#define PBUF_DEBUG                      LWIP_DBG_OFF
> +#define API_LIB_DEBUG                   LWIP_DBG_OFF
> +#define API_MSG_DEBUG                   LWIP_DBG_OFF
> +#define SOCKETS_DEBUG                   LWIP_DBG_OFF
> +#define ICMP_DEBUG                      LWIP_DBG_OFF
> +#define IGMP_DEBUG                      LWIP_DBG_OFF
> +#define INET_DEBUG                      LWIP_DBG_OFF
> +#define IP_DEBUG                        LWIP_DBG_OFF
> +#define IP_REASS_DEBUG                  LWIP_DBG_OFF
> +#define RAW_DEBUG                       LWIP_DBG_OFF
> +#define MEM_DEBUG                       LWIP_DBG_OFF
> +#define MEMP_DEBUG                      LWIP_DBG_OFF
> +#define SYS_DEBUG                       LWIP_DBG_OFF
> +#define TIMERS_DEBUG                    LWIP_DBG_OFF
> +#define TCP_DEBUG                       LWIP_DBG_OFF
> +#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF
> +#define TCP_FR_DEBUG                    LWIP_DBG_OFF
> +#define TCP_RTO_DEBUG                   LWIP_DBG_OFF
> +#define TCP_CWND_DEBUG                  LWIP_DBG_OFF
> +#define TCP_WND_DEBUG                   LWIP_DBG_OFF
> +#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF
> +#define TCP_RST_DEBUG                   LWIP_DBG_OFF
> +#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF
> +#define UDP_DEBUG                       LWIP_DBG_OFF
> +#define TCPIP_DEBUG                     LWIP_DBG_OFF
> +#define SLIP_DEBUG                      LWIP_DBG_OFF
> +#define DHCP_DEBUG                      LWIP_DBG_ON
> +#define AUTOIP_DEBUG                    LWIP_DBG_ON
> +#define DNS_DEBUG                       LWIP_DBG_OFF
> +#define IP6_DEBUG                       LWIP_DBG_OFF
> +#define DHCP6_DEBUG                     LWIP_DBG_OFF
> +#else
> +#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
> +#define LWIP_DBG_TYPES_ON               LWIP_DBG_OFF
> +#define ETHARP_DEBUG                    LWIP_DBG_OFF
> +#define NETIF_DEBUG                     LWIP_DBG_OFF
> +#define PBUF_DEBUG                      LWIP_DBG_OFF
> +#define API_LIB_DEBUG                   LWIP_DBG_OFF
> +#define API_MSG_DEBUG                   LWIP_DBG_OFF
> +#define SOCKETS_DEBUG                   LWIP_DBG_OFF
> +#define ICMP_DEBUG                      LWIP_DBG_OFF
> +#define IGMP_DEBUG                      LWIP_DBG_OFF
> +#define INET_DEBUG                      LWIP_DBG_OFF
> +#define IP_DEBUG                        LWIP_DBG_OFF
> +#define IP_REASS_DEBUG                  LWIP_DBG_OFF
> +#define RAW_DEBUG                       LWIP_DBG_OFF
> +#define MEM_DEBUG                       LWIP_DBG_OFF
> +#define MEMP_DEBUG                      LWIP_DBG_OFF
> +#define SYS_DEBUG                       LWIP_DBG_OFF
> +#define TIMERS_DEBUG                    LWIP_DBG_OFF
> +#define TCP_DEBUG                       LWIP_DBG_OFF
> +#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF
> +#define TCP_FR_DEBUG                    LWIP_DBG_OFF
> +#define TCP_RTO_DEBUG                   LWIP_DBG_OFF
> +#define TCP_CWND_DEBUG                  LWIP_DBG_OFF
> +#define TCP_WND_DEBUG                   LWIP_DBG_OFF
> +#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF
> +#define TCP_RST_DEBUG                   LWIP_DBG_OFF
> +#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF
> +#define UDP_DEBUG                       LWIP_DBG_OFF
> +#define TCPIP_DEBUG                     LWIP_DBG_OFF
> +#define SLIP_DEBUG                      LWIP_DBG_OFF
> +#define DHCP_DEBUG                      LWIP_DBG_OFF
> +#define AUTOIP_DEBUG                    LWIP_DBG_OFF
> +#define DNS_DEBUG                       LWIP_DBG_OFF
> +#define IP6_DEBUG                       LWIP_DBG_OFF
> +#define DHCP6_DEBUG                     LWIP_DBG_OFF
> +#endif
> +#define LWIP_TESTMODE                   0
> +
> +#if defined(CONFIG_LWIP_LIB_NOASSERT)
> +#define LWIP_NOASSERT 1
> +#define LWIP_ASSERT(message, assertion)
> +#endif
> +
> +#include "lwip/debug.h"
> +
> +#define SYS_LIGHTWEIGHT_PROT            0
> +#define NO_SYS                          0
> +
> +#define MEM_ALIGNMENT                   1
> +#define MEM_SIZE                        CONFIG_LWIP_LIB_MEM_SIZE
> +
> +#define MEMP_NUM_PBUF                   4
> +#define MEMP_NUM_RAW_PCB                2
> +#define MEMP_NUM_UDP_PCB                4
> +#define MEMP_NUM_TCP_PCB                2
> +#define MEMP_NUM_TCP_PCB_LISTEN         2
> +#define MEMP_NUM_TCP_SEG                16
> +#define MEMP_NUM_REASSDATA              1
> +#define MEMP_NUM_ARP_QUEUE              2
> +#define MEMP_NUM_SYS_TIMEOUT            4
> +#define MEMP_NUM_NETBUF                 2
> +#define MEMP_NUM_NETCONN               32
> +#define MEMP_NUM_TCPIP_MSG_API          8
> +#define MEMP_NUM_TCPIP_MSG_INPKT        8
> +#define PBUF_POOL_SIZE                  8
> +
> +#define LWIP_ARP                        1
> +
> +#define IP_FORWARD                      0
> +#define IP_OPTIONS_ALLOWED              1
> +#define IP_REASSEMBLY                   1
> +#define IP_FRAG                         1
> +#define IP_REASS_MAXAGE                 3
> +#define IP_REASS_MAX_PBUFS              4
> +#define IP_FRAG_USES_STATIC_BUF         0
> +
> +#define IP_DEFAULT_TTL                  255
> +
> +#define LWIP_ICMP                       1
> +
> +#define LWIP_RAW                        1
> +
> +#if defined(CONFIG_LWIP_LIB_DHCP)
> +#define LWIP_DHCP                       1
> +#define LWIP_DHCP_BOOTP_FILE		1
> +#else
> +#define LWIP_DHCP                       0
> +#endif
> +#define LWIP_DHCP_DOES_ACD_CHECK	0
> +
> +#define LWIP_AUTOIP                     0
> +
> +#define LWIP_SNMP                       0
> +
> +#define LWIP_IGMP                       0
> +
> +#if defined(CONFIG_LWIP_LIB_DNS)
> +#define LWIP_DNS                        1
> +#else
> +#define LWIP_DNS                        0
> +#endif
> +
> +#if defined(CONFIG_LWIP_LIB_TCP)
> +#define LWIP_UDP                        1
> +#else
> +#define LWIP_UDP                        0
> +#endif
> +
> +#if defined(CONFIG_LWIP_LIB_TCP)
> +#define LWIP_TCP                        1
> +#else
> +#define LWIP_TCP                        0
> +#endif
> +
> +#define LWIP_LISTEN_BACKLOG             0
> +
> +#define PBUF_LINK_HLEN                  CONFIG_LWIP_LIB_PBUF_LINK_HLEN
> +#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS + 40 + PBUF_LINK_HLEN)
> +
> +#define LWIP_HAVE_LOOPIF                0
> +
> +#if defined(CONFIG_LWIP_LIB_NETCONN)
> +#define LWIP_NETCONN                    1
> +#else
> +#define LWIP_NETCONN                    0
> +#define LWIP_DISABLE_MEMP_SANITY_CHECKS 1
> +#endif
> +
> +#if defined(CONFIG_LWIP_LIB_SOCKET)
> +#define LWIP_SOCKET                     1
> +
> +#define SO_REUSE                        1
> +#else
> +#define LWIP_SOCKET                     0
> +#define SO_REUSE                        0
> +#endif
> +
> +#define LWIP_STATS                      0
> +
> +#define PPP_SUPPORT                     0
> +
> +#define LWIP_TCPIP_CORE_LOCKING		0
> +
> +#if defined(CONFIG_LWIP_LIB_LOOPBACK)
> +#define LWIP_NETIF_LOOPBACK		1
> +#else
> +#define LWIP_NETIF_LOOPBACK		0
> +#endif
> +/* use malloc instead of pool */
> +#define MEMP_MEM_MALLOC                 1
> +#define MEMP_MEM_INIT			1
> +#define MEM_LIBC_MALLOC			1
> +
> +#endif /* LWIP_LWIPOPTS_H */
> diff --git a/lib/lwip/port/if.c b/lib/lwip/port/if.c
> new file mode 100644
> index 0000000000..15d44054be
> --- /dev/null
> +++ b/lib/lwip/port/if.c
> @@ -0,0 +1,260 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +extern int eth_init(void); /* net.h */
> +extern void string_to_enetaddr(const char *addr, uint8_t *enetaddr); /* net.h */
> +extern struct in_addr net_ip;
> +extern u8 net_ethaddr[6];
> +
> +#include "lwip/debug.h"
> +#include "lwip/arch.h"
> +#include "netif/etharp.h"
> +#include "lwip/stats.h"
> +#include "lwip/def.h"
> +#include "lwip/mem.h"
> +#include "lwip/pbuf.h"
> +#include "lwip/sys.h"
> +#include "lwip/netif.h"
> +
> +#include "lwip/ip.h"
> +
> +#define IFNAME0 'e'
> +#define IFNAME1 '0'
> +
> +static struct pbuf *low_level_input(struct netif *netif);
> +static int uboot_net_use_lwip;
> +
> +int ulwip_enabled(void)
> +{
> +	return uboot_net_use_lwip;
> +}
> +
> +/* 1 - in loop
> + * 0 - no loop
> + */
> +static int loop_lwip;
> +
> +/* ret 1 - in loop
> + *     0 - no loop
> + */
> +int ulwip_in_loop(void)
> +{
> +	return loop_lwip;
> +}
> +
> +void ulwip_loop_set(int loop)
> +{
> +	loop_lwip = loop;
> +}
> +
> +static int ulwip_app_err;
> +
> +void ulwip_exit(int err)
> +{
> +	ulwip_app_err = err;
> +	ulwip_loop_set(0);
> +}
> +
> +int ulwip_app_get_err(void)
> +{
> +	return ulwip_app_err;
> +}
> +
> +struct uboot_lwip_if {
> +};
> +
> +#if defined(CONFIG_CMD_LWIP_DHCP)
> +struct netif uboot_netif;
> +#else
> +static struct netif uboot_netif;
> +#endif
> +
> +#define LWIP_PORT_INIT_NETMASK(addr)  IP4_ADDR((addr), 255, 255, 255, 0)
> +
> +extern uchar *net_rx_packet;
> +extern int    net_rx_packet_len;
> +
> +int uboot_lwip_poll(void)
> +{
> +	struct pbuf *p;
> +	int err;
> +
> +	p = low_level_input(&uboot_netif);
> +	if (!p) {
> +		printf("error p = low_level_input = NULL\n");
> +		return 0;
> +	}
> +
> +	err = ethernet_input(p, &uboot_netif);
> +	if (err)
> +		printf("ip4_input err %d\n", err);
> +
> +	return 0;
> +}
> +
> +static struct pbuf *low_level_input(struct netif *netif)
> +{
> +	struct pbuf *p, *q;
> +	u16_t len = net_rx_packet_len;
> +	uchar *data = net_rx_packet;
> +
> +#if ETH_PAD_SIZE
> +	len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
> +#endif
> +
> +	/* We allocate a pbuf chain of pbufs from the pool. */
> +	p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
> +	if (p) {
> +#if ETH_PAD_SIZE
> +		pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding word */
> +#endif
> +		/* We iterate over the pbuf chain until we have read the entire
> +		 * packet into the pbuf.
> +		 */
> +		for (q = p; q != NULL; q = q->next) {
> +			/* Read enough bytes to fill this pbuf in the chain. The
> +			 * available data in the pbuf is given by the q->len
> +			 * variable.
> +			 * This does not necessarily have to be a memcpy, you can also preallocate
> +			 * pbufs for a DMA-enabled MAC and after receiving truncate it to the
> +			 * actually received size. In this case, ensure the tot_len member of the
> +			 * pbuf is the sum of the chained pbuf len members.
> +			 */
> +			MEMCPY(q->payload, data, q->len);
> +			data += q->len;
> +		}
> +		//acknowledge that packet has been read();
> +
> +#if ETH_PAD_SIZE
> +		pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
> +#endif
> +		LINK_STATS_INC(link.recv);
> +	} else {
> +		//drop packet();
> +		LINK_STATS_INC(link.memerr);
> +		LINK_STATS_INC(link.drop);
> +	}
> +
> +	return p;
> +}
> +
> +static int ethernetif_input(struct pbuf *p, struct netif *netif)
> +{
> +	struct ethernetif *ethernetif;
> +
> +	ethernetif = netif->state;
> +
> +	/* move received packet into a new pbuf */
> +	p = low_level_input(netif);
> +
> +	/* if no packet could be read, silently ignore this */
> +	if (p) {
> +		/* pass all packets to ethernet_input, which decides what packets it supports */
> +		if (netif->input(p, netif) != ERR_OK) {
> +			LWIP_DEBUGF(NETIF_DEBUG, ("%s: IP input error\n", __func__));
> +			pbuf_free(p);
> +			p = NULL;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static err_t low_level_output(struct netif *netif, struct pbuf *p)
> +{
> +	int err;
> +
> +	err = eth_send(p->payload, p->len);
> +	if (err != 0) {
> +		printf("eth_send error %d\n", err);
> +		return ERR_ABRT;
> +	}
> +	return ERR_OK;
> +}
> +
> +err_t uboot_lwip_if_init(struct netif *netif)
> +{
> +	struct uboot_lwip_if *uif = (struct uboot_lwip_if *)malloc(sizeof(struct uboot_lwip_if));
> +
> +	if (!uif) {
> +		printf("uboot_lwip_if: out of memory\n");
> +		return ERR_MEM;
> +	}
> +	netif->state = uif;
> +
> +	netif->name[0] = IFNAME0;
> +	netif->name[1] = IFNAME1;
> +
> +	netif->hwaddr_len = ETHARP_HWADDR_LEN;
> +	string_to_enetaddr(env_get("ethaddr"), netif->hwaddr);
> +#if defined(CONFIG_LWIP_LIB_DEBUG)
> +	printf("              MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
> +	       netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2],
> +	       netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]);
> +#endif
> +
> +#if LWIP_IPV4
> +	netif->output = etharp_output;
> +#endif /* LWIP_IPV4 */
> +#if LWIP_IPV6
> +	netif->output_ip6 = ethip6_output;
> +#endif /* LWIP_IPV6 */
> +	netif->linkoutput = low_level_output;
> +	netif->mtu = 1500;
> +	netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
> +
> +	eth_init(); /* activate u-boot eth dev */
> +
> +	if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) {
> +		printf("Initialized LWIP stack\n");
> +	}
> +
> +	return ERR_OK;
> +}
> +
> +int uboot_lwip_init(void)
> +{
> +	ip4_addr_t ipaddr, netmask, gw;
> +
> +	if (uboot_net_use_lwip)
> +		return CMD_RET_SUCCESS;
> +
> +	ip4_addr_set_zero(&gw);
> +	ip4_addr_set_zero(&ipaddr);
> +	ip4_addr_set_zero(&netmask);
> +
> +	ipaddr_aton(env_get("ipaddr"), &ipaddr);
> +	ipaddr_aton(env_get("ipaddr"), &netmask);
> +
> +	LWIP_PORT_INIT_NETMASK(&netmask);
> +	if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) {
> +		printf("Starting lwIP, IP: %s\n", ip4addr_ntoa(&ipaddr));
> +		printf("               GW: %s\n", ip4addr_ntoa(&gw));
> +		printf("             mask: %s\n", ip4addr_ntoa(&netmask));
> +	}
> +
> +	if (!netif_add(&uboot_netif, &ipaddr, &netmask, &gw,
> +		       &uboot_netif, uboot_lwip_if_init, ethernetif_input))
> +		printf("err: netif_add failed!\n");
> +
> +	netif_set_up(&uboot_netif);
> +	netif_set_link_up(&uboot_netif);
> +#if LWIP_IPV6
> +	netif_create_ip6_linklocal_address(&uboot_netif, 1);
> +	printf("             IPv6: %s\n", ip6addr_ntoa(netif_ip6_addr(uboot_netif, 0)));
> +#endif /* LWIP_IPV6 */
> +
> +	uboot_net_use_lwip = 1;
> +
> +	return CMD_RET_SUCCESS;
> +}
> +
> +/* placeholder, not used now */
> +void uboot_lwip_destroy(void)
> +{
> +	uboot_net_use_lwip = 0;
> +}
> diff --git a/lib/lwip/port/include/arch/cc.h b/lib/lwip/port/include/arch/cc.h
> new file mode 100644
> index 0000000000..db30d7614e
> --- /dev/null
> +++ b/lib/lwip/port/include/arch/cc.h
> @@ -0,0 +1,46 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#ifndef LWIP_ARCH_CC_H
> +#define LWIP_ARCH_CC_H
> +
> +#include <linux/types.h>
> +#include <linux/kernel.h>
> +
> +#define LWIP_ERRNO_INCLUDE <errno.h>
> +
> +#define LWIP_ERRNO_STDINCLUDE	1
> +#define LWIP_NO_UNISTD_H 1
> +#define LWIP_TIMEVAL_PRIVATE 1
> +
> +extern unsigned int lwip_port_rand(void);
> +#define LWIP_RAND() (lwip_port_rand())
> +
> +/* different handling for unit test, normally not needed */
> +#ifdef LWIP_NOASSERT_ON_ERROR
> +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
> +						    handler; }} while (0)
> +#endif
> +
> +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS
> +
> +#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
> +				    x, __LINE__, __FILE__); } while (0)
> +
> +static inline int atoi(const char *str)
> +{
> +	int r = 0;
> +	int i;
> +
> +	for (i = 0; str[i] != '\0'; ++i)
> +		r = r * 10 + str[i] - '0';
> +
> +	return r;
> +}
> +
> +#define LWIP_ERR_T int
> +
> +#endif /* LWIP_ARCH_CC_H */
> diff --git a/lib/lwip/port/include/arch/sys_arch.h b/lib/lwip/port/include/arch/sys_arch.h
> new file mode 100644
> index 0000000000..8d95146275
> --- /dev/null
> +++ b/lib/lwip/port/include/arch/sys_arch.h
> @@ -0,0 +1,59 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#ifndef LWIP_ARCH_SYS_ARCH_H
> +#define LWIP_ARCH_SYS_ARCH_H
> +
> +#include "lwip/opt.h"
> +#include "lwip/arch.h"
> +#include "lwip/err.h"
> +
> +#define ERR_NEED_SCHED 123
> +
> +void sys_arch_msleep(u32_t delay_ms);
> +#define sys_msleep(ms) sys_arch_msleep(ms)
> +
> +#if SYS_LIGHTWEIGHT_PROT
> +typedef u32_t sys_prot_t;
> +#endif /* SYS_LIGHTWEIGHT_PROT */
> +
> +#include <errno.h>
> +
> +#define SYS_MBOX_NULL NULL
> +#define SYS_SEM_NULL  NULL
> +
> +typedef u32_t sys_prot_t;
> +
> +struct sys_sem;
> +typedef struct sys_sem *sys_sem_t;
> +#define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL))
> +#define sys_sem_set_invalid(sem) do { if ((sem) != NULL) { *(sem) = NULL; }} while (0)
> +
> +/* let sys.h use binary semaphores for mutexes */
> +#define LWIP_COMPAT_MUTEX 1
> +#define LWIP_COMPAT_MUTEX_ALLOWED 1
> +
> +struct sys_mbox;
> +typedef struct sys_mbox *sys_mbox_t;
> +#define sys_mbox_valid(mbox) (((mbox) != NULL) && (*(mbox) != NULL))
> +#define sys_mbox_set_invalid(mbox) do { if ((mbox) != NULL) { *(mbox) = NULL; }} while (0)
> +
> +struct sys_thread;
> +typedef struct sys_thread *sys_thread_t;
> +
> +static inline u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
> +{
> +	return 0;
> +};
> +
> +static inline err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
> +{
> +	return 0;
> +};
> +
> +#define sys_sem_signal(s)
> +
> +#endif /* LWIP_ARCH_SYS_ARCH_H */
> diff --git a/lib/lwip/port/include/limits.h b/lib/lwip/port/include/limits.h
> new file mode 100644
> index 0000000000..e69de29bb2
> diff --git a/lib/lwip/port/sys-arch.c b/lib/lwip/port/sys-arch.c
> new file mode 100644
> index 0000000000..609eeccf8c
> --- /dev/null
> +++ b/lib/lwip/port/sys-arch.c
> @@ -0,0 +1,20 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> + */
> +
> +#include <common.h>
> +#include <rand.h>
> +#include "lwip/opt.h"
> +
> +u32_t sys_now(void)
> +{
> +	return get_timer(0);
> +}
> +
> +u32_t lwip_port_rand(void)
> +{
> +	return (u32_t)rand();
> +}
> +
> diff --git a/lib/lwip/ulwip.h b/lib/lwip/ulwip.h
> new file mode 100644
> index 0000000000..11ca52aa1f
> --- /dev/null
> +++ b/lib/lwip/ulwip.h
> @@ -0,0 +1,9 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +int ulwip_enabled(void);
> +int ulwip_in_loop(void);
> +int ulwip_loop_set(int loop);
> +int ulwip_exit(int err);
> +int uboot_lwip_poll(void);
> +int ulwip_app_get_err(void);
> +void ulwip_set_tmo(int (*tmo)(void));
> diff --git a/net/eth-uclass.c b/net/eth-uclass.c
> index f41da4b37b..6031ad805d 100644
> --- a/net/eth-uclass.c
> +++ b/net/eth-uclass.c
> @@ -367,8 +367,10 @@ int eth_send(void *packet, int length)
>  	if (!current)
>  		return -ENODEV;
>
> -	if (!eth_is_active(current))
> +	if (!eth_is_active(current)) {
> +		printf("%s() !eth_is_active\n", __func__);
>  		return -EINVAL;
> +	}
>
>  	ret = eth_get_ops(current)->send(current, packet, length);
>  	if (ret < 0) {
> diff --git a/net/net.c b/net/net.c
> index 57da9bda85..aa9dd85a99 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -121,6 +121,7 @@
>  #endif
>  #include <net/tcp.h>
>  #include <net/wget.h>
> +#include "../lib/lwip/ulwip.h"
>
>  /** BOOTP EXTENTIONS **/
>
> @@ -438,7 +439,11 @@ int net_loop(enum proto_t protocol)
>  #endif
>
>  	bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
> +#if defined(CONFIG_LWIP_LIB)
> +	if (!ulwip_enabled() || !ulwip_in_loop())
> +#endif
>  	net_init();
> +
>  	if (eth_is_on_demand_init()) {
>  		eth_halt();
>  		eth_set_current();
> @@ -619,10 +624,23 @@ restart:
>  		 */
>  		eth_rx();
>
> +#if defined(CONFIG_LWIP_LIB)
> +		if (ulwip_enabled()) {
> +			net_set_state(NETLOOP_CONTINUE);
> +			if (!ulwip_in_loop()) {
> +				if (ulwip_app_get_err())
> +					net_set_state(NETLOOP_FAIL);
> +				else
> +					net_set_state(NETLOOP_SUCCESS);
> +				goto done;
> +			}
> +		}
> +#endif
>  		/*
>  		 *	Abort if ctrl-c was pressed.
>  		 */
>  		if (ctrlc()) {
> +			printf("-->enter ctrlc\n");
>  			/* cancel any ARP that may not have completed */
>  			net_arp_wait_packet_ip.s_addr = 0;
>
> @@ -1177,6 +1195,13 @@ void net_process_received_packet(uchar *in_packet, int len)
>  	if (len < ETHER_HDR_SIZE)
>  		return;
>
> +#if defined(CONFIG_LWIP_LIB)
> +	if (ulwip_enabled()) {
> +		uboot_lwip_poll();
> +		return;
> +	}
> +#endif
> +
>  #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
>  	if (push_packet) {
>  		(*push_packet)(in_packet, len);
> --
> 2.30.2
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 3/3] net/lwip: add lwip library for the network stack
  2023-06-30 10:03   ` Ilias Apalodimas
@ 2023-06-30 10:31     ` Maxim Uvarov
  0 siblings, 0 replies; 11+ messages in thread
From: Maxim Uvarov @ 2023-06-30 10:31 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: u-boot, pbrobinson, joe.hershberger, rfried.dev, trini, goldsimon,
	lwip-devel

On Fri, 30 Jun 2023 at 16:03, Ilias Apalodimas <ilias.apalodimas@linaro.org>
wrote:

> Hi Maxim,
>
> On Thu, Jun 29, 2023 at 06:34:30PM +0600, Maxim Uvarov wrote:
> > This commit adds lwip library for the U-boot network
> > stack. Supported commands: ping, tftp, dhcp and wget.
> >
> > Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> > ---
> >  .gitignore                            |   9 +
> >  cmd/net.c                             |  38 +++-
> >  include/net.h                         |   2 +-
> >  lib/Kconfig                           |   2 +
> >  lib/Makefile                          |   2 +
> >  lib/lwip/Kconfig                      | 108 ++++++++++
> >  lib/lwip/Makefile                     |  98 +++++++++
> >  lib/lwip/apps/dhcp/lwip-dhcp.c        |  52 +++++
> >  lib/lwip/apps/http/lwip-wget.c        |  71 +++++++
> >  lib/lwip/apps/ping/lwip_ping.c        |  37 ++++
> >  lib/lwip/apps/ping/lwip_ping.h        |  24 +++
>
> I thought we could compile dhcp/wget etc directly from lwip.  Do we have to
> copy them over?
>
> Thanks
> /Ilias
>

It's part of the library or part of examples. I think U-boot should
maintain connection code between lwip and lwip and maintain a library and
examples.
DHCP in the lwip library is a method to call for the lwip network
interface.  I.e. It's part of the library.
Wget - is http_client example, and U-boot code to write results to the
memory instead of file.
tftp - is a tftp example.
ping - is a ping example.
So in Makefile I copy an example and compile it. Then add a transition
layer between U-boot and lwip to make it work. That has to be easy to
maintain when
we will have to upgrade the lwip library to a new version.

BR,
Maxim.



> >  lib/lwip/apps/ping/ping.h             |  35 ++++
> >  lib/lwip/apps/tftp/lwip-tftp.c        | 121 +++++++++++
> >  lib/lwip/cmd-lwip.c                   | 276 ++++++++++++++++++++++++++
> >  lib/lwip/lwipopts.h                   | 203 +++++++++++++++++++
> >  lib/lwip/port/if.c                    | 260 ++++++++++++++++++++++++
> >  lib/lwip/port/include/arch/cc.h       |  46 +++++
> >  lib/lwip/port/include/arch/sys_arch.h |  59 ++++++
> >  lib/lwip/port/include/limits.h        |   0
> >  lib/lwip/port/sys-arch.c              |  20 ++
> >  lib/lwip/ulwip.h                      |   9 +
> >  net/eth-uclass.c                      |   4 +-
> >  net/net.c                             |  25 +++
> >  23 files changed, 1496 insertions(+), 5 deletions(-)
> >  create mode 100644 lib/lwip/Kconfig
> >  create mode 100644 lib/lwip/Makefile
> >  create mode 100644 lib/lwip/apps/dhcp/lwip-dhcp.c
> >  create mode 100644 lib/lwip/apps/http/lwip-wget.c
> >  create mode 100644 lib/lwip/apps/ping/lwip_ping.c
> >  create mode 100644 lib/lwip/apps/ping/lwip_ping.h
> >  create mode 100644 lib/lwip/apps/ping/ping.h
> >  create mode 100644 lib/lwip/apps/tftp/lwip-tftp.c
> >  create mode 100644 lib/lwip/cmd-lwip.c
> >  create mode 100644 lib/lwip/lwipopts.h
> >  create mode 100644 lib/lwip/port/if.c
> >  create mode 100644 lib/lwip/port/include/arch/cc.h
> >  create mode 100644 lib/lwip/port/include/arch/sys_arch.h
> >  create mode 100644 lib/lwip/port/include/limits.h
> >  create mode 100644 lib/lwip/port/sys-arch.c
> >  create mode 100644 lib/lwip/ulwip.h
> >
> > diff --git a/.gitignore b/.gitignore
> > index eb769f144c..be3676c59e 100644
> > --- a/.gitignore
> > +++ b/.gitignore
> > @@ -104,3 +104,12 @@ __pycache__
> >  # pylint files
> >  /pylint.cur
> >  /pylint.out/
> > +
> > +lib/lwip/lwip-external
> > +lib/lwip/apps/ping/ping.c
> > +lib/lwip/apps/http/http_client.c
> > +lib/lwip/apps/http/http_client.h
> > +lib/lwip/apps/tftp/tftp.c
> > +lib/lwip/apps/tftp/tftp_client.h
> > +lib/lwip/apps/tftp/tftp_common.h
> > +lib/lwip/apps/tftp/tftp_example.h
> > diff --git a/cmd/net.c b/cmd/net.c
> > index 0e9f200ca9..5b3dfd6c7e 100644
> > --- a/cmd/net.c
> > +++ b/cmd/net.c
> > @@ -36,6 +36,10 @@ U_BOOT_CMD(
> >  #endif
> >
> >  #ifdef CONFIG_CMD_TFTPBOOT
> > +#if defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
> > +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc,
> > +              char *const argv[]);
> > +#endif
> >  int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const
> argv[])
> >  {
> >       int ret;
> > @@ -56,7 +60,12 @@ U_BOOT_CMD(
> >  );
> >  #else
> >  U_BOOT_CMD(
> > -     tftpboot,       3,      1,      do_tftpb,
> > +     tftpboot,       3,      1,
> > +#if defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
> > +     do_lwip_tftp,
> > +#else
> > +     do_tftpb,
> > +#endif
> >       "load file via network using TFTP protocol",
> >       "[loadAddress] [[hostIPaddr:]bootfilename]"
> >  );
> > @@ -112,7 +121,11 @@ U_BOOT_CMD(
> >  static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
> >                  char *const argv[])
> >  {
> > +#if defined(CONFIG_CMD_LWIP_REPLACE_DHCP)
> > +     return do_lwip_dhcp();
> > +#else
> >       return netboot_common(DHCP, cmdtp, argc, argv);
> > +#endif
> >  }
> >
> >  U_BOOT_CMD(
> > @@ -137,13 +150,22 @@ U_BOOT_CMD(
> >  #endif
> >
> >  #if defined(CONFIG_CMD_WGET)
> > +#if defined(CONFIG_CMD_LWIP_REPLACE_WGET)
> > +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
> > +              char *const argv[])
> > +#endif
> >  static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char *
> const argv[])
> >  {
> >       return netboot_common(WGET, cmdtp, argc, argv);
> >  }
> >
> >  U_BOOT_CMD(
> > -     wget,   3,      1,      do_wget,
> > +     wget,   3,      1,
> > +#if defined(CONFIG_CMD_LWIP_REPLACE_WGET)
> > +     do_lwip_wget,
> > +#else
> > +     do_wget,
> > +#endif
> >       "boot image via network using HTTP protocol",
> >       "[loadAddress] [[hostIPaddr:]path and image name]"
> >  );
> > @@ -376,6 +398,10 @@ static int netboot_common(enum proto_t proto,
> struct cmd_tbl *cmdtp, int argc,
> >  }
> >
> >  #if defined(CONFIG_CMD_PING)
> > +#if defined(CONFIG_CMD_LWIP_REPLACE_PING)
> > +extern int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> > +                     char *const argv[]);
> > +#else
> >  static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> >                  char *const argv[])
> >  {
> > @@ -395,9 +421,15 @@ static int do_ping(struct cmd_tbl *cmdtp, int flag,
> int argc,
> >
> >       return CMD_RET_SUCCESS;
> >  }
> > +#endif
> >
> >  U_BOOT_CMD(
> > -     ping,   2,      1,      do_ping,
> > +     ping,   2,      1,
> > +#if defined(CONFIG_CMD_LWIP_REPLACE_PING)
> > +     do_lwip_ping,
> > +#else
> > +     do_ping,
> > +#endif
> >       "send ICMP ECHO_REQUEST to network host",
> >       "pingAddress"
> >  );
> > diff --git a/include/net.h b/include/net.h
> > index 1a99009959..8622983597 100644
> > --- a/include/net.h
> > +++ b/include/net.h
> > @@ -561,7 +561,7 @@ extern int                net_restart_wrap;       /*
> Tried all network devices */
> >
> >  enum proto_t {
> >       BOOTP, RARP, ARP, TFTPGET, DHCP, PING, PING6, DNS, NFS, CDP,
> NETCONS,
> > -     SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, WGET
> > +     SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, WGET,
> LWIP
> >  };
> >
> >  extern char  net_boot_file_name[1024];/* Boot File name */
> > diff --git a/lib/Kconfig b/lib/Kconfig
> > index 3c5a4ab386..7485a1f3bf 100644
> > --- a/lib/Kconfig
> > +++ b/lib/Kconfig
> > @@ -1031,3 +1031,5 @@ menu "FWU Multi Bank Updates"
> >  source lib/fwu_updates/Kconfig
> >
> >  endmenu
> > +
> > +source lib/lwip/Kconfig
> > diff --git a/lib/Makefile b/lib/Makefile
> > index d77b33e7f4..3b80a41187 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -91,6 +91,8 @@ obj-$(CONFIG_LIBAVB) += libavb/
> >  obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += libfdt/
> >  obj-$(CONFIG_$(SPL_TPL_)OF_REAL) += fdtdec_common.o fdtdec.o
> >
> > +obj-y += lwip/
> > +
> >  ifdef CONFIG_SPL_BUILD
> >  obj-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16-ccitt.o
> >  obj-$(CONFIG_$(SPL_TPL_)HASH) += crc16-ccitt.o
> > diff --git a/lib/lwip/Kconfig b/lib/lwip/Kconfig
> > new file mode 100644
> > index 0000000000..80d540ba54
> > --- /dev/null
> > +++ b/lib/lwip/Kconfig
> > @@ -0,0 +1,108 @@
> > +menu "LWIP"
> > +config LWIP_LIB
> > +     bool "Support LWIP library"
> > +     help
> > +       Selecting this option will enable the shared LWIP library code.
> > +
> > +menu "LWIP options"
> > +config LWIP_LIB_DEBUG
> > +     bool "enable debug"
> > +     default n
> > +config LWIP_LIB_NOASSERT
> > +     bool "disable asserts"
> > +     default y
> > +     help
> > +         Disabling asserts reduces binary size on 16k.
> > +config LWIP_LIB_TCP
> > +        bool "tcp"
> > +        default y
> > +config LWIP_LIB_UDP
> > +        bool "udp"
> > +        default y
> > +config LWIP_LIB_DNS
> > +        bool "dns"
> > +        default n
> > +config LWIP_LIB_DHCP
> > +        bool "dhcp"
> > +        default y
> > +
> > +config LWIP_LIB_LOOPBACK
> > +        bool "loopback"
> > +        default n
> > +        help
> > +        Increases size on 1k.
> > +config LWIP_LIB_SOCKET
> > +        bool "socket API"
> > +        default n
> > +config LWIP_LIB_NETCONN
> > +        bool "netconn API"
> > +        default n
> > +config LWIP_LIB_MEM_SIZE
> > +     int "mem size"
> > +     default 1600
> > +     range 1 4096
> > +     help
> > +         MEM_SIZE: the size of the heap memory. If the application will
> send
> > +         a lot of data that needs to be copied, this should be set high.
> > +
> > +config LWIP_LIB_PBUF_LINK_HLEN
> > +        int "pbuf link hlen"
> > +        default 14
> > +        range 4 1024
> > +        help
> > +        PBUF_LINK_HLEN: the number of bytes that should be allocated
> for a
> > +           link level header. The default is 14, the standard value for
> Ethernet.
> > +endmenu
> > +
> > +config CMD_LWIP
> > +        bool "lwip cmd"
> > +        default y
> > +     depends on LWIP_LIB
> > +        help
> > +          lwip networking command.
> > +
> > +config CMD_LWIP_PING
> > +        bool "ping"
> > +        default y
> > +     depends on CMD_LWIP
> > +        help
> > +          lwip ping command.
> > +
> > +config CMD_LWIP_REPLACE_PING
> > +        bool "replace original ping command"
> > +        default n
> > +
> > +config CMD_LWIP_WGET
> > +        bool "wget"
> > +        default y
> > +     depends on CMD_LWIP
> > +        help
> > +          lwip wget command.
> > +
> > +config CMD_LWIP_REPLACE_WGET
> > +     bool "replace original wget command"
> > +     default n
> > +
> > +config CMD_LWIP_TFTP
> > +        bool "tftp"
> > +        default y
> > +     depends on CMD_LWIP
> > +        help
> > +          lwip tftp command.
> > +
> > +config CMD_LWIP_REPLACE_TFTP
> > +     bool "replace original tftp command"
> > +     default n
> > +
> > +config CMD_LWIP_DHCP
> > +        bool "dhcp"
> > +        default y
> > +     depends on CMD_LWIP
> > +     depends on LWIP_LIB_DHCP
> > +        help
> > +          lwip dhcp command.
> > +
> > +config CMD_LWIP_REPLACE_DHCP
> > +     bool "replace original dhcp command"
> > +     default n
> > +endmenu
> > diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile
> > new file mode 100644
> > index 0000000000..6f68eb04ed
> > --- /dev/null
> > +++ b/lib/lwip/Makefile
> > @@ -0,0 +1,98 @@
> > +# SPDX-License-Identifier: GPL-2.0+
> > +#
> > +# (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > +
> > +LWIPDIR=lwip-external/src
> > +
> > +ccflags-y += -I$(CURDIR)/lib/lwip/port/include
> > +ccflags-y += -I$(CURDIR)/lib/lwip/lwip-external/src/include
> -I$(CURDIR)/lib/lwip
> > +
> > +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/init.o \
> > +     $(LWIPDIR)/core/def.o \
> > +     $(LWIPDIR)/core/dns.o \
> > +     $(LWIPDIR)/core/inet_chksum.o \
> > +     $(LWIPDIR)/core/ip.o \
> > +     $(LWIPDIR)/core/mem.o \
> > +     $(LWIPDIR)/core/memp.o \
> > +     $(LWIPDIR)/core/netif.o \
> > +     $(LWIPDIR)/core/pbuf.o \
> > +     $(LWIPDIR)/core/raw.o \
> > +     $(LWIPDIR)/core/stats.o \
> > +     $(LWIPDIR)/core/sys.o \
> > +     $(LWIPDIR)/core/altcp.o \
> > +     $(LWIPDIR)/core/altcp_alloc.o \
> > +     $(LWIPDIR)/core/altcp_tcp.o \
> > +     $(LWIPDIR)/core/tcp.o \
> > +     $(LWIPDIR)/core/tcp_in.o \
> > +     $(LWIPDIR)/core/tcp_out.o \
> > +     $(LWIPDIR)/core/timeouts.o \
> > +     $(LWIPDIR)/core/udp.o
> > +
> > +# IPv4
> > +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/ipv4/acd.o \
> > +        $(LWIPDIR)/core/ipv4/autoip.o \
> > +        $(LWIPDIR)/core/ipv4/dhcp.o \
> > +        $(LWIPDIR)/core/ipv4/etharp.o \
> > +        $(LWIPDIR)/core/ipv4/icmp.o \
> > +        $(LWIPDIR)/core/ipv4/igmp.o \
> > +        $(LWIPDIR)/core/ipv4/ip4_frag.o \
> > +        $(LWIPDIR)/core/ipv4/ip4.o \
> > +        $(LWIPDIR)/core/ipv4/ip4_addr.o
> > +# IPv6
> > +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/core/ipv6/dhcp6.o \
> > +        $(LWIPDIR)/core/ipv6/ethip6.o \
> > +        $(LWIPDIR)/core/ipv6/icmp6.o \
> > +        $(LWIPDIR)/core/ipv6/inet6.o \
> > +        $(LWIPDIR)/core/ipv6/ip6.o \
> > +        $(LWIPDIR)/core/ipv6/ip6_addr.o \
> > +        $(LWIPDIR)/core/ipv6/ip6_frag.o \
> > +        $(LWIPDIR)/core/ipv6/mld6.o \
> > +        $(LWIPDIR)/core/ipv6/nd6.o
> > +# API
> > +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/api/api_lib.o \
> > +     $(LWIPDIR)/api/api_msg.o \
> > +     $(LWIPDIR)/api/err.o \
> > +     $(LWIPDIR)/api/if_api.o \
> > +     $(LWIPDIR)/api/netbuf.o \
> > +     $(LWIPDIR)/api/netdb.o \
> > +     $(LWIPDIR)/api/netifapi.o \
> > +     $(LWIPDIR)/api/sockets.o \
> > +     $(LWIPDIR)/api/tcpip.o
> > +
> > +# Netdevs
> > +obj-$(CONFIG_LWIP_LIB) += $(LWIPDIR)/netif/ethernet.o
> > +
> > +obj-$(CONFIG_LWIP_LIB) += port/if.o
> > +obj-$(CONFIG_LWIP_LIB) += port/sys-arch.o
> > +
> > +obj-$(CONFIG_CMD_LWIP) += cmd-lwip.o
> > +
> > +.PHONY: $(obj)/apps/ping/ping.c
> > +$(obj)/apps/ping/ping.o: $(obj)/apps/ping/ping.c
> > +$(obj)/apps/ping/ping.c:
> > +     cp ./lib/lwip/lwip-external/contrib/apps/ping/ping.c
> $(obj)/apps/ping/ping.c
> > +
> > +obj-$(CONFIG_CMD_LWIP) += apps/ping/ping.o
> > +obj-$(CONFIG_CMD_LWIP) += apps/ping/lwip_ping.o
> > +
> > +$(obj)/apps/http/http_clinet.o: $(obj)/apps/http/http_client.c
> > +.PHONY: $(obj)/apps/http/http_client.c
> > +$(obj)/apps/http/http_client.c:
> > +     cp ./lib/lwip/lwip-external/src/apps/http/http_client.c
> $(obj)/apps/http/http_client.c
> > +     cp ./lib/lwip/lwip-external/src/include/lwip/apps/http_client.h
> $(obj)/apps/http/http_client.h
> > +
> > +obj-$(CONFIG_CMD_LWIP_WGET) += apps/http/http_client.o
> > +obj-$(CONFIG_CMD_LWIP_WGET) += apps/http/lwip-wget.o
> > +
> > +$(obj)/apps/tftp/tftp.o: $(obj)/apps/tftp/tftp.c
> > +.PHONY: $(obj)/apps/tftp/tftp.c
> > +$(obj)/apps/tftp/tftp.c:
> > +     cp ./lib/lwip/lwip-external/src/apps/tftp/tftp.c
> $(obj)/apps/tftp/tftp.c
> > +     cp ./lib/lwip/lwip-external/src/include/lwip/apps/tftp_client.h
> $(obj)/apps/tftp/tftp_client.h
> > +     cp ./lib/lwip/lwip-external/src/include/lwip/apps/tftp_common.h
> $(obj)/apps/tftp/tftp_common.h
> > +     cp ./lib/lwip/lwip-external/contrib/examples/tftp/tftp_example.h
> $(obj)/apps/tftp/tftp_example.h
> > +
> > +obj-$(CONFIG_CMD_LWIP_TFTP) += apps/tftp/tftp.o
> > +obj-$(CONFIG_CMD_LWIP_TFTP) += apps/tftp/lwip-tftp.o
> > +
> > +obj-$(CONFIG_CMD_LWIP_DHCP) += apps/dhcp/lwip-dhcp.o
> > diff --git a/lib/lwip/apps/dhcp/lwip-dhcp.c
> b/lib/lwip/apps/dhcp/lwip-dhcp.c
> > new file mode 100644
> > index 0000000000..2e4812c7dd
> > --- /dev/null
> > +++ b/lib/lwip/apps/dhcp/lwip-dhcp.c
> > @@ -0,0 +1,52 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#include <common.h>
> > +#include <command.h>
> > +#include <console.h>
> > +
> > +#include <lwip/dhcp.h>
> > +#include <lwip/prot/dhcp.h>
> > +
> > +#include "../../../lwip/ulwip.h"
> > +
> > +static struct dhcp dhcp;
> > +static bool dhcp_is_set;
> > +extern struct netif uboot_netif;
> > +
> > +static int ulwip_dhcp_tmo(void)
> > +{
> > +     switch (dhcp.state) {
> > +     case DHCP_STATE_BOUND:
> > +             env_set("bootfile", dhcp.boot_file_name);
> > +             env_set("ipaddr", ip4addr_ntoa(&dhcp.offered_ip_addr));
> > +             env_set("netmask", ip4addr_ntoa(&dhcp.offered_sn_mask));
> > +             env_set("serverip", ip4addr_ntoa(&dhcp.server_ip_addr));
> > +             printf("DHCP client bound to address %s\n",
> ip4addr_ntoa(&dhcp.offered_ip_addr));
> > +             break;
> > +     default:
> > +             return 0;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +int ulwip_dhcp(void)
> > +{
> > +     int err;
> > +
> > +     ulwip_set_tmo(ulwip_dhcp_tmo);
> > +
> > +     if (!dhcp_is_set) {
> > +             dhcp_set_struct(&uboot_netif, &dhcp);
> > +             dhcp_is_set = true;
> > +     }
> > +     err = dhcp_start(&uboot_netif);
> > +     if (err)
> > +             printf("dhcp_start error %d\n", err);
> > +
> > +     return err;
> > +}
> > diff --git a/lib/lwip/apps/http/lwip-wget.c
> b/lib/lwip/apps/http/lwip-wget.c
> > new file mode 100644
> > index 0000000000..07aabd15f3
> > --- /dev/null
> > +++ b/lib/lwip/apps/http/lwip-wget.c
> > @@ -0,0 +1,71 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#include <common.h>
> > +#include <command.h>
> > +#include <console.h>
> > +
> > +#include "http_client.h"
> > +#include "../../../lwip/ulwip.h"
> > +
> > +static ulong daddr;
> > +static httpc_connection_t settings;
> > +
> > +static err_t httpc_recv(void *arg, struct altcp_pcb *pcb, struct pbuf
> *p, err_t err)
> > +{
> > +     struct pbuf *q;
> > +     LWIP_UNUSED_ARG(err);
> > +
> > +     if (!p)
> > +             return ERR_BUF;
> > +
> > +     for (q = p; q != NULL; q = q->next) {
> > +             memcpy((void *)daddr, q->payload, q->len);
> > +             printf("downloaded chunk size %d, to addr 0x%lx\n",
> q->len, daddr);
> > +             daddr += q->len;
> > +     }
> > +     altcp_recved(pcb, p->tot_len);
> > +     pbuf_free(p);
> > +     return ERR_OK;
> > +}
> > +
> > +static void httpc_result(void *arg, httpc_result_t httpc_result, u32_t
> rx_content_len,
> > +                      u32_t srv_res, err_t err)
> > +{
> > +     if (httpc_result == HTTPC_RESULT_OK) {
> > +             printf("\n%d bytes successfully downloaded.\n",
> rx_content_len);
> > +             ulwip_exit(0);
> > +     } else {
> > +             printf("\nhttp eroror: %d\n", httpc_result);
> > +             ulwip_exit(-1);
> > +     }
> > +}
> > +
> > +int lwip_wget(ulong addr, char *url)
> > +{
> > +     err_t err;
> > +     int port = 80;
> > +     char *server_name;
> > +     httpc_state_t *connection;
> > +
> > +     daddr = addr;
> > +     server_name = env_get("serverip");
> > +     if (!server_name) {
> > +             printf("error: serverip variable has to be set\n");
> > +             return CMD_RET_FAILURE;
> > +     }
> > +
> > +     printf("downloading %s to addr 0x%lx\n", url, addr);
> > +     memset(&settings, 0, sizeof(httpc_connection_t));
> > +     settings.result_fn = httpc_result;
> > +     err = httpc_get_file_dns(server_name, port, url, &settings,
> > +                              httpc_recv, NULL,  &connection);
> > +     if (err != ERR_OK) {
> > +             printf("httpc_init_connection failed\n");
> > +             return err;
> > +     }
> > +     return 0;
> > +}
> > diff --git a/lib/lwip/apps/ping/lwip_ping.c
> b/lib/lwip/apps/ping/lwip_ping.c
> > new file mode 100644
> > index 0000000000..a05dc76326
> > --- /dev/null
> > +++ b/lib/lwip/apps/ping/lwip_ping.c
> > @@ -0,0 +1,37 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#include "lwip/opt.h"
> > +#include "lwip/ip_addr.h"
> > +#include "ping.h"
> > +
> > +#include "../../../lwip/ulwip.h"
> > +
> > +static ip_addr_t ip_target;
> > +
> > +static int ulwip_ping_tmo(void)
> > +{
> > +
> > +     printf("ping failed; host %s is not alive\n",
> ipaddr_ntoa(&ip_target));
> > +     return 0;
> > +}
> > +
> > +int lwip_ping_init(char *ping_addr)
> > +{
> > +     int err;
> > +
> > +     err = ipaddr_aton(ping_addr, &ip_target);
> > +     if (err == 0) {
> > +             printf("wrong ping addr string \"%s\" \n", ping_addr);
> > +             return -1;
> > +     }
> > +
> > +     ulwip_set_tmo(ulwip_ping_tmo);
> > +
> > +     ping_init(&ip_target);
> > +
> > +     return 0;
> > +}
> > diff --git a/lib/lwip/apps/ping/lwip_ping.h
> b/lib/lwip/apps/ping/lwip_ping.h
> > new file mode 100644
> > index 0000000000..7f08095427
> > --- /dev/null
> > +++ b/lib/lwip/apps/ping/lwip_ping.h
> > @@ -0,0 +1,24 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#ifndef LWIP_PING_H
> > +#define LWIP_PING_H
> > +
> > +#include <lwip/ip_addr.h>
> > +
> > +/**
> > + * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is
> used
> > + */
> > +#ifndef PING_USE_SOCKETS
> > +#define PING_USE_SOCKETS   0
> > +#endif
> > +
> > +int lwip_ping_init(char *ping_addr);
> > +
> > +void ping_raw_init(void);
> > +void ping_send_now(void);
> > +
> > +#endif /* LWIP_PING_H */
> > diff --git a/lib/lwip/apps/ping/ping.h b/lib/lwip/apps/ping/ping.h
> > new file mode 100644
> > index 0000000000..0dd4bd78c7
> > --- /dev/null
> > +++ b/lib/lwip/apps/ping/ping.h
> > @@ -0,0 +1,35 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +#include "../../../lwip/ulwip.h"
> > +
> > +#include "lwip/prot/ip4.h"
> > +
> > +#define ip4_print_parts(a, b, c, d) \
> > +     printf("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, a, b, c, d);
> > +
> > +#define ip4_print(ipaddr) \
> > +     ip4_print_parts(\
> > +                     (u16_t)((ipaddr) != NULL ? ip4_addr1_16(ipaddr) :
> 0), \
> > +                     (u16_t)((ipaddr) != NULL ? ip4_addr2_16(ipaddr) :
> 0), \
> > +                     (u16_t)((ipaddr) != NULL ? ip4_addr3_16(ipaddr) :
> 0), \
> > +                     (u16_t)((ipaddr) != NULL ? ip4_addr4_16(ipaddr) :
> 0))
> > +
> > +
> > +#define LWIP_DEBUG 1 /* ping_time is under ifdef*/
> > +#define PING_RESULT(cond) { \
> > +     if (cond == 1) { \
> > +             printf("host "); \
> > +             ip4_print(addr); \
> > +             printf(" is alive\n"); \
> > +             printf(" %"U32_F" ms\n", (sys_now() - ping_time)); \
> > +             ulwip_exit(0); \
> > +     } else { \
> > +             printf("ping failed; host "); \
> > +             ip4_print(addr); \
> > +             printf(" is not alive\n"); \
> > +             ulwip_exit(-1); \
> > +     } \
> > +     } while (0);
> > +
> > +#include "lwip/ip_addr.h"
> > +void ping_init(const ip_addr_t *ping_addr);
> > diff --git a/lib/lwip/apps/tftp/lwip-tftp.c
> b/lib/lwip/apps/tftp/lwip-tftp.c
> > new file mode 100644
> > index 0000000000..c38e83c8ee
> > --- /dev/null
> > +++ b/lib/lwip/apps/tftp/lwip-tftp.c
> > @@ -0,0 +1,121 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#include <common.h>
> > +#include <command.h>
> > +#include <console.h>
> > +
> > +#include "lwip/apps/tftp_client.h"
> > +#include "lwip/apps/tftp_server.h"
> > +#include "tftp_example.h"
> > +
> > +#include <string.h>
> > +
> > +#include "../../../lwip/ulwip.h"
> > +
> > +#if LWIP_UDP
> > +
> > +static ulong daddr;
> > +static ulong size;
> > +
> > +static void *tftp_open(const char *fname, const char *mode, u8_t
> is_write)
> > +{
> > +     LWIP_UNUSED_ARG(mode);
> > +     return NULL;
> > +}
> > +
> > +static void tftp_close(void *handle)
> > +{
> > +     printf("\ndone\n");
> > +     printf("Bytes transferred = %ld (0x%lx hex)\n", size, size);
> > +     ulwip_exit(0);
> > +}
> > +
> > +static int tftp_read(void *handle, void *buf, int bytes)
> > +{
> > +     return 0;
> > +}
> > +
> > +static int tftp_write(void *handle, struct pbuf *p)
> > +{
> > +     struct pbuf *q;
> > +
> > +     for (q = p; q != NULL; q = q->next) {
> > +             memcpy((void *)daddr, q->payload, q->len);
> > +             /* printf("downloaded chunk size %d, to addr 0x%lx\n",
> q->len, daddr); */
> > +             daddr += q->len;
> > +             size += q->len;
> > +             printf("#");
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +/* For TFTP client only */
> > +static void tftp_error(void *handle, int err, const char *msg, int size)
> > +{
> > +     char message[100];
> > +
> > +     LWIP_UNUSED_ARG(handle);
> > +
> > +     memset(message, 0, sizeof(message));
> > +     MEMCPY(message, msg, LWIP_MIN(sizeof(message)-1, (size_t)size));
> > +
> > +     printf("TFTP error: %d (%s)", err, message);
> > +}
> > +
> > +static const struct tftp_context tftp = {
> > +     tftp_open,
> > +     tftp_close,
> > +     tftp_read,
> > +     tftp_write,
> > +     tftp_error
> > +};
> > +
> > +int lwip_tftp(ulong addr, char *fname)
> > +{
> > +     void *f = (void *)0x1; /*fake handle*/
> > +     err_t err;
> > +     ip_addr_t srv;
> > +     int ret;
> > +     char *server_ip;
> > +
> > +     if (!fname || addr == 0)
> > +             return CMD_RET_FAILURE;
> > +
> > +     size = 0;
> > +     daddr = addr;
> > +     server_ip = env_get("serverip");
> > +     if (!server_ip) {
> > +             printf("error: serverip variable has to be set\n");
> > +             return CMD_RET_FAILURE;
> > +     }
> > +
> > +     ret = ipaddr_aton(server_ip, &srv);
> > +     LWIP_ASSERT("ipaddr_aton failed", ret == 1);
> > +
> > +     printf("TFTP from server %s; our IP address is %s\n",
> > +                     server_ip, env_get("ipaddr"));
> > +     printf("Filename '%s'.\n", fname);
> > +     printf("Load address: 0x%lx\n", daddr);
> > +     printf("Loading:");
> > +
> > +     err = tftp_init_client(&tftp);
> > +     if (!(err == ERR_OK || err == ERR_USE))
> > +             printf("tftp_init_client err: %d\n", err);
> > +
> > +     err = tftp_get(f, &srv, TFTP_PORT, fname, TFTP_MODE_OCTET);
> > +     /* might return different errors, like routing problems */
> > +     if (err != ERR_OK) {
> > +             printf("tftp_get err=%d\n", err);
> > +     }
> > +     LWIP_ASSERT("tftp_get failed", err == ERR_OK);
> > +
> > +     return err;
> > +}
> > +#else
> > +#error "UDP has to be supported"
> > +#endif /* LWIP_UDP */
> > diff --git a/lib/lwip/cmd-lwip.c b/lib/lwip/cmd-lwip.c
> > new file mode 100644
> > index 0000000000..d7cdc4e411
> > --- /dev/null
> > +++ b/lib/lwip/cmd-lwip.c
> > @@ -0,0 +1,276 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +/*
> > + * (C) Copyright 2023 Maxim Uvarov, maxim.uvarov@linaro.org
> > + */
> > +
> > +#include <common.h>
> > +#include <command.h>
> > +#include <console.h>
> > +#include <display_options.h>
> > +#include <memalign.h>
> > +#include <net.h>
> > +#include <image.h>
> > +
> > +#include "apps/ping/lwip_ping.h"
> > +#include "ulwip.h"
> > +
> > +extern int uboot_lwip_init(void);
> > +extern int uboot_lwip_loop_is_done(void);
> > +
> > +static int do_lwip_info(struct cmd_tbl *cmdtp, int flag, int argc,
> > +                   char *const argv[])
> > +{
> > +     printf("TBD: %s\n", __func__);
> > +     return CMD_RET_SUCCESS;
> > +}
> > +
> > +static int do_lwip_init(struct cmd_tbl *cmdtp, int flag, int argc,
> > +                   char *const argv[])
> > +{
> > +     if (!uboot_lwip_init())
> > +             return CMD_RET_SUCCESS;
> > +     return CMD_RET_FAILURE;
> > +}
> > +
> > +static int lwip_empty_tmo(void) { return 0; };
> > +int (*ulwip_tmo)(void) = lwip_empty_tmo;
> > +void ulwip_set_tmo(int (*tmo)(void))
> > +{
> > +     ulwip_tmo = tmo;
> > +}
> > +
> > +static void ulwip_clear_tmo(void)
> > +{
> > +     ulwip_tmo = lwip_empty_tmo;
> > +}
> > +
> > +static void ulwip_timeout_handler(void)
> > +{
> > +     eth_halt();
> > +     ulwip_tmo();
> > +     net_set_state(NETLOOP_FAIL);    /* we did not get the reply */
> > +     ulwip_loop_set(0);
> > +}
> > +
> > +static int ulwip_loop(void)
> > +{
> > +     ulwip_loop_set(1);
> > +     if (net_loop(LWIP) < 0) {
> > +             ulwip_loop_set(0);
> > +             return CMD_RET_FAILURE;
> > +     }
> > +     ulwip_loop_set(0);
> > +     return CMD_RET_SUCCESS;
> > +}
> > +
> > +#if !defined(CONFIG_CMD_LWIP_REPLACE_PING)
> > +static
> > +#endif
> > +int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> > +              char *const argv[])
> > +{
> > +     if (argc < 2) {
> > +             printf("argc = %d, error\n", argc);
> > +             return CMD_RET_USAGE;
> > +     }
> > +
> > +     uboot_lwip_init();
> > +
> > +     eth_init(); /* activate u-boot eth dev */
> > +
> > +     printf("Using %s device\n", eth_get_name());
> > +     printf("pinging addr: %s\n", argv[1]);
> > +
> > +     net_set_timeout_handler(1000UL, ulwip_timeout_handler);
> > +
> > +     if (lwip_ping_init(argv[1])) {
> > +             printf("ping init fail\n");
> > +             return CMD_RET_FAILURE;
> > +     }
> > +
> > +     ping_send_now();
> > +
> > +     return ulwip_loop();
> > +}
> > +
> > +extern int lwip_wget(ulong addr, char *url);
> > +
> > +#if !defined(CONFIG_CMD_LWIP_REPLACE_WGET)
> > +static
> > +#endif
> > +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
> > +              char *const argv[])
> > +{
> > +     char *url;
> > +
> > +     if (argc < 2) {
> > +             printf("argc = %d, error\n", argc);
> > +             return CMD_RET_USAGE;
> > +     }
> > +     url = argv[1];
> > +
> > +     uboot_lwip_init();
> > +
> > +     eth_init(); /* activate u-boot eth dev */
> > +
> > +     lwip_wget(image_load_addr, url);
> > +
> > +     return ulwip_loop();
> > +}
> > +
> > +#if defined(CONFIG_CMD_LWIP_TFTP)
> > +extern int lwip_tftp(ulong addr, char *filename);
> > +#if !defined(CONFIG_CMD_LWIP_REPLACE_TFTP)
> > +static
> > +#endif
> > +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc,
> > +              char *const argv[])
> > +{
> > +     char *filename;
> > +     ulong addr;
> > +     char *end;
> > +     int ret;
> > +
> > +     switch (argc) {
> > +     case 1:
> > +             filename = env_get("bootfile");
> > +             break;
> > +     case 2:
> > +             /*
> > +              * Only one arg - accept two forms:
> > +              * Just load address, or just boot file name. The latter
> > +              * form must be written in a format which can not be
> > +              * mis-interpreted as a valid number.
> > +              */
> > +             addr = hextoul(argv[1], &end);
> > +             if (end == (argv[1] + strlen(argv[1]))) {
> > +                     image_load_addr = addr;
> > +                     filename = env_get("bootfile");
> > +             } else {
> > +                     filename = argv[1];
> > +             }
> > +             break;
> > +     case 3:
> > +             image_load_addr = hextoul(argv[1], NULL);
> > +             filename = argv[2];
> > +             break;
> > +     default:
> > +             return CMD_RET_USAGE;
> > +     }
> > +
> > +     uboot_lwip_init();
> > +
> > +     eth_init(); /* activate u-boot eth dev */
> > +
> > +     ret = lwip_tftp(image_load_addr, filename);
> > +     if (ret)
> > +             return ret;
> > +
> > +     return ulwip_loop();
> > +}
> > +#endif
> > +
> > +#if defined(CONFIG_CMD_LWIP_DHCP)
> > +extern int ulwip_dhcp(void);
> > +
> > +#if !defined(CONFIG_CMD_LWIP_REPLACE_DHCP)
> > +static
> > +#endif
> > +int do_lwip_dhcp(void)
> > +{
> > +     int ret;
> > +     char *filename;
> > +
> > +     uboot_lwip_init();
> > +
> > +     ret = ulwip_dhcp();
> > +
> > +     net_set_timeout_handler(2000UL, ulwip_timeout_handler);
> > +
> > +     ulwip_loop();
> > +     if (IS_ENABLED(CONFIG_CMD_LWIP_TFTP)) {
> > +             ulwip_clear_tmo();
> > +
> > +             filename = env_get("bootfile");
> > +             if (!filename) {
> > +                     printf("no bootfile\n");
> > +                     return CMD_RET_FAILURE;
> > +             }
> > +
> > +             eth_init(); /* activate u-boot eth dev */
> > +             net_set_timeout_handler(20000UL, ulwip_timeout_handler);
> > +             lwip_tftp(image_load_addr, filename);
> > +
> > +             ret =  ulwip_loop();
> > +     }
> > +
> > +     return ret;
> > +}
> > +
> > +static int _do_lwip_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
> > +             char *const argv[])
> > +{
> > +     return do_lwip_dhcp();
> > +}
> > +#endif
> > +
> > +static struct cmd_tbl cmds[] = {
> > +     U_BOOT_CMD_MKENT(info, 1, 0, do_lwip_info, "Info and stats", ""),
> > +     U_BOOT_CMD_MKENT(init, 1, 0, do_lwip_init,
> > +                      "initialize lwip stack", ""),
> > +#if defined(CONFIG_CMD_LWIP_PING)
> > +     U_BOOT_CMD_MKENT(ping, 2, 0, do_lwip_ping,
> > +                      "send ICMP ECHO_REQUEST to network host",
> > +                      "pingAddress"),
> > +#endif
> > +#if defined(CONFIG_CMD_LWIP_WGET)
> > +     U_BOOT_CMD_MKENT(wget, 2, 0, do_lwip_wget, "", ""),
> > +#endif
> > +#if defined(CONFIG_CMD_LWIP_TFTP)
> > +     U_BOOT_CMD_MKENT(tftp, 3, 0, do_lwip_tftp,
> > +                     "boot image via network using TFTP protocol\n",
> > +                     "[loadAddress] [[hostIPaddr:]bootfilename]"),
> > +#endif
> > +#if defined(CONFIG_CMD_LWIP_DHCP)
> > +     U_BOOT_CMD_MKENT(dhcp, 1, 0, _do_lwip_dhcp,
> > +                     "boot image via network using DHCP/TFTP protocol",
> > +                     ""),
> > +#endif
> > +};
> > +
> > +static int do_ops(struct cmd_tbl *cmdtp, int flag, int argc,
> > +                  char *const argv[])
> > +{
> > +     struct cmd_tbl *cp;
> > +
> > +     cp = find_cmd_tbl(argv[1], cmds, ARRAY_SIZE(cmds));
> > +
> > +     argc--;
> > +     argv++;
> > +
> > +     if (cp == NULL || argc > cp->maxargs)
> > +             return CMD_RET_USAGE;
> > +     if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
> > +             return CMD_RET_SUCCESS;
> > +
> > +     return cp->cmd(cmdtp, flag, argc, argv);
> > +}
> > +
> > +U_BOOT_CMD(
> > +     lwip, 4, 1, do_ops,
> > +     "LWIP sub system",
> > +     "info - display info\n"
> > +     "init - init LWIP\n"
> > +     "ping addr - pingAddress\n"
> > +     "wget http://IPadress/url/\n"
> > +     "tftp [loadAddress] [[hostIPaddr:]bootfilename]\n"
> > +     "dhcp - boot image via network using DHCP/TFTP protocol\n"
> > +     );
> > +
> > +/* Old command kept for compatibility. Same as 'mmc info' */
> > +U_BOOT_CMD(
> > +     lwipinfo, 1, 0, do_lwip_info,
> > +     "display LWIP info",
> > +     "- display LWIP stack info"
> > +);
> > diff --git a/lib/lwip/lwipopts.h b/lib/lwip/lwipopts.h
> > new file mode 100644
> > index 0000000000..b943d7b9be
> > --- /dev/null
> > +++ b/lib/lwip/lwipopts.h
> > @@ -0,0 +1,203 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#ifndef LWIP_LWIPOPTS_H
> > +#define LWIP_LWIPOPTS_H
> > +
> > +#include "lwipopts.h"
> > +
> > +#if defined(CONFIG_LWIP_LIB_DEBUG)
> > +#define LWIP_DEBUG 1
> > +#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
> > +#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON
> > +#define ETHARP_DEBUG                    LWIP_DBG_OFF
> > +#define NETIF_DEBUG                     LWIP_DBG_OFF
> > +#define PBUF_DEBUG                      LWIP_DBG_OFF
> > +#define API_LIB_DEBUG                   LWIP_DBG_OFF
> > +#define API_MSG_DEBUG                   LWIP_DBG_OFF
> > +#define SOCKETS_DEBUG                   LWIP_DBG_OFF
> > +#define ICMP_DEBUG                      LWIP_DBG_OFF
> > +#define IGMP_DEBUG                      LWIP_DBG_OFF
> > +#define INET_DEBUG                      LWIP_DBG_OFF
> > +#define IP_DEBUG                        LWIP_DBG_OFF
> > +#define IP_REASS_DEBUG                  LWIP_DBG_OFF
> > +#define RAW_DEBUG                       LWIP_DBG_OFF
> > +#define MEM_DEBUG                       LWIP_DBG_OFF
> > +#define MEMP_DEBUG                      LWIP_DBG_OFF
> > +#define SYS_DEBUG                       LWIP_DBG_OFF
> > +#define TIMERS_DEBUG                    LWIP_DBG_OFF
> > +#define TCP_DEBUG                       LWIP_DBG_OFF
> > +#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF
> > +#define TCP_FR_DEBUG                    LWIP_DBG_OFF
> > +#define TCP_RTO_DEBUG                   LWIP_DBG_OFF
> > +#define TCP_CWND_DEBUG                  LWIP_DBG_OFF
> > +#define TCP_WND_DEBUG                   LWIP_DBG_OFF
> > +#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF
> > +#define TCP_RST_DEBUG                   LWIP_DBG_OFF
> > +#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF
> > +#define UDP_DEBUG                       LWIP_DBG_OFF
> > +#define TCPIP_DEBUG                     LWIP_DBG_OFF
> > +#define SLIP_DEBUG                      LWIP_DBG_OFF
> > +#define DHCP_DEBUG                      LWIP_DBG_ON
> > +#define AUTOIP_DEBUG                    LWIP_DBG_ON
> > +#define DNS_DEBUG                       LWIP_DBG_OFF
> > +#define IP6_DEBUG                       LWIP_DBG_OFF
> > +#define DHCP6_DEBUG                     LWIP_DBG_OFF
> > +#else
> > +#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_ALL
> > +#define LWIP_DBG_TYPES_ON               LWIP_DBG_OFF
> > +#define ETHARP_DEBUG                    LWIP_DBG_OFF
> > +#define NETIF_DEBUG                     LWIP_DBG_OFF
> > +#define PBUF_DEBUG                      LWIP_DBG_OFF
> > +#define API_LIB_DEBUG                   LWIP_DBG_OFF
> > +#define API_MSG_DEBUG                   LWIP_DBG_OFF
> > +#define SOCKETS_DEBUG                   LWIP_DBG_OFF
> > +#define ICMP_DEBUG                      LWIP_DBG_OFF
> > +#define IGMP_DEBUG                      LWIP_DBG_OFF
> > +#define INET_DEBUG                      LWIP_DBG_OFF
> > +#define IP_DEBUG                        LWIP_DBG_OFF
> > +#define IP_REASS_DEBUG                  LWIP_DBG_OFF
> > +#define RAW_DEBUG                       LWIP_DBG_OFF
> > +#define MEM_DEBUG                       LWIP_DBG_OFF
> > +#define MEMP_DEBUG                      LWIP_DBG_OFF
> > +#define SYS_DEBUG                       LWIP_DBG_OFF
> > +#define TIMERS_DEBUG                    LWIP_DBG_OFF
> > +#define TCP_DEBUG                       LWIP_DBG_OFF
> > +#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF
> > +#define TCP_FR_DEBUG                    LWIP_DBG_OFF
> > +#define TCP_RTO_DEBUG                   LWIP_DBG_OFF
> > +#define TCP_CWND_DEBUG                  LWIP_DBG_OFF
> > +#define TCP_WND_DEBUG                   LWIP_DBG_OFF
> > +#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF
> > +#define TCP_RST_DEBUG                   LWIP_DBG_OFF
> > +#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF
> > +#define UDP_DEBUG                       LWIP_DBG_OFF
> > +#define TCPIP_DEBUG                     LWIP_DBG_OFF
> > +#define SLIP_DEBUG                      LWIP_DBG_OFF
> > +#define DHCP_DEBUG                      LWIP_DBG_OFF
> > +#define AUTOIP_DEBUG                    LWIP_DBG_OFF
> > +#define DNS_DEBUG                       LWIP_DBG_OFF
> > +#define IP6_DEBUG                       LWIP_DBG_OFF
> > +#define DHCP6_DEBUG                     LWIP_DBG_OFF
> > +#endif
> > +#define LWIP_TESTMODE                   0
> > +
> > +#if defined(CONFIG_LWIP_LIB_NOASSERT)
> > +#define LWIP_NOASSERT 1
> > +#define LWIP_ASSERT(message, assertion)
> > +#endif
> > +
> > +#include "lwip/debug.h"
> > +
> > +#define SYS_LIGHTWEIGHT_PROT            0
> > +#define NO_SYS                          0
> > +
> > +#define MEM_ALIGNMENT                   1
> > +#define MEM_SIZE                        CONFIG_LWIP_LIB_MEM_SIZE
> > +
> > +#define MEMP_NUM_PBUF                   4
> > +#define MEMP_NUM_RAW_PCB                2
> > +#define MEMP_NUM_UDP_PCB                4
> > +#define MEMP_NUM_TCP_PCB                2
> > +#define MEMP_NUM_TCP_PCB_LISTEN         2
> > +#define MEMP_NUM_TCP_SEG                16
> > +#define MEMP_NUM_REASSDATA              1
> > +#define MEMP_NUM_ARP_QUEUE              2
> > +#define MEMP_NUM_SYS_TIMEOUT            4
> > +#define MEMP_NUM_NETBUF                 2
> > +#define MEMP_NUM_NETCONN               32
> > +#define MEMP_NUM_TCPIP_MSG_API          8
> > +#define MEMP_NUM_TCPIP_MSG_INPKT        8
> > +#define PBUF_POOL_SIZE                  8
> > +
> > +#define LWIP_ARP                        1
> > +
> > +#define IP_FORWARD                      0
> > +#define IP_OPTIONS_ALLOWED              1
> > +#define IP_REASSEMBLY                   1
> > +#define IP_FRAG                         1
> > +#define IP_REASS_MAXAGE                 3
> > +#define IP_REASS_MAX_PBUFS              4
> > +#define IP_FRAG_USES_STATIC_BUF         0
> > +
> > +#define IP_DEFAULT_TTL                  255
> > +
> > +#define LWIP_ICMP                       1
> > +
> > +#define LWIP_RAW                        1
> > +
> > +#if defined(CONFIG_LWIP_LIB_DHCP)
> > +#define LWIP_DHCP                       1
> > +#define LWIP_DHCP_BOOTP_FILE         1
> > +#else
> > +#define LWIP_DHCP                       0
> > +#endif
> > +#define LWIP_DHCP_DOES_ACD_CHECK     0
> > +
> > +#define LWIP_AUTOIP                     0
> > +
> > +#define LWIP_SNMP                       0
> > +
> > +#define LWIP_IGMP                       0
> > +
> > +#if defined(CONFIG_LWIP_LIB_DNS)
> > +#define LWIP_DNS                        1
> > +#else
> > +#define LWIP_DNS                        0
> > +#endif
> > +
> > +#if defined(CONFIG_LWIP_LIB_TCP)
> > +#define LWIP_UDP                        1
> > +#else
> > +#define LWIP_UDP                        0
> > +#endif
> > +
> > +#if defined(CONFIG_LWIP_LIB_TCP)
> > +#define LWIP_TCP                        1
> > +#else
> > +#define LWIP_TCP                        0
> > +#endif
> > +
> > +#define LWIP_LISTEN_BACKLOG             0
> > +
> > +#define PBUF_LINK_HLEN                  CONFIG_LWIP_LIB_PBUF_LINK_HLEN
> > +#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS +
> 40 + PBUF_LINK_HLEN)
> > +
> > +#define LWIP_HAVE_LOOPIF                0
> > +
> > +#if defined(CONFIG_LWIP_LIB_NETCONN)
> > +#define LWIP_NETCONN                    1
> > +#else
> > +#define LWIP_NETCONN                    0
> > +#define LWIP_DISABLE_MEMP_SANITY_CHECKS 1
> > +#endif
> > +
> > +#if defined(CONFIG_LWIP_LIB_SOCKET)
> > +#define LWIP_SOCKET                     1
> > +
> > +#define SO_REUSE                        1
> > +#else
> > +#define LWIP_SOCKET                     0
> > +#define SO_REUSE                        0
> > +#endif
> > +
> > +#define LWIP_STATS                      0
> > +
> > +#define PPP_SUPPORT                     0
> > +
> > +#define LWIP_TCPIP_CORE_LOCKING              0
> > +
> > +#if defined(CONFIG_LWIP_LIB_LOOPBACK)
> > +#define LWIP_NETIF_LOOPBACK          1
> > +#else
> > +#define LWIP_NETIF_LOOPBACK          0
> > +#endif
> > +/* use malloc instead of pool */
> > +#define MEMP_MEM_MALLOC                 1
> > +#define MEMP_MEM_INIT                        1
> > +#define MEM_LIBC_MALLOC                      1
> > +
> > +#endif /* LWIP_LWIPOPTS_H */
> > diff --git a/lib/lwip/port/if.c b/lib/lwip/port/if.c
> > new file mode 100644
> > index 0000000000..15d44054be
> > --- /dev/null
> > +++ b/lib/lwip/port/if.c
> > @@ -0,0 +1,260 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#include <common.h>
> > +#include <command.h>
> > +extern int eth_init(void); /* net.h */
> > +extern void string_to_enetaddr(const char *addr, uint8_t *enetaddr); /*
> net.h */
> > +extern struct in_addr net_ip;
> > +extern u8 net_ethaddr[6];
> > +
> > +#include "lwip/debug.h"
> > +#include "lwip/arch.h"
> > +#include "netif/etharp.h"
> > +#include "lwip/stats.h"
> > +#include "lwip/def.h"
> > +#include "lwip/mem.h"
> > +#include "lwip/pbuf.h"
> > +#include "lwip/sys.h"
> > +#include "lwip/netif.h"
> > +
> > +#include "lwip/ip.h"
> > +
> > +#define IFNAME0 'e'
> > +#define IFNAME1 '0'
> > +
> > +static struct pbuf *low_level_input(struct netif *netif);
> > +static int uboot_net_use_lwip;
> > +
> > +int ulwip_enabled(void)
> > +{
> > +     return uboot_net_use_lwip;
> > +}
> > +
> > +/* 1 - in loop
> > + * 0 - no loop
> > + */
> > +static int loop_lwip;
> > +
> > +/* ret 1 - in loop
> > + *     0 - no loop
> > + */
> > +int ulwip_in_loop(void)
> > +{
> > +     return loop_lwip;
> > +}
> > +
> > +void ulwip_loop_set(int loop)
> > +{
> > +     loop_lwip = loop;
> > +}
> > +
> > +static int ulwip_app_err;
> > +
> > +void ulwip_exit(int err)
> > +{
> > +     ulwip_app_err = err;
> > +     ulwip_loop_set(0);
> > +}
> > +
> > +int ulwip_app_get_err(void)
> > +{
> > +     return ulwip_app_err;
> > +}
> > +
> > +struct uboot_lwip_if {
> > +};
> > +
> > +#if defined(CONFIG_CMD_LWIP_DHCP)
> > +struct netif uboot_netif;
> > +#else
> > +static struct netif uboot_netif;
> > +#endif
> > +
> > +#define LWIP_PORT_INIT_NETMASK(addr)  IP4_ADDR((addr), 255, 255, 255, 0)
> > +
> > +extern uchar *net_rx_packet;
> > +extern int    net_rx_packet_len;
> > +
> > +int uboot_lwip_poll(void)
> > +{
> > +     struct pbuf *p;
> > +     int err;
> > +
> > +     p = low_level_input(&uboot_netif);
> > +     if (!p) {
> > +             printf("error p = low_level_input = NULL\n");
> > +             return 0;
> > +     }
> > +
> > +     err = ethernet_input(p, &uboot_netif);
> > +     if (err)
> > +             printf("ip4_input err %d\n", err);
> > +
> > +     return 0;
> > +}
> > +
> > +static struct pbuf *low_level_input(struct netif *netif)
> > +{
> > +     struct pbuf *p, *q;
> > +     u16_t len = net_rx_packet_len;
> > +     uchar *data = net_rx_packet;
> > +
> > +#if ETH_PAD_SIZE
> > +     len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
> > +#endif
> > +
> > +     /* We allocate a pbuf chain of pbufs from the pool. */
> > +     p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
> > +     if (p) {
> > +#if ETH_PAD_SIZE
> > +             pbuf_remove_header(p, ETH_PAD_SIZE); /* drop the padding
> word */
> > +#endif
> > +             /* We iterate over the pbuf chain until we have read the
> entire
> > +              * packet into the pbuf.
> > +              */
> > +             for (q = p; q != NULL; q = q->next) {
> > +                     /* Read enough bytes to fill this pbuf in the
> chain. The
> > +                      * available data in the pbuf is given by the
> q->len
> > +                      * variable.
> > +                      * This does not necessarily have to be a memcpy,
> you can also preallocate
> > +                      * pbufs for a DMA-enabled MAC and after receiving
> truncate it to the
> > +                      * actually received size. In this case, ensure
> the tot_len member of the
> > +                      * pbuf is the sum of the chained pbuf len members.
> > +                      */
> > +                     MEMCPY(q->payload, data, q->len);
> > +                     data += q->len;
> > +             }
> > +             //acknowledge that packet has been read();
> > +
> > +#if ETH_PAD_SIZE
> > +             pbuf_add_header(p, ETH_PAD_SIZE); /* reclaim the padding
> word */
> > +#endif
> > +             LINK_STATS_INC(link.recv);
> > +     } else {
> > +             //drop packet();
> > +             LINK_STATS_INC(link.memerr);
> > +             LINK_STATS_INC(link.drop);
> > +     }
> > +
> > +     return p;
> > +}
> > +
> > +static int ethernetif_input(struct pbuf *p, struct netif *netif)
> > +{
> > +     struct ethernetif *ethernetif;
> > +
> > +     ethernetif = netif->state;
> > +
> > +     /* move received packet into a new pbuf */
> > +     p = low_level_input(netif);
> > +
> > +     /* if no packet could be read, silently ignore this */
> > +     if (p) {
> > +             /* pass all packets to ethernet_input, which decides what
> packets it supports */
> > +             if (netif->input(p, netif) != ERR_OK) {
> > +                     LWIP_DEBUGF(NETIF_DEBUG, ("%s: IP input error\n",
> __func__));
> > +                     pbuf_free(p);
> > +                     p = NULL;
> > +             }
> > +     }
> > +     return 0;
> > +}
> > +
> > +static err_t low_level_output(struct netif *netif, struct pbuf *p)
> > +{
> > +     int err;
> > +
> > +     err = eth_send(p->payload, p->len);
> > +     if (err != 0) {
> > +             printf("eth_send error %d\n", err);
> > +             return ERR_ABRT;
> > +     }
> > +     return ERR_OK;
> > +}
> > +
> > +err_t uboot_lwip_if_init(struct netif *netif)
> > +{
> > +     struct uboot_lwip_if *uif = (struct uboot_lwip_if
> *)malloc(sizeof(struct uboot_lwip_if));
> > +
> > +     if (!uif) {
> > +             printf("uboot_lwip_if: out of memory\n");
> > +             return ERR_MEM;
> > +     }
> > +     netif->state = uif;
> > +
> > +     netif->name[0] = IFNAME0;
> > +     netif->name[1] = IFNAME1;
> > +
> > +     netif->hwaddr_len = ETHARP_HWADDR_LEN;
> > +     string_to_enetaddr(env_get("ethaddr"), netif->hwaddr);
> > +#if defined(CONFIG_LWIP_LIB_DEBUG)
> > +     printf("              MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
> > +            netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2],
> > +            netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5]);
> > +#endif
> > +
> > +#if LWIP_IPV4
> > +     netif->output = etharp_output;
> > +#endif /* LWIP_IPV4 */
> > +#if LWIP_IPV6
> > +     netif->output_ip6 = ethip6_output;
> > +#endif /* LWIP_IPV6 */
> > +     netif->linkoutput = low_level_output;
> > +     netif->mtu = 1500;
> > +     netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP |
> NETIF_FLAG_LINK_UP;
> > +
> > +     eth_init(); /* activate u-boot eth dev */
> > +
> > +     if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) {
> > +             printf("Initialized LWIP stack\n");
> > +     }
> > +
> > +     return ERR_OK;
> > +}
> > +
> > +int uboot_lwip_init(void)
> > +{
> > +     ip4_addr_t ipaddr, netmask, gw;
> > +
> > +     if (uboot_net_use_lwip)
> > +             return CMD_RET_SUCCESS;
> > +
> > +     ip4_addr_set_zero(&gw);
> > +     ip4_addr_set_zero(&ipaddr);
> > +     ip4_addr_set_zero(&netmask);
> > +
> > +     ipaddr_aton(env_get("ipaddr"), &ipaddr);
> > +     ipaddr_aton(env_get("ipaddr"), &netmask);
> > +
> > +     LWIP_PORT_INIT_NETMASK(&netmask);
> > +     if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) {
> > +             printf("Starting lwIP, IP: %s\n", ip4addr_ntoa(&ipaddr));
> > +             printf("               GW: %s\n", ip4addr_ntoa(&gw));
> > +             printf("             mask: %s\n", ip4addr_ntoa(&netmask));
> > +     }
> > +
> > +     if (!netif_add(&uboot_netif, &ipaddr, &netmask, &gw,
> > +                    &uboot_netif, uboot_lwip_if_init, ethernetif_input))
> > +             printf("err: netif_add failed!\n");
> > +
> > +     netif_set_up(&uboot_netif);
> > +     netif_set_link_up(&uboot_netif);
> > +#if LWIP_IPV6
> > +     netif_create_ip6_linklocal_address(&uboot_netif, 1);
> > +     printf("             IPv6: %s\n",
> ip6addr_ntoa(netif_ip6_addr(uboot_netif, 0)));
> > +#endif /* LWIP_IPV6 */
> > +
> > +     uboot_net_use_lwip = 1;
> > +
> > +     return CMD_RET_SUCCESS;
> > +}
> > +
> > +/* placeholder, not used now */
> > +void uboot_lwip_destroy(void)
> > +{
> > +     uboot_net_use_lwip = 0;
> > +}
> > diff --git a/lib/lwip/port/include/arch/cc.h
> b/lib/lwip/port/include/arch/cc.h
> > new file mode 100644
> > index 0000000000..db30d7614e
> > --- /dev/null
> > +++ b/lib/lwip/port/include/arch/cc.h
> > @@ -0,0 +1,46 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#ifndef LWIP_ARCH_CC_H
> > +#define LWIP_ARCH_CC_H
> > +
> > +#include <linux/types.h>
> > +#include <linux/kernel.h>
> > +
> > +#define LWIP_ERRNO_INCLUDE <errno.h>
> > +
> > +#define LWIP_ERRNO_STDINCLUDE        1
> > +#define LWIP_NO_UNISTD_H 1
> > +#define LWIP_TIMEVAL_PRIVATE 1
> > +
> > +extern unsigned int lwip_port_rand(void);
> > +#define LWIP_RAND() (lwip_port_rand())
> > +
> > +/* different handling for unit test, normally not needed */
> > +#ifdef LWIP_NOASSERT_ON_ERROR
> > +#define LWIP_ERROR(message, expression, handler) do { if
> (!(expression)) { \
> > +                                                 handler; }} while (0)
> > +#endif
> > +
> > +#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS
> > +
> > +#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at
> line %d in %s\n", \
> > +                                 x, __LINE__, __FILE__); } while (0)
> > +
> > +static inline int atoi(const char *str)
> > +{
> > +     int r = 0;
> > +     int i;
> > +
> > +     for (i = 0; str[i] != '\0'; ++i)
> > +             r = r * 10 + str[i] - '0';
> > +
> > +     return r;
> > +}
> > +
> > +#define LWIP_ERR_T int
> > +
> > +#endif /* LWIP_ARCH_CC_H */
> > diff --git a/lib/lwip/port/include/arch/sys_arch.h
> b/lib/lwip/port/include/arch/sys_arch.h
> > new file mode 100644
> > index 0000000000..8d95146275
> > --- /dev/null
> > +++ b/lib/lwip/port/include/arch/sys_arch.h
> > @@ -0,0 +1,59 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#ifndef LWIP_ARCH_SYS_ARCH_H
> > +#define LWIP_ARCH_SYS_ARCH_H
> > +
> > +#include "lwip/opt.h"
> > +#include "lwip/arch.h"
> > +#include "lwip/err.h"
> > +
> > +#define ERR_NEED_SCHED 123
> > +
> > +void sys_arch_msleep(u32_t delay_ms);
> > +#define sys_msleep(ms) sys_arch_msleep(ms)
> > +
> > +#if SYS_LIGHTWEIGHT_PROT
> > +typedef u32_t sys_prot_t;
> > +#endif /* SYS_LIGHTWEIGHT_PROT */
> > +
> > +#include <errno.h>
> > +
> > +#define SYS_MBOX_NULL NULL
> > +#define SYS_SEM_NULL  NULL
> > +
> > +typedef u32_t sys_prot_t;
> > +
> > +struct sys_sem;
> > +typedef struct sys_sem *sys_sem_t;
> > +#define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL))
> > +#define sys_sem_set_invalid(sem) do { if ((sem) != NULL) { *(sem) =
> NULL; }} while (0)
> > +
> > +/* let sys.h use binary semaphores for mutexes */
> > +#define LWIP_COMPAT_MUTEX 1
> > +#define LWIP_COMPAT_MUTEX_ALLOWED 1
> > +
> > +struct sys_mbox;
> > +typedef struct sys_mbox *sys_mbox_t;
> > +#define sys_mbox_valid(mbox) (((mbox) != NULL) && (*(mbox) != NULL))
> > +#define sys_mbox_set_invalid(mbox) do { if ((mbox) != NULL) { *(mbox) =
> NULL; }} while (0)
> > +
> > +struct sys_thread;
> > +typedef struct sys_thread *sys_thread_t;
> > +
> > +static inline u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
> > +{
> > +     return 0;
> > +};
> > +
> > +static inline err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
> > +{
> > +     return 0;
> > +};
> > +
> > +#define sys_sem_signal(s)
> > +
> > +#endif /* LWIP_ARCH_SYS_ARCH_H */
> > diff --git a/lib/lwip/port/include/limits.h
> b/lib/lwip/port/include/limits.h
> > new file mode 100644
> > index 0000000000..e69de29bb2
> > diff --git a/lib/lwip/port/sys-arch.c b/lib/lwip/port/sys-arch.c
> > new file mode 100644
> > index 0000000000..609eeccf8c
> > --- /dev/null
> > +++ b/lib/lwip/port/sys-arch.c
> > @@ -0,0 +1,20 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +/*
> > + * (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > + */
> > +
> > +#include <common.h>
> > +#include <rand.h>
> > +#include "lwip/opt.h"
> > +
> > +u32_t sys_now(void)
> > +{
> > +     return get_timer(0);
> > +}
> > +
> > +u32_t lwip_port_rand(void)
> > +{
> > +     return (u32_t)rand();
> > +}
> > +
> > diff --git a/lib/lwip/ulwip.h b/lib/lwip/ulwip.h
> > new file mode 100644
> > index 0000000000..11ca52aa1f
> > --- /dev/null
> > +++ b/lib/lwip/ulwip.h
> > @@ -0,0 +1,9 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +int ulwip_enabled(void);
> > +int ulwip_in_loop(void);
> > +int ulwip_loop_set(int loop);
> > +int ulwip_exit(int err);
> > +int uboot_lwip_poll(void);
> > +int ulwip_app_get_err(void);
> > +void ulwip_set_tmo(int (*tmo)(void));
> > diff --git a/net/eth-uclass.c b/net/eth-uclass.c
> > index f41da4b37b..6031ad805d 100644
> > --- a/net/eth-uclass.c
> > +++ b/net/eth-uclass.c
> > @@ -367,8 +367,10 @@ int eth_send(void *packet, int length)
> >       if (!current)
> >               return -ENODEV;
> >
> > -     if (!eth_is_active(current))
> > +     if (!eth_is_active(current)) {
> > +             printf("%s() !eth_is_active\n", __func__);
> >               return -EINVAL;
> > +     }
> >
> >       ret = eth_get_ops(current)->send(current, packet, length);
> >       if (ret < 0) {
> > diff --git a/net/net.c b/net/net.c
> > index 57da9bda85..aa9dd85a99 100644
> > --- a/net/net.c
> > +++ b/net/net.c
> > @@ -121,6 +121,7 @@
> >  #endif
> >  #include <net/tcp.h>
> >  #include <net/wget.h>
> > +#include "../lib/lwip/ulwip.h"
> >
> >  /** BOOTP EXTENTIONS **/
> >
> > @@ -438,7 +439,11 @@ int net_loop(enum proto_t protocol)
> >  #endif
> >
> >       bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
> > +#if defined(CONFIG_LWIP_LIB)
> > +     if (!ulwip_enabled() || !ulwip_in_loop())
> > +#endif
> >       net_init();
> > +
> >       if (eth_is_on_demand_init()) {
> >               eth_halt();
> >               eth_set_current();
> > @@ -619,10 +624,23 @@ restart:
> >                */
> >               eth_rx();
> >
> > +#if defined(CONFIG_LWIP_LIB)
> > +             if (ulwip_enabled()) {
> > +                     net_set_state(NETLOOP_CONTINUE);
> > +                     if (!ulwip_in_loop()) {
> > +                             if (ulwip_app_get_err())
> > +                                     net_set_state(NETLOOP_FAIL);
> > +                             else
> > +                                     net_set_state(NETLOOP_SUCCESS);
> > +                             goto done;
> > +                     }
> > +             }
> > +#endif
> >               /*
> >                *      Abort if ctrl-c was pressed.
> >                */
> >               if (ctrlc()) {
> > +                     printf("-->enter ctrlc\n");
> >                       /* cancel any ARP that may not have completed */
> >                       net_arp_wait_packet_ip.s_addr = 0;
> >
> > @@ -1177,6 +1195,13 @@ void net_process_received_packet(uchar
> *in_packet, int len)
> >       if (len < ETHER_HDR_SIZE)
> >               return;
> >
> > +#if defined(CONFIG_LWIP_LIB)
> > +     if (ulwip_enabled()) {
> > +             uboot_lwip_poll();
> > +             return;
> > +     }
> > +#endif
> > +
> >  #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
> >       if (push_packet) {
> >               (*push_packet)(in_packet, len);
> > --
> > 2.30.2
> >
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 2/3] net/lwip: add README.lwip
  2023-06-30 10:01   ` Ilias Apalodimas
@ 2023-06-30 16:33     ` Tom Rini
  2023-07-03 16:22     ` Maxim Uvarov
  1 sibling, 0 replies; 11+ messages in thread
From: Tom Rini @ 2023-06-30 16:33 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: Maxim Uvarov, u-boot, pbrobinson, joe.hershberger, rfried.dev,
	goldsimon, lwip-devel

[-- Attachment #1: Type: text/plain, Size: 455 bytes --]

On Fri, Jun 30, 2023 at 01:01:54PM +0300, Ilias Apalodimas wrote:
> Hi Maxim,
> 
> On Thu, Jun 29, 2023 at 06:34:29PM +0600, Maxim Uvarov wrote:
> > Just add inital README.lwip doc.
> 
> We'll need a more accurate description for this.  The first paragraph of
> the documentation you are adding would do

And since we're iterating on this anyhow still, please move this under
doc/ and use rST, as part of the next go-round, thanks.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 3/3] net/lwip: add lwip library for the network stack
  2023-06-29 12:34 ` [PATCHv2 3/3] net/lwip: add lwip library for the network stack Maxim Uvarov
  2023-06-30 10:03   ` Ilias Apalodimas
@ 2023-06-30 16:38   ` Tom Rini
  2023-07-03  7:15     ` Maxim Uvarov
  1 sibling, 1 reply; 11+ messages in thread
From: Tom Rini @ 2023-06-30 16:38 UTC (permalink / raw)
  To: Maxim Uvarov
  Cc: u-boot, pbrobinson, ilias.apalodimas, joe.hershberger, rfried.dev,
	goldsimon, lwip-devel

[-- Attachment #1: Type: text/plain, Size: 3678 bytes --]

On Thu, Jun 29, 2023 at 06:34:30PM +0600, Maxim Uvarov wrote:

> This commit adds lwip library for the U-boot network
> stack. Supported commands: ping, tftp, dhcp and wget.
> 
> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
[snip]
> diff --git a/lib/lwip/Kconfig b/lib/lwip/Kconfig
> new file mode 100644
> index 0000000000..80d540ba54
> --- /dev/null
> +++ b/lib/lwip/Kconfig
> @@ -0,0 +1,108 @@
> +menu "LWIP"
> +config LWIP_LIB
> +	bool "Support LWIP library"
> +	help
> +	  Selecting this option will enable the shared LWIP library code.
> +
> +menu "LWIP options"
> +config LWIP_LIB_DEBUG
> +	bool "enable debug"
> +	default n
> +config LWIP_LIB_NOASSERT
> +	bool "disable asserts"
> +	default y
> +	help
> +	    Disabling asserts reduces binary size on 16k.
> +config LWIP_LIB_TCP
> +        bool "tcp"
> +        default y
> +config LWIP_LIB_UDP
> +        bool "udp"
> +        default y
> +config LWIP_LIB_DNS
> +        bool "dns"
> +        default n
> +config LWIP_LIB_DHCP
> +        bool "dhcp"
> +        default y
> +
> +config LWIP_LIB_LOOPBACK
> +        bool "loopback"
> +        default n
> +        help
> +	   Increases size on 1k.
> +config LWIP_LIB_SOCKET
> +        bool "socket API"
> +        default n
> +config LWIP_LIB_NETCONN
> +        bool "netconn API"
> +        default n
> +config LWIP_LIB_MEM_SIZE
> +	int "mem size"
> +	default 1600
> +	range 1 4096
> +	help
> +	    MEM_SIZE: the size of the heap memory. If the application will send
> +	    a lot of data that needs to be copied, this should be set high.
> +
> +config LWIP_LIB_PBUF_LINK_HLEN
> +        int "pbuf link hlen"
> +        default 14
> +        range 4 1024
> +        help
> +	   PBUF_LINK_HLEN: the number of bytes that should be allocated for a
> +           link level header. The default is 14, the standard value for Ethernet.
> +endmenu
> +
> +config CMD_LWIP
> +        bool "lwip cmd"
> +        default y
> +	depends on LWIP_LIB
> +        help
> +          lwip networking command.
> +
> +config CMD_LWIP_PING
> +        bool "ping"
> +        default y
> +	depends on CMD_LWIP
> +        help
> +          lwip ping command.
> +
> +config CMD_LWIP_REPLACE_PING
> +        bool "replace original ping command"
> +        default n
> +
> +config CMD_LWIP_WGET
> +        bool "wget"
> +        default y
> +	depends on CMD_LWIP
> +        help
> +          lwip wget command.
> +
> +config CMD_LWIP_REPLACE_WGET
> +	bool "replace original wget command"
> +	default n
> +
> +config CMD_LWIP_TFTP
> +        bool "tftp"
> +        default y
> +	depends on CMD_LWIP
> +        help
> +          lwip tftp command.
> +
> +config CMD_LWIP_REPLACE_TFTP
> +	bool "replace original tftp command"
> +	default n
> +
> +config CMD_LWIP_DHCP
> +        bool "dhcp"
> +        default y
> +	depends on CMD_LWIP
> +	depends on LWIP_LIB_DHCP
> +        help
> +          lwip dhcp command.
> +
> +config CMD_LWIP_REPLACE_DHCP
> +	bool "replace original dhcp command"
> +	default n
> +endmenu

So,, the spacing needs to be fixed up, and "default n" is the default
when no "default" keyword is present.  But here's the big change I want,
if we enable LWIP it should replace the other commands. For debug /
testing, it's OK for "lwip dhcp" to be how to run it, but since the goal
is replacement, it needs to replace.  I want to be able to do drop
CONFIG_LWIP=y in my CI script and have all of my boards use LWIP for
the normal networking tests so I can report back that things work, or
that there's problems to sort out.  Thanks!

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 3/3] net/lwip: add lwip library for the network stack
  2023-06-30 16:38   ` Tom Rini
@ 2023-07-03  7:15     ` Maxim Uvarov
  0 siblings, 0 replies; 11+ messages in thread
From: Maxim Uvarov @ 2023-07-03  7:15 UTC (permalink / raw)
  To: Tom Rini
  Cc: u-boot, pbrobinson, ilias.apalodimas, joe.hershberger, rfried.dev,
	goldsimon, lwip-devel

On Fri, 30 Jun 2023 at 22:38, Tom Rini <trini@konsulko.com> wrote:

> On Thu, Jun 29, 2023 at 06:34:30PM +0600, Maxim Uvarov wrote:
>
> > This commit adds lwip library for the U-boot network
> > stack. Supported commands: ping, tftp, dhcp and wget.
> >
> > Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> [snip]
> > diff --git a/lib/lwip/Kconfig b/lib/lwip/Kconfig
> > new file mode 100644
> > index 0000000000..80d540ba54
> > --- /dev/null
> > +++ b/lib/lwip/Kconfig
> > @@ -0,0 +1,108 @@
> > +menu "LWIP"
> > +config LWIP_LIB
> > +     bool "Support LWIP library"
> > +     help
> > +       Selecting this option will enable the shared LWIP library code.
> > +
> > +menu "LWIP options"
> > +config LWIP_LIB_DEBUG
> > +     bool "enable debug"
> > +     default n
> > +config LWIP_LIB_NOASSERT
> > +     bool "disable asserts"
> > +     default y
> > +     help
> > +         Disabling asserts reduces binary size on 16k.
> > +config LWIP_LIB_TCP
> > +        bool "tcp"
> > +        default y
> > +config LWIP_LIB_UDP
> > +        bool "udp"
> > +        default y
> > +config LWIP_LIB_DNS
> > +        bool "dns"
> > +        default n
> > +config LWIP_LIB_DHCP
> > +        bool "dhcp"
> > +        default y
> > +
> > +config LWIP_LIB_LOOPBACK
> > +        bool "loopback"
> > +        default n
> > +        help
> > +        Increases size on 1k.
> > +config LWIP_LIB_SOCKET
> > +        bool "socket API"
> > +        default n
> > +config LWIP_LIB_NETCONN
> > +        bool "netconn API"
> > +        default n
> > +config LWIP_LIB_MEM_SIZE
> > +     int "mem size"
> > +     default 1600
> > +     range 1 4096
> > +     help
> > +         MEM_SIZE: the size of the heap memory. If the application will
> send
> > +         a lot of data that needs to be copied, this should be set high.
> > +
> > +config LWIP_LIB_PBUF_LINK_HLEN
> > +        int "pbuf link hlen"
> > +        default 14
> > +        range 4 1024
> > +        help
> > +        PBUF_LINK_HLEN: the number of bytes that should be allocated
> for a
> > +           link level header. The default is 14, the standard value for
> Ethernet.
> > +endmenu
> > +
> > +config CMD_LWIP
> > +        bool "lwip cmd"
> > +        default y
> > +     depends on LWIP_LIB
> > +        help
> > +          lwip networking command.
> > +
> > +config CMD_LWIP_PING
> > +        bool "ping"
> > +        default y
> > +     depends on CMD_LWIP
> > +        help
> > +          lwip ping command.
> > +
> > +config CMD_LWIP_REPLACE_PING
> > +        bool "replace original ping command"
> > +        default n
> > +
> > +config CMD_LWIP_WGET
> > +        bool "wget"
> > +        default y
> > +     depends on CMD_LWIP
> > +        help
> > +          lwip wget command.
> > +
> > +config CMD_LWIP_REPLACE_WGET
> > +     bool "replace original wget command"
> > +     default n
> > +
> > +config CMD_LWIP_TFTP
> > +        bool "tftp"
> > +        default y
> > +     depends on CMD_LWIP
> > +        help
> > +          lwip tftp command.
> > +
> > +config CMD_LWIP_REPLACE_TFTP
> > +     bool "replace original tftp command"
> > +     default n
> > +
> > +config CMD_LWIP_DHCP
> > +        bool "dhcp"
> > +        default y
> > +     depends on CMD_LWIP
> > +     depends on LWIP_LIB_DHCP
> > +        help
> > +          lwip dhcp command.
> > +
> > +config CMD_LWIP_REPLACE_DHCP
> > +     bool "replace original dhcp command"
> > +     default n
> > +endmenu
>
> So,, the spacing needs to be fixed up, and "default n" is the default
> when no "default" keyword is present.  But here's the big change I want,
> if we enable LWIP it should replace the other commands. For debug /
> testing, it's OK for "lwip dhcp" to be how to run it, but since the goal
> is replacement, it needs to replace.  I want to be able to do drop
> CONFIG_LWIP=y in my CI script and have all of my boards use LWIP for
> the normal networking tests so I can report back that things work, or
> that there's problems to sort out.  Thanks!
>
> --
> Tom
>

Yea, it will be good to do some good testing for this.
In this patch there are 4 options:
CONFIG_CMD_LWIP_REPLACE_PING=y
CONFIG_CMD_LWIP_REPLACE_WGET=y
CONFIG_CMD_LWIP_REPLACE_TFTP=y
CONFIG_CMD_LWIP_REPLACE_DHCP=y

which actually replace original commands with lwip one.

In the next version I will drop CONFIG_LWIP=y and make it compile when
CONFIG_NET=y is enabled.

BR,
Maxim.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCHv2 2/3] net/lwip: add README.lwip
  2023-06-30 10:01   ` Ilias Apalodimas
  2023-06-30 16:33     ` Tom Rini
@ 2023-07-03 16:22     ` Maxim Uvarov
  1 sibling, 0 replies; 11+ messages in thread
From: Maxim Uvarov @ 2023-07-03 16:22 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: u-boot, pbrobinson, joe.hershberger, rfried.dev, trini, goldsimon,
	lwip-devel

On Fri, 30 Jun 2023 at 16:01, Ilias Apalodimas <ilias.apalodimas@linaro.org>
wrote:

> Hi Maxim,
>
> On Thu, Jun 29, 2023 at 06:34:29PM +0600, Maxim Uvarov wrote:
> > Just add inital README.lwip doc.
>
> We'll need a more accurate description for this.  The first paragraph of
> the documentation you are adding would do
>
> >
> > Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> > ---
> >  doc/README.lwip | 90 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 90 insertions(+)
> >  create mode 100644 doc/README.lwip
> >
> > diff --git a/doc/README.lwip b/doc/README.lwip
> > new file mode 100644
> > index 0000000000..16f41049ab
> > --- /dev/null
> > +++ b/doc/README.lwip
> > @@ -0,0 +1,90 @@
> > +     RFC LWIP IP stack intergation for U-boot
> > +        ----------------------------------------
> > +
> > +Reliable and bug free IP stack is usually an issue when you are trying
> to write it
>
> I am not sure about the bug free part :).  Just move this entire paragraph
> as
> part of the commit message and remove the 'RFC' parts.
>
> > +from scratch. It looks like not, but when addinging new features it
> will be chelledging.
> > +This RFC work is a demo to enable lwIP (lightweight IP) which is a
> widely used open-source
> > +TCP/IP stack designed for embedded systems for U-boot. That will allow
> using already
> > +written network applications for microcontrollers.
> > +
> > +LwIP  license:
> > +lwIP is licensed under a BSD-style license:
> http://lwip.wikia.com/wiki/License.
> > +
> > +Main features include:
> > +- Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE
> > +- DHCP client, DNS client (incl. mDNS hostname resolver), AutoIP/APIPA
> (Zeroconf), SNMP agent (v1, v2c, v3, private MIB support & MIB compiler)
> > +- APIs: specialized APIs for enhanced performance, optional
> Berkeley-alike socket API
> > +- Extended features: IP forwarding over multiple network interfaces,
> TCP congestion control, RTT estimation and fast recovery/fast retransmit
> > +- Addon applications: HTTP(S) server, SNTP client, SMTP(S) client,
> ping, NetBIOS nameserver, mDNS responder, MQTT client, TFTP server
> > +
> > +U-boot implementation details:
> > +
> > +1. In general we can build lwIP as .a library and link it against
> u-boot or compile it in
> > +the U-boot tree in the same way as other U-boot files. There are few
> reasons why I selected
> > +the second variant: iwIP is very customizable with defines for
> features, memory size, types of
> > +allocation, some internal types and platform specific code. And it was
> more easy to enable/disable
> > + debug which is also done with defines, and is needed periodically.
> > +
> > +2. lwIP has 2 APIs - raw mode and sequential (as lwIP names it, or
> socket API as we name it in Linux).
> > +  This RFC implements only raw API as the proof of work.
> > +
> > +Raw IP means that the call back function for RX path is registered and
> will be called when packet
> > +data passes the IP stack and is ready for the application.
> > +
> > +This RFC has an unmodified working ping example from lwip sources which
> registeres this callback.
> > +  ping_pcb = raw_new(IP_PROTO_ICMP);
> > +  raw_recv(ping_pcb, ping_recv, NULL); <- ping_recv is app callback.
> > +  raw_bind(ping_pcb, IP_ADDR_ANY)
> > +
> > +Socket API also gives nice advantages due it will be easy to port linux
> socket applications to u-boot.
> > +I.e. lwIP sockets compatible with the linux ones. But that will require
> RX thread running in the background.
> > +So that means we need some kind of scheduler, locking and threading
> support or find some other solution.
> > +
> > +3.  Input and output
> > +
> > +RX packet path is injected to U-boot eth_rx() polling loop and TX patch
> is in eth_send() accordingly.
> > +So we do not touch any drivers code and just eat packets when they are
> ready.
> > +
> > +4. Testing
> > +
> > +Unmodified ping example can be used. I did ping from qemu/u-boot tap
> device on the host:
> > +
> > +=> lwip init
> > +=> lwip ping 192.168.1.2
> > +ping: recv 3 ms
> > +tcpdump on the host:
> > +5:09:10.925951 ARP, Request who-has 192.168.1.200 tell 192.168.1.200,
> length 28 15:09:12.114643 IP6 fe80::38e2:41ff:fec3:8bda > ip6-allrouters:
> ICMP6, router solicitation, length 16 15:09:20.370725 ARP, Request who-has
> 192.168.1.2 tell 192.168.1.200, length 28 15:09:20.370740 ARP, Reply
> 192.168.1.2 is-at 3a:e2:41:c3:8b:da (oui Unknown), length 28
> 15:09:20.372789 IP 192.168.1.200 > 192.168.1.2: ICMP echo request, id
> 44975, seq 1, length 40 15:09:20.372810 IP 192.168.1.2 > 192.168.1.200:
> ICMP echo reply, id 44975, seq 1, length 40 15:09:25.426636 ARP, Request
> who-has 192.168.1.200 tell 192.168.1.2, length 28 15:09:25.426870 ARP,
> Reply 192.168.1.200 is-at f6:11:01:02:03:04 (oui Unknown), length 28
> > +
> > +
> > +5. Wget example
> > +
> > +Http server has 192.168.1.2 IP address. (I did not port DNS resolving
> yet,
> > +but it's also exist in lwip.) So example just downloads some file with
> http
> > +protocol:
> > +
> > +Net:   eth0: virtio-net#30
> > +Hit any key to stop autoboot:  0
> > +=> lwip init
> > +Starting lwIP, local interface IP is 192.168.1.200
> > +Initialized LWIP stack
> > +=> lwip wget http://192.168.1.2/
> > +downloading http://192.168.1.2/ to addr 0x40200000
>
> Does wget with lwip work with dns as well?
>
>
Yes it works with dns also. But to test that I need to set up access to the
dns server. So dns is more likely the next command to implement.


> > +downloaded chunk size 294, to addr 0x40200000
> > +downloaded chunk size 318, to addr 0x40200126
> > +=> md 0x40200000 0x40
> > +40200000: 4f44213c 50595443 74682045 0a3e6c6d  <!DOCTYPE html>.
> > +40200010: 6d74683c 3c0a3e6c 64616568 743c0a3e  <html>.<head>.<t
> > +40200020: 656c7469 6c65573e 656d6f63 206f7420  itle>Welcome to
> > +40200030: 6e69676e 2f3c2178 6c746974 3c0a3e65  nginx!</title>.<
> > +40200040: 6c797473 200a3e65 62202020 2079646f  style>.    body
> > +40200050: 20200a7b 20202020 69772020 3a687464  {.        width:
> > +40200060: 65353320 200a3b6d 20202020 6d202020   35em;.        m
> > +40200070: 69677261 30203a6e 74756120 200a3b6f  argin: 0 auto;.
> > +40200080: 20202020 66202020 2d746e6f 696d6166         font-fami
> > +40200090: 203a796c 6f686154 202c616d 64726556  ly: Tahoma, Verd
> > +402000a0: 2c616e61 69724120 202c6c61 736e6173  ana, Arial, sans
> > +402000b0: 7265732d 0a3b6669 20202020 2f3c0a7d  -serif;.    }.</
> > +402000c0: 6c797473 3c0a3e65 6165682f 3c0a3e64  style>.</head>.<
> > +402000d0: 79646f62 683c0a3e 65573e31 6d6f636c  body>.<h1>Welcom
> > +402000e0: 6f742065 69676e20 3c21786e 3e31682f  e to nginx!</h1>
> > +402000f0: 3e703c0a 79206649 7320756f 74206565  .<p>If you see t
> > --
> > 2.30.2
> >
>
> Thanks
> /Ilias
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2023-07-03 16:22 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-29 12:34 [PATCHv2 1/3] net/lwip: add lwip-external submodule Maxim Uvarov
2023-06-29 12:34 ` [PATCHv2 2/3] net/lwip: add README.lwip Maxim Uvarov
2023-06-30 10:01   ` Ilias Apalodimas
2023-06-30 16:33     ` Tom Rini
2023-07-03 16:22     ` Maxim Uvarov
2023-06-29 12:34 ` [PATCHv2 3/3] net/lwip: add lwip library for the network stack Maxim Uvarov
2023-06-30 10:03   ` Ilias Apalodimas
2023-06-30 10:31     ` Maxim Uvarov
2023-06-30 16:38   ` Tom Rini
2023-07-03  7:15     ` Maxim Uvarov
2023-06-29 19:10 ` [PATCHv2 1/3] net/lwip: add lwip-external submodule Simon Glass

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox