usb ehci driver: Get rid of echi_alloc/free
[barebox-mini2440.git] / net / tftp.c
blobbff32c153ebe5e4025315bc8ec1a091a6fddef34
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 "tftp.h"
15 #include "bootp.h"
17 #undef ET_DEBUG
19 #define WELL_KNOWN_PORT 69 /* Well known TFTP port # */
20 #define TIMEOUT 5 /* Seconds to timeout for a lost pkt */
21 #ifndef CONFIG_NET_RETRY_COUNT
22 # define TIMEOUT_COUNT 10 /* # of timeouts before giving up */
23 #else
24 # define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2)
25 #endif
26 /* (for checking the image size) */
27 #define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */
30 * TFTP operations.
32 #define TFTP_RRQ 1
33 #define TFTP_WRQ 2
34 #define TFTP_DATA 3
35 #define TFTP_ACK 4
36 #define TFTP_ERROR 5
37 #define TFTP_OACK 6
40 static int TftpServerPort; /* The UDP port at their end */
41 static int TftpOurPort; /* The UDP port at our end */
42 static int TftpTimeoutCount;
43 static ulong TftpBlock; /* packet sequence number */
44 static ulong TftpLastBlock; /* last packet sequence number received */
45 static ulong TftpBlockWrap; /* count of sequence number wraparounds */
46 static ulong TftpBlockWrapOffset; /* memory offset due to wrapping */
47 static int TftpState;
49 #define STATE_RRQ 1
50 #define STATE_DATA 2
51 #define STATE_TOO_LARGE 3
52 #define STATE_BAD_MAGIC 4
53 #define STATE_OACK 5
55 #define TFTP_BLOCK_SIZE 512 /* default TFTP block size */
56 #define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) /* sequence number is 16 bit */
58 #define DEFAULT_NAME_LEN (8 + 4 + 1)
59 static char default_filename[DEFAULT_NAME_LEN];
60 static char *tftp_filename;
62 extern int net_store_fd;
64 static int
65 store_block (unsigned block, uchar * src, unsigned len)
67 ulong offset = block * TFTP_BLOCK_SIZE + TftpBlockWrapOffset;
68 ulong newsize = offset + len;
69 int ret;
71 ret = write(net_store_fd, src, len);
72 if (ret < 0)
73 return ret;
75 if (NetBootFileXferSize < newsize)
76 NetBootFileXferSize = newsize;
77 return 0;
80 static void TftpSend (void);
81 static void TftpTimeout (void);
83 /**********************************************************************/
85 static void
86 TftpSend (void)
88 volatile uchar * pkt;
89 volatile uchar * xp;
90 int len = 0;
91 volatile ushort *s;
94 * We will always be sending some sort of packet, so
95 * cobble together the packet headers now.
97 pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
99 switch (TftpState) {
101 case STATE_RRQ:
102 xp = pkt;
103 s = (ushort *)pkt;
104 *s++ = htons(TFTP_RRQ);
105 pkt = (uchar *)s;
106 pkt += sprintf((uchar *)pkt, "%s%coctet%ctimeout%c%d",
107 tftp_filename, 0, 0, 0, TIMEOUT) + 1;
108 len = pkt - xp;
109 break;
111 case STATE_DATA:
112 case STATE_OACK:
113 xp = pkt;
114 s = (ushort *)pkt;
115 *s++ = htons(TFTP_ACK);
116 *s++ = htons(TftpBlock);
117 pkt = (uchar *)s;
118 len = pkt - xp;
119 break;
121 case STATE_TOO_LARGE:
122 xp = pkt;
123 s = (ushort *)pkt;
124 *s++ = htons(TFTP_ERROR);
125 *s++ = htons(3);
126 pkt = (uchar *)s;
127 strcpy ((char *)pkt, "File too large");
128 pkt += 14 /*strlen("File too large")*/ + 1;
129 len = pkt - xp;
130 break;
132 case STATE_BAD_MAGIC:
133 xp = pkt;
134 s = (ushort *)pkt;
135 *s++ = htons(TFTP_ERROR);
136 *s++ = htons(2);
137 pkt = (uchar *)s;
138 strcpy ((char *)pkt, "File has bad magic");
139 pkt += 18 /*strlen("File has bad magic")*/ + 1;
140 len = pkt - xp;
141 break;
144 NetSendUDPPacket(NetServerEther, NetServerIP, TftpServerPort, TftpOurPort, len);
148 static void
149 TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
151 ushort proto;
152 ushort *s;
154 if (dest != TftpOurPort) {
155 return;
157 if (TftpState != STATE_RRQ && src != TftpServerPort) {
158 return;
161 if (len < 2) {
162 return;
164 len -= 2;
165 /* warning: don't use increment (++) in ntohs() macros!! */
166 s = (ushort *)pkt;
167 proto = *s++;
168 pkt = (uchar *)s;
169 switch (ntohs(proto)) {
171 case TFTP_RRQ:
172 case TFTP_WRQ:
173 case TFTP_ACK:
174 break;
175 default:
176 break;
178 case TFTP_OACK:
179 #ifdef ET_DEBUG
180 printf("Got OACK: %s %s\n", pkt, pkt+strlen(pkt)+1);
181 #endif
182 TftpState = STATE_OACK;
183 TftpServerPort = src;
184 TftpSend (); /* Send ACK */
185 break;
186 case TFTP_DATA:
187 if (len < 2)
188 return;
189 len -= 2;
190 TftpBlock = ntohs(*(ushort *)pkt);
193 * RFC1350 specifies that the first data packet will
194 * have sequence number 1. If we receive a sequence
195 * number of 0 this means that there was a wrap
196 * around of the (16 bit) counter.
198 if (TftpBlock == 0) {
199 TftpBlockWrap++;
200 TftpBlockWrapOffset += TFTP_BLOCK_SIZE * TFTP_SEQUENCE_SIZE;
201 printf ("\n\t %lu MB received\n\t ", TftpBlockWrapOffset>>20);
202 } else {
203 if (((TftpBlock - 1) % 10) == 0) {
204 putchar('#');
205 } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
206 puts ("\n\t ");
210 #ifdef ET_DEBUG
211 if (TftpState == STATE_RRQ) {
212 puts ("Server did not acknowledge timeout option!\n");
214 #endif
216 if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
217 /* first block received */
218 TftpState = STATE_DATA;
219 TftpServerPort = src;
220 TftpLastBlock = 0;
221 TftpBlockWrap = 0;
222 TftpBlockWrapOffset = 0;
224 if (TftpBlock != 1) { /* Assertion */
225 printf ("\nTFTP error: "
226 "First block is not block 1 (%ld)\n"
227 "Starting again\n\n",
228 TftpBlock);
229 NetStartAgain ();
230 break;
234 if (TftpBlock == TftpLastBlock) {
236 * Same block again; ignore it.
238 break;
241 TftpLastBlock = TftpBlock;
242 NetSetTimeout (TIMEOUT * SECOND, TftpTimeout);
244 if (store_block (TftpBlock - 1, pkt + 2, len) < 0) {
245 perror("write");
246 NetState = NETLOOP_FAIL;
247 return;
251 * Acknoledge the block just received, which will prompt
252 * the server for the next one.
254 TftpSend ();
256 if (len < TFTP_BLOCK_SIZE) {
258 * We received the whole thing. Try to
259 * run it.
261 puts ("\ndone\n");
262 NetState = NETLOOP_SUCCESS;
264 break;
266 case TFTP_ERROR:
267 printf ("\nTFTP error: '%s' (%d)\n",
268 pkt + 2, ntohs(*(ushort *)pkt));
269 puts ("Starting again\n\n");
270 NetStartAgain ();
271 break;
276 static void
277 TftpTimeout (void)
279 if (++TftpTimeoutCount > TIMEOUT_COUNT) {
280 puts ("\nRetry count exceeded; starting again\n");
281 NetStartAgain ();
282 } else {
283 puts ("T ");
284 NetSetTimeout (TIMEOUT * SECOND, TftpTimeout);
285 TftpSend ();
290 void
291 TftpStart (void)
293 #ifdef CONFIG_TFTP_PORT
294 char *ep; /* Environment pointer */
295 #endif
297 if (BootFile[0] == '\0') {
298 sprintf(default_filename, "%02lX%02lX%02lX%02lX.img",
299 NetOurIP & 0xFF,
300 (NetOurIP >> 8) & 0xFF,
301 (NetOurIP >> 16) & 0xFF,
302 (NetOurIP >> 24) & 0xFF );
303 tftp_filename = default_filename;
305 printf ("*** Warning: no boot file name; using '%s'\n",
306 tftp_filename);
307 } else {
308 tftp_filename = BootFile;
311 puts ("TFTP from server "); print_IPaddr (NetServerIP);
312 puts ("; our IP address is "); print_IPaddr (NetOurIP);
314 /* Check if we need to send across this subnet */
315 if (NetOurGatewayIP && NetOurSubnetMask) {
316 IPaddr_t OurNet = NetOurIP & NetOurSubnetMask;
317 IPaddr_t ServerNet = NetServerIP & NetOurSubnetMask;
319 if (OurNet != ServerNet) {
320 puts ("; sending through gateway ");
321 print_IPaddr (NetOurGatewayIP) ;
324 putchar('\n');
326 printf ("Filename '%s'.", tftp_filename);
328 if (NetBootFileSize)
329 printf (" Size is 0x%x Bytes = %s",
330 NetBootFileSize<<9,
331 size_human_readable(NetBootFileSize<<9));
333 puts ("\nLoading: *\b");
335 NetSetTimeout (TIMEOUT * SECOND, TftpTimeout);
336 NetSetHandler (TftpHandler);
338 TftpServerPort = WELL_KNOWN_PORT;
339 TftpTimeoutCount = 0;
340 TftpState = STATE_RRQ;
341 /* Use a pseudo-random port unless a specific port is set */
342 TftpOurPort = 1024 + ((unsigned int)get_time_ns() % 3072);
343 #ifdef CONFIG_TFTP_PORT
344 if ((ep = getenv("tftpdstp")) != NULL) {
345 TftpServerPort = simple_strtol(ep, NULL, 10);
347 if ((ep = getenv("tftpsrcp")) != NULL) {
348 TftpOurPort= simple_strtol(ep, NULL, 10);
350 #endif
351 TftpBlock = 0;
353 /* zero out server ether in case the server ip has changed */
354 memset(NetServerEther, 0, 6);
356 TftpSend ();