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

changelog: v4: - tested with tests/py/ did some minor fixes (out of tree build, variables set after downloads). - accounted review comments for documentation. - implemented dns command - corrected wget command to not use serverip variable and use just url string. v3: - use lwip commands for ping,tftp,wget,dhcp if this patch applied. Drop CONFIG_LIB_LWIP_REPLACE_<COMMAND> option. - docs: use rst variant and drop references to RFC.
build: git submodule init git submodule update make
I tested with qemu and ubuntu host for the server manually and with ./test/py/test -bd qemu_arm64 --build -k net.
Maxim Uvarov (5): net/lwip: add lwip-external submodule net/lwip: add lwip library for the network stack net/lwip: add doc/develop/net_lwip.rst net/lwip: add dns command net/lwip: apps/http: add dns support
.gitignore | 9 + .gitmodules | 3 + boot/bootmeth_pxe.c | 2 +- cmd/net.c | 89 +------- cmd/pxe.c | 2 +- doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 59 +++++ include/net.h | 8 +- lib/Kconfig | 2 + lib/Makefile | 2 + lib/lwip/Kconfig | 63 ++++++ lib/lwip/Makefile | 103 +++++++++ lib/lwip/apps/dhcp/lwip-dhcp.c | 52 +++++ lib/lwip/apps/dns/lwip-dns.c | 46 ++++ lib/lwip/apps/dns/lwip-dns.h | 3 + lib/lwip/apps/http/lwip-wget.c | 121 ++++++++++ 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 | 308 ++++++++++++++++++++++++++ lib/lwip/lwip-external | 1 + 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 ++ 31 files changed, 1634 insertions(+), 82 deletions(-) create mode 100644 .gitmodules create mode 100644 doc/develop/net_lwip.rst 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/dns/lwip-dns.c create mode 100644 lib/lwip/apps/dns/lwip-dns.h 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 160000 lib/lwip/lwip-external 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

This commit adds the lwip library as a git submodule. I think there has to be advantages to compile lwip inside U-boot, i.e. use the same compiler and flags as the main code. One of them is LTO and the other is to enable additional debug options for network protocol during development. Also we can copy lwip library code inside U-boot, but for now I don't want to send all lwip code to the mailing list. So it's git submodule.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- .gitmodules | 3 +++ lib/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 lib/lwip/lwip-external
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..afc709af10 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/lwip/lwip-external"] + path = lib/lwip/lwip-external + url = https://git.savannah.nongnu.org/git/lwip.git diff --git a/lib/lwip/lwip-external b/lib/lwip/lwip-external new file mode 160000 index 0000000000..3fe8d2fc43 --- /dev/null +++ b/lib/lwip/lwip-external @@ -0,0 +1 @@ +Subproject commit 3fe8d2fc43a9b69f7ed28c63d44a7744f9c0def9

Tom, Simon are you ok with submodules on this one?
thanks /Ilias On Fri, Jul 14, 2023 at 08:19:56PM +0600, Maxim Uvarov wrote:
This commit adds the lwip library as a git submodule. I think there has to be advantages to compile lwip inside U-boot, i.e. use the same compiler and flags as the main code. One of them is LTO and the other is to enable additional debug options for network protocol during development. Also we can copy lwip library code inside U-boot, but for now I don't want to send all lwip code to the mailing list. So it's git submodule.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
.gitmodules | 3 +++ lib/lwip/lwip-external | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 lib/lwip/lwip-external
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..afc709af10 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/lwip/lwip-external"]
- path = lib/lwip/lwip-external
- url = https://git.savannah.nongnu.org/git/lwip.git
diff --git a/lib/lwip/lwip-external b/lib/lwip/lwip-external new file mode 160000 index 0000000000..3fe8d2fc43 --- /dev/null +++ b/lib/lwip/lwip-external @@ -0,0 +1 @@
+Subproject commit 3fe8d2fc43a9b69f7ed28c63d44a7744f9c0def9
2.30.2

On Thu, Jul 27, 2023 at 03:34:48PM +0300, Ilias Apalodimas wrote:
Tom, Simon are you ok with submodules on this one?
Still punting on that question and waiting for commentary from distribution people.

Hi Tom,
On Fri, 28 Jul 2023 at 12:09, Tom Rini trini@konsulko.com wrote:
On Thu, Jul 27, 2023 at 03:34:48PM +0300, Ilias Apalodimas wrote:
Tom, Simon are you ok with submodules on this one?
Still punting on that question and waiting for commentary from distribution people.
I really quite badly don't want the pain of submodules. They are used in coreboot and I sometimes end up just deleting everything and starting again.
Regards, Simon

On Fri, Jul 28, 2023 at 7:09 PM Tom Rini trini@konsulko.com wrote:
On Thu, Jul 27, 2023 at 03:34:48PM +0300, Ilias Apalodimas wrote:
Tom, Simon are you ok with submodules on this one?
Still punting on that question and waiting for commentary from distribution people.
I would prefer not to have to deal with submodules unless the required bits were pulled as part of the release tarball process where it wouldn't then matter to distributions.
Peter

On Mon, 31 Jul 2023 at 04:06, Peter Robinson pbrobinson@gmail.com wrote:
On Fri, Jul 28, 2023 at 7:09 PM Tom Rini trini@konsulko.com wrote:
On Thu, Jul 27, 2023 at 03:34:48PM +0300, Ilias Apalodimas wrote:
Tom, Simon are you ok with submodules on this one?
Still punting on that question and waiting for commentary from distribution people.
I would prefer not to have to deal with submodules unless the required bits were pulled as part of the release tarball process where it wouldn't then matter to distributions.
Peter
Ilias pointed to an interesting alternative which edk2 uses its git subtrees. Docs: https://www.atlassian.com/git/tutorials/git-subtree https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt
Examples: git subtree add --prefix lib/lwip/lwip-external https://git.savannah.nongnu.org/git/lwip.git master --squash $ git log commit 83488286d287e53fad1efbfe1d4f5dbf69202f4a (HEAD -> master) Merge: 27b050e91d 120e0665c3 Author: Maxim Uvarov maxim.uvarov@linaro.org Date: Wed Aug 2 07:53:17 2023 +0000
Merge commit '120e0665c37ec69d46c10fc341e253ae2e69afca' as 'lib/lwip/lwip-external'
commit 120e0665c37ec69d46c10fc341e253ae2e69afca Author: Maxim Uvarov maxim.uvarov@linaro.org Date: Wed Aug 2 07:53:17 2023 +0000
Squashed 'lib/lwip/lwip-external/' content from commit 84fde1ebbf
git-subtree-dir: lib/lwip/lwip-external git-subtree-split: 84fde1ebbfe35b3125fc2d89b8a456cbacf148e9
So it actually plases code of lwip.git into a subdirectory as a git commit. When you do git clone then all sources will be fetched. No need for any additional commands after that. I vote for subtree instead of plain code copy.
BR, Maxim.

On Wed, Aug 02, 2023 at 02:03:04PM +0600, Maxim Uvarov wrote:
On Mon, 31 Jul 2023 at 04:06, Peter Robinson pbrobinson@gmail.com wrote:
On Fri, Jul 28, 2023 at 7:09 PM Tom Rini trini@konsulko.com wrote:
On Thu, Jul 27, 2023 at 03:34:48PM +0300, Ilias Apalodimas wrote:
Tom, Simon are you ok with submodules on this one?
Still punting on that question and waiting for commentary from distribution people.
I would prefer not to have to deal with submodules unless the required bits were pulled as part of the release tarball process where it wouldn't then matter to distributions.
Peter
Ilias pointed to an interesting alternative which edk2 uses its git subtrees. Docs: https://www.atlassian.com/git/tutorials/git-subtree https://github.com/git/git/blob/master/contrib/subtree/git-subtree.txt
Examples: git subtree add --prefix lib/lwip/lwip-external https://git.savannah.nongnu.org/git/lwip.git master --squash $ git log commit 83488286d287e53fad1efbfe1d4f5dbf69202f4a (HEAD -> master) Merge: 27b050e91d 120e0665c3 Author: Maxim Uvarov maxim.uvarov@linaro.org Date: Wed Aug 2 07:53:17 2023 +0000
Merge commit '120e0665c37ec69d46c10fc341e253ae2e69afca' as
'lib/lwip/lwip-external'
commit 120e0665c37ec69d46c10fc341e253ae2e69afca Author: Maxim Uvarov maxim.uvarov@linaro.org Date: Wed Aug 2 07:53:17 2023 +0000
Squashed 'lib/lwip/lwip-external/' content from commit 84fde1ebbf git-subtree-dir: lib/lwip/lwip-external git-subtree-split: 84fde1ebbfe35b3125fc2d89b8a456cbacf148e9
So it actually plases code of lwip.git into a subdirectory as a git commit. When you do git clone then all sources will be fetched. No need for any additional commands after that. I vote for subtree instead of plain code copy.
Since I think we could use this to start off on one stable tag and then merge to the next as they come out (which is likely the cadence we want), this does seem like the reasonable way forward. Too late for v5, but for v6 can you please make sure the doc contains (and an easy way to test this would be to start with say STABLE_2_1_0_RELEASE and move it up to STABLE_2_1_3_RELEASE) an example / instructions on how to use subtree to perform the updates.

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, "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/%5Cn" + "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);

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/%5Cn"
- "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

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

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.

Just add inital doc.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 doc/develop/net_lwip.rst
diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 97c526e997..a092c33df0 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -43,6 +43,7 @@ Implementation smbios spl uefi/index + net_lwip vbe version
diff --git a/doc/develop/net_lwip.rst b/doc/develop/net_lwip.rst new file mode 100644 index 0000000000..567234fff2 --- /dev/null +++ b/doc/develop/net_lwip.rst @@ -0,0 +1,59 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +LWIP IP stack intergation for U-Boot +==================================== + +Intro +----- + +LWIP is a library for implementation network protocols, which is commonly used +on embedded devices. + +https://savannah.nongnu.org/projects/lwip/ + +LwIP license: +LwIP is licensed under a BSD-style license: http://lwip.wikia.com/wiki/License. + +Main features include: + +* Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE + +* DHCP client, DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), SNMP agent (v1, v2c, v3, private MIB support & MIB compiler) + +* APIs: specialized APIs for enhanced performance, optional Berkeley-alike socket API + +* Extended features: IP forwarding over multiple network interfaces, TCP congestion control, RTT estimation and fast recovery/fast retransmit + +* Addon applications: HTTP(S) server, SNTP client, SMTP(S) client, ping, NetBIOS nameserver, mDNS responder, MQTT client, TFTP server + +U-Boot implementation details +----------------------------- + +1. In general we can build lwIP as .a library and link it against u-boot or compile it in +the U-Boot tree in the same way as other U-Boot files. There are few reasons why I selected +the second variant: LwIP is very customizable with defines for features, memory size, types of +allocation, some internal types and platform specific code. And it was more easy to enable/disable +debug which is also done with defines, and is needed periodically. + +2. lwIP has 2 APIs - raw mode and sequential (as lwIP names it, or socket API as we name it in Linux). +For now only raw API is supported. + +Raw IP means that the call back function for RX path is registered and will be called when packet +data passes the IP stack and is ready for the application. + +Example is unmodified working ping example from lwip sources which registeres the callback: + +.. code-block:: c + + ping_pcb = raw_new(IP_PROTO_ICMP); + raw_recv(ping_pcb, ping_recv, NULL); <- ping_recv is app callback. + raw_bind(ping_pcb, IP_ADDR_ANY) + +Socket API also gives nice advantages due it will be easy to port linux socket applications to u-boot. +I.e. LwIP sockets compatible with the linux ones. But that will require RX thread running in the background. +So that means we need some kind of scheduler, locking and threading support or find some other solution. + +3. Input and output + +RX packet path is injected to U-Boot eth_rx() polling loop and TX patch is in eth_send() accordingly. +So we do not touch any drivers code and just eat packets when they are ready.

Hi Maxim,
On Fri, Jul 14, 2023 at 08:19:58PM +0600, Maxim Uvarov wrote:
Just add inital doc.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 doc/develop/net_lwip.rst
diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 97c526e997..a092c33df0 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -43,6 +43,7 @@ Implementation smbios spl uefi/index
- net_lwip vbe version
diff --git a/doc/develop/net_lwip.rst b/doc/develop/net_lwip.rst new file mode 100644 index 0000000000..567234fff2 --- /dev/null +++ b/doc/develop/net_lwip.rst @@ -0,0 +1,59 @@ +.. SPDX-License-Identifier: GPL-2.0+
+LWIP IP stack intergation for U-Boot +====================================
+Intro +-----
+LWIP is a library for implementation network protocols, which is commonly used
s/for implementation/implementing/
+on embedded devices.
+https://savannah.nongnu.org/projects/lwip/
+LwIP license: +LwIP is licensed under a BSD-style license: http://lwip.wikia.com/wiki/License.
+Main features include:
+* Protocols: IP, IPv6, ICMP, ND, MLD, UDP, TCP, IGMP, ARP, PPPoS, PPPoE
+* DHCP client, DNS client (incl. mDNS hostname resolver), AutoIP/APIPA (Zeroconf), SNMP agent (v1, v2c, v3, private MIB support & MIB compiler)
+* APIs: specialized APIs for enhanced performance, optional Berkeley-alike socket API
+* Extended features: IP forwarding over multiple network interfaces, TCP congestion control, RTT estimation and fast recovery/fast retransmit
+* Addon applications: HTTP(S) server, SNTP client, SMTP(S) client, ping, NetBIOS nameserver, mDNS responder, MQTT client, TFTP server
+U-Boot implementation details +-----------------------------
+1. In general we can build lwIP as .a library and link it against u-boot or compile it in +the U-Boot tree in the same way as other U-Boot files. There are few reasons why I selected +the second variant: LwIP is very customizable with defines for features, memory size, types of +allocation, some internal types and platform specific code. And it was more easy to enable/disable
s/And it was more easy/it turned out easier to/
+debug which is also done with defines, and is needed periodically.
+2. lwIP has 2 APIs - raw mode and sequential (as lwIP names it, or socket API as we name it in Linux). +For now only raw API is supported.
+Raw IP means that the call back function for RX path is registered and will be called when packet
s/Raw IP IP means/In raw IP mode a callback function etc
+data passes the IP stack and is ready for the application.
is passed to the ip stack?
+Example is unmodified working ping example from lwip sources which registeres the callback:
+.. code-block:: c
ping_pcb = raw_new(IP_PROTO_ICMP);
raw_recv(ping_pcb, ping_recv, NULL); <- ping_recv is app callback.
raw_bind(ping_pcb, IP_ADDR_ANY)
+Socket API also gives nice advantages due it will be easy to port linux socket applications to u-boot. +I.e. LwIP sockets compatible with the linux ones. But that will require RX thread running in the background. +So that means we need some kind of scheduler, locking and threading support or find some other solution.
I think you can drop this entirely and we can add it if we ever want to support sockets
+3. Input and output
+RX packet path is injected to U-Boot eth_rx() polling loop and TX patch is in eth_send() accordingly.
+So we do not touch any drivers code and just eat packets when they are ready.
2.30.2
Thanks /Ilias

dns lwip version of the command. This commmit might be good example how to enable new network command.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- cmd/net.c | 41 +++----------------------------- lib/lwip/Kconfig | 2 +- lib/lwip/Makefile | 2 ++ lib/lwip/apps/dns/lwip-dns.c | 46 ++++++++++++++++++++++++++++++++++++ lib/lwip/apps/dns/lwip-dns.h | 3 +++ lib/lwip/cmd-lwip.c | 39 ++++++++++++++++++++++++++++++ lib/lwip/lwipopts.h | 2 +- 7 files changed, 95 insertions(+), 40 deletions(-) create mode 100644 lib/lwip/apps/dns/lwip-dns.c create mode 100644 lib/lwip/apps/dns/lwip-dns.h
diff --git a/cmd/net.c b/cmd/net.c index 6d704fba86..2a68477aae 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -491,45 +491,10 @@ U_BOOT_CMD( #endif
#if defined(CONFIG_CMD_DNS) -int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{ - if (argc == 1) - return CMD_RET_USAGE; - - /* - * We should check for a valid hostname: - * - Each label must be between 1 and 63 characters long - * - the entire hostname has a maximum of 255 characters - * - only the ASCII letters 'a' through 'z' (case-insensitive), - * the digits '0' through '9', and the hyphen - * - cannot begin or end with a hyphen - * - no other symbols, punctuation characters, or blank spaces are - * permitted - * but hey - this is a minimalist implmentation, so only check length - * and let the name server deal with things. - */ - if (strlen(argv[1]) >= 255) { - printf("dns error: hostname too long\n"); - return CMD_RET_FAILURE; - } - - net_dns_resolve = argv[1]; - - if (argc == 3) - net_dns_env_var = argv[2]; - else - net_dns_env_var = NULL; - - if (net_loop(DNS) < 0) { - printf("dns lookup of %s failed, check setup\n", argv[1]); - return CMD_RET_FAILURE; - } - - return CMD_RET_SUCCESS; -} - +extern int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); U_BOOT_CMD( - dns, 3, 1, do_dns, + dns, 3, 1, do_lwip_dns, "lookup the IP of a hostname", "hostname [envvar]" ); diff --git a/lib/lwip/Kconfig b/lib/lwip/Kconfig index 3688ac3305..5e9062a6da 100644 --- a/lib/lwip/Kconfig +++ b/lib/lwip/Kconfig @@ -26,7 +26,7 @@ config LWIP_LIB_UDP
config LWIP_LIB_DNS bool "dns" - default n + default y
config LWIP_LIB_DHCP bool "dhcp" diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile index e1a8a2a7b7..d6e511dff1 100644 --- a/lib/lwip/Makefile +++ b/lib/lwip/Makefile @@ -99,3 +99,5 @@ 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 + +obj-$(CONFIG_CMD_DNS) += apps/dns/lwip-dns.o diff --git a/lib/lwip/apps/dns/lwip-dns.c b/lib/lwip/apps/dns/lwip-dns.c new file mode 100644 index 0000000000..04fd53bfcb --- /dev/null +++ b/lib/lwip/apps/dns/lwip-dns.c @@ -0,0 +1,46 @@ +// 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/dns.h> +#include <lwip/ip_addr.h> + +#include "../../../lwip/ulwip.h" + +static void dns_found_cb(const char *name, const ip_addr_t *ipaddr, void *callback_arg) +{ + char *varname = (char *)callback_arg; + + if (varname) + env_set(varname, ip4addr_ntoa(ipaddr)); + + printf("resolved %s to %s\n", name, ip4addr_ntoa(ipaddr)); + ulwip_exit(0); +} + +int ulwip_dns(char *name, char *varname) +{ + int err; + ip_addr_t ipaddr; /* not used */ + ip_addr_t dns1; + ip_addr_t dns2; + + ipaddr_aton(env_get("dnsip"), &dns1); + ipaddr_aton(env_get("dnsip2"), &dns2); + + dns_init(); + dns_setserver(0, &dns1); + dns_setserver(1, &dns2); + + err = dns_gethostbyname(name, &ipaddr, dns_found_cb, varname); + if (err == ERR_OK) + dns_found_cb(name, &ipaddr, varname); + + return err; +} diff --git a/lib/lwip/apps/dns/lwip-dns.h b/lib/lwip/apps/dns/lwip-dns.h new file mode 100644 index 0000000000..c59f99e099 --- /dev/null +++ b/lib/lwip/apps/dns/lwip-dns.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +int ulwip_dns(char *name, char *varname); diff --git a/lib/lwip/cmd-lwip.c b/lib/lwip/cmd-lwip.c index 625c8c53b8..86b35ccff8 100644 --- a/lib/lwip/cmd-lwip.c +++ b/lib/lwip/cmd-lwip.c @@ -12,6 +12,7 @@ #include <net.h> #include <image.h>
+#include "apps/dns/lwip-dns.h" #include "apps/ping/lwip_ping.h" #include "ulwip.h"
@@ -208,6 +209,39 @@ static int _do_lwip_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, } #endif /* CONFIG_CMD_DHCP */
+#if defined(CONFIG_CMD_DNS) +int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret; + char *name; + char *varname; + int LWIP_ERR_INPROGRESS = -5; + + if (argc == 1) + return CMD_RET_USAGE; + + name = argv[1]; + + if (argc == 3) + varname = argv[2]; + else + varname = NULL; + + uboot_lwip_init(); + + ret = ulwip_dns(name, varname); + if (ret == 0) + return CMD_RET_SUCCESS; + if (ret != LWIP_ERR_INPROGRESS) + return CMD_RET_FAILURE; + + net_set_timeout_handler(1000UL, ulwip_timeout_handler); + + return ulwip_loop(); +} +#endif /* CONFIG_CMD_DNS */ + 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, @@ -230,6 +264,11 @@ static struct cmd_tbl cmds[] = { "boot image via network using DHCP/TFTP protocol", ""), #endif +#if defined(CONFIG_CMD_DNS) + U_BOOT_CMD_MKENT(dns, 3, 0, do_lwip_dns, + "lookup dns name [and store address at variable]", + ""), +#endif };
static int do_ops(struct cmd_tbl *cmdtp, int flag, int argc, diff --git a/lib/lwip/lwipopts.h b/lib/lwip/lwipopts.h index b943d7b9be..7f99a536ee 100644 --- a/lib/lwip/lwipopts.h +++ b/lib/lwip/lwipopts.h @@ -43,7 +43,7 @@ #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 DNS_DEBUG LWIP_DBG_ON #define IP6_DEBUG LWIP_DBG_OFF #define DHCP6_DEBUG LWIP_DBG_OFF #else

provide hostname to client and allow lwip to resolve it.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- lib/lwip/apps/http/lwip-wget.c | 59 ++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 6 deletions(-)
diff --git a/lib/lwip/apps/http/lwip-wget.c b/lib/lwip/apps/http/lwip-wget.c index 0308b0b04a..db553a0f14 100644 --- a/lib/lwip/apps/http/lwip-wget.c +++ b/lib/lwip/apps/http/lwip-wget.c @@ -45,18 +45,65 @@ static void httpc_result(void *arg, httpc_result_t httpc_result, u32_t rx_conten } }
+/* http://hostname:port/url */ +static int parse_url(char *url, char *host, int *port) +{ + int ret; + char *p, *pp; + + p = strstr(url, "http://"); + if (!p) { + printf("err: no http://!%5Cn"); + return -1; + } + + p += strlen("http://"); + + /* parse hostname */ + pp = strchr(p, ':'); + if (pp) { + char portstr[5]; + + memcpy(host, p, pp - p); + host[pp - p + 1] = '\0'; + + p = pp + 1; + pp = strchr(p, '/'); + if (!pp) { + printf("wrong url\n"); + return -2; + } + + memcpy(portstr, p, pp - p); + portstr[pp - p] = '\0'; + *port = atoi(portstr); + } else { + pp = strchr(p, '/'); + if (!pp) { + printf("wrong url\n"); + return -3; + } + memcpy(host, p, pp - p); + host[pp - p + 1] = '\0'; + *port = 80; /* default */ + } + + return 0; +} + int lwip_wget(ulong addr, char *url) { err_t err; - int port = 80; - char *server_name; + int port; + char server_name[80]; 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; + + err = parse_url(url, server_name, &port); + if (err) { + printf("error parse_url\n"); + return -1; }
printf("downloading %s to addr 0x%lx\n", url, addr);

On Fri, Jul 14, 2023 at 08:20:00PM +0600, Maxim Uvarov wrote:
provide hostname to client and allow lwip to resolve it.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
lib/lwip/apps/http/lwip-wget.c | 59 ++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 6 deletions(-)
diff --git a/lib/lwip/apps/http/lwip-wget.c b/lib/lwip/apps/http/lwip-wget.c index 0308b0b04a..db553a0f14 100644 --- a/lib/lwip/apps/http/lwip-wget.c +++ b/lib/lwip/apps/http/lwip-wget.c @@ -45,18 +45,65 @@ static void httpc_result(void *arg, httpc_result_t httpc_result, u32_t rx_conten } }
+/* http://hostname:port/url */ +static int parse_url(char *url, char *host, int *port) +{
- int ret;
- char *p, *pp;
- p = strstr(url, "http://");
- if (!p) {
printf("err: no http://!\n");
return -1;
- }
- p += strlen("http://");
- /* parse hostname */
- pp = strchr(p, ':');
- if (pp) {
char portstr[5];
memcpy(host, p, pp - p);
You are copying bytes over without taking into account the length of the array. Also, I think we should keep things as simple as possible for the first iteration, so can we ignore the port config for now and just stick to 80?
Thanks /Ilias
host[pp - p + 1] = '\0';
p = pp + 1;
pp = strchr(p, '/');
if (!pp) {
printf("wrong url\n");
return -2;
}
memcpy(portstr, p, pp - p);
portstr[pp - p] = '\0';
*port = atoi(portstr);
- } else {
pp = strchr(p, '/');
if (!pp) {
printf("wrong url\n");
return -3;
}
memcpy(host, p, pp - p);
host[pp - p + 1] = '\0';
*port = 80; /* default */
- }
- return 0;
+}
int lwip_wget(ulong addr, char *url) { err_t err;
- int port = 80;
- char *server_name;
int port;
char server_name[80]; 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;
err = parse_url(url, server_name, &port);
if (err) {
printf("error parse_url\n");
return -1;
}
printf("downloading %s to addr 0x%lx\n", url, addr);
-- 2.30.2

Hi Maxim,
On Fri, Jul 14, 2023 at 08:19:55PM +0600, Maxim Uvarov wrote:
changelog: v4: - tested with tests/py/ did some minor fixes (out of tree build, variables set after downloads). - accounted review comments for documentation. - implemented dns command - corrected wget command to not use serverip variable and use just url string. v3: - use lwip commands for ping,tftp,wget,dhcp if this patch applied. Drop CONFIG_LIB_LWIP_REPLACE_<COMMAND> option. - docs: use rst variant and drop references to RFC.
build: git submodule init git submodule update make
I tested with qemu and ubuntu host for the server manually and with ./test/py/test -bd qemu_arm64 --build -k net.
Maxim Uvarov (5): net/lwip: add lwip-external submodule net/lwip: add lwip library for the network stack net/lwip: add doc/develop/net_lwip.rst net/lwip: add dns command
This dones't apply to master. Can you rebase and resend it?
Thanks /Ilias
net/lwip: apps/http: add dns support
.gitignore | 9 + .gitmodules | 3 + boot/bootmeth_pxe.c | 2 +- cmd/net.c | 89 +------- cmd/pxe.c | 2 +- doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 59 +++++ include/net.h | 8 +- lib/Kconfig | 2 + lib/Makefile | 2 + lib/lwip/Kconfig | 63 ++++++ lib/lwip/Makefile | 103 +++++++++ lib/lwip/apps/dhcp/lwip-dhcp.c | 52 +++++ lib/lwip/apps/dns/lwip-dns.c | 46 ++++ lib/lwip/apps/dns/lwip-dns.h | 3 + lib/lwip/apps/http/lwip-wget.c | 121 ++++++++++ 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 | 308 ++++++++++++++++++++++++++ lib/lwip/lwip-external | 1 + 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 ++ 31 files changed, 1634 insertions(+), 82 deletions(-) create mode 100644 .gitmodules create mode 100644 doc/develop/net_lwip.rst 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/dns/lwip-dns.c create mode 100644 lib/lwip/apps/dns/lwip-dns.h 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 160000 lib/lwip/lwip-external 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
-- 2.30.2

Hi Maxim,
On Fri, 14 Jul 2023 at 08:22, Maxim Uvarov maxim.uvarov@linaro.org wrote:
changelog: v4: - tested with tests/py/ did some minor fixes (out of tree build, variables set after downloads). - accounted review comments for documentation. - implemented dns command - corrected wget command to not use serverip variable and use just url string. v3: - use lwip commands for ping,tftp,wget,dhcp if this patch applied. Drop CONFIG_LIB_LWIP_REPLACE_<COMMAND> option. - docs: use rst variant and drop references to RFC.
build: git submodule init git submodule update make
I tested with qemu and ubuntu host for the server manually and with ./test/py/test -bd qemu_arm64 --build -k net.
If we are moving to a new stack we should take this oppty to create unit tests that deal with error paths as well, as it done in test/dm/eth.c
What unit tests does lwip have?
Regards, Simon

On Fri, 28 Jul 2023 at 07:52, Simon Glass sjg@google.com wrote:
Hi Maxim,
On Fri, 14 Jul 2023 at 08:22, Maxim Uvarov maxim.uvarov@linaro.org wrote:
changelog: v4: - tested with tests/py/ did some minor fixes (out of tree build, variables set after downloads). - accounted review comments for documentation. - implemented dns command - corrected wget command to not use serverip variable and
use just
url string. v3: - use lwip commands for ping,tftp,wget,dhcp if this patch applied. Drop CONFIG_LIB_LWIP_REPLACE_<COMMAND> option. - docs: use rst variant and drop references to RFC.
build: git submodule init git submodule update make
I tested with qemu and ubuntu host for the server manually and with ./test/py/test -bd qemu_arm64 --build -k net.
If we are moving to a new stack we should take this oppty to create unit tests that deal with error paths as well, as it done in test/dm/eth.c
lwip itself has unit tests: https://git.savannah.nongnu.org/cgit/lwip.git/tree/test
I first time look on what is test/dm/eth.c but to compare it to for example https://git.savannah.nongnu.org/cgit/lwip.git/tree/test/unit/dhcp/test_dhcp.... it's about the same.
BR, Maxim.
What unit tests does lwip have?
Regards, Simon
participants (5)
-
Ilias Apalodimas
-
Maxim Uvarov
-
Peter Robinson
-
Simon Glass
-
Tom Rini