mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
To: barebox@lists.infradead.org
Cc: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
Subject: [PATCH 5/8] tftp: support non rfc 2347 servers
Date: Sun, 28 Aug 2022 16:02:28 +0200	[thread overview]
Message-ID: <20220828140231.930643-6-enrico.scholz@sigma-chemnitz.de> (raw)
In-Reply-To: <20220828140231.930643-1-enrico.scholz@sigma-chemnitz.de>

State machine must be changed for servers without OACK support.  Here,
objects for data transfer must be allocated before the first datagram
is handled and it is possible that whole transfer finishes at this
point.

Fixes "tftp: allocate buffers and fifo dynamically"

Signed-off-by: Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
---
 fs/tftp.c | 87 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 58 insertions(+), 29 deletions(-)

diff --git a/fs/tftp.c b/fs/tftp.c
index fb6c368b3a64..7edea904aabe 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -64,13 +64,12 @@
 #define STATE_WRQ	2
 #define STATE_RDATA	3
 #define STATE_WDATA	4
-#define STATE_OACK	5
+/* OACK from server has been received and we can begin to sent either the ACK
+   (for RRQ) or data (for WRQ) */
+#define STATE_START	5
 #define STATE_WAITACK	6
 #define STATE_LAST	7
 #define STATE_DONE	8
-/* OACK from server has been received and we can begin to sent either the ACK
-   (for RRQ) or data (for WRQ) */
-#define STATE_START	9
 
 #define TFTP_BLOCK_SIZE		512	/* default TFTP block size */
 #define TFTP_MTU_SIZE		1432	/* MTU based block size */
@@ -363,7 +362,6 @@ static char const * const tftp_states[] = {
 	[STATE_WRQ] = "WRQ",
 	[STATE_RDATA] = "RDATA",
 	[STATE_WDATA] = "WDATA",
-	[STATE_OACK] = "OACK",
 	[STATE_WAITACK] = "WAITACK",
 	[STATE_LAST] = "LAST",
 	[STATE_DONE] = "DONE",
@@ -431,7 +429,6 @@ static int tftp_send(struct file_priv *priv)
 		break;
 
 	case STATE_RDATA:
-	case STATE_OACK:
 		xp = pkt;
 		s = (uint16_t *)pkt;
 		*s++ = htons(TFTP_ACK);
@@ -649,6 +646,7 @@ static void tftp_recv(struct file_priv *priv,
 {
 	uint16_t opcode;
 	uint16_t block;
+	int rc;
 
 	/* according to RFC1350 minimal tftp packet length is 4 bytes */
 	if (len < 4)
@@ -711,12 +709,20 @@ static void tftp_recv(struct file_priv *priv,
 		len -= 2;
 		block = ntohs(*(uint16_t *)pkt);
 
-		if (priv->state == STATE_RRQ || priv->state == STATE_OACK) {
-			/* first block received */
-			priv->state = STATE_RDATA;
+		if (priv->state == STATE_RRQ) {
+			/* first block received; entered only with non rfc
+			   2347 (TFTP Option extension) compliant servers */
 			priv->tftp_con->udp->uh_dport = uh_sport;
+			priv->state = STATE_RDATA;
 			priv->last_block = 0;
-			tftp_window_cache_reset(&priv->cache);
+			priv->ack_block = priv->windowsize;
+
+			rc = tftp_allocate_transfer(priv);
+			if (rc < 0) {
+				priv->err = rc;
+				priv->state = STATE_DONE;
+				break;
+			}
 		}
 
 		if (priv->state != STATE_RDATA) {
@@ -726,7 +732,6 @@ static void tftp_recv(struct file_priv *priv,
 		}
 
 		tftp_handle_data(priv, block, pkt + 2, len);
-
 		break;
 
 	case TFTP_ERROR:
@@ -775,7 +780,7 @@ static int tftp_start_transfer(struct file_priv *priv)
 		priv->block = 1;
 	} else {
 		/* send ACK */
-		priv->state = STATE_OACK;
+		priv->state = STATE_RDATA;
 		priv->last_block = 0;
 		tftp_send(priv);
 	}
@@ -828,26 +833,49 @@ static struct file_priv *tftp_do_open(struct device_d *dev,
 		goto out1;
 
 	tftp_timer_reset(priv);
-	while (priv->state != STATE_DONE && priv->state != STATE_START) {
-		ret = tftp_poll(priv);
-		if (ret == TFTP_ERR_RESEND)
-			tftp_send(priv);
-		if (ret < 0)
-			goto out1;
-	}
 
-	if (priv->state == STATE_DONE) {
-		/* this should not happen; STATE_DONE without error happens
-		   after completing the transfer but this has not been started
-		   yet */
-		if (WARN_ON(priv->err == 0))
-			priv->err = -EIO;
+	/* - 'ret < 0'  ... error
+	   - 'ret == 0' ... further tftp_poll() required
+	   - 'ret == 1' ... startup finished */
+	do {
+		switch (priv->state) {
+		case STATE_DONE:
+			/* branch is entered in two situations:
+			   - non rfc 2347 compliant servers finished the
+			     transfer by sending a small file
+			   - some error occurred */
+			if (priv->err < 0)
+				ret = priv->err;
+			else
+				ret = 1;
+			break;
 
-		ret = priv->err;
-		goto out1;
-	}
+		case STATE_START:
+			ret = tftp_start_transfer(priv);
+			if (!ret)
+				ret = 1;
+			break;
+
+		case STATE_RDATA:
+			/* first data block of non rfc 2347 servers */
+			ret = 1;
+			break;
+
+		case STATE_RRQ:
+		case STATE_WRQ:
+			ret = tftp_poll(priv);
+			if (ret == TFTP_ERR_RESEND) {
+				tftp_send(priv);
+				ret = 0;
+			}
+			break;
+
+		default:
+			debug_assert(false);
+			break;
+		}
+	} while (ret == 0);
 
-	ret = tftp_start_transfer(priv);
 	if (ret < 0)
 		goto out1;
 
@@ -855,6 +883,7 @@ static struct file_priv *tftp_do_open(struct device_d *dev,
 out1:
 	net_unregister(priv->tftp_con);
 out:
+	debug_assert(!priv->fifo);
 	free(priv);
 
 	return ERR_PTR(ret);
-- 
2.37.2




  parent reply	other threads:[~2022-08-28 14:05 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-28 14:02 [PATCH 0/8] tftp fixups Enrico Scholz
2022-08-28 14:02 ` [PATCH 1/8] tftp: make debug_assert() critical when selftest is enabled Enrico Scholz
2022-08-28 14:02 ` [PATCH 2/8] tftp: remove sanity check of first block Enrico Scholz
2022-08-28 14:02 ` [PATCH 3/8] tftp: split out allocation and cache initialization Enrico Scholz
2022-08-28 14:02 ` [PATCH 4/8] tftp: accept OACK + DATA datagrams only in certain states Enrico Scholz
2022-08-28 14:02 ` Enrico Scholz [this message]
2022-08-28 14:02 ` [PATCH 6/8] tftp: do not set 'tsize' in wrq requests Enrico Scholz
2022-08-28 14:02 ` [PATCH 7/8] tftp: fix WRQ support Enrico Scholz
2022-08-28 14:02 ` [PATCH 8/8] tftp: add some documentation about windowsize support Enrico Scholz
2022-08-29 10:52 ` [PATCH 0/8] tftp fixups Ahmad Fatoum
2022-08-30  7:30   ` Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220828140231.930643-6-enrico.scholz@sigma-chemnitz.de \
    --to=enrico.scholz@sigma-chemnitz.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox