diff mbox series

[PATCHv4,2/5] net/lwip: add lwip library for the network stack

Message ID 20230714142000.5534-3-maxim.uvarov@linaro.org
State New
Headers show
Series net/lwip: add lwip library for the network stack | expand

Commit Message

Maxim Uvarov July 14, 2023, 2:19 p.m. UTC
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 +
 boot/bootmeth_pxe.c                   |   2 +-
 cmd/net.c                             |  48 +----
 cmd/pxe.c                             |   2 +-
 include/net.h                         |   8 +-
 lib/Kconfig                           |   2 +
 lib/Makefile                          |   2 +
 lib/lwip/Kconfig                      |  63 ++++++
 lib/lwip/Makefile                     | 101 ++++++++++
 lib/lwip/apps/dhcp/lwip-dhcp.c        |  52 +++++
 lib/lwip/apps/http/lwip-wget.c        |  74 +++++++
 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        | 124 ++++++++++++
 lib/lwip/cmd-lwip.c                   | 269 ++++++++++++++++++++++++++
 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/Kconfig                           |   1 +
 net/net.c                             |  24 +++
 25 files changed, 1430 insertions(+), 44 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

Comments

Ilias Apalodimas July 27, 2023, 1:29 p.m. UTC | #1
Hi Maxim, 


This is too much for a single patch review.  Can you pleas split it in
something that's easier to review and comment. 

For example, 
#1 add the lwip library only
#2-#5 add ping, wget, tcp and ping

Some random comments below as well.

On Fri, Jul 14, 2023 at 08:19:57PM +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 +
>  boot/bootmeth_pxe.c                   |   2 +-
>  cmd/net.c                             |  48 +----
>  cmd/pxe.c                             |   2 +-
>  include/net.h                         |   8 +-
>  lib/Kconfig                           |   2 +
>  lib/Makefile                          |   2 +
>  lib/lwip/Kconfig                      |  63 ++++++
>  lib/lwip/Makefile                     | 101 ++++++++++
>  lib/lwip/apps/dhcp/lwip-dhcp.c        |  52 +++++
>  lib/lwip/apps/http/lwip-wget.c        |  74 +++++++
>  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        | 124 ++++++++++++
>  lib/lwip/cmd-lwip.c                   | 269 ++++++++++++++++++++++++++
>  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/Kconfig                           |   1 +
>  net/net.c                             |  24 +++
>  25 files changed, 1430 insertions(+), 44 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/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
> index e6992168c0..30331a9806 100644
> --- a/boot/bootmeth_pxe.c
> +++ b/boot/bootmeth_pxe.c
> @@ -118,7 +118,7 @@ static int distro_pxe_read_file(struct udevice *dev, struct bootflow *bflow,
>  	tftp_argv[1] = file_addr;
>  	tftp_argv[2] = (void *)file_path;
>  
> -	if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
> +	if (do_lwip_tftp(ctx->cmdtp, 0, 3, tftp_argv))
>  		return -ENOENT;
>  	ret = pxe_get_file_size(&size);
>  	if (ret)
> diff --git a/cmd/net.c b/cmd/net.c
> index 0e9f200ca9..6d704fba86 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -36,19 +36,9 @@ U_BOOT_CMD(
>  #endif
>  
>  #ifdef CONFIG_CMD_TFTPBOOT
> -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> -{
> -	int ret;
> -
> -	bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
> -	ret = netboot_common(TFTPGET, cmdtp, argc, argv);
> -	bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
> -	return ret;
> -}
> -
>  #if IS_ENABLED(CONFIG_IPV6)
>  U_BOOT_CMD(
> -	tftpboot,	4,	1,	do_tftpb,
> +	tftpboot,	4,	1, do_lwip_tftp,
>  	"boot image via network using TFTP protocol\n"
>  	"To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed "
>  	"with [] brackets",
> @@ -56,7 +46,7 @@ U_BOOT_CMD(
>  );
>  #else
>  U_BOOT_CMD(
> -	tftpboot,	3,	1,	do_tftpb,
> +	tftpboot,	3,	1,  do_lwip_tftp,
>  	"load file via network using TFTP protocol",
>  	"[loadAddress] [[hostIPaddr:]bootfilename]"
>  );
> @@ -112,7 +102,7 @@ U_BOOT_CMD(
>  static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
>  		   char *const argv[])
>  {
> -	return netboot_common(DHCP, cmdtp, argc, argv);
> +	return do_lwip_dhcp();
>  }
>  
>  U_BOOT_CMD(
> @@ -137,13 +127,11 @@ U_BOOT_CMD(
>  #endif
>  
>  #if defined(CONFIG_CMD_WGET)
> -static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
> -{
> -	return netboot_common(WGET, cmdtp, argc, argv);
> -}
> +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
> +		 char *const argv[]);
>  
>  U_BOOT_CMD(
> -	wget,   3,      1,      do_wget,
> +	wget,   3,      1, do_lwip_wget,

I thought we agreed on keeping both the native u-boot stack and lwip until
we can proove the later is useful.  Do I remember this wrong? Same goes for
all the other commands

>  	"boot image via network using HTTP protocol",
>  	"[loadAddress] [[hostIPaddr:]path and image name]"
>  );
> @@ -376,28 +364,10 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
>  }
>  
>  #if defined(CONFIG_CMD_PING)
> -static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> -		   char *const argv[])
> -{
> -	if (argc < 2)
> -		return CMD_RET_USAGE;
> -
> -	net_ping_ip = string_to_ip(argv[1]);
> -	if (net_ping_ip.s_addr == 0)
> -		return CMD_RET_USAGE;
> -
> -	if (net_loop(PING) < 0) {
> -		printf("ping failed; host %s is not alive\n", argv[1]);
> -		return CMD_RET_FAILURE;
> -	}
> -
> -	printf("host %s is alive\n", argv[1]);
> -
> -	return CMD_RET_SUCCESS;
> -}
> -
> +extern int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> +			char *const argv[]);

Why extern? Cant we define it properly as part of our header file?

>  U_BOOT_CMD(
> -	ping,	2,	1,	do_ping,
> +	ping,	2,	1, do_lwip_ping,
>  	"send ICMP ECHO_REQUEST to network host",
>  	"pingAddress"
>  );
> diff --git a/cmd/pxe.c b/cmd/pxe.c
> index db8e4697f2..bd4d6f5f2b 100644
> --- a/cmd/pxe.c
> +++ b/cmd/pxe.c
> @@ -33,7 +33,7 @@ static int do_get_tftp(struct pxe_context *ctx, const char *file_path,
>  	tftp_argv[1] = file_addr;
>  	tftp_argv[2] = (void *)file_path;
>  
> -	if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
> +	if (do_lwip_tftp(ctx->cmdtp, 0, 3, tftp_argv))
>  		return -ENOENT;
>  	ret = pxe_get_file_size(sizep);
>  	if (ret)
> diff --git a/include/net.h b/include/net.h
> index 1a99009959..6b573f3319 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -54,8 +54,10 @@ struct in_addr {
>  	__be32 s_addr;
>  };
>  
> +int do_lwip_dhcp(void);
> +
>  /**
> - * do_tftpb - Run the tftpboot command
> + * do_lwip_tftp - Run the tftpboot command
>   *
>   * @cmdtp: Command information for tftpboot
>   * @flag: Command flags (CMD_FLAG_...)
> @@ -63,7 +65,7 @@ struct in_addr {
>   * @argv: List of arguments
>   * Return: result (see enum command_ret_t)
>   */
> -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
> +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
>  
>  /**
>   * An incoming packet handler.
> @@ -561,7 +563,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..3688ac3305
> --- /dev/null
> +++ b/lib/lwip/Kconfig
> @@ -0,0 +1,63 @@
> +menu "LWIP"
> +config LWIP_LIB
> +	bool "Support LWIP library"
> +	help
> +	  Selecting this option will enable the 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

You need some useful help entry on all of those. 

> +        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"
> +        help
> +	   Increases size on 1k.
> +
> +config LWIP_LIB_SOCKET
> +        bool "socket API"
> +
> +config LWIP_LIB_NETCONN
> +        bool "netconn API"
> +
> +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
> +
> +endmenu
> diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile
> new file mode 100644
> index 0000000000..e1a8a2a7b7
> --- /dev/null
> +++ b/lib/lwip/Makefile
> @@ -0,0 +1,101 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> +
> +LWIPDIR=lwip-external/src
> +
> +ccflags-y += -I$(srctree)/lib/lwip/port/include
> +ccflags-y += -I$(srctree)/lib/lwip/lwip-external/src/include -I$(srctree)/lib/lwip
> +
> +obj-$(CONFIG_NET) += $(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_NET) += $(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_NET) += $(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_NET) += $(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_NET) += $(LWIPDIR)/netif/ethernet.o
> +
> +obj-$(CONFIG_NET) += port/if.o
> +obj-$(CONFIG_NET) += port/sys-arch.o
> +
> +obj-$(CONFIG_NET) += cmd-lwip.o
> +
> +
> +ccflags-y += -I$(srctree)/lib/lwip/apps/ping
> +.PHONY: $(obj)/apps/ping/ping.c
> +$(obj)/apps/ping/ping.o: $(obj)/apps/ping/ping.c
> +$(obj)/apps/ping/ping.c:
> +	cp $(srctree)/lib/lwip/lwip-external/contrib/apps/ping/ping.c $(obj)/apps/ping/ping.c
> +
> +obj-$(CONFIG_CMD_PING) += apps/ping/ping.o
> +obj-$(CONFIG_CMD_PING) += 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 $(srctree)/lib/lwip/lwip-external/src/apps/http/http_client.c $(obj)/apps/http/http_client.c
> +	cp $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/http_client.h $(obj)/apps/http/http_client.h
> +
> +obj-$(CONFIG_CMD_WGET) += apps/http/http_client.o
> +obj-$(CONFIG_CMD_WGET) += apps/http/lwip-wget.o
> +
> +ccflags-y += -I$(CURDIR)/lib/lwip/apps/tftp
> +$(obj)/apps/tftp/tftp.o: $(obj)/apps/tftp/tftp.c
> +.PHONY: $(obj)/apps/tftp/tftp.c
> +$(obj)/apps/tftp/tftp.c:
> +	cp $(srctree)/lib/lwip/lwip-external/src/apps/tftp/tftp.c $(obj)/apps/tftp/tftp.c
> +	cp $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/tftp_client.h $(obj)/apps/tftp/tftp_client.h
> +	cp $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/tftp_common.h $(obj)/apps/tftp/tftp_common.h
> +	cp $(srctree)/lib/lwip/lwip-external/contrib/examples/tftp/tftp_example.h $(obj)/apps/tftp/tftp_example.h
> +
> +obj-$(CONFIG_CMD_TFTPBOOT) += apps/tftp/tftp.o
> +obj-$(CONFIG_CMD_TFTPBOOT) += apps/tftp/lwip-tftp.o
> +
> +obj-$(CONFIG_CMD_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;

Again why extern?  I dont think it's sane to carry around the uboot_netif
variable everytime we need to change a member.  Instead we should functions
doing that

> +
> +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;
> +}

The return value is always 0, why are we at least checking the result of
env_set()?

> +
> +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..0308b0b04a
> --- /dev/null
> +++ b/lib/lwip/apps/http/lwip-wget.c
> @@ -0,0 +1,74 @@
> +// 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);
> +		env_set_ulong("filesize", 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));

sizeof(settings) is preferred

> +	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;
> +	}
> +
> +	env_set_hex("fileaddr", addr);
> +	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"

Please dont do this.  Can't we just use -I or something and have this is a
normal include path?

> +
> +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..511d82e600
> --- /dev/null
> +++ b/lib/lwip/apps/tftp/lwip-tftp.c
> @@ -0,0 +1,124 @@
> +// 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);
> +
> +	env_set_ulong("filesize", 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);
> +
> +	env_set_hex("fileaddr", addr);
> +	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..625c8c53b8
> --- /dev/null
> +++ b/lib/lwip/cmd-lwip.c
> @@ -0,0 +1,269 @@
> +// 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_PING)
> +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();
> +}
> +#endif /* CONFIG_CMD_PING */
> +
> +#if defined(CONFIG_CMD_WGET)
> +extern int lwip_wget(ulong addr, char *url);
> +
> +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();
> +}
> +#endif
> +
> +#if defined(CONFIG_CMD_TFTPBOOT)
> +extern int lwip_tftp(ulong addr, char *filename);
> +
> +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 /* CONFIG_CMD_TFTPBOOT */
> +
> +#if defined(CONFIG_CMD_DHCP)
> +extern int ulwip_dhcp(void);
> +
> +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_TFTPBOOT)) {
> +		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 /* CONFIG_CMD_DHCP */
> +
> +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_WGET)
> +	U_BOOT_CMD_MKENT(wget, 2, 0, do_lwip_wget, "", ""),
> +#endif
> +#if defined(CONFIG_CMD_TFTPBOOT)
> +	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_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..37c02a451f
> --- /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_DHCP)
> +struct netif uboot_netif;
> +#else
> +static struct netif uboot_netif;
> +#endif

I am not sure I understand why this exists.  If you want to change some
some members of the struct from the dhcp code, why dont you create a
function that resides here?

> +
> +#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/Kconfig b/net/Kconfig
> index a1ec3f8542..2c5d8b8aca 100644
> --- a/net/Kconfig
> +++ b/net/Kconfig
> @@ -5,6 +5,7 @@
>  menuconfig NET
>  	bool "Networking support"
>  	default y
> +	select LWIP_LIB
>  
>  if NET
>  
> diff --git a/net/net.c b/net/net.c
> index 57da9bda85..3d9a2e798a 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,6 +624,18 @@ 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.
>  		 */
> @@ -1177,6 +1194,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
> 

Thanks
/Ilias
Maxim Uvarov July 27, 2023, 2:23 p.m. UTC | #2
On Thu, 27 Jul 2023 at 19:29, Ilias Apalodimas <ilias.apalodimas@linaro.org>
wrote:

> Hi Maxim,
>
>
> This is too much for a single patch review.  Can you pleas split it in
> something that's easier to review and comment.
>
> For example,
> #1 add the lwip library only
> #2-#5 add ping, wget, tcp and ping
>
> Some random comments below as well.
>
> On Fri, Jul 14, 2023 at 08:19:57PM +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 +
> >  boot/bootmeth_pxe.c                   |   2 +-
> >  cmd/net.c                             |  48 +----
> >  cmd/pxe.c                             |   2 +-
> >  include/net.h                         |   8 +-
> >  lib/Kconfig                           |   2 +
> >  lib/Makefile                          |   2 +
> >  lib/lwip/Kconfig                      |  63 ++++++
> >  lib/lwip/Makefile                     | 101 ++++++++++
> >  lib/lwip/apps/dhcp/lwip-dhcp.c        |  52 +++++
> >  lib/lwip/apps/http/lwip-wget.c        |  74 +++++++
> >  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        | 124 ++++++++++++
> >  lib/lwip/cmd-lwip.c                   | 269 ++++++++++++++++++++++++++
> >  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/Kconfig                           |   1 +
> >  net/net.c                             |  24 +++
> >  25 files changed, 1430 insertions(+), 44 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/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
> > index e6992168c0..30331a9806 100644
> > --- a/boot/bootmeth_pxe.c
> > +++ b/boot/bootmeth_pxe.c
> > @@ -118,7 +118,7 @@ static int distro_pxe_read_file(struct udevice *dev,
> struct bootflow *bflow,
> >       tftp_argv[1] = file_addr;
> >       tftp_argv[2] = (void *)file_path;
> >
> > -     if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
> > +     if (do_lwip_tftp(ctx->cmdtp, 0, 3, tftp_argv))
> >               return -ENOENT;
> >       ret = pxe_get_file_size(&size);
> >       if (ret)
> > diff --git a/cmd/net.c b/cmd/net.c
> > index 0e9f200ca9..6d704fba86 100644
> > --- a/cmd/net.c
> > +++ b/cmd/net.c
> > @@ -36,19 +36,9 @@ U_BOOT_CMD(
> >  #endif
> >
> >  #ifdef CONFIG_CMD_TFTPBOOT
> > -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const
> argv[])
> > -{
> > -     int ret;
> > -
> > -     bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
> > -     ret = netboot_common(TFTPGET, cmdtp, argc, argv);
> > -     bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
> > -     return ret;
> > -}
> > -
> >  #if IS_ENABLED(CONFIG_IPV6)
> >  U_BOOT_CMD(
> > -     tftpboot,       4,      1,      do_tftpb,
> > +     tftpboot,       4,      1, do_lwip_tftp,
> >       "boot image via network using TFTP protocol\n"
> >       "To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed "
> >       "with [] brackets",
> > @@ -56,7 +46,7 @@ U_BOOT_CMD(
> >  );
> >  #else
> >  U_BOOT_CMD(
> > -     tftpboot,       3,      1,      do_tftpb,
> > +     tftpboot,       3,      1,  do_lwip_tftp,
> >       "load file via network using TFTP protocol",
> >       "[loadAddress] [[hostIPaddr:]bootfilename]"
> >  );
> > @@ -112,7 +102,7 @@ U_BOOT_CMD(
> >  static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
> >                  char *const argv[])
> >  {
> > -     return netboot_common(DHCP, cmdtp, argc, argv);
> > +     return do_lwip_dhcp();
> >  }
> >
> >  U_BOOT_CMD(
> > @@ -137,13 +127,11 @@ U_BOOT_CMD(
> >  #endif
> >
> >  #if defined(CONFIG_CMD_WGET)
> > -static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char *
> const argv[])
> > -{
> > -     return netboot_common(WGET, cmdtp, argc, argv);
> > -}
> > +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
> > +              char *const argv[]);
> >
> >  U_BOOT_CMD(
> > -     wget,   3,      1,      do_wget,
> > +     wget,   3,      1, do_lwip_wget,
>
> I thought we agreed on keeping both the native u-boot stack and lwip until
> we can proove the later is useful.  Do I remember this wrong? Same goes for
> all the other commands
>

Ilias thanks for review, I will walk over all comments.

Regarding this one in v3, there was a comment from Tom to switch to a new
version
for implemented comments. v3 had 3 modes 1 lwip disabled, original commands
2. lwip enabled,
original command and "lwip  <command>" 3. lwip replaces original commands
and has "lwip <command>"
For current v4 it's mode 3 only.

<snip>
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!
</snip>

I agree if we can do good tests for lwip variants then more likely no need
to support original commands.
But I would like to see some consolidation here so I can account for that
in updated patches.

BR,
Maxim.




>
> >       "boot image via network using HTTP protocol",
> >       "[loadAddress] [[hostIPaddr:]path and image name]"
> >  );
> > @@ -376,28 +364,10 @@ static int netboot_common(enum proto_t proto,
> struct cmd_tbl *cmdtp, int argc,
> >  }
> >
> >  #if defined(CONFIG_CMD_PING)
> > -static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> > -                char *const argv[])
> > -{
> > -     if (argc < 2)
> > -             return CMD_RET_USAGE;
> > -
> > -     net_ping_ip = string_to_ip(argv[1]);
> > -     if (net_ping_ip.s_addr == 0)
> > -             return CMD_RET_USAGE;
> > -
> > -     if (net_loop(PING) < 0) {
> > -             printf("ping failed; host %s is not alive\n", argv[1]);
> > -             return CMD_RET_FAILURE;
> > -     }
> > -
> > -     printf("host %s is alive\n", argv[1]);
> > -
> > -     return CMD_RET_SUCCESS;
> > -}
> > -
> > +extern int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> > +                     char *const argv[]);
>
> Why extern? Cant we define it properly as part of our header file?
>
> >  U_BOOT_CMD(
> > -     ping,   2,      1,      do_ping,
> > +     ping,   2,      1, do_lwip_ping,
> >       "send ICMP ECHO_REQUEST to network host",
> >       "pingAddress"
> >  );
> > diff --git a/cmd/pxe.c b/cmd/pxe.c
> > index db8e4697f2..bd4d6f5f2b 100644
> > --- a/cmd/pxe.c
> > +++ b/cmd/pxe.c
> > @@ -33,7 +33,7 @@ static int do_get_tftp(struct pxe_context *ctx, const
> char *file_path,
> >       tftp_argv[1] = file_addr;
> >       tftp_argv[2] = (void *)file_path;
> >
> > -     if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
> > +     if (do_lwip_tftp(ctx->cmdtp, 0, 3, tftp_argv))
> >               return -ENOENT;
> >       ret = pxe_get_file_size(sizep);
> >       if (ret)
> > diff --git a/include/net.h b/include/net.h
> > index 1a99009959..6b573f3319 100644
> > --- a/include/net.h
> > +++ b/include/net.h
> > @@ -54,8 +54,10 @@ struct in_addr {
> >       __be32 s_addr;
> >  };
> >
> > +int do_lwip_dhcp(void);
> > +
> >  /**
> > - * do_tftpb - Run the tftpboot command
> > + * do_lwip_tftp - Run the tftpboot command
> >   *
> >   * @cmdtp: Command information for tftpboot
> >   * @flag: Command flags (CMD_FLAG_...)
> > @@ -63,7 +65,7 @@ struct in_addr {
> >   * @argv: List of arguments
> >   * Return: result (see enum command_ret_t)
> >   */
> > -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const
> argv[]);
> > +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, char *const
> argv[]);
> >
> >  /**
> >   * An incoming packet handler.
> > @@ -561,7 +563,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..3688ac3305
> > --- /dev/null
> > +++ b/lib/lwip/Kconfig
> > @@ -0,0 +1,63 @@
> > +menu "LWIP"
> > +config LWIP_LIB
> > +     bool "Support LWIP library"
> > +     help
> > +       Selecting this option will enable the 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
>
> You need some useful help entry on all of those.
>
> > +        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"
> > +        help
> > +        Increases size on 1k.
> > +
> > +config LWIP_LIB_SOCKET
> > +        bool "socket API"
> > +
> > +config LWIP_LIB_NETCONN
> > +        bool "netconn API"
> > +
> > +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
> > +
> > +endmenu
> > diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile
> > new file mode 100644
> > index 0000000000..e1a8a2a7b7
> > --- /dev/null
> > +++ b/lib/lwip/Makefile
> > @@ -0,0 +1,101 @@
> > +# SPDX-License-Identifier: GPL-2.0+
> > +#
> > +# (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > +
> > +LWIPDIR=lwip-external/src
> > +
> > +ccflags-y += -I$(srctree)/lib/lwip/port/include
> > +ccflags-y += -I$(srctree)/lib/lwip/lwip-external/src/include
> -I$(srctree)/lib/lwip
> > +
> > +obj-$(CONFIG_NET) += $(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_NET) += $(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_NET) += $(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_NET) += $(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_NET) += $(LWIPDIR)/netif/ethernet.o
> > +
> > +obj-$(CONFIG_NET) += port/if.o
> > +obj-$(CONFIG_NET) += port/sys-arch.o
> > +
> > +obj-$(CONFIG_NET) += cmd-lwip.o
> > +
> > +
> > +ccflags-y += -I$(srctree)/lib/lwip/apps/ping
> > +.PHONY: $(obj)/apps/ping/ping.c
> > +$(obj)/apps/ping/ping.o: $(obj)/apps/ping/ping.c
> > +$(obj)/apps/ping/ping.c:
> > +     cp $(srctree)/lib/lwip/lwip-external/contrib/apps/ping/ping.c
> $(obj)/apps/ping/ping.c
> > +
> > +obj-$(CONFIG_CMD_PING) += apps/ping/ping.o
> > +obj-$(CONFIG_CMD_PING) += 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 $(srctree)/lib/lwip/lwip-external/src/apps/http/http_client.c
> $(obj)/apps/http/http_client.c
> > +     cp
> $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/http_client.h
> $(obj)/apps/http/http_client.h
> > +
> > +obj-$(CONFIG_CMD_WGET) += apps/http/http_client.o
> > +obj-$(CONFIG_CMD_WGET) += apps/http/lwip-wget.o
> > +
> > +ccflags-y += -I$(CURDIR)/lib/lwip/apps/tftp
> > +$(obj)/apps/tftp/tftp.o: $(obj)/apps/tftp/tftp.c
> > +.PHONY: $(obj)/apps/tftp/tftp.c
> > +$(obj)/apps/tftp/tftp.c:
> > +     cp $(srctree)/lib/lwip/lwip-external/src/apps/tftp/tftp.c
> $(obj)/apps/tftp/tftp.c
> > +     cp
> $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/tftp_client.h
> $(obj)/apps/tftp/tftp_client.h
> > +     cp
> $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/tftp_common.h
> $(obj)/apps/tftp/tftp_common.h
> > +     cp
> $(srctree)/lib/lwip/lwip-external/contrib/examples/tftp/tftp_example.h
> $(obj)/apps/tftp/tftp_example.h
> > +
> > +obj-$(CONFIG_CMD_TFTPBOOT) += apps/tftp/tftp.o
> > +obj-$(CONFIG_CMD_TFTPBOOT) += apps/tftp/lwip-tftp.o
> > +
> > +obj-$(CONFIG_CMD_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;
>
> Again why extern?  I dont think it's sane to carry around the uboot_netif
> variable everytime we need to change a member.  Instead we should functions
> doing that
>
> > +
> > +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;
> > +}
>
> The return value is always 0, why are we at least checking the result of
> env_set()?
>
> > +
> > +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..0308b0b04a
> > --- /dev/null
> > +++ b/lib/lwip/apps/http/lwip-wget.c
> > @@ -0,0 +1,74 @@
> > +// 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);
> > +             env_set_ulong("filesize", 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));
>
> sizeof(settings) is preferred
>
> > +     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;
> > +     }
> > +
> > +     env_set_hex("fileaddr", addr);
> > +     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"
>
> Please dont do this.  Can't we just use -I or something and have this is a
> normal include path?
>
> > +
> > +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..511d82e600
> > --- /dev/null
> > +++ b/lib/lwip/apps/tftp/lwip-tftp.c
> > @@ -0,0 +1,124 @@
> > +// 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);
> > +
> > +     env_set_ulong("filesize", 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);
> > +
> > +     env_set_hex("fileaddr", addr);
> > +     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..625c8c53b8
> > --- /dev/null
> > +++ b/lib/lwip/cmd-lwip.c
> > @@ -0,0 +1,269 @@
> > +// 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_PING)
> > +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();
> > +}
> > +#endif /* CONFIG_CMD_PING */
> > +
> > +#if defined(CONFIG_CMD_WGET)
> > +extern int lwip_wget(ulong addr, char *url);
> > +
> > +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();
> > +}
> > +#endif
> > +
> > +#if defined(CONFIG_CMD_TFTPBOOT)
> > +extern int lwip_tftp(ulong addr, char *filename);
> > +
> > +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 /* CONFIG_CMD_TFTPBOOT */
> > +
> > +#if defined(CONFIG_CMD_DHCP)
> > +extern int ulwip_dhcp(void);
> > +
> > +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_TFTPBOOT)) {
> > +             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 /* CONFIG_CMD_DHCP */
> > +
> > +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_WGET)
> > +     U_BOOT_CMD_MKENT(wget, 2, 0, do_lwip_wget, "", ""),
> > +#endif
> > +#if defined(CONFIG_CMD_TFTPBOOT)
> > +     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_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..37c02a451f
> > --- /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_DHCP)
> > +struct netif uboot_netif;
> > +#else
> > +static struct netif uboot_netif;
> > +#endif
>
> I am not sure I understand why this exists.  If you want to change some
> some members of the struct from the dhcp code, why dont you create a
> function that resides here?
>
> > +
> > +#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/Kconfig b/net/Kconfig
> > index a1ec3f8542..2c5d8b8aca 100644
> > --- a/net/Kconfig
> > +++ b/net/Kconfig
> > @@ -5,6 +5,7 @@
> >  menuconfig NET
> >       bool "Networking support"
> >       default y
> > +     select LWIP_LIB
> >
> >  if NET
> >
> > diff --git a/net/net.c b/net/net.c
> > index 57da9bda85..3d9a2e798a 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,6 +624,18 @@ 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.
> >                */
> > @@ -1177,6 +1194,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
> >
>
> Thanks
> /Ilias
>
Maxim Uvarov July 28, 2023, 2:26 p.m. UTC | #3
On Thu, 27 Jul 2023 at 19:29, Ilias Apalodimas <ilias.apalodimas@linaro.org>
wrote:

> Hi Maxim,
>
>
> This is too much for a single patch review.  Can you pleas split it in
> something that's easier to review and comment.
>
> For example,
> #1 add the lwip library only
> #2-#5 add ping, wget, tcp and ping
>
> Some random comments below as well.
>
> On Fri, Jul 14, 2023 at 08:19:57PM +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 +
> >  boot/bootmeth_pxe.c                   |   2 +-
> >  cmd/net.c                             |  48 +----
> >  cmd/pxe.c                             |   2 +-
> >  include/net.h                         |   8 +-
> >  lib/Kconfig                           |   2 +
> >  lib/Makefile                          |   2 +
> >  lib/lwip/Kconfig                      |  63 ++++++
> >  lib/lwip/Makefile                     | 101 ++++++++++
> >  lib/lwip/apps/dhcp/lwip-dhcp.c        |  52 +++++
> >  lib/lwip/apps/http/lwip-wget.c        |  74 +++++++
> >  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        | 124 ++++++++++++
> >  lib/lwip/cmd-lwip.c                   | 269 ++++++++++++++++++++++++++
> >  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/Kconfig                           |   1 +
> >  net/net.c                             |  24 +++
> >  25 files changed, 1430 insertions(+), 44 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/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
> > index e6992168c0..30331a9806 100644
> > --- a/boot/bootmeth_pxe.c
> > +++ b/boot/bootmeth_pxe.c
> > @@ -118,7 +118,7 @@ static int distro_pxe_read_file(struct udevice *dev,
> struct bootflow *bflow,
> >       tftp_argv[1] = file_addr;
> >       tftp_argv[2] = (void *)file_path;
> >
> > -     if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
> > +     if (do_lwip_tftp(ctx->cmdtp, 0, 3, tftp_argv))
> >               return -ENOENT;
> >       ret = pxe_get_file_size(&size);
> >       if (ret)
> > diff --git a/cmd/net.c b/cmd/net.c
> > index 0e9f200ca9..6d704fba86 100644
> > --- a/cmd/net.c
> > +++ b/cmd/net.c
> > @@ -36,19 +36,9 @@ U_BOOT_CMD(
> >  #endif
> >
> >  #ifdef CONFIG_CMD_TFTPBOOT
> > -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const
> argv[])
> > -{
> > -     int ret;
> > -
> > -     bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
> > -     ret = netboot_common(TFTPGET, cmdtp, argc, argv);
> > -     bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
> > -     return ret;
> > -}
> > -
> >  #if IS_ENABLED(CONFIG_IPV6)
> >  U_BOOT_CMD(
> > -     tftpboot,       4,      1,      do_tftpb,
> > +     tftpboot,       4,      1, do_lwip_tftp,
> >       "boot image via network using TFTP protocol\n"
> >       "To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed "
> >       "with [] brackets",
> > @@ -56,7 +46,7 @@ U_BOOT_CMD(
> >  );
> >  #else
> >  U_BOOT_CMD(
> > -     tftpboot,       3,      1,      do_tftpb,
> > +     tftpboot,       3,      1,  do_lwip_tftp,
> >       "load file via network using TFTP protocol",
> >       "[loadAddress] [[hostIPaddr:]bootfilename]"
> >  );
> > @@ -112,7 +102,7 @@ U_BOOT_CMD(
> >  static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
> >                  char *const argv[])
> >  {
> > -     return netboot_common(DHCP, cmdtp, argc, argv);
> > +     return do_lwip_dhcp();
> >  }
> >
> >  U_BOOT_CMD(
> > @@ -137,13 +127,11 @@ U_BOOT_CMD(
> >  #endif
> >
> >  #if defined(CONFIG_CMD_WGET)
> > -static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char *
> const argv[])
> > -{
> > -     return netboot_common(WGET, cmdtp, argc, argv);
> > -}
> > +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
> > +              char *const argv[]);
> >
> >  U_BOOT_CMD(
> > -     wget,   3,      1,      do_wget,
> > +     wget,   3,      1, do_lwip_wget,
>
> I thought we agreed on keeping both the native u-boot stack and lwip until
> we can proove the later is useful.  Do I remember this wrong? Same goes for
> all the other commands
>
> >       "boot image via network using HTTP protocol",
> >       "[loadAddress] [[hostIPaddr:]path and image name]"
> >  );
> > @@ -376,28 +364,10 @@ static int netboot_common(enum proto_t proto,
> struct cmd_tbl *cmdtp, int argc,
> >  }
> >
> >  #if defined(CONFIG_CMD_PING)
> > -static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> > -                char *const argv[])
> > -{
> > -     if (argc < 2)
> > -             return CMD_RET_USAGE;
> > -
> > -     net_ping_ip = string_to_ip(argv[1]);
> > -     if (net_ping_ip.s_addr == 0)
> > -             return CMD_RET_USAGE;
> > -
> > -     if (net_loop(PING) < 0) {
> > -             printf("ping failed; host %s is not alive\n", argv[1]);
> > -             return CMD_RET_FAILURE;
> > -     }
> > -
> > -     printf("host %s is alive\n", argv[1]);
> > -
> > -     return CMD_RET_SUCCESS;
> > -}
> > -
> > +extern int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
> > +                     char *const argv[]);
>
> Why extern? Cant we define it properly as part of our header file?
>
> >  U_BOOT_CMD(
> > -     ping,   2,      1,      do_ping,
> > +     ping,   2,      1, do_lwip_ping,
> >       "send ICMP ECHO_REQUEST to network host",
> >       "pingAddress"
> >  );
> > diff --git a/cmd/pxe.c b/cmd/pxe.c
> > index db8e4697f2..bd4d6f5f2b 100644
> > --- a/cmd/pxe.c
> > +++ b/cmd/pxe.c
> > @@ -33,7 +33,7 @@ static int do_get_tftp(struct pxe_context *ctx, const
> char *file_path,
> >       tftp_argv[1] = file_addr;
> >       tftp_argv[2] = (void *)file_path;
> >
> > -     if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
> > +     if (do_lwip_tftp(ctx->cmdtp, 0, 3, tftp_argv))
> >               return -ENOENT;
> >       ret = pxe_get_file_size(sizep);
> >       if (ret)
> > diff --git a/include/net.h b/include/net.h
> > index 1a99009959..6b573f3319 100644
> > --- a/include/net.h
> > +++ b/include/net.h
> > @@ -54,8 +54,10 @@ struct in_addr {
> >       __be32 s_addr;
> >  };
> >
> > +int do_lwip_dhcp(void);
> > +
> >  /**
> > - * do_tftpb - Run the tftpboot command
> > + * do_lwip_tftp - Run the tftpboot command
> >   *
> >   * @cmdtp: Command information for tftpboot
> >   * @flag: Command flags (CMD_FLAG_...)
> > @@ -63,7 +65,7 @@ struct in_addr {
> >   * @argv: List of arguments
> >   * Return: result (see enum command_ret_t)
> >   */
> > -int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const
> argv[]);
> > +int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, char *const
> argv[]);
> >
> >  /**
> >   * An incoming packet handler.
> > @@ -561,7 +563,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..3688ac3305
> > --- /dev/null
> > +++ b/lib/lwip/Kconfig
> > @@ -0,0 +1,63 @@
> > +menu "LWIP"
> > +config LWIP_LIB
> > +     bool "Support LWIP library"
> > +     help
> > +       Selecting this option will enable the 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
>
> You need some useful help entry on all of those.
>
> > +        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"
> > +        help
> > +        Increases size on 1k.
> > +
> > +config LWIP_LIB_SOCKET
> > +        bool "socket API"
> > +
> > +config LWIP_LIB_NETCONN
> > +        bool "netconn API"
> > +
> > +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
> > +
> > +endmenu
> > diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile
> > new file mode 100644
> > index 0000000000..e1a8a2a7b7
> > --- /dev/null
> > +++ b/lib/lwip/Makefile
> > @@ -0,0 +1,101 @@
> > +# SPDX-License-Identifier: GPL-2.0+
> > +#
> > +# (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
> > +
> > +LWIPDIR=lwip-external/src
> > +
> > +ccflags-y += -I$(srctree)/lib/lwip/port/include
> > +ccflags-y += -I$(srctree)/lib/lwip/lwip-external/src/include
> -I$(srctree)/lib/lwip
> > +
> > +obj-$(CONFIG_NET) += $(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_NET) += $(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_NET) += $(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_NET) += $(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_NET) += $(LWIPDIR)/netif/ethernet.o
> > +
> > +obj-$(CONFIG_NET) += port/if.o
> > +obj-$(CONFIG_NET) += port/sys-arch.o
> > +
> > +obj-$(CONFIG_NET) += cmd-lwip.o
> > +
> > +
> > +ccflags-y += -I$(srctree)/lib/lwip/apps/ping
> > +.PHONY: $(obj)/apps/ping/ping.c
> > +$(obj)/apps/ping/ping.o: $(obj)/apps/ping/ping.c
> > +$(obj)/apps/ping/ping.c:
> > +     cp $(srctree)/lib/lwip/lwip-external/contrib/apps/ping/ping.c
> $(obj)/apps/ping/ping.c
> > +
> > +obj-$(CONFIG_CMD_PING) += apps/ping/ping.o
> > +obj-$(CONFIG_CMD_PING) += 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 $(srctree)/lib/lwip/lwip-external/src/apps/http/http_client.c
> $(obj)/apps/http/http_client.c
> > +     cp
> $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/http_client.h
> $(obj)/apps/http/http_client.h
> > +
> > +obj-$(CONFIG_CMD_WGET) += apps/http/http_client.o
> > +obj-$(CONFIG_CMD_WGET) += apps/http/lwip-wget.o
> > +
> > +ccflags-y += -I$(CURDIR)/lib/lwip/apps/tftp
> > +$(obj)/apps/tftp/tftp.o: $(obj)/apps/tftp/tftp.c
> > +.PHONY: $(obj)/apps/tftp/tftp.c
> > +$(obj)/apps/tftp/tftp.c:
> > +     cp $(srctree)/lib/lwip/lwip-external/src/apps/tftp/tftp.c
> $(obj)/apps/tftp/tftp.c
> > +     cp
> $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/tftp_client.h
> $(obj)/apps/tftp/tftp_client.h
> > +     cp
> $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/tftp_common.h
> $(obj)/apps/tftp/tftp_common.h
> > +     cp
> $(srctree)/lib/lwip/lwip-external/contrib/examples/tftp/tftp_example.h
> $(obj)/apps/tftp/tftp_example.h
> > +
> > +obj-$(CONFIG_CMD_TFTPBOOT) += apps/tftp/tftp.o
> > +obj-$(CONFIG_CMD_TFTPBOOT) += apps/tftp/lwip-tftp.o
> > +
> > +obj-$(CONFIG_CMD_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;
>
> Again why extern?  I dont think it's sane to carry around the uboot_netif
> variable everytime we need to change a member.  Instead we should functions
> doing that
>

yes,  netif_get_by_index(1) can be used to get a default pointer to netif.
Changed that.



>
> > +
> > +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;
> > +}
>
> The return value is always 0, why are we at least checking the result of
> env_set()?
>
>
Yes, thanks I did not check the error path here. Actually this chunk will
be changed when lwip will have a callback for changing states. That is in
progress. But for now I just registered a timeout to check if the state was
changed.


> > +
> > +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..0308b0b04a
> > --- /dev/null
> > +++ b/lib/lwip/apps/http/lwip-wget.c
> > @@ -0,0 +1,74 @@
> > +// 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);
> > +             env_set_ulong("filesize", 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));
>
> sizeof(settings) is preferred
>
> ok


> > +     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;
> > +     }
> > +
> > +     env_set_hex("fileaddr", addr);
> > +     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"
>
> Please dont do this.  Can't we just use -I or something and have this is a
> normal include path?
>
>

simple <ulwip.h> can be used. fixed.


> > +
> > +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..511d82e600
> > --- /dev/null
> > +++ b/lib/lwip/apps/tftp/lwip-tftp.c
> > @@ -0,0 +1,124 @@
> > +// 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);
> > +
> > +     env_set_ulong("filesize", 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);
> > +
> > +     env_set_hex("fileaddr", addr);
> > +     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..625c8c53b8
> > --- /dev/null
> > +++ b/lib/lwip/cmd-lwip.c
> > @@ -0,0 +1,269 @@
> > +// 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_PING)
> > +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();
> > +}
> > +#endif /* CONFIG_CMD_PING */
> > +
> > +#if defined(CONFIG_CMD_WGET)
> > +extern int lwip_wget(ulong addr, char *url);
> > +
> > +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();
> > +}
> > +#endif
> > +
> > +#if defined(CONFIG_CMD_TFTPBOOT)
> > +extern int lwip_tftp(ulong addr, char *filename);
> > +
> > +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 /* CONFIG_CMD_TFTPBOOT */
> > +
> > +#if defined(CONFIG_CMD_DHCP)
> > +extern int ulwip_dhcp(void);
> > +
> > +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_TFTPBOOT)) {
> > +             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 /* CONFIG_CMD_DHCP */
> > +
> > +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_WGET)
> > +     U_BOOT_CMD_MKENT(wget, 2, 0, do_lwip_wget, "", ""),
> > +#endif
> > +#if defined(CONFIG_CMD_TFTPBOOT)
> > +     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_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..37c02a451f
> > --- /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_DHCP)
> > +struct netif uboot_netif;
> > +#else
> > +static struct netif uboot_netif;
> > +#endif
>
> I am not sure I understand why this exists.  If you want to change some
> some members of the struct from the dhcp code, why dont you create a
> function that resides here?
>
>
ok. changed to use a helper function to get netif pointer.


> > +
> > +#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/Kconfig b/net/Kconfig
> > index a1ec3f8542..2c5d8b8aca 100644
> > --- a/net/Kconfig
> > +++ b/net/Kconfig
> > @@ -5,6 +5,7 @@
> >  menuconfig NET
> >       bool "Networking support"
> >       default y
> > +     select LWIP_LIB
> >
> >  if NET
> >
> > diff --git a/net/net.c b/net/net.c
> > index 57da9bda85..3d9a2e798a 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,6 +624,18 @@ 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.
> >                */
> > @@ -1177,6 +1194,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
> >
>
> Thanks
> /Ilias
>

Agree that the patch is really huge. And it's even complex to navigate over
the comments. I will split it into smaller changs.
What I also worry about is IPv6 support which theoretically exists and is
supported by lwip, but I did not test it. Because of
original commands have IPv5 it will be good to not break working code.

BR,
Maxim.
diff mbox series

Patch

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/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
index e6992168c0..30331a9806 100644
--- a/boot/bootmeth_pxe.c
+++ b/boot/bootmeth_pxe.c
@@ -118,7 +118,7 @@  static int distro_pxe_read_file(struct udevice *dev, struct bootflow *bflow,
 	tftp_argv[1] = file_addr;
 	tftp_argv[2] = (void *)file_path;
 
-	if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
+	if (do_lwip_tftp(ctx->cmdtp, 0, 3, tftp_argv))
 		return -ENOENT;
 	ret = pxe_get_file_size(&size);
 	if (ret)
diff --git a/cmd/net.c b/cmd/net.c
index 0e9f200ca9..6d704fba86 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -36,19 +36,9 @@  U_BOOT_CMD(
 #endif
 
 #ifdef CONFIG_CMD_TFTPBOOT
-int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
-{
-	int ret;
-
-	bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
-	ret = netboot_common(TFTPGET, cmdtp, argc, argv);
-	bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
-	return ret;
-}
-
 #if IS_ENABLED(CONFIG_IPV6)
 U_BOOT_CMD(
-	tftpboot,	4,	1,	do_tftpb,
+	tftpboot,	4,	1, do_lwip_tftp,
 	"boot image via network using TFTP protocol\n"
 	"To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed "
 	"with [] brackets",
@@ -56,7 +46,7 @@  U_BOOT_CMD(
 );
 #else
 U_BOOT_CMD(
-	tftpboot,	3,	1,	do_tftpb,
+	tftpboot,	3,	1,  do_lwip_tftp,
 	"load file via network using TFTP protocol",
 	"[loadAddress] [[hostIPaddr:]bootfilename]"
 );
@@ -112,7 +102,7 @@  U_BOOT_CMD(
 static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
 		   char *const argv[])
 {
-	return netboot_common(DHCP, cmdtp, argc, argv);
+	return do_lwip_dhcp();
 }
 
 U_BOOT_CMD(
@@ -137,13 +127,11 @@  U_BOOT_CMD(
 #endif
 
 #if defined(CONFIG_CMD_WGET)
-static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
-{
-	return netboot_common(WGET, cmdtp, argc, argv);
-}
+int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[]);
 
 U_BOOT_CMD(
-	wget,   3,      1,      do_wget,
+	wget,   3,      1, do_lwip_wget,
 	"boot image via network using HTTP protocol",
 	"[loadAddress] [[hostIPaddr:]path and image name]"
 );
@@ -376,28 +364,10 @@  static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
 }
 
 #if defined(CONFIG_CMD_PING)
-static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
-		   char *const argv[])
-{
-	if (argc < 2)
-		return CMD_RET_USAGE;
-
-	net_ping_ip = string_to_ip(argv[1]);
-	if (net_ping_ip.s_addr == 0)
-		return CMD_RET_USAGE;
-
-	if (net_loop(PING) < 0) {
-		printf("ping failed; host %s is not alive\n", argv[1]);
-		return CMD_RET_FAILURE;
-	}
-
-	printf("host %s is alive\n", argv[1]);
-
-	return CMD_RET_SUCCESS;
-}
-
+extern int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[]);
 U_BOOT_CMD(
-	ping,	2,	1,	do_ping,
+	ping,	2,	1, do_lwip_ping,
 	"send ICMP ECHO_REQUEST to network host",
 	"pingAddress"
 );
diff --git a/cmd/pxe.c b/cmd/pxe.c
index db8e4697f2..bd4d6f5f2b 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -33,7 +33,7 @@  static int do_get_tftp(struct pxe_context *ctx, const char *file_path,
 	tftp_argv[1] = file_addr;
 	tftp_argv[2] = (void *)file_path;
 
-	if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
+	if (do_lwip_tftp(ctx->cmdtp, 0, 3, tftp_argv))
 		return -ENOENT;
 	ret = pxe_get_file_size(sizep);
 	if (ret)
diff --git a/include/net.h b/include/net.h
index 1a99009959..6b573f3319 100644
--- a/include/net.h
+++ b/include/net.h
@@ -54,8 +54,10 @@  struct in_addr {
 	__be32 s_addr;
 };
 
+int do_lwip_dhcp(void);
+
 /**
- * do_tftpb - Run the tftpboot command
+ * do_lwip_tftp - Run the tftpboot command
  *
  * @cmdtp: Command information for tftpboot
  * @flag: Command flags (CMD_FLAG_...)
@@ -63,7 +65,7 @@  struct in_addr {
  * @argv: List of arguments
  * Return: result (see enum command_ret_t)
  */
-int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
+int do_lwip_tftp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
 
 /**
  * An incoming packet handler.
@@ -561,7 +563,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..3688ac3305
--- /dev/null
+++ b/lib/lwip/Kconfig
@@ -0,0 +1,63 @@ 
+menu "LWIP"
+config LWIP_LIB
+	bool "Support LWIP library"
+	help
+	  Selecting this option will enable the 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"
+        help
+	   Increases size on 1k.
+
+config LWIP_LIB_SOCKET
+        bool "socket API"
+
+config LWIP_LIB_NETCONN
+        bool "netconn API"
+
+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
+
+endmenu
diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile
new file mode 100644
index 0000000000..e1a8a2a7b7
--- /dev/null
+++ b/lib/lwip/Makefile
@@ -0,0 +1,101 @@ 
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2023 Linaro Ltd. <maxim.uvarov@linaro.org>
+
+LWIPDIR=lwip-external/src
+
+ccflags-y += -I$(srctree)/lib/lwip/port/include
+ccflags-y += -I$(srctree)/lib/lwip/lwip-external/src/include -I$(srctree)/lib/lwip
+
+obj-$(CONFIG_NET) += $(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_NET) += $(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_NET) += $(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_NET) += $(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_NET) += $(LWIPDIR)/netif/ethernet.o
+
+obj-$(CONFIG_NET) += port/if.o
+obj-$(CONFIG_NET) += port/sys-arch.o
+
+obj-$(CONFIG_NET) += cmd-lwip.o
+
+
+ccflags-y += -I$(srctree)/lib/lwip/apps/ping
+.PHONY: $(obj)/apps/ping/ping.c
+$(obj)/apps/ping/ping.o: $(obj)/apps/ping/ping.c
+$(obj)/apps/ping/ping.c:
+	cp $(srctree)/lib/lwip/lwip-external/contrib/apps/ping/ping.c $(obj)/apps/ping/ping.c
+
+obj-$(CONFIG_CMD_PING) += apps/ping/ping.o
+obj-$(CONFIG_CMD_PING) += 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 $(srctree)/lib/lwip/lwip-external/src/apps/http/http_client.c $(obj)/apps/http/http_client.c
+	cp $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/http_client.h $(obj)/apps/http/http_client.h
+
+obj-$(CONFIG_CMD_WGET) += apps/http/http_client.o
+obj-$(CONFIG_CMD_WGET) += apps/http/lwip-wget.o
+
+ccflags-y += -I$(CURDIR)/lib/lwip/apps/tftp
+$(obj)/apps/tftp/tftp.o: $(obj)/apps/tftp/tftp.c
+.PHONY: $(obj)/apps/tftp/tftp.c
+$(obj)/apps/tftp/tftp.c:
+	cp $(srctree)/lib/lwip/lwip-external/src/apps/tftp/tftp.c $(obj)/apps/tftp/tftp.c
+	cp $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/tftp_client.h $(obj)/apps/tftp/tftp_client.h
+	cp $(srctree)/lib/lwip/lwip-external/src/include/lwip/apps/tftp_common.h $(obj)/apps/tftp/tftp_common.h
+	cp $(srctree)/lib/lwip/lwip-external/contrib/examples/tftp/tftp_example.h $(obj)/apps/tftp/tftp_example.h
+
+obj-$(CONFIG_CMD_TFTPBOOT) += apps/tftp/tftp.o
+obj-$(CONFIG_CMD_TFTPBOOT) += apps/tftp/lwip-tftp.o
+
+obj-$(CONFIG_CMD_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..0308b0b04a
--- /dev/null
+++ b/lib/lwip/apps/http/lwip-wget.c
@@ -0,0 +1,74 @@ 
+// 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);
+		env_set_ulong("filesize", 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;
+	}
+
+	env_set_hex("fileaddr", addr);
+	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..511d82e600
--- /dev/null
+++ b/lib/lwip/apps/tftp/lwip-tftp.c
@@ -0,0 +1,124 @@ 
+// 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);
+
+	env_set_ulong("filesize", 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);
+
+	env_set_hex("fileaddr", addr);
+	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..625c8c53b8
--- /dev/null
+++ b/lib/lwip/cmd-lwip.c
@@ -0,0 +1,269 @@ 
+// 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_PING)
+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();
+}
+#endif /* CONFIG_CMD_PING */
+
+#if defined(CONFIG_CMD_WGET)
+extern int lwip_wget(ulong addr, char *url);
+
+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();
+}
+#endif
+
+#if defined(CONFIG_CMD_TFTPBOOT)
+extern int lwip_tftp(ulong addr, char *filename);
+
+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 /* CONFIG_CMD_TFTPBOOT */
+
+#if defined(CONFIG_CMD_DHCP)
+extern int ulwip_dhcp(void);
+
+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_TFTPBOOT)) {
+		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 /* CONFIG_CMD_DHCP */
+
+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_WGET)
+	U_BOOT_CMD_MKENT(wget, 2, 0, do_lwip_wget, "", ""),
+#endif
+#if defined(CONFIG_CMD_TFTPBOOT)
+	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_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..37c02a451f
--- /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_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/Kconfig b/net/Kconfig
index a1ec3f8542..2c5d8b8aca 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -5,6 +5,7 @@ 
 menuconfig NET
 	bool "Networking support"
 	default y
+	select LWIP_LIB
 
 if NET
 
diff --git a/net/net.c b/net/net.c
index 57da9bda85..3d9a2e798a 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,6 +624,18 @@  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.
 		 */
@@ -1177,6 +1194,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);