|
|
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 |
|