xref: /openbmc/u-boot/net/tftp.c (revision dd875c76)
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