tftp return value
[barebox-mini2440.git] / net / tftp.c
blobe8a8a3a899b3c6ce79c3a5eb3f9a79bb3ace22b8
1 /*
2 * Copyright 1994, 1995, 2000 Neil Russell.
3 * (See License)
4 * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
5 */
7 #include <common.h>
8 #include <command.h>
9 #include <net.h>
10 #include <driver.h>
11 #include <clock.h>
12 #include <fs.h>
13 #include <errno.h>
14 #include <libgen.h>
15 #include <fcntl.h>
16 #include "tftp.h"
18 #define WELL_KNOWN_PORT 69 /* Well known TFTP port # */
19 #define TIMEOUT 5 /* Seconds to timeout for a lost pkt */
20 # define TIMEOUT_COUNT 10 /* # of timeouts before giving up */
21 /* (for checking the image size) */
22 #define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */
25 * TFTP operations.
27 #define TFTP_RRQ 1
28 #define TFTP_WRQ 2
29 #define TFTP_DATA 3
30 #define TFTP_ACK 4
31 #define TFTP_ERROR 5
32 #define TFTP_OACK 6
35 static int TftpServerPort; /* The UDP port at their end */
36 static int TftpOurPort; /* The UDP port at our end */
37 static ulong TftpBlock; /* packet sequence number */
38 static ulong TftpLastBlock; /* last packet sequence number received */
39 static ulong TftpBlockWrap; /* count of sequence number wraparounds */
40 static ulong TftpBlockWrapOffset; /* memory offset due to wrapping */
41 static int TftpState;
43 #define STATE_RRQ 1
44 #define STATE_DATA 2
45 #define STATE_OACK 3
47 #define TFTP_BLOCK_SIZE 512 /* default TFTP block size */
48 #define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) /* sequence number is 16 bit */
50 static char *tftp_filename;
52 static int net_store_fd;
54 static int store_block(unsigned block, uchar * src, unsigned len)
56 ulong offset = block * TFTP_BLOCK_SIZE + TftpBlockWrapOffset;
57 ulong newsize = offset + len;
58 int ret;
60 ret = write(net_store_fd, src, len);
61 if (ret < 0)
62 return ret;
64 if (NetBootFileXferSize < newsize)
65 NetBootFileXferSize = newsize;
66 return 0;
69 static void TftpSend(void)
71 uchar *pkt;
72 uchar *xp;
73 int len = 0;
74 ushort *s;
77 * We will always be sending some sort of packet, so
78 * cobble together the packet headers now.
80 pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
82 switch (TftpState) {
83 case STATE_RRQ:
84 xp = pkt;
85 s = (ushort *)pkt;
86 *s++ = htons(TFTP_RRQ);
87 pkt = (uchar *)s;
88 pkt += sprintf((uchar *)pkt, "%s%coctet%ctimeout%c%d",
89 tftp_filename, 0, 0, 0, TIMEOUT) + 1;
90 len = pkt - xp;
91 break;
93 case STATE_DATA:
94 case STATE_OACK:
95 xp = pkt;
96 s = (ushort *)pkt;
97 *s++ = htons(TFTP_ACK);
98 *s++ = htons(TftpBlock);
99 pkt = (uchar *)s;
100 len = pkt - xp;
101 break;
104 NetSendUDPPacket(NetServerEther, NetServerIP, TftpServerPort,
105 TftpOurPort, len);
108 static void TftpTimeout(void)
110 puts("T ");
111 NetSetTimeout(TIMEOUT * SECOND, TftpTimeout);
112 TftpSend();
115 static void TftpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
117 ushort proto;
118 ushort *s;
120 if (dest != TftpOurPort)
121 return;
123 if (TftpState != STATE_RRQ && src != TftpServerPort)
124 return;
126 if (len < 2)
127 return;
129 len -= 2;
130 /* warning: don't use increment (++) in ntohs() macros!! */
131 s = (ushort *)pkt;
132 proto = *s++;
133 pkt = (uchar *)s;
134 switch (ntohs(proto)) {
135 case TFTP_RRQ:
136 case TFTP_WRQ:
137 case TFTP_ACK:
138 break;
139 default:
140 break;
142 case TFTP_OACK:
143 debug("Got OACK: %s %s\n", pkt, pkt+strlen(pkt)+1);
144 TftpState = STATE_OACK;
145 TftpServerPort = src;
146 TftpSend(); /* Send ACK */
147 break;
148 case TFTP_DATA:
149 if (len < 2)
150 return;
151 len -= 2;
152 TftpBlock = ntohs(*(ushort *)pkt);
155 * RFC1350 specifies that the first data packet will
156 * have sequence number 1. If we receive a sequence
157 * number of 0 this means that there was a wrap
158 * around of the (16 bit) counter.
160 if (TftpBlock == 0) {
161 TftpBlockWrap++;
162 TftpBlockWrapOffset += TFTP_BLOCK_SIZE * TFTP_SEQUENCE_SIZE;
163 printf ("\n\t %lu MB received\n\t ", TftpBlockWrapOffset>>20);
164 } else {
165 if (((TftpBlock - 1) % 10) == 0) {
166 putchar('#');
167 } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
168 puts("\n\t ");
172 if (TftpState == STATE_RRQ)
173 debug("Server did not acknowledge timeout option!\n");
175 if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
176 /* first block received */
177 TftpState = STATE_DATA;
178 TftpServerPort = src;
179 TftpLastBlock = 0;
180 TftpBlockWrap = 0;
181 TftpBlockWrapOffset = 0;
183 if (TftpBlock != 1) { /* Assertion */
184 printf("\nTFTP error: "
185 "First block is not block 1 (%ld)\n"
186 "Starting again\n\n",
187 TftpBlock);
188 NetState = NETLOOP_FAIL;
189 break;
193 if (TftpBlock == TftpLastBlock)
194 /* Same block again; ignore it. */
195 break;
197 TftpLastBlock = TftpBlock;
198 NetSetTimeout(TIMEOUT * SECOND, TftpTimeout);
200 if (store_block(TftpBlock - 1, pkt + 2, len) < 0) {
201 perror("write");
202 NetState = NETLOOP_FAIL;
203 return;
207 * Acknowledge the block just received, which will prompt
208 * the server for the next one.
210 TftpSend();
212 if (len < TFTP_BLOCK_SIZE) {
214 * We received the whole thing. Try to
215 * run it.
217 puts("\ndone\n");
218 NetState = NETLOOP_SUCCESS;
220 break;
222 case TFTP_ERROR:
223 printf("\nTFTP error: '%s' (%d)\n",
224 pkt + 2, ntohs(*(ushort *)pkt));
225 NetState = NETLOOP_FAIL;
226 break;
230 void TftpStart(char *filename)
232 char ip1[16], ip2[16];
234 tftp_filename = filename;
236 printf("TFTP from server %s; our IP address is %s\n"
237 "\nFilename '%s'.\nLoading: *\b",
238 ip_to_string(NetServerIP, ip1),
239 ip_to_string(NetOurIP, ip2),
240 tftp_filename);
242 NetSetTimeout(TIMEOUT * SECOND, TftpTimeout);
243 NetSetHandler(TftpHandler);
245 TftpServerPort = WELL_KNOWN_PORT;
246 TftpState = STATE_RRQ;
247 /* Use a pseudo-random port */
248 TftpOurPort = 1024 + ((unsigned int)get_time_ns() % 3072);
249 TftpBlock = 0;
251 /* zero out server ether in case the server ip has changed */
252 memset(NetServerEther, 0, 6);
254 TftpSend();
257 static int do_tftpb(struct command *cmdtp, int argc, char *argv[])
259 int rcode = 0;
260 char *localfile;
261 char *remotefile;
263 if (argc < 2)
264 return COMMAND_ERROR_USAGE;
266 remotefile = argv[1];
268 if (argc == 2)
269 localfile = basename(remotefile);
270 else
271 localfile = argv[2];
273 net_store_fd = open(localfile, O_WRONLY | O_CREAT);
274 if (net_store_fd < 0) {
275 perror("open");
276 return 1;
279 if (NetLoopInit(TFTP) < 0)
280 goto out;
282 TftpStart(remotefile);
284 if (NetLoop() < 0) {
285 rcode = 1;
286 goto out;
289 /* NetLoop ok, update environment */
290 netboot_update_env();
292 out:
293 close(net_store_fd);
294 return rcode;
297 static const __maybe_unused char cmd_tftp_help[] =
298 "Usage: tftp <file> [localfile]\n"
299 "Load a file via network using BootP/TFTP protocol.\n";
301 BAREBOX_CMD_START(tftp)
302 .cmd = do_tftpb,
303 .usage = "Load file using tftp protocol",
304 BAREBOX_CMD_HELP(cmd_tftp_help)
305 BAREBOX_CMD_END
308 * @page tftp_command tftp
310 * Usage is: tftp \<filename\> [\<localfilename\>]
312 * Load a file via network using BootP/TFTP protocol. The loaded file you
313 * can find after download in you current ramdisk. Refer \b ls command.
315 * \<localfile> can be the local filename only, or also a device name. In the
316 * case of a device name, the will gets stored there. This works also for
317 * partitions of flash memory. Refer \b erase, \b unprotect for flash
318 * preparation.
320 * Note: This command is available only, if enabled in the menuconfig.