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