diff options
author | Rasmus Villemoes <rasmus.villemoes@prevas.dk> | 2022-10-14 19:43:42 +0200 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-11-28 13:06:39 -0500 |
commit | 087648b5df8db0d4786ff86e61e7616ebc181cf4 (patch) | |
tree | 9e0635e1420af60923b95b421b9436dd2e018da3 | |
parent | 4b8c44e39c9eb1717831e3b3f31c33e0932b0767 (diff) | |
download | u-boot-087648b5df8db0d4786ff86e61e7616ebc181cf4.zip u-boot-087648b5df8db0d4786ff86e61e7616ebc181cf4.tar.gz u-boot-087648b5df8db0d4786ff86e61e7616ebc181cf4.tar.bz2 |
net: tftp: sanitize tftp block size, especially for TX
U-Boot does not support IP fragmentation on TX (and unless
CONFIG_IP_DEFRAG is set, neither on RX). So the blocks we send must
fit in a single ethernet packet.
Currently, if tftpblocksize is set to something like 5000 and I
tftpput a large enough file, U-Boot crashes because we overflow
net_tx_packet (which only has room for 1500 bytes plus change).
Similarly, if tftpblocksize is set to something larger than what we
can actually receive (e.g. 50000, with NET_MAXDEFRAG being 16384), any
tftp get just hangs because we never receive any packets.
Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
-rw-r--r-- | net/tftp.c | 47 |
1 files changed, 47 insertions, 0 deletions
@@ -708,9 +708,54 @@ static int tftp_init_load_addr(void) return 0; } +static int saved_tftp_block_size_option; +static void sanitize_tftp_block_size_option(enum proto_t protocol) +{ + int cap, max_defrag; + + switch (protocol) { + case TFTPGET: + max_defrag = config_opt_enabled(CONFIG_IP_DEFRAG, CONFIG_NET_MAXDEFRAG, 0); + if (max_defrag) { + /* Account for IP, UDP and TFTP headers. */ + cap = max_defrag - (20 + 8 + 4); + /* RFC2348 sets a hard upper limit. */ + cap = min(cap, 65464); + break; + } + /* + * If not CONFIG_IP_DEFRAG, cap at the same value as + * for tftp put, namely normal MTU minus protocol + * overhead. + */ + fallthrough; + case TFTPPUT: + default: + /* + * U-Boot does not support IP fragmentation on TX, so + * this must be small enough that it fits normal MTU + * (and small enough that it fits net_tx_packet which + * has room for PKTSIZE_ALIGN bytes). + */ + cap = 1468; + } + if (tftp_block_size_option > cap) { + printf("Capping tftp block size option to %d (was %d)\n", + cap, tftp_block_size_option); + saved_tftp_block_size_option = tftp_block_size_option; + tftp_block_size_option = cap; + } +} + void tftp_start(enum proto_t protocol) { __maybe_unused char *ep; /* Environment pointer */ + + if (saved_tftp_block_size_option) { + tftp_block_size_option = saved_tftp_block_size_option; + saved_tftp_block_size_option = 0; + } + if (IS_ENABLED(CONFIG_NET_TFTP_VARS)) { /* @@ -747,6 +792,8 @@ void tftp_start(enum proto_t protocol) } } + sanitize_tftp_block_size_option(protocol); + debug("TFTP blocksize = %i, TFTP windowsize = %d timeout = %ld ms\n", tftp_block_size_option, tftp_window_size_option, timeout_ms); |