summaryrefslogtreecommitdiff
path: root/net/tftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tftp.c')
-rw-r--r--net/tftp.c103
1 files changed, 75 insertions, 28 deletions
diff --git a/net/tftp.c b/net/tftp.c
index dea9c25ffd8..39421f8daa7 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -708,44 +708,91 @@ 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)
{
-#if CONFIG_NET_TFTP_VARS
- char *ep; /* Environment pointer */
+ __maybe_unused char *ep; /* Environment pointer */
- /*
- * Allow the user to choose TFTP blocksize and timeout.
- * TFTP protocol has a minimal timeout of 1 second.
- */
+ if (saved_tftp_block_size_option) {
+ tftp_block_size_option = saved_tftp_block_size_option;
+ saved_tftp_block_size_option = 0;
+ }
- ep = env_get("tftpblocksize");
- if (ep != NULL)
- tftp_block_size_option = simple_strtol(ep, NULL, 10);
+ if (IS_ENABLED(CONFIG_NET_TFTP_VARS)) {
- ep = env_get("tftpwindowsize");
- if (ep != NULL)
- tftp_window_size_option = simple_strtol(ep, NULL, 10);
+ /*
+ * Allow the user to choose TFTP blocksize and timeout.
+ * TFTP protocol has a minimal timeout of 1 second.
+ */
- ep = env_get("tftptimeout");
- if (ep != NULL)
- timeout_ms = simple_strtol(ep, NULL, 10);
+ ep = env_get("tftpblocksize");
+ if (ep != NULL)
+ tftp_block_size_option = simple_strtol(ep, NULL, 10);
- if (timeout_ms < 1000) {
- printf("TFTP timeout (%ld ms) too low, set min = 1000 ms\n",
- timeout_ms);
- timeout_ms = 1000;
- }
+ ep = env_get("tftpwindowsize");
+ if (ep != NULL)
+ tftp_window_size_option = simple_strtol(ep, NULL, 10);
- ep = env_get("tftptimeoutcountmax");
- if (ep != NULL)
- tftp_timeout_count_max = simple_strtol(ep, NULL, 10);
+ ep = env_get("tftptimeout");
+ if (ep != NULL)
+ timeout_ms = simple_strtol(ep, NULL, 10);
+
+ if (timeout_ms < 1000) {
+ printf("TFTP timeout (%ld ms) too low, set min = 1000 ms\n",
+ timeout_ms);
+ timeout_ms = 1000;
+ }
+
+ ep = env_get("tftptimeoutcountmax");
+ if (ep != NULL)
+ tftp_timeout_count_max = simple_strtol(ep, NULL, 10);
- if (tftp_timeout_count_max < 0) {
- printf("TFTP timeout count max (%d ms) negative, set to 0\n",
- tftp_timeout_count_max);
- tftp_timeout_count_max = 0;
+ if (tftp_timeout_count_max < 0) {
+ printf("TFTP timeout count max (%d ms) negative, set to 0\n",
+ tftp_timeout_count_max);
+ tftp_timeout_count_max = 0;
+ }
}
-#endif
+
+ 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);