d1a30d6643923548998c7fb20821794f2a2c406a
[platform/kernel/u-boot.git] / net / tftp.c
1 /*
2  *      Copyright 1994, 1995, 2000 Neil Russell.
3  *      (See License)
4  *      Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
5  */
6
7 #include <common.h>
8 #include <command.h>
9 #include <net.h>
10 #include "tftp.h"
11 #include "bootp.h"
12
13 #undef  ET_DEBUG
14
15 #if (CONFIG_COMMANDS & CFG_CMD_NET)
16
17 #define WELL_KNOWN_PORT 69              /* Well known TFTP port #               */
18 #define TIMEOUT         5               /* Seconds to timeout for a lost pkt    */
19 #ifndef CONFIG_NET_RETRY_COUNT
20 # define TIMEOUT_COUNT  10              /* # of timeouts before giving up  */
21 #else
22 # define TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT * 2)
23 #endif
24                                         /* (for checking the image size)        */
25 #define HASHES_PER_LINE 65              /* Number of "loading" hashes per line  */
26
27 /*
28  *      TFTP operations.
29  */
30 #define TFTP_RRQ        1
31 #define TFTP_WRQ        2
32 #define TFTP_DATA       3
33 #define TFTP_ACK        4
34 #define TFTP_ERROR      5
35 #define TFTP_OACK       6
36
37
38 static int      TftpServerPort;         /* The UDP port at their end            */
39 static int      TftpOurPort;            /* The UDP port at our end              */
40 static int      TftpTimeoutCount;
41 static unsigned TftpBlock;
42 static unsigned TftpLastBlock;
43 static int      TftpState;
44 #define STATE_RRQ       1
45 #define STATE_DATA      2
46 #define STATE_TOO_LARGE 3
47 #define STATE_BAD_MAGIC 4
48 #define STATE_OACK      5
49
50 #define DEFAULT_NAME_LEN        (8 + 4 + 1)
51 static char default_filename[DEFAULT_NAME_LEN];
52 static char *tftp_filename;
53
54 #ifdef CFG_DIRECT_FLASH_TFTP
55 extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS];
56 #endif
57
58 static __inline__ void
59 store_block (unsigned block, uchar * src, unsigned len)
60 {
61         ulong offset = block * 512, newsize = offset + len;
62 #ifdef CFG_DIRECT_FLASH_TFTP
63         int i, rc = 0;
64
65         for (i=0; i<CFG_MAX_FLASH_BANKS; i++) {
66                 /* start address in flash? */
67                 if (load_addr + offset >= flash_info[i].start[0]) {
68                         rc = 1;
69                         break;
70                 }
71         }
72
73         if (rc) { /* Flash is destination for this packet */
74                 rc = flash_write ((uchar *)src, (ulong)(load_addr+offset), len);
75                 if (rc) {
76                         flash_perror (rc);
77                         NetState = NETLOOP_FAIL;
78                         return;
79                 }
80         }
81         else
82 #endif /* CFG_DIRECT_FLASH_TFTP */
83         {
84                 (void)memcpy((void *)(load_addr + offset), src, len);
85         }
86
87         if (NetBootFileXferSize < newsize)
88                 NetBootFileXferSize = newsize;
89 }
90
91 static void TftpSend (void);
92 static void TftpTimeout (void);
93
94 /**********************************************************************/
95
96 static void
97 TftpSend (void)
98 {
99         volatile uchar *        pkt;
100         volatile uchar *        xp;
101         int                     len = 0;
102
103         /*
104          *      We will always be sending some sort of packet, so
105          *      cobble together the packet headers now.
106          */
107         pkt = NetTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE;
108
109         switch (TftpState) {
110
111         case STATE_RRQ:
112                 xp = pkt;
113                 *((ushort *)pkt)++ = htons(TFTP_RRQ);
114                 strcpy ((char *)pkt, tftp_filename);
115                 pkt += strlen(tftp_filename) + 1;
116                 strcpy ((char *)pkt, "octet");
117                 pkt += 5 /*strlen("octet")*/ + 1;
118                 strcpy ((char *)pkt, "timeout");
119                 pkt += 7 /*strlen("timeout")*/ + 1;
120                 sprintf((char *)pkt, "%d", TIMEOUT);
121 #ifdef ET_DEBUG
122                 printf("send option \"timeout %s\"\n", (char *)pkt);
123 #endif
124                 pkt += strlen((char *)pkt) + 1;
125                 len = pkt - xp;
126                 break;
127
128         case STATE_DATA:
129         case STATE_OACK:
130                 xp = pkt;
131                 *((ushort *)pkt)++ = htons(TFTP_ACK);
132                 *((ushort *)pkt)++ = htons(TftpBlock);
133                 len = pkt - xp;
134                 break;
135
136         case STATE_TOO_LARGE:
137                 xp = pkt;
138                 *((ushort *)pkt)++ = htons(TFTP_ERROR);
139                 *((ushort *)pkt)++ = htons(3);
140                 strcpy ((char *)pkt, "File too large");
141                 pkt += 14 /*strlen("File too large")*/ + 1;
142                 len = pkt - xp;
143                 break;
144
145         case STATE_BAD_MAGIC:
146                 xp = pkt;
147                 *((ushort *)pkt)++ = htons(TFTP_ERROR);
148                 *((ushort *)pkt)++ = htons(2);
149                 strcpy ((char *)pkt, "File has bad magic");
150                 pkt += 18 /*strlen("File has bad magic")*/ + 1;
151                 len = pkt - xp;
152                 break;
153         }
154
155         NetSendUDPPacket(NetServerEther, NetServerIP, TftpServerPort, TftpOurPort, len);
156 }
157
158
159 static void
160 TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
161 {
162         ushort proto;
163
164         if (dest != TftpOurPort) {
165                 return;
166         }
167         if (TftpState != STATE_RRQ && src != TftpServerPort) {
168                 return;
169         }
170
171         if (len < 2) {
172                 return;
173         }
174         len -= 2;
175         /* warning: don't use increment (++) in ntohs() macros!! */
176         proto = *((ushort *)pkt)++;
177         switch (ntohs(proto)) {
178
179         case TFTP_RRQ:
180         case TFTP_WRQ:
181         case TFTP_ACK:
182                 break;
183         default:
184                 break;
185
186         case TFTP_OACK:
187 #ifdef ET_DEBUG
188                 printf("Got OACK: %s %s\n", pkt, pkt+strlen(pkt)+1);
189 #endif
190                 TftpState = STATE_OACK;
191                 TftpServerPort = src;
192                 TftpSend (); /* Send ACK */
193                 break;
194         case TFTP_DATA:
195                 if (len < 2)
196                         return;
197                 len -= 2;
198                 TftpBlock = ntohs(*(ushort *)pkt);
199                 if (((TftpBlock - 1) % 10) == 0) {
200                         putc ('#');
201                 } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
202                         puts ("\n\t ");
203                 }
204
205 #ifdef ET_DEBUG
206                 if (TftpState == STATE_RRQ) {
207                         printf("Server did not acknowledge timeout option!\n");
208                 }
209 #endif
210
211                 if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
212                         TftpState = STATE_DATA;
213                         TftpServerPort = src;
214                         TftpLastBlock = 0;
215
216                         if (TftpBlock != 1) {   /* Assertion */
217                                 printf ("\nTFTP error: "
218                                         "First block is not block 1 (%d)\n"
219                                         "Starting again\n\n",
220                                         TftpBlock);
221                                 NetStartAgain ();
222                                 break;
223                         }
224                 }
225
226                 if (TftpBlock == TftpLastBlock) {
227                         /*
228                          *      Same block again; ignore it.
229                          */
230                         break;
231                 }
232
233                 TftpLastBlock = TftpBlock;
234                 NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
235
236                 store_block (TftpBlock - 1, pkt + 2, len);
237
238                 /*
239                  *      Acknoledge the block just received, which will prompt
240                  *      the server for the next one.
241                  */
242                 TftpSend ();
243
244                 if (len < 512) {
245                         /*
246                          *      We received the whole thing.  Try to
247                          *      run it.
248                          */
249                         puts ("\ndone\n");
250                         NetState = NETLOOP_SUCCESS;
251                 }
252                 break;
253
254         case TFTP_ERROR:
255                 printf ("\nTFTP error: '%s' (%d)\n",
256                                         pkt + 2, ntohs(*(ushort *)pkt));
257                 puts ("Starting again\n\n");
258                 NetStartAgain ();
259                 break;
260         }
261 }
262
263
264 static void
265 TftpTimeout (void)
266 {
267         if (++TftpTimeoutCount > TIMEOUT_COUNT) {
268                 puts ("\nRetry count exceeded; starting again\n");
269                 NetStartAgain ();
270         } else {
271                 puts ("T ");
272                 NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
273                 TftpSend ();
274         }
275 }
276
277
278 void
279 TftpStart (void)
280 {
281         if (BootFile[0] == '\0') {
282                 IPaddr_t OurIP = ntohl(NetOurIP);
283
284                 sprintf(default_filename, "%02lX%02lX%02lX%02lX.img",
285                         OurIP & 0xFF,
286                         (OurIP >>  8) & 0xFF,
287                         (OurIP >> 16) & 0xFF,
288                         (OurIP >> 24) & 0xFF    );
289                 tftp_filename = default_filename;
290
291                 printf ("*** Warning: no boot file name; using '%s'\n",
292                         tftp_filename);
293         } else {
294                 tftp_filename = BootFile;
295         }
296
297 #if defined(CONFIG_NET_MULTI)
298         printf ("Using %s device\n", eth_get_name());
299 #endif
300         puts ("TFTP from server ");     print_IPaddr (NetServerIP);
301         puts ("; our IP address is ");  print_IPaddr (NetOurIP);
302
303         /* Check if we need to send across this subnet */
304         if (NetOurGatewayIP && NetOurSubnetMask) {
305             IPaddr_t OurNet     = NetOurIP    & NetOurSubnetMask;
306             IPaddr_t ServerNet  = NetServerIP & NetOurSubnetMask;
307
308             if (OurNet != ServerNet) {
309                 puts ("; sending through gateway ");
310                 print_IPaddr (NetOurGatewayIP) ;
311             }
312         }
313         putc ('\n');
314
315         printf ("Filename '%s'.", tftp_filename);
316
317         if (NetBootFileSize) {
318                 printf (" Size is 0x%x Bytes = ", NetBootFileSize<<9);
319                 print_size (NetBootFileSize<<9, "");
320         }
321
322         putc ('\n');
323
324         printf ("Load address: 0x%lx\n", load_addr);
325
326         puts ("Loading: *\b");
327
328         NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
329         NetSetHandler (TftpHandler);
330
331         TftpServerPort = WELL_KNOWN_PORT;
332         TftpTimeoutCount = 0;
333         TftpState = STATE_RRQ;
334         TftpOurPort = 1024 + (get_timer(0) % 3072);
335         TftpBlock = 0;
336
337         /* zero out server ether in case the server ip has changed */
338         memset(NetServerEther, 0, 6);
339
340         TftpSend ();
341 }
342
343 #endif /* CFG_CMD_NET */