Blame 0179-slirp-Implement-TFTP-Blocksize-option.patch

5544c1
From e070dc7276c7958c322ca0fbf5ac10e639502b4d Mon Sep 17 00:00:00 2001
5544c1
From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= <hpoussin@reactos.org>
5544c1
Date: Thu, 13 Sep 2012 07:55:01 +0200
5544c1
Subject: [PATCH] slirp: Implement TFTP Blocksize option
5544c1
MIME-Version: 1.0
5544c1
Content-Type: text/plain; charset=UTF-8
5544c1
Content-Transfer-Encoding: 8bit
5544c1
5544c1
This option is described in RFC 1783. As this is only an optional field,
5544c1
we may ignore it in some situations and handle it in some others.
5544c1
5544c1
However, MS Windows 2003 PXE boot client requests a block size of the MTU
5544c1
(most of the times 1472 bytes), and doesn't work if the option is not
5544c1
acknowledged (with whatever value).
5544c1
5544c1
According to the RFC 1783, we cannot acknowledge the option with a bigger
5544c1
value than the requested one.
5544c1
5544c1
As current implementation is using 512 bytes by block, accept the option
5544c1
with a value of 512 if the option was specified, and don't acknowledge it
5544c1
if it is not present or less than 512 bytes.
5544c1
5544c1
Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
5544c1
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
5544c1
(cherry picked from commit 95b1ad7ad86793c27ab8e9987be69571937900d1)
5544c1
5544c1
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
5544c1
---
5544c1
 slirp/tftp.c | 42 +++++++++++++++++++++++++++++++++---------
5544c1
 1 file changed, 33 insertions(+), 9 deletions(-)
5544c1
5544c1
diff --git a/slirp/tftp.c b/slirp/tftp.c
5544c1
index c6a5df2..37b0387 100644
5544c1
--- a/slirp/tftp.c
5544c1
+++ b/slirp/tftp.c
5544c1
@@ -120,13 +120,13 @@ static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
5544c1
 }
5544c1
 
5544c1
 static int tftp_send_oack(struct tftp_session *spt,
5544c1
-                          const char *key, uint32_t value,
5544c1
+                          const char *keys[], uint32_t values[], int nb,
5544c1
                           struct tftp_t *recv_tp)
5544c1
 {
5544c1
     struct sockaddr_in saddr, daddr;
5544c1
     struct mbuf *m;
5544c1
     struct tftp_t *tp;
5544c1
-    int n = 0;
5544c1
+    int i, n = 0;
5544c1
 
5544c1
     m = m_get(spt->slirp);
5544c1
 
5544c1
@@ -140,10 +140,12 @@ static int tftp_send_oack(struct tftp_session *spt,
5544c1
     m->m_data += sizeof(struct udpiphdr);
5544c1
 
5544c1
     tp->tp_op = htons(TFTP_OACK);
5544c1
-    n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
5544c1
-                  key) + 1;
5544c1
-    n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
5544c1
-                  value) + 1;
5544c1
+    for (i = 0; i < nb; i++) {
5544c1
+        n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s",
5544c1
+                      keys[i]) + 1;
5544c1
+        n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u",
5544c1
+                      values[i]) + 1;
5544c1
+    }
5544c1
 
5544c1
     saddr.sin_addr = recv_tp->ip.ip_dst;
5544c1
     saddr.sin_port = recv_tp->udp.uh_dport;
5544c1
@@ -260,6 +262,9 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
5544c1
   int s, k;
5544c1
   size_t prefix_len;
5544c1
   char *req_fname;
5544c1
+  const char *option_name[2];
5544c1
+  uint32_t option_value[2];
5544c1
+  int nb_options = 0;
5544c1
 
5544c1
   /* check if a session already exists and if so terminate it */
5544c1
   s = tftp_session_find(slirp, tp);
5544c1
@@ -337,7 +342,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
5544c1
       return;
5544c1
   }
5544c1
 
5544c1
-  while (k < pktlen) {
5544c1
+  while (k < pktlen && nb_options < ARRAY_SIZE(option_name)) {
5544c1
       const char *key, *value;
5544c1
 
5544c1
       key = &tp->x.tp_buf[k];
5544c1
@@ -364,11 +369,30 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
5544c1
 	      }
5544c1
 	  }
5544c1
 
5544c1
-	  tftp_send_oack(spt, "tsize", tsize, tp);
5544c1
-	  return;
5544c1
+          option_name[nb_options] = "tsize";
5544c1
+          option_value[nb_options] = tsize;
5544c1
+          nb_options++;
5544c1
+      } else if (strcasecmp(key, "blksize") == 0) {
5544c1
+          int blksize = atoi(value);
5544c1
+
5544c1
+          /* If blksize option is bigger than what we will
5544c1
+           * emit, accept the option with our packet size.
5544c1
+           * Otherwise, simply do as we didn't see the option.
5544c1
+           */
5544c1
+          if (blksize >= 512) {
5544c1
+              option_name[nb_options] = "blksize";
5544c1
+              option_value[nb_options] = 512;
5544c1
+              nb_options++;
5544c1
+          }
5544c1
       }
5544c1
   }
5544c1
 
5544c1
+  if (nb_options > 0) {
5544c1
+      assert(nb_options <= ARRAY_SIZE(option_name));
5544c1
+      tftp_send_oack(spt, option_name, option_value, nb_options, tp);
5544c1
+      return;
5544c1
+  }
5544c1
+
5544c1
   spt->block_nr = 0;
5544c1
   tftp_send_next_block(spt, tp);
5544c1
 }
5544c1
-- 
5544c1
1.7.12.1
5544c1