[U-Boot] [PATCH 7/8] tftpput: implement tftp logic
Simon Glass
sjg at chromium.org
Sat Oct 22 06:51:39 CEST 2011
This adds logic to tftp.c to implement the tftp 'put' command, and
updates the README.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
README | 2 +
net/net.c | 4 ++
net/tftp.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++----------
3 files changed, 100 insertions(+), 20 deletions(-)
diff --git a/README b/README
index 7e032a9..8261bfb 100644
--- a/README
+++ b/README
@@ -784,6 +784,7 @@ The following options need to be configured:
CONFIG_CMD_SOURCE "source" command Support
CONFIG_CMD_SPI * SPI serial bus support
CONFIG_CMD_TFTPSRV * TFTP transfer in server mode
+ CONFIG_CMD_TFTPPUT * TFTP put command (upload)
CONFIG_CMD_TIME * run command and report execution time
CONFIG_CMD_USB * USB support
CONFIG_CMD_CDP * Cisco Discover Protocol support
@@ -3340,6 +3341,7 @@ bootp - boot image via network using BootP/TFTP protocol
tftpboot- boot image via network using TFTP protocol
and env variables "ipaddr" and "serverip"
(and eventually "gatewayip")
+tftpput - upload a file via network using TFTP protocol
rarpboot- boot image via network using RARP/TFTP protocol
diskboot- boot from IDE devicebootd - boot default, i.e., run 'bootcmd'
loads - load S-Record file over serial line
diff --git a/net/net.c b/net/net.c
index ce07ed6..89596d3 100644
--- a/net/net.c
+++ b/net/net.c
@@ -406,6 +406,9 @@ restart:
NetBootFileXferSize = 0;
switch (protocol) {
case TFTPGET:
+#ifdef CONFIG_CMD_TFTPPUT
+ case TFTPPUT:
+#endif
/* always use ARP to get server ethernet address */
TftpStart(protocol);
break;
@@ -1758,6 +1761,7 @@ static int net_check_prereq(enum proto_t protocol)
case NFS:
#endif
case TFTPGET:
+ case TFTPPUT:
if (NetServerIP == 0) {
puts("*** ERROR: `serverip' not set\n");
return 1;
diff --git a/net/tftp.c b/net/tftp.c
index 3a58e32..02862c6 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -82,6 +82,11 @@ static int TftpTsize;
static short TftpNumchars;
#endif
static int TftpWriting; /* 1 if writing, else 0 */
+#ifdef CONFIG_CMD_TFTPPUT
+static int TftpFinalBlock; /* 1 if we have sent the last block */
+#else
+#define TftpWriting 0
+#endif
#define STATE_SEND_RRQ 1
#define STATE_DATA 2
@@ -89,6 +94,7 @@ static int TftpWriting; /* 1 if writing, else 0 */
#define STATE_BAD_MAGIC 4
#define STATE_OACK 5
#define STATE_RECV_WRQ 6
+#define STATE_SEND_WRQ 7
/* default TFTP block size */
#define TFTP_BLOCK_SIZE 512
@@ -191,6 +197,28 @@ store_block(unsigned block, uchar *src, unsigned len)
NetBootFileXferSize = newsize;
}
+#ifdef CONFIG_CMD_TFTPPUT
+/**
+ * Load the next block from memory to be sent over tftp.
+ *
+ * @param block Block number to send
+ * @param dst Destination buffer for data
+ * @param len Number of bytes in block (this one and every other)
+ * @return number of bytes loaded
+ */
+static int load_block(unsigned block, uchar *dst, unsigned len)
+{
+ ulong offset = (block - 1) * len + TftpBlockWrapOffset;
+ ulong tosend = len;
+
+ tosend = min(NetBootFileXferSize - offset, tosend);
+ (void)memcpy(dst, (void *)(save_addr + offset), tosend);
+ debug("%s: block=%d, offset=%ld, len=%d, tosend=%ld\n", __func__,
+ block, offset, len, tosend);
+ return tosend;
+}
+#endif
+
static void TftpSend(void);
static void TftpTimeout(void);
@@ -235,7 +263,7 @@ static void tftp_complete(void)
static void
TftpSend(void)
{
- volatile uchar *pkt;
+ uchar *pkt;
volatile uchar *xp;
int len = 0;
volatile ushort *s;
@@ -251,14 +279,15 @@ TftpSend(void)
* We will always be sending some sort of packet, so
* cobble together the packet headers now.
*/
- pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
+ pkt = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE);
switch (TftpState) {
-
case STATE_SEND_RRQ:
+ case STATE_SEND_WRQ:
xp = pkt;
s = (ushort *)pkt;
- *s++ = htons(TFTP_RRQ);
+ *s++ = htons(TftpState == STATE_SEND_RRQ ? TFTP_RRQ
+ : TFTP_WRQ);
pkt = (uchar *)s;
strcpy((char *)pkt, tftp_filename);
pkt += strlen(tftp_filename) + 1;
@@ -270,8 +299,8 @@ TftpSend(void)
debug("send option \"timeout %s\"\n", (char *)pkt);
pkt += strlen((char *)pkt) + 1;
#ifdef CONFIG_TFTP_TSIZE
- memcpy((char *)pkt, "tsize\0000\0", 8);
- pkt += 8;
+ pkt += sprintf((char *)pkt, "tsize%c%lu%c",
+ 0, NetBootFileXferSize, 0);
#endif
/* try for more effic. blk size */
pkt += sprintf((char *)pkt, "blksize%c%d%c",
@@ -302,9 +331,19 @@ TftpSend(void)
case STATE_DATA:
xp = pkt;
s = (ushort *)pkt;
- *s++ = htons(TFTP_ACK);
- *s++ = htons(TftpBlock);
- pkt = (uchar *)s;
+ s[0] = htons(TFTP_ACK);
+ s[1] = htons(TftpBlock);
+ pkt = (uchar *)(s + 2);
+#ifdef CONFIG_CMD_TFTPPUT
+ if (TftpWriting) {
+ int toload = TftpBlkSize;
+ int loaded = load_block(TftpBlock, pkt, toload);
+
+ s[0] = htons(TFTP_DATA);
+ pkt += loaded;
+ TftpFinalBlock = (loaded < toload);
+ }
+#endif
len = pkt - xp;
break;
@@ -312,7 +351,8 @@ TftpSend(void)
xp = pkt;
s = (ushort *)pkt;
*s++ = htons(TFTP_ERROR);
- *s++ = htons(3);
+ *s++ = htons(3);
+
pkt = (uchar *)s;
strcpy((char *)pkt, "File too large");
pkt += 14 /*strlen("File too large")*/ + 1;
@@ -342,7 +382,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
{
ushort proto;
ushort *s;
- int i;
+ int i, block;
if (dest != TftpOurPort) {
#ifdef CONFIG_MCAST_TFTP
@@ -352,7 +392,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
return;
}
if (TftpState != STATE_SEND_RRQ && src != TftpRemotePort &&
- TftpState != STATE_RECV_WRQ)
+ TftpState != STATE_RECV_WRQ && TftpState != STATE_SEND_WRQ)
return;
if (len < 2)
@@ -362,11 +402,28 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
s = (ushort *)pkt;
proto = *s++;
pkt = (uchar *)s;
+ block = ntohs(*s);
switch (ntohs(proto)) {
case TFTP_RRQ:
+ break;
+
case TFTP_ACK:
+#ifdef CONFIG_CMD_TFTPPUT
+ debug("Ack block %d\n", block);
+ show_block_marker();
+ if (TftpWriting) {
+ if (TftpFinalBlock) {
+ tftp_complete();
+ } else {
+ TftpBlock = block + 1;
+ show_block_marker();
+ TftpSend(); /* Send next data block */
+ }
+ }
+#endif
break;
+
default:
break;
@@ -417,7 +474,14 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
TftpState = STATE_DATA; /* passive.. */
else
#endif
- TftpSend(); /* Send ACK */
+#ifdef CONFIG_CMD_TFTPPUT
+ if (TftpWriting) {
+ /* Get ready to send the first block */
+ TftpState = STATE_DATA;
+ TftpBlock++;
+ }
+#endif
+ TftpSend(); /* Send ACK or first data block */
break;
case TFTP_DATA:
if (len < 2)
@@ -626,8 +690,8 @@ void TftpStart(proto_t protocol)
}
printf("Using %s device\n", eth_get_name());
- printf("TFTP from server %pI4"
- "; our IP address is %pI4", &TftpRemoteIP, &NetOurIP);
+ printf("TFTP %s server %pI4; our IP address is %pI4",
+ protocol == TFTPPUT ? "to" : "from", &TftpRemoteIP, &NetOurIP);
/* Check if we need to send across this subnet */
if (NetOurGatewayIP && NetOurSubnetMask) {
@@ -649,10 +713,21 @@ void TftpStart(proto_t protocol)
putc('\n');
TftpWriting = (protocol == TFTPPUT);
-
- printf("Load address: 0x%lx\n", load_addr);
-
- puts("Loading: *\b");
+#ifdef CONFIG_CMD_TFTPPUT
+ if (TftpWriting) {
+ printf("Save address: 0x%lx\n", save_addr);
+ printf("Save size: 0x%lx\n", save_size);
+ NetBootFileXferSize = save_size;
+ puts("Saving: *\b");
+ TftpState = STATE_SEND_WRQ;
+ TftpFinalBlock = 0;
+ }
+#endif
+ else {
+ printf("Load address: 0x%lx\n", load_addr);
+ puts("Loading: *\b");
+ TftpState = STATE_SEND_RRQ;
+ }
TftpTimeoutCountMax = TftpRRQTimeoutCountMax;
@@ -661,7 +736,6 @@ void TftpStart(proto_t protocol)
TftpRemotePort = WELL_KNOWN_PORT;
TftpTimeoutCount = 0;
- TftpState = STATE_SEND_RRQ;
/* Use a pseudo-random port unless a specific port is set */
TftpOurPort = 1024 + (get_timer(0) % 3072);
--
1.7.3.1
More information about the U-Boot
mailing list