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