xref: /openbmc/u-boot/net/tftp.c (revision 2262cfee)
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 	NetSetEther (NetTxPacket, NetServerEther, PROT_IP);
146 	NetSetIP (NetTxPacket + ETHER_HDR_SIZE, NetServerIP,
147 					TftpServerPort, TftpOurPort, len);
148 	NetSendPacket (NetTxPacket, ETHER_HDR_SIZE + IP_HDR_SIZE + len);
149 }
150 
151 
152 static void
153 TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
154 {
155 	ushort proto;
156 
157 	if (dest != TftpOurPort) {
158 		return;
159 	}
160 	if (TftpState != STATE_RRQ && src != TftpServerPort) {
161 		return;
162 	}
163 
164 	if (len < 2) {
165 		return;
166 	}
167 	len -= 2;
168 	/* warning: don't use increment (++) in ntohs() macros!! */
169 	proto = *((ushort *)pkt)++;
170 	switch (ntohs(proto)) {
171 
172 	case TFTP_RRQ:
173 	case TFTP_WRQ:
174 	case TFTP_ACK:
175 		break;
176 	default:
177 		break;
178 
179 	case TFTP_DATA:
180 		if (len < 2)
181 			return;
182 		len -= 2;
183 		TftpBlock = ntohs(*(ushort *)pkt);
184 		if (((TftpBlock - 1) % 10) == 0) {
185 			putc ('#');
186 		} else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
187 			puts ("\n\t ");
188 		}
189 
190 		if (TftpState == STATE_RRQ) {
191 			TftpState = STATE_DATA;
192 			TftpServerPort = src;
193 			TftpLastBlock = 0;
194 
195 			if (TftpBlock != 1) {	/* Assertion */
196 				printf ("\nTFTP error: "
197 					"First block is not block 1 (%d)\n"
198 					"Starting again\n\n",
199 					TftpBlock);
200 				NetStartAgain ();
201 				break;
202 			}
203 		}
204 
205 		if (TftpBlock == TftpLastBlock) {
206 			/*
207 			 *	Same block again; ignore it.
208 			 */
209 			break;
210 		}
211 
212 		TftpLastBlock = TftpBlock;
213 		NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
214 
215 		store_block (TftpBlock - 1, pkt + 2, len);
216 
217 		/*
218 		 *	Acknoledge the block just received, which will prompt
219 		 *	the server for the next one.
220 		 */
221 		TftpSend ();
222 
223 		if (len < 512) {
224 			/*
225 			 *	We received the whole thing.  Try to
226 			 *	run it.
227 			 */
228 			puts ("\ndone\n");
229 			NetState = NETLOOP_SUCCESS;
230 		}
231 		break;
232 
233 	case TFTP_ERROR:
234 		printf ("\nTFTP error: '%s' (%d)\n",
235 					pkt + 2, ntohs(*(ushort *)pkt));
236 		puts ("Starting again\n\n");
237 		NetStartAgain ();
238 		break;
239 	}
240 }
241 
242 
243 static void
244 TftpTimeout (void)
245 {
246 	if (++TftpTimeoutCount >= TIMEOUT_COUNT) {
247 		puts ("\nRetry count exceeded; starting again\n");
248 		NetStartAgain ();
249 	} else {
250 		puts ("T ");
251 		NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
252 		TftpSend ();
253 	}
254 }
255 
256 
257 void
258 TftpStart (void)
259 {
260 #ifdef ET_DEBUG
261 	printf ("\nServer ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n",
262 		NetServerEther[0],
263 		NetServerEther[1],
264 		NetServerEther[2],
265 		NetServerEther[3],
266 		NetServerEther[4],
267 		NetServerEther[5]
268 	);
269 #endif /* DEBUG */
270 
271 	if (BootFile[0] == '\0') {
272 		IPaddr_t OurIP = ntohl(NetOurIP);
273 
274 		sprintf(default_filename, "%02lX%02lX%02lX%02lX.img",
275 			OurIP & 0xFF,
276 			(OurIP >>  8) & 0xFF,
277 			(OurIP >> 16) & 0xFF,
278 			(OurIP >> 24) & 0xFF	);
279 		tftp_filename = default_filename;
280 
281 		printf ("*** Warning: no boot file name; using '%s'\n",
282 			tftp_filename);
283 	} else {
284 		tftp_filename = BootFile;
285 	}
286 
287 	puts ("TFTP from server ");	print_IPaddr (NetServerIP);
288 	puts ("; our IP address is ");	print_IPaddr (NetOurIP);
289 
290 	/* Check if we need to send across this subnet */
291 	if (NetOurGatewayIP && NetOurSubnetMask) {
292 	    IPaddr_t OurNet 	= NetOurIP    & NetOurSubnetMask;
293 	    IPaddr_t ServerNet 	= NetServerIP & NetOurSubnetMask;
294 
295 	    if (OurNet != ServerNet) {
296 		puts ("; sending through gateway ");
297 		print_IPaddr (NetOurGatewayIP) ;
298 	    }
299 	}
300 	putc ('\n');
301 
302 	printf ("Filename '%s'.", tftp_filename);
303 
304 	if (NetBootFileSize) {
305 		printf (" Size is 0x%x Bytes = ", NetBootFileSize<<9);
306 		print_size (NetBootFileSize<<9, "");
307 	}
308 
309 	putc ('\n');
310 
311 	printf ("Load address: 0x%lx\n", load_addr);
312 
313 	puts ("Loading: *\b");
314 
315 	NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
316 	NetSetHandler (TftpHandler);
317 
318 	TftpServerPort = WELL_KNOWN_PORT;
319 	TftpTimeoutCount = 0;
320 	TftpState = STATE_RRQ;
321 	TftpOurPort = 1024 + (get_timer(0) % 3072);
322 
323 	TftpSend ();
324 }
325 
326 #endif /* CFG_CMD_NET */
327