]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - net/tftp.c
* Switch LWMON board default config from FRAM to EEPROM;
[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         NetSetEther (NetTxPacket, NetServerEther, PROT_IP);
146         NetSetIP (NetTxPacket + ETHER_HDR_SIZE, NetServerIP,
147                                         TftpServerPort, TftpOurPort, len);
148         NetSendPacket (NetTxPacket, ETHER_HDR_SIZE + IP_HDR_SIZE + len);
149 }
150
151
152 static void
153 TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
154 {
155         ushort proto;
156
157         if (dest != TftpOurPort) {
158                 return;
159         }
160         if (TftpState != STATE_RRQ && src != TftpServerPort) {
161                 return;
162         }
163
164         if (len < 2) {
165                 return;
166         }
167         len -= 2;
168         /* warning: don't use increment (++) in ntohs() macros!! */
169         proto = *((ushort *)pkt)++;
170         switch (ntohs(proto)) {
171
172         case TFTP_RRQ:
173         case TFTP_WRQ:
174         case TFTP_ACK:
175                 break;
176         default:
177                 break;
178
179         case TFTP_DATA:
180                 if (len < 2)
181                         return;
182                 len -= 2;
183                 TftpBlock = ntohs(*(ushort *)pkt);
184                 if (((TftpBlock - 1) % 10) == 0) {
185                         putc ('#');
186                 } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
187                         puts ("\n\t ");
188                 }
189
190                 if (TftpState == STATE_RRQ) {
191                         TftpState = STATE_DATA;
192                         TftpServerPort = src;
193                         TftpLastBlock = 0;
194
195                         if (TftpBlock != 1) {   /* Assertion */
196                                 printf ("\nTFTP error: "
197                                         "First block is not block 1 (%d)\n"
198                                         "Starting again\n\n",
199                                         TftpBlock);
200                                 NetStartAgain ();
201                                 break;
202                         }
203                 }
204
205                 if (TftpBlock == TftpLastBlock) {
206                         /*
207                          *      Same block again; ignore it.
208                          */
209                         break;
210                 }
211
212                 TftpLastBlock = TftpBlock;
213                 NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
214
215                 store_block (TftpBlock - 1, pkt + 2, len);
216
217                 /*
218                  *      Acknoledge the block just received, which will prompt
219                  *      the server for the next one.
220                  */
221                 TftpSend ();
222
223                 if (len < 512) {
224                         /*
225                          *      We received the whole thing.  Try to
226                          *      run it.
227                          */
228                         puts ("\ndone\n");
229                         NetState = NETLOOP_SUCCESS;
230                 }
231                 break;
232
233         case TFTP_ERROR:
234                 printf ("\nTFTP error: '%s' (%d)\n",
235                                         pkt + 2, ntohs(*(ushort *)pkt));
236                 puts ("Starting again\n\n");
237                 NetStartAgain ();
238                 break;
239         }
240 }
241
242
243 static void
244 TftpTimeout (void)
245 {
246         if (++TftpTimeoutCount >= TIMEOUT_COUNT) {
247                 puts ("\nRetry count exceeded; starting again\n");
248                 NetStartAgain ();
249         } else {
250                 puts ("T ");
251                 NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
252                 TftpSend ();
253         }
254 }
255
256
257 void
258 TftpStart (void)
259 {
260 #ifdef ET_DEBUG
261         printf ("\nServer ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
262                 NetServerEther[0],
263                 NetServerEther[1],
264                 NetServerEther[2],
265                 NetServerEther[3],
266                 NetServerEther[4],
267                 NetServerEther[5]
268         );
269 #endif /* DEBUG */
270
271         if (BootFile[0] == '\0') {
272                 IPaddr_t OurIP = ntohl(NetOurIP);
273
274                 sprintf(default_filename, "%02lX%02lX%02lX%02lX.img",
275                         OurIP & 0xFF,
276                         (OurIP >>  8) & 0xFF,
277                         (OurIP >> 16) & 0xFF,
278                         (OurIP >> 24) & 0xFF    );
279                 tftp_filename = default_filename;
280
281                 printf ("*** Warning: no boot file name; using '%s'\n",
282                         tftp_filename);
283         } else {
284                 tftp_filename = BootFile;
285         }
286
287         puts ("TFTP from server ");     print_IPaddr (NetServerIP);
288         puts ("; our IP address is ");  print_IPaddr (NetOurIP);
289
290         /* Check if we need to send across this subnet */
291         if (NetOurGatewayIP && NetOurSubnetMask) {
292             IPaddr_t OurNet     = NetOurIP    & NetOurSubnetMask;
293             IPaddr_t ServerNet  = NetServerIP & NetOurSubnetMask;
294
295             if (OurNet != ServerNet) {
296                 puts ("; sending through gateway ");
297                 print_IPaddr (NetOurGatewayIP) ;
298             }
299         }
300         putc ('\n');
301
302         printf ("Filename '%s'.", tftp_filename);
303
304         if (NetBootFileSize) {
305                 printf (" Size is 0x%x Bytes = ", NetBootFileSize<<9);
306                 print_size (NetBootFileSize<<9, "");
307         }
308
309         putc ('\n');
310
311         printf ("Load address: 0x%lx\n", load_addr);
312
313         puts ("Loading: *\b");
314
315         NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
316         NetSetHandler (TftpHandler);
317
318         TftpServerPort = WELL_KNOWN_PORT;
319         TftpTimeoutCount = 0;
320         TftpState = STATE_RRQ;
321         TftpOurPort = 1024 + (get_timer(0) % 3072);
322
323         TftpSend ();
324 }
325
326 #endif /* CFG_CMD_NET */