[PATCHv8 00/15] net/lwip: add lwip library for the network stack

Before apply these patches it is needed to create lwIP merge into U-Boot: git subtree add --prefix net/lwip/lwip-external https://git.savannah.nongnu.org/git/lwip.git master --squash or create git submodule, depends how it's more easy to maintain external library.
changelog: v8: - comments for previous review - removed lwip timeout callback pointer - made lwip timeouts works, that also allowed to remove static vars. - setenv for filesize tftp and wget has to be in hex. - Makefile changes always compile it tftp,dns,wget,ping due to it can be used not only by CONFIG_CMD_. - Kconfig changes - simplify lwIP settings and support only one configuration. - tested with mini debian.iso load over http or tftp, mount and boot it (qemu, arm64). v7: - more review fixes. - support of multiply eth devices, were "ethact" selects the active device. v6: - fixed review comments for v5 (thanks Ilias and Simon). - lwip is not under /net, so prior applying patch following commit is needed to create lwIP merge into U-Boot: git subtree add --prefix net/lwip/lwip-external https://git.savannah.nongnu.org/git/lwip.git master --squash
v5: - fixed Iliases comments and split big patch on the small ones. You also need to issue command: git subtree add --prefix lib/lwip/lwip-external https://git.savannah.nongnu.org/git/lwip.git master --squash Which will create merge commit of lwip library placing sources into lib/lwip/lwip-external directory. I do not send it a patch due to 1. merges are not friendly with git format-patch and 2. the source code of lwip is 78kb. 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.
Maxim Uvarov (15): net/lwip: add doc/develop/net_lwip.rst net/lwip: integrate lwIP library net/lwip: implement dns cmd net/lwip: implement dhcp cmd net/lwip: implement tftp cmd net/lwip: implement wget cmd net/lwip: implement ping cmd net/lwip: add lwIP configuration net/lwip: implement lwIP port to U-Boot net/lwip: update .gitignore with lwIP net/lwip: connection between cmd and lwip apps net/lwip: replace original net commands with lwip net/lwip: split net.h to net.h, arp.h and eth.h net/lwip: drop old net/wget net/lwip/wget add port selection
boot/bootmeth_efi.c | 18 +- boot/bootmeth_pxe.c | 21 +- cmd/Makefile | 1 + cmd/net-lwip.c | 286 +++++++++++++++++ cmd/net.c | 86 +---- cmd/pxe.c | 19 +- doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 75 +++++ include/net.h | 197 +----------- include/net/arp.h | 7 + include/net/eth.h | 190 +++++++++++ include/net/lwip.h | 73 +++++ include/net/ulwip.h | 64 ++++ include/net/wget.h | 22 -- net/Kconfig | 3 + net/Makefile | 2 +- net/eth-uclass.c | 8 + net/lwip/.gitignore | 8 + net/lwip/Kconfig | 25 ++ net/lwip/Makefile | 70 ++++ net/lwip/apps/dhcp/lwip-dhcp.c | 61 ++++ net/lwip/apps/dns/lwip-dns.c | 63 ++++ net/lwip/apps/http/Makefile | 6 + net/lwip/apps/http/lwip-wget.c | 126 ++++++++ net/lwip/apps/ping/Makefile | 12 + net/lwip/apps/ping/lwip_ping.c | 40 +++ net/lwip/apps/ping/lwip_ping.h | 15 + net/lwip/apps/ping/ping.h | 19 ++ net/lwip/apps/tftp/Makefile | 7 + net/lwip/apps/tftp/lwip-tftp.c | 129 ++++++++ net/lwip/lwipopts.h | 178 +++++++++++ net/lwip/port/if.c | 332 +++++++++++++++++++ net/lwip/port/include/arch/cc.h | 38 +++ net/lwip/port/include/arch/sys_arch.h | 10 + net/lwip/port/include/limits.h | 0 net/lwip/port/sys-arch.c | 13 + net/net.c | 26 +- net/wget.c | 440 -------------------------- 38 files changed, 1933 insertions(+), 758 deletions(-) create mode 100644 cmd/net-lwip.c create mode 100644 doc/develop/net_lwip.rst create mode 100644 include/net/arp.h create mode 100644 include/net/eth.h create mode 100644 include/net/lwip.h create mode 100644 include/net/ulwip.h delete mode 100644 include/net/wget.h create mode 100644 net/lwip/.gitignore create mode 100644 net/lwip/Kconfig create mode 100644 net/lwip/Makefile create mode 100644 net/lwip/apps/dhcp/lwip-dhcp.c create mode 100644 net/lwip/apps/dns/lwip-dns.c create mode 100644 net/lwip/apps/http/Makefile create mode 100644 net/lwip/apps/http/lwip-wget.c create mode 100644 net/lwip/apps/ping/Makefile create mode 100644 net/lwip/apps/ping/lwip_ping.c create mode 100644 net/lwip/apps/ping/lwip_ping.h create mode 100644 net/lwip/apps/ping/ping.h create mode 100644 net/lwip/apps/tftp/Makefile create mode 100644 net/lwip/apps/tftp/lwip-tftp.c create mode 100644 net/lwip/lwipopts.h create mode 100644 net/lwip/port/if.c create mode 100644 net/lwip/port/include/arch/cc.h create mode 100644 net/lwip/port/include/arch/sys_arch.h create mode 100644 net/lwip/port/include/limits.h create mode 100644 net/lwip/port/sys-arch.c delete mode 100644 net/wget.c

Add initial documentation of lwIP network IP stack integration to the U-Boot (net_lwip.rst).
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org Reviewed-by: Simon Glass sjg@chromium.org --- doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 75 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 doc/develop/net_lwip.rst
diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 5b230d0321..4764990f25 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -48,6 +48,7 @@ Implementation spl falcon 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..a77ab60d0f --- /dev/null +++ b/doc/develop/net_lwip.rst @@ -0,0 +1,75 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +lwIP IP stack integration for U-Boot +==================================== + +Intro +----- + +lwIP is a library implementing 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 second variant was selected: lwIP is very customizable + with defines for features, memory size, types of allocation, some internal + types and platform specific code. It turned out easier 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. + +In raw IP mode a callback function for RX path is registered and will be called +when packet is passed to the IP stack and is ready for the application. + +One example is the unmodified working ping example from lwip sources which +registered 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) + +3. Input and output + +RX packet path is injected to U-Boot eth_rx() polling loop and TX patch is in +eth_send() accordingly. That way we can leave the driver code unmodified and +consume packets once they are ready. So we do not touch any drivers code and +just eat packets when they are ready. + +U-Boot lwIP Applications +======================== + +.. kernel-doc:: include/net/lwip.h + :internal: + +lwIP API to control polling loop +================================ + +.. kernel-doc:: include/net/ulwip.h + :internal:

On Fri, Sep 08, 2023 at 07:53:06PM +0600, Maxim Uvarov wrote:
Add initial documentation of lwIP network IP stack integration to the U-Boot (net_lwip.rst).
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
doc/develop/index.rst | 1 + doc/develop/net_lwip.rst | 75 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 doc/develop/net_lwip.rst
diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 5b230d0321..4764990f25 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -48,6 +48,7 @@ Implementation spl falcon 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..a77ab60d0f --- /dev/null +++ b/doc/develop/net_lwip.rst @@ -0,0 +1,75 @@ +.. SPDX-License-Identifier: GPL-2.0+
+lwIP IP stack integration for U-Boot +====================================
+Intro +-----
+lwIP is a library implementing 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 second variant was selected: lwIP is very customizable
- with defines for features, memory size, types of allocation, some internal
- types and platform specific code. It turned out easier 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.
+In raw IP mode a callback function for RX path is registered and will be called +when packet is passed to the IP stack and is ready for the application.
+One example is the unmodified working ping example from lwip sources which +registered 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)
+3. Input and output
+RX packet path is injected to U-Boot eth_rx() polling loop and TX patch is in +eth_send() accordingly. That way we can leave the driver code unmodified and +consume packets once they are ready. So we do not touch any drivers code and +just eat packets when they are ready.
+U-Boot lwIP Applications +========================
+.. kernel-doc:: include/net/lwip.h
- :internal:
+lwIP API to control polling loop +================================
+.. kernel-doc:: include/net/ulwip.h
- :internal:
-- 2.30.2
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

Define Makefile and Kconfig to build lwIP inside the U-Boot. We compile lwIP the same as the main code, plus we can do optimization for size at compile time with disabling not needed debug asserts, or not used protocols. So we can tune lwIP configuration specially for U-Boot environments.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- net/Kconfig | 3 +++ net/Makefile | 1 + net/lwip/Kconfig | 25 ++++++++++++++++++ net/lwip/Makefile | 64 +++++++++++++++++++++++++++++++++++++++++++++++ net/net.c | 20 ++++++++++++++- 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 net/lwip/Kconfig create mode 100644 net/lwip/Makefile
diff --git a/net/Kconfig b/net/Kconfig index 4215889127..34c1e43c87 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -5,9 +5,12 @@ menuconfig NET bool "Networking support" default y + imply LWIP
if NET
+source net/lwip/Kconfig + config ARP_TIMEOUT int "Milliseconds before trying ARP again" default 5000 diff --git a/net/Makefile b/net/Makefile index 3e2d061338..61930c244e 100644 --- a/net/Makefile +++ b/net/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_PROT_UDP) += udp.o obj-$(CONFIG_PROT_TCP) += tcp.o obj-$(CONFIG_CMD_WGET) += wget.o +obj-$(CONFIG_LWIP) += lwip/
# Disable this warning as it is triggered by: # sprintf(buf, index ? "foo%d" : "foo", index) diff --git a/net/lwip/Kconfig b/net/lwip/Kconfig new file mode 100644 index 0000000000..19f987a074 --- /dev/null +++ b/net/lwip/Kconfig @@ -0,0 +1,25 @@ +menu "lwIP" +config LWIP + bool "Support LWIP library" + help + Enable the lwIP library code with + all dependencies (commands are implemented with lwIP + library. This option is automatically enabled if CONFIG_NET=y. + lwIP library (https://git.savannah.nongnu.org/git/lwip.git) provides + network stack and application code for U-Boot commands. + Please see doc/develop/net_lwip.rst for more details. + +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 by 16k. +endmenu + +endmenu diff --git a/net/lwip/Makefile b/net/lwip/Makefile new file mode 100644 index 0000000000..3fd5d34564 --- /dev/null +++ b/net/lwip/Makefile @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip + +obj-$(CONFIG_NET) += lwip-external/src/core/init.o \ + lwip-external/src/core/def.o \ + lwip-external/src/core/dns.o \ + lwip-external/src/core/inet_chksum.o \ + lwip-external/src/core/ip.o \ + lwip-external/src/core/mem.o \ + lwip-external/src/core/memp.o \ + lwip-external/src/core/netif.o \ + lwip-external/src/core/pbuf.o \ + lwip-external/src/core/raw.o \ + lwip-external/src/core/stats.o \ + lwip-external/src/core/sys.o \ + lwip-external/src/core/altcp.o \ + lwip-external/src/core/altcp_alloc.o \ + lwip-external/src/core/altcp_tcp.o \ + lwip-external/src/core/tcp.o \ + lwip-external/src/core/tcp_in.o \ + lwip-external/src/core/tcp_out.o \ + lwip-external/src/core/timeouts.o \ + lwip-external/src/core/udp.o + +# IPv4 +obj-$(CONFIG_NET) += lwip-external/src/core/ipv4/acd.o \ + lwip-external/src/core/ipv4/autoip.o \ + lwip-external/src/core/ipv4/dhcp.o \ + lwip-external/src/core/ipv4/etharp.o \ + lwip-external/src/core/ipv4/icmp.o \ + lwip-external/src/core/ipv4/igmp.o \ + lwip-external/src/core/ipv4/ip4_frag.o \ + lwip-external/src/core/ipv4/ip4.o \ + lwip-external/src/core/ipv4/ip4_addr.o +# IPv6 +obj-$(CONFIG_NET) += lwip-external/src/core/ipv6/dhcp6.o \ + lwip-external/src/core/ipv6/ethip6.o \ + lwip-external/src/core/ipv6/icmp6.o \ + lwip-external/src/core/ipv6/inet6.o \ + lwip-external/src/core/ipv6/ip6.o \ + lwip-external/src/core/ipv6/ip6_addr.o \ + lwip-external/src/core/ipv6/ip6_frag.o \ + lwip-external/src/core/ipv6/mld6.o \ + lwip-external/src/core/ipv6/nd6.o +# API +obj-$(CONFIG_NET) += lwip-external/src/api/api_lib.o \ + lwip-external/src/api/api_msg.o \ + lwip-external/src/api/err.o \ + lwip-external/src/api/if_api.o \ + lwip-external/src/api/netbuf.o \ + lwip-external/src/api/netdb.o \ + lwip-external/src/api/netifapi.o \ + lwip-external/src/api/sockets.o \ + lwip-external/src/api/tcpip.o + +# Netdevs +obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o + +obj-$(CONFIG_NET) += port/if.o +obj-$(CONFIG_NET) += port/sys-arch.o diff --git a/net/net.c b/net/net.c index 43abbac7c3..d9e566081c 100644 --- a/net/net.c +++ b/net/net.c @@ -125,6 +125,7 @@ #endif #include "dhcpv6.h" #include "net_rand.h" +#include <net/ulwip.h>
/** BOOTP EXTENTIONS **/
@@ -452,7 +453,9 @@ int net_loop(enum proto_t protocol) #endif
bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start"); - net_init(); + if (!ulwip_enabled() || !ulwip_in_loop()) + net_init(); + if (eth_is_on_demand_init()) { eth_halt(); eth_set_current(); @@ -649,6 +652,16 @@ restart: */ eth_rx();
+ 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; + } + } /* * Abort if ctrl-c was pressed. */ @@ -1213,6 +1226,11 @@ void net_process_received_packet(uchar *in_packet, int len) if (len < ETHER_HDR_SIZE) return;
+ if (ulwip_enabled()) { + ulwip_poll(); + return; + } + #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) if (push_packet) { (*push_packet)(in_packet, len);

U-Boot recently got support for an alternative network stack using LWIP. Replace dns command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 19 +++++++++++ net/lwip/Makefile | 2 ++ net/lwip/apps/dns/lwip-dns.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 include/net/lwip.h create mode 100644 net/lwip/apps/dns/lwip-dns.c
diff --git a/include/net/lwip.h b/include/net/lwip.h new file mode 100644 index 0000000000..ab3db1a214 --- /dev/null +++ b/include/net/lwip.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); + +/** + * ulwip_dns() - creates the DNS request to resolve a domain host name + * + * This function creates the DNS request to resolve a domain host name. Function + * can return immediately if previous request was cached or it might require + * entering the polling loop for a request to a remote server. + * + * @name: dns name to resolve + * @varname: (optional) U-Boot variable name to store the result + * Returns: ERR_OK(0) for fetching entry from the cache + * -EINPROGRESS success, can go to the polling loop + * Other value < 0, if error + */ +int ulwip_dns(char *name, char *varname); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 3fd5d34564..5d8d5527c6 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o
obj-$(CONFIG_NET) += port/if.o obj-$(CONFIG_NET) += port/sys-arch.o + +obj-y += apps/dns/lwip-dns.o diff --git a/net/lwip/apps/dns/lwip-dns.c b/net/lwip/apps/dns/lwip-dns.c new file mode 100644 index 0000000000..b340302f2c --- /dev/null +++ b/net/lwip/apps/dns/lwip-dns.c @@ -0,0 +1,63 @@ +// 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 <net/ulwip.h> + +static void dns_found_cb(const char *name, const ip_addr_t *ipaddr, void *callback_arg) +{ + char *varname = (char *)callback_arg; + char *ipstr = ip4addr_ntoa(ipaddr); + + if (varname) + env_set(varname, ipstr); + log_info("resolved %s to %s\n", name, ipstr); + 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; + char *dnsenv = env_get("dnsip"); + char *dns2env = env_get("dnsip2"); + + if (!dnsenv && !dns2env) { + log_err("nameserver is not set with dnsip and dnsip2 vars\n"); + return -ENOENT; + } + + if (!dnsenv) + log_warning("dnsip var is not set\n"); + if (!dns2env) + log_warning("dnsip2 var is not set\n"); + + dns_init(); + + if (ipaddr_aton(dnsenv, &dns1)) + dns_setserver(0, &dns1); + + if (ipaddr_aton(dns2env, &dns2)) + dns_setserver(1, &dns2); + + err = dns_gethostbyname(name, &ipaddr, dns_found_cb, varname); + if (err == ERR_OK) + dns_found_cb(name, &ipaddr, varname); + + /* convert lwIP ERR_INPROGRESS to U-Boot -EINPROGRESS */ + if (err == ERR_INPROGRESS) + err = -EINPROGRESS; + + return err; +}

On Fri, Sep 08, 2023 at 07:53:08PM +0600, Maxim Uvarov wrote:
U-Boot recently got support for an alternative network stack using LWIP. Replace dns command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
include/net/lwip.h | 19 +++++++++++ net/lwip/Makefile | 2 ++ net/lwip/apps/dns/lwip-dns.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 include/net/lwip.h create mode 100644 net/lwip/apps/dns/lwip-dns.c
diff --git a/include/net/lwip.h b/include/net/lwip.h new file mode 100644 index 0000000000..ab3db1a214 --- /dev/null +++ b/include/net/lwip.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */
+int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
+/**
- ulwip_dns() - creates the DNS request to resolve a domain host name
- This function creates the DNS request to resolve a domain host name. Function
- can return immediately if previous request was cached or it might require
- entering the polling loop for a request to a remote server.
- @name: dns name to resolve
- @varname: (optional) U-Boot variable name to store the result
- Returns: ERR_OK(0) for fetching entry from the cache
-EINPROGRESS success, can go to the polling loop
Other value < 0, if error
- */
+int ulwip_dns(char *name, char *varname); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 3fd5d34564..5d8d5527c6 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o
obj-$(CONFIG_NET) += port/if.o obj-$(CONFIG_NET) += port/sys-arch.o
+obj-y += apps/dns/lwip-dns.o diff --git a/net/lwip/apps/dns/lwip-dns.c b/net/lwip/apps/dns/lwip-dns.c new file mode 100644 index 0000000000..b340302f2c --- /dev/null +++ b/net/lwip/apps/dns/lwip-dns.c @@ -0,0 +1,63 @@ +// 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 <net/ulwip.h>
+static void dns_found_cb(const char *name, const ip_addr_t *ipaddr, void *callback_arg) +{
- char *varname = (char *)callback_arg;
- char *ipstr = ip4addr_ntoa(ipaddr);
- if (varname)
env_set(varname, ipstr);
- log_info("resolved %s to %s\n", name, ipstr);
- 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;
- char *dnsenv = env_get("dnsip");
- char *dns2env = env_get("dnsip2");
- if (!dnsenv && !dns2env) {
log_err("nameserver is not set with dnsip and dnsip2 vars\n");
return -ENOENT;
- }
- if (!dnsenv)
log_warning("dnsip var is not set\n");
- if (!dns2env)
log_warning("dnsip2 var is not set\n");
- dns_init();
- if (ipaddr_aton(dnsenv, &dns1))
dns_setserver(0, &dns1);
- if (ipaddr_aton(dns2env, &dns2))
dns_setserver(1, &dns2);
env_get will return NULL if any of these is not set. Looking at ipaddr_aton() of lwip that might lead to a NULL deref in ip_2_ip6()
- err = dns_gethostbyname(name, &ipaddr, dns_found_cb, varname);
- if (err == ERR_OK)
dns_found_cb(name, &ipaddr, varname);
- /* convert lwIP ERR_INPROGRESS to U-Boot -EINPROGRESS */
- if (err == ERR_INPROGRESS)
err = -EINPROGRESS;
- return err;
+}
2.30.2

On 13.09.2023 07:56, Ilias Apalodimas wrote:
On Fri, Sep 08, 2023 at 07:53:08PM +0600, Maxim Uvarov wrote:
U-Boot recently got support for an alternative network stack using LWIP. Replace dns command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
include/net/lwip.h | 19 +++++++++++ net/lwip/Makefile | 2 ++ net/lwip/apps/dns/lwip-dns.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 include/net/lwip.h create mode 100644 net/lwip/apps/dns/lwip-dns.c
diff --git a/include/net/lwip.h b/include/net/lwip.h new file mode 100644 index 0000000000..ab3db1a214 --- /dev/null +++ b/include/net/lwip.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */
+int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
+/**
- ulwip_dns() - creates the DNS request to resolve a domain host name
- This function creates the DNS request to resolve a domain host name. Function
- can return immediately if previous request was cached or it might require
- entering the polling loop for a request to a remote server.
- @name: dns name to resolve
- @varname: (optional) U-Boot variable name to store the result
- Returns: ERR_OK(0) for fetching entry from the cache
-EINPROGRESS success, can go to the polling loop
Other value < 0, if error
- */
+int ulwip_dns(char *name, char *varname); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 3fd5d34564..5d8d5527c6 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o
obj-$(CONFIG_NET) += port/if.o obj-$(CONFIG_NET) += port/sys-arch.o
+obj-y += apps/dns/lwip-dns.o diff --git a/net/lwip/apps/dns/lwip-dns.c b/net/lwip/apps/dns/lwip-dns.c new file mode 100644 index 0000000000..b340302f2c --- /dev/null +++ b/net/lwip/apps/dns/lwip-dns.c @@ -0,0 +1,63 @@ +// 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 <net/ulwip.h>
+static void dns_found_cb(const char *name, const ip_addr_t *ipaddr, void *callback_arg) +{
- char *varname = (char *)callback_arg;
- char *ipstr = ip4addr_ntoa(ipaddr);
- if (varname)
env_set(varname, ipstr);
- log_info("resolved %s to %s\n", name, ipstr);
- 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;
- char *dnsenv = env_get("dnsip");
- char *dns2env = env_get("dnsip2");
- if (!dnsenv && !dns2env) {
log_err("nameserver is not set with dnsip and dnsip2 vars\n");
return -ENOENT;
- }
- if (!dnsenv)
log_warning("dnsip var is not set\n");
- if (!dns2env)
log_warning("dnsip2 var is not set\n");
- dns_init();
- if (ipaddr_aton(dnsenv, &dns1))
dns_setserver(0, &dns1);
- if (ipaddr_aton(dns2env, &dns2))
dns_setserver(1, &dns2);
env_get will return NULL if any of these is not set. Looking at ipaddr_aton() of lwip that might lead to a NULL deref in ip_2_ip6()
Looking at the NULL checks in ipaddr_aton(), you found a bug in lwIP. I'd vote to leave the above code as is and rely on the bug being fixed in lwIP before U-Boot enables IPv6 (this is only a bug in dual-stack mode where IPv4 and IPv6 is enabled).
Regards, Simon
- err = dns_gethostbyname(name, &ipaddr, dns_found_cb, varname);
- if (err == ERR_OK)
dns_found_cb(name, &ipaddr, varname);
- /* convert lwIP ERR_INPROGRESS to U-Boot -EINPROGRESS */
- if (err == ERR_INPROGRESS)
err = -EINPROGRESS;
- return err;
+}
2.30.2

On Wed, 13 Sept 2023 at 14:32, Simon Goldschmidt goldsimon@gmx.de wrote:
On 13.09.2023 07:56, Ilias Apalodimas wrote:
On Fri, Sep 08, 2023 at 07:53:08PM +0600, Maxim Uvarov wrote:
U-Boot recently got support for an alternative network stack using LWIP. Replace dns command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
include/net/lwip.h | 19 +++++++++++ net/lwip/Makefile | 2 ++ net/lwip/apps/dns/lwip-dns.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 include/net/lwip.h create mode 100644 net/lwip/apps/dns/lwip-dns.c
diff --git a/include/net/lwip.h b/include/net/lwip.h new file mode 100644 index 0000000000..ab3db1a214 --- /dev/null +++ b/include/net/lwip.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */
+int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
+/**
- ulwip_dns() - creates the DNS request to resolve a domain host name
- This function creates the DNS request to resolve a domain host
name. Function
- can return immediately if previous request was cached or it might
require
- entering the polling loop for a request to a remote server.
- @name: dns name to resolve
- @varname: (optional) U-Boot variable name to store the result
- Returns: ERR_OK(0) for fetching entry from the cache
-EINPROGRESS success, can go to the polling loop
Other value < 0, if error
- */
+int ulwip_dns(char *name, char *varname); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 3fd5d34564..5d8d5527c6 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -62,3 +62,5 @@ obj-$(CONFIG_NET) +=
lwip-external/src/netif/ethernet.o
obj-$(CONFIG_NET) += port/if.o obj-$(CONFIG_NET) += port/sys-arch.o
+obj-y += apps/dns/lwip-dns.o diff --git a/net/lwip/apps/dns/lwip-dns.c b/net/lwip/apps/dns/lwip-dns.c new file mode 100644 index 0000000000..b340302f2c --- /dev/null +++ b/net/lwip/apps/dns/lwip-dns.c @@ -0,0 +1,63 @@ +// 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 <net/ulwip.h>
+static void dns_found_cb(const char *name, const ip_addr_t *ipaddr,
void *callback_arg)
+{
- char *varname = (char *)callback_arg;
- char *ipstr = ip4addr_ntoa(ipaddr);
- if (varname)
env_set(varname, ipstr);
- log_info("resolved %s to %s\n", name, ipstr);
- 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;
- char *dnsenv = env_get("dnsip");
- char *dns2env = env_get("dnsip2");
- if (!dnsenv && !dns2env) {
log_err("nameserver is not set with dnsip and dnsip2
vars\n");
return -ENOENT;
- }
- if (!dnsenv)
log_warning("dnsip var is not set\n");
- if (!dns2env)
log_warning("dnsip2 var is not set\n");
- dns_init();
- if (ipaddr_aton(dnsenv, &dns1))
dns_setserver(0, &dns1);
- if (ipaddr_aton(dns2env, &dns2))
dns_setserver(1, &dns2);
env_get will return NULL if any of these is not set. Looking at ipaddr_aton() of lwip that might lead to a NULL deref in ip_2_ip6()
Looking at the NULL checks in ipaddr_aton(), you found a bug in lwIP. I'd vote to leave the above code as is and rely on the bug being fixed in lwIP before U-Boot enables IPv6 (this is only a bug in dual-stack mode where IPv4 and IPv6 is enabled).
Regards, Simon
Yes, I looked for an ipv4 case with null check. But I think here we can go with: if (dns2env && ipaddr_aton(dns2env, &dns2))
- err = dns_gethostbyname(name, &ipaddr, dns_found_cb, varname);
- if (err == ERR_OK)
dns_found_cb(name, &ipaddr, varname);
- /* convert lwIP ERR_INPROGRESS to U-Boot -EINPROGRESS */
- if (err == ERR_INPROGRESS)
err = -EINPROGRESS;
- return err;
+}
2.30.2

U-Boot recently got support for an alternative network stack using LWIP. Replace dhcp command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 12 +++++++ net/lwip/Makefile | 1 + net/lwip/apps/dhcp/lwip-dhcp.c | 61 ++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 net/lwip/apps/dhcp/lwip-dhcp.c
diff --git a/include/net/lwip.h b/include/net/lwip.h index ab3db1a214..6a8fcef392 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -17,3 +17,15 @@ int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, * Other value < 0, if error */ int ulwip_dns(char *name, char *varname); + +/** + * ulwip_dhcp() - create the DHCP request to obtain IP address. + * + * This function creates the DHCP request to obtain IP address. If DHCP server + * returns file name, this file will be downloaded with tftp. After this + * function you need to invoke the polling loop to process network communication. + * + * Returns: 0 if success + * Other value < 0, if error +*/ +int ulwip_dhcp(void); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 5d8d5527c6..a3a33b7f71 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -63,4 +63,5 @@ obj-$(CONFIG_NET) += lwip-external/src/netif/ethernet.o obj-$(CONFIG_NET) += port/if.o obj-$(CONFIG_NET) += port/sys-arch.o
+obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o diff --git a/net/lwip/apps/dhcp/lwip-dhcp.c b/net/lwip/apps/dhcp/lwip-dhcp.c new file mode 100644 index 0000000000..68334a02bb --- /dev/null +++ b/net/lwip/apps/dhcp/lwip-dhcp.c @@ -0,0 +1,61 @@ +// 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/timeouts.h" + +#include <net/eth.h> +#include <net/ulwip.h> + +#define DHCP_WAIT_MS 2000 + +static void dhcp_tmo(void *arg) +{ + struct netif *netif = (struct netif *)arg; + struct dhcp *dhcp; + int err = 0; + + dhcp = netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP); + if (!dhcp) + return; + + switch (dhcp->state) { + case DHCP_STATE_BOUND: + err += env_set("bootfile", dhcp->boot_file_name); + err += env_set("ipaddr", ip4addr_ntoa(&dhcp->offered_ip_addr)); + err += env_set("netmask", ip4addr_ntoa(&dhcp->offered_sn_mask)); + err += env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr)); + if (err) + log_err("error update envs\n"); + log_info("DHCP client bound to address %s\n", ip4addr_ntoa(&dhcp->offered_ip_addr)); + break; + default: + return; + } +} + +int ulwip_dhcp(void) +{ + struct netif *netif; + int eth_idx; + + eth_idx = eth_get_dev_index(); + if (eth_idx < 0) + return -EPERM; + + netif = netif_get_by_index(eth_idx + 1); + if (!netif) + return -ENOENT; + + sys_timeout(DHCP_WAIT_MS, dhcp_tmo, netif); + + return dhcp_start(netif) ? 0 : -EPERM; +}

On Fri, Sep 08, 2023 at 07:53:09PM +0600, Maxim Uvarov wrote:
+#include <common.h> +#include <command.h> +#include <console.h>
+#include <lwip/dhcp.h> +#include <lwip/prot/dhcp.h> +#include "lwip/timeouts.h"
+#include <net/eth.h> +#include <net/ulwip.h>
+#define DHCP_WAIT_MS 2000
Is this the time we wait for a dhcp reply? If so we should bump it to something higher
+static void dhcp_tmo(void *arg) +{
- struct netif *netif = (struct netif *)arg;
- struct dhcp *dhcp;
- int err = 0;
- dhcp = netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
- if (!dhcp)
return;
- switch (dhcp->state) {
- case DHCP_STATE_BOUND:
err += env_set("bootfile", dhcp->boot_file_name);
err += env_set("ipaddr", ip4addr_ntoa(&dhcp->offered_ip_addr));
err += env_set("netmask", ip4addr_ntoa(&dhcp->offered_sn_mask));
err += env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr));
if (err)
log_err("error update envs\n");
log_info("DHCP client bound to address %s\n", ip4addr_ntoa(&dhcp->offered_ip_addr));
break;
- default:
return;
- }
+}
+int ulwip_dhcp(void) +{
- struct netif *netif;
- int eth_idx;
- eth_idx = eth_get_dev_index();
- if (eth_idx < 0)
return -EPERM;
- netif = netif_get_by_index(eth_idx + 1);
Why is the +1 needed here?
- if (!netif)
return -ENOENT;
- sys_timeout(DHCP_WAIT_MS, dhcp_tmo, netif);
- return dhcp_start(netif) ? 0 : -EPERM;
+}
2.30.2

On 13.09.2023 08:07, Ilias Apalodimas wrote:
On Fri, Sep 08, 2023 at 07:53:09PM +0600, Maxim Uvarov wrote:
+#include <common.h> +#include <command.h> +#include <console.h>
+#include <lwip/dhcp.h> +#include <lwip/prot/dhcp.h> +#include "lwip/timeouts.h"
+#include <net/eth.h> +#include <net/ulwip.h>
+#define DHCP_WAIT_MS 2000
Is this the time we wait for a dhcp reply? If so we should bump it to something higher
+static void dhcp_tmo(void *arg) +{
- struct netif *netif = (struct netif *)arg;
- struct dhcp *dhcp;
- int err = 0;
- dhcp = netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);
- if (!dhcp)
return;
- switch (dhcp->state) {
- case DHCP_STATE_BOUND:
err += env_set("bootfile", dhcp->boot_file_name);
err += env_set("ipaddr", ip4addr_ntoa(&dhcp->offered_ip_addr));
err += env_set("netmask", ip4addr_ntoa(&dhcp->offered_sn_mask));
err += env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr));
if (err)
log_err("error update envs\n");
log_info("DHCP client bound to address %s\n", ip4addr_ntoa(&dhcp->offered_ip_addr));
break;
- default:
return;
- }
+}
+int ulwip_dhcp(void) +{
- struct netif *netif;
- int eth_idx;
- eth_idx = eth_get_dev_index();
- if (eth_idx < 0)
return -EPERM;
- netif = netif_get_by_index(eth_idx + 1);
Why is the +1 needed here?
Netif index is driven by posix design and is 1-based in contrast to U-Boot's 0-based dev index. A comment noting that would probably help the ones not knowing lwIP.
Regards, Simon
- if (!netif)
return -ENOENT;
- sys_timeout(DHCP_WAIT_MS, dhcp_tmo, netif);
- return dhcp_start(netif) ? 0 : -EPERM;
+}
2.30.2

U-Boot recently got support for an alternative network stack using LWIP. Replace tftp command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 14 +++- net/lwip/Makefile | 1 + net/lwip/apps/tftp/Makefile | 7 ++ net/lwip/apps/tftp/lwip-tftp.c | 129 +++++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 net/lwip/apps/tftp/Makefile create mode 100644 net/lwip/apps/tftp/lwip-tftp.c
diff --git a/include/net/lwip.h b/include/net/lwip.h index 6a8fcef392..c9e2982a78 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -28,4 +28,16 @@ int ulwip_dns(char *name, char *varname); * Returns: 0 if success * Other value < 0, if error */ -int ulwip_dhcp(void); + +/** + * ulwip_tftp() - load file with tftp + * + * Load file with tftp to specific address + * + * @addr: Address to store downloaded file + * @filename: File name on remote tftp server to download + * + * + * Returns: 0 if success, !0 if error + */ +int ulwip_tftp(ulong addr, const char *filename); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index a3a33b7f71..b348e5ca31 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -65,3 +65,4 @@ obj-$(CONFIG_NET) += port/sys-arch.o
obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o +obj-y += apps/tftp/ diff --git a/net/lwip/apps/tftp/Makefile b/net/lwip/apps/tftp/Makefile new file mode 100644 index 0000000000..c3ad3c6353 --- /dev/null +++ b/net/lwip/apps/tftp/Makefile @@ -0,0 +1,7 @@ +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include/lwip/apps +ccflags-y += -I$(srctree)/net/lwip/lwip-external/contrib/examples/tftp/ + +obj-y += ../../lwip-external/src/apps/tftp/tftp.o +obj-y += lwip-tftp.o diff --git a/net/lwip/apps/tftp/lwip-tftp.c b/net/lwip/apps/tftp/lwip-tftp.c new file mode 100644 index 0000000000..56eed3030b --- /dev/null +++ b/net/lwip/apps/tftp/lwip-tftp.c @@ -0,0 +1,129 @@ +// 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 <bootstage.h> + +#include "tftp_client.h" +#include "tftp_server.h" +#include <tftp_example.h> + +#include <string.h> + +#include <net/ulwip.h> + +static ulong daddr; +static ulong size; + +static void *tftp_open(const char *fname, const char *mode, u8_t is_write) +{ + return NULL; +} + +static void tftp_close(void *handle) +{ + log_info("\ndone\n"); + log_info("Bytes transferred = %ld (0x%lx hex)\n", size, size); + + bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done"); + if (env_set_hex("filesize", size)) { + log_err("filesize not updated\n"); + ulwip_exit(-1); + return; + } + 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); + daddr += q->len; + size += q->len; + log_info("#"); + } + + return 0; +} + +static void tftp_error(void *handle, int err, const char *msg, int size) +{ + char message[100]; + + memset(message, 0, sizeof(message)); + memcpy(message, msg, LWIP_MIN(sizeof(message) - 1, (size_t)size)); + + log_info("TFTP error: %d (%s)", err, message); +} + +static const struct tftp_context tftp = { + tftp_open, + tftp_close, + tftp_read, + tftp_write, + tftp_error +}; + +int ulwip_tftp(ulong addr, char *fname) +{ + void *f = (void *)0x1; /* unused fake file 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) { + log_err("error: serverip variable has to be set\n"); + return CMD_RET_FAILURE; + } + + ret = ipaddr_aton(server_ip, &srv); + if (!ret) { + log_err("error: ipaddr_aton\n"); + return CMD_RET_FAILURE; + } + + log_info("TFTP from server %s; our IP address is %s\n", + server_ip, env_get("ipaddr")); + log_info("Filename '%s'.\n", fname); + log_info("Load address: 0x%lx\n", daddr); + log_info("Loading:"); + + bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start"); + + err = tftp_init_client(&tftp); + if (!(err == ERR_OK || err == ERR_USE)) + log_err("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) { + log_err("tftp_get err=%d\n", err); + return CMD_RET_FAILURE; + } + + if (env_set_hex("fileaddr", addr)) { + log_err("fileaddr not updated\n"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +}

+/*
- (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org
- */
+#include <common.h> +#include <command.h> +#include <console.h> +#include <bootstage.h>
+#include "tftp_client.h" +#include "tftp_server.h" +#include <tftp_example.h>
+#include <string.h>
+#include <net/ulwip.h>
+static ulong daddr; +static ulong size;
+static void *tftp_open(const char *fname, const char *mode, u8_t is_write) +{
- return NULL;
+}
+static void tftp_close(void *handle) +{
- log_info("\ndone\n");
- log_info("Bytes transferred = %ld (0x%lx hex)\n", size, size);
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
- if (env_set_hex("filesize", size)) {
log_err("filesize not updated\n");
ulwip_exit(-1);
return;
- }
- 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);
daddr += q->len;
size += q->len;
log_info("#");
- }
- return 0;
+}
+static void tftp_error(void *handle, int err, const char *msg, int size) +{
- char message[100];
- memset(message, 0, sizeof(message));
- memcpy(message, msg, LWIP_MIN(sizeof(message) - 1, (size_t)size));
- log_info("TFTP error: %d (%s)", err, message);
+}
+static const struct tftp_context tftp = {
- tftp_open,
- tftp_close,
- tftp_read,
- tftp_write,
- tftp_error
+};
+int ulwip_tftp(ulong addr, char *fname) +{
- void *f = (void *)0x1; /* unused fake file handle*/
I haven't dug into lwip details yet, but I am not sure this is safe to use. Simon, since you maintain the lwip part can you elaborate a bit more?
- 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) {
log_err("error: serverip variable has to be set\n");
return CMD_RET_FAILURE;
- }
- ret = ipaddr_aton(server_ip, &srv);
- if (!ret) {
log_err("error: ipaddr_aton\n");
return CMD_RET_FAILURE;
- }
- log_info("TFTP from server %s; our IP address is %s\n",
server_ip, env_get("ipaddr"));
- log_info("Filename '%s'.\n", fname);
- log_info("Load address: 0x%lx\n", daddr);
- log_info("Loading:");
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
- err = tftp_init_client(&tftp);
- if (!(err == ERR_OK || err == ERR_USE))
log_err("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) {
log_err("tftp_get err=%d\n", err);
return CMD_RET_FAILURE;
- }
- if (env_set_hex("fileaddr", addr)) {
log_err("fileaddr not updated\n");
return CMD_RET_FAILURE;
- }
- return CMD_RET_SUCCESS;
+}
2.30.2
Thanks /Ilias

On 13.09.2023 08:15, Ilias Apalodimas wrote:
+/*
- (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org
- */
+#include <common.h> +#include <command.h> +#include <console.h> +#include <bootstage.h>
+#include "tftp_client.h" +#include "tftp_server.h" +#include <tftp_example.h>
+#include <string.h>
+#include <net/ulwip.h>
+static ulong daddr; +static ulong size;
+static void *tftp_open(const char *fname, const char *mode, u8_t is_write) +{
- return NULL;
+}
+static void tftp_close(void *handle) +{
- log_info("\ndone\n");
- log_info("Bytes transferred = %ld (0x%lx hex)\n", size, size);
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
- if (env_set_hex("filesize", size)) {
log_err("filesize not updated\n");
ulwip_exit(-1);
return;
- }
- 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);
daddr += q->len;
size += q->len;
log_info("#");
- }
- return 0;
+}
+static void tftp_error(void *handle, int err, const char *msg, int size) +{
- char message[100];
- memset(message, 0, sizeof(message));
- memcpy(message, msg, LWIP_MIN(sizeof(message) - 1, (size_t)size));
- log_info("TFTP error: %d (%s)", err, message);
+}
+static const struct tftp_context tftp = {
- tftp_open,
- tftp_close,
- tftp_read,
- tftp_write,
- tftp_error
+};
+int ulwip_tftp(ulong addr, char *fname) +{
- void *f = (void *)0x1; /* unused fake file handle*/
I haven't dug into lwip details yet, but I am not sure this is safe to use. Simon, since you maintain the lwip part can you elaborate a bit more?
From the lwIP design, using an invalid pointer here is ok: that pointer is only used as a client handle which is never dereferenced internally. The only requirement is that it is not NULL, as that is the validity check for the tftp client to know the handle is valid (or e.g. open failed etc.).
So while we can leave 0x1 here, using a static uint8_t would probably be better, at the expense of using a byte for nothing.
Regards, Simon
- 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) {
log_err("error: serverip variable has to be set\n");
return CMD_RET_FAILURE;
- }
- ret = ipaddr_aton(server_ip, &srv);
- if (!ret) {
log_err("error: ipaddr_aton\n");
return CMD_RET_FAILURE;
- }
- log_info("TFTP from server %s; our IP address is %s\n",
server_ip, env_get("ipaddr"));
- log_info("Filename '%s'.\n", fname);
- log_info("Load address: 0x%lx\n", daddr);
- log_info("Loading:");
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
- err = tftp_init_client(&tftp);
- if (!(err == ERR_OK || err == ERR_USE))
log_err("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) {
log_err("tftp_get err=%d\n", err);
return CMD_RET_FAILURE;
- }
- if (env_set_hex("fileaddr", addr)) {
log_err("fileaddr not updated\n");
return CMD_RET_FAILURE;
- }
- return CMD_RET_SUCCESS;
+}
2.30.2
Thanks /Ilias

On Wed, 13 Sept 2023 at 14:38, Simon Goldschmidt goldsimon@gmx.de wrote:
On 13.09.2023 08:15, Ilias Apalodimas wrote:
+/*
- (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org
- */
+#include <common.h> +#include <command.h> +#include <console.h> +#include <bootstage.h>
+#include "tftp_client.h" +#include "tftp_server.h" +#include <tftp_example.h>
+#include <string.h>
+#include <net/ulwip.h>
+static ulong daddr; +static ulong size;
+static void *tftp_open(const char *fname, const char *mode, u8_t
is_write)
+{
- return NULL;
+}
+static void tftp_close(void *handle) +{
- log_info("\ndone\n");
- log_info("Bytes transferred = %ld (0x%lx hex)\n", size, size);
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
- if (env_set_hex("filesize", size)) {
log_err("filesize not updated\n");
ulwip_exit(-1);
return;
- }
- 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);
daddr += q->len;
size += q->len;
log_info("#");
- }
- return 0;
+}
+static void tftp_error(void *handle, int err, const char *msg, int
size)
+{
- char message[100];
- memset(message, 0, sizeof(message));
- memcpy(message, msg, LWIP_MIN(sizeof(message) - 1, (size_t)size));
- log_info("TFTP error: %d (%s)", err, message);
+}
+static const struct tftp_context tftp = {
- tftp_open,
- tftp_close,
- tftp_read,
- tftp_write,
- tftp_error
+};
+int ulwip_tftp(ulong addr, char *fname) +{
- void *f = (void *)0x1; /* unused fake file handle*/
I haven't dug into lwip details yet, but I am not sure this is safe to
use.
Simon, since you maintain the lwip part can you elaborate a bit more?
From the lwIP design, using an invalid pointer here is ok: that pointer is only used as a client handle which is never dereferenced internally. The only requirement is that it is not NULL, as that is the validity check for the tftp client to know the handle is valid (or e.g. open failed etc.).
So while we can leave 0x1 here, using a static uint8_t would probably be better, at the expense of using a byte for nothing.
Regards, Simon
U-Boot does not like statics due to the fact that it can relocate itself to another address.
BR, Maxim.
- 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) {
log_err("error: serverip variable has to be set\n");
return CMD_RET_FAILURE;
- }
- ret = ipaddr_aton(server_ip, &srv);
- if (!ret) {
log_err("error: ipaddr_aton\n");
return CMD_RET_FAILURE;
- }
- log_info("TFTP from server %s; our IP address is %s\n",
server_ip, env_get("ipaddr"));
- log_info("Filename '%s'.\n", fname);
- log_info("Load address: 0x%lx\n", daddr);
- log_info("Loading:");
- bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
- err = tftp_init_client(&tftp);
- if (!(err == ERR_OK || err == ERR_USE))
log_err("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) {
log_err("tftp_get err=%d\n", err);
return CMD_RET_FAILURE;
- }
- if (env_set_hex("fileaddr", addr)) {
log_err("fileaddr not updated\n");
return CMD_RET_FAILURE;
- }
- return CMD_RET_SUCCESS;
+}
2.30.2
Thanks /Ilias

U-Boot recently got support for an alternative network stack using LWIP. Replace wget command with the LWIP variant while keeping the output and error messages identical.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 15 +++++ net/lwip/Makefile | 1 + net/lwip/apps/http/Makefile | 6 ++ net/lwip/apps/http/lwip-wget.c | 106 +++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 net/lwip/apps/http/Makefile create mode 100644 net/lwip/apps/http/lwip-wget.c
diff --git a/include/net/lwip.h b/include/net/lwip.h index c9e2982a78..85f08343fd 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -28,6 +28,7 @@ int ulwip_dns(char *name, char *varname); * Returns: 0 if success * Other value < 0, if error */ +int ulwip_dhcp(void);
/** * ulwip_tftp() - load file with tftp @@ -41,3 +42,17 @@ int ulwip_dns(char *name, char *varname); * Returns: 0 if success, !0 if error */ int ulwip_tftp(ulong addr, const char *filename); + +/** + * ulwip_wget() - creates the HTTP request to download file + * + * This function creates the HTTP request to download file from url to the address + * specified in parameters. After this function you need to invoke the polling + * loop to process network communication. + * + * + * @addr: start address to download result + * @url: url in format http://host/url + * Returns: 0 for success, !0 if error + */ +int ulwip_wget(ulong addr, char *url); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index b348e5ca31..61042862e1 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -66,3 +66,4 @@ obj-$(CONFIG_NET) += port/sys-arch.o obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o obj-y += apps/tftp/ +obj-y += apps/http/ diff --git a/net/lwip/apps/http/Makefile b/net/lwip/apps/http/Makefile new file mode 100644 index 0000000000..ac0b3ede0d --- /dev/null +++ b/net/lwip/apps/http/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include/lwip/apps + +obj-$(CONFIG_CMD_WGET) += ../../lwip-external/src/apps/http/http_client.o +obj-$(CONFIG_CMD_WGET) += lwip-wget.o diff --git a/net/lwip/apps/http/lwip-wget.c b/net/lwip/apps/http/lwip-wget.c new file mode 100644 index 0000000000..5c432056b1 --- /dev/null +++ b/net/lwip/apps/http/lwip-wget.c @@ -0,0 +1,106 @@ +// 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 <vsprintf.h> + +#include "http_client.h" +#include <net/ulwip.h> + +static ulong daddr; +static httpc_connection_t settings; + +#define SERVER_NAME_SIZE 200 +#define HTTP_PORT_DEFAULT 80 + +static err_t httpc_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *pbuf, + err_t unused_err) +{ + struct pbuf *buf; + + if (!pbuf) + return ERR_BUF; + + for (buf = pbuf; buf != NULL; buf = buf->next) { + memcpy((void *)daddr, buf->payload, buf->len); + log_debug("downloaded chunk size %d, to addr 0x%lx\n", + buf->len, daddr); + daddr += buf->len; + } + + altcp_recved(pcb, pbuf->tot_len); + pbuf_free(pbuf); + 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) { + log_info("\n%d bytes successfully downloaded.\n", rx_content_len); + env_set_hex("filesize", rx_content_len); + ulwip_exit(0); + } else { + log_err("\nhttp eroror: %d\n", httpc_result); + ulwip_exit(-1); + } +} + +/* http://hostname:port/url */ +static int parse_url(char *url, char *host, u16 *port) +{ + char *p, *pp; + + p = strstr(url, "http://"); + if (!p) + return -1; + + p += strlen("http://"); + + /* parse hostname */ + pp = strchr(p, '/'); + if (!pp) { + return -2; + } + + if (pp - p >= SERVER_NAME_SIZE) + return -3; + + memcpy(host, p, pp - p); + host[pp - p + 1] = '\0'; + *port = HTTP_PORT_DEFAULT; + + return 0; +} + +int ulwip_wget(ulong addr, char *url) +{ + err_t err; + u16 port; + char server_name[SERVER_NAME_SIZE]; + httpc_state_t *connection; + + daddr = addr; + + err = parse_url(url, server_name, &port); + if (err) + return -ENOENT; + + log_info("downloading %s to addr 0x%lx\n", url, addr); + memset(&settings, 0, sizeof(settings)); + settings.result_fn = httpc_result; + err = httpc_get_file_dns(server_name, port, url, &settings, + httpc_recv, NULL, &connection); + if (err != ERR_OK) + return -EPERM; + + if (env_set_hex("fileaddr", addr)) + return -EACCES; + + return 0; +}

4 files changed, 128 insertions(+) create mode 100644 net/lwip/apps/http/Makefile create mode 100644 net/lwip/apps/http/lwip-wget.c
diff --git a/include/net/lwip.h b/include/net/lwip.h index c9e2982a78..85f08343fd 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -28,6 +28,7 @@ int ulwip_dns(char *name, char *varname);
- Returns: 0 if success
Other value < 0, if error
*/ +int ulwip_dhcp(void);
This seems unrelated to wget changes
[...]
+// 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 <vsprintf.h>
+#include "http_client.h" +#include <net/ulwip.h>
+static ulong daddr; +static httpc_connection_t settings;
+#define SERVER_NAME_SIZE 200 +#define HTTP_PORT_DEFAULT 80
+static err_t httpc_recv(void *arg, struct altcp_pcb *pcb, struct pbuf *pbuf,
err_t unused_err)
+{
- struct pbuf *buf;
- if (!pbuf)
return ERR_BUF;
- for (buf = pbuf; buf != NULL; buf = buf->next) {
memcpy((void *)daddr, buf->payload, buf->len);
log_debug("downloaded chunk size %d, to addr 0x%lx\n",
buf->len, daddr);
daddr += buf->len;
- }
- altcp_recved(pcb, pbuf->tot_len);
- pbuf_free(pbuf);
- 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) {
log_info("\n%d bytes successfully downloaded.\n", rx_content_len);
env_set_hex("filesize", rx_content_len);
ulwip_exit(0);
- } else {
log_err("\nhttp eroror: %d\n", httpc_result);
ulwip_exit(-1);
- }
+}
+/* http://hostname:port/url */
The format doesn't expect a port (for now we can change that once we add https)
+static int parse_url(char *url, char *host, u16 *port) +{
- char *p, *pp;
- p = strstr(url, "http://");
- if (!p)
return -1;
- p += strlen("http://");
- /* parse hostname */
- pp = strchr(p, '/');
- if (!pp) {
return -2;
-1, -2 -3 etc should be mapped to proper ERRNOs
- }
- if (pp - p >= SERVER_NAME_SIZE)
Can you change this to p + SERVER_NAME_SIZE >= pp ?
return -3;
- memcpy(host, p, pp - p);
- host[pp - p + 1] = '\0';
- *port = HTTP_PORT_DEFAULT;
- return 0;
+}
+int ulwip_wget(ulong addr, char *url) +{
- err_t err;
- u16 port;
- char server_name[SERVER_NAME_SIZE];
- httpc_state_t *connection;
- daddr = addr;
- err = parse_url(url, server_name, &port);
- if (err)
return -ENOENT;
- log_info("downloading %s to addr 0x%lx\n", url, addr);
- memset(&settings, 0, sizeof(settings));
- settings.result_fn = httpc_result;
- err = httpc_get_file_dns(server_name, port, url, &settings,
httpc_recv, NULL, &connection);
- if (err != ERR_OK)
return -EPERM;
- if (env_set_hex("fileaddr", addr))
return -EACCES;
- return 0;
+}
2.30.2
Thanks /Ilias

U-Boot recently got support for an alternative network stack using LWIP. Replace ping command with the LWIP variant while keeping the output and error messages identical. ping uses lwIP contrib/apps/ping/ping.c code. Custom timeout is used to get an error message on not modified example. lwIP timeouts are not yet implemented in U-Boot (#define LWIP_TIMERS 1) so that for now ping can not rechange itself for continuous pings and stops after the first request (the same behavior as the original ping.)
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 15 +++++++++++++ net/lwip/Makefile | 1 + net/lwip/apps/ping/Makefile | 12 ++++++++++ net/lwip/apps/ping/lwip_ping.c | 40 ++++++++++++++++++++++++++++++++++ net/lwip/apps/ping/lwip_ping.h | 15 +++++++++++++ net/lwip/apps/ping/ping.h | 19 ++++++++++++++++ 6 files changed, 102 insertions(+) create mode 100644 net/lwip/apps/ping/Makefile create mode 100644 net/lwip/apps/ping/lwip_ping.c create mode 100644 net/lwip/apps/ping/lwip_ping.h create mode 100644 net/lwip/apps/ping/ping.h
diff --git a/include/net/lwip.h b/include/net/lwip.h index 85f08343fd..1e92f9871c 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -2,6 +2,8 @@
int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]);
/** * ulwip_dns() - creates the DNS request to resolve a domain host name @@ -56,3 +58,16 @@ int ulwip_tftp(ulong addr, const char *filename); * Returns: 0 for success, !0 if error */ int ulwip_wget(ulong addr, char *url); + +/** + * ulwip_ping - create the ping request + * + * This function creates the ping for address provided in parameters. + * After this function you need to invoke the polling + * loop to process network communication. + * + * + * @ping_addr: IP address to ping + * Returns: 0 for success, !0 if error +*/ +int ulwip_ping(char *ping_addr); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 61042862e1..5839d125c2 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -67,3 +67,4 @@ obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o obj-y += apps/tftp/ obj-y += apps/http/ +obj-y += apps/ping/ diff --git a/net/lwip/apps/ping/Makefile b/net/lwip/apps/ping/Makefile new file mode 100644 index 0000000000..e567c0dc3e --- /dev/null +++ b/net/lwip/apps/ping/Makefile @@ -0,0 +1,12 @@ +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip +ccflags-y += -I$(obj) + +# ping.c includes "ping.h", copy it to local directory, to override ping.h +.PHONY: $(obj)/ping.c +$(obj)/ping.o: $(obj)/ping.c +$(obj)/ping.c: + cp $(srctree)/net/lwip/lwip-external/contrib/apps/ping/ping.c $(obj)/ping.c + +obj-y += ping.o +obj-y += lwip_ping.o diff --git a/net/lwip/apps/ping/lwip_ping.c b/net/lwip/apps/ping/lwip_ping.c new file mode 100644 index 0000000000..231ea6473a --- /dev/null +++ b/net/lwip/apps/ping/lwip_ping.c @@ -0,0 +1,40 @@ +// 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 "lwip/timeouts.h" +#include <linux/errno.h> +#include "ping.h" +#include "lwip_ping.h" + +#define PING_WAIT_MS 1000 + +static ip_addr_t ip_target; + +static void ping_tmo(void *arg) +{ + char *ping_addr = (char *)arg; + + log_err("ping failed; host %s is not alive\n", ping_addr); + ulwip_exit(1); +} + +int ulwip_ping(char *ping_addr) +{ + int err; + + err = ipaddr_aton(ping_addr, &ip_target); + if (!err) + return -ENOENT; + + sys_timeout(PING_WAIT_MS, ping_tmo, ping_addr); + + ping_init(&ip_target); + ping_send_now(); + + return 0; +} diff --git a/net/lwip/apps/ping/lwip_ping.h b/net/lwip/apps/ping/lwip_ping.h new file mode 100644 index 0000000000..0374f07d9e --- /dev/null +++ b/net/lwip/apps/ping/lwip_ping.h @@ -0,0 +1,15 @@ +/* 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> + +void ping_raw_init(void); +void ping_send_now(void); + +#endif /* LWIP_PING_H */ diff --git a/net/lwip/apps/ping/ping.h b/net/lwip/apps/ping/ping.h new file mode 100644 index 0000000000..006a18c658 --- /dev/null +++ b/net/lwip/apps/ping/ping.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <net/ulwip.h> +#include "lwip/ip_addr.h" + +#define LWIP_DEBUG 1 /* ping_time is under ifdef*/ +#define PING_RESULT(cond) { \ + if (cond == 1) { \ + printf("host %s a alive\n", ipaddr_ntoa(addr)); \ + printf(" %"U32_F" ms\n", (sys_now() - ping_time)); \ + ulwip_exit(0); \ + } else { \ + printf("ping failed; host %s in not alive\n",\ + ipaddr_ntoa(addr)); \ + ulwip_exit(-1); \ + } \ + } while (0); + +void ping_init(const ip_addr_t *ping_addr);

On Fri, Sep 08, 2023 at 07:53:12PM +0600, Maxim Uvarov wrote:
U-Boot recently got support for an alternative network stack using LWIP. Replace ping command with the LWIP variant while keeping the output and error messages identical. ping uses lwIP contrib/apps/ping/ping.c code. Custom timeout is used to get an error message on not modified example. lwIP timeouts are not yet implemented in U-Boot (#define LWIP_TIMERS 1) so that for now ping can not rechange itself for continuous pings and stops after the first request (the same behavior as the original ping.)
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
include/net/lwip.h | 15 +++++++++++++ net/lwip/Makefile | 1 + net/lwip/apps/ping/Makefile | 12 ++++++++++ net/lwip/apps/ping/lwip_ping.c | 40 ++++++++++++++++++++++++++++++++++ net/lwip/apps/ping/lwip_ping.h | 15 +++++++++++++ net/lwip/apps/ping/ping.h | 19 ++++++++++++++++ 6 files changed, 102 insertions(+) create mode 100644 net/lwip/apps/ping/Makefile create mode 100644 net/lwip/apps/ping/lwip_ping.c create mode 100644 net/lwip/apps/ping/lwip_ping.h create mode 100644 net/lwip/apps/ping/ping.h
diff --git a/include/net/lwip.h b/include/net/lwip.h index 85f08343fd..1e92f9871c 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -2,6 +2,8 @@
int do_lwip_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]);
/**
- ulwip_dns() - creates the DNS request to resolve a domain host name
@@ -56,3 +58,16 @@ int ulwip_tftp(ulong addr, const char *filename);
- Returns: 0 for success, !0 if error
*/ int ulwip_wget(ulong addr, char *url);
+/**
- ulwip_ping - create the ping request
- This function creates the ping for address provided in parameters.
- After this function you need to invoke the polling
- loop to process network communication.
- @ping_addr: IP address to ping
- Returns: 0 for success, !0 if error
+*/ +int ulwip_ping(char *ping_addr); diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 61042862e1..5839d125c2 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -67,3 +67,4 @@ obj-y += apps/dhcp/lwip-dhcp.o obj-y += apps/dns/lwip-dns.o obj-y += apps/tftp/ obj-y += apps/http/ +obj-y += apps/ping/ diff --git a/net/lwip/apps/ping/Makefile b/net/lwip/apps/ping/Makefile new file mode 100644 index 0000000000..e567c0dc3e --- /dev/null +++ b/net/lwip/apps/ping/Makefile @@ -0,0 +1,12 @@ +ccflags-y += -I$(srctree)/net/lwip/port/include +ccflags-y += -I$(srctree)/net/lwip/lwip-external/src/include -I$(srctree)/net/lwip +ccflags-y += -I$(obj)
+# ping.c includes "ping.h", copy it to local directory, to override ping.h +.PHONY: $(obj)/ping.c +$(obj)/ping.o: $(obj)/ping.c +$(obj)/ping.c:
- cp $(srctree)/net/lwip/lwip-external/contrib/apps/ping/ping.c $(obj)/ping.c
+obj-y += ping.o +obj-y += lwip_ping.o diff --git a/net/lwip/apps/ping/lwip_ping.c b/net/lwip/apps/ping/lwip_ping.c new file mode 100644 index 0000000000..231ea6473a --- /dev/null +++ b/net/lwip/apps/ping/lwip_ping.c @@ -0,0 +1,40 @@ +// 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 "lwip/timeouts.h" +#include <linux/errno.h> +#include "ping.h" +#include "lwip_ping.h"
+#define PING_WAIT_MS 1000
+static ip_addr_t ip_target;
+static void ping_tmo(void *arg) +{
- char *ping_addr = (char *)arg;
- log_err("ping failed; host %s is not alive\n", ping_addr);
just cast (char *)arg directly on log_err
- ulwip_exit(1);
+}
[...]
- return 0;
+} diff --git a/net/lwip/apps/ping/lwip_ping.h b/net/lwip/apps/ping/lwip_ping.h new file mode 100644 index 0000000000..0374f07d9e --- /dev/null +++ b/net/lwip/apps/ping/lwip_ping.h @@ -0,0 +1,15 @@ +/* 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>
+void ping_raw_init(void); +void ping_send_now(void);
+#endif /* LWIP_PING_H */ diff --git a/net/lwip/apps/ping/ping.h b/net/lwip/apps/ping/ping.h new file mode 100644 index 0000000000..006a18c658 --- /dev/null +++ b/net/lwip/apps/ping/ping.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */
+#include <net/ulwip.h> +#include "lwip/ip_addr.h"
+#define LWIP_DEBUG 1 /* ping_time is under ifdef*/ +#define PING_RESULT(cond) { \
- if (cond == 1) { \
printf("host %s a alive\n", ipaddr_ntoa(addr)); \
printf(" %"U32_F" ms\n", (sys_now() - ping_time)); \
ulwip_exit(0); \
- } else { \
printf("ping failed; host %s in not alive\n",\
ipaddr_ntoa(addr)); \
ulwip_exit(-1); \
- } \
} while (0);
+void ping_init(const ip_addr_t *ping_addr);
2.30.2
Thanks /Ilias

lwip configuration can be tuned with header file.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- net/lwip/lwipopts.h | 178 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 net/lwip/lwipopts.h
diff --git a/net/lwip/lwipopts.h b/net/lwip/lwipopts.h new file mode 100644 index 0000000000..731da30baa --- /dev/null +++ b/net/lwip/lwipopts.h @@ -0,0 +1,178 @@ +/* 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_ON +#define NETIF_DEBUG LWIP_DBG_ON +#define PBUF_DEBUG LWIP_DBG_OFF +#define API_LIB_DEBUG LWIP_DBG_ON +#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_ON +#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_ON +#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_ON +#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 1 + +#define LWIP_IPV6 0 + +#define MEM_ALIGNMENT 1 +#define MEM_SIZE 1600 + +#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 ARP_TABLE_SIZE 10 +#define ARP_QUEUEING 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 + +#define LWIP_DHCP 1 +#define LWIP_DHCP_BOOTP_FILE 1 +#define LWIP_DHCP_DOES_ACD_CHECK 0 + +#define LWIP_AUTOIP 0 + +#define LWIP_SNMP 0 + +#define LWIP_IGMP 0 + +#define LWIP_DNS 1 + +#define LWIP_UDP 1 + +#define LWIP_TCP 1 + +#define LWIP_LISTEN_BACKLOG 0 + +#define PBUF_LINK_HLEN 14 +#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS + 40 + PBUF_LINK_HLEN) + +#define LWIP_HAVE_LOOPIF 0 + +#define LWIP_NETCONN 0 +#define LWIP_DISABLE_MEMP_SANITY_CHECKS 1 + +#define LWIP_SOCKET 0 +#define SO_REUSE 0 + +#define LWIP_STATS 0 + +#define PPP_SUPPORT 0 + +#define LWIP_TCPIP_CORE_LOCKING 0 + +#define LWIP_NETIF_LOOPBACK 1 + +/* use malloc instead of pool */ +#define MEMP_MEM_MALLOC 1 +#define MEMP_MEM_INIT 1 +#define MEM_LIBC_MALLOC 1 + +#endif /* LWIP_LWIPOPTS_H */

Implement port of lwIP stack to the U-Boot. lwIP is well known full IP stack which provides wide functionality, various examples, API closer to linux userland. Rich debug printing and possibility to run lwIP apps under linux make it easier to develop and debug apps. U-Boot implementation keeps the original file structure widely used for lwIP ports. (i.e. port/if.c port/sys-arch.c). That should allow us to easy port apps to or from U-Boot. Multiply ethernet devices are supported and "ethact" env variable chooses the active device. Having a rich IP stack inside U-Boot will allow us to have such applications as http or https clients.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- net/eth-uclass.c | 8 + net/lwip/port/if.c | 332 ++++++++++++++++++++++++++ net/lwip/port/include/arch/cc.h | 38 +++ net/lwip/port/include/arch/sys_arch.h | 10 + net/lwip/port/include/limits.h | 0 net/lwip/port/sys-arch.c | 13 + 6 files changed, 401 insertions(+) create mode 100644 net/lwip/port/if.c create mode 100644 net/lwip/port/include/arch/cc.h create mode 100644 net/lwip/port/include/arch/sys_arch.h create mode 100644 net/lwip/port/include/limits.h create mode 100644 net/lwip/port/sys-arch.c
diff --git a/net/eth-uclass.c b/net/eth-uclass.c index c393600fab..6625f6d8a5 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -32,6 +32,7 @@ DECLARE_GLOBAL_DATA_PTR; struct eth_device_priv { enum eth_state_t state; bool running; + ulwip ulwip; };
/** @@ -347,6 +348,13 @@ int eth_init(void) return ret; }
+struct ulwip *eth_lwip_priv(struct udevice *current) +{ + struct eth_device_priv *priv = dev_get_uclass_priv(current); + + return &priv->ulwip; +} + void eth_halt(void) { struct udevice *current; diff --git a/net/lwip/port/if.c b/net/lwip/port/if.c new file mode 100644 index 0000000000..0025b1273f --- /dev/null +++ b/net/lwip/port/if.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include <common.h> +#include <command.h> +#include <net/eth.h> +#include <dm/device.h> +#include <dm/uclass-id.h> +#include <dm/uclass.h> +#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/ethip6.h" +#include "lwip/timeouts.h" + +#include "lwip/ip.h" + +/* + * MAC_ADDR_STRLEN: length of mac address string + */ +#define MAC_ADDR_STRLEN 17 + +int ulwip_enabled(void) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return 0; + + ulwip = eth_lwip_priv(udev); + return ulwip->init_done; +} + +int ulwip_in_loop(void) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return 0; + + sys_check_timeouts(); + + ulwip = eth_lwip_priv(udev); + return ulwip->loop; +} + +void ulwip_loop_set(int loop) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return; + + ulwip = eth_lwip_priv(udev); + ulwip->loop = loop; +} + +void ulwip_exit(int err) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return; + + ulwip = eth_lwip_priv(udev); + ulwip->loop = 0; + ulwip->err = err; +} + +int ulwip_app_get_err(void) +{ + struct udevice *udev; + struct ulwip *ulwip; + + udev = eth_get_dev(); + if (!udev) + return 0; + + ulwip = eth_lwip_priv(udev); + return ulwip->err; +} + +typedef struct { +} ulwip_if_t; + +static struct pbuf *low_level_input(void) +{ + struct pbuf *p, *q; + u16_t len = net_rx_packet_len; + uchar *data = net_rx_packet; + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + if (!p) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + return NULL; + } + + for (q = p; q != NULL; q = q->next) { + memcpy(q->payload, data, q->len); + data += q->len; + } + + LINK_STATS_INC(link.recv); + + return p; +} + +void ulwip_poll(void) +{ + struct pbuf *p; + int err; + struct netif *netif; + int eth_idx; + + eth_idx = eth_get_dev_index(); + if (eth_idx < 0) { + log_err("no eth idx\n"); + return; + } + + netif = netif_get_by_index(eth_idx + 1); + if (!netif) { + log_err("!netif\n"); + return; + } + + p = low_level_input(); + if (!p) { + log_err("no mem\n"); + return; + } + + /* ethernet_input always returns ERR_OK */ + err = ethernet_input(p, netif); + if (err) + log_err("ip4_input err %d\n", err); +} + +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(); + + /* 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; + + /* switch dev to active state */ + eth_init_state_only(); + + err = eth_send(p->payload, p->len); + if (err) { + log_err("eth_send error %d\n", err); + return ERR_ABRT; + } + return ERR_OK; +} + +err_t ulwip_if_init(struct netif *netif) +{ + ulwip_if_t *uif; + struct ulwip *ulwip; + + uif = malloc(sizeof(ulwip_if_t)); + if (!uif) { + log_err("uif: out of memory\n"); + return ERR_MEM; + } + netif->state = uif; + +#if defined(CONFIG_LWIP_LIB_DEBUG) + log_info(" 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]); + log_info(" NAME: %s\n", netif->name); +#endif +#if LWIP_IPV4 + netif->output = etharp_output; +#endif +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif + + netif->linkoutput = low_level_output; + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + + ulwip = eth_lwip_priv(eth_get_dev()); + ulwip->init_done = 1; + + return ERR_OK; +} + +int ulwip_init(void) +{ + ip4_addr_t ipaddr, netmask, gw; + struct netif *unetif; + struct ulwip *ulwip; + struct udevice *udev; + int ret; + unsigned char env_enetaddr[ARP_HLEN]; + const struct udevice *dev; + struct uclass *uc; + + ret = eth_init(); + if (ret) { + log_err("eth_init error %d\n", ret); + return ERR_IF; + } + + udev = eth_get_dev(); + if (!udev) { + log_err("no active eth device\n"); + return ERR_IF; + } + + eth_set_current(); + + ulwip = eth_lwip_priv(udev); + if (ulwip->init_done) { + log_info("init already done for %s\n", udev->name); + return CMD_RET_SUCCESS; + } + + uclass_id_foreach_dev(UCLASS_ETH, dev, uc) { + char ipstr[IP4ADDR_STRLEN_MAX]; + char maskstr[IP4ADDR_STRLEN_MAX]; + char gwstr[IP4ADDR_STRLEN_MAX]; + char hwstr[MAC_ADDR_STRLEN]; + + eth_env_get_enetaddr_by_index("eth", dev_seq(dev), env_enetaddr); + log_info("eth%d: %s %pM %s\n", dev_seq(dev), dev->name, env_enetaddr, + udev == dev ? "active" : ""); + + unetif = malloc(sizeof(struct netif)); + if (!unetif) + return ERR_MEM; + memset(unetif, 0, sizeof(struct netif)); + + ip4_addr_set_zero(&gw); + ip4_addr_set_zero(&ipaddr); + ip4_addr_set_zero(&netmask); + + if (dev_seq(dev) == 0) { + snprintf(ipstr, IP4ADDR_STRLEN_MAX, "ipaddr"); + snprintf(maskstr, IP4ADDR_STRLEN_MAX, "netmask"); + snprintf(gwstr, IP4ADDR_STRLEN_MAX, "gw"); + } else { + snprintf(ipstr, IP4ADDR_STRLEN_MAX, "ipaddr%d", dev_seq(dev)); + snprintf(maskstr, IP4ADDR_STRLEN_MAX, "netmask%d", dev_seq(dev)); + snprintf(gwstr, IP4ADDR_STRLEN_MAX, "gw%d", dev_seq(dev)); + } + snprintf(hwstr, MAC_ADDR_STRLEN, "%pM", env_enetaddr); + snprintf(unetif->name, 2, "%d", dev_seq(dev)); + + string_to_enetaddr(hwstr, unetif->hwaddr); + unetif->hwaddr_len = ETHARP_HWADDR_LEN; + + ipaddr_aton(env_get(ipstr), &ipaddr); + ipaddr_aton(env_get(maskstr), &netmask); + + if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) { + log_info("Starting lwIP\n "); + log_info(" netdev: %s\n", dev->name); + log_info(" IP: %s\n", ip4addr_ntoa(&ipaddr)); + log_info(" GW: %s\n", ip4addr_ntoa(&gw)); + log_info(" mask: %s\n", ip4addr_ntoa(&netmask)); + } + +#if LWIP_IPV6 +#define MAC_FROM_48_BIT 1 + netif_create_ip6_linklocal_address(unetif, MAC_FROM_48_BIT); + log_info(" IPv6: %s\n", ip6addr_ntoa(netif_ip6_addr(unetif, 0))); +#endif /* LWIP_IPV6 */ + + if (!netif_add(unetif, &ipaddr, &netmask, &gw, + unetif, ulwip_if_init, ethernetif_input)) { + log_err("err: netif_add failed!\n"); + free(unetif); + return ERR_IF; + } + + netif_set_up(unetif); + netif_set_link_up(unetif); + } + + if (IS_ENABLED(CONFIG_LWIP_LIB_DEBUG)) { + log_info("Initialized LWIP stack\n"); + } + return CMD_RET_SUCCESS; +} + +/* placeholder, not used now */ +void ulwip_destroy(void) +{ +} diff --git a/net/lwip/port/include/arch/cc.h b/net/lwip/port/include/arch/cc.h new file mode 100644 index 0000000000..23fd51c308 --- /dev/null +++ b/net/lwip/port/include/arch/cc.h @@ -0,0 +1,38 @@ +/* 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> +#include <vsprintf.h> +#include <rand.h> + +#define LWIP_ERRNO_INCLUDE <errno.h> + +#define LWIP_ERRNO_STDINCLUDE 1 +#define LWIP_NO_UNISTD_H 1 +#define LWIP_TIMEVAL_PRIVATE 1 + +#define LWIP_RAND() ((u32_t)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) + +#define atoi(str) (int)dectoul(str, NULL) + +#define LWIP_ERR_T int + +#endif /* LWIP_ARCH_CC_H */ diff --git a/net/lwip/port/include/arch/sys_arch.h b/net/lwip/port/include/arch/sys_arch.h new file mode 100644 index 0000000000..87a3fb66d1 --- /dev/null +++ b/net/lwip/port/include/arch/sys_arch.h @@ -0,0 +1,10 @@ +/* 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 + +#endif /* LWIP_ARCH_SYS_ARCH_H */ diff --git a/net/lwip/port/include/limits.h b/net/lwip/port/include/limits.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/net/lwip/port/sys-arch.c b/net/lwip/port/sys-arch.c new file mode 100644 index 0000000000..68476d16e8 --- /dev/null +++ b/net/lwip/port/sys-arch.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * (C) Copyright 2023 Linaro Ltd. maxim.uvarov@linaro.org + */ + +#include <common.h> +#include "lwip/opt.h" + +u32_t sys_now(void) +{ + return get_timer(0); +}

ignore lwIP library code and reused files from the lwIP.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- net/lwip/.gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 net/lwip/.gitignore
diff --git a/net/lwip/.gitignore b/net/lwip/.gitignore new file mode 100644 index 0000000000..7b5dacce90 --- /dev/null +++ b/net/lwip/.gitignore @@ -0,0 +1,8 @@ +lwip-external +apps/ping/ping.c +apps/http/http_client.c +apps/http/http_client.h +apps/tftp/tftp.c +apps/tftp/tftp_client.h +apps/tftp/tftp_common.h +apps/tftp/tftp_example.h

Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- cmd/Makefile | 1 + cmd/net-lwip.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 cmd/net-lwip.c
diff --git a/cmd/Makefile b/cmd/Makefile index 9bebf321c3..6ab6b16aab 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -128,6 +128,7 @@ endif obj-$(CONFIG_CMD_MUX) += mux.o obj-$(CONFIG_CMD_NAND) += nand.o obj-$(CONFIG_CMD_NET) += net.o +obj-$(CONFIG_CMD_NET) += net-lwip.o obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o obj-$(CONFIG_CMD_ONENAND) += onenand.o obj-$(CONFIG_CMD_OSD) += osd.o diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c new file mode 100644 index 0000000000..82e0fe392d --- /dev/null +++ b/cmd/net-lwip.c @@ -0,0 +1,286 @@ +// 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 "net/lwip.h" +#include "net/ulwip.h" + +static int do_lwip_init(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + if (!ulwip_init()) + return CMD_RET_SUCCESS; + return CMD_RET_FAILURE; +} + +static void ulwip_timeout_handler(void) +{ + eth_halt(); + net_set_state(NETLOOP_FAIL); /* we did not get the reply */ + ulwip_loop_set(0); +} + +int ulwip_loop(void) +{ + int ret = CMD_RET_FAILURE; + + ulwip_loop_set(1); + if (!net_loop(LWIP)) + ret = CMD_RET_SUCCESS; + ulwip_loop_set(0); + return ret; +} + +#if defined(CONFIG_CMD_PING) +int do_lwip_ping(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + log_info("Using %s device\n", eth_get_name()); + log_info("pinging addr: %s\n", argv[1]); + + if (ulwip_ping(argv[1])) { + printf("ping init fail\n"); + return CMD_RET_FAILURE; + } + + return ulwip_loop(); +} +#endif /* CONFIG_CMD_PING */ + +#if defined(CONFIG_CMD_WGET) +int do_lwip_wget(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + char *url; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + url = argv[1]; + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = ulwip_wget(image_load_addr, url); + if (ret) { + log_err("lwip_wget err %d\n", ret); + return CMD_RET_FAILURE; + } + + + return ulwip_loop(); +} +#endif + +#if defined(CONFIG_CMD_TFTPBOOT) +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; + } + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = ulwip_tftp(image_load_addr, filename); + if (ret) + return ret; + + return ulwip_loop(); +} +#endif /* CONFIG_CMD_TFTPBOOT */ + +#if defined(CONFIG_CMD_DHCP) +int do_lwip_dhcp(void) +{ + int ret; + char *filename; + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = ulwip_dhcp(); + + net_set_timeout_handler(2000UL, ulwip_timeout_handler); + + ulwip_loop(); + if (IS_ENABLED(CONFIG_CMD_TFTPBOOT)) { + filename = env_get("bootfile"); + if (!filename) { + log_notice("no bootfile\n"); + return CMD_RET_SUCCESS; + } + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + net_set_timeout_handler(20000UL, ulwip_timeout_handler); + ulwip_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 */ + +#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; + + if (argc == 1) + return CMD_RET_USAGE; + + name = argv[1]; + + if (argc == 3) + varname = argv[2]; + else + varname = NULL; + + ret = ulwip_init(); + if (ret) { + log_err("ulwip_init err %d\n", ret); + return CMD_RET_FAILURE; + } + + ret = ulwip_dns(name, varname); + if (ret == 0) + return CMD_RET_SUCCESS; + if (ret != -EINPROGRESS) + 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(init, 1, 0, do_lwip_init, + "initialize lwip stack", ""), +#if defined(CONFIG_CMD_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 +#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, + 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", + "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" + );

Replace original commands: ping, tftp, dhcp and wget.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- boot/bootmeth_efi.c | 18 +++++++--- boot/bootmeth_pxe.c | 21 ++++++----- cmd/net.c | 86 +++++---------------------------------------- cmd/pxe.c | 19 +++++----- include/net.h | 8 +++-- include/net/ulwip.h | 64 +++++++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+), 103 deletions(-) create mode 100644 include/net/ulwip.h
diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index ae936c8daa..52399d627c 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -20,6 +20,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/lwip.h> +#include <net/ulwip.h> #include <pxe_utils.h> #include <linux/sizes.h>
@@ -319,9 +321,7 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
static int distro_efi_read_bootflow_net(struct bootflow *bflow) { - char file_addr[17], fname[256]; - char *tftp_argv[] = {"tftp", file_addr, fname, NULL}; - struct cmd_tbl cmdtp = {}; /* dummy */ + char fname[256]; const char *addr_str, *fdt_addr_str; int ret, arch, size; ulong addr, fdt_addr; @@ -368,7 +368,6 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!fdt_addr_str) return log_msg_ret("fdt", -EINVAL); fdt_addr = hextoul(fdt_addr_str, NULL); - sprintf(file_addr, "%lx", fdt_addr);
/* We only allow the first prefix with PXE */ ret = distro_efi_get_fdt_name(fname, sizeof(fname), 0); @@ -379,7 +378,16 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow) if (!bflow->fdt_fname) return log_msg_ret("fil", -ENOMEM);
- if (!do_tftpb(&cmdtp, 0, 3, tftp_argv)) { + ret = ulwip_init(); + if (ret) + return log_msg_ret("ulwip_init", ret); + + ret = ulwip_tftp(fdt_addr, fname); + if (ret) + return log_msg_ret("ulwip_tftp", ret); + + ret = ulwip_loop(); + if (!ret) { bflow->fdt_size = env_get_hex("filesize", 0); bflow->fdt_addr = fdt_addr; } else { diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 8d489a11aa..fc6aabaa18 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -21,6 +21,8 @@ #include <mapmem.h> #include <mmc.h> #include <net.h> +#include <net/ulwip.h> +#include <net/lwip.h> #include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path, @@ -116,18 +118,21 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep) { - char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; - struct pxe_context *ctx = dev_get_priv(dev); - char file_addr[17]; ulong size; int ret;
- sprintf(file_addr, "%lx", addr); - tftp_argv[1] = file_addr; - tftp_argv[2] = (void *)file_path; + ret = ulwip_init(); + if (ret) + return log_msg_ret("ulwip_init", ret); + + ret = ulwip_tftp(addr, file_path); + if (ret) + return log_msg_ret("ulwip_tftp", ret); + + ret = ulwip_loop(); + if (ret) + return log_msg_ret("ulwip_loop", ret);
- if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv)) - return -ENOENT; ret = pxe_get_file_size(&size); if (ret) return log_msg_ret("tftp", ret); diff --git a/cmd/net.c b/cmd/net.c index d407d8320a..dc5a114309 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -22,6 +22,7 @@ #include <net/udp.h> #include <net/sntp.h> #include <net/ncsi.h> +#include <net/lwip.h>
static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
@@ -40,19 +41,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", @@ -60,7 +51,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]" ); @@ -139,7 +130,7 @@ U_BOOT_CMD(dhcp6, 3, 1, do_dhcp6, 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( @@ -196,13 +187,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]" ); @@ -456,28 +445,8 @@ 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; -} - U_BOOT_CMD( - ping, 2, 1, do_ping, + ping, 2, 1, do_lwip_ping, "send ICMP ECHO_REQUEST to network host", "pingAddress" ); @@ -601,45 +570,8 @@ 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; -} - 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/cmd/pxe.c b/cmd/pxe.c index 677142520b..d44df428d2 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -8,6 +8,7 @@ #include <command.h> #include <fs.h> #include <net.h> +#include <net/lwip.h> #include <net6.h> #include <malloc.h>
@@ -29,21 +30,19 @@ const char *pxe_default_paths[] = { static int do_get_tftp(struct pxe_context *ctx, const char *file_path, char *file_addr, ulong *sizep) { - char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; + ulong addr; + char *end; int ret; - int num_args;
- tftp_argv[1] = file_addr; - tftp_argv[2] = (void *)file_path; + addr = hextoul(file_addr, &end); + if (ctx->use_ipv6) { - tftp_argv[3] = USE_IP6_CMD_PARAM; - num_args = 4; - } else { - num_args = 3; + /* @todo: check and fix me, here */ }
- if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv)) - return -ENOENT; + ret = ulwip_tftp(addr, file_path); + if (ret) + return log_msg_ret("tftp", ret);
ret = pxe_get_file_size(sizep); if (ret) diff --git a/include/net.h b/include/net.h index e254df7d7f..de7baeb121 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[]);
/** * dhcp_run() - Run DHCP on the current ethernet device @@ -514,7 +516,7 @@ extern int net_restart_wrap; /* Tried all network devices */ enum proto_t { BOOTP, RARP, ARP, TFTPGET, DHCP, DHCP6, PING, PING6, DNS, NFS, CDP, NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT_UDP, FASTBOOT_TCP, - WOL, UDP, NCSI, WGET, RS + WOL, UDP, NCSI, WGET, RS, LWIP };
extern char net_boot_file_name[1024];/* Boot File name */ diff --git a/include/net/ulwip.h b/include/net/ulwip.h new file mode 100644 index 0000000000..8eac7aa130 --- /dev/null +++ b/include/net/ulwip.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/** + * ulwip_init() - initialize lwIP network stack + * + * @return 0 if success, !0 if error + */ +int ulwip_init(void); + +/** + * ulwip_enabled() - check if lwIP network stack was initialized + * + * @return 1 lwip initialized, 0 if not yet initialized + */ +int ulwip_enabled(void); + +/** + * ulwip_in_loop() - lwIP controls packet net loop + * + * @return 1 lwIP owns packet loop, 0 lwip does not own packet loop + */ +int ulwip_in_loop(void); + +/** + * ulwip_loop_set() - make loop to be used by lwIP + * + * Function is used to make lwIP control network pool. + * + * @loop: 1. Rx packets go to lwIP 2. Rx packets go to the original stack. + */ +void ulwip_loop_set(int loop); + +/** + * ulwip_exit() - exit from lwIP with a return code + * + * Exit from lwIP application back to the U-Boot with specific error code. + * + * @err: Error code to return + */ +void ulwip_exit(int err); + +/** + * ulwip_poll() - polling function to feed lwIP with ethernet packet + * + * Function takes network packet and passes it to lwIP network stack + */ +void ulwip_poll(void); + +/** + * ulwip_app_get_err() - return error code from lwIP application + * + * @return error code + */ +int ulwip_app_get_err(void); + +/** + * ulwip_loop() - enter to packet polling loop + * + * When lwIP application did it's initialization stage, then it needs to enter + * to packet polling loop to grab rx packets. + * + * Returns: 0 if success, !0 if error + */ +int ulwip_loop(void);

current net.h has ethernet and protocol definitions. Protocol definitions overlap with lwIP protocol definitions and net.h can not be included from lwIP code. Splitting on logical blocks makes that work.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net.h | 189 +-------------------------------------------- include/net/arp.h | 7 ++ include/net/eth.h | 190 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 185 deletions(-) create mode 100644 include/net/arp.h create mode 100644 include/net/eth.h
diff --git a/include/net.h b/include/net.h index de7baeb121..780c51fab9 100644 --- a/include/net.h +++ b/include/net.h @@ -20,6 +20,7 @@ #include <time.h> #include <linux/if_ether.h> #include <rand.h> +#include <net/arp.h>
struct bd_info; struct cmd_tbl; @@ -30,25 +31,6 @@ struct udevice; #define DEBUG_NET_PKT 0 /* Packets on info on the network at large */ #define DEBUG_INT_STATE 0 /* Internal network state changes */
-/* - * The number of receive packet buffers, and the required packet buffer - * alignment in memory. - * - */ -#define PKTBUFSRX CONFIG_SYS_RX_ETH_BUFFER -#define PKTALIGN ARCH_DMA_MINALIGN - -/* Number of packets processed together */ -#define ETH_PACKETS_BATCH_RECV 32 - -/* ARP hardware address length */ -#define ARP_HLEN 6 -/* - * The size of a MAC address in string form, each digit requires two chars - * and five separator characters to form '00:00:00:00:00:00'. - */ -#define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1) - /* IPv4 addresses are always 32 bits in size */ struct in_addr { __be32 s_addr; @@ -112,150 +94,7 @@ typedef void rxhand_icmp_f(unsigned type, unsigned code, unsigned dport, */ typedef void thand_f(void);
-enum eth_state_t { - ETH_STATE_INIT, - ETH_STATE_PASSIVE, - ETH_STATE_ACTIVE -}; - -/** - * struct eth_pdata - Platform data for Ethernet MAC controllers - * - * @iobase: The base address of the hardware registers - * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env - * @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_... - * @max_speed: Maximum speed of Ethernet connection supported by MAC - * @priv_pdata: device specific plat - */ -struct eth_pdata { - phys_addr_t iobase; - unsigned char enetaddr[ARP_HLEN]; - int phy_interface; - int max_speed; - void *priv_pdata; -}; - -enum eth_recv_flags { - /* - * Check hardware device for new packets (otherwise only return those - * which are already in the memory buffer ready to process) - */ - ETH_RECV_CHECK_DEVICE = 1 << 0, -}; - -/** - * struct eth_ops - functions of Ethernet MAC controllers - * - * start: Prepare the hardware to send and receive packets - * send: Send the bytes passed in "packet" as a packet on the wire - * recv: Check if the hardware received a packet. If so, set the pointer to the - * packet buffer in the packetp parameter. If not, return an error or 0 to - * indicate that the hardware receive FIFO is empty. If 0 is returned, the - * network stack will not process the empty packet, but free_pkt() will be - * called if supplied - * free_pkt: Give the driver an opportunity to manage its packet buffer memory - * when the network stack is finished processing it. This will only be - * called when no error was returned from recv - optional - * stop: Stop the hardware from looking for packets - may be called even if - * state == PASSIVE - * mcast: Join or leave a multicast group (for TFTP) - optional - * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux - * on some platforms like ARM). This function expects the - * eth_pdata::enetaddr field to be populated. The method can - * return -ENOSYS to indicate that this is not implemented for - this hardware - optional. - * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a - * ROM on the board. This is how the driver should expose it - * to the network stack. This function should fill in the - * eth_pdata::enetaddr field - optional - * set_promisc: Enable or Disable promiscuous mode - * get_sset_count: Number of statistics counters - * get_string: Names of the statistic counters - * get_stats: The values of the statistic counters - */ -struct eth_ops { - int (*start)(struct udevice *dev); - int (*send)(struct udevice *dev, void *packet, int length); - int (*recv)(struct udevice *dev, int flags, uchar **packetp); - int (*free_pkt)(struct udevice *dev, uchar *packet, int length); - void (*stop)(struct udevice *dev); - int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); - int (*write_hwaddr)(struct udevice *dev); - int (*read_rom_hwaddr)(struct udevice *dev); - int (*set_promisc)(struct udevice *dev, bool enable); - int (*get_sset_count)(struct udevice *dev); - void (*get_strings)(struct udevice *dev, u8 *data); - void (*get_stats)(struct udevice *dev, u64 *data); -}; - -#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops) - -struct udevice *eth_get_dev(void); /* get the current device */ -/* - * The devname can be either an exact name given by the driver or device tree - * or it can be an alias of the form "eth%d" - */ -struct udevice *eth_get_dev_by_name(const char *devname); -unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ - -/* Used only when NetConsole is enabled */ -int eth_is_active(struct udevice *dev); /* Test device for active state */ -int eth_init_state_only(void); /* Set active state */ -void eth_halt_state_only(void); /* Set passive state */ - -int eth_initialize(void); /* Initialize network subsystem */ -void eth_try_another(int first_restart); /* Change the device */ -void eth_set_current(void); /* set nterface to ethcur var */ - -int eth_get_dev_index(void); /* get the device index */ - -/** - * eth_env_set_enetaddr_by_index() - set the MAC address environment variable - * - * This sets up an environment variable with the given MAC address (@enetaddr). - * The environment variable to be set is defined by <@base_name><@index>addr. - * If @index is 0 it is omitted. For common Ethernet this means ethaddr, - * eth1addr, etc. - * - * @base_name: Base name for variable, typically "eth" - * @index: Index of interface being updated (>=0) - * @enetaddr: Pointer to MAC address to put into the variable - * Return: 0 if OK, other value on error - */ -int eth_env_set_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); - - -/* - * Initialize USB ethernet device with CONFIG_DM_ETH - * Returns: - * 0 is success, non-zero is error status. - */ -int usb_ether_init(void); - -/* - * Get the hardware address for an ethernet interface . - * Args: - * base_name - base name for device (normally "eth") - * index - device index number (0 for first) - * enetaddr - returns 6 byte hardware address - * Returns: - * Return true if the address is valid. - */ -int eth_env_get_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); - -int eth_init(void); /* Initialize the device */ -int eth_send(void *packet, int length); /* Send a packet */ - -#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) -int eth_receive(void *packet, int length); /* Receive a packet*/ -extern void (*push_packet)(void *packet, int length); -#endif -int eth_rx(void); /* Check for received packets */ -void eth_halt(void); /* stop SCC */ -const char *eth_get_name(void); /* get name of current device */ -int eth_mcast_join(struct in_addr mcast_addr, int join); +#include <net/eth.h>
/**********************************************************************/ /* @@ -495,16 +334,6 @@ extern char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN]; /* Our root path */ /* Indicates whether the pxe path prefix / config file was specified in dhcp option */ extern char *pxelinux_configfile; /** END OF BOOTP EXTENTIONS **/ -extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet address */ -extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet address */ -extern struct in_addr net_ip; /* Our IP addr (0 = unknown) */ -extern struct in_addr net_server_ip; /* Server IP addr (0 = unknown) */ -extern uchar *net_tx_packet; /* THE transmit packet */ -extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ -extern uchar *net_rx_packet; /* Current receive packet */ -extern int net_rx_packet_len; /* Current rx packet length */ -extern const u8 net_bcast_ethaddr[ARP_HLEN]; /* Ethernet broadcast address */ -extern const u8 net_null_ethaddr[ARP_HLEN];
#define VLAN_NONE 4095 /* untagged */ #define VLAN_IDMASK 0x0fff /* mask of valid vlan id */ @@ -557,6 +386,8 @@ extern struct in_addr net_ntp_server; /* the ip address to NTP */ extern int net_ntp_time_offset; /* offset time from UTC */ #endif
+int eth_mcast_join(struct in_addr mcast_addr, int join); + /* Initialize the network adapter */ int net_init(void); int net_loop(enum proto_t); @@ -827,18 +658,6 @@ static inline void net_random_ethaddr(uchar *addr) addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ }
-/** - * string_to_enetaddr() - Parse a MAC address - * - * Convert a string MAC address - * - * Implemented in lib/net_utils.c (built unconditionally) - * - * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit - * hex value - * @enetaddr: Place to put MAC address (6 bytes) - */ -void string_to_enetaddr(const char *addr, uint8_t *enetaddr);
/* Convert an IP address to a string */ void ip_to_string(struct in_addr x, char *s); diff --git a/include/net/arp.h b/include/net/arp.h new file mode 100644 index 0000000000..f614f0ef78 --- /dev/null +++ b/include/net/arp.h @@ -0,0 +1,7 @@ +/* ARP hardware address length */ +#define ARP_HLEN 6 +/* + * The size of a MAC address in string form, each digit requires two chars + * and five separator characters to form '00:00:00:00:00:00'. + */ +#define ARP_HLEN_ASCII (ARP_HLEN * 2) + (ARP_HLEN - 1) diff --git a/include/net/eth.h b/include/net/eth.h new file mode 100644 index 0000000000..17552bca81 --- /dev/null +++ b/include/net/eth.h @@ -0,0 +1,190 @@ +#include <net/arp.h> + +struct udevice; + +enum eth_state_t { + ETH_STATE_INIT, + ETH_STATE_PASSIVE, + ETH_STATE_ACTIVE +}; + +/** + * struct eth_pdata - Platform data for Ethernet MAC controllers + * + * @iobase: The base address of the hardware registers + * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env + * @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_... + * @max_speed: Maximum speed of Ethernet connection supported by MAC + * @priv_pdata: device specific plat + */ +struct eth_pdata { + phys_addr_t iobase; + unsigned char enetaddr[ARP_HLEN]; + int phy_interface; + int max_speed; + void *priv_pdata; +}; + +enum eth_recv_flags { + /* + * Check hardware device for new packets (otherwise only return those + * which are already in the memory buffer ready to process) + */ + ETH_RECV_CHECK_DEVICE = 1 << 0, +}; + +/** + * struct eth_ops - functions of Ethernet MAC controllers + * + * start: Prepare the hardware to send and receive packets + * send: Send the bytes passed in "packet" as a packet on the wire + * recv: Check if the hardware received a packet. If so, set the pointer to the + * packet buffer in the packetp parameter. If not, return an error or 0 to + * indicate that the hardware receive FIFO is empty. If 0 is returned, the + * network stack will not process the empty packet, but free_pkt() will be + * called if supplied + * free_pkt: Give the driver an opportunity to manage its packet buffer memory + * when the network stack is finished processing it. This will only be + * called when no error was returned from recv - optional + * stop: Stop the hardware from looking for packets - may be called even if + * state == PASSIVE + * mcast: Join or leave a multicast group (for TFTP) - optional + * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux + * on some platforms like ARM). This function expects the + * eth_pdata::enetaddr field to be populated. The method can + * return -ENOSYS to indicate that this is not implemented for + this hardware - optional. + * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a + * ROM on the board. This is how the driver should expose it + * to the network stack. This function should fill in the + * eth_pdata::enetaddr field - optional + * set_promisc: Enable or Disable promiscuous mode + * get_sset_count: Number of statistics counters + * get_string: Names of the statistic counters + * get_stats: The values of the statistic counters + */ +struct eth_ops { + int (*start)(struct udevice *dev); + int (*send)(struct udevice *dev, void *packet, int length); + int (*recv)(struct udevice *dev, int flags, uchar **packetp); + int (*free_pkt)(struct udevice *dev, uchar *packet, int length); + void (*stop)(struct udevice *dev); + int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join); + int (*write_hwaddr)(struct udevice *dev); + int (*read_rom_hwaddr)(struct udevice *dev); + int (*set_promisc)(struct udevice *dev, bool enable); + int (*get_sset_count)(struct udevice *dev); + void (*get_strings)(struct udevice *dev, u8 *data); + void (*get_stats)(struct udevice *dev, u64 *data); +}; + +#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops) + +struct udevice *eth_get_dev(void); /* get the current device */ +/* + * The devname can be either an exact name given by the driver or device tree + * or it can be an alias of the form "eth%d" + */ +struct udevice *eth_get_dev_by_name(const char *devname); +unsigned char *eth_get_ethaddr(void); /* get the current device MAC */ + +/* Used only when NetConsole is enabled */ +int eth_is_active(struct udevice *dev); /* Test device for active state */ +int eth_init_state_only(void); /* Set active state */ +void eth_halt_state_only(void); /* Set passive state */ + +int eth_initialize(void); /* Initialize network subsystem */ +void eth_try_another(int first_restart); /* Change the device */ +void eth_set_current(void); /* set nterface to ethcur var */ + +int eth_get_dev_index(void); /* get the device index */ + +/** + * eth_env_set_enetaddr_by_index() - set the MAC address environment variable + * + * This sets up an environment variable with the given MAC address (@enetaddr). + * The environment variable to be set is defined by <@base_name><@index>addr. + * If @index is 0 it is omitted. For common Ethernet this means ethaddr, + * eth1addr, etc. + * + * @base_name: Base name for variable, typically "eth" + * @index: Index of interface being updated (>=0) + * @enetaddr: Pointer to MAC address to put into the variable + * Return: 0 if OK, other value on error + */ +int eth_env_set_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr); + + +/* + * Initialize USB ethernet device with CONFIG_DM_ETH + * Returns: + * 0 is success, non-zero is error status. + */ +int usb_ether_init(void); + +/* + * Get the hardware address for an ethernet interface . + * Args: + * base_name - base name for device (normally "eth") + * index - device index number (0 for first) + * enetaddr - returns 6 byte hardware address + * Returns: + * Return true if the address is valid. + */ +int eth_env_get_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr); + +int eth_init(void); /* Initialize the device */ +int eth_send(void *packet, int length); /* Send a packet */ + +#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) +int eth_receive(void *packet, int length); /* Receive a packet*/ +extern void (*push_packet)(void *packet, int length); +#endif +int eth_rx(void); /* Check for received packets */ +void eth_halt(void); /* stop SCC */ +const char *eth_get_name(void); /* get name of current device */ + +/* + * The number of receive packet buffers, and the required packet buffer + * alignment in memory. + * + */ +#define PKTBUFSRX CONFIG_SYS_RX_ETH_BUFFER +#define PKTALIGN ARCH_DMA_MINALIGN + +/* Number of packets processed together */ +#define ETH_PACKETS_BATCH_RECV 32 + +extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet address */ +extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet address */ +extern struct in_addr net_ip; /* Our IP addr (0 = unknown) */ +extern struct in_addr net_server_ip; /* Server IP addr (0 = unknown) */ +extern uchar *net_tx_packet; /* THE transmit packet */ +extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */ +extern uchar *net_rx_packet; /* Current receive packet */ +extern int net_rx_packet_len; /* Current rx packet length */ +extern const u8 net_bcast_ethaddr[ARP_HLEN]; /* Ethernet broadcast address */ +extern const u8 net_null_ethaddr[ARP_HLEN]; + +/** + * string_to_enetaddr() - Parse a MAC address + * + * Convert a string MAC address + * + * Implemented in lib/net_utils.c (built unconditionally) + * + * @addr: MAC address in aa:bb:cc:dd:ee:ff format, where each part is a 2-digit + * hex value + * @enetaddr: Place to put MAC address (6 bytes) + */ +void string_to_enetaddr(const char *addr, uint8_t *enetaddr); + +typedef struct ulwip { + bool loop; + int err; + bool init_done; +} ulwip; + +struct ulwip *eth_lwip_priv(struct udevice *current);

After which to lwip variants of working apps we need to drop old code with all dependencies. This commit drop old wget command files.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/wget.h | 22 --- net/Makefile | 1 - net/net.c | 6 - net/wget.c | 440 --------------------------------------------- 4 files changed, 469 deletions(-) delete mode 100644 include/net/wget.h delete mode 100644 net/wget.c
diff --git a/include/net/wget.h b/include/net/wget.h deleted file mode 100644 index da0920de11..0000000000 --- a/include/net/wget.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Duncan Hare Copyright 2017 - */ - -/** - * wget_start() - begin wget - */ -void wget_start(void); - -enum wget_state { - WGET_CLOSED, - WGET_CONNECTING, - WGET_CONNECTED, - WGET_TRANSFERRING, - WGET_TRANSFERRED -}; - -#define DEBUG_WGET 0 /* Set to 1 for debug messages */ -#define SERVER_PORT 80 -#define WGET_RETRY_COUNT 30 -#define WGET_TIMEOUT 2000UL diff --git a/net/Makefile b/net/Makefile index 61930c244e..eda21f988a 100644 --- a/net/Makefile +++ b/net/Makefile @@ -32,7 +32,6 @@ obj-$(CONFIG_TCP_FUNCTION_FASTBOOT) += fastboot_tcp.o obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_PROT_UDP) += udp.o obj-$(CONFIG_PROT_TCP) += tcp.o -obj-$(CONFIG_CMD_WGET) += wget.o obj-$(CONFIG_LWIP) += lwip/
# Disable this warning as it is triggered by: diff --git a/net/net.c b/net/net.c index d9e566081c..677eda26bc 100644 --- a/net/net.c +++ b/net/net.c @@ -109,7 +109,6 @@ #include <linux/compiler.h> #include <test/test.h> #include <net/tcp.h> -#include <net/wget.h> #include "arp.h" #include "bootp.h" #include "cdp.h" @@ -564,11 +563,6 @@ restart: nfs_start(); break; #endif -#if defined(CONFIG_CMD_WGET) - case WGET: - wget_start(); - break; -#endif #if defined(CONFIG_CMD_CDP) case CDP: cdp_start(); diff --git a/net/wget.c b/net/wget.c deleted file mode 100644 index 2dbfeb1a1d..0000000000 --- a/net/wget.c +++ /dev/null @@ -1,440 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * WGET/HTTP support driver based on U-BOOT's nfs.c - * Copyright Duncan Hare dh@synoia.com 2017 - */ - -#include <command.h> -#include <common.h> -#include <display_options.h> -#include <env.h> -#include <image.h> -#include <mapmem.h> -#include <net.h> -#include <net/tcp.h> -#include <net/wget.h> - -static const char bootfile1[] = "GET "; -static const char bootfile3[] = " HTTP/1.0\r\n\r\n"; -static const char http_eom[] = "\r\n\r\n"; -static const char http_ok[] = "200"; -static const char content_len[] = "Content-Length"; -static const char linefeed[] = "\r\n"; -static struct in_addr web_server_ip; -static int our_port; -static int wget_timeout_count; - -struct pkt_qd { - uchar *pkt; - unsigned int tcp_seq_num; - unsigned int len; -}; - -/* - * This is a control structure for out of order packets received. - * The actual packet bufers are in the kernel space, and are - * expected to be overwritten by the downloaded image. - */ -static struct pkt_qd pkt_q[PKTBUFSRX / 4]; -static int pkt_q_idx; -static unsigned long content_length; -static unsigned int packets; - -static unsigned int initial_data_seq_num; - -static enum wget_state current_wget_state; - -static char *image_url; -static unsigned int wget_timeout = WGET_TIMEOUT; - -static enum net_loop_state wget_loop_state; - -/* Timeout retry parameters */ -static u8 retry_action; /* actions for TCP retry */ -static unsigned int retry_tcp_ack_num; /* TCP retry acknowledge number*/ -static unsigned int retry_tcp_seq_num; /* TCP retry sequence number */ -static int retry_len; /* TCP retry length */ - -/** - * store_block() - store block in memory - * @src: source of data - * @offset: offset - * @len: length - */ -static inline int store_block(uchar *src, unsigned int offset, unsigned int len) -{ - ulong newsize = offset + len; - uchar *ptr; - - ptr = map_sysmem(image_load_addr + offset, len); - memcpy(ptr, src, len); - unmap_sysmem(ptr); - - if (net_boot_file_size < (offset + len)) - net_boot_file_size = newsize; - - return 0; -} - -/** - * wget_send_stored() - wget response dispatcher - * - * WARNING, This, and only this, is the place in wget.c where - * SEQUENCE NUMBERS are swapped between incoming (RX) - * and outgoing (TX). - * Procedure wget_handler() is correct for RX traffic. - */ -static void wget_send_stored(void) -{ - u8 action = retry_action; - int len = retry_len; - unsigned int tcp_ack_num = retry_tcp_seq_num + (len == 0 ? 1 : len); - unsigned int tcp_seq_num = retry_tcp_ack_num; - uchar *ptr, *offset; - - switch (current_wget_state) { - case WGET_CLOSED: - debug_cond(DEBUG_WGET, "wget: send SYN\n"); - current_wget_state = WGET_CONNECTING; - net_send_tcp_packet(0, SERVER_PORT, our_port, action, - tcp_seq_num, tcp_ack_num); - packets = 0; - break; - case WGET_CONNECTING: - pkt_q_idx = 0; - net_send_tcp_packet(0, SERVER_PORT, our_port, action, - tcp_seq_num, tcp_ack_num); - - ptr = net_tx_packet + net_eth_hdr_size() + - IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2; - offset = ptr; - - memcpy(offset, &bootfile1, strlen(bootfile1)); - offset += strlen(bootfile1); - - memcpy(offset, image_url, strlen(image_url)); - offset += strlen(image_url); - - memcpy(offset, &bootfile3, strlen(bootfile3)); - offset += strlen(bootfile3); - net_send_tcp_packet((offset - ptr), SERVER_PORT, our_port, - TCP_PUSH, tcp_seq_num, tcp_ack_num); - current_wget_state = WGET_CONNECTED; - break; - case WGET_CONNECTED: - case WGET_TRANSFERRING: - case WGET_TRANSFERRED: - net_send_tcp_packet(0, SERVER_PORT, our_port, action, - tcp_seq_num, tcp_ack_num); - break; - } -} - -static void wget_send(u8 action, unsigned int tcp_seq_num, - unsigned int tcp_ack_num, int len) -{ - retry_action = action; - retry_tcp_ack_num = tcp_ack_num; - retry_tcp_seq_num = tcp_seq_num; - retry_len = len; - - wget_send_stored(); -} - -void wget_fail(char *error_message, unsigned int tcp_seq_num, - unsigned int tcp_ack_num, u8 action) -{ - printf("wget: Transfer Fail - %s\n", error_message); - net_set_timeout_handler(0, NULL); - wget_send(action, tcp_seq_num, tcp_ack_num, 0); -} - -void wget_success(u8 action, unsigned int tcp_seq_num, - unsigned int tcp_ack_num, int len, int packets) -{ - printf("Packets received %d, Transfer Successful\n", packets); - wget_send(action, tcp_seq_num, tcp_ack_num, len); -} - -/* - * Interfaces of U-BOOT - */ -static void wget_timeout_handler(void) -{ - if (++wget_timeout_count > WGET_RETRY_COUNT) { - puts("\nRetry count exceeded; starting again\n"); - wget_send(TCP_RST, 0, 0, 0); - net_start_again(); - } else { - puts("T "); - net_set_timeout_handler(wget_timeout + - WGET_TIMEOUT * wget_timeout_count, - wget_timeout_handler); - wget_send_stored(); - } -} - -#define PKT_QUEUE_OFFSET 0x20000 -#define PKT_QUEUE_PACKET_SIZE 0x800 - -static void wget_connected(uchar *pkt, unsigned int tcp_seq_num, - u8 action, unsigned int tcp_ack_num, unsigned int len) -{ - uchar *pkt_in_q; - char *pos; - int hlen, i; - uchar *ptr1; - - pkt[len] = '\0'; - pos = strstr((char *)pkt, http_eom); - - if (!pos) { - debug_cond(DEBUG_WGET, - "wget: Connected, data before Header %p\n", pkt); - pkt_in_q = (void *)image_load_addr + PKT_QUEUE_OFFSET + - (pkt_q_idx * PKT_QUEUE_PACKET_SIZE); - - ptr1 = map_sysmem((phys_addr_t)pkt_in_q, len); - memcpy(ptr1, pkt, len); - unmap_sysmem(ptr1); - - pkt_q[pkt_q_idx].pkt = pkt_in_q; - pkt_q[pkt_q_idx].tcp_seq_num = tcp_seq_num; - pkt_q[pkt_q_idx].len = len; - pkt_q_idx++; - } else { - debug_cond(DEBUG_WGET, "wget: Connected HTTP Header %p\n", pkt); - /* sizeof(http_eom) - 1 is the string length of (http_eom) */ - hlen = pos - (char *)pkt + sizeof(http_eom) - 1; - pos = strstr((char *)pkt, linefeed); - if (pos > 0) - i = pos - (char *)pkt; - else - i = hlen; - printf("%.*s", i, pkt); - - current_wget_state = WGET_TRANSFERRING; - - if (strstr((char *)pkt, http_ok) == 0) { - debug_cond(DEBUG_WGET, - "wget: Connected Bad Xfer\n"); - initial_data_seq_num = tcp_seq_num + hlen; - wget_loop_state = NETLOOP_FAIL; - wget_send(action, tcp_seq_num, tcp_ack_num, len); - } else { - debug_cond(DEBUG_WGET, - "wget: Connctd pkt %p hlen %x\n", - pkt, hlen); - initial_data_seq_num = tcp_seq_num + hlen; - - pos = strstr((char *)pkt, content_len); - if (!pos) { - content_length = -1; - } else { - pos += sizeof(content_len) + 2; - strict_strtoul(pos, 10, &content_length); - debug_cond(DEBUG_WGET, - "wget: Connected Len %lu\n", - content_length); - } - - net_boot_file_size = 0; - - if (len > hlen) - store_block(pkt + hlen, 0, len - hlen); - - debug_cond(DEBUG_WGET, - "wget: Connected Pkt %p hlen %x\n", - pkt, hlen); - - for (i = 0; i < pkt_q_idx; i++) { - ptr1 = map_sysmem( - (phys_addr_t)(pkt_q[i].pkt), - pkt_q[i].len); - store_block(ptr1, - pkt_q[i].tcp_seq_num - - initial_data_seq_num, - pkt_q[i].len); - unmap_sysmem(ptr1); - debug_cond(DEBUG_WGET, - "wget: Connctd pkt Q %p len %x\n", - pkt_q[i].pkt, pkt_q[i].len); - } - } - } - wget_send(action, tcp_seq_num, tcp_ack_num, len); -} - -/** - * wget_handler() - TCP handler of wget - * @pkt: pointer to the application packet - * @dport: destination TCP port - * @sip: source IP address - * @sport: source TCP port - * @tcp_seq_num: TCP sequential number - * @tcp_ack_num: TCP acknowledgment number - * @action: TCP action (SYN, ACK, FIN, etc) - * @len: packet length - * - * In the "application push" invocation, the TCP header with all - * its information is pointed to by the packet pointer. - */ -static void wget_handler(uchar *pkt, u16 dport, - struct in_addr sip, u16 sport, - u32 tcp_seq_num, u32 tcp_ack_num, - u8 action, unsigned int len) -{ - enum tcp_state wget_tcp_state = tcp_get_tcp_state(); - - net_set_timeout_handler(wget_timeout, wget_timeout_handler); - packets++; - - switch (current_wget_state) { - case WGET_CLOSED: - debug_cond(DEBUG_WGET, "wget: Handler: Error!, State wrong\n"); - break; - case WGET_CONNECTING: - debug_cond(DEBUG_WGET, - "wget: Connecting In len=%x, Seq=%u, Ack=%u\n", - len, tcp_seq_num, tcp_ack_num); - if (!len) { - if (wget_tcp_state == TCP_ESTABLISHED) { - debug_cond(DEBUG_WGET, - "wget: Cting, send, len=%x\n", len); - wget_send(action, tcp_seq_num, tcp_ack_num, - len); - } else { - printf("%.*s", len, pkt); - wget_fail("wget: Handler Connected Fail\n", - tcp_seq_num, tcp_ack_num, action); - } - } - break; - case WGET_CONNECTED: - debug_cond(DEBUG_WGET, "wget: Connected seq=%u, len=%x\n", - tcp_seq_num, len); - if (!len) { - wget_fail("Image not found, no data returned\n", - tcp_seq_num, tcp_ack_num, action); - } else { - wget_connected(pkt, tcp_seq_num, action, tcp_ack_num, len); - } - break; - case WGET_TRANSFERRING: - debug_cond(DEBUG_WGET, - "wget: Transferring, seq=%x, ack=%x,len=%x\n", - tcp_seq_num, tcp_ack_num, len); - - if (tcp_seq_num >= initial_data_seq_num && - store_block(pkt, tcp_seq_num - initial_data_seq_num, - len) != 0) { - wget_fail("wget: store error\n", - tcp_seq_num, tcp_ack_num, action); - return; - } - - switch (wget_tcp_state) { - case TCP_FIN_WAIT_2: - wget_send(TCP_ACK, tcp_seq_num, tcp_ack_num, len); - fallthrough; - case TCP_SYN_SENT: - case TCP_SYN_RECEIVED: - case TCP_CLOSING: - case TCP_FIN_WAIT_1: - case TCP_CLOSED: - net_set_state(NETLOOP_FAIL); - break; - case TCP_ESTABLISHED: - wget_send(TCP_ACK, tcp_seq_num, tcp_ack_num, - len); - wget_loop_state = NETLOOP_SUCCESS; - break; - case TCP_CLOSE_WAIT: /* End of transfer */ - current_wget_state = WGET_TRANSFERRED; - wget_send(action | TCP_ACK | TCP_FIN, - tcp_seq_num, tcp_ack_num, len); - break; - } - break; - case WGET_TRANSFERRED: - printf("Packets received %d, Transfer Successful\n", packets); - net_set_state(wget_loop_state); - break; - } -} - -#define RANDOM_PORT_START 1024 -#define RANDOM_PORT_RANGE 0x4000 - -/** - * random_port() - make port a little random (1024-17407) - * - * Return: random port number from 1024 to 17407 - * - * This keeps the math somewhat trivial to compute, and seems to work with - * all supported protocols/clients/servers - */ -static unsigned int random_port(void) -{ - return RANDOM_PORT_START + (get_timer(0) % RANDOM_PORT_RANGE); -} - -#define BLOCKSIZE 512 - -void wget_start(void) -{ - image_url = strchr(net_boot_file_name, ':'); - if (image_url > 0) { - web_server_ip = string_to_ip(net_boot_file_name); - ++image_url; - net_server_ip = web_server_ip; - } else { - web_server_ip = net_server_ip; - image_url = net_boot_file_name; - } - - debug_cond(DEBUG_WGET, - "wget: Transfer HTTP Server %pI4; our IP %pI4\n", - &web_server_ip, &net_ip); - - /* Check if we need to send across this subnet */ - if (net_gateway.s_addr && net_netmask.s_addr) { - struct in_addr our_net; - struct in_addr server_net; - - our_net.s_addr = net_ip.s_addr & net_netmask.s_addr; - server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr; - if (our_net.s_addr != server_net.s_addr) - debug_cond(DEBUG_WGET, - "wget: sending through gateway %pI4", - &net_gateway); - } - debug_cond(DEBUG_WGET, "URL '%s'\n", image_url); - - if (net_boot_file_expected_size_in_blocks) { - debug_cond(DEBUG_WGET, "wget: Size is 0x%x Bytes = ", - net_boot_file_expected_size_in_blocks * BLOCKSIZE); - print_size(net_boot_file_expected_size_in_blocks * BLOCKSIZE, - ""); - } - debug_cond(DEBUG_WGET, - "\nwget:Load address: 0x%lx\nLoading: *\b", image_load_addr); - - net_set_timeout_handler(wget_timeout, wget_timeout_handler); - tcp_set_tcp_handler(wget_handler); - - wget_timeout_count = 0; - current_wget_state = WGET_CLOSED; - - our_port = random_port(); - - /* - * Zero out server ether to force arp resolution in case - * the server ip for the previous u-boot command, for example dns - * is not the same as the web server ip. - */ - - memset(net_server_ethaddr, 0, 6); - - wget_send(TCP_SYN, 0, 0, 0); -}

Allow to specify HTTP port instead of just using default for wget command.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org --- include/net/lwip.h | 2 +- net/lwip/apps/http/lwip-wget.c | 40 +++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/include/net/lwip.h b/include/net/lwip.h index 1e92f9871c..6de646771e 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -54,7 +54,7 @@ int ulwip_tftp(ulong addr, const char *filename); * * * @addr: start address to download result - * @url: url in format http://host/url + * @url: url in format http://host%5B:port%5D/url * Returns: 0 for success, !0 if error */ int ulwip_wget(ulong addr, char *url); diff --git a/net/lwip/apps/http/lwip-wget.c b/net/lwip/apps/http/lwip-wget.c index 5c432056b1..7de1c962c6 100644 --- a/net/lwip/apps/http/lwip-wget.c +++ b/net/lwip/apps/http/lwip-wget.c @@ -63,18 +63,38 @@ static int parse_url(char *url, char *host, u16 *port) p += strlen("http://");
/* parse hostname */ - pp = strchr(p, '/'); - if (!pp) { - return -2; + pp = strchr(p, ':'); + if (pp) { +#define PORT_STR_SIZE 5 + char portstr[PORT_STR_SIZE]; + + if (pp - p >= SERVER_NAME_SIZE) + return -2; + memcpy(host, p, pp - p); + host[pp - p + 1] = '\0'; + + p = pp + 1; + pp = strchr(p, '/'); + if (!pp) + return -3; + + if (pp - p >= PORT_STR_SIZE) + return -4; + memcpy(portstr, p, pp - p); + portstr[pp - p] = '\0'; + *port = (u16)dectoul(portstr, NULL); + } else { + pp = strchr(p, '/'); + if (!pp) + return -5; + + if (pp - p >= SERVER_NAME_SIZE) + return -6; + memcpy(host, p, pp - p); + host[pp - p + 1] = '\0'; + *port = HTTP_PORT_DEFAULT; }
- if (pp - p >= SERVER_NAME_SIZE) - return -3; - - memcpy(host, p, pp - p); - host[pp - p + 1] = '\0'; - *port = HTTP_PORT_DEFAULT; - return 0; }

Hi Maxi,
I'd drop this from the series. It's useful in the long run, but let's just get the minimum functionality in first
Thanks /Ilias On Fri, Sep 08, 2023 at 07:53:20PM +0600, Maxim Uvarov wrote:
Allow to specify HTTP port instead of just using default for wget command.
Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
include/net/lwip.h | 2 +- net/lwip/apps/http/lwip-wget.c | 40 +++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/include/net/lwip.h b/include/net/lwip.h index 1e92f9871c..6de646771e 100644 --- a/include/net/lwip.h +++ b/include/net/lwip.h @@ -54,7 +54,7 @@ int ulwip_tftp(ulong addr, const char *filename);
- @addr: start address to download result
- @url: url in format http://host/url
*/
- @url: url in format http://host%5B:port%5D/url
- Returns: 0 for success, !0 if error
int ulwip_wget(ulong addr, char *url); diff --git a/net/lwip/apps/http/lwip-wget.c b/net/lwip/apps/http/lwip-wget.c index 5c432056b1..7de1c962c6 100644 --- a/net/lwip/apps/http/lwip-wget.c +++ b/net/lwip/apps/http/lwip-wget.c @@ -63,18 +63,38 @@ static int parse_url(char *url, char *host, u16 *port) p += strlen("http://");
/* parse hostname */
- pp = strchr(p, '/');
- if (!pp) {
return -2;
- pp = strchr(p, ':');
- if (pp) {
+#define PORT_STR_SIZE 5
char portstr[PORT_STR_SIZE];
if (pp - p >= SERVER_NAME_SIZE)
return -2;
memcpy(host, p, pp - p);
host[pp - p + 1] = '\0';
p = pp + 1;
pp = strchr(p, '/');
if (!pp)
return -3;
if (pp - p >= PORT_STR_SIZE)
return -4;
memcpy(portstr, p, pp - p);
portstr[pp - p] = '\0';
*port = (u16)dectoul(portstr, NULL);
- } else {
pp = strchr(p, '/');
if (!pp)
return -5;
if (pp - p >= SERVER_NAME_SIZE)
return -6;
memcpy(host, p, pp - p);
host[pp - p + 1] = '\0';
}*port = HTTP_PORT_DEFAULT;
- if (pp - p >= SERVER_NAME_SIZE)
return -3;
- memcpy(host, p, pp - p);
- host[pp - p + 1] = '\0';
- *port = HTTP_PORT_DEFAULT;
- return 0;
}
-- 2.30.2

On Fri, Sep 08, 2023 at 07:53:05PM +0600, Maxim Uvarov wrote:
Before apply these patches it is needed to create lwIP merge into U-Boot: git subtree add --prefix net/lwip/lwip-external https://git.savannah.nongnu.org/git/lwip.git master --squash or create git submodule, depends how it's more easy to maintain external library.
So, I think we're going to go with subtree. Please work out how to integrate the above in to the build process automatically (and such that we can maintain it via upgrades moving forward).

On Fri, 8 Sept 2023 at 19:59, Tom Rini trini@konsulko.com wrote:
On Fri, Sep 08, 2023 at 07:53:05PM +0600, Maxim Uvarov wrote:
Before apply these patches it is needed to create lwIP merge into
U-Boot:
git subtree add --prefix net/lwip/lwip-external
https://git.savannah.nongnu.org/git/lwip.git master --squash
or create git submodule, depends how it's more easy to maintain external library.
So, I think we're going to go with subtree. Please work out how to integrate the above in to the build process automatically (and such that we can maintain it via upgrades moving forward).
-- Tom
I did not find a good way to friend git format-patch, git am and subtree. And now with using subtree I can provide my thoughts, in general I do not see any big advantages with maintaining subtree code.
Problem is that:
1. subtree does some root reset. So rebase looks like: label onto
# Branch acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset [new root]
pick acbc0469a4 Squashed 'net/lwip/lwip-external/' content from commit 84fde1ebbf label acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset onto
merge -C ec4a128c8d acbc0469a49de7055141cc730aa9c728e61b6de2-2 # Merge commit 'acbc0469a49de7055141cc730aa9c728e61b6de2' as 'net/lwip/lwip-external' pick 739681a6f5 net/lwip: add doc/develop/net_lwip.rst
pick f0ecab85e0 net/lwip: integrate lwIP library
2. if --rebase-merges option was not provided to rebase, then rebase will omit subtree directory and try to apply rebase patches to root directory. I.e. in current case squashed commit for lwip, will be applied to uboot root directory instead of ./net/lwip/lwip-external.
3. due to broken rebases without --rebase-merges more likely things like git bisect also will not work.
4. change in subtree code ./net/lwip/lwip-external/../something.c will create a git commit which looks like a standard U-Boot commit. I.e. path starts with ./net/lwip/lwip-external/
5. lwip maintains code with a mailing list. So we don't need to push subtree git somewhere to create a pull request.
6. I rechecked the latest edk2 and they use submodules now. (openssl, libfdt, berkeley-softfloat-3 and others).
7. dynamic download also looks horrible for me. I.e. create subtree in Makefile on compilation process. I think maintaining that will give you a bunch of problems. I think we should not touch git structure after cloning.
So what I can here suggest: 1. lwip source code is 9.4M. If we compare all code it will be 564M in total. So just having 1 commit witn copy of lwip library will work here.
or
2. use git submodules. Size of the project will be lower. Submodule will not allow you to use local changes. I.e. change needs to be merged into the upstream project and then you can update git HEAD for the submodule.
or
3. inside u-boot.git create branch lib-lwip and clone lwip repo there. Then use git submoule to connect this branch as a folder to the main U-Boot code.
BR, Maxim.

Hi Maxim,
On Tue, 12 Sept 2023 at 05:42, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Fri, 8 Sept 2023 at 19:59, Tom Rini trini@konsulko.com wrote:
On Fri, Sep 08, 2023 at 07:53:05PM +0600, Maxim Uvarov wrote:
Before apply these patches it is needed to create lwIP merge into
U-Boot:
git subtree add --prefix net/lwip/lwip-external
https://git.savannah.nongnu.org/git/lwip.git master --squash
or create git submodule, depends how it's more easy to maintain external library.
So, I think we're going to go with subtree. Please work out how to integrate the above in to the build process automatically (and such that we can maintain it via upgrades moving forward).
-- Tom
I did not find a good way to friend git format-patch, git am and subtree. And now with using subtree I can provide my thoughts, in general I do not see any big advantages with maintaining subtree code.
Problem is that:
- subtree does some root reset. So rebase looks like:
label onto
# Branch acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset [new root]
pick acbc0469a4 Squashed 'net/lwip/lwip-external/' content from commit 84fde1ebbf label acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset onto
merge -C ec4a128c8d acbc0469a49de7055141cc730aa9c728e61b6de2-2 # Merge commit 'acbc0469a49de7055141cc730aa9c728e61b6de2' as 'net/lwip/lwip-external' pick 739681a6f5 net/lwip: add doc/develop/net_lwip.rst
pick f0ecab85e0 net/lwip: integrate lwIP library
- if --rebase-merges option was not provided to rebase, then rebase will
omit subtree directory and try to apply rebase patches to root directory. I.e. in current case squashed commit for lwip, will be applied to uboot root directory instead of ./net/lwip/lwip-external.
- due to broken rebases without --rebase-merges more likely things like
git bisect also will not work.
- change in subtree code ./net/lwip/lwip-external/../something.c will
create a git commit which looks like a standard U-Boot commit. I.e. path starts with ./net/lwip/lwip-external/
I don't really understand most of the above, but I take it that subtree has some problems...I did find an article about subtree [1]
- lwip maintains code with a mailing list. So we don't need to push
subtree git somewhere to create a pull request.
- I rechecked the latest edk2 and they use submodules now. (openssl,
libfdt, berkeley-softfloat-3 and others).
- dynamic download also looks horrible for me. I.e. create subtree in
Makefile on compilation process. I think maintaining that will give you a bunch of problems. I think we should not touch git structure after cloning.
So what I can here suggest:
- lwip source code is 9.4M. If we compare all code it will be 564M in
total. So just having 1 commit witn copy of lwip library will work here.
So we add a 9.4MB patch for the code we need? I suppose that is OK, although it is much larger than net/ today (0.5MB).
What is the churn on lwip? E.g. would it be easy to add a commit every few months to bring in upstream changes?
or
- use git submodules. Size of the project will be lower. Submodule will
not allow you to use local changes. I.e. change needs to be merged into the upstream project and then you can update git HEAD for the submodule.
I really don't want to work with a submodule project. I've just had too many problems.
or
- inside u-boot.git create branch lib-lwip and clone lwip repo there. Then
use git submoule to connect this branch as a folder to the main U-Boot code.
It really needs to be properly part of U-Boot.
BR, Maxim.
Regards, Simon

On Wed, 13 Sept 2023 at 01:27, Simon Glass sjg@google.com wrote:
Hi Maxim,
On Tue, 12 Sept 2023 at 05:42, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Fri, 8 Sept 2023 at 19:59, Tom Rini trini@konsulko.com wrote:
On Fri, Sep 08, 2023 at 07:53:05PM +0600, Maxim Uvarov wrote:
Before apply these patches it is needed to create lwIP merge into
U-Boot:
git subtree add --prefix net/lwip/lwip-external
https://git.savannah.nongnu.org/git/lwip.git master --squash
or create git submodule, depends how it's more easy to maintain external library.
So, I think we're going to go with subtree. Please work out how to integrate the above in to the build process automatically (and such
that
we can maintain it via upgrades moving forward).
-- Tom
I did not find a good way to friend git format-patch, git am and subtree. And now with using subtree I can provide my thoughts, in general I do not see any big advantages with maintaining subtree code.
Problem is that:
- subtree does some root reset. So rebase looks like:
label onto
# Branch acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset [new root]
pick acbc0469a4 Squashed 'net/lwip/lwip-external/' content from commit 84fde1ebbf label acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset onto
merge -C ec4a128c8d acbc0469a49de7055141cc730aa9c728e61b6de2-2 # Merge commit 'acbc0469a49de7055141cc730aa9c728e61b6de2' as 'net/lwip/lwip-external' pick 739681a6f5 net/lwip: add doc/develop/net_lwip.rst
pick f0ecab85e0 net/lwip: integrate lwIP library
- if --rebase-merges option was not provided to rebase, then rebase
will
omit subtree directory and try to apply rebase patches to root directory. I.e. in current case squashed commit for lwip, will be applied to uboot root directory instead of ./net/lwip/lwip-external.
- due to broken rebases without --rebase-merges more likely things like
git bisect also will not work.
- change in subtree code ./net/lwip/lwip-external/../something.c will
create a git commit which looks like a standard U-Boot commit. I.e. path starts with ./net/lwip/lwip-external/
I don't really understand most of the above, but I take it that subtree has some problems...I did find an article about subtree [1]
- lwip maintains code with a mailing list. So we don't need to push
subtree git somewhere to create a pull request.
- I rechecked the latest edk2 and they use submodules now. (openssl,
libfdt, berkeley-softfloat-3 and others).
- dynamic download also looks horrible for me. I.e. create subtree in
Makefile on compilation process. I think maintaining that will give you a bunch of problems. I think we should not touch git structure after
cloning.
So what I can here suggest:
- lwip source code is 9.4M. If we compare all code it will be 564M in
total. So just having 1 commit witn copy of lwip library will work here.
So we add a 9.4MB patch for the code we need? I suppose that is OK, although it is much larger than net/ today (0.5MB).
What is the churn on lwip? E.g. would it be easy to add a commit every few months to bring in upstream changes?
or
- use git submodules. Size of the project will be lower. Submodule will
not allow you to use local changes. I.e. change needs to be merged into
the
upstream project and then you can update git HEAD for the submodule.
I really don't want to work with a submodule project. I've just had too many problems.
or
- inside u-boot.git create branch lib-lwip and clone lwip repo there.
Then
use git submoule to connect this branch as a folder to the main U-Boot
code.
It really needs to be properly part of U-Boot.
Ok. Then more likely we don't need all the git history of lwip inside uboot.git. Then the option with a single commit is more preferable. Then we can use part 2 of this article, how to go with standard git commands:
1. <cmd> git remote add -f lwip https://git.savannah.nongnu.org/git/lwip.git git read-tree --prefix=net/lwip/lwip-external -u lwip/master git commit -m "lwip merge sha: xxxx" </cmd> this will create a git format-patch friendly commit. Then we send it to the mailing list and apply. I hope the mailing list will allow us to send a 7.8 MB patch.
Then if for development you need to pull he history of lwip, you can do it with: git pull -s subtree lwip master --allow-unrelated-histories (but I think nobody will need this.)
New update of the lwip net/lwip/lwip-external dir will be done with: git pull -s subtree lwip master --allow-unrelated-histories --squash Squash commit also has to be git format-patch friendly.
If you are ok with that proposal I will send v9 with the first patch created with steps above.
Thanks, Maxim.
BR, Maxim.
Regards, Simon

Hi Maxim,
On Wed, 13 Sept 2023 at 10:32, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Wed, 13 Sept 2023 at 01:27, Simon Glass sjg@google.com wrote:
Hi Maxim,
On Tue, 12 Sept 2023 at 05:42, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Fri, 8 Sept 2023 at 19:59, Tom Rini trini@konsulko.com wrote:
On Fri, Sep 08, 2023 at 07:53:05PM +0600, Maxim Uvarov wrote:
Before apply these patches it is needed to create lwIP merge into
U-Boot:
git subtree add --prefix net/lwip/lwip-external
https://git.savannah.nongnu.org/git/lwip.git master --squash
or create git submodule, depends how it's more easy to maintain external library.
So, I think we're going to go with subtree. Please work out how to integrate the above in to the build process automatically (and such that we can maintain it via upgrades moving forward).
-- Tom
I did not find a good way to friend git format-patch, git am and subtree. And now with using subtree I can provide my thoughts, in general I do not see any big advantages with maintaining subtree code.
Problem is that:
- subtree does some root reset. So rebase looks like:
label onto
# Branch acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset [new root]
pick acbc0469a4 Squashed 'net/lwip/lwip-external/' content from commit 84fde1ebbf label acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset onto
merge -C ec4a128c8d acbc0469a49de7055141cc730aa9c728e61b6de2-2 # Merge commit 'acbc0469a49de7055141cc730aa9c728e61b6de2' as 'net/lwip/lwip-external' pick 739681a6f5 net/lwip: add doc/develop/net_lwip.rst
pick f0ecab85e0 net/lwip: integrate lwIP library
- if --rebase-merges option was not provided to rebase, then rebase will
omit subtree directory and try to apply rebase patches to root directory. I.e. in current case squashed commit for lwip, will be applied to uboot root directory instead of ./net/lwip/lwip-external.
- due to broken rebases without --rebase-merges more likely things like
git bisect also will not work.
- change in subtree code ./net/lwip/lwip-external/../something.c will
create a git commit which looks like a standard U-Boot commit. I.e. path starts with ./net/lwip/lwip-external/
I don't really understand most of the above, but I take it that subtree has some problems...I did find an article about subtree [1]
- lwip maintains code with a mailing list. So we don't need to push
subtree git somewhere to create a pull request.
- I rechecked the latest edk2 and they use submodules now. (openssl,
libfdt, berkeley-softfloat-3 and others).
- dynamic download also looks horrible for me. I.e. create subtree in
Makefile on compilation process. I think maintaining that will give you a bunch of problems. I think we should not touch git structure after cloning.
So what I can here suggest:
- lwip source code is 9.4M. If we compare all code it will be 564M in
total. So just having 1 commit witn copy of lwip library will work here.
So we add a 9.4MB patch for the code we need? I suppose that is OK, although it is much larger than net/ today (0.5MB).
What is the churn on lwip? E.g. would it be easy to add a commit every few months to bring in upstream changes?
or
- use git submodules. Size of the project will be lower. Submodule will
not allow you to use local changes. I.e. change needs to be merged into the upstream project and then you can update git HEAD for the submodule.
I really don't want to work with a submodule project. I've just had too many problems.
or
- inside u-boot.git create branch lib-lwip and clone lwip repo there. Then
use git submoule to connect this branch as a folder to the main U-Boot code.
It really needs to be properly part of U-Boot.
Ok. Then more likely we don't need all the git history of lwip inside uboot.git. Then the option with a single commit is more preferable. Then we can use part 2 of this article, how to go with standard git commands:
<cmd> git remote add -f lwip https://git.savannah.nongnu.org/git/lwip.git git read-tree --prefix=net/lwip/lwip-external -u lwip/master git commit -m "lwip merge sha: xxxx" </cmd> this will create a git format-patch friendly commit. Then we send it to the mailing list and apply. I hope the mailing list will allow us to send a 7.8 MB patch.
Then if for development you need to pull he history of lwip, you can do it with: git pull -s subtree lwip master --allow-unrelated-histories (but I think nobody will need this.)
New update of the lwip net/lwip/lwip-external dir will be done with: git pull -s subtree lwip master --allow-unrelated-histories --squash Squash commit also has to be git format-patch friendly.
If you are ok with that proposal I will send v9 with the first patch created with steps above.
We've gone through this before. The whole purpose of this is not having to maintain patches. Simon, instead of "I had problems in the past", can you elaborate a bit more?
Tom said he is fine with subtrees instead of submodules and I know for a fact EDK2 doesn't have too many issues with submodules. Their documentation is pretty clear on building and requires
git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init
Perhaps the situation has improved since you had issues?
Thanks /Ilias
Thanks, Maxim.
BR, Maxim.
Regards, Simon

On 13.09.2023 09:53, Ilias Apalodimas wrote:
Hi Maxim,
On Wed, 13 Sept 2023 at 10:32, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Wed, 13 Sept 2023 at 01:27, Simon Glass sjg@google.com wrote:
Hi Maxim,
On Tue, 12 Sept 2023 at 05:42, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Fri, 8 Sept 2023 at 19:59, Tom Rini trini@konsulko.com wrote:
On Fri, Sep 08, 2023 at 07:53:05PM +0600, Maxim Uvarov wrote:
Before apply these patches it is needed to create lwIP merge into
U-Boot:
git subtree add --prefix net/lwip/lwip-external
https://git.savannah.nongnu.org/git/lwip.git master --squash
or create git submodule, depends how it's more easy to maintain external library.
So, I think we're going to go with subtree. Please work out how to integrate the above in to the build process automatically (and such that we can maintain it via upgrades moving forward).
-- Tom
I did not find a good way to friend git format-patch, git am and subtree. And now with using subtree I can provide my thoughts, in general I do not see any big advantages with maintaining subtree code.
Problem is that:
- subtree does some root reset. So rebase looks like:
label onto
# Branch acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset [new root]
pick acbc0469a4 Squashed 'net/lwip/lwip-external/' content from commit 84fde1ebbf label acbc0469a49de7055141cc730aa9c728e61b6de2-2
reset onto
merge -C ec4a128c8d acbc0469a49de7055141cc730aa9c728e61b6de2-2 # Merge commit 'acbc0469a49de7055141cc730aa9c728e61b6de2' as 'net/lwip/lwip-external' pick 739681a6f5 net/lwip: add doc/develop/net_lwip.rst
pick f0ecab85e0 net/lwip: integrate lwIP library
- if --rebase-merges option was not provided to rebase, then rebase will
omit subtree directory and try to apply rebase patches to root directory. I.e. in current case squashed commit for lwip, will be applied to uboot root directory instead of ./net/lwip/lwip-external.
- due to broken rebases without --rebase-merges more likely things like
git bisect also will not work.
- change in subtree code ./net/lwip/lwip-external/../something.c will
create a git commit which looks like a standard U-Boot commit. I.e. path starts with ./net/lwip/lwip-external/
I don't really understand most of the above, but I take it that subtree has some problems...I did find an article about subtree [1]
- lwip maintains code with a mailing list. So we don't need to push
subtree git somewhere to create a pull request.
- I rechecked the latest edk2 and they use submodules now. (openssl,
libfdt, berkeley-softfloat-3 and others).
- dynamic download also looks horrible for me. I.e. create subtree in
Makefile on compilation process. I think maintaining that will give you a bunch of problems. I think we should not touch git structure after cloning.
So what I can here suggest:
- lwip source code is 9.4M. If we compare all code it will be 564M in
total. So just having 1 commit witn copy of lwip library will work here.
So we add a 9.4MB patch for the code we need? I suppose that is OK, although it is much larger than net/ today (0.5MB).
What is the churn on lwip? E.g. would it be easy to add a commit every few months to bring in upstream changes?
or
- use git submodules. Size of the project will be lower. Submodule will
not allow you to use local changes. I.e. change needs to be merged into the upstream project and then you can update git HEAD for the submodule.
I really don't want to work with a submodule project. I've just had too many problems.
or
- inside u-boot.git create branch lib-lwip and clone lwip repo there. Then
use git submoule to connect this branch as a folder to the main U-Boot code.
It really needs to be properly part of U-Boot.
Ok. Then more likely we don't need all the git history of lwip inside uboot.git. Then the option with a single commit is more preferable. Then we can use part 2 of this article, how to go with standard git commands:
<cmd> git remote add -f lwip https://git.savannah.nongnu.org/git/lwip.git git read-tree --prefix=net/lwip/lwip-external -u lwip/master git commit -m "lwip merge sha: xxxx" </cmd> this will create a git format-patch friendly commit. Then we send it to the mailing list and apply. I hope the mailing list will allow us to send a 7.8 MB patch.
Then if for development you need to pull he history of lwip, you can do it with: git pull -s subtree lwip master --allow-unrelated-histories (but I think nobody will need this.)
New update of the lwip net/lwip/lwip-external dir will be done with: git pull -s subtree lwip master --allow-unrelated-histories --squash Squash commit also has to be git format-patch friendly.
If you are ok with that proposal I will send v9 with the first patch created with steps above.
We've gone through this before. The whole purpose of this is not having to maintain patches. Simon, instead of "I had problems in the past", can you elaborate a bit more?
Tom said he is fine with subtrees instead of submodules and I know for a fact EDK2 doesn't have too many issues with submodules. Their documentation is pretty clear on building and requires
git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init
Perhaps the situation has improved since you had issues?
While I don't really care how you solve this technically, I'd *strongly* be interested for U-Boot to use *unmodified* lwIP sources where an explicit reference to an lwIP commit is used. I'd rather integrate bugfixes for U-Boot into lwIP than having the sources drift apart.
Regards, Simon
Thanks /Ilias
Thanks, Maxim.
BR, Maxim.
Regards, Simon

Then if for development you need to pull he history of lwip, you can do it with: git pull -s subtree lwip master --allow-unrelated-histories (but I think nobody will need this.)
New update of the lwip net/lwip/lwip-external dir will be done with: git pull -s subtree lwip master --allow-unrelated-histories --squash Squash commit also has to be git format-patch friendly.
If you are ok with that proposal I will send v9 with the first patch created with steps above.
We've gone through this before. The whole purpose of this is not having to maintain patches. Simon, instead of "I had problems in the past", can you elaborate a bit more?
Tom said he is fine with subtrees instead of submodules and I know for a fact EDK2 doesn't have too many issues with submodules. Their documentation is pretty clear on building and requires
git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init
Perhaps the situation has improved since you had issues?
While I don't really care how you solve this technically, I'd *strongly* be interested for U-Boot to use *unmodified* lwIP sources where an explicit reference to an lwIP commit is used. I'd rather integrate bugfixes for U-Boot into lwIP than having the sources drift apart.
Strongly agree here, we want to use upstream and all the combined development and reviews etc rather than forking off and ending up with yet another slightly different IP stack. The whole advantage of adopting LWIP is the advantage of combined security, features and bugs from a wide range of projects :-)

On Wed, Sep 13, 2023 at 11:06:13AM +0100, Peter Robinson wrote:
Then if for development you need to pull he history of lwip, you can do it with: git pull -s subtree lwip master --allow-unrelated-histories (but I think nobody will need this.)
New update of the lwip net/lwip/lwip-external dir will be done with: git pull -s subtree lwip master --allow-unrelated-histories --squash Squash commit also has to be git format-patch friendly.
If you are ok with that proposal I will send v9 with the first patch created with steps above.
We've gone through this before. The whole purpose of this is not having to maintain patches. Simon, instead of "I had problems in the past", can you elaborate a bit more?
Tom said he is fine with subtrees instead of submodules and I know for a fact EDK2 doesn't have too many issues with submodules. Their documentation is pretty clear on building and requires
git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init
Perhaps the situation has improved since you had issues?
While I don't really care how you solve this technically, I'd *strongly* be interested for U-Boot to use *unmodified* lwIP sources where an explicit reference to an lwIP commit is used. I'd rather integrate bugfixes for U-Boot into lwIP than having the sources drift apart.
Strongly agree here, we want to use upstream and all the combined development and reviews etc rather than forking off and ending up with yet another slightly different IP stack. The whole advantage of adopting LWIP is the advantage of combined security, features and bugs from a wide range of projects :-)
Yes, this is what I want as well, and why I'm perhaps more agreeable with the approaches where it's a lot harder for us to start forking things unintentionally. I gather submodule rather than subtree would be better for that case?

On Wed, 13 Sept 2023 at 19:14, Tom Rini trini@konsulko.com wrote:
On Wed, Sep 13, 2023 at 11:06:13AM +0100, Peter Robinson wrote:
Then if for development you need to pull he history of lwip, you
can do it with:
git pull -s subtree lwip master --allow-unrelated-histories (but I think nobody will need this.)
New update of the lwip net/lwip/lwip-external dir will be done with: git pull -s subtree lwip master --allow-unrelated-histories
--squash
Squash commit also has to be git format-patch friendly.
If you are ok with that proposal I will send v9 with the first
patch created with steps above.
We've gone through this before. The whole purpose of this is not having to maintain patches. Simon, instead of "I had problems in the past", can you elaborate a
bit more?
Tom said he is fine with subtrees instead of submodules and I know
for
a fact EDK2 doesn't have too many issues with submodules. Their documentation is pretty clear on building and requires
git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init
Perhaps the situation has improved since you had issues?
While I don't really care how you solve this technically, I'd
*strongly*
be interested for U-Boot to use *unmodified* lwIP sources where an explicit reference to an lwIP commit is used. I'd rather integrate bugfixes for U-Boot into lwIP than having the sources drift apart.
Strongly agree here, we want to use upstream and all the combined development and reviews etc rather than forking off and ending up with yet another slightly different IP stack. The whole advantage of adopting LWIP is the advantage of combined security, features and bugs from a wide range of projects :-)
Yes, this is what I want as well, and why I'm perhaps more agreeable with the approaches where it's a lot harder for us to start forking things unintentionally. I gather submodule rather than subtree would be better for that case?
-- Tom
Yes, submodule will be a much better solution for us. And I also don't think that today there are any issues with submodules. It works well of OE, RPM and DEB builds, distributions should not have problems with it.
BR, Maxim.

Hi,
On Wed, 13 Sept 2023 at 07:35, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Wed, 13 Sept 2023 at 19:14, Tom Rini trini@konsulko.com wrote:
On Wed, Sep 13, 2023 at 11:06:13AM +0100, Peter Robinson wrote:
Then if for development you need to pull he history of lwip, you can do it with: git pull -s subtree lwip master --allow-unrelated-histories (but I think nobody will need this.)
New update of the lwip net/lwip/lwip-external dir will be done with: git pull -s subtree lwip master --allow-unrelated-histories --squash Squash commit also has to be git format-patch friendly.
If you are ok with that proposal I will send v9 with the first patch created with steps above.
We've gone through this before. The whole purpose of this is not having to maintain patches. Simon, instead of "I had problems in the past", can you elaborate a bit more?
Tom said he is fine with subtrees instead of submodules and I know for a fact EDK2 doesn't have too many issues with submodules. Their documentation is pretty clear on building and requires
git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init
Perhaps the situation has improved since you had issues?
Nope.
While I don't really care how you solve this technically, I'd *strongly* be interested for U-Boot to use *unmodified* lwIP sources where an explicit reference to an lwIP commit is used. I'd rather integrate bugfixes for U-Boot into lwIP than having the sources drift apart.
Strongly agree here, we want to use upstream and all the combined development and reviews etc rather than forking off and ending up with yet another slightly different IP stack. The whole advantage of adopting LWIP is the advantage of combined security, features and bugs from a wide range of projects :-)
Yes, this is what I want as well, and why I'm perhaps more agreeable with the approaches where it's a lot harder for us to start forking things unintentionally. I gather submodule rather than subtree would be better for that case?
-- Tom
Yes, submodule will be a much better solution for us. And I also don't think that today there are any issues with submodules. It works well of OE, RPM and DEB builds, distributions should not have problems with it.
My particular experience is with coreboot. Some problems I have:
1. Updating the modules doesn't work and I need to reset, try the --init thing, fetch things manually, etc. etc. 2. In ChromiumOS coreboot we can't use submodules internally since each package has its own build script. E.g. we need to build coreboot separately from its blobs, fsp, external libraries, etc. At least there we can do this, but if U-Boot adopts a submodule for a core feature, this is going to create no end of problems. 3. It makes it impossible to patch lwip for any fix we need for a release 4. We still have to 'fast forward' to a new commit every now and then, which really is no easier than doing a merge commit for the changes since the last sync, is it?
Really, we need a maintainer for the lwip piece, if we are to adopt it. Using submodules is not a substitute for that.
Regards, Simon

On 21.09.2023 18:29, Simon Glass wrote:
Hi,
On Wed, 13 Sept 2023 at 07:35, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Wed, 13 Sept 2023 at 19:14, Tom Rini trini@konsulko.com wrote:
On Wed, Sep 13, 2023 at 11:06:13AM +0100, Peter Robinson wrote:
> Then if for development you need to pull he history of lwip, you can do it with: > git pull -s subtree lwip master --allow-unrelated-histories > (but I think nobody will need this.) > > New update of the lwip net/lwip/lwip-external dir will be done with: > git pull -s subtree lwip master --allow-unrelated-histories --squash > Squash commit also has to be git format-patch friendly. > > If you are ok with that proposal I will send v9 with the first patch created with steps above.
We've gone through this before. The whole purpose of this is not having to maintain patches. Simon, instead of "I had problems in the past", can you elaborate a bit more?
Tom said he is fine with subtrees instead of submodules and I know for a fact EDK2 doesn't have too many issues with submodules. Their documentation is pretty clear on building and requires
git clone https://github.com/tianocore/edk2.git cd edk2 git submodule update --init
Perhaps the situation has improved since you had issues?
Nope.
While I don't really care how you solve this technically, I'd *strongly* be interested for U-Boot to use *unmodified* lwIP sources where an explicit reference to an lwIP commit is used. I'd rather integrate bugfixes for U-Boot into lwIP than having the sources drift apart.
Strongly agree here, we want to use upstream and all the combined development and reviews etc rather than forking off and ending up with yet another slightly different IP stack. The whole advantage of adopting LWIP is the advantage of combined security, features and bugs from a wide range of projects :-)
Yes, this is what I want as well, and why I'm perhaps more agreeable with the approaches where it's a lot harder for us to start forking things unintentionally. I gather submodule rather than subtree would be better for that case?
-- Tom
Yes, submodule will be a much better solution for us. And I also don't think that today there are any issues with submodules. It works well of OE, RPM and DEB builds, distributions should not have problems with it.
My particular experience is with coreboot. Some problems I have:
- Updating the modules doesn't work and I need to reset, try the
--init thing, fetch things manually, etc. etc. 2. In ChromiumOS coreboot we can't use submodules internally since each package has its own build script. E.g. we need to build coreboot separately from its blobs, fsp, external libraries, etc. At least there we can do this, but if U-Boot adopts a submodule for a core feature, this is going to create no end of problems. 3. It makes it impossible to patch lwip for any fix we need for a release 4. We still have to 'fast forward' to a new commit every now and then, which really is no easier than doing a merge commit for the changes since the last sync, is it?
Really, we need a maintainer for the lwip piece, if we are to adopt it. Using submodules is not a substitute for that.
As an lwIP maintainer, I cannot step up as a maintainer of lwIP in U-Boot, however, I can assure you I will do my best to work with you on integrating fixes into upstream lwIP if required.
Without wanting to promote using submodules: all other examples of lwIP being copied into another repository have practically never resulted in bugfixes being sent back to us (ok, that's not 100% true, but we do get them only once in a while) and being like that, those projects are facing problems upgrading our stack in turn. I wouldn't want to be a maintainer of such code, either.
Regards, Simon

On Fri, Sep 22, 2023 at 12:56:58PM +0200, Simon Goldschmidt wrote:
On 21.09.2023 18:29, Simon Glass wrote:
Hi,
On Wed, 13 Sept 2023 at 07:35, Maxim Uvarov maxim.uvarov@linaro.org wrote:
On Wed, 13 Sept 2023 at 19:14, Tom Rini trini@konsulko.com wrote:
On Wed, Sep 13, 2023 at 11:06:13AM +0100, Peter Robinson wrote:
> > Then if for development you need to pull he history of lwip, you can do it with: > > git pull -s subtree lwip master --allow-unrelated-histories > > (but I think nobody will need this.) > > > > New update of the lwip net/lwip/lwip-external dir will be done with: > > git pull -s subtree lwip master --allow-unrelated-histories --squash > > Squash commit also has to be git format-patch friendly. > > > > If you are ok with that proposal I will send v9 with the first patch created with steps above. > > We've gone through this before. The whole purpose of this is not > having to maintain patches. > Simon, instead of "I had problems in the past", can you elaborate a bit more? > > Tom said he is fine with subtrees instead of submodules and I know for > a fact EDK2 doesn't have too many issues with submodules. > Their documentation is pretty clear on building and requires > > git clone https://github.com/tianocore/edk2.git > cd edk2 > git submodule update --init > > Perhaps the situation has improved since you had issues?
Nope.
While I don't really care how you solve this technically, I'd *strongly* be interested for U-Boot to use *unmodified* lwIP sources where an explicit reference to an lwIP commit is used. I'd rather integrate bugfixes for U-Boot into lwIP than having the sources drift apart.
Strongly agree here, we want to use upstream and all the combined development and reviews etc rather than forking off and ending up with yet another slightly different IP stack. The whole advantage of adopting LWIP is the advantage of combined security, features and bugs from a wide range of projects :-)
Yes, this is what I want as well, and why I'm perhaps more agreeable with the approaches where it's a lot harder for us to start forking things unintentionally. I gather submodule rather than subtree would be better for that case?
-- Tom
Yes, submodule will be a much better solution for us. And I also don't think that today there are any issues with submodules. It works well of OE, RPM and DEB builds, distributions should not have problems with it.
My particular experience is with coreboot. Some problems I have:
- Updating the modules doesn't work and I need to reset, try the
--init thing, fetch things manually, etc. etc. 2. In ChromiumOS coreboot we can't use submodules internally since each package has its own build script. E.g. we need to build coreboot separately from its blobs, fsp, external libraries, etc. At least there we can do this, but if U-Boot adopts a submodule for a core feature, this is going to create no end of problems. 3. It makes it impossible to patch lwip for any fix we need for a release 4. We still have to 'fast forward' to a new commit every now and then, which really is no easier than doing a merge commit for the changes since the last sync, is it?
Really, we need a maintainer for the lwip piece, if we are to adopt it. Using submodules is not a substitute for that.
As an lwIP maintainer, I cannot step up as a maintainer of lwIP in U-Boot, however, I can assure you I will do my best to work with you on integrating fixes into upstream lwIP if required.
Without wanting to promote using submodules: all other examples of lwIP being copied into another repository have practically never resulted in bugfixes being sent back to us (ok, that's not 100% true, but we do get them only once in a while) and being like that, those projects are facing problems upgrading our stack in turn. I wouldn't want to be a maintainer of such code, either.
So, ideally once we've integrated lwip, I'd be having us track the stable tags, rather than top of tree. Is this what you'd recommend, first of all? And second, assuming we can take STABLE_2_2_0 once it's released how often do you envision updates? I ask since maybe things do move slow enough that if I make some of my local every-time test scripts stop and confirm it's OK to have some changes to net/ (or where ever...) I can make sure we don't diverge and then like the calendar entries I do have to remind me to check with a resync to X I could do that for lwip.
participants (6)
-
Ilias Apalodimas
-
Maxim Uvarov
-
Peter Robinson
-
Simon Glass
-
Simon Goldschmidt
-
Tom Rini