Blame view
net/tftp.c
22.6 KB
fe8c2806c
|
1 |
/* |
2f09413fd
|
2 3 4 |
* Copyright 1994, 1995, 2000 Neil Russell. * (See License) * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de |
e59e35620
|
5 6 |
* Copyright 2011 Comelit Group SpA, * Luca Ceresoli <luca.ceresoli@comelit.it> |
fe8c2806c
|
7 8 9 10 11 12 13 |
*/ #include <common.h> #include <command.h> #include <net.h> #include "tftp.h" #include "bootp.h" |
13dfe9437
|
14 15 16 |
#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP #include <flash.h> #endif |
fe8c2806c
|
17 |
|
2f09413fd
|
18 19 20 21 |
/* Well known TFTP port # */ #define WELL_KNOWN_PORT 69 /* Millisecs to timeout for lost pkt */ #define TIMEOUT 5000UL |
fe8c2806c
|
22 |
#ifndef CONFIG_NET_RETRY_COUNT |
2f09413fd
|
23 24 |
/* # of timeouts before giving up */ # define TIMEOUT_COUNT 10 |
fe8c2806c
|
25 26 27 |
#else # define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2) #endif |
2f09413fd
|
28 29 |
/* Number of "loading" hashes per line (for checking the image size) */ #define HASHES_PER_LINE 65 |
fe8c2806c
|
30 31 32 33 34 35 36 37 38 |
/* * TFTP operations. */ #define TFTP_RRQ 1 #define TFTP_WRQ 2 #define TFTP_DATA 3 #define TFTP_ACK 4 #define TFTP_ERROR 5 |
fbe4b5cbd
|
39 |
#define TFTP_OACK 6 |
fe8c2806c
|
40 |
|
e83cc0637
|
41 42 |
static ulong TftpTimeoutMSecs = TIMEOUT; static int TftpTimeoutCountMax = TIMEOUT_COUNT; |
85b198027
|
43 |
static ulong time_start; /* Record time we started tftp */ |
e83cc0637
|
44 45 46 47 48 49 50 51 52 53 54 55 |
/* * 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; |
aafda38fb
|
56 57 58 59 60 61 62 63 64 |
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, }; |
20478ceaa
|
65 |
static IPaddr_t TftpRemoteIP; |
2f09413fd
|
66 |
/* The UDP port at their end */ |
20478ceaa
|
67 |
static int TftpRemotePort; |
2f09413fd
|
68 69 |
/* The UDP port at our end */ static int TftpOurPort; |
fe8c2806c
|
70 |
static int TftpTimeoutCount; |
2f09413fd
|
71 72 73 74 75 76 77 78 |
/* 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; |
fe8c2806c
|
79 |
static int TftpState; |
4fccb818e
|
80 |
#ifdef CONFIG_TFTP_TSIZE |
2f09413fd
|
81 82 83 84 |
/* The file size reported by the server */ static int TftpTsize; /* The number of hashes we printed */ static short TftpNumchars; |
4fccb818e
|
85 |
#endif |
1fb7cd498
|
86 87 88 89 90 91 |
#ifdef CONFIG_CMD_TFTPPUT static int TftpWriting; /* 1 if writing, else 0 */ static int TftpFinalBlock; /* 1 if we have sent the last block */ #else #define TftpWriting 0 #endif |
3f85ce278
|
92 |
|
e3fb0abe2
|
93 |
#define STATE_SEND_RRQ 1 |
fe8c2806c
|
94 95 96 |
#define STATE_DATA 2 #define STATE_TOO_LARGE 3 #define STATE_BAD_MAGIC 4 |
fbe4b5cbd
|
97 |
#define STATE_OACK 5 |
e59e35620
|
98 |
#define STATE_RECV_WRQ 6 |
1fb7cd498
|
99 |
#define STATE_SEND_WRQ 7 |
fe8c2806c
|
100 |
|
2f09413fd
|
101 102 103 104 |
/* default TFTP block size */ #define TFTP_BLOCK_SIZE 512 /* sequence number is 16 bit */ #define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) |
3f85ce278
|
105 |
|
fe8c2806c
|
106 107 |
#define DEFAULT_NAME_LEN (8 + 4 + 1) static char default_filename[DEFAULT_NAME_LEN]; |
a93907c43
|
108 109 110 111 112 113 114 115 |
#ifndef CONFIG_TFTP_FILE_NAME_MAX_LEN #define MAX_LEN 128 #else #define MAX_LEN CONFIG_TFTP_FILE_NAME_MAX_LEN #endif static char tftp_filename[MAX_LEN]; |
fe8c2806c
|
116 |
|
85eb5caf6
|
117 118 |
/* 512 is poor choice for ethernet, MTU is typically 1500. * Minus eth.hdrs thats 1468. Can get 2x better throughput with |
53a5c424b
|
119 |
* almost-MTU block sizes. At least try... fall back to 512 if need be. |
89ba81d10
|
120 |
* (but those using CONFIG_IP_DEFRAG may want to set a larger block in cfg file) |
53a5c424b
|
121 |
*/ |
89ba81d10
|
122 123 124 |
#ifdef CONFIG_TFTP_BLOCKSIZE #define TFTP_MTU_BLOCKSIZE CONFIG_TFTP_BLOCKSIZE #else |
53a5c424b
|
125 |
#define TFTP_MTU_BLOCKSIZE 1468 |
89ba81d10
|
126 |
#endif |
c718b1439
|
127 128 |
static unsigned short TftpBlkSize = TFTP_BLOCK_SIZE; static unsigned short TftpBlkSizeOption = TFTP_MTU_BLOCKSIZE; |
53a5c424b
|
129 130 131 132 133 |
#ifdef CONFIG_MCAST_TFTP #include <malloc.h> #define MTFTP_BITMAPSIZE 0x1000 static unsigned *Bitmap; |
c718b1439
|
134 |
static int PrevBitmapHole, Mapsize = MTFTP_BITMAPSIZE; |
9bb0a1bf9
|
135 136 |
static uchar ProhibitMcast, MasterClient; static uchar Multicast; |
53a5c424b
|
137 138 |
static int Mcast_port; static ulong TftpEndingBlock; /* can get 'last' block before done..*/ |
c718b1439
|
139 |
static void parse_multicast_oack(char *pkt, int len); |
53a5c424b
|
140 141 142 143 |
static void mcast_cleanup(void) { |
6d2231e8f
|
144 145 146 147 |
if (Mcast_addr) eth_mcast_join(Mcast_addr, 0); if (Bitmap) free(Bitmap); |
c718b1439
|
148 |
Bitmap = NULL; |
53a5c424b
|
149 150 151 152 153 |
Mcast_addr = Multicast = Mcast_port = 0; TftpEndingBlock = -1; } #endif /* CONFIG_MCAST_TFTP */ |
13dfe9437
|
154 |
static inline void |
bc46dfac2
|
155 |
store_block(int block, uchar *src, unsigned len) |
fe8c2806c
|
156 |
{ |
53a5c424b
|
157 |
ulong offset = block * TftpBlkSize + TftpBlockWrapOffset; |
3f85ce278
|
158 |
ulong newsize = offset + len; |
6d0f6bcf3
|
159 |
#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP |
fe8c2806c
|
160 |
int i, rc = 0; |
c718b1439
|
161 |
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { |
fe8c2806c
|
162 |
/* start address in flash? */ |
be1b0d277
|
163 164 |
if (flash_info[i].flash_id == FLASH_UNKNOWN) continue; |
fe8c2806c
|
165 166 167 168 169 170 171 |
if (load_addr + offset >= flash_info[i].start[0]) { rc = 1; break; } } if (rc) { /* Flash is destination for this packet */ |
c718b1439
|
172 |
rc = flash_write((char *)src, (ulong)(load_addr+offset), len); |
fe8c2806c
|
173 |
if (rc) { |
c718b1439
|
174 |
flash_perror(rc); |
22f6e99d5
|
175 |
net_set_state(NETLOOP_FAIL); |
fe8c2806c
|
176 177 |
return; } |
13dfe9437
|
178 |
} else |
6d0f6bcf3
|
179 |
#endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */ |
fe8c2806c
|
180 181 182 |
{ (void)memcpy((void *)(load_addr + offset), src, len); } |
53a5c424b
|
183 184 185 186 |
#ifdef CONFIG_MCAST_TFTP if (Multicast) ext2_set_bit(block, Bitmap); #endif |
fe8c2806c
|
187 188 189 190 |
if (NetBootFileXferSize < newsize) NetBootFileXferSize = newsize; } |
e4cde2f70
|
191 |
/* Clear our state ready for a new transfer */ |
165099e75
|
192 |
static void new_transfer(void) |
e4cde2f70
|
193 194 195 196 197 198 199 200 |
{ TftpLastBlock = 0; TftpBlockWrap = 0; TftpBlockWrapOffset = 0; #ifdef CONFIG_CMD_TFTPPUT TftpFinalBlock = 0; #endif } |
1fb7cd498
|
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
#ifdef CONFIG_CMD_TFTPPUT /** * Load the next block from memory to be sent over tftp. * * @param block Block number to send * @param dst Destination buffer for data * @param len Number of bytes in block (this one and every other) * @return number of bytes loaded */ static int load_block(unsigned block, uchar *dst, unsigned len) { /* We may want to get the final block from the previous set */ ulong offset = ((int)block - 1) * len + TftpBlockWrapOffset; ulong tosend = len; tosend = min(NetBootFileXferSize - offset, tosend); (void)memcpy(dst, (void *)(save_addr + offset), tosend); debug("%s: block=%d, offset=%ld, len=%d, tosend=%ld ", __func__, block, offset, len, tosend); return tosend; } #endif |
c718b1439
|
224 225 |
static void TftpSend(void); static void TftpTimeout(void); |
fe8c2806c
|
226 227 |
/**********************************************************************/ |
f5329bbc3
|
228 229 230 231 232 233 234 235 236 237 |
static void show_block_marker(void) { #ifdef CONFIG_TFTP_TSIZE if (TftpTsize) { ulong pos = TftpBlock * TftpBlkSize + TftpBlockWrapOffset; while (TftpNumchars < pos * 50 / TftpTsize) { putc('#'); TftpNumchars++; } |
1fb7cd498
|
238 |
} else |
f5329bbc3
|
239 |
#endif |
1fb7cd498
|
240 |
{ |
f5329bbc3
|
241 242 243 244 245 246 247 |
if (((TftpBlock - 1) % 10) == 0) putc('#'); else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) puts(" \t "); } } |
e4cde2f70
|
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
/** * restart the current transfer due to an error * * @param msg Message to print for user */ static void restart(const char *msg) { printf(" %s; starting again ", msg); #ifdef CONFIG_MCAST_TFTP mcast_cleanup(); #endif NetStartAgain(); } /* * Check if the block number has wrapped, and update progress * * TODO: The egregious use of global variables in this file should be tidied. */ static void update_block_number(void) { /* * RFC1350 specifies that the first data packet will * have sequence number 1. If we receive a sequence * number of 0 this means that there was a wrap * around of the (16 bit) counter. */ |
f754f5dc6
|
277 |
if (TftpBlock == 0 && TftpLastBlock != 0) { |
e4cde2f70
|
278 279 280 281 282 283 284 |
TftpBlockWrap++; TftpBlockWrapOffset += TftpBlkSize * TFTP_SEQUENCE_SIZE; TftpTimeoutCount = 0; /* we've done well, reset thhe timeout */ } else { show_block_marker(); } } |
f5329bbc3
|
285 286 287 288 289 290 291 292 293 294 |
/* The TFTP get or put is complete */ static void tftp_complete(void) { #ifdef CONFIG_TFTP_TSIZE /* Print hash marks for the last packet received */ while (TftpTsize && TftpNumchars < 49) { putc('#'); TftpNumchars++; } #endif |
85b198027
|
295 296 297 298 299 300 301 |
time_start = get_timer(time_start); if (time_start > 0) { puts(" \t "); /* Line up with "Loading: " */ print_size(NetBootFileXferSize / time_start * 1000, "/s"); } |
f5329bbc3
|
302 303 304 |
puts(" done "); |
22f6e99d5
|
305 |
net_set_state(NETLOOP_SUCCESS); |
f5329bbc3
|
306 |
} |
fe8c2806c
|
307 |
static void |
c718b1439
|
308 |
TftpSend(void) |
fe8c2806c
|
309 |
{ |
1fb7cd498
|
310 |
uchar *pkt; |
db288a960
|
311 312 313 |
uchar *xp; int len = 0; ushort *s; |
fe8c2806c
|
314 |
|
85eb5caf6
|
315 |
#ifdef CONFIG_MCAST_TFTP |
53a5c424b
|
316 |
/* Multicast TFTP.. non-MasterClients do not ACK data. */ |
85eb5caf6
|
317 318 319 |
if (Multicast && (TftpState == STATE_DATA) && (MasterClient == 0)) |
53a5c424b
|
320 321 |
return; #endif |
fe8c2806c
|
322 323 324 325 |
/* * We will always be sending some sort of packet, so * cobble together the packet headers now. */ |
594c26f8a
|
326 |
pkt = NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; |
fe8c2806c
|
327 328 |
switch (TftpState) { |
e3fb0abe2
|
329 |
case STATE_SEND_RRQ: |
1fb7cd498
|
330 |
case STATE_SEND_WRQ: |
fe8c2806c
|
331 |
xp = pkt; |
7bc5ee078
|
332 |
s = (ushort *)pkt; |
8c6914f10
|
333 |
#ifdef CONFIG_CMD_TFTPPUT |
1fb7cd498
|
334 335 |
*s++ = htons(TftpState == STATE_SEND_RRQ ? TFTP_RRQ : TFTP_WRQ); |
8c6914f10
|
336 337 338 |
#else *s++ = htons(TFTP_RRQ); #endif |
7bc5ee078
|
339 |
pkt = (uchar *)s; |
c718b1439
|
340 |
strcpy((char *)pkt, tftp_filename); |
fe8c2806c
|
341 |
pkt += strlen(tftp_filename) + 1; |
c718b1439
|
342 |
strcpy((char *)pkt, "octet"); |
fe8c2806c
|
343 |
pkt += 5 /*strlen("octet")*/ + 1; |
c718b1439
|
344 |
strcpy((char *)pkt, "timeout"); |
fbe4b5cbd
|
345 |
pkt += 7 /*strlen("timeout")*/ + 1; |
c96f86eef
|
346 |
sprintf((char *)pkt, "%lu", TftpTimeoutMSecs / 1000); |
0ebf04c60
|
347 348 |
debug("send option \"timeout %s\" ", (char *)pkt); |
fbe4b5cbd
|
349 |
pkt += strlen((char *)pkt) + 1; |
4fccb818e
|
350 |
#ifdef CONFIG_TFTP_TSIZE |
1fb7cd498
|
351 352 |
pkt += sprintf((char *)pkt, "tsize%c%lu%c", 0, NetBootFileXferSize, 0); |
4fccb818e
|
353 |
#endif |
53a5c424b
|
354 |
/* try for more effic. blk size */ |
c718b1439
|
355 356 |
pkt += sprintf((char *)pkt, "blksize%c%d%c", 0, TftpBlkSizeOption, 0); |
85eb5caf6
|
357 |
#ifdef CONFIG_MCAST_TFTP |
53a5c424b
|
358 |
/* Check all preconditions before even trying the option */ |
13dfe9437
|
359 360 361 362 363 364 365 366 |
if (!ProhibitMcast) { Bitmap = malloc(Mapsize); if (Bitmap && eth_get_dev()->mcast) { free(Bitmap); Bitmap = NULL; pkt += sprintf((char *)pkt, "multicast%c%c", 0, 0); } |
53a5c424b
|
367 368 |
} #endif /* CONFIG_MCAST_TFTP */ |
fe8c2806c
|
369 370 |
len = pkt - xp; break; |
fbe4b5cbd
|
371 |
case STATE_OACK: |
53a5c424b
|
372 373 374 |
#ifdef CONFIG_MCAST_TFTP /* My turn! Start at where I need blocks I missed.*/ if (Multicast) |
c718b1439
|
375 376 |
TftpBlock = ext2_find_next_zero_bit(Bitmap, (Mapsize*8), 0); |
53a5c424b
|
377 378 |
/*..falling..*/ #endif |
e59e35620
|
379 380 |
case STATE_RECV_WRQ: |
53a5c424b
|
381 |
case STATE_DATA: |
fe8c2806c
|
382 |
xp = pkt; |
7bc5ee078
|
383 |
s = (ushort *)pkt; |
1fb7cd498
|
384 385 386 387 388 389 390 391 392 393 394 395 396 |
s[0] = htons(TFTP_ACK); s[1] = htons(TftpBlock); pkt = (uchar *)(s + 2); #ifdef CONFIG_CMD_TFTPPUT if (TftpWriting) { int toload = TftpBlkSize; int loaded = load_block(TftpBlock, pkt, toload); s[0] = htons(TFTP_DATA); pkt += loaded; TftpFinalBlock = (loaded < toload); } #endif |
fe8c2806c
|
397 398 399 400 401 |
len = pkt - xp; break; case STATE_TOO_LARGE: xp = pkt; |
7bc5ee078
|
402 403 |
s = (ushort *)pkt; *s++ = htons(TFTP_ERROR); |
1fb7cd498
|
404 |
*s++ = htons(3); |
7bc5ee078
|
405 |
pkt = (uchar *)s; |
c718b1439
|
406 |
strcpy((char *)pkt, "File too large"); |
fe8c2806c
|
407 408 409 410 411 412 |
pkt += 14 /*strlen("File too large")*/ + 1; len = pkt - xp; break; case STATE_BAD_MAGIC: xp = pkt; |
7bc5ee078
|
413 414 415 416 |
s = (ushort *)pkt; *s++ = htons(TFTP_ERROR); *s++ = htons(2); pkt = (uchar *)s; |
c718b1439
|
417 |
strcpy((char *)pkt, "File has bad magic"); |
fe8c2806c
|
418 419 420 421 |
pkt += 18 /*strlen("File has bad magic")*/ + 1; len = pkt - xp; break; } |
20478ceaa
|
422 |
NetSendUDPPacket(NetServerEther, TftpRemoteIP, TftpRemotePort, |
2f09413fd
|
423 |
TftpOurPort, len); |
fe8c2806c
|
424 |
} |
39bccd21d
|
425 |
#ifdef CONFIG_CMD_TFTPPUT |
1fb7cd498
|
426 427 428 429 430 431 432 433 |
static void icmp_handler(unsigned type, unsigned code, unsigned dest, IPaddr_t sip, unsigned src, uchar *pkt, unsigned len) { if (type == ICMP_NOT_REACH && code == ICMP_NOT_REACH_PORT) { /* Oh dear the other end has gone away */ restart("TFTP server died"); } } |
39bccd21d
|
434 |
#endif |
1fb7cd498
|
435 |
|
fe8c2806c
|
436 |
static void |
03eb129f8
|
437 438 |
TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) |
fe8c2806c
|
439 |
{ |
61fdd4f7c
|
440 441 |
__be16 proto; __be16 *s; |
ff13ac8c7
|
442 |
int i; |
fe8c2806c
|
443 444 |
if (dest != TftpOurPort) { |
53a5c424b
|
445 |
#ifdef CONFIG_MCAST_TFTP |
85eb5caf6
|
446 |
if (Multicast |
53a5c424b
|
447 448 |
&& (!Mcast_port || (dest != Mcast_port))) #endif |
0bdd8acc3
|
449 |
return; |
fe8c2806c
|
450 |
} |
e59e35620
|
451 |
if (TftpState != STATE_SEND_RRQ && src != TftpRemotePort && |
1fb7cd498
|
452 |
TftpState != STATE_RECV_WRQ && TftpState != STATE_SEND_WRQ) |
fe8c2806c
|
453 |
return; |
fe8c2806c
|
454 |
|
7bc325a1b
|
455 |
if (len < 2) |
fe8c2806c
|
456 |
return; |
fe8c2806c
|
457 458 |
len -= 2; /* warning: don't use increment (++) in ntohs() macros!! */ |
61fdd4f7c
|
459 |
s = (__be16 *)pkt; |
7bc5ee078
|
460 461 |
proto = *s++; pkt = (uchar *)s; |
fe8c2806c
|
462 463 464 |
switch (ntohs(proto)) { case TFTP_RRQ: |
1fb7cd498
|
465 |
break; |
fe8c2806c
|
466 |
case TFTP_ACK: |
1fb7cd498
|
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 |
#ifdef CONFIG_CMD_TFTPPUT if (TftpWriting) { if (TftpFinalBlock) { tftp_complete(); } else { /* * Move to the next block. We want our block * count to wrap just like the other end! */ int block = ntohs(*s); int ack_ok = (TftpBlock == block); TftpBlock = (unsigned short)(block + 1); update_block_number(); if (ack_ok) TftpSend(); /* Send next data block */ } } #endif |
fe8c2806c
|
486 |
break; |
1fb7cd498
|
487 |
|
fe8c2806c
|
488 489 |
default: break; |
e59e35620
|
490 491 492 493 494 495 496 |
#ifdef CONFIG_CMD_TFTPSRV case TFTP_WRQ: debug("Got WRQ "); TftpRemoteIP = sip; TftpRemotePort = src; TftpOurPort = 1024 + (get_timer(0) % 3072); |
e4cde2f70
|
497 |
new_transfer(); |
e59e35620
|
498 499 500 |
TftpSend(); /* Send ACK(0) */ break; #endif |
fbe4b5cbd
|
501 |
case TFTP_OACK: |
d371708a1
|
502 503 504 505 |
debug("Got OACK: %s %s ", pkt, pkt + strlen((char *)pkt) + 1); |
fbe4b5cbd
|
506 |
TftpState = STATE_OACK; |
20478ceaa
|
507 |
TftpRemotePort = src; |
60174746c
|
508 509 510 511 512 |
/* * Check for 'blksize' option. * Careful: "i" is signed, "len" is unsigned, thus * something like "len-8" may give a *huge* number */ |
c718b1439
|
513 |
for (i = 0; i+8 < len; i++) { |
2e320257c
|
514 |
if (strcmp((char *)pkt+i, "blksize") == 0) { |
ff13ac8c7
|
515 |
TftpBlkSize = (unsigned short) |
2e320257c
|
516 |
simple_strtoul((char *)pkt+i+8, NULL, |
c718b1439
|
517 |
10); |
0ebf04c60
|
518 519 |
debug("Blocksize ack: %s, %d ", |
2e320257c
|
520 |
(char *)pkt+i+8, TftpBlkSize); |
ff13ac8c7
|
521 |
} |
4fccb818e
|
522 |
#ifdef CONFIG_TFTP_TSIZE |
2e320257c
|
523 524 |
if (strcmp((char *)pkt+i, "tsize") == 0) { TftpTsize = simple_strtoul((char *)pkt+i+6, |
2f09413fd
|
525 |
NULL, 10); |
4fccb818e
|
526 527 |
debug("size = %s, %d ", |
2e320257c
|
528 |
(char *)pkt+i+6, TftpTsize); |
4fccb818e
|
529 530 |
} #endif |
53a5c424b
|
531 532 |
} #ifdef CONFIG_MCAST_TFTP |
c718b1439
|
533 |
parse_multicast_oack((char *)pkt, len-1); |
85eb5caf6
|
534 |
if ((Multicast) && (!MasterClient)) |
53a5c424b
|
535 536 537 |
TftpState = STATE_DATA; /* passive.. */ else #endif |
1fb7cd498
|
538 539 540 541 542 543 544 545 |
#ifdef CONFIG_CMD_TFTPPUT if (TftpWriting) { /* Get ready to send the first block */ TftpState = STATE_DATA; TftpBlock++; } #endif TftpSend(); /* Send ACK or first data block */ |
fbe4b5cbd
|
546 |
break; |
fe8c2806c
|
547 548 549 550 |
case TFTP_DATA: if (len < 2) return; len -= 2; |
61fdd4f7c
|
551 |
TftpBlock = ntohs(*(__be16 *)pkt); |
3f85ce278
|
552 |
|
e4cde2f70
|
553 |
update_block_number(); |
fe8c2806c
|
554 |
|
e3fb0abe2
|
555 |
if (TftpState == STATE_SEND_RRQ) |
0ebf04c60
|
556 557 |
debug("Server did not acknowledge timeout option! "); |
fbe4b5cbd
|
558 |
|
e59e35620
|
559 560 |
if (TftpState == STATE_SEND_RRQ || TftpState == STATE_OACK || TftpState == STATE_RECV_WRQ) { |
3f85ce278
|
561 |
/* first block received */ |
fe8c2806c
|
562 |
TftpState = STATE_DATA; |
20478ceaa
|
563 |
TftpRemotePort = src; |
e4cde2f70
|
564 |
new_transfer(); |
fe8c2806c
|
565 |
|
53a5c424b
|
566 567 568 569 570 |
#ifdef CONFIG_MCAST_TFTP if (Multicast) { /* start!=1 common if mcast */ TftpLastBlock = TftpBlock - 1; } else #endif |
fe8c2806c
|
571 |
if (TftpBlock != 1) { /* Assertion */ |
c718b1439
|
572 573 574 575 576 577 578 |
printf(" TFTP error: " "First block is not block 1 (%ld) " "Starting again ", |
fe8c2806c
|
579 |
TftpBlock); |
c718b1439
|
580 |
NetStartAgain(); |
fe8c2806c
|
581 582 583 584 585 586 587 588 589 590 591 592 |
break; } } if (TftpBlock == TftpLastBlock) { /* * Same block again; ignore it. */ break; } TftpLastBlock = TftpBlock; |
e83cc0637
|
593 |
TftpTimeoutCountMax = TIMEOUT_COUNT; |
c718b1439
|
594 |
NetSetTimeout(TftpTimeoutMSecs, TftpTimeout); |
fe8c2806c
|
595 |
|
c718b1439
|
596 |
store_block(TftpBlock - 1, pkt + 2, len); |
fe8c2806c
|
597 598 |
/* |
4d69e98c0
|
599 |
* Acknowledge the block just received, which will prompt |
20478ceaa
|
600 |
* the remote for the next one. |
fe8c2806c
|
601 |
*/ |
53a5c424b
|
602 |
#ifdef CONFIG_MCAST_TFTP |
85eb5caf6
|
603 604 |
/* if I am the MasterClient, actively calculate what my next * needed block is; else I'm passive; not ACKING |
a93907c43
|
605 |
*/ |
53a5c424b
|
606 607 608 609 |
if (Multicast) { if (len < TftpBlkSize) { TftpEndingBlock = TftpBlock; } else if (MasterClient) { |
85eb5caf6
|
610 |
TftpBlock = PrevBitmapHole = |
53a5c424b
|
611 612 613 614 615 |
ext2_find_next_zero_bit( Bitmap, (Mapsize*8), PrevBitmapHole); if (TftpBlock > ((Mapsize*8) - 1)) { |
c718b1439
|
616 617 |
printf("tftpfile too big "); |
53a5c424b
|
618 |
/* try to double it and retry */ |
c718b1439
|
619 |
Mapsize <<= 1; |
53a5c424b
|
620 |
mcast_cleanup(); |
c718b1439
|
621 |
NetStartAgain(); |
53a5c424b
|
622 623 624 625 626 627 |
return; } TftpLastBlock = TftpBlock; } } #endif |
c718b1439
|
628 |
TftpSend(); |
fe8c2806c
|
629 |
|
53a5c424b
|
630 631 632 |
#ifdef CONFIG_MCAST_TFTP if (Multicast) { if (MasterClient && (TftpBlock >= TftpEndingBlock)) { |
c718b1439
|
633 634 635 |
puts(" Multicast tftp done "); |
53a5c424b
|
636 |
mcast_cleanup(); |
22f6e99d5
|
637 |
net_set_state(NETLOOP_SUCCESS); |
85eb5caf6
|
638 |
} |
13dfe9437
|
639 |
} else |
53a5c424b
|
640 |
#endif |
f5329bbc3
|
641 642 |
if (len < TftpBlkSize) tftp_complete(); |
fe8c2806c
|
643 644 645 |
break; case TFTP_ERROR: |
c718b1439
|
646 647 648 |
printf(" TFTP error: '%s' (%d) ", |
61fdd4f7c
|
649 |
pkt + 2, ntohs(*(__be16 *)pkt)); |
aafda38fb
|
650 |
|
61fdd4f7c
|
651 |
switch (ntohs(*(__be16 *)pkt)) { |
aafda38fb
|
652 653 654 655 656 |
case TFTP_ERR_FILE_NOT_FOUND: case TFTP_ERR_ACCESS_DENIED: puts("Not retrying... "); eth_halt(); |
22f6e99d5
|
657 |
net_set_state(NETLOOP_FAIL); |
aafda38fb
|
658 659 660 661 662 663 664 665 666 667 |
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 "); |
53a5c424b
|
668 |
#ifdef CONFIG_MCAST_TFTP |
aafda38fb
|
669 |
mcast_cleanup(); |
53a5c424b
|
670 |
#endif |
aafda38fb
|
671 672 673 |
NetStartAgain(); break; } |
fe8c2806c
|
674 675 676 677 678 679 |
break; } } static void |
c718b1439
|
680 |
TftpTimeout(void) |
fe8c2806c
|
681 |
{ |
e83cc0637
|
682 |
if (++TftpTimeoutCount > TftpTimeoutCountMax) { |
e4cde2f70
|
683 |
restart("Retry count exceeded"); |
fe8c2806c
|
684 |
} else { |
c718b1439
|
685 686 |
puts("T "); NetSetTimeout(TftpTimeoutMSecs, TftpTimeout); |
e59e35620
|
687 688 |
if (TftpState != STATE_RECV_WRQ) TftpSend(); |
fe8c2806c
|
689 690 |
} } |
58f317d18
|
691 |
void TftpStart(enum proto_t protocol) |
fe8c2806c
|
692 |
{ |
ecb0ccd9c
|
693 |
char *ep; /* Environment pointer */ |
89ba81d10
|
694 |
|
c96f86eef
|
695 696 697 698 |
/* * Allow the user to choose TFTP blocksize and timeout. * TFTP protocol has a minimal timeout of 1 second. */ |
2cb536080
|
699 700 |
ep = getenv("tftpblocksize"); if (ep != NULL) |
89ba81d10
|
701 |
TftpBlkSizeOption = simple_strtol(ep, NULL, 10); |
c96f86eef
|
702 |
|
2cb536080
|
703 704 |
ep = getenv("tftptimeout"); if (ep != NULL) |
c96f86eef
|
705 706 707 708 709 710 711 712 713 714 715 716 717 |
TftpTimeoutMSecs = simple_strtol(ep, NULL, 10); if (TftpTimeoutMSecs < 1000) { printf("TFTP timeout (%ld ms) too low, " "set minimum = 1000 ms ", TftpTimeoutMSecs); TftpTimeoutMSecs = 1000; } debug("TFTP blocksize = %i, timeout = %ld ms ", TftpBlkSizeOption, TftpTimeoutMSecs); |
ecb0ccd9c
|
718 |
|
20478ceaa
|
719 |
TftpRemoteIP = NetServerIP; |
fe8c2806c
|
720 |
if (BootFile[0] == '\0') { |
ea45cb0ad
|
721 |
sprintf(default_filename, "%02X%02X%02X%02X.img", |
c43352ccf
|
722 723 724 |
NetOurIP & 0xFF, (NetOurIP >> 8) & 0xFF, (NetOurIP >> 16) & 0xFF, |
c718b1439
|
725 |
(NetOurIP >> 24) & 0xFF); |
a93907c43
|
726 727 728 |
strncpy(tftp_filename, default_filename, MAX_LEN); tftp_filename[MAX_LEN-1] = 0; |
fe8c2806c
|
729 |
|
c718b1439
|
730 731 |
printf("*** Warning: no boot file name; using '%s' ", |
fe8c2806c
|
732 733 |
tftp_filename); } else { |
c718b1439
|
734 |
char *p = strchr(BootFile, ':'); |
a93907c43
|
735 736 737 738 739 |
if (p == NULL) { strncpy(tftp_filename, BootFile, MAX_LEN); tftp_filename[MAX_LEN-1] = 0; } else { |
20478ceaa
|
740 |
TftpRemoteIP = string_to_ip(BootFile); |
6a86bb6c2
|
741 |
strncpy(tftp_filename, p + 1, MAX_LEN); |
a93907c43
|
742 743 |
tftp_filename[MAX_LEN-1] = 0; } |
fe8c2806c
|
744 |
} |
c718b1439
|
745 746 |
printf("Using %s device ", eth_get_name()); |
1fb7cd498
|
747 |
printf("TFTP %s server %pI4; our IP address is %pI4", |
8c6914f10
|
748 749 750 751 752 753 |
#ifdef CONFIG_CMD_TFTPPUT protocol == TFTPPUT ? "to" : "from", #else "from", #endif &TftpRemoteIP, &NetOurIP); |
fe8c2806c
|
754 755 756 |
/* Check if we need to send across this subnet */ if (NetOurGatewayIP && NetOurSubnetMask) { |
0bdd8acc3
|
757 |
IPaddr_t OurNet = NetOurIP & NetOurSubnetMask; |
20478ceaa
|
758 |
IPaddr_t RemoteNet = TftpRemoteIP & NetOurSubnetMask; |
fe8c2806c
|
759 |
|
20478ceaa
|
760 |
if (OurNet != RemoteNet) |
0bdd8acc3
|
761 762 |
printf("; sending through gateway %pI4", &NetOurGatewayIP); |
fe8c2806c
|
763 |
} |
c718b1439
|
764 765 |
putc(' '); |
fe8c2806c
|
766 |
|
c718b1439
|
767 |
printf("Filename '%s'.", tftp_filename); |
fe8c2806c
|
768 769 |
if (NetBootFileSize) { |
c718b1439
|
770 771 |
printf(" Size is 0x%x Bytes = ", NetBootFileSize<<9); print_size(NetBootFileSize<<9, ""); |
fe8c2806c
|
772 |
} |
c718b1439
|
773 774 |
putc(' '); |
1fb7cd498
|
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 |
#ifdef CONFIG_CMD_TFTPPUT TftpWriting = (protocol == TFTPPUT); if (TftpWriting) { printf("Save address: 0x%lx ", save_addr); printf("Save size: 0x%lx ", save_size); NetBootFileXferSize = save_size; puts("Saving: *\b"); TftpState = STATE_SEND_WRQ; new_transfer(); } else #endif { printf("Load address: 0x%lx ", load_addr); puts("Loading: *\b"); TftpState = STATE_SEND_RRQ; } |
fe8c2806c
|
794 |
|
85b198027
|
795 |
time_start = get_timer(0); |
e83cc0637
|
796 |
TftpTimeoutCountMax = TftpRRQTimeoutCountMax; |
c718b1439
|
797 |
NetSetTimeout(TftpTimeoutMSecs, TftpTimeout); |
ece223b52
|
798 |
net_set_udp_handler(TftpHandler); |
39bccd21d
|
799 |
#ifdef CONFIG_CMD_TFTPPUT |
1fb7cd498
|
800 |
net_set_icmp_handler(icmp_handler); |
39bccd21d
|
801 |
#endif |
20478ceaa
|
802 |
TftpRemotePort = WELL_KNOWN_PORT; |
fe8c2806c
|
803 |
TftpTimeoutCount = 0; |
ecb0ccd9c
|
804 |
/* Use a pseudo-random port unless a specific port is set */ |
fe8c2806c
|
805 |
TftpOurPort = 1024 + (get_timer(0) % 3072); |
53a5c424b
|
806 |
|
ecb0ccd9c
|
807 |
#ifdef CONFIG_TFTP_PORT |
2cb536080
|
808 |
ep = getenv("tftpdstp"); |
7bc325a1b
|
809 |
if (ep != NULL) |
20478ceaa
|
810 |
TftpRemotePort = simple_strtol(ep, NULL, 10); |
2cb536080
|
811 |
ep = getenv("tftpsrcp"); |
7bc325a1b
|
812 |
if (ep != NULL) |
c718b1439
|
813 |
TftpOurPort = simple_strtol(ep, NULL, 10); |
ecb0ccd9c
|
814 |
#endif |
fbe4b5cbd
|
815 |
TftpBlock = 0; |
fe8c2806c
|
816 |
|
73a8b27c5
|
817 818 |
/* zero out server ether in case the server ip has changed */ memset(NetServerEther, 0, 6); |
53a5c424b
|
819 820 821 |
/* Revert TftpBlkSize to dflt */ TftpBlkSize = TFTP_BLOCK_SIZE; #ifdef CONFIG_MCAST_TFTP |
a93907c43
|
822 |
mcast_cleanup(); |
53a5c424b
|
823 |
#endif |
4fccb818e
|
824 825 826 827 |
#ifdef CONFIG_TFTP_TSIZE TftpTsize = 0; TftpNumchars = 0; #endif |
73a8b27c5
|
828 |
|
c718b1439
|
829 |
TftpSend(); |
fe8c2806c
|
830 |
} |
e59e35620
|
831 832 833 834 835 |
#ifdef CONFIG_CMD_TFTPSRV void TftpStartServer(void) { tftp_filename[0] = 0; |
e59e35620
|
836 837 |
printf("Using %s device ", eth_get_name()); |
e59e35620
|
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
printf("Listening for TFTP transfer on %pI4 ", &NetOurIP); printf("Load address: 0x%lx ", load_addr); puts("Loading: *\b"); TftpTimeoutCountMax = TIMEOUT_COUNT; TftpTimeoutCount = 0; TftpTimeoutMSecs = TIMEOUT; NetSetTimeout(TftpTimeoutMSecs, TftpTimeout); /* Revert TftpBlkSize to dflt */ TftpBlkSize = TFTP_BLOCK_SIZE; TftpBlock = 0; TftpOurPort = WELL_KNOWN_PORT; #ifdef CONFIG_TFTP_TSIZE TftpTsize = 0; TftpNumchars = 0; #endif TftpState = STATE_RECV_WRQ; |
ece223b52
|
861 |
net_set_udp_handler(TftpHandler); |
8e52533d1
|
862 863 864 |
/* zero out server ether in case the server ip has changed */ memset(NetServerEther, 0, 6); |
e59e35620
|
865 866 |
} #endif /* CONFIG_CMD_TFTPSRV */ |
53a5c424b
|
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 |
#ifdef CONFIG_MCAST_TFTP /* Credits: atftp project. */ /* pick up BcastAddr, Port, and whether I am [now] the master-client. * * Frame: * +-------+-----------+---+-------~~-------+---+ * | opc | multicast | 0 | addr, port, mc | 0 | * +-------+-----------+---+-------~~-------+---+ * The multicast addr/port becomes what I listen to, and if 'mc' is '1' then * I am the new master-client so must send ACKs to DataBlocks. If I am not * master-client, I'm a passive client, gathering what DataBlocks I may and * making note of which ones I got in my bitmask. * In theory, I never go from master->passive.. * .. this comes in with pkt already pointing just past opc */ static void parse_multicast_oack(char *pkt, int len) { |
c718b1439
|
885 886 887 |
int i; IPaddr_t addr; char *mc_adr, *port, *mc; |
53a5c424b
|
888 |
|
c718b1439
|
889 |
mc_adr = port = mc = NULL; |
53a5c424b
|
890 891 892 |
/* march along looking for 'multicast\0', which has to start at least * 14 bytes back from the end. */ |
c718b1439
|
893 894 |
for (i = 0; i < len-14; i++) if (strcmp(pkt+i, "multicast") == 0) |
53a5c424b
|
895 896 897 |
break; if (i >= (len-14)) /* non-Multicast OACK, ign. */ return; |
85eb5caf6
|
898 |
|
c718b1439
|
899 |
i += 10; /* strlen multicast */ |
53a5c424b
|
900 |
mc_adr = pkt+i; |
c718b1439
|
901 |
for (; i < len; i++) { |
53a5c424b
|
902 903 904 905 906 907 908 909 910 911 |
if (*(pkt+i) == ',') { *(pkt+i) = '\0'; if (port) { mc = pkt+i+1; break; } else { port = pkt+i+1; } } } |
6d2231e8f
|
912 913 |
if (!port || !mc_adr || !mc) return; |
53a5c424b
|
914 |
if (Multicast && MasterClient) { |
c718b1439
|
915 916 |
printf("I got a OACK as master Client, WRONG! "); |
53a5c424b
|
917 918 919 920 921 |
return; } /* ..I now accept packets destined for this MCAST addr, port */ if (!Multicast) { if (Bitmap) { |
c718b1439
|
922 923 |
printf("Internal failure! no mcast. "); |
53a5c424b
|
924 |
free(Bitmap); |
c718b1439
|
925 926 |
Bitmap = NULL; ProhibitMcast = 1; |
53a5c424b
|
927 928 929 |
return ; } /* I malloc instead of pre-declare; so that if the file ends |
85eb5caf6
|
930 931 |
* up being too big for this bitmap I can retry */ |
2cb536080
|
932 933 |
Bitmap = malloc(Mapsize); if (!Bitmap) { |
c718b1439
|
934 935 936 |
printf("No Bitmap, no multicast. Sorry. "); ProhibitMcast = 1; |
53a5c424b
|
937 938 |
return; } |
c718b1439
|
939 |
memset(Bitmap, 0, Mapsize); |
53a5c424b
|
940 941 942 943 944 945 946 |
PrevBitmapHole = 0; Multicast = 1; } addr = string_to_ip(mc_adr); if (Mcast_addr != addr) { if (Mcast_addr) eth_mcast_join(Mcast_addr, 0); |
2cb536080
|
947 948 |
Mcast_addr = addr; if (eth_mcast_join(Mcast_addr, 1)) { |
c718b1439
|
949 950 951 |
printf("Fail to set mcast, revert to TFTP "); ProhibitMcast = 1; |
53a5c424b
|
952 953 954 955 |
mcast_cleanup(); NetStartAgain(); } } |
c718b1439
|
956 957 958 959 |
MasterClient = (unsigned char)simple_strtoul((char *)mc, NULL, 10); Mcast_port = (unsigned short)simple_strtoul(port, NULL, 10); printf("Multicast: %s:%d [%d] ", mc_adr, Mcast_port, MasterClient); |
53a5c424b
|
960 961 962 963 |
return; } #endif /* Multicast TFTP */ |