[PATCH v4] net: lwip: add tftpsrv command
Jerome Forissier
jerome.forissier at arm.com
Thu Jul 9 11:10:02 CEST 2026
On 08/07/2026 21:31, James Hilliard wrote:
> The legacy network stack supports tftpsrv, which listens for an
> incoming TFTP write request and receives the first file into memory.
> Despite the old command help wording, the command returns after
> receiving the file and does not boot it automatically.
>
> The lwIP stack already builds the lwIP TFTP application, but only wires
> it up for client-side tftpboot. Add a lwIP tftpsrv command and
> implement the server path with tftp_init_server(). Reuse the existing
> lwIP TFTP write callback and memory copy path so LMB checks, progress
> output, filesize/fileaddr updates and EFI bootdev handling stay
> consistent with tftpboot.
>
> Track receive timeout and write-failure state around the lwIP callbacks
> so a stalled or rejected receive is not reported as a successful close.
>
> Move CMD_TFTPSRV out of the legacy-only Kconfig block so it can be
> enabled with either network stack. Update the command help text and add
> usage documentation for the receive-only behavior.
>
> Add pytest coverage for tftpsrv using a generated host file and curl's
> TFTP upload support. Enable the command in qemu_arm64_lwip_defconfig so
> the test can be run with the existing lwIP QEMU build when the boardenv
> provides env__net_tftpsrv_file.
>
> Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
> ---
> Changes v3 -> v4:
> - Match lwIP TFTP filename length with legacy TFTP
> - Keep the server transfer context on the stack
> - Use the existing net_lwip_eth_stop() helper after tftpsrv exits
>
> Changes v2 -> v3:
> - Use an explicit TFTPSRV_LISTEN_TIMEOUT_MS value
> - Allocate the server transfer context dynamically
> - Halt the lwIP Ethernet device after tftpsrv exits
>
> Changes v1 -> v2:
> - Add tftpsrv usage documentation (suggested by Quentin Schulz)
> - Add tftpsrv pytest coverage (suggested by Quentin Schulz)
> - Enable CMD_TFTPSRV in qemu_arm64_lwip_defconfig
> - Allow tftpsrv pytest coverage to use an explicit upload URL
> - Keep tftpsrv pytest coverage gated by env__net_tftpsrv_file
> - Clarify that tftpsrv returns after receiving instead of booting
> - Update legacy and lwIP command help text for receive-only behavior
> ---
> cmd/Kconfig | 14 ++-
> cmd/lwip/Makefile | 1 +
> cmd/lwip/tftpsrv.c | 11 ++
> cmd/net.c | 4 +-
> configs/qemu_arm64_lwip_defconfig | 1 +
> doc/usage/cmd/tftpsrv.rst | 73 ++++++++++++
> include/net-lwip.h | 1 +
> lib/lwip/u-boot/lwipopts.h | 11 ++
> net/lwip/tftp.c | 188 +++++++++++++++++++++++++++++-
> test/py/tests/test_net.py | 94 +++++++++++++++
> 10 files changed, 385 insertions(+), 13 deletions(-)
> create mode 100644 cmd/lwip/tftpsrv.c
> create mode 100644 doc/usage/cmd/tftpsrv.rst
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index ca1039f6a03..c9a6c7c33a2 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -2134,12 +2134,6 @@ config CMD_TFTPPUT
> help
> TFTP put command, for uploading files to a server
>
> -config CMD_TFTPSRV
> - bool "tftpsrv"
> - depends on CMD_TFTPBOOT
> - help
> - Act as a TFTP server and boot the first received file
> -
> config NET_TFTP_VARS
> bool "Control TFTP timeout and count through environment"
> depends on CMD_TFTPBOOT
> @@ -2286,6 +2280,14 @@ config CMD_TFTPBOOT
> help
> tftpboot - load file via network using TFTP protocol
>
> +config CMD_TFTPSRV
> + bool "tftpsrv"
> + depends on CMD_TFTPBOOT
> + help
> + Act as a TFTP server and receive the first incoming file into
> + memory. The command returns successfully after the transfer so
> + boot scripts can boot the received image from the load address.
> +
> config CMD_WGET
> bool "wget"
> default y if SANDBOX || ARCH_QEMU
> diff --git a/cmd/lwip/Makefile b/cmd/lwip/Makefile
> index 90df1f5511c..245683a9672 100644
> --- a/cmd/lwip/Makefile
> +++ b/cmd/lwip/Makefile
> @@ -4,4 +4,5 @@ obj-$(CONFIG_CMD_NFS) += nfs.o
> obj-$(CONFIG_CMD_PING) += ping.o
> obj-$(CONFIG_CMD_SNTP) += sntp.o
> obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
> +obj-$(CONFIG_CMD_TFTPSRV) += tftpsrv.o
> obj-$(CONFIG_CMD_WGET) += wget.o
> diff --git a/cmd/lwip/tftpsrv.c b/cmd/lwip/tftpsrv.c
> new file mode 100644
> index 00000000000..6370c900489
> --- /dev/null
> +++ b/cmd/lwip/tftpsrv.c
> @@ -0,0 +1,11 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <command.h>
> +#include <net.h>
> +
> +U_BOOT_CMD(tftpsrv, 2, 1, do_tftpsrv,
> + "act as a TFTP server and receive the first file",
> + "[loadAddress]\n"
> + "Listen for an incoming TFTP transfer and receive a file into memory.\n"
> + "The transfer is aborted if a transfer has not been started after\n"
> + "about 50 seconds or if Ctrl-C is pressed.");
> diff --git a/cmd/net.c b/cmd/net.c
> index f6f556f36ae..0f0b2386d87 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -89,9 +89,9 @@ static int do_tftpsrv(struct cmd_tbl *cmdtp, int flag, int argc,
>
> U_BOOT_CMD(
> tftpsrv, 2, 1, do_tftpsrv,
> - "act as a TFTP server and boot the first received file",
> + "act as a TFTP server and receive the first file",
> "[loadAddress]\n"
> - "Listen for an incoming TFTP transfer, receive a file and boot it.\n"
> + "Listen for an incoming TFTP transfer and receive a file into memory.\n"
> "The transfer is aborted if a transfer has not been started after\n"
> "about 50 seconds or if Ctrl-C is pressed."
> );
> diff --git a/configs/qemu_arm64_lwip_defconfig b/configs/qemu_arm64_lwip_defconfig
> index a974970c3d3..06ed5a131db 100644
> --- a/configs/qemu_arm64_lwip_defconfig
> +++ b/configs/qemu_arm64_lwip_defconfig
> @@ -7,6 +7,7 @@ CONFIG_NET_LWIP=y
> CONFIG_CMD_DNS=y
> CONFIG_CMD_NFS=y
> CONFIG_CMD_SNTP=y
> +CONFIG_CMD_TFTPSRV=y
> CONFIG_CMD_WGET=y
> CONFIG_EFI_HTTP_BOOT=y
> CONFIG_WGET_HTTPS=y
> diff --git a/doc/usage/cmd/tftpsrv.rst b/doc/usage/cmd/tftpsrv.rst
> new file mode 100644
> index 00000000000..597a2f3a8bd
> --- /dev/null
> +++ b/doc/usage/cmd/tftpsrv.rst
> @@ -0,0 +1,73 @@
> +.. SPDX-License-Identifier: GPL-2.0+:
Extra ':' character. No need to respin, I can remove it when taking
the patch.
Reviewed-by: Jerome Forissier <jerome.forissier at arm.com>
Thanks,
--
Jerome
More information about the U-Boot
mailing list