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