On Fri, Oct 14, 2022 at 8:44 PM Rasmus Villemoes
<rasmus.villem...@prevas.dk> wrote:
>
> 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.villem...@prevas.dk>
> ---
> net/tftp.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 46 insertions(+)
>
> diff --git a/net/tftp.c b/net/tftp.c
> index e5e140bcd5..60e1273332 100644
> --- a/net/tftp.c
> +++ b/net/tftp.c
> @@ -708,8 +708,52 @@ 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.
> + */
> + /* fall through */
> + 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)
> {
> + 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)) {
> char *ep; /* Environment pointer */
>
> @@ -747,6 +791,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);
>
> --
> 2.37.2
>
Reviewed-by: Ramon Fried <rfried....@gmail.com>