This adds logic to tftp.c to implement the tftp 'put' command, and updates the README.
Signed-off-by: Simon Glass <s...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot