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 <[email protected]> > --- > 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 <[email protected]> Thanks, -- Jerome

