X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=net%2Ftftp.c;h=2eace3dee1e9abb3112b195573005ff71d23418e;hb=2f09413fd9ca949715d77f31b5a695bbb142e8c6;hp=84d83ca97b1e9f333efe1fa780c3803ce6cadca5;hpb=859f24350e6e4313626f85161dd03f025a4dac59;p=karo-tx-uboot.git diff --git a/net/tftp.c b/net/tftp.c index 84d83ca97b..2eace3dee1 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -1,7 +1,7 @@ /* - * Copyright 1994, 1995, 2000 Neil Russell. - * (See License) - * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de + * Copyright 1994, 1995, 2000 Neil Russell. + * (See License) + * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de */ #include @@ -10,19 +10,18 @@ #include "tftp.h" #include "bootp.h" -#undef ET_DEBUG - -#if defined(CONFIG_CMD_NET) - -#define WELL_KNOWN_PORT 69 /* Well known TFTP port # */ -#define TIMEOUT 5UL /* Seconds to timeout for a lost pkt */ +/* Well known TFTP port # */ +#define WELL_KNOWN_PORT 69 +/* Millisecs to timeout for lost pkt */ +#define TIMEOUT 5000UL #ifndef CONFIG_NET_RETRY_COUNT -# define TIMEOUT_COUNT 10 /* # of timeouts before giving up */ +/* # of timeouts before giving up */ +# define TIMEOUT_COUNT 10 #else # define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2) #endif - /* (for checking the image size) */ -#define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */ +/* Number of "loading" hashes per line (for checking the image size) */ +#define HASHES_PER_LINE 65 /* * TFTP operations. @@ -34,15 +33,52 @@ #define TFTP_ERROR 5 #define TFTP_OACK 6 +static ulong TftpTimeoutMSecs = TIMEOUT; +static int TftpTimeoutCountMax = TIMEOUT_COUNT; + +/* + * These globals govern the timeout behavior when attempting a connection to a + * TFTP server. TftpRRQTimeoutMSecs specifies the number of milliseconds to + * wait for the server to respond to initial connection. Second global, + * TftpRRQTimeoutCountMax, gives the number of such connection retries. + * TftpRRQTimeoutCountMax must be non-negative and TftpRRQTimeoutMSecs must be + * positive. The globals are meant to be set (and restored) by code needing + * non-standard timeout behavior when initiating a TFTP transfer. + */ +ulong TftpRRQTimeoutMSecs = TIMEOUT; +int TftpRRQTimeoutCountMax = TIMEOUT_COUNT; + +enum { + TFTP_ERR_UNDEFINED = 0, + TFTP_ERR_FILE_NOT_FOUND = 1, + TFTP_ERR_ACCESS_DENIED = 2, + TFTP_ERR_DISK_FULL = 3, + TFTP_ERR_UNEXPECTED_OPCODE = 4, + TFTP_ERR_UNKNOWN_TRANSFER_ID = 5, + TFTP_ERR_FILE_ALREADY_EXISTS = 6, +}; + static IPaddr_t TftpServerIP; -static int TftpServerPort; /* The UDP port at their end */ -static int TftpOurPort; /* The UDP port at our end */ +/* The UDP port at their end */ +static int TftpServerPort; +/* The UDP port at our end */ +static int TftpOurPort; static int TftpTimeoutCount; -static ulong TftpBlock; /* packet sequence number */ -static ulong TftpLastBlock; /* last packet sequence number received */ -static ulong TftpBlockWrap; /* count of sequence number wraparounds */ -static ulong TftpBlockWrapOffset; /* memory offset due to wrapping */ +/* packet sequence number */ +static ulong TftpBlock; +/* last packet sequence number received */ +static ulong TftpLastBlock; +/* count of sequence number wraparounds */ +static ulong TftpBlockWrap; +/* memory offset due to wrapping */ +static ulong TftpBlockWrapOffset; static int TftpState; +#ifdef CONFIG_TFTP_TSIZE +/* The file size reported by the server */ +static int TftpTsize; +/* The number of hashes we printed */ +static short TftpNumchars; +#endif #define STATE_RRQ 1 #define STATE_DATA 2 @@ -50,8 +86,10 @@ static int TftpState; #define STATE_BAD_MAGIC 4 #define STATE_OACK 5 -#define TFTP_BLOCK_SIZE 512 /* default TFTP block size */ -#define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) /* sequence number is 16 bit */ +/* default TFTP block size */ +#define TFTP_BLOCK_SIZE 512 +/* sequence number is 16 bit */ +#define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) #define DEFAULT_NAME_LEN (8 + 4 + 1) static char default_filename[DEFAULT_NAME_LEN]; @@ -64,15 +102,21 @@ static char default_filename[DEFAULT_NAME_LEN]; static char tftp_filename[MAX_LEN]; -#ifdef CFG_DIRECT_FLASH_TFTP +#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP extern flash_info_t flash_info[]; #endif /* 512 is poor choice for ethernet, MTU is typically 1500. * Minus eth.hdrs thats 1468. Can get 2x better throughput with * almost-MTU block sizes. At least try... fall back to 512 if need be. + * (but those using CONFIG_IP_DEFRAG may want to set a larger block in cfg file) */ +#ifdef CONFIG_TFTP_BLOCKSIZE +#define TFTP_MTU_BLOCKSIZE CONFIG_TFTP_BLOCKSIZE +#else #define TFTP_MTU_BLOCKSIZE 1468 +#endif + static unsigned short TftpBlkSize=TFTP_BLOCK_SIZE; static unsigned short TftpBlkSizeOption=TFTP_MTU_BLOCKSIZE; @@ -106,11 +150,13 @@ store_block (unsigned block, uchar * src, unsigned len) { ulong offset = block * TftpBlkSize + TftpBlockWrapOffset; ulong newsize = offset + len; -#ifdef CFG_DIRECT_FLASH_TFTP +#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP int i, rc = 0; - for (i=0; i= flash_info[i].start[0]) { rc = 1; break; @@ -126,7 +172,7 @@ store_block (unsigned block, uchar * src, unsigned len) } } else -#endif /* CFG_DIRECT_FLASH_TFTP */ +#endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ { (void)memcpy((void *)(load_addr + offset), src, len); } @@ -178,11 +224,13 @@ TftpSend (void) pkt += 5 /*strlen("octet")*/ + 1; strcpy ((char *)pkt, "timeout"); pkt += 7 /*strlen("timeout")*/ + 1; - sprintf((char *)pkt, "%lu", TIMEOUT); -#ifdef ET_DEBUG - printf("send option \"timeout %s\"\n", (char *)pkt); -#endif + sprintf((char *)pkt, "%lu", TftpTimeoutMSecs / 1000); + debug("send option \"timeout %s\"\n", (char *)pkt); pkt += strlen((char *)pkt) + 1; +#ifdef CONFIG_TFTP_TSIZE + memcpy((char *)pkt, "tsize\0000\0", 8); + pkt += 8; +#endif /* try for more effic. blk size */ pkt += sprintf((char *)pkt,"blksize%c%d%c", 0,TftpBlkSizeOption,0); @@ -238,12 +286,14 @@ TftpSend (void) break; } - NetSendUDPPacket(NetServerEther, TftpServerIP, TftpServerPort, TftpOurPort, len); + NetSendUDPPacket(NetServerEther, TftpServerIP, TftpServerPort, + TftpOurPort, len); } static void -TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) +TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, + unsigned len) { ushort proto; ushort *s; @@ -278,9 +328,9 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) break; case TFTP_OACK: -#ifdef ET_DEBUG - printf("Got OACK: %s %s\n", pkt, pkt+strlen(pkt)+1); -#endif + debug("Got OACK: %s %s\n", + pkt, + pkt + strlen((char *)pkt) + 1); TftpState = STATE_OACK; TftpServerPort = src; /* @@ -292,12 +342,17 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) if (strcmp ((char*)pkt+i,"blksize") == 0) { TftpBlkSize = (unsigned short) simple_strtoul((char*)pkt+i+8,NULL,10); -#ifdef ET_DEBUG - printf ("Blocksize ack: %s, %d\n", + debug("Blocksize ack: %s, %d\n", (char*)pkt+i+8,TftpBlkSize); -#endif - break; } +#ifdef CONFIG_TFTP_TSIZE + if (strcmp ((char*)pkt+i,"tsize") == 0) { + TftpTsize = simple_strtoul((char*)pkt+i+6, + NULL, 10); + debug("size = %s, %d\n", + (char*)pkt+i+6, TftpTsize); + } +#endif } #ifdef CONFIG_MCAST_TFTP parse_multicast_oack((char *)pkt,len-1); @@ -321,9 +376,21 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) */ if (TftpBlock == 0) { TftpBlockWrap++; - TftpBlockWrapOffset += TftpBlkSize * TFTP_SEQUENCE_SIZE; - printf ("\n\t %lu MB received\n\t ", TftpBlockWrapOffset>>20); - } else { + TftpBlockWrapOffset += + TftpBlkSize * TFTP_SEQUENCE_SIZE; + printf ("\n\t %lu MB received\n\t ", + TftpBlockWrapOffset>>20); + } +#ifdef CONFIG_TFTP_TSIZE + else if (TftpTsize) { + while (TftpNumchars < + NetBootFileXferSize * 50 / TftpTsize) { + putc('#'); + TftpNumchars++; + } + } +#endif + else { if (((TftpBlock - 1) % 10) == 0) { putc ('#'); } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) { @@ -331,11 +398,8 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) } } -#ifdef ET_DEBUG - if (TftpState == STATE_RRQ) { - puts ("Server did not acknowledge timeout option!\n"); - } -#endif + if (TftpState == STATE_RRQ) + debug("Server did not acknowledge timeout option!\n"); if (TftpState == STATE_RRQ || TftpState == STATE_OACK) { /* first block received */ @@ -368,7 +432,8 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) } TftpLastBlock = TftpBlock; - NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout); + TftpTimeoutCountMax = TIMEOUT_COUNT; + NetSetTimeout (TftpTimeoutMSecs, TftpTimeout); store_block (TftpBlock - 1, pkt + 2, len); @@ -418,6 +483,13 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) * We received the whole thing. Try to * run it. */ +#ifdef CONFIG_TFTP_TSIZE + /* Print hash marks for the last packet received */ + while (TftpTsize && TftpNumchars < 49) { + putc('#'); + TftpNumchars++; + } +#endif puts ("\ndone\n"); NetState = NETLOOP_SUCCESS; } @@ -426,11 +498,27 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) case TFTP_ERROR: printf ("\nTFTP error: '%s' (%d)\n", pkt + 2, ntohs(*(ushort *)pkt)); - puts ("Starting again\n\n"); + + switch (ntohs(*(ushort *)pkt)) { + case TFTP_ERR_FILE_NOT_FOUND: + case TFTP_ERR_ACCESS_DENIED: + puts("Not retrying...\n"); + eth_halt(); + NetState = NETLOOP_FAIL; + break; + case TFTP_ERR_UNDEFINED: + case TFTP_ERR_DISK_FULL: + case TFTP_ERR_UNEXPECTED_OPCODE: + case TFTP_ERR_UNKNOWN_TRANSFER_ID: + case TFTP_ERR_FILE_ALREADY_EXISTS: + default: + puts("Starting again\n\n"); #ifdef CONFIG_MCAST_TFTP - mcast_cleanup(); + mcast_cleanup(); #endif - NetStartAgain (); + NetStartAgain(); + break; + } break; } } @@ -439,7 +527,7 @@ TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len) static void TftpTimeout (void) { - if (++TftpTimeoutCount > TIMEOUT_COUNT) { + if (++TftpTimeoutCount > TftpTimeoutCountMax) { puts ("\nRetry count exceeded; starting again\n"); #ifdef CONFIG_MCAST_TFTP mcast_cleanup(); @@ -447,7 +535,7 @@ TftpTimeout (void) NetStartAgain (); } else { puts ("T "); - NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout); + NetSetTimeout (TftpTimeoutMSecs, TftpTimeout); TftpSend (); } } @@ -456,9 +544,27 @@ TftpTimeout (void) void TftpStart (void) { -#ifdef CONFIG_TFTP_PORT char *ep; /* Environment pointer */ -#endif + + /* + * Allow the user to choose TFTP blocksize and timeout. + * TFTP protocol has a minimal timeout of 1 second. + */ + if ((ep = getenv("tftpblocksize")) != NULL) + TftpBlkSizeOption = simple_strtol(ep, NULL, 10); + + if ((ep = getenv("tftptimeout")) != NULL) + TftpTimeoutMSecs = simple_strtol(ep, NULL, 10); + + if (TftpTimeoutMSecs < 1000) { + printf("TFTP timeout (%ld ms) too low, " + "set minimum = 1000 ms\n", + TftpTimeoutMSecs); + TftpTimeoutMSecs = 1000; + } + + debug("TFTP blocksize = %i, timeout = %ld ms\n", + TftpBlkSizeOption, TftpTimeoutMSecs); TftpServerIP = NetServerIP; if (BootFile[0] == '\0') { @@ -480,9 +586,8 @@ TftpStart (void) strncpy(tftp_filename, BootFile, MAX_LEN); tftp_filename[MAX_LEN-1] = 0; } else { - *p++ = '\0'; TftpServerIP = string_to_ip (BootFile); - strncpy(tftp_filename, p, MAX_LEN); + strncpy(tftp_filename, p + 1, MAX_LEN); tftp_filename[MAX_LEN-1] = 0; } } @@ -490,18 +595,16 @@ TftpStart (void) #if defined(CONFIG_NET_MULTI) printf ("Using %s device\n", eth_get_name()); #endif - puts ("TFTP from server "); print_IPaddr (TftpServerIP); - puts ("; our IP address is "); print_IPaddr (NetOurIP); + printf("TFTP from server %pI4" + "; our IP address is %pI4", &TftpServerIP, &NetOurIP); /* Check if we need to send across this subnet */ if (NetOurGatewayIP && NetOurSubnetMask) { IPaddr_t OurNet = NetOurIP & NetOurSubnetMask; IPaddr_t ServerNet = TftpServerIP & NetOurSubnetMask; - if (OurNet != ServerNet) { - puts ("; sending through gateway "); - print_IPaddr (NetOurGatewayIP) ; - } + if (OurNet != ServerNet) + printf("; sending through gateway %pI4", &NetOurGatewayIP); } putc ('\n'); @@ -518,7 +621,9 @@ TftpStart (void) puts ("Loading: *\b"); - NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout); + TftpTimeoutCountMax = TftpRRQTimeoutCountMax; + + NetSetTimeout (TftpTimeoutMSecs, TftpTimeout); NetSetHandler (TftpHandler); TftpServerPort = WELL_KNOWN_PORT; @@ -544,6 +649,10 @@ TftpStart (void) #ifdef CONFIG_MCAST_TFTP mcast_cleanup(); #endif +#ifdef CONFIG_TFTP_TSIZE + TftpTsize = 0; + TftpNumchars = 0; +#endif TftpSend (); } @@ -637,5 +746,3 @@ static void parse_multicast_oack(char *pkt, int len) } #endif /* Multicast TFTP */ - -#endif