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 */ 316