1 /*
2  *  GRUB  --  GRand Unified Bootloader
3  *  Copyright (C) 2000,2001,2002,2004  Free Software Foundation, Inc.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 /* Based on "src/main.c" in etherboot-4.5.8.  */
21 /**************************************************************************
22 ETHERBOOT -  BOOTP/TFTP Bootstrap Program
23 
24 Author: Martin Renters
25   Date: Dec/93
26 
27 **************************************************************************/
28 
29 /* #define TFTP_DEBUG	1 */
30 
31 #include <filesys.h>
32 #include <shared.h>
33 
34 #include "grub.h"
35 #include "tftp.h"
36 #include "nic.h"
37 
38 static int retry;
39 static unsigned short iport = 2000;
40 static unsigned short oport = 0;
41 static unsigned short block, prevblock;
42 static int bcounter;
43 static struct tftp_t tp, saved_tp;
44 static int packetsize;
45 static int buf_eof, buf_read;
46 static int saved_filepos;
47 static unsigned short len, saved_len;
48 static char *buf;
49 
50 /**
51  * tftp_read
52  *
53  * Read file with _name_, data handled by _fnc_. In fact, grub never
54  * use it, we just use it to read dhcp config file.
55  */
56 static int await_tftp(int ival, void *ptr __unused,
57 		      unsigned short ptype __unused, struct iphdr *ip,
58 		      struct udphdr *udp)
59 {
60 	static int tftp_count = 0;
61 
62 	if (!udp) {
63 		return 0;
64 	}
65 	if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
66 		return 0;
67 	if (ntohs(udp->dest) != ival)
68 		return 0;
69 	tftp_count++;	/* show progress */
70 	if ((tftp_count % 1000) == 0)
71 		printf(".");
72 	return 1;
73 }
74 
75 int tftp_file_read(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
76 {
77 	struct tftpreq_t tp;
78 	struct tftp_t  *tr;
79 	int		rc;
80 
81 	retry = 0;
82 	block = 0;
83 	prevblock = 0;
84 	bcounter = 0;
85 
86 
87 	rx_qdrain();
88 
89 	tp.opcode = htons(TFTP_RRQ);
90 	/* Warning: the following assumes the layout of bootp_t.
91 	   But that's fixed by the IP, UDP and BOOTP specs. */
92 	len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) +
93 		sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
94 		name, 0, 0, 0, TFTP_MAX_PACKET) + 1;
95 	if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
96 			  TFTP_PORT, len, &tp))
97 		return (0);
98 	for (;;)
99 	{
100 		long timeout;
101 #ifdef	CONGESTED
102 		timeout = rfc2131_sleep_interval(block?TFTP_REXMT: TIMEOUT, retry);
103 #else
104 		timeout = rfc2131_sleep_interval(TIMEOUT, retry);
105 #endif
106 		if (!await_reply(await_tftp, iport, NULL, timeout))
107 		{
108 			if (!block && retry++ < MAX_TFTP_RETRIES)
109 			{	/* maybe initial request was lost */
110 				if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
111 						  ++iport, TFTP_PORT, len, &tp))
112 					return (0);
113 				continue;
114 			}
115 #ifdef	CONGESTED
116 			if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
117 			{	/* we resend our last ack */
118 #ifdef	MDEBUG
119 				printf("<REXMT>\n");
120 #endif
121 				udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
122 					     iport, oport,
123 					     TFTP_MIN_PACKET, &tp);
124 				continue;
125 			}
126 #endif
127 			break;	/* timeout */
128 		}
129 		tr = (struct tftp_t *)&nic.packet[ETH_HLEN];
130 		if (tr->opcode == ntohs(TFTP_ERROR))
131 		{
132 			printf("TFTP error %d (%s)\n",
133 			       ntohs(tr->u.err.errcode),
134 			       tr->u.err.errmsg);
135 			break;
136 		}
137 
138 		if (tr->opcode == ntohs(TFTP_OACK)) {
139 			char *p = tr->u.oack.data, *e;
140 
141 			if (prevblock)		/* shouldn't happen */
142 				continue;	/* ignore it */
143 			len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
144 			if (len > TFTP_MAX_PACKET)
145 				goto noak;
146 			e = p + len;
147 			while (*p != '\0' && p < e) {
148 /* 				if (!strcasecmp("blksize", p)) { */
149 				if (!grub_strcmp("blksize", p)) {
150 					p += 8;
151 /* 					if ((packetsize = strtoul(p, &p, 10)) < */
152 					if ((packetsize = getdec(&p)) < TFTP_DEFAULTSIZE_PACKET)
153 						goto noak;
154 					while (p < e && *p) p++;
155 					if (p < e)
156 						p++;
157 				}
158 				else {
159 				noak:
160 					tp.opcode = htons(TFTP_ERROR);
161 					tp.u.err.errcode = 8;
162 /*
163  *	Warning: the following assumes the layout of bootp_t.
164  *	But that's fixed by the IP, UDP and BOOTP specs.
165  */
166 					len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + sizeof(tp.u.err.errcode) +
167 /*
168  *	Normally bad form to omit the format string, but in this case
169  *	the string we are copying from is fixed. sprintf is just being
170  *	used as a strcpy and strlen.
171  */
172 						sprintf((char *)tp.u.err.errmsg,
173 						"RFC1782 error") + 1;
174 					udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
175 						     iport, ntohs(tr->udp.src),
176 						     len, &tp);
177 					return (0);
178 				}
179 			}
180 			if (p > e)
181 				goto noak;
182 			block = tp.u.ack.block = 0; /* this ensures, that */
183 						/* the packet does not get */
184 						/* processed as data! */
185 		}
186 		else if (tr->opcode == htons(TFTP_DATA)) {
187 			len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
188 			if (len > packetsize)	/* shouldn't happen */
189 				continue;	/* ignore it */
190 			block = ntohs(tp.u.ack.block = tr->u.data.block); }
191 		else {/* neither TFTP_OACK nor TFTP_DATA */
192 			break;
193 		}
194 
195 		if ((block || bcounter) && (block != (unsigned short)(prevblock+1))) {
196 			/* Block order should be continuous */
197 			tp.u.ack.block = htons(block = prevblock);
198 		}
199 		tp.opcode = htons(TFTP_ACK);
200 		oport = ntohs(tr->udp.src);
201 		udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport,
202 			     oport, TFTP_MIN_PACKET, &tp);	/* ack */
203 		if ((unsigned short)(block-prevblock) != 1) {
204 			/* Retransmission or OACK, don't process via callback
205 			 * and don't change the value of prevblock.  */
206 			continue;
207 		}
208 		prevblock = block;
209 		retry = 0;	/* It's the right place to zero the timer? */
210 		if ((rc = fnc(tr->u.data.download,
211 			      ++bcounter, len, len < packetsize)) <= 0)
212 			return(rc);
213 		if (len < packetsize) {	/* End of data --- fnc should not have returned */
214 			printf("tftp download complete, but\n");
215 			return (1);
216 		}
217 	}
218 	return (0);
219 }
220 
221 /* Fill the buffer by receiving the data via the TFTP protocol.  */
222 static int
223 buf_fill (int abort)
224 {
225 #ifdef TFTP_DEBUG
226   grub_printf ("buf_fill (%d)\n", abort);
227 #endif
228 
229   while (! buf_eof && (buf_read + packetsize <= FSYS_BUFLEN))
230     {
231       struct tftp_t *tr;
232       long timeout;
233 
234 #ifdef CONGESTED
235       timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);
236 #else
237       timeout = rfc2131_sleep_interval (TIMEOUT, retry);
238 #endif
239 
240       if (! await_reply (await_tftp, iport, NULL, timeout))
241 	{
242 	  if (user_abort)
243 	    return 0;
244 
245 	  if (! block && retry++ < MAX_TFTP_RETRIES)
246 	    {
247 	      /* Maybe initial request was lost.  */
248 #ifdef TFTP_DEBUG
249 	      grub_printf ("Maybe initial request was lost.\n");
250 #endif
251 	      if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
252 				  ++iport, TFTP_PORT, len, &tp))
253 		return 0;
254 
255 	      continue;
256 	    }
257 
258 #ifdef CONGESTED
259 	  if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
260 	    {
261 	      /* We resend our last ack.  */
262 # ifdef TFTP_DEBUG
263 	      grub_printf ("<REXMT>\n");
264 # endif
265 	      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
266 			    iport, oport,
267 			    TFTP_MIN_PACKET, &tp);
268 	      continue;
269 	    }
270 #endif
271 	  /* Timeout.  */
272 	  return 0;
273 	}
274 
275       tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
276       if (tr->opcode == ntohs (TFTP_ERROR))
277 	{
278 	  grub_printf ("TFTP error %d (%s)\n",
279 		       ntohs (tr->u.err.errcode),
280 		       tr->u.err.errmsg);
281 	  return 0;
282 	}
283 
284       if (tr->opcode == ntohs (TFTP_OACK))
285 	{
286 	  char *p = tr->u.oack.data, *e;
287 
288 #ifdef TFTP_DEBUG
289 	  grub_printf ("OACK ");
290 #endif
291 	  /* Shouldn't happen.  */
292 	  if (prevblock)
293 	    {
294 	      /* Ignore it.  */
295 	      grub_printf ("%s:%d: warning: PREVBLOCK != 0 (0x%x)\n",
296 			   __FILE__, __LINE__, prevblock);
297 	      continue;
298 	    }
299 
300 	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2;
301 	  if (len > TFTP_MAX_PACKET)
302 	    goto noak;
303 
304 	  e = p + len;
305 	  while (*p != '\000' && p < e)
306 	    {
307 	      if (! grub_strcmp ("blksize", p))
308 		{
309 		  p += 8;
310 		  if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET)
311 		    goto noak;
312 #ifdef TFTP_DEBUG
313 		  grub_printf ("blksize = %d\n", packetsize);
314 #endif
315 		}
316 	      else if (! grub_strcmp ("tsize", p))
317 		{
318 		  p += 6;
319 		  if ((filemax = getdec (&p)) < 0)
320 		    {
321 		      filemax = -1;
322 		      goto noak;
323 		    }
324 #ifdef TFTP_DEBUG
325 		  grub_printf ("tsize = %d\n", filemax);
326 #endif
327 		}
328 	      else
329 		{
330 		noak:
331 #ifdef TFTP_DEBUG
332 		  grub_printf ("NOAK\n");
333 #endif
334 		  tp.opcode = htons (TFTP_ERROR);
335 		  tp.u.err.errcode = 8;
336 		  len = (grub_sprintf ((char *) tp.u.err.errmsg,
337 				       "RFC1782 error")
338 			 + sizeof (tp.ip) + sizeof (tp.udp)
339 			 + sizeof (tp.opcode) + sizeof (tp.u.err.errcode)
340 			 + 1);
341 		  udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
342 				iport, ntohs (tr->udp.src),
343 				len, &tp);
344 		  return 0;
345 		}
346 
347 	      while (p < e && *p)
348 		p++;
349 
350 	      if (p < e)
351 		p++;
352 	    }
353 
354 	  if (p > e)
355 	    goto noak;
356 
357 	  /* This ensures that the packet does not get processed as
358 	     data!  */
359 	  block = tp.u.ack.block = 0;
360 	}
361       else if (tr->opcode == ntohs (TFTP_DATA))
362 	{
363 #ifdef TFTP_DEBUG
364 	  grub_printf ("DATA ");
365 #endif
366 	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4;
367 
368 	  /* Shouldn't happen.  */
369 	  if (len > packetsize)
370 	    {
371 	      /* Ignore it.  */
372 	      grub_printf ("%s:%d: warning: LEN > PACKETSIZE (0x%x > 0x%x)\n",
373 			   __FILE__, __LINE__, len, packetsize);
374 	      continue;
375 	    }
376 
377 	  block = ntohs (tp.u.ack.block = tr->u.data.block);
378 	}
379       else
380 	/* Neither TFTP_OACK nor TFTP_DATA.  */
381 	break;
382 
383       if ((block || bcounter) && (block != prevblock + (unsigned short) 1))
384 	/* Block order should be continuous */
385 	tp.u.ack.block = htons (block = prevblock);
386 
387       /* Should be continuous.  */
388       tp.opcode = abort ? htons (TFTP_ERROR) : htons (TFTP_ACK);
389       oport = ntohs (tr->udp.src);
390 
391 #ifdef TFTP_DEBUG
392       grub_printf ("ACK\n");
393 #endif
394       /* Ack.  */
395       udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport,
396 		    oport, TFTP_MIN_PACKET, &tp);
397 
398       if (abort)
399 	{
400 	  buf_eof = 1;
401 	  break;
402 	}
403 
404       /* Retransmission or OACK.  */
405       if ((unsigned short) (block - prevblock) != 1)
406 	/* Don't process.  */
407 	continue;
408 
409       prevblock = block;
410       /* Is it the right place to zero the timer?  */
411       retry = 0;
412 
413       /* In GRUB, this variable doesn't play any important role at all,
414 	 but use it for consistency with Etherboot.  */
415       bcounter++;
416 
417       /* Copy the downloaded data to the buffer.  */
418       grub_memmove (buf + buf_read, tr->u.data.download, len);
419       buf_read += len;
420 
421       /* End of data.  */
422       if (len < packetsize)
423 	buf_eof = 1;
424     }
425 
426   return 1;
427 }
428 
429 /* Send the RRQ whose length is LEN.  */
430 static int
431 send_rrq (void)
432 {
433   /* Initialize some variables.  */
434   retry = 0;
435   block = 0;
436   prevblock = 0;
437   packetsize = TFTP_DEFAULTSIZE_PACKET;
438   bcounter = 0;
439 
440   buf = (char *) FSYS_BUF;
441   buf_eof = 0;
442   buf_read = 0;
443   saved_filepos = 0;
444 
445   rx_qdrain();
446 
447 #ifdef TFTP_DEBUG
448   grub_printf ("send_rrq ()\n");
449   {
450     int i;
451     char *p;
452 
453     for (i = 0, p = (char *) &tp; i < len; i++)
454       if (p[i] >= ' ' && p[i] <= '~')
455 	grub_putchar (p[i]);
456       else
457 	grub_printf ("\\%x", (unsigned) p[i]);
458 
459     grub_putchar ('\n');
460   }
461 #endif
462   /* Send the packet.  */
463   return udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
464 		       TFTP_PORT, len, &tp);
465 }
466 
467 /* Mount the network drive. If the drive is ready, return one, otherwise
468    return zero.  */
469 int
470 tftp_mount (void)
471 {
472   /* Check if the current drive is the network drive.  */
473   if (current_drive != NETWORK_DRIVE)
474     return 0;
475 
476   /* If the drive is not initialized yet, abort.  */
477   if (! network_ready)
478     return 0;
479 
480   return 1;
481 }
482 
483 /* Read up to SIZE bytes, returned in ADDR.  */
484 int
485 tftp_read (char *addr, int size)
486 {
487   /* How many bytes is read?  */
488   int ret = 0;
489 
490 #ifdef TFTP_DEBUG
491   grub_printf ("tftp_read (0x%x, %d)\n", (int) addr, size);
492 #endif
493 
494   if (filepos < saved_filepos)
495     {
496       /* Uggh.. FILEPOS has been moved backwards. So reopen the file.  */
497       buf_read = 0;
498       buf_fill (1);
499       grub_memmove ((char *) &tp, (char *) &saved_tp, saved_len);
500       len = saved_len;
501 #ifdef TFTP_DEBUG
502       {
503 	int i;
504 	grub_printf ("opcode = 0x%x, rrq = ", (unsigned long) tp.opcode);
505 	for (i = 0; i < TFTP_DEFAULTSIZE_PACKET; i++)
506 	  {
507 	    if (tp.u.rrq[i] >= ' ' && tp.u.rrq[i] <= '~')
508 	      grub_putchar (tp.u.rrq[i]);
509 	    else
510 	      grub_putchar ('*');
511 	  }
512 	grub_putchar ('\n');
513       }
514 #endif
515 
516       if (! send_rrq ())
517 	{
518 	  errnum = ERR_WRITE;
519 	  return 0;
520 	}
521     }
522 
523   while (size > 0)
524     {
525       int amt = buf_read + saved_filepos - filepos;
526 
527       /* If the length that can be copied from the buffer is over the
528 	 requested size, cut it down.  */
529       if (amt > size)
530 	amt = size;
531 
532       if (amt > 0)
533 	{
534 	  /* Copy the buffer to the supplied memory space.  */
535 	  grub_memmove (addr, buf + filepos - saved_filepos, amt);
536 	  size -= amt;
537 	  addr += amt;
538 	  filepos += amt;
539 	  ret += amt;
540 
541 	  /* If the size of the empty space becomes small, move the unused
542 	     data forwards.  */
543 	  if (filepos - saved_filepos > FSYS_BUFLEN / 2)
544 	    {
545 	      grub_memmove (buf, buf + FSYS_BUFLEN / 2, FSYS_BUFLEN / 2);
546 	      buf_read -= FSYS_BUFLEN / 2;
547 	      saved_filepos += FSYS_BUFLEN / 2;
548 	    }
549 	}
550       else
551 	{
552 	  /* Skip the whole buffer.  */
553 	  saved_filepos += buf_read;
554 	  buf_read = 0;
555 	}
556 
557       /* Read the data.  */
558       if (size > 0 && ! buf_fill (0))
559 	{
560 	  errnum = ERR_READ;
561 	  return 0;
562 	}
563 
564       /* Sanity check.  */
565       if (size > 0 && buf_read == 0)
566 	{
567 	  errnum = ERR_READ;
568 	  return 0;
569 	}
570     }
571 
572   return ret;
573 }
574 
575 /* Check if the file DIRNAME really exists. Get the size and save it in
576    FILEMAX.  */
577 int
578 tftp_dir (char *dirname)
579 {
580   int ch;
581 
582 #ifdef TFTP_DEBUG
583   grub_printf ("tftp_dir (%s)\n", dirname);
584 #endif
585 
586   /* In TFTP, there is no way to know what files exist.  */
587   if (print_possibilities)
588     return 1;
589 
590   /* Don't know the size yet.  */
591   filemax = -1;
592 
593  reopen:
594   /* Construct the TFTP request packet.  */
595   tp.opcode = htons (TFTP_RRQ);
596   /* Terminate the filename.  */
597   ch = nul_terminate (dirname);
598   /* Make the request string (octet, blksize and tsize).  */
599   len = (grub_sprintf ((char *) tp.u.rrq,
600 		       "%s%coctet%cblksize%c%d%ctsize%c0",
601 		       dirname, 0, 0, 0, TFTP_MAX_PACKET, 0, 0)
602 	 + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1);
603   /* Restore the original DIRNAME.  */
604   dirname[grub_strlen (dirname)] = ch;
605   /* Save the TFTP packet so that we can reopen the file later.  */
606   grub_memmove ((char *) &saved_tp, (char *) &tp, len);
607   saved_len = len;
608   if (! send_rrq ())
609     {
610       errnum = ERR_WRITE;
611       return 0;
612     }
613 
614   /* Read the data.  */
615   if (! buf_fill (0))
616     {
617       errnum = ERR_FILE_NOT_FOUND;
618       return 0;
619     }
620 
621   if (filemax == -1)
622     {
623       /* The server doesn't support the "tsize" option, so we must read
624 	 the file twice...  */
625 
626       /* Zero the size of the file.  */
627       filemax = 0;
628       do
629 	{
630 	  /* Add the length of the downloaded data.  */
631 	  filemax += buf_read;
632 	  /* Reset the offset. Just discard the contents of the buffer.  */
633 	  buf_read = 0;
634 	  /* Read the data.  */
635 	  if (! buf_fill (0))
636 	    {
637 	      errnum = ERR_READ;
638 	      return 0;
639 	    }
640 	}
641       while (! buf_eof);
642 
643       /* Maybe a few amounts of data remains.  */
644       filemax += buf_read;
645 
646       /* Retry the open instruction.  */
647       goto reopen;
648     }
649 
650   return 1;
651 }
652 
653 /* Close the file.  */
654 void
655 tftp_close (void)
656 {
657 #ifdef TFTP_DEBUG
658   grub_printf ("tftp_close ()\n");
659 #endif
660 
661   buf_read = 0;
662   buf_fill (1);
663 }
664