]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - net/tftp.c
net: express the first argument to NetSetTimeout() in milliseconds
[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 defined(CONFIG_CMD_NET)
16
17 #define WELL_KNOWN_PORT 69              /* Well known TFTP port #               */
18 #define TIMEOUT         5000UL          /* Millisecs to timeout for 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 static IPaddr_t TftpServerIP;
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 ulong    TftpBlock;              /* packet sequence number               */
42 static ulong    TftpLastBlock;          /* last packet sequence number received */
43 static ulong    TftpBlockWrap;          /* count of sequence number wraparounds */
44 static ulong    TftpBlockWrapOffset;    /* memory offset due to wrapping        */
45 static int      TftpState;
46
47 #define STATE_RRQ       1
48 #define STATE_DATA      2
49 #define STATE_TOO_LARGE 3
50 #define STATE_BAD_MAGIC 4
51 #define STATE_OACK      5
52
53 #define TFTP_BLOCK_SIZE         512                 /* default TFTP block size  */
54 #define TFTP_SEQUENCE_SIZE      ((ulong)(1<<16))    /* sequence number is 16 bit */
55
56 #define DEFAULT_NAME_LEN        (8 + 4 + 1)
57 static char default_filename[DEFAULT_NAME_LEN];
58
59 #ifndef CONFIG_TFTP_FILE_NAME_MAX_LEN
60 #define MAX_LEN 128
61 #else
62 #define MAX_LEN CONFIG_TFTP_FILE_NAME_MAX_LEN
63 #endif
64
65 static char tftp_filename[MAX_LEN];
66
67 #ifdef CFG_DIRECT_FLASH_TFTP
68 extern flash_info_t flash_info[];
69 #endif
70
71 /* 512 is poor choice for ethernet, MTU is typically 1500.
72  * Minus eth.hdrs thats 1468.  Can get 2x better throughput with
73  * almost-MTU block sizes.  At least try... fall back to 512 if need be.
74  */
75 #define TFTP_MTU_BLOCKSIZE 1468
76 static unsigned short TftpBlkSize=TFTP_BLOCK_SIZE;
77 static unsigned short TftpBlkSizeOption=TFTP_MTU_BLOCKSIZE;
78
79 #ifdef CONFIG_MCAST_TFTP
80 #include <malloc.h>
81 #define MTFTP_BITMAPSIZE        0x1000
82 static unsigned *Bitmap;
83 static int PrevBitmapHole,Mapsize=MTFTP_BITMAPSIZE;
84 static uchar ProhibitMcast=0, MasterClient=0;
85 static uchar Multicast=0;
86 extern IPaddr_t Mcast_addr;
87 static int Mcast_port;
88 static ulong TftpEndingBlock; /* can get 'last' block before done..*/
89
90 static void parse_multicast_oack(char *pkt,int len);
91
92 static void
93 mcast_cleanup(void)
94 {
95         if (Mcast_addr) eth_mcast_join(Mcast_addr, 0);
96         if (Bitmap) free(Bitmap);
97         Bitmap=NULL;
98         Mcast_addr = Multicast = Mcast_port = 0;
99         TftpEndingBlock = -1;
100 }
101
102 #endif  /* CONFIG_MCAST_TFTP */
103
104 static __inline__ void
105 store_block (unsigned block, uchar * src, unsigned len)
106 {
107         ulong offset = block * TftpBlkSize + TftpBlockWrapOffset;
108         ulong newsize = offset + len;
109 #ifdef CFG_DIRECT_FLASH_TFTP
110         int i, rc = 0;
111
112         for (i=0; i<CFG_MAX_FLASH_BANKS; i++) {
113                 /* start address in flash? */
114                 if (flash_info[i].flash_id == FLASH_UNKNOWN)
115                         continue;
116                 if (load_addr + offset >= flash_info[i].start[0]) {
117                         rc = 1;
118                         break;
119                 }
120         }
121
122         if (rc) { /* Flash is destination for this packet */
123                 rc = flash_write ((char *)src, (ulong)(load_addr+offset), len);
124                 if (rc) {
125                         flash_perror (rc);
126                         NetState = NETLOOP_FAIL;
127                         return;
128                 }
129         }
130         else
131 #endif /* CFG_DIRECT_FLASH_TFTP */
132         {
133                 (void)memcpy((void *)(load_addr + offset), src, len);
134         }
135 #ifdef CONFIG_MCAST_TFTP
136         if (Multicast)
137                 ext2_set_bit(block, Bitmap);
138 #endif
139
140         if (NetBootFileXferSize < newsize)
141                 NetBootFileXferSize = newsize;
142 }
143
144 static void TftpSend (void);
145 static void TftpTimeout (void);
146
147 /**********************************************************************/
148
149 static void
150 TftpSend (void)
151 {
152         volatile uchar *        pkt;
153         volatile uchar *        xp;
154         int                     len = 0;
155         volatile ushort *s;
156
157 #ifdef CONFIG_MCAST_TFTP
158         /* Multicast TFTP.. non-MasterClients do not ACK data. */
159         if (Multicast
160          && (TftpState == STATE_DATA)
161          && (MasterClient == 0))
162                 return;
163 #endif
164         /*
165          *      We will always be sending some sort of packet, so
166          *      cobble together the packet headers now.
167          */
168         pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
169
170         switch (TftpState) {
171
172         case STATE_RRQ:
173                 xp = pkt;
174                 s = (ushort *)pkt;
175                 *s++ = htons(TFTP_RRQ);
176                 pkt = (uchar *)s;
177                 strcpy ((char *)pkt, tftp_filename);
178                 pkt += strlen(tftp_filename) + 1;
179                 strcpy ((char *)pkt, "octet");
180                 pkt += 5 /*strlen("octet")*/ + 1;
181                 strcpy ((char *)pkt, "timeout");
182                 pkt += 7 /*strlen("timeout")*/ + 1;
183                 sprintf((char *)pkt, "%lu", TIMEOUT / 1000);
184 #ifdef ET_DEBUG
185                 printf("send option \"timeout %s\"\n", (char *)pkt);
186 #endif
187                 pkt += strlen((char *)pkt) + 1;
188                 /* try for more effic. blk size */
189                 pkt += sprintf((char *)pkt,"blksize%c%d%c",
190                                 0,TftpBlkSizeOption,0);
191 #ifdef CONFIG_MCAST_TFTP
192                 /* Check all preconditions before even trying the option */
193                 if (!ProhibitMcast
194                  && (Bitmap=malloc(Mapsize))
195                  && eth_get_dev()->mcast) {
196                         free(Bitmap);
197                         Bitmap=NULL;
198                         pkt += sprintf((char *)pkt,"multicast%c%c",0,0);
199                 }
200 #endif /* CONFIG_MCAST_TFTP */
201                 len = pkt - xp;
202                 break;
203
204         case STATE_OACK:
205 #ifdef CONFIG_MCAST_TFTP
206                 /* My turn!  Start at where I need blocks I missed.*/
207                 if (Multicast)
208                         TftpBlock=ext2_find_next_zero_bit(Bitmap,(Mapsize*8),0);
209                 /*..falling..*/
210 #endif
211         case STATE_DATA:
212                 xp = pkt;
213                 s = (ushort *)pkt;
214                 *s++ = htons(TFTP_ACK);
215                 *s++ = htons(TftpBlock);
216                 pkt = (uchar *)s;
217                 len = pkt - xp;
218                 break;
219
220         case STATE_TOO_LARGE:
221                 xp = pkt;
222                 s = (ushort *)pkt;
223                 *s++ = htons(TFTP_ERROR);
224                 *s++ = htons(3);
225                 pkt = (uchar *)s;
226                 strcpy ((char *)pkt, "File too large");
227                 pkt += 14 /*strlen("File too large")*/ + 1;
228                 len = pkt - xp;
229                 break;
230
231         case STATE_BAD_MAGIC:
232                 xp = pkt;
233                 s = (ushort *)pkt;
234                 *s++ = htons(TFTP_ERROR);
235                 *s++ = htons(2);
236                 pkt = (uchar *)s;
237                 strcpy ((char *)pkt, "File has bad magic");
238                 pkt += 18 /*strlen("File has bad magic")*/ + 1;
239                 len = pkt - xp;
240                 break;
241         }
242
243         NetSendUDPPacket(NetServerEther, TftpServerIP, TftpServerPort, TftpOurPort, len);
244 }
245
246
247 static void
248 TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
249 {
250         ushort proto;
251         ushort *s;
252         int i;
253
254         if (dest != TftpOurPort) {
255 #ifdef CONFIG_MCAST_TFTP
256                 if (Multicast
257                  && (!Mcast_port || (dest != Mcast_port)))
258 #endif
259                 return;
260         }
261         if (TftpState != STATE_RRQ && src != TftpServerPort) {
262                 return;
263         }
264
265         if (len < 2) {
266                 return;
267         }
268         len -= 2;
269         /* warning: don't use increment (++) in ntohs() macros!! */
270         s = (ushort *)pkt;
271         proto = *s++;
272         pkt = (uchar *)s;
273         switch (ntohs(proto)) {
274
275         case TFTP_RRQ:
276         case TFTP_WRQ:
277         case TFTP_ACK:
278                 break;
279         default:
280                 break;
281
282         case TFTP_OACK:
283 #ifdef ET_DEBUG
284                 printf("Got OACK: %s %s\n", pkt, pkt+strlen(pkt)+1);
285 #endif
286                 TftpState = STATE_OACK;
287                 TftpServerPort = src;
288                 /*
289                  * Check for 'blksize' option.
290                  * Careful: "i" is signed, "len" is unsigned, thus
291                  * something like "len-8" may give a *huge* number
292                  */
293                 for (i=0; i+8<len; i++) {
294                         if (strcmp ((char*)pkt+i,"blksize") == 0) {
295                                 TftpBlkSize = (unsigned short)
296                                         simple_strtoul((char*)pkt+i+8,NULL,10);
297 #ifdef ET_DEBUG
298                                 printf ("Blocksize ack: %s, %d\n",
299                                         (char*)pkt+i+8,TftpBlkSize);
300 #endif
301                                 break;
302                         }
303                 }
304 #ifdef CONFIG_MCAST_TFTP
305                 parse_multicast_oack((char *)pkt,len-1);
306                 if ((Multicast) && (!MasterClient))
307                         TftpState = STATE_DATA; /* passive.. */
308                 else
309 #endif
310                 TftpSend (); /* Send ACK */
311                 break;
312         case TFTP_DATA:
313                 if (len < 2)
314                         return;
315                 len -= 2;
316                 TftpBlock = ntohs(*(ushort *)pkt);
317
318                 /*
319                  * RFC1350 specifies that the first data packet will
320                  * have sequence number 1. If we receive a sequence
321                  * number of 0 this means that there was a wrap
322                  * around of the (16 bit) counter.
323                  */
324                 if (TftpBlock == 0) {
325                         TftpBlockWrap++;
326                         TftpBlockWrapOffset += TftpBlkSize * TFTP_SEQUENCE_SIZE;
327                         printf ("\n\t %lu MB received\n\t ", TftpBlockWrapOffset>>20);
328                 } else {
329                         if (((TftpBlock - 1) % 10) == 0) {
330                                 putc ('#');
331                         } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
332                                 puts ("\n\t ");
333                         }
334                 }
335
336 #ifdef ET_DEBUG
337                 if (TftpState == STATE_RRQ) {
338                         puts ("Server did not acknowledge timeout option!\n");
339                 }
340 #endif
341
342                 if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
343                         /* first block received */
344                         TftpState = STATE_DATA;
345                         TftpServerPort = src;
346                         TftpLastBlock = 0;
347                         TftpBlockWrap = 0;
348                         TftpBlockWrapOffset = 0;
349
350 #ifdef CONFIG_MCAST_TFTP
351                         if (Multicast) { /* start!=1 common if mcast */
352                                 TftpLastBlock = TftpBlock - 1;
353                         } else
354 #endif
355                         if (TftpBlock != 1) {   /* Assertion */
356                                 printf ("\nTFTP error: "
357                                         "First block is not block 1 (%ld)\n"
358                                         "Starting again\n\n",
359                                         TftpBlock);
360                                 NetStartAgain ();
361                                 break;
362                         }
363                 }
364
365                 if (TftpBlock == TftpLastBlock) {
366                         /*
367                          *      Same block again; ignore it.
368                          */
369                         break;
370                 }
371
372                 TftpLastBlock = TftpBlock;
373                 NetSetTimeout (TIMEOUT, TftpTimeout);
374
375                 store_block (TftpBlock - 1, pkt + 2, len);
376
377                 /*
378                  *      Acknoledge the block just received, which will prompt
379                  *      the server for the next one.
380                  */
381 #ifdef CONFIG_MCAST_TFTP
382                 /* if I am the MasterClient, actively calculate what my next
383                  * needed block is; else I'm passive; not ACKING
384                  */
385                 if (Multicast) {
386                         if (len < TftpBlkSize)  {
387                                 TftpEndingBlock = TftpBlock;
388                         } else if (MasterClient) {
389                                 TftpBlock = PrevBitmapHole =
390                                         ext2_find_next_zero_bit(
391                                                 Bitmap,
392                                                 (Mapsize*8),
393                                                 PrevBitmapHole);
394                                 if (TftpBlock > ((Mapsize*8) - 1)) {
395                                         printf ("tftpfile too big\n");
396                                         /* try to double it and retry */
397                                         Mapsize<<=1;
398                                         mcast_cleanup();
399                                         NetStartAgain ();
400                                         return;
401                                 }
402                                 TftpLastBlock = TftpBlock;
403                         }
404                 }
405 #endif
406                 TftpSend ();
407
408 #ifdef CONFIG_MCAST_TFTP
409                 if (Multicast) {
410                         if (MasterClient && (TftpBlock >= TftpEndingBlock)) {
411                                 puts ("\nMulticast tftp done\n");
412                                 mcast_cleanup();
413                                 NetState = NETLOOP_SUCCESS;
414                         }
415                 }
416                 else
417 #endif
418                 if (len < TftpBlkSize) {
419                         /*
420                          *      We received the whole thing.  Try to
421                          *      run it.
422                          */
423                         puts ("\ndone\n");
424                         NetState = NETLOOP_SUCCESS;
425                 }
426                 break;
427
428         case TFTP_ERROR:
429                 printf ("\nTFTP error: '%s' (%d)\n",
430                                         pkt + 2, ntohs(*(ushort *)pkt));
431                 puts ("Starting again\n\n");
432 #ifdef CONFIG_MCAST_TFTP
433                 mcast_cleanup();
434 #endif
435                 NetStartAgain ();
436                 break;
437         }
438 }
439
440
441 static void
442 TftpTimeout (void)
443 {
444         if (++TftpTimeoutCount > TIMEOUT_COUNT) {
445                 puts ("\nRetry count exceeded; starting again\n");
446 #ifdef CONFIG_MCAST_TFTP
447                 mcast_cleanup();
448 #endif
449                 NetStartAgain ();
450         } else {
451                 puts ("T ");
452                 NetSetTimeout (TIMEOUT, TftpTimeout);
453                 TftpSend ();
454         }
455 }
456
457
458 void
459 TftpStart (void)
460 {
461 #ifdef CONFIG_TFTP_PORT
462         char *ep;             /* Environment pointer */
463 #endif
464
465         TftpServerIP = NetServerIP;
466         if (BootFile[0] == '\0') {
467                 sprintf(default_filename, "%02lX%02lX%02lX%02lX.img",
468                         NetOurIP & 0xFF,
469                         (NetOurIP >>  8) & 0xFF,
470                         (NetOurIP >> 16) & 0xFF,
471                         (NetOurIP >> 24) & 0xFF );
472
473                 strncpy(tftp_filename, default_filename, MAX_LEN);
474                 tftp_filename[MAX_LEN-1] = 0;
475
476                 printf ("*** Warning: no boot file name; using '%s'\n",
477                         tftp_filename);
478         } else {
479                 char *p = strchr (BootFile, ':');
480
481                 if (p == NULL) {
482                         strncpy(tftp_filename, BootFile, MAX_LEN);
483                         tftp_filename[MAX_LEN-1] = 0;
484                 } else {
485                         *p++ = '\0';
486                         TftpServerIP = string_to_ip (BootFile);
487                         strncpy(tftp_filename, p, MAX_LEN);
488                         tftp_filename[MAX_LEN-1] = 0;
489                 }
490         }
491
492 #if defined(CONFIG_NET_MULTI)
493         printf ("Using %s device\n", eth_get_name());
494 #endif
495         puts ("TFTP from server ");     print_IPaddr (TftpServerIP);
496         puts ("; our IP address is ");  print_IPaddr (NetOurIP);
497
498         /* Check if we need to send across this subnet */
499         if (NetOurGatewayIP && NetOurSubnetMask) {
500             IPaddr_t OurNet     = NetOurIP    & NetOurSubnetMask;
501             IPaddr_t ServerNet  = TftpServerIP & NetOurSubnetMask;
502
503             if (OurNet != ServerNet) {
504                 puts ("; sending through gateway ");
505                 print_IPaddr (NetOurGatewayIP) ;
506             }
507         }
508         putc ('\n');
509
510         printf ("Filename '%s'.", tftp_filename);
511
512         if (NetBootFileSize) {
513                 printf (" Size is 0x%x Bytes = ", NetBootFileSize<<9);
514                 print_size (NetBootFileSize<<9, "");
515         }
516
517         putc ('\n');
518
519         printf ("Load address: 0x%lx\n", load_addr);
520
521         puts ("Loading: *\b");
522
523         NetSetTimeout (TIMEOUT, TftpTimeout);
524         NetSetHandler (TftpHandler);
525
526         TftpServerPort = WELL_KNOWN_PORT;
527         TftpTimeoutCount = 0;
528         TftpState = STATE_RRQ;
529         /* Use a pseudo-random port unless a specific port is set */
530         TftpOurPort = 1024 + (get_timer(0) % 3072);
531
532 #ifdef CONFIG_TFTP_PORT
533         if ((ep = getenv("tftpdstp")) != NULL) {
534                 TftpServerPort = simple_strtol(ep, NULL, 10);
535         }
536         if ((ep = getenv("tftpsrcp")) != NULL) {
537                 TftpOurPort= simple_strtol(ep, NULL, 10);
538         }
539 #endif
540         TftpBlock = 0;
541
542         /* zero out server ether in case the server ip has changed */
543         memset(NetServerEther, 0, 6);
544         /* Revert TftpBlkSize to dflt */
545         TftpBlkSize = TFTP_BLOCK_SIZE;
546 #ifdef CONFIG_MCAST_TFTP
547         mcast_cleanup();
548 #endif
549
550         TftpSend ();
551 }
552
553 #ifdef CONFIG_MCAST_TFTP
554 /* Credits: atftp project.
555  */
556
557 /* pick up BcastAddr, Port, and whether I am [now] the master-client. *
558  * Frame:
559  *    +-------+-----------+---+-------~~-------+---+
560  *    |  opc  | multicast | 0 | addr, port, mc | 0 |
561  *    +-------+-----------+---+-------~~-------+---+
562  * The multicast addr/port becomes what I listen to, and if 'mc' is '1' then
563  * I am the new master-client so must send ACKs to DataBlocks.  If I am not
564  * master-client, I'm a passive client, gathering what DataBlocks I may and
565  * making note of which ones I got in my bitmask.
566  * In theory, I never go from master->passive..
567  * .. this comes in with pkt already pointing just past opc
568  */
569 static void parse_multicast_oack(char *pkt, int len)
570 {
571  int i;
572  IPaddr_t addr;
573  char *mc_adr, *port,  *mc;
574
575         mc_adr=port=mc=NULL;
576         /* march along looking for 'multicast\0', which has to start at least
577          * 14 bytes back from the end.
578          */
579         for (i=0;i<len-14;i++)
580                 if (strcmp (pkt+i,"multicast") == 0)
581                         break;
582         if (i >= (len-14)) /* non-Multicast OACK, ign. */
583                 return;
584
585         i+=10; /* strlen multicast */
586         mc_adr = pkt+i;
587         for (;i<len;i++) {
588                 if (*(pkt+i) == ',') {
589                         *(pkt+i) = '\0';
590                         if (port) {
591                                 mc = pkt+i+1;
592                                 break;
593                         } else {
594                                 port = pkt+i+1;
595                         }
596                 }
597         }
598         if (!port || !mc_adr || !mc ) return;
599         if (Multicast && MasterClient) {
600                 printf ("I got a OACK as master Client, WRONG!\n");
601                 return;
602         }
603         /* ..I now accept packets destined for this MCAST addr, port */
604         if (!Multicast) {
605                 if (Bitmap) {
606                         printf ("Internal failure! no mcast.\n");
607                         free(Bitmap);
608                         Bitmap=NULL;
609                         ProhibitMcast=1;
610                         return ;
611                 }
612                 /* I malloc instead of pre-declare; so that if the file ends
613                  * up being too big for this bitmap I can retry
614                  */
615                 if (!(Bitmap = malloc (Mapsize))) {
616                         printf ("No Bitmap, no multicast. Sorry.\n");
617                         ProhibitMcast=1;
618                         return;
619                 }
620                 memset (Bitmap,0,Mapsize);
621                 PrevBitmapHole = 0;
622                 Multicast = 1;
623         }
624         addr = string_to_ip(mc_adr);
625         if (Mcast_addr != addr) {
626                 if (Mcast_addr)
627                         eth_mcast_join(Mcast_addr, 0);
628                 if (eth_mcast_join(Mcast_addr=addr, 1)) {
629                         printf ("Fail to set mcast, revert to TFTP\n");
630                         ProhibitMcast=1;
631                         mcast_cleanup();
632                         NetStartAgain();
633                 }
634         }
635         MasterClient = (unsigned char)simple_strtoul((char *)mc,NULL,10);
636         Mcast_port = (unsigned short)simple_strtoul(port,NULL,10);
637         printf ("Multicast: %s:%d [%d]\n", mc_adr, Mcast_port, MasterClient);
638         return;
639 }
640
641 #endif /* Multicast TFTP */
642
643 #endif